Select Git revision
nonLinearMechSolver.cpp

Van Dung NGUYEN authored
nonLinearMechSolver.cpp 553.63 KiB
//
//
// Description: Non linear solver for mechanic problems
// quasi-static implicit scheme & dynamic explicit Hulbert-Chung scheme
//
// Author: <Gauthier BECKER>, (C) 2011
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include <string.h>
#include <cstdlib>
#include <ctime>
#include <time.h>
#include <cstdio>
#include <vector>
#include <sys/stat.h>
#include "GmshConfig.h"
#include "meshPartition.h"
#include "nonLinearMechSolver.h"
#include "linearSystemCSR.h"
#include "linearSystemPETSc.h"
#include "linearSystemGmm.h"
#include "Numeric.h"
#include "nlTerms.h"
#include "solverAlgorithms.h"
#include "quadratureRules.h"
#include "MPoint.h"
#include "ipstate.h"
#include "ipField.h"
#include "GModel.h"
#include "explicitHulbertChungPETSc.h"
#include "explicitHulbertChungBLAS.h"
#include "nlsolAlgorithms.h"
#include "nonLinearMechSolver.h"
#include "MTriangle.h"
#include "MQuadrangle.h"
#include "energyField.h"
#include "nlsolAlgorithms.h"
#include "solverAlgorithms.h"
#include "quadratureRules.h"
#include "MPoint.h"
#include "pbcDofManager.h"
#include "staticDofManager.h"
#include "dofManagerMultiSystems.h"
#include "contactTerms.h"
#include "NonLinearSolverConfig.h"
#include "currentConfig.h"
#include "MInterfaceLine.h"
#include "fragment.h"
#include "OS.h"
#include "pathFollowingSystem.h"
#include "StringUtils.h"
#include "Context.h"
#include "HighOrder.h"
#include "nonLinearSystemGmm.h"
#include "nonLinearSystemGMRESk.h"
#include "implicitHulbertChungPETSc.h"
#include "pathFollowingSystemPETSc.h"
#include "pbcPathFollowingSystemPETSc.h"
#include "generalLocalControlBasedPathFollowingSystemPETSc.h"
#include "eigenSolver.h"
#include "eigenModeView.h"
#include "eigenVectorData.h"
#include "failureDetection.h"
//#include "linearSystemGMRESk.h"
#include "restartManager.h"
#include "geometryRotation.h"
#include "interfaceReferenceLocalBasis.h"
#include "numericalMaterial.h"
#include "criticalTimeStepElements.h"
#include "generalHyperellipticPathFollowingSystemPETSc.h"
#if defined(HAVE_PLUGINS)
#include "PluginManager.h"
#endif //HAVE_PLUGINS
#include "periodicBoundaryCondition.h"
#include "ipFiniteStrain.h"
#if defined(HAVE_POST)
#include "PView.h"
#include "PViewData.h"
#endif
#if defined(HAVE_MPI)
#include "elementFilterMPI.h"
#include "nlmpiAlgorithms.h"
#endif // HAVE_MPI
int clustersData::realClusterSize() const
{
int realSize =0;
for (std::map<int, std::map<int, double> >::const_iterator itm = clusterMap.begin(); itm != clusterMap.end(); itm++)
{
int clusterId = itm->first;
if (clusterId >=0)
{
realSize ++;
}
}
return realSize;
}
void clustersData::loadFromFile(const std::string fileName)
{
clusterDataFileName = fileName;
clusterIndexMap.clear();
materialMap.clear();
weightMap.clear();
clusterMap.clear();
Msg::Info("read clusters data from file: %s",fileName.c_str());
FILE* fp = fopen(fileName.c_str(),"r");
if (fp !=NULL) {
printf("start reading file: %s\n",fileName.c_str());
if(!feof(fp))
{
char what1[256];
char what2[256];
char what3[256];
char what4[256];
int ok = fscanf(fp, "%s %s %s %s", what1, what2, what3, what4);
printf("%s %s %s %s\n",what1,what2,what3,what4);
}
while (1){
if(feof(fp))
break;
int ele, gp, indx, matNum;
if (fscanf(fp, "%d %d %d %d", &ele,&gp,&indx,&matNum)==4)
{
int type = numericalMaterialBase::createTypeWithTwoInts(ele,gp);
clusterIndexMap[type] = indx;
materialMap[type] = matNum;
//printf("%d %d %d %d\n",ele,gp,indx,matNum);
}
}
printf("done reading file: %s\n",fileName.c_str());
fclose(fp);
}
else
{
Msg::Error("File %s does not exist !!!",fileName.c_str());
Msg::Exit(0);
}
Msg::Info("done reading clusters data from file: %s",fileName.c_str());
}
void AvergageCluster::getAverageValue(const IPField* ipf, std::vector<double>& val) const
{
if (clusterData == NULL)
{
Msg::Error("cluster data is not available");
Msg::Exit(0);
}
int nClusters = clusterData->realClusterSize();
if (nClusters >0)
{
val.resize(nClusters);
for (std::map<int, std::map<int, double> >::const_iterator itm = clusterData->clusterMap.begin(); itm != clusterData->clusterMap.end(); itm++)
{
int cluster = itm->first;
if (cluster >=0)
{
const std::map<int, double>& weight = itm->second;
val[cluster] = 0;
double volume = 0.;
for (std::map<int, double>::const_iterator it = weight.begin(); it != weight.end(); it++)
{
int type = it->first;
double w = it->second;
int eleNum, gp;
numericalMaterialBase::getTwoIntsFromType(type,eleNum,gp);
const AllIPState::ipstateElementContainer *vips = ipf->getAips()->getIPstate(eleNum);
const IPVariable* ipv = (*vips)[gp]->getState(IPStateBase::current);
val[cluster] += (w*ipv->get(ipVal));
volume += w;
}
if (volume ==0.)
{
val[cluster] = 0.;
}
else
{
val[cluster] /= volume;
}
}
}
}
};
TimeManager::TimeManager():
_timeSeries(),_numStepSeries(),
_startTime(0.), _endTime(0.), _numStep(1), _tol(1e-6),
_lastTime(0.),
_lastIterationIndex(0.),
_timeStep(0.),
_previousTimeStep(0.),
_maxTimeStepReached(0.),
_upperBoundTimeStep(std::numeric_limits<double>::max()),
_lowerBoundTimeStep(0.),
_timeStepAdaptation(false),
_numNROptimal(0),
_expNROptimal(0.),
_maxNRite(15),
_timeStepFactorReduction(2.),
_maxAttemptStepReduction(6),
_niteTimeStepIncrease(5),
_numberTimeStepReduction(0),
_timeStepIncreaseBecauseOfSolverFailure(false)
{}
TimeManager::TimeManager(const TimeManager& src):
_timeSeries(src._timeSeries),_numStepSeries(src._numStepSeries),
_startTime(src._startTime), _endTime(src._endTime), _numStep(src._numStep), _tol(src._tol),
_lastTime(src._lastTime),
_lastIterationIndex(src._lastIterationIndex),
_timeStep(src._timeStep),
_previousTimeStep(src._previousTimeStep),
_maxTimeStepReached(src._maxTimeStepReached),
_upperBoundTimeStep(src._upperBoundTimeStep),
_lowerBoundTimeStep(src._lowerBoundTimeStep),
_timeStepAdaptation(src._timeStepAdaptation),
_numNROptimal(src._numNROptimal),
_expNROptimal(src._expNROptimal),
_maxNRite(src._maxNRite),
_timeStepFactorReduction(src._timeStepFactorReduction),
_maxAttemptStepReduction(src._maxAttemptStepReduction),
_niteTimeStepIncrease(src._niteTimeStepIncrease),
_numberTimeStepReduction(src._numberTimeStepReduction),
_timeStepIncreaseBecauseOfSolverFailure(src._timeStepIncreaseBecauseOfSolverFailure)
{
}
void TimeManager::clearNumStepSeries()
{
_timeSeries.clear();
_numStepSeries.clear();
}
void TimeManager::setNumStepTimeInterval(double t, int nstep)
{
if (t > _endTime) _endTime = t;
_timeSeries.push_back(t);
_numStepSeries.push_back(nstep);
}
void TimeManager::reset()
{
clearNumStepSeries();
_endTime = _startTime;
_numStep = 1;
// no simulation before
_lastTime = _startTime;
_lastIterationIndex = 0;
// previous data
_previousTimeStep = 0.;
_maxTimeStepReached = 0.;
_timeStep = 0.;
};
void TimeManager::activateTimeStepAdaptation(bool adap, int numNROptimal, double exp, double maximalStep, double minTimeStep)
{
if (adap)
{
Msg::Info("time step adaptation is activated");
_timeStepAdaptation = adap;
_numNROptimal = numNROptimal;
_expNROptimal = exp;
_upperBoundTimeStep = maximalStep;
_lowerBoundTimeStep = minTimeStep;
};
};
void TimeManager::setManageTimeStepSafeguard(const int miteNR,const int iteIncreaseTS, const double redfactor, const int maxAttemptRedFactor)
{
_maxNRite = miteNR;
_niteTimeStepIncrease = iteIncreaseTS;
_timeStepFactorReduction = redfactor;
_maxAttemptStepReduction = maxAttemptRedFactor;
if (_timeStepFactorReduction < 1.)
{
_timeStepFactorReduction= 1.;
Msg::Warning("step factor cannot be smaller than 1");
}
};
void TimeManager::setMaximalNumberOfFails(int maxnbFails)
{
_maxAttemptStepReduction = maxnbFails;
Msg::Info("set maximal number of fails: %d",_maxAttemptStepReduction);
}
void TimeManager::restart()
{
//restartManager::restart(_numNROptimal}; // num optimal
//restartManager::restart(_numNROptimalLocal}; // number optimal for local
//restartManager::restart(_expNROptimal};
//restartManager::restart(_timeStepAdaptation}; // true if path following step is adapted with number NR
restartManager::restart(_lastTime);
restartManager::restart(_lastIterationIndex);
}
bool TimeManager::willArchive(double curtime, int numstep) const {return true;}
bool TimeManager::reachEndTime() const
{
if (fabs(_lastTime -_endTime) > _tol*_endTime)
{
return false;
}
else
{
return true;
}
}
void TimeManager::reduceTimeStep()
{
_numberTimeStepReduction ++;
_timeStep /= _timeStepFactorReduction;
Msg::Info("Reduced time step = %e",_timeStep);
}
void TimeManager::setTimeStep(double dt)
{
_timeStep = dt;
//Msg::Info("modified time step = %e",_timeStep);
};
double TimeManager::getStartTime() const
{
return _startTime;
}
double TimeManager::getEndTime() const
{
return _endTime;
}
int TimeManager::getNumSteps() const
{
return _numStep;
};
void TimeManager::setStartTime(double starttime)
{
_startTime = starttime;
};
void TimeManager::setEndTime(double endtime)
{
_endTime = endtime;
};
void TimeManager::setNumSteps(int st)
{
_numStep = st;
}
double TimeManager::getLastTime() const
{
return _lastTime;
}
int TimeManager::getLastIterationIndex() const
{
return _lastIterationIndex;
};
double TimeManager::getTimeStep() const
{
return _timeStep;
};
int TimeManager::getMaxNbIterations() const {return _maxNRite;};
int TimeManager::getMaxNbFails() const{return _maxAttemptStepReduction;};
int TimeManager::getNbFails() const {return _numberTimeStepReduction;}
void TimeManager::computeTimeStepForNextSolving(int niteNR)
{
// from data on _lastTim, _timeStep,
int lastTimeInterVal = -1;
int sizeTimeSeries = _timeSeries.size();
for (int i=0; i< sizeTimeSeries-1; i++)
{
if (fabs(_lastTime-_timeSeries[i]) < _tol*_endTime)
{
lastTimeInterVal = i;
break;
}
}
if (lastTimeInterVal == -1)
{
if (_timeStepAdaptation)
{
// change current time step with optimal number
_timeStep = _previousTimeStep*pow((double)_numNROptimal/(double)niteNR,_expNROptimal);
if (_timeStep > _upperBoundTimeStep)
{
_timeStep = _upperBoundTimeStep;
Msg::Info("New time step for next solving using max time step = %e",_timeStep);
}
else if (_timeStep < _lowerBoundTimeStep)
{
_timeStep = _lowerBoundTimeStep;
Msg::Info("fNew time step for next solving using min time step = %e",_timeStep);
}
else
{
Msg::Info("New time step for next solving by time adaptation = %e",_timeStep);
}
}
else
{
// increase time step due to reduce time step because of the solver fail
_timeStepIncreaseBecauseOfSolverFailure=false;
if((niteNR <= _niteTimeStepIncrease) && (_numberTimeStepReduction > 0)) // increase time step if convergence in a few iteration
{
_timeStepIncreaseBecauseOfSolverFailure = true;
_numberTimeStepReduction --;
_timeStep *=_timeStepFactorReduction;
if (_timeStepFactorReduction > 1.)
{
Msg::Info("Time step is increased due to convergence of Newton-Raphson in less than %d",_niteTimeStepIncrease);
}
}
}
}
else
{
// start with timetep at other time interval
_timeStep = (_timeSeries[lastTimeInterVal+1]- _timeSeries[lastTimeInterVal])/(_numStepSeries[lastTimeInterVal+1]);
Msg::Info("start new time step = %e in time interval [%e %e] lastTime = %e",_timeStep,_timeSeries[lastTimeInterVal],_timeSeries[lastTimeInterVal+1],_lastTime);
}
for (int i=0; i< sizeTimeSeries; i++)
{
if ( _lastTime+_tol*_endTime < _timeSeries[i] and _lastTime+_timeStep > _timeSeries[i]+_tol*_endTime)
{
_timeStep = _timeSeries[i] - _lastTime;
Msg::Info("modify time step %e",_timeStep);
}
}
// check if end time
if (_lastTime + _timeStep >_endTime)
{
// end time will reach
_timeStep = _endTime - _lastTime;
}
};
bool TimeManager::withTimeStepAdaptation() const
{
return _timeStepAdaptation;
}
void TimeManager::saveTimeHistory()
{
// update last time
_lastTime += _timeStep;
_lastIterationIndex ++;
//
_previousTimeStep = _timeStep;
//
if (_maxTimeStepReached < _timeStep)
{
_maxTimeStepReached = _timeStep;
}
};
void TimeManager::initializeTimeSteppingPlan()
{
// no simulation before
_lastTime = _startTime;
_lastIterationIndex = 0;
// previous data
_previousTimeStep = 0.;
_maxTimeStepReached = 0.;
//
_numberTimeStepReduction = 0; // test
//
if (_timeSeries.size() == 0)
{
_timeStep = (_endTime-_startTime)/_numStep;
}
else
{
// modify total number of step;
_numStep = 0;
for (int i=0; i< _numStepSeries.size(); i++)
{
_numStep += _numStepSeries[i];
}
if (_endTime > _timeSeries.back())
{
double lastTimeStep = _timeSeries.back()/_numStep;
_numStep += (int) round((_endTime-_timeSeries.back())/lastTimeStep);
}
_timeStep = _timeSeries[0]/_numStepSeries[0]; // start as first interval
}
};
PointwiseTimeManager::PointwiseTimeManager(double t):TimeManager(),_savePoints(),_tol(t){}
void PointwiseTimeManager::put(double val)
{
_savePoints.push_back(val);
}
bool PointwiseTimeManager::willArchive(double curtime, int numstep) const
{
// the most stupid algorithm
for (int i=0; i< _savePoints.size(); i++)
{
if (fabs(curtime - _savePoints[i]) < _tol)
{
printf("saving file: \n");
return true;
}
}
return false;
}
StepwiseBeginTimeManager::StepwiseBeginTimeManager(int nstepArchBegin):TimeManager(),_nstepArchBegin(nstepArchBegin){}
bool StepwiseBeginTimeManager::willArchive(double curtime, int numstep) const
{
if (numstep > _nstepArchBegin)
{
printf("saving file: \n");
return true;
} else {
return false;
}
}
pathFollowingManager::pathFollowingManager():
_pathFollowingMethod(GLOBAL_ARC_LENGTH_BASED),
_controlTypePathFollowing(-1),
_correctionMethodPathFollowing(-1),
_tranversalCriterionPathFollowing(-1),
_solverTypePathFollowing(-1),
_pathFollowingEqRatio(1.),
_switchedControlType(false),
_pathFollowingSwitchCriterion(0.),
_pathFollowingIncrementType(DISSIPATION_ENERGY),
_pathFollowingLocation(BULK_INTERFACE),
_localStep(0.),
_localStepPrev(0.),
_localStepMinimal(0.),
_localStepMaximal(1e100),
_arcLengthStep(0.),
_arcLengthStepPrev(0.),
_arcLengthStepMinimal(0.),
_arcLengthStepMaximal(1e100),
_pfStepAdaptation(false),
_numNROptimal(0),
_expNROptimal(0.),
_numNROptimalLocal(0)
{}
pathFollowingManager::pathFollowingManager(const pathFollowingManager &src)
{
_pathFollowingMethod = src._pathFollowingMethod;
// if _pathFollowingMethod=GLOBAL_ARC_LENGTH_BASED or HYPERELLIPTIC_BASED is used,
_controlTypePathFollowing = src._controlTypePathFollowing; // control type
_correctionMethodPathFollowing = src._correctionMethodPathFollowing; // correction method
_tranversalCriterionPathFollowing = src._tranversalCriterionPathFollowing; // method to correctly estimate load paramater in the predictor of path following constrain as two solutions exists
_solverTypePathFollowing = src._solverTypePathFollowing; // solve method two use,
_pathFollowingEqRatio = src._pathFollowingEqRatio; // equa ratio
_hyperellipticControlComp = src._hyperellipticControlComp; // comp used in hyperelliptic control
//
// if _pathFollowingMethod = LOCAL_BASED
//bool _switchedControlType;
_pathFollowingSwitchCriterion = src._pathFollowingSwitchCriterion;
_pathFollowingIncrementType = src._pathFollowingIncrementType;
_pathFollowingLocation = src._pathFollowingLocation;
//
/*TIME STEP AND PATHFOLLOWING STEP MANAGEMENT*/
// for path following increment (arc-length or local == dissipation increment)
_localStep = src._localStep; // to local cr control
_localStepPrev = src._localStepPrev;
_localStepMinimal = src._localStepMinimal;
_localStepMaximal = src._localStepMaximal;
_arcLengthStep = src._arcLengthStep; // for arc-length control
_arcLengthStepPrev = src._arcLengthStepPrev;
_arcLengthStepMinimal = src._arcLengthStepMinimal;
_arcLengthStepMaximal = src._arcLengthStepMaximal;
_pfStepAdaptation = src._pfStepAdaptation;
_numNROptimal = src._numNROptimal;
_expNROptimal = src._expNROptimal;
_numNROptimalLocal = src._numNROptimalLocal;
}
pathFollowingManager& pathFollowingManager::operator = (const pathFollowingManager &src)
{
//_pathFollowingMethod holds the method of path following, 0- GLOBAL_ARC_LENGTH_BASED , 1 - LOCAL_BASED, and 2- HYPERELLIPTIC_BASED
//GLOBAL_ARC_LENGTH_BASED based on the general path following constraint type
//
//LOCAL_BASED is a combination of LOAD CONTROL+ DISSIPATION CONTROL after the onset of dissipation
//
//HYPERELLIPTIC_BASED uses several particular DOFs insteads of all DOF used in GLOBAL_ARC_LENGTH_BASED to build the path following constraint
//
_pathFollowingMethod = src._pathFollowingMethod;
// if _pathFollowingMethod=GLOBAL_ARC_LENGTH_BASED or HYPERELLIPTIC_BASED is used,
_controlTypePathFollowing = src._controlTypePathFollowing; // control type
_correctionMethodPathFollowing = src._correctionMethodPathFollowing; // correction method
_tranversalCriterionPathFollowing = src._tranversalCriterionPathFollowing; // method to correctly estimate load paramater in the predictor of path following constrain as two solutions exists
_solverTypePathFollowing = src._solverTypePathFollowing; // solve method two use,
_pathFollowingEqRatio = src._pathFollowingEqRatio; // equa ratio
_hyperellipticControlComp = src._hyperellipticControlComp; // comp used in hyperelliptic control
//
// if _pathFollowingMethod = LOCAL_BASED
//bool _switchedControlType;
_pathFollowingSwitchCriterion = src._pathFollowingSwitchCriterion;
_pathFollowingIncrementType = src._pathFollowingIncrementType;
_pathFollowingLocation = src._pathFollowingLocation;
//
/*TIME STEP AND PATHFOLLOWING STEP MANAGEMENT*/
// for path following increment (arc-length or local == dissipation increment)
_localStep = src._localStep; // to local cr control
_localStepPrev = src._localStepPrev;
_localStepMinimal = src._localStepMinimal;
_localStepMaximal = src._localStepMaximal;
_arcLengthStep = src._arcLengthStep; // for arc-length control
_arcLengthStepPrev = src._arcLengthStepPrev;
_arcLengthStepMinimal = src._arcLengthStepMinimal;
_arcLengthStepMaximal = src._arcLengthStepMaximal;
_pfStepAdaptation = src._pfStepAdaptation;
_numNROptimal = src._numNROptimal;
_expNROptimal = src._expNROptimal;
_numNROptimalLocal = src._numNROptimalLocal;
return *this;
};
void pathFollowingManager::reducePathFollowingStep(const TimeManager* tm)
{
// update data for next solve in case of path following
if (_pathFollowingMethod == LOCAL_BASED )
{
if (!_switchedControlType)
{
_arcLengthStep /= tm->_timeStepFactorReduction;
Msg::Info("Reduced path following step step = %e",_arcLengthStep);
}
else
{
_localStep /= tm->_timeStepFactorReduction;
Msg::Info("Reduced path following step step = %e",_localStep);
}
}
else if (_pathFollowingMethod == GLOBAL_ARC_LENGTH_BASED or _pathFollowingMethod == HYPERELLIPTIC_BASED)
{
_arcLengthStep /= tm->_timeStepFactorReduction;
Msg::Info("Reduced path following step step = %e",_arcLengthStep);
}
else
Msg::Error("missing case nonLinearMechSolver::oneStepPreSolvePathFollowing");
}
double pathFollowingManager::getCurrentPathFollowingIncrement() const
{
double currentPathFollowingIncr = 0;
if (_pathFollowingMethod == LOCAL_BASED )
{
if (!_switchedControlType)
{
currentPathFollowingIncr = _arcLengthStep;
}
else
{
currentPathFollowingIncr = _localStep;
}
}
else if (_pathFollowingMethod == GLOBAL_ARC_LENGTH_BASED or _pathFollowingMethod == HYPERELLIPTIC_BASED)
{
currentPathFollowingIncr = _arcLengthStep;
}
else
Msg::Error("missing case nonLinearMechSolver::oneStepPreSolvePathFollowing");
return currentPathFollowingIncr;
};
void pathFollowingManager::computePathFollowingIncrementForNextSolving(const nonLinearMechSolver* solver, int niteNR, const TimeManager* tm)
{
// update data for next solve in case of path following
if (_pathFollowingMethod == LOCAL_BASED )
{
// local control always starts with load control
if (!_switchedControlType)
{
if (solver->localPathFollowingSwitching())
{
Msg::Info("local control is switched in next solve");
_switchedControlType = true;
}
}
if (_pfStepAdaptation)
{
if (!_switchedControlType)
{
_arcLengthStep = _arcLengthStepPrev*pow((double)_numNROptimal/(double)niteNR,_expNROptimal);
}
else
{
_localStep = _localStepPrev*pow((double)_numNROptimalLocal/(double)niteNR,_expNROptimal);
// check if local step is out of range
if (_localStep < _localStepMinimal) _localStep = _localStepMinimal;
else if (_localStep > _localStepMaximal) _localStep = _localStepMaximal;
}
}
else
{
// increase time step due to reduce time step because of the solver fail
if(tm->_timeStepIncreaseBecauseOfSolverFailure) // increase time step if convergence in a few iteration
{
if (!_switchedControlType)
{
_arcLengthStep *= tm->_timeStepFactorReduction;
}
else
{
_localStep *= tm->_timeStepFactorReduction;
}
}
}
}
else if (_pathFollowingMethod == GLOBAL_ARC_LENGTH_BASED or _pathFollowingMethod == HYPERELLIPTIC_BASED)
{
if (_pfStepAdaptation)
{
_arcLengthStep = _arcLengthStepPrev*pow((double)_numNROptimal/(double)niteNR,_expNROptimal);
if (_arcLengthStep < _arcLengthStepMinimal) _arcLengthStep = _arcLengthStepMinimal;
else if (_arcLengthStep > _arcLengthStepMaximal) _arcLengthStep = _arcLengthStepMaximal;
}
else
{
// increase time step due to reduce time step because of the solver fail
if(tm->_timeStepIncreaseBecauseOfSolverFailure) // increase time step if convergence in a few iteration
{
_arcLengthStep *=tm->_timeStepFactorReduction;
}
}
}
else
Msg::Error("missing case nonLinearMechSolver::oneStepPreSolvePathFollowing");
}
void pathFollowingManager::saveIncrementHistory(const nonLinearMechSolver* solver)
{
if ((_pathFollowingMethod == LOCAL_BASED) && (!_switchedControlType) && _pfStepAdaptation)
{
// compute local step
_localStep = solver->computeLocalPathFollowingStep();
}
_localStepPrev = _localStep;
_arcLengthStepPrev = _arcLengthStep;
}
void pathFollowingManager::restart()
{
//restartManager::restart(_pathFollowing); // true if considering pathFollowing
//int _macroControlTypePathFollowing;
//int _correctionMethodPathFollowing;
//int _tranversalCriterionPathFollowing;
//int _solverTypePathFollowing;
//double _pathFollowingEqRatio;
//pathFollowingMethod _pathFollowingMethod; // 0- arclength based, 1 -
restartManager::restart(_localStep); // to local cr control
restartManager::restart(_localStepPrev); // to local cr control
//double _localStepMinimal;
//double _localStepMaximal;
restartManager::restart(_arcLengthStep); // for arc-length control
restartManager::restart(_arcLengthStepPrev); // previous
//double _pathFollowingSwitchCriterion;
restartManager::restart(_switchedControlType);
//pathFollowingLocalIncrementType _pathFollowingIncrementType;
//pathFollowingLocation _pathFollowingLocation;
};
NLS_MPI::NLS_MPI()
{
#if defined(HAVE_MPI)
int flag;
MPI_Initialized(&flag);
if(!flag) MPI_Init(NULL, NULL);
MPI_Comm_rank(MPI_COMM_WORLD, &commRank);
MPI_Comm_size(MPI_COMM_WORLD, &commSize);
MPI_Comm_set_errhandler(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
#endif
};
void NLS_MPI::Init()
{
#if defined(HAVE_MPI)
int flag;
MPI_Initialized(&flag);
if(!flag) MPI_Init(NULL, NULL);
MPI_Comm_rank(MPI_COMM_WORLD, &commRank);
MPI_Comm_size(MPI_COMM_WORLD, &commSize);
MPI_Comm_set_errhandler(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
#endif
}
int NLS_MPI::commRank = 0;
int NLS_MPI::commSize = 1;
int NLS_MPI::GetCommSize() {return commSize;}
int NLS_MPI::GetCommRank() {return commRank;}
void NLS_MPI::Barrier()
{
#if defined(HAVE_MPI)
MPI_Barrier(MPI_COMM_WORLD);
#endif
}
void NLS_MPI::Finalize()
{
#if defined(HAVE_MPI)
int finalized;
MPI_Finalized(&finalized);
if (!finalized)
MPI_Finalize();
#endif
};
StiffnessModificationMonitoring::StiffnessModificationMonitoring(int ws)
{
if (ws == 0)
{
_ws = IPStateBase::previous;
Msg::Info("tangent of the previous converged solution is used");
}
else if (ws=1)
{
_ws = IPStateBase::current;
Msg::Info("first iteration tangent of the current solution is used");
}
else
{
Msg::Error("ws = %s wrong, this value must be 0 or 1",ws);
}
}
TimeBasedStiffnessModificationMonitoring::TimeBasedStiffnessModificationMonitoring(int ws) : StiffnessModificationMonitoring(ws)
{
_modificationAtTime.push_back(0.);
};
TimeBasedStiffnessModificationMonitoring::TimeBasedStiffnessModificationMonitoring(const TimeBasedStiffnessModificationMonitoring& src):
StiffnessModificationMonitoring(src),_modificationAtTime(src._modificationAtTime){};
TimeBasedStiffnessModificationMonitoring::~TimeBasedStiffnessModificationMonitoring(){}
void TimeBasedStiffnessModificationMonitoring::modifyStiffnessAtTime(double t)
{
_modificationAtTime.push_back(t);
}
bool TimeBasedStiffnessModificationMonitoring::willModify(int iter, double time) const
{
// check validity
double tol = 1e-6;
for (int i=0; i< _modificationAtTime.size(); i++)
{
if (fabs(time-_modificationAtTime[i]) < tol*fabs(_modificationAtTime[i]))
{
Msg::Info("stiffness will be modified");
return true;
}
}
return false;
};
NumIterationBasedStiffnessModificationMonitoring::NumIterationBasedStiffnessModificationMonitoring(int ws) :
StiffnessModificationMonitoring(ws),
_numIterBetweenTwoModfication(0)
{
_modificationAtIteration.push_back(0);
};
NumIterationBasedStiffnessModificationMonitoring::NumIterationBasedStiffnessModificationMonitoring(const NumIterationBasedStiffnessModificationMonitoring& src):
StiffnessModificationMonitoring(src),_modificationAtIteration(src._modificationAtIteration), _numIterBetweenTwoModfication(src._numIterBetweenTwoModfication){};
NumIterationBasedStiffnessModificationMonitoring::~NumIterationBasedStiffnessModificationMonitoring(){}
void NumIterationBasedStiffnessModificationMonitoring::modifyStiffnessAfterNumIterations(int numIterBetween)
{
_numIterBetweenTwoModfication = numIterBetween;
Msg::Info("stiffness will be modified each %d iterations ",_numIterBetweenTwoModfication);
}
void NumIterationBasedStiffnessModificationMonitoring::modifyStiffnessAtIteration(int iter)
{
_modificationAtIteration.push_back(iter);
}
bool NumIterationBasedStiffnessModificationMonitoring::willModify(int iter, double time) const
{
// check validity
double tol = 1e-6;
for (int i=0; i< _modificationAtIteration.size(); i++)
{
if (fabs(time-(double)_modificationAtIteration[i]) < tol*fabs((double)_modificationAtIteration[i]))
{
Msg::Info("stiffness will be modified");
return true;
}
}
if (_numIterBetweenTwoModfication > 0)
{
if (iter%_numIterBetweenTwoModfication == 0)
{
Msg::Info("stiffness will be modified");
return true;
}
}
return false;
};
nonLinearMechSolver::nonLinearMechSolver(int tag) :
pModel(NULL),
_dim(0),
_tag(tag),
_mpiUserDom(0),
_workingRank(0),
_isPartitioned(false),
_mapRanks(),
_meshFileName(""),
_timeManager(new TimeManager()),
_solver_options(""),
_GmshOneLabViewNum(0),
pAssembler(NULL),
_ipf(NULL),
_ufield(NULL),
_energField(NULL),
whatSolver(Petsc),
whatScheme(StaticLinear),
_explicitOpts(),
_tol(1.e-6),
_absTol(1.e-12),
_stiffEstimation(true),
_stiffnessModification(true),
_stiffnessModificationMonitoring(NULL),
_iterativeNR(true),
_lineSearch(false),
_implicitOpts(),
_pathFollowing(false),
_pfManager(),
_restartMshFileName("restart_"),
_resetRestart(false),
_disableResetRestart(false),
_crackTrackingName(""),
_crackTrackingFile(NULL),
_fragmentationName(""),
_fragmentationFile(NULL),
_energyComputation(1),
_fractureEnergyComputation(0),
nsba(0),
_collection(NULL),
_previousInit(false),
_notResetedBC(false),
_notResetedContact(false),
_strainMap(NULL),
_endSchemeMonitoringObject(NULL),
_selectiveObject(NULL),
_bulkElementErosionFlag(false),
_interfaceElementErosionFlag(false),
_erosionType(ALL_IP_FAILED),
_erosionGlobalCriterion(NULL),
_eigOpts(),
_isWriteDeformedMeshToFile(false),
_enumMinus(0),
_enumPlus(0),
_gnum(0),
_sucessMicroSolve(false),
_macroTime(1.),
_macroTimeStep(1.),
_macroStep(1),
_systemType(MULT_ELIM),
_controlType(LOAD_CONTROL),
_microFlag(false),
_multiscaleFlag(false),
_microBC(NULL),
_microBCOld(NULL),
_microFailureBC(NULL),
_stressflag(true),
_tangentflag(false),
_homogenizeStressMethod(VOLUME),
_homogenizeTangentMethod(PERTURB),
_sameStateCriterion(1e-8),
_archive(true),
_isHommProSaveToFile(true),
_isHommStrainSaveToFile(true),
_extractPerturbationToFile(false),
_messageView(false),
_tangentPerturbation(1.e-8),
_rho(0.),
_rveVolume(0.),
_rveGeoInertia(0.),
_rveGeometry(0.),
_currentState(NULL),
_initialState(NULL),
_elasticState(NULL),
_pAl(NULL),
_condensation(NULL),
_homogenizedFiles(NULL),
_outputFile(NULL),
_testFlag(false),
_pbcGroup(NULL),
_batchComputations(false),
_damageIsBlocked(false),
_solverIsBroken(false),
_maximalLostEllipticityCriterion(-1.),
_homogenizedCrackSurface(0.),
_failureBCIsSwitched(false),
_failureBasedOnPreviousState(true),
_GModelIsRotated(false),
_checkFailureOnset(false),
_checkWithNormal(true),
_damageToCohesiveJump(false),
_RVELengthInCohesiveNormal(1.),
_surfaceReductionRatio(1.),
_lostSolutionUniquenssTolerance(0.),
_voidPartInLocalizationBand(0.),
_extractIrreversibleEnergy(false),
_FdamOnset(0.),
_lostSolutionUniquenssNormal(0.,0.,0.),
_homogenizedStressLastActiveDissipation(0.),
_homogenizedStrainLastActiveDissipation(0.),
_homogenizedDissipationStrainLastActiveDissipation(0.),
_homogenizedCohesiveJumpLastActiveDissipation(0.),
_extractElasticTangentOperator(false),
_elasticDPDFTangentFile(NULL)
{
_isPartitioned = false;
#if defined(HAVE_MPI)
_workingRank = Msg::GetCommRank();
#else
_workingRank = 0;
#endif //HAVE_MPI
// default view (displacement)
unknownView.emplace_back("displacement",0,nlsField::crude,0,nlsField::val,1);
// initialize c++ function rand (already made in gmsh ?? put elsewhere ??)
_beginTime = time(NULL);
srand(_beginTime);
restartManager::Init(2000000000);
std::ostringstream oss;
oss << Msg::GetCommRank();
std::string srank = oss.str();
_restartMshFileName += oss.str() + ".msh";
_pfManager._hyperellipticControlComp.resize(3);
_pfManager._hyperellipticControlComp[0] =0;
_pfManager._hyperellipticControlComp[1] =1;
_pfManager._hyperellipticControlComp[2] =2;
}
nonLinearMechSolver::~nonLinearMechSolver(){
if (pModel) delete pModel;
if (pAssembler) delete pAssembler;
if(_ipf != NULL) delete _ipf;
if (_ufield) delete _ufield;
if (_energField) delete _energField;
if (_collection) delete _collection;
if (_timeManager) delete _timeManager;
if (_crackTrackingFile != NULL) fclose(_crackTrackingFile);
if (_fragmentationFile != NULL) fclose(_fragmentationFile);
if (_strainMap) delete _strainMap;
if (_endSchemeMonitoringObject != NULL) delete _endSchemeMonitoringObject;
if (_selectiveObject) delete _selectiveObject;
if (_erosionGlobalCriterion!=NULL){
delete _erosionGlobalCriterion;
}
if (_stiffnessModificationMonitoring!=NULL)
{
delete _stiffnessModificationMonitoring;
}
if (_microBC){
delete _microBC;
_microBC = NULL;
}
if (_microBCOld) delete _microBCOld;
if (_microFailureBC) delete _microFailureBC;
this->resetBoundaryConditions();
this->resetContactInteraction();
if (_pAl) delete _pAl;
if (_condensation) delete _condensation;
if (_pbcGroup != NULL) delete _pbcGroup;
if (_homogenizedFiles !=NULL)
{
_homogenizedFiles->closeFiles();
delete _homogenizedFiles;
}
if (_elasticDPDFTangentFile) {fclose(_elasticDPDFTangentFile); _elasticDPDFTangentFile = NULL;};
if (_initialState) {delete _initialState;}
if (_currentState) {delete _currentState;}
if (_elasticState) {delete _elasticState;};
if (_outputFile != NULL) fclose(_outputFile);
if((!_microFlag) && (!_batchComputations)) // only on the master solver? -->ok, we need to pass once only to finish everything (PETSc, SLEPc, ...)
Msg::Exit(0);
}
nonLinearMechSolver::nonLinearMechSolver(const nonLinearMechSolver& src):
_dim(src._dim), _tag(src._tag),
_mpiUserDom(src._mpiUserDom),
_workingRank(src._workingRank), // current working rank
_isPartitioned(src._isPartitioned), // true if FE mesh is partitioned
// the mapRank is created from number of proc available and number of mesh partion,
_mapRanks(),
_meshFileName(""), // To transfert the mesh file from one folder to an other one
_timeManager(new TimeManager()),
// user solver option given as a string
_solver_options(src._solver_options),
// For Onelab display
_GmshOneLabViewNum(src._GmshOneLabViewNum),
pAssembler(NULL),
_ipf(NULL),
_ufield(NULL),
_energField(NULL),
whatSolver(Petsc),
whatScheme(StaticLinear),
_tol(1.e-6),
_absTol(1.e-12),
_stiffEstimation(true),
_stiffnessModification(true),
_stiffnessModificationMonitoring(NULL),
_iterativeNR(true),
_lineSearch(false),
_implicitOpts(),
_pathFollowing(false),
_pfManager(),
_restartMshFileName("restart_"),
_resetRestart(false),
_disableResetRestart(false),
_crackTrackingName(""),
_crackTrackingFile(NULL),
_fragmentationName(""),
_fragmentationFile(NULL),
_energyComputation(1),
_fractureEnergyComputation(0),
nsba(0),
_collection(NULL),
_previousInit(false),
_notResetedBC(false),
_notResetedContact(false),
_strainMap(NULL),
_endSchemeMonitoringObject(NULL),
_selectiveObject(NULL),
_bulkElementErosionFlag(false),
_interfaceElementErosionFlag(false),
_erosionType(ALL_IP_FAILED),
_erosionGlobalCriterion(NULL),
_eigOpts(),
_isWriteDeformedMeshToFile(false),
_enumMinus(0),
_enumPlus(0),
_gnum(0),
_sucessMicroSolve(false),
_macroTime(1.),
_macroTimeStep(1.),
_macroStep(1),
_systemType(MULT_ELIM),
_controlType(LOAD_CONTROL),
_microFlag(false),
_multiscaleFlag(false),
_microBC(NULL),
_microBCOld(NULL),
_microFailureBC(NULL),
_stressflag(true),
_tangentflag(false),
_homogenizeStressMethod(VOLUME),
_homogenizeTangentMethod(PERTURB),
_sameStateCriterion(1e-8),
_archive(true),
_isHommProSaveToFile(true),
_isHommStrainSaveToFile(true),
_extractPerturbationToFile(false),
_messageView(false),
_tangentPerturbation(1.e-8),
_rho(0.),
_rveVolume(0.),
_rveGeoInertia(0.),
_rveGeometry(0.),
_currentState(NULL),
_initialState(NULL),
_elasticState(NULL),
_pAl(NULL),
_condensation(NULL),
_homogenizedFiles(NULL),
_outputFile(NULL),
_testFlag(false),
_pbcGroup(NULL),
_batchComputations(false),
_damageIsBlocked(false),
_solverIsBroken(false),
_maximalLostEllipticityCriterion(-1.),
_homogenizedCrackSurface(0.),
_failureBCIsSwitched(false),
_failureBasedOnPreviousState(true),
_GModelIsRotated(false),
_checkFailureOnset(false),
_checkWithNormal(true),
_damageToCohesiveJump(false),
_RVELengthInCohesiveNormal(1.),
_surfaceReductionRatio(1.),
_lostSolutionUniquenssTolerance(0.),
_voidPartInLocalizationBand(0.),
_extractIrreversibleEnergy(false),
_FdamOnset(0.),
_lostSolutionUniquenssNormal(0.,0.,0.),
_homogenizedStressLastActiveDissipation(0.),
_homogenizedStrainLastActiveDissipation(0.),
_homogenizedDissipationStrainLastActiveDissipation(0.),
_homogenizedCohesiveJumpLastActiveDissipation(0.),
_extractElasticTangentOperator(false),
_elasticDPDFTangentFile(NULL)
{
src.copyOptionsToOtherSolver(this);
loadModel(src._meshFileName);
// domain
for (int i=0; i<src.domainVector.size(); i++)
{
const partDomain* dom = src.domainVector[i];
const dgPartDomain* dgdom = dynamic_cast<const dgPartDomain*>(dom);
bool add=false;
if (dgdom)
{
add = true;
if (dom->elementGroupSize() ==0 and (dgdom->getPlusDomain()->getPhysical() == dgdom->getMinusDomain()->getPhysical()))
{
add = false;
}
}
else
{
add = true;
}
if (add)
{
addDomain(src.domainVector[i]->clone());
}
};
// material law
for (std::map<int,materialLaw*>::const_iterator it = src.maplaw.begin(); it!= src.maplaw.end(); it++)
{
addMaterialLaw(it->second->clone());
}
src.copyBCsToOtherSolver(this);
};
void nonLinearMechSolver::transferIPField(nonLinearMechSolver* other, const IPDataTransfer& datatransfer)
{
if (!(this->isInitialized()))
{
Msg::Warning("Solver is not yet initialized");
if (this->getScheme() == StaticLinear)
{
this->init();
this->init2();
}
else if (this->getScheme() == StaticNonLinear)
{
this->initializeStaticScheme();
}
else if (this->getScheme() == Implicit)
{
this->initializeStaticScheme();
}
else if (this->getScheme() == Explicit)
{
this->initializeExplicitScheme();
}
else if (this->getScheme() == Multi)
{
this->init();
this->init2();
}
else
{
Msg::Error("solverType %d has not implemented",this->getScheme());
}
}
IPField* srcIPF = other->getIPField();
IPField* destIPF = this->getIPField();
for (int idom = 0; idom < domainVector.size(); idom ++)
{
// for bulk
partDomain* dom = domainVector[idom];
if (dom->getFormulation())
{
Msg::Error("DG domain has not been implemented, please complete !!!");
Msg::Exit(0);
}
int phys = dom->getPhysical();
if (datatransfer.withTranfer(phys))
{
for (elementGroup::elementContainer::const_iterator ite = dom->element_begin(); ite != dom->element_end(); ite++)
{
int eleNum = ite->second->getNum();
AllIPState::ipstateElementContainer& srcIPs = *(srcIPF->getAips()->getIPstate(eleNum));
AllIPState::ipstateElementContainer& destIPs = *(destIPF->getAips()->getIPstate(eleNum));
if (srcIPs.size() != destIPs.size())
{
Msg::Error("two ipstates are not compatible in element %d",eleNum);
Msg::Exit(0);
}
else
{
int Numstate = srcIPs.size();
for (int j=0; j< Numstate; j++)
{
IPStateBase* src = srcIPs[j];
IPStateBase* dest = destIPs[j];
std::vector<IPVariable*> allIPsrc, allIPdest;
src->getAllIPVariable(allIPsrc);
dest->getAllIPVariable(allIPdest);
if (allIPsrc.size() != allIPdest.size())
{
Msg::Error("two ipstate is not compatible ele %d gp %d",eleNum,j);
Msg::Exit(0);
}
else
{
for (int k=0; k< allIPsrc.size(); k++)
{
datatransfer.transferDataIPv(phys, allIPsrc[k],allIPdest[k]);
}
}
}
}
}
}
}
};
nonLinearMechSolver* nonLinearMechSolver::clone(const std::string mshFile, int tag) const
{
nonLinearMechSolver* sv = new nonLinearMechSolver(tag);
// avoid douplicate views
sv->unknownView.clear();
//
copyOptionsToOtherSolver(sv);
// load model
sv->loadModel(mshFile);
// domain
for (int i=0; i<domainVector.size(); i++)
{
const partDomain* dom = domainVector[i];
const dgPartDomain* dgdom = dynamic_cast<const dgPartDomain*>(dom);
bool add=false;
if (dgdom)
{
add = true;
if (dom->elementGroupSize() ==0 and (dgdom->getPlusDomain()->getPhysical() == dgdom->getMinusDomain()->getPhysical()))
{
add = false;
}
}
else
{
add = true;
}
if (add)
{
sv->addDomain(domainVector[i]->clone());
}
};
// material law
for (std::map<int,materialLaw*>::const_iterator it = maplaw.begin(); it!= maplaw.end(); it++)
{
sv->addMaterialLaw(it->second->clone());
}
copyBCsToOtherSolver(sv);
return sv;
};
nonLinearMechSolver* nonLinearMechSolver::clone(int tag,
const std::string mshFile,
std::vector<partDomain*>& allDom,
std::vector<materialLaw*>& allMat) const
{
nonLinearMechSolver* sv = new nonLinearMechSolver(tag);
//
// avoid douplicate views
sv->unknownView.clear();
//
copyOptionsToOtherSolver(sv);
sv->loadModel(mshFile);
// domain
for (int i=0; i<allDom.size(); i++)
{
sv->addDomain(allDom[i]);
};
// material law
for (int i=0; i< allMat.size(); i++)
{
sv->addMaterialLaw(allMat[i]);
}
copyBCsToOtherSolver(sv);
return sv;
}
void nonLinearMechSolver::copyOptionsToOtherSolver(nonLinearMechSolver* sv) const
{
sv->whatSolver = whatSolver; // Solver used to solve
sv->whatScheme = whatScheme; // scheme used to solve equation
//
// get all Options
/*TIME SETTING FOR NONLINEAR SOLVER*/
if (sv->_timeManager) delete sv->_timeManager;
sv->_timeManager = _timeManager->clone();
/*FOR EXPLICIT SCHEME*/
sv->_explicitOpts = _explicitOpts;
/* FOR MULTI SYSTEM */
/* MultiSystems solve */
sv->_vcompBySys = _vcompBySys;
sv->_vschemeBySys = _vschemeBySys;
/*FOR QUASI-STATIC AND IMPLICIT SCHEMES*/
sv->_tol = _tol;
sv->_absTol = _absTol; // relative and absolute tolerance for iteration
//sv->_stiffEstimation = _stiffEstimation;
sv->_stiffnessModification = _stiffnessModification; // true if recalculate stiffness matrix
if (_stiffnessModificationMonitoring!=NULL)
{
sv->_stiffnessModificationMonitoring =_stiffnessModificationMonitoring->clone();
}
sv->_iterativeNR = _iterativeNR; // true if using iterative procedure
sv->_lineSearch = _lineSearch;
/*FOR CH DYNAMIC SCHEME*/
sv->_implicitOpts = _implicitOpts;
/*FOR PATH FOLLOWING*/
sv->_pathFollowing = _pathFollowing; // true to activate path following
sv->_pfManager = _pfManager;
//
/* data for restart */
//size_t _beginTime;
//std::string _restartMshFileName;
//bool _resetRestart; //to avoid restart when shitfing schemes
//bool _disableResetRestart; //to allow restat in battery only
/*FOR CRACK*/
// physical entities that are initialy broken
sv->initbrokeninter = initbrokeninter;
sv->initbrokeninterInDomains = initbrokeninterInDomains;
/* crack tracking */
//FILE *_crackTrackingFile; // name of files for crack tracking no name == NULL and no track
if (_crackTrackingFile!=NULL)
{
sv->crackTracking(_crackTrackingName);
}
/* fragmentation */
//FILE *_fragmentationFile;
if (_fragmentationFile!=NULL)
{
sv->postproFragment(_fragmentationName);
}
/* FOR ARCHIVING*/
// archivng internal force at nodes
//std::list<archiveInternalForce> vafIntenal;
for (std::list<archiveInternalForce>::const_iterator it = vafIntenal.begin(); it!= vafIntenal.end(); it++)
{
const archiveInternalForce& ar = *it;
sv->vafIntenal.emplace_back(ar.phys,ar.dim,ar.nstep);
}
// std vector to archive a node displacement
//std::vector<unknownField::archiveNode> anoded;
for (std::vector<unknownField::archiveNode>::const_iterator it = anoded.begin(); it != anoded.end(); it++)
{
const unknownField::archiveNode& ar = *it;
sv->anoded.emplace_back(ar.physnum,ar.nodenum,ar._comp,ar.wc,ar.nstep);
};
// std::vector to archive a force
//std::vector<archiveForce> vaf;
for (std::vector<archiveForce>::const_iterator it = vaf.begin(); it != vaf.end(); it++)
{
const archiveForce& ar = *it;
sv->vaf.emplace_back(ar.numphys,ar.dim,ar.comp,ar.nstep);
};
// std vector to archive ipvariable
//std::vector<IPField::ip2archive> vaip;
for (std::vector<IPField::ip2archive>::const_iterator it = vaip.begin(); it != vaip.end(); it++)
{
const IPField::ip2archive& ar = *it;
sv->vaip.emplace_back(ar);
}
// list to archive the integral operation in volume
//std::list<IntegralVolume> _dataVolumeIntegral;
for (std::list<IntegralVolume>::const_iterator it = _dataVolumeIntegral.begin(); it!=_dataVolumeIntegral.end(); it++)
{
const IntegralVolume& ar = *it;
sv->_dataVolumeIntegral.emplace_back(ar.integType,ar.ipVal,ar.physical,ar.nbArch);
}
//std::list<clustersData> _clusterData;
for (std::list<clustersData>::const_iterator it = _clusterData.begin(); it!= _clusterData.end(); it++)
{
sv->loadClustersDataFile(it->clusterDataFileName);
}
//std::list<AvergageCluster> _averageClusters;
for (std::list<AvergageCluster>::const_iterator it = _averageClusters.begin(); it != _averageClusters.end(); it++)
{
const AvergageCluster& ar = *it;
sv->_averageClusters.emplace_back(ar.ipVal,ar.nbArch);
}
// list to archive IP data over physical (data at gauss point with coordinates)
//std::list<IPDataOnPhysical> _dataOnPhysical;
// for archiving energy and fracture energy
sv->_energyComputation = _energyComputation; // equal to 0 if no energy is saved; >0 if energy is saved with _energyComputation as interval step of archiving
sv->_fractureEnergyComputation = _fractureEnergyComputation; // equal to 0 if no energy is saved; >0 if energy is saved with _energyComputation as interval step of archiving
/*FOR VIEW*/
// view of unknown --> disp file
//std::vector<nlsField::dataBuildView> unknownView;
for (std::vector<nlsField::dataBuildView>::const_iterator it = unknownView.begin(); it!= unknownView.end(); it++)
{
const nlsField::dataBuildView& ar = *it;
sv->unknownView.emplace_back(ar.viewname,ar.comp,ar.ev,ar.gpNum,ar.valtype,ar.nbstepArch);
}
// view of ip field --> stress file
//std::vector<nlsField::dataBuildView> ipView;
for (std::vector<nlsField::dataBuildView>::const_iterator it = ipView.begin(); it!= ipView.end(); it++)
{
const nlsField::dataBuildView& ar = *it;
sv->ipView.emplace_back(ar.viewname,ar.comp,ar.ev,ar.gpNum,ar.valtype,ar.nbstepArch);
}
//std::vector<nlsField::dataBuildView> ipViewInterface;
for (std::vector<nlsField::dataBuildView>::const_iterator it = ipViewInterface.begin(); it!= ipViewInterface.end(); it++)
{
const nlsField::dataBuildView& ar = *it;
sv->ipViewInterface.emplace_back(ar.viewname,ar.comp,ar.ev,ar.gpNum,ar.valtype,ar.nbstepArch);
}
// view of energy field --> energy file, but it is not
//std::vector<nlsField::dataBuildView> energyView;
for (std::vector<nlsField::dataBuildView>::const_iterator it = energyView.begin(); it!= energyView.end(); it++)
{
const nlsField::dataBuildView& ar = *it;
sv->energyView.emplace_back(ar.viewname,ar.comp,ar.ev,ar.gpNum,ar.valtype,ar.nbstepArch);
}
sv->nsba=nsba; // number of step between two view
/* SWITCH scheme data */
//bool _previousInit; // To known if the initialization as already be made by an other scheme
//bool _notResetedBC; // To known if the BC are modified.
//bool _notResetedContact; // To known if the contact interaction are modified
//bool _notResetUnknowns; // To known if the unknowns are modified
// strain mapping for foams
if (_strainMap!=NULL)
{
GModel* pm = GModel::current();
sv->createStrainMapping(_strainMap->getMappingMeshFileName(),_strainMap->getNumStepBetweenTwoSaves());
GModel::setCurrent(pm);
}
// programe monitoring
if (_endSchemeMonitoringObject!=NULL)
{
sv->endSchemeMonitoring(*_endSchemeMonitoringObject);
}
// selective update with cohesive crack
if (_selectiveObject)
{
sv->setSelectiveUpdate(*_selectiveObject);
}
// element erosion control
if (_bulkElementErosionFlag or _interfaceElementErosionFlag)
{
sv->setElementErosion(_bulkElementErosionFlag,_interfaceElementErosionFlag,_erosionType);
}
if (_erosionGlobalCriterion)
{
sv->setGlobalErosionCheck(true,_erosionGlobalCriterion);
}
/*EIGEN SOLVER*/
sv->_eigOpts = _eigOpts;
//std::vector<nlsField::dataBuildView> _eigview;
for (std::vector<nlsField::dataBuildView>::const_iterator it = _eigview.begin(); it!= _eigview.end(); it++)
{
const nlsField::dataBuildView& ar = *it;
sv->_eigview.emplace_back(ar.viewname,ar.comp,ar.ev,ar.gpNum,ar.valtype,ar.nbstepArch);
}
/*DEFORMED MESH TO FILE*/
sv->_isWriteDeformedMeshToFile = _isWriteDeformedMeshToFile; // write deformed mesh to file
/*FOR MULTISCALE ANALYSIS*/
// Element number and Integration point number
sv->_enumMinus = _enumMinus;
sv->_enumPlus = _enumPlus;
sv->_gnum =_gnum;
sv->_sucessMicroSolve = _sucessMicroSolve;
// time and time step
sv->_macroTimeStep = _macroTimeStep; // for law which works on increment. (Use only in so no getTimeStep function)
sv->_macroTime = _macroTime; // To save results vs time
sv->_macroStep = _macroStep; // current macroscopic step
//for micro flag
sv->_systemType = _systemType;
sv->_controlType = _controlType;
// micro flag--> true if microsolver is used
sv->_microFlag = _microFlag;
sv->_multiscaleFlag = _multiscaleFlag; // to know if a multiscale analysis is performed, to be true with both micro and marco solver
//stress flag and tangent flag
sv->_stressflag = _stressflag; // true if homogenized stress is estimated
sv->_tangentflag = _tangentflag; // true if homogenizd tangnent is estimated
// homogenized method
sv->_homogenizeTangentMethod = _homogenizeTangentMethod;
sv->_homogenizeStressMethod = _homogenizeStressMethod;
sv->_sameStateCriterion = _sameStateCriterion; // this parameter to check if same sate-> economise
// for archiving
sv->_archive = _archive;
// all homogenized filename
sv->_isHommProSaveToFile = _isHommProSaveToFile; // flag -->save homogenized properties to files
sv->_isHommStrainSaveToFile = _isHommStrainSaveToFile; //flag --> save homogenized strain to files
sv->_extractPerturbationToFile = _extractPerturbationToFile; //flag --> save perturbation on RVE boundary to file
sv->_messageView = _messageView; // flag to archive message to file
sv->_tangentPerturbation = _tangentPerturbation; // tangent by perturbation
sv->_rho = _rho; // homogenized density
sv->_rveVolume = _rveVolume; // rve volume
sv->_rveGeoInertia = _rveGeoInertia; // rve geometrical inertia
sv->_rveGeometry = _rveGeometry;
sv->_damageIsBlocked = _damageIsBlocked;
sv->_solverIsBroken = _solverIsBroken;
sv->_maximalLostEllipticityCriterion = _maximalLostEllipticityCriterion; // maximal value
sv->_homogenizedCrackSurface = _homogenizedCrackSurface;
//
sv->_failureBCIsSwitched = _failureBCIsSwitched; // true if FailureBC is switsched after failure,
sv->_failureBasedOnPreviousState = _failureBasedOnPreviousState;
sv->_GModelIsRotated = _GModelIsRotated;
sv->_checkFailureOnset = _checkFailureOnset; //
sv->_checkWithNormal = _checkWithNormal; //
sv->_damageToCohesiveJump = _damageToCohesiveJump; // true if extracting cohsive law
sv->_RVELengthInCohesiveNormal = _RVELengthInCohesiveNormal; // length perpendicular to cohesive normal
sv->_surfaceReductionRatio = _surfaceReductionRatio; // load carrying surface over nominal surface following cohesive normal
sv->_lostSolutionUniquenssTolerance = _lostSolutionUniquenssTolerance;
sv->_voidPartInLocalizationBand = _voidPartInLocalizationBand; // void part in localization band
sv->_extractIrreversibleEnergy = _extractIrreversibleEnergy; // flag
//
sv->_extractElasticTangentOperator = _extractElasticTangentOperator; // true if elastic tangent operator is extracted at the same time as full tangent operator
};
void nonLinearMechSolver::copyBCsToOtherSolver(nonLinearMechSolver* sv) const
{
/*FOR CONTACT*/ // TODO
// contact
//contactContainer _allContact;
// defo defo contact BC
//defoDefoContactContainer _allDefoDefoContact;
/*FOR BOUNDARY CONDITIONS*/
// neumann BC
//std::list<nonLinearNeumannBC> allNeumann;
for (std::list<nonLinearNeumannBC>::const_iterator it = allNeumann.begin(); it!=allNeumann.end(); it++)
{
const nonLinearNeumannBC& bc = *it;
sv->allNeumann.emplace_back();
nonLinearNeumannBC& neu = sv->allNeumann.back();
neu.onWhat = bc.onWhat;
neu._tag = bc._tag;
neu._NeumannBCType = bc._NeumannBCType;
neu._f= bc._f;
neu._comp=bc._comp;
if(neu.onWhat==nonLinearBoundaryCondition::ON_VERTEX)
{
neu.g = new elementGroup (0, neu._tag);
}
else if(neu.onWhat==nonLinearBoundaryCondition::ON_EDGE)
{
neu.g = new elementGroup (1, neu._tag);
}
else if(neu.onWhat==nonLinearBoundaryCondition::ON_FACE)
{
neu.g = new elementGroup (2, neu._tag);
}
else if(neu.onWhat==nonLinearBoundaryCondition::ON_FACE_VERTEX)
{
neu.g = new elementGroup(2,neu._tag);
}
else if(neu.onWhat==nonLinearBoundaryCondition::ON_VOLUME)
{
neu.g = new elementGroup (3, neu._tag);
}
}
// dirichlet BC
//std::list<nonLinearDirichletBC> allDirichlet;
for (std::list<nonLinearDirichletBC>::const_iterator it = allDirichlet.begin(); it != allDirichlet.end(); it++)
{
const nonLinearDirichletBC& bc = *it;
sv->allDirichlet.emplace_back();
nonLinearDirichletBC& diri = sv->allDirichlet.back();
diri.onWhat = bc.onWhat;
diri._tag = bc._tag;
diri._comp = bc._comp;
diri._f = bc._f;
diri._mycondition = bc._mycondition;
if(diri.onWhat==nonLinearBoundaryCondition::ON_VERTEX)
{
diri.g = new elementGroup (0, diri._tag);
}
else if(diri.onWhat==nonLinearBoundaryCondition::ON_EDGE)
{
diri.g = new elementGroup (1, diri._tag);
}
else if(diri.onWhat==nonLinearBoundaryCondition::ON_FACE)
{
diri.g = new elementGroup (2, diri._tag);
}
else if(diri.onWhat==nonLinearBoundaryCondition::ON_FACE_VERTEX)
{
diri.g = new elementGroup(2,diri._tag);
}
else if(diri.onWhat==nonLinearBoundaryCondition::ON_VOLUME)
{
diri.g = new elementGroup (3, diri._tag);
}
}
// all periodic groups
//std::list<nonLinearPeriodicBCBetweenTwoGroups> allPeriodic;
sv->_edgePeriodicPhysicals = _edgePeriodicPhysicals;
sv->_nodePeriodicPhysicals = _nodePeriodicPhysicals;
for (std::list<nonLinearPeriodicBCBetweenTwoGroups>::const_iterator it = allPeriodic.begin(); it != allPeriodic.end(); it++)
{
const nonLinearPeriodicBCBetweenTwoGroups& bc = *it;
sv->allPeriodic.emplace_back();
nonLinearPeriodicBCBetweenTwoGroups& pbc = sv->allPeriodic.back();
pbc.onWhat=bc.onWhat;
pbc.phys1 = bc.phys1;
pbc.phys2 = bc.phys2;
pbc.physVer1 = bc.physVer1;
pbc.physVer2 = bc.physVer2;
pbc.comp = bc.comp;
if (pbc.onWhat==nonLinearBoundaryCondition::ON_VERTEX)
{
pbc.g1 = new elementGroup (0, pbc.phys1);
pbc.g2 = new elementGroup (0, pbc.phys2);
}
else if (pbc.onWhat==nonLinearBoundaryCondition::ON_EDGE)
{
pbc.g1 = new elementGroup (1, pbc.phys1);
pbc.g2 = new elementGroup (1, pbc.phys2);
}
else if (pbc.onWhat==nonLinearBoundaryCondition::ON_FACE)
{
pbc.g1 = new elementGroup (2, pbc.phys1);
pbc.g2 = new elementGroup (2, pbc.phys2);
}
if ((pbc.physVer1 > 0) && (pbc.physVer2 >0))
{
elementGroup grv1(0,pbc.physVer1);
elementGroup grv2(0,pbc.physVer2);
if (grv1.vsize() > 0 and grv2.vsize() > 0)
{
pbc.v1 = (grv1.vbegin()->second);
pbc.v2 = (grv2.vbegin()->second);
}
else{
Msg::Error("periodic root vertices have not been correctly defined on cloned solver");
Msg::Exit(0);
}
}
else
{
pbc.v1 = NULL;
pbc.v2 = NULL;
}
}
//all average PBC groups
//std::list<nonLinearAveragePeriodicBCBetweenTwoGroups> allAveragePeriodic;
for (std::list<nonLinearAveragePeriodicBCBetweenTwoGroups>::const_iterator it = allAveragePeriodic.begin(); it != allAveragePeriodic.end(); it++)
{
const nonLinearAveragePeriodicBCBetweenTwoGroups& bc = *it;
sv->allAveragePeriodic.emplace_back();
nonLinearAveragePeriodicBCBetweenTwoGroups& pbc = sv->allAveragePeriodic.back();
pbc.onWhat=bc.onWhat;
pbc.phys1 = bc.phys1;
pbc.phys2 = bc.phys2;
pbc.physVer1 = bc.physVer1;
pbc.physVer2 = bc.physVer2;
pbc.comp = bc.comp;
if (pbc.onWhat==nonLinearBoundaryCondition::ON_EDGE)
{
pbc.g1 = new elementGroup (1, pbc.phys1);
pbc.g2 = new elementGroup (1, pbc.phys2);
}
else if (pbc.onWhat==nonLinearBoundaryCondition::ON_FACE)
{
pbc.g1 = new elementGroup (2, pbc.phys1);
pbc.g2 = new elementGroup (2, pbc.phys2);
}
if ((pbc.physVer1 > 0) && (pbc.physVer2 >0))
{
elementGroup grv1(0,pbc.physVer1);
elementGroup grv2(0,pbc.physVer2);
if (grv1.vsize() > 0 and grv2.vsize() > 0)
{
pbc.v1 = (grv1.vbegin()->second);
pbc.v2 = (grv2.vbegin()->second);
}
else{
Msg::Error("average periodic root vertices have not been correctly defined on cloned solver");
Msg::Exit(0);
}
}
else
{
pbc.v1 = NULL;
pbc.v2 = NULL;
}
}
// all samedisp bc
//std::list<nonLinearSameDisplacementBC> allSameDisp;
for (std::list<nonLinearSameDisplacementBC>::const_iterator it = allSameDisp.begin(); it != allSameDisp.end(); it++)
{
const nonLinearSameDisplacementBC& bc = *it;
sv->allSameDisp.emplace_back();
nonLinearSameDisplacementBC& sameDispBC = sv->allSameDisp.back();
sameDispBC.onWhat = bc.onWhat;
sameDispBC._tag = bc._tag;
sameDispBC.comp = bc.comp;
sameDispBC.tagRoot = bc.tagRoot;
sameDispBC.fac = bc.fac;
sameDispBC.gRoot = new elementGroup(0,sameDispBC.tagRoot);
if(sameDispBC.onWhat==nonLinearBoundaryCondition::ON_VERTEX)
{
sameDispBC.g = new elementGroup(0,sameDispBC._tag);
}
if(sameDispBC.onWhat==nonLinearBoundaryCondition::ON_EDGE)
{
sameDispBC.g = new elementGroup(1,sameDispBC._tag);
}
else if (sameDispBC.onWhat==nonLinearBoundaryCondition::ON_FACE)
{
sameDispBC.g = new elementGroup(2,sameDispBC._tag);
}
else if (sameDispBC.onWhat==nonLinearBoundaryCondition::ON_VOLUME)
{
sameDispBC.g = new elementGroup(3,sameDispBC._tag);
}
}
// fix on face
//std::list<nonLinearFixOnFaceBC> allFixAllFace;
for (std::list<nonLinearFixOnFaceBC>::const_iterator it = allFixAllFace.begin(); it != allFixAllFace.end(); it++)
{
const nonLinearFixOnFaceBC& bc = *it;
sv->allFixAllFace.emplace_back(bc.A,bc.B,bc.C,bc.D);
nonLinearFixOnFaceBC& fixBC = sv->allFixAllFace.back();
fixBC.onWhat = bc.onWhat;
fixBC._tag = bc._tag;
if (fixBC.onWhat == nonLinearBoundaryCondition::ON_VERTEX)
{
fixBC.g = new elementGroup(0,fixBC._tag);
}
else if (fixBC.onWhat == nonLinearBoundaryCondition::ON_EDGE)
{
fixBC.g = new elementGroup(1,fixBC._tag);
}
else if (fixBC.onWhat == nonLinearBoundaryCondition::ON_FACE)
{
fixBC.g = new elementGroup(2,fixBC._tag);
}
else if (fixBC.onWhat == nonLinearBoundaryCondition::ON_VOLUME)
{
fixBC.g = new elementGroup(3,fixBC._tag);
}
}
// constraint BC
//std::list<nonLinearConstraintBC> allConstraint;
for (std::list<nonLinearConstraintBC>::const_iterator it = allConstraint.begin(); it!= allConstraint.end(); it++)
{
const nonLinearConstraintBC& bc = *it;
sv->allConstraint.emplace_back();
nonLinearConstraintBC& uc = sv->allConstraint.back();
uc.onWhat = bc.onWhat;
uc._tag = bc._tag;
uc._comp=bc._comp;
uc._tag=bc._tag;
if (uc.onWhat == nonLinearBoundaryCondition::ON_VERTEX)
{
uc.g = new elementGroup (0, uc._tag);
}
else if (uc.onWhat == nonLinearBoundaryCondition::ON_EDGE)
{
uc.g = new elementGroup (1, uc._tag);
}
else if (uc.onWhat == nonLinearBoundaryCondition::ON_FACE)
{
uc.g = new elementGroup (2, uc._tag);
}
else if (uc.onWhat == nonLinearBoundaryCondition::ON_VOLUME)
{
uc.g = new elementGroup (3, uc._tag);
}
}
// when using with microBC, BC can appy on corners of RVE
//std::list<nonLinearDirichletBCAtCorner> allCornerConstraint;
for (std::list<nonLinearDirichletBCAtCorner>::const_iterator it = allCornerConstraint.begin(); it !=allCornerConstraint.end(); it++)
{
const nonLinearDirichletBCAtCorner& bc = *it;
sv->allCornerConstraint.emplace_back();
nonLinearDirichletBCAtCorner& cornerConstraint = sv->allCornerConstraint.back();
cornerConstraint._tag = bc._tag;
cornerConstraint._comp = bc._comp;
cornerConstraint._cornerNumber = bc._cornerNumber;
cornerConstraint._f = bc._f;
}
// force BC
//std::list<nonLinearNeumannBCAtCorner> allCornerForce;
for (std::list<nonLinearNeumannBCAtCorner>::const_iterator it =allCornerForce.begin(); it != allCornerForce.end(); it++)
{
const nonLinearNeumannBCAtCorner& bc = *it;
sv->allCornerForce.emplace_back();
nonLinearNeumannBCAtCorner& cornerConstraint = sv->allCornerForce.back();
cornerConstraint._tag = bc._tag;
cornerConstraint._comp = bc._comp;
cornerConstraint._cornerNumber = bc._cornerNumber;
cornerConstraint._f = bc._f;
}
// initial BC
//std::list<initialCondition> allinitial;
for (std::list<initialCondition>::const_iterator it = allinitial.begin(); it!= allinitial.end(); it++)
{
const initialCondition& bc = *it;
sv->allinitial.emplace_back(bc._comp,bc._mycondition);
initialCondition& initc = sv->allinitial.back();
initc.onWhat = bc.onWhat;
initc._tag = bc._tag;
initc._f = bc._f;
elementFilterTrivial filter;
initc.g = new elementGroup();
if (initc.onWhat == nonLinearBoundaryCondition::ON_VERTEX)
{
initc.g->addPhysical(0,initc._tag,filter);
}
else if (initc.onWhat == nonLinearBoundaryCondition::ON_EDGE)
{
initc.g->addPhysical(1,initc._tag,filter);
}
else if (initc.onWhat == nonLinearBoundaryCondition::ON_FACE)
{
initc.g->addPhysical(2,initc._tag,filter);
}
else if (initc.onWhat == nonLinearBoundaryCondition::ON_VOLUME)
{
initc.g->addPhysical(3,initc._tag,filter);
}
else if (initc.onWhat == nonLinearBoundaryCondition::RIGIDCONTACT)
{
}
else if (initc.onWhat == nonLinearBoundaryCondition::UNDEF)
{
initc.g->addPhysical(2,initc._tag,filter);
}
}
// neumann BC theta (weak enforcement of rotation) group this with allNeumann ?
//std::list<nonLinearNeumannBC> allTheta;
for (std::list<nonLinearNeumannBC>::const_iterator it = allTheta.begin(); it != allTheta.end(); it++)
{
const nonLinearNeumannBC& bc = *it;
sv->allTheta.emplace_back();
nonLinearNeumannBC& neu = sv->allTheta.back();
neu._tag = bc._tag;
neu._comp = bc._comp;
neu.onWhat = nonLinearBoundaryCondition::UNDEF;
neu.g = new elementGroup(1,neu._tag);
neu._f = bc._f;
}
// dirichlet BC on rigid surface (prescribed the motion of gravity center)
//std::list<rigidContactBC> allContactBC;
for (std::list<rigidContactBC>::const_iterator it = allContactBC.begin(); it != allContactBC.end(); it++)
{
const rigidContactBC& bc = *it;
sv->allContactBC.emplace_back(bc._tag);
rigidContactBC& diri = sv->allContactBC.back();
diri.onWhat = nonLinearBoundaryCondition::RIGIDCONTACT;
diri._comp = bc._comp;
diri._f = bc._f;
};
// general linear constrait BC
//std::list<nonLinearLinearConstraintBCBetweenTwoGroups> allLinearConstraintBC;
for (std::list<nonLinearLinearConstraintBCBetweenTwoGroups>::const_iterator it = allLinearConstraintBC.begin(); it != allLinearConstraintBC.end(); it++)
{
const nonLinearLinearConstraintBCBetweenTwoGroups& oldbc = *it;
sv->allLinearConstraintBC.emplace_back();
nonLinearLinearConstraintBCBetweenTwoGroups& bc = sv->allLinearConstraintBC.back();
bc.onWhat = oldbc.onWhat;
bc.phyMaster = oldbc.phyMaster;
bc.phySlave = oldbc.phySlave;
int physMater = bc.phyMaster;
int physSlave = bc.phySlave;
if(bc.onWhat==nonLinearBoundaryCondition::ON_VERTEX){
bc.gMaster = new elementGroup (0, physMater);
if (physSlave > 0)
bc.gSlave = new elementGroup (0, physSlave);
else
bc.gSlave = new elementGroup ();
}
else if(bc.onWhat==nonLinearBoundaryCondition::ON_EDGE){
bc.gMaster = new elementGroup (1, physMater);
if (physSlave > 0)
bc.gSlave = new elementGroup (1, physSlave);
else
bc.gSlave = new elementGroup ();
}
else if(bc.onWhat==nonLinearBoundaryCondition::ON_FACE){
bc.gMaster = new elementGroup (2, physMater);
if (physSlave > 0)
bc.gSlave = new elementGroup (2, physSlave);
else
bc.gSlave = new elementGroup ();
}
else if(bc.onWhat==nonLinearBoundaryCondition::ON_VOLUME){
bc.gMaster = new elementGroup (3, physMater);
if (physSlave > 0)
bc.gSlave = new elementGroup (3, physSlave);
else
bc.gSlave = new elementGroup ();
}
bc.comp = oldbc.comp;
if (oldbc.rightHandSide !=NULL)
{
bc.rightHandSide = oldbc.rightHandSide->clone();
}
else
{
Msg::Error("linearCombinationOfVertices must be set");
Msg::Exit(0);
}
if (oldbc.vgOperation!=NULL)
{
bc.vgOperation = oldbc.vgOperation->clone();
}
else
{
bc.vgOperation = new vertexGroupOperation_trivial();
}
bc.slaveFactor = oldbc.slaveFactor;
bc.excludedVertices.copyData(oldbc.excludedVertices);
}
//micro BC
if (_microBC)
{
sv->addMicroBC(_microBC);
}
if (_microFailureBC)
{
sv->addMicroBCForFailure(_microFailureBC);
}
// for test use microBC with macrosolver
if (_testFlag)
{
sv->activateTest(_testFlag);
}
}
void nonLinearMechSolver::createRestartByTime(const int day,const int hour,const int minute,const int second)
{
restartManager::setTimeBetweenCheckpoint(day,hour,minute,second);
}
void nonLinearMechSolver::createRestartBySteps(const int numstep)
{
restartManager::setStepBetweenCheckpoint(numstep);
}
bool nonLinearMechSolver::mustRestart(const int numstep)
{
return restartManager::checkpoint(numstep);
}
void nonLinearMechSolver::stepBetweenArchiving(const int n)
{
if (n > 0)
{
nsba = n;
if (_ipf!=NULL)
{
_ipf->stepBetweenArchiving(n);
}
if (_ufield != NULL)
{
_ufield->stepBetweenArchiving(n);
}
if (_energField != NULL)
{
_energField->stepBetweenArchiving(n);
}
// modify all existing view
for(int i=0;i<ipView.size();i++)
{
ipView[i].nbstepArch = n;
}
// modify all existing view
for(int i=0;i<ipViewInterface.size();i++)
{
ipViewInterface[i].nbstepArch = n;
}
for(int i=0;i<unknownView.size();i++)
{
unknownView[i].nbstepArch = n;
}
for (int i=0; i< energyView.size(); i++)
{
energyView[i].nbstepArch = n;
}
}
}
void nonLinearMechSolver::setFactorOnArchivingFiles(const int fact)
{
if (fact > 0)
{
// chang factor in solver
for (int i=0; i< vaip.size(); i++)
{
vaip[i].nstep*=fact;
}
for(int i=0;i<anoded.size();i++)
{
anoded[i].nstep*=fact;
}
// force
for(int i=0;i<vaf.size();i++)
{
vaf[i].nstep*=fact;
}
_energyComputation *= fact;
_fractureEnergyComputation *= fact;
// change factor inside field if exist
if (_ipf!=NULL)
{
_ipf->setFactorOnArchivingFiles(fact);
}
if (_ufield!=NULL)
{
_ufield->setFactorOnArchivingFiles(fact);
}
if (_energField !=NULL)
{
_energField->setFactorOnArchivingFiles(fact);
}
}
}
// nonLinearMechSolver
void nonLinearMechSolver::loadModel(const std::string &meshFileName)
{
// handle restart case
/* if(restartManager::available())
{
pModel = new GModel();
pModel->setFileName(meshFileName);
pModel->setAsCurrent();
pModel->readMSH(_restartMshFileName.c_str());
_dim = pModel->getNumRegions() ? 3 : 2;
pModel->setFileName(meshFileName);
pModel->setName(SplitFileName(meshFileName)[1]);
return;
}*/
pModel = new GModel();
pModel->setAsCurrent();
pModel->readMSH(meshFileName.c_str());
_meshFileName = meshFileName;
pModel->setFileName(meshFileName);
pModel->setName(SplitFileName(meshFileName)[1]);
this->commonModel();
}
void nonLinearMechSolver::commonModel()
{
_dim = pModel->getNumRegions() ? 3 : 2;
#if defined(HAVE_MPI)
int numPartitions = pModel->getNumPartitions();
if (numPartitions >0) {
_isPartitioned = true;
}
else
{
// only first
_isPartitioned = false;
}
if (_microFlag)
{
if (_isPartitioned)
{
Msg::Error("micro solver cannot run with partitioned meshes");
Msg::Exit(0);
}
}
else
{
Msg::Info("Number of mesh partition %d for %d cpu(s)",numPartitions,Msg::GetCommSize());
if(numPartitions > Msg::GetCommSize())
{
Msg::Error("Your mesh is wrong partitioned");
Msg::Exit(0);
}
else if(numPartitions !=0 and Msg::GetCommSize() == 1)
{
Msg::Error("Cannot perform a serial computation with a partitionned mesh");
Msg::Exit(0);
}
else if(numPartitions > 0 and numPartitions < Msg::GetCommSize())
{
Msg::Warning("You have more cpu than mesh partition so some cpus may have no work");
}
// partitions are numerated from 1 to numPartitions
std::set<int> mshPart;
for (int im=1; im < numPartitions+1; im++){
mshPart.insert(im);
}
// int map of ranks
initMapRanks(mshPart);
}
#endif // HAVE_MPI
}
void nonLinearMechSolver::createModel(const std::string &geoFileName, const std::string &outFileName,
const int dim,const int order,const bool incomplete)
{
// check reserved name
//if(!strcmp(outFileName.c_str(),_restartMshFileName.c_str()))
//{
// Msg::Error("The output file name you request to save your mesh is a reserved name! Change it to continue");
//}
// check restart file and if so use the saved msh file
//if(restartManager::available())
//{
// this->loadModel(_restartMshFileName);
// return;
//}
// Overwrite options
CTX::instance()->mesh.order = order;
CTX::instance()->mesh.secondOrderIncomplete = incomplete;
// Use version 3 of mesh to avoid a renmbering of the elements
if (Msg::GetCommSize()>1){
CTX::instance()->mesh.mshFileVersion = 3.0;
CTX::instance()->mesh.partitionCreatePhysicals = 0;
}
else{
CTX::instance()->mesh.mshFileVersion = 3.0;
}
pModel = new GModel();
pModel->setAsCurrent();
pModel->setFileName(geoFileName);
pModel->setName(SplitFileName(geoFileName)[1]);
pModel->readGEO(geoFileName);
pModel->mesh(dim);
if((!_microFlag) && Msg::GetCommSize()>1) /// if _microFlag is true, mesh is not partitioned
{
CTX::instance()->mesh.numPartitions = Msg::GetCommSize();
PartitionMesh(pModel, Msg::GetCommSize());
}
if(!outFileName.empty() && Msg::GetCommRank() == 0){
pModel->writeMSH(outFileName,
CTX::instance()->mesh.mshFileVersion,CTX::instance()->mesh.binary, CTX::instance()->mesh.saveAll,
CTX::instance()->mesh.saveParametric, CTX::instance()->mesh.scalingFactor);
}
_meshFileName = outFileName;
commonModel();
}
void nonLinearMechSolver::createMicroModel(const std::string geoFile, const int dim, const int order,
const bool incomplte){
std::string mshFile = getFileSavingPrefix()+".msh";
this->createModel(geoFile,mshFile,dim,order,incomplte);
};
void nonLinearMechSolver::initMapRanks(const std::set<int>& parts){
_mapRanks.clear();
std::vector<int> macroProcs;
int partSize = parts.size();
for (int i=0; i< partSize; i++){
macroProcs.push_back(i);
}
if (macroProcs.size() == 0){
// only rank 0 has a real solver
macroProcs.push_back(0);
_workingRank = 0;
}
int macroSize = macroProcs.size();
int allSize = Msg::GetCommSize();
int distSize = allSize - macroSize;
int div = distSize/macroSize;
for (int i=0; i<macroSize; i++){
int root = macroProcs[i];
std::set<int> others;
for (int j=0; j<div; j++){
int num = macroSize+i*div+j;
others.insert(num);
}
_mapRanks[root] = others;
}
int j = macroSize+ div*macroSize;
while (j< allSize){
for (int i=0; i< macroSize; i++){
int root = macroProcs[i];
std::set<int>& others =_mapRanks[root];
others.insert(j);
j++; // check here
if (j>=allSize) break;
}
}
#ifdef _DEBUG
printf("print map ranks:\n");
for (std::map<int,std::set<int> >::iterator it = _mapRanks.begin(); it!= _mapRanks.end(); it++){
if (Msg::GetCommRank() == it->first){
std::set<int>& others = it->second;
printf("proc %d -- root rank = %d, other size = %d \n", it->first, it->first,others.size());
for (std::set<int>::iterator its = others.begin(); its!= others.end(); its++){
printf("proc %d -- other rank: %d \n",it->first,*its);
}
}
}
#endif // _DEBUG
};
int nonLinearMechSolver::getNumRanks() const{
if (_mapRanks.size() > 0){
int num=0;
for (std::map<int,std::set<int> >::const_iterator it = _mapRanks.begin(); it != _mapRanks.end(); it++){
const std::set<int>& others = it->second;
num += (1+others.size());
}
return num;
}
else{
return 1; // in serial case, we have at least 1 proc
}
};
int nonLinearMechSolver::getNumRootRanks() const{
if (_mapRanks.size() > 0){
return _mapRanks.size(); //
}
else{
return 1; // in serial case, we have at least 1 proc
}
};
bool nonLinearMechSolver::rankOnSolver(const int rank) const{
for (std::map<int,std::set<int> >::const_iterator it = _mapRanks.begin(); it != _mapRanks.end(); it++){
if (rank == it->first) return true;
else{
const std::set<int>& others = it->second;
if (others.find(rank) != others.end()){
return true;
}
}
}
return false;
};
void nonLinearMechSolver::getAllRootRanks(std::set<int>& rootRanks) const{
rootRanks.clear();
for (std::map<int,std::set<int> >::const_iterator it = _mapRanks.begin(); it != _mapRanks.end(); it++){
rootRanks.insert(it->first);
}
};
void nonLinearMechSolver::getAllOtherRanks(std::set<int>& otherRanks) const{
otherRanks.clear();
for (std::map<int,std::set<int> >::const_iterator it = _mapRanks.begin(); it != _mapRanks.end(); it++){
otherRanks.insert(it->second.begin(), it->second.end());
}
};
void nonLinearMechSolver::getRootRank(const int otherRank, int& rootRank) const{
bool found = false;
for (std::map<int,std::set<int> >::const_iterator it = _mapRanks.begin(); it != _mapRanks.end(); it++){
if (otherRank == it->first){
Msg::Error("_mapRanks is wrongly initiated: wrong rank %d is root in nonLinearMechSolver::getRootRank",otherRank);
}
const std::set<int>& others = it->second;
if (others.find(otherRank) != others.end()){
rootRank = it->first;
found = true;
break;
}
}
if (!found){
Msg::Error("_mapRanks is wrongly initiated: root of other rank %d can not be found nonLinearMechSolver::getRootRank",otherRank);
}
};
void nonLinearMechSolver::getOtherRanks(const int rootRank, std::set<int>& otherRanks) const{
otherRanks.clear();
std::map<int,std::set<int> >::const_iterator it = _mapRanks.find(rootRank);
if (it != _mapRanks.end()){
otherRanks = it->second;
}
};
bool nonLinearMechSolver::isInitialized() const
{
return _previousInit;
}
bool nonLinearMechSolver::isMultiscale() const{
bool isMult = false;
for (std::map<int,materialLaw*>::const_iterator it = maplaw.begin(); it!= maplaw.end(); it++){
materialLaw* mlaw = it->second;
if (mlaw != NULL){
if (mlaw->isNumeric()){
isMult = true;
break;
}
}
}
return isMult;
};
bool nonLinearMechSolver::isDgDomain() const{
for (int i=0; i<domainVector.size(); i++){
partDomain* dom = domainVector[i];
if (dom->getFormulation()) return true;
}
return false;
};
bool nonLinearMechSolver::computedUdF() const{
for (int i=0; i<domainVector.size(); i++){
partDomain* dom = domainVector[i];
if (dom->hasBodyForceForHO()) return true;
}
return false;
};
partDomain::BodyForceModuliType nonLinearMechSolver::useWhichModuliForBF() const{
partDomain* dom = domainVector[0];
return dom->useWhichModuliForBF();
};
IPField* nonLinearMechSolver::getIPField() {return _ipf;};
const IPField* nonLinearMechSolver::getIPField() const {return _ipf;};
unknownField* nonLinearMechSolver::getUnknownField() {return _ufield;};
const unknownField* nonLinearMechSolver::getUnknownField() const {return _ufield;};
nlsDofManager* nonLinearMechSolver::getDofManager() {return pAssembler;};
const nlsDofManager* nonLinearMechSolver::getDofManager() const {return pAssembler;};
std::vector<partDomain*>* nonLinearMechSolver::getDomainVector() {return &domainVector;}
const std::vector<partDomain*>* nonLinearMechSolver::getDomainVector() const {return &domainVector;}
std::vector<partDomain*>* nonLinearMechSolver::getGhostDomainMPI(){return &_ghostDomainMPI;};
const std::vector<partDomain*>* nonLinearMechSolver::getGhostDomainMPI() const {return &_ghostDomainMPI;};
nonLinearMechSolver::contactContainer* nonLinearMechSolver::getAllContactDomain(){return &_allContact;};
const nonLinearMechSolver::contactContainer* nonLinearMechSolver::getAllContactDomain() const{return &_allContact;};
nonLinearMechSolver::defoDefoContactContainer* nonLinearMechSolver::getAllDefoDefoContactDomain(){return &_allDefoDefoContact;};
const nonLinearMechSolver::defoDefoContactContainer* nonLinearMechSolver::getAllDefoDefoContactDomain() const{return &_allDefoDefoContact;};
GModel* nonLinearMechSolver::getGModel(){return pModel;};
const GModel* nonLinearMechSolver::getGModel() const {return pModel;};
void nonLinearMechSolver::init(){
if(!_previousInit)
{
// Set the material law for each domain and the gauss integration rule
for(std::vector<partDomain*>::iterator it = domainVector.begin(); it!=domainVector.end(); ++it){
partDomain *dom = *it;
dom->setMaterialLaw(maplaw);
}
#if defined(HAVE_MPI)
// remove all unecessary domains in other ranks
if (this->getNumRanks() > 1){
bool OneDomRemove = true;
while (OneDomRemove){
OneDomRemove = false;
for(std::vector<partDomain*>::iterator it = domainVector.begin(); it!=domainVector.end(); ++it){
partDomain *dom = *it;
dgPartDomain* dgdom = NULL;
if (dom->IsInterfaceTerms()){
dgdom = static_cast<dgPartDomain*>(dom);
}
std::set<int> otherRanks;
int rootRank = dom->getRootRank();
dom->getOtherRanks(otherRanks);
if (otherRanks.size()> 0){
bool isNumMat = false;
if (dom->getMaterialLaw()){
if (dom->getMaterialLaw()->isNumeric()) isNumMat = true;
}
if (!isNumMat){
if (dom->IsInterfaceTerms()){
if (dgdom->getMaterialLawMinus()->isNumeric() or (dgdom->getMaterialLawPlus()->isNumeric())) {
isNumMat = true;
}
}
}
if (!isNumMat){
// if material is not numerical
if (otherRanks.find(Msg::GetCommRank()) != otherRanks.end()){
// in other rank
if (dom->elementGroupSize() > 0)
Msg::Error("Remove wrong partDomain %d",dom->getPhysical());
else if (dom->IsInterfaceTerms()){
if (dgdom->gi->size()> 0)
Msg::Error("Remove wrong dgPartDomain %d",dom->getPhysical());
}
domainVector.erase(it);
OneDomRemove = true;
break;
}
else if (rootRank == Msg::GetCommRank()){
// in root rank, clear other ranks
dom->clearOtherRanks();
}
}
}
}
}
}
#endif // HAVE_MPI
// create interfaceElement
this->createInterfaceElement();
for(std::vector<partDomain*>::iterator it = domainVector.begin(); it!=domainVector.end(); ++it){
partDomain *dom = *it;
dom->setGaussIntegrationRule();
// set Solver
dom->setMacroSolver(this); // some options in domaian come from solver
}
// add create new material cerate inside solver
for(std::vector<partDomain*>::iterator it = domainVector.begin(); it!=domainVector.end(); ++it){
dgPartDomain *dom = dynamic_cast<dgPartDomain*>(*it);
if (dom != NULL){
materialLaw* mlawMinus = dom->getMaterialLawMinus();
if (maplaw.find(mlawMinus->getNum()) == maplaw.end()){
maplaw[mlawMinus->getNum()] = mlawMinus;
}
materialLaw* mlawPlus = dom->getMaterialLawPlus();
if (maplaw.find(mlawPlus->getNum()) == maplaw.end()){
maplaw[mlawPlus->getNum()] = mlawPlus;
}
}
};
for (std::map<int,materialLaw*>::iterator it = maplaw.begin(); it!= maplaw.end(); it++){
it->second->setMacroSolver(this);
}
// at root ranks
#if defined(HAVE_MPI)
if (this->getNumRanks() > 1){
Msg::Barrier(); // wait to finish all previous mesages
}
#endif // HAVE_MPI
if (isDgDomain()){
_interfaceElements.clear();
//printf("begin filling reference local basis\n");
for (int idom= 0; idom < domainVector.size(); idom++){
const partDomain* dom = domainVector[idom];
if (dom->IsInterfaceTerms()){
const dgPartDomain* dgdom = static_cast<const dgPartDomain*>(dom);
for (elementGroup::elementContainer::const_iterator ite = dgdom->gi->begin(); ite != dgdom->gi->end(); ite++){
MElement* ele = ite->second;
MInterfaceElement* iele = dynamic_cast<MInterfaceElement*>(ele);
TwoNum tn(iele->getElem(0)->getNum(),iele->getElem(1)->getNum());
_interfaceElements[tn] = ele->getNum();
_interfaceElementsInverseMap[ele->getNum()] = tn;
}
}
}
if (_interfaceElementsInverseMap.size() > 0){
FILE* interFile = NULL;
if (Msg::GetCommSize() > 1){
std::ostringstream oss;
oss<<Msg::GetCommRank();
std::string partNum = oss.str();
std::string filename = getFileSavingPrefix()+"InterfaceElement_part"+partNum+".csv";
interFile = fopen(filename.c_str(),"w");
}
else{
std::string filename = getFileSavingPrefix()+ "InterfaceElement.csv";
interFile = fopen(filename.c_str(),"w");
}
for (std::map<int,TwoNum>::const_iterator itm = _interfaceElementsInverseMap.begin(); itm != _interfaceElementsInverseMap.end(); itm++){
fprintf(interFile,"%d %d %d\n",itm->first,itm->second.small,itm->second.large);
}
fclose(interFile);
}
#if defined(HAVE_MPI)
if (this->getNumRanks() > 1){
std::set<int> allRootRanks, allOtherRanks;
this->getAllRootRanks(allRootRanks);
this->getAllOtherRanks(allOtherRanks);
if (allRootRanks.find(Msg::GetCommRank()) != allRootRanks.end()){
std::set<int> otherRanks;
this->getOtherRanks(Msg::GetCommRank(),otherRanks);
if (otherRanks.size() > 0){
// send to other rank
int interfaceSize = _interfaceElements.size();
for (std::set<int>::const_iterator itR = otherRanks.begin(); itR != otherRanks.end(); itR++){
int oRank = *itR;
int tag = numericalMaterialBase::createTypeWithTwoInts(Msg::GetCommRank(),1);
MPI_Send(&interfaceSize,1,MPI_INT,oRank,tag,MPI_COMM_WORLD);
if (interfaceSize > 0){
int bufferSize = interfaceSize*3;
std::vector<int> buffer(bufferSize);
int index = 0;
for (std::map<TwoNum,int>::const_iterator itm = _interfaceElements.begin(); itm != _interfaceElements.end(); itm++){
buffer[index] = itm->first.small;
buffer[index+1] = itm->first.large;
buffer[index+2] = itm->second;
index += 3;
}
tag = numericalMaterialBase::createTypeWithTwoInts(Msg::GetCommRank(),2);
MPI_Send(&buffer[0],bufferSize,MPI_INT,oRank,tag,MPI_COMM_WORLD);
buffer.clear();
}
}
}
}
else if (allOtherRanks.find(Msg::GetCommRank()) != allOtherRanks.end()){
// receive data from root ranks
int rootRank;
this->getRootRank(Msg::GetCommRank(),rootRank);
// receive message
MPI_Status status;
int tag = numericalMaterialBase::createTypeWithTwoInts(rootRank,1);
int interfaceSize=0;
MPI_Recv(&interfaceSize,1,MPI_INT,rootRank,tag,MPI_COMM_WORLD,&status);
if (interfaceSize > 0){
int bufferSize = 3*interfaceSize;
tag = numericalMaterialBase::createTypeWithTwoInts(rootRank,2);
std::vector<int> buffer(bufferSize);
MPI_Recv(&buffer[0],bufferSize,MPI_INT,rootRank,tag,MPI_COMM_WORLD,&status);
int idex = 0;
for (int i=0; i< interfaceSize; i++){
TwoNum tn(buffer[idex],buffer[idex+1]);
_interfaceElements[tn] = buffer[idex+2];
_interfaceElementsInverseMap[buffer[idex+2]] = tn;
idex += 3;
}
}
}
}
#endif // HAVE_MPI
}
// fill reference system axis of interface GPs
if (isMultiscale()){
this->fillLocalReferenceBasisForAllInterfaceElement();
#if defined(HAVE_MPI)
if (getNumRanks() > 1){
std::set<int> allRootRanks, allOtherRanks;
this->getAllRootRanks(allRootRanks);
this->getAllOtherRanks(allOtherRanks);
if (allRootRanks.find(Msg::GetCommRank()) != allRootRanks.end()){
std::set<int> otherRanks;
this->getOtherRanks(Msg::GetCommRank(),otherRanks);
if (otherRanks.size() > 0){
int sizeOfInterfaceLocalBasis = _allInterfaceLocalBasis.size();
for (std::set<int>::const_iterator itR = otherRanks.begin(); itR != otherRanks.end(); itR++){
int oRank = *itR;
int tag = numericalMaterialBase::createTypeWithTwoInts(Msg::GetCommRank(),3);
MPI_Send(&sizeOfInterfaceLocalBasis,1,MPI_INT,oRank,tag,MPI_COMM_WORLD);
if (sizeOfInterfaceLocalBasis > 0){
int sizeBufferEleNum = sizeOfInterfaceLocalBasis;
int sizeBufferLocalBasis = 9*sizeBufferEleNum;
std::vector<int> bufferEleNum(sizeBufferEleNum);
std::vector<double> bufferLocalBasis(sizeBufferLocalBasis);
int rowEleNum =0;
for (std::map<int,STensor3>::const_iterator it = _allInterfaceLocalBasis.begin(); it != _allInterfaceLocalBasis.end(); it++){
bufferEleNum[rowEleNum] = it->first;
const STensor3& mat = it->second;
for (int index = 0; index< 9; index++){
int i,j;
Tensor23::getIntsFromIndex(index,i,j);
bufferLocalBasis[9*rowEleNum + index] = mat(i,j);
}
rowEleNum++;
}
tag = numericalMaterialBase::createTypeWithTwoInts(Msg::GetCommRank(),4);
MPI_Send(&bufferEleNum[0],sizeBufferEleNum,MPI_INT,oRank,tag,MPI_COMM_WORLD);
tag = numericalMaterialBase::createTypeWithTwoInts(Msg::GetCommRank(),5);
MPI_Send(&bufferLocalBasis[0],sizeBufferLocalBasis,MPI_DOUBLE,oRank,tag,MPI_COMM_WORLD);
}
};
}
}
else if (allOtherRanks.find(Msg::GetCommRank()) != allOtherRanks.end()){
// receive data from root ranks
int rootRank;
this->getRootRank(Msg::GetCommRank(),rootRank);
int bufferSize=0;
MPI_Status status;
int tag = numericalMaterialBase::createTypeWithTwoInts(rootRank,3);
MPI_Recv(&bufferSize,1,MPI_INT,rootRank,tag,MPI_COMM_WORLD,&status);
if (bufferSize > 0){
int sizeBufferEleNum = bufferSize;
int sizeBufferLocalBasis = 9*bufferSize;
std::vector<int> bufferEleNum(sizeBufferEleNum);
std::vector<double> bufferLocalBasis(sizeBufferLocalBasis);
tag = numericalMaterialBase::createTypeWithTwoInts(rootRank,4);
MPI_Recv(&bufferEleNum[0],sizeBufferEleNum,MPI_INT,rootRank,tag,MPI_COMM_WORLD,&status);
tag = numericalMaterialBase::createTypeWithTwoInts(rootRank,5);
MPI_Recv(&bufferLocalBasis[0],sizeBufferLocalBasis,MPI_DOUBLE,rootRank,tag,MPI_COMM_WORLD,&status);
// set data
for (int id=0; id< bufferSize; id++){
int type = bufferEleNum[id];
STensor3 mat(0.);
for (int index = 0; index< 9; index++){
int i,j;
Tensor23::getIntsFromIndex(index,i,j);
mat(i,j) = bufferLocalBasis[9*id+index];
}
_allInterfaceLocalBasis[type] = mat;
}
}
}
}
#endif // HAVE_MPI
}
#if defined(HAVE_MPI)
if (this->getNumRanks() > 1){
Msg::Barrier(); // wait to finish all previous mesages
}
#endif // HAVE_MPI
}
else // move all archiving data in a folder to start a new analysis
// keep only the previous one ( --> not valid if 2 switches)
// Linux only ?? (implementation MAC and Windows)
{
moveFiles("previousScheme","mv");
if(!_disableResetRestart) _resetRestart=true; //to avoid restart when shitfing schemes
}
if(whatScheme==Explicit or whatScheme==Multi)
this->initMapMElementToComputeTimeStep();
// find the domain associated to a physical slave number of a rigid contact interaction
// WARNING a contact interaction cannot be defined on two domains in the same time
// a physical group has to be define by domain
if(!_notResetedContact){
this->initContactInteraction();
_notResetedContact =true;
}
if(!_notResetedBC){
this->setPairSpaceElementForBoundaryConditions();
_notResetedBC = true;
}
// initialisation of archiving force
if (!_previousInit)
{
this->initArchiveForce();
this->initPathFollowingArchiving();
this->initArchiveInternalForce();
this->initAverageCluster();
}
else
{
// for force
for (std::vector<archiveForce>::iterator it = vaf.begin(); it!= vaf.end(); it++)
{
it->clear();
}
this->initArchiveForce();
// for
for (std::list<archiveInternalForce>::iterator it = vafIntenal.begin(); it!= vafIntenal.end(); it++)
{
it->clear();
}
this->initArchiveInternalForce();
for (std::list<IntegralVolume>::iterator it = _dataVolumeIntegral.begin(); it!= _dataVolumeIntegral.end(); it++)
{
it->resetArchiving(getFileSavingPrefix());
}
for (std::list<IPDataOnPhysical>::iterator it= _dataOnPhysical.begin(); it!= _dataOnPhysical.end(); it++)
{
it->resetArchiving();
}
this->initPathFollowingArchiving();
for (std::list<AvergageCluster>::iterator it= _averageClusters.begin(); it!= _averageClusters.end(); it++)
{
it->resetArchiving(getFileSavingPrefix());
}
}
}
void nonLinearMechSolver::moveFiles(const std::string &dirName, const std::string &cm)
{
#if defined(HAVE_MPI)
if(Msg::GetCommSize() > 1)
{
// get the host name of each rank
const char* myhostname = (GetEnvironmentVar("HOSTNAME")).c_str();
if(myhostname==NULL)
{
//Msg::Info("Hostname does not exist use rank");
//std::ostringstream strm;
//strm<<Msg::GetCommRank();
//myhostname= strm.str().c_str();
Msg::Info("Hostname does not exist use rank");
myhostname= "DEFAULTNAME";
}
int* vsizename = new int[Msg::GetCommSize()];
int* vallsizename = new int[Msg::GetCommSize()];
for(int i=0;i<Msg::GetCommSize();i++)
{
vallsizename[i] = 0;
vsizename[i] = 0;
}
vsizename[Msg::GetCommRank()] = (int) strlen(myhostname);
MPI_Allreduce(vsizename,vallsizename,Msg::GetCommSize(),MPI_INT,MPI_SUM,MPI_COMM_WORLD);
delete[] vsizename;
char** vhostname = new char*[Msg::GetCommSize()];
for(int i=0;i<Msg::GetCommSize();i++)
{
vhostname[i] = new char[vallsizename[i]];
if(Msg::GetCommRank()==i)
{
vhostname[i] = (char*)myhostname;
}
MPI_Bcast(vhostname[i],vallsizename[i],MPI_CHAR,i,MPI_COMM_WORLD);
}
// At this point all processes have an array with the host name of all processes
// if the host name of the rank doesn't match lower rank files are deleted
bool firsthostname=true;
for(int i=0;i<Msg::GetCommRank();i++){
if(!strcmp(myhostname,vhostname[i]))
{
firsthostname = false;
break;
}
}
if(firsthostname)
{
Msg::Warning("File are moved on rank %d, hostname %s",Msg::GetCommRank(),vhostname[Msg::GetCommRank()]);
std::string rmdir= "rm -rf " + dirName;
int oks = system(rmdir.c_str());
std::string mdir= "mkdir " + dirName;
oks = system(mdir.c_str());
std::string mvcsv= cm + " *.csv " + dirName +"/";
oks = system(mvcsv.c_str());
std::string mvdisp= cm + " "+ getFileSavingPrefix()+ "disp*.msh " + dirName +"/";
oks = system(mvdisp.c_str());
std::string mvstr= cm + " "+getFileSavingPrefix()+"stress*.msh " + dirName +"/";
oks = system(mvstr.c_str());
std::string mvint= cm + " "+getFileSavingPrefix()+"interfaceStress*.msh " + dirName +"/";
oks = system(mvint.c_str());
if(!_disableResetRestart){
struct stat st;
if(stat("nonLinearMechSolver0.ckp",&st) == 0)
{
std::string mvstr= cm + " *.ckp " + dirName +"/";
oks = system(mvstr.c_str());
}
}
// get back the mesh file
//if(!_meshFileName.empty())
//{
// std::string backMesh = "cp previousScheme/" + _meshFileName + " .";
// system(backMesh.c_str());
//}
}
else
{
Msg::Warning("Nothing moved on rank %d, hostname %s",Msg::GetCommRank(),vhostname[Msg::GetCommRank()]);
}
if (getNumRanks() > 1)
Msg::Barrier();
// delete array
delete[] vhostname;
delete[] vallsizename;
}
else
#endif // HAVE_MPI
{
std::string rmdir= "rm -rf " + dirName;
int oks = system(rmdir.c_str());
std::string mdir= "mkdir " + dirName;
oks =system(mdir.c_str());
std::string mvcsv= cm + " *.csv " + dirName +"/";
oks =system(mvcsv.c_str());
std::string mvdisp= cm + " "+getFileSavingPrefix()+"disp*.msh " + dirName +"/";
oks =system(mvdisp.c_str());
std::string mvstr= cm + " "+getFileSavingPrefix()+"stress*.msh " + dirName +"/";
oks =system(mvstr.c_str());
std::string mvint= cm + " "+getFileSavingPrefix()+"interfaceStress*.msh " + dirName +"/";
oks = system(mvint.c_str());
if(!_disableResetRestart){
struct stat st;
if(stat("nonLinearMechSolver0.ckp",&st) == 0)
{
std::string mvstr= cm + " *.ckp " + dirName +"/";
oks =system(mvstr.c_str());
}
}
// get back the mesh file
//if(!_meshFileName.empty())
//{
// std::string backMesh = "cp previousScheme/" + _meshFileName + " .";
// system(backMesh.c_str());
//}
}
}
void nonLinearMechSolver::initAllBCsOnDofs(){
if(whatScheme!=StaticLinear)
this->setTimeForBC(0.);
else
this->setTimeForBC(1.);
this->fixNodalDofs();
#if defined(HAVE_MPI)
if (Msg::GetCommRank() == _workingRank)
#endif //HAVE_MPI
{
// Boundary Conditions and Dof creation
this->fillConstraintDof();
this->applyConstraintBC();
// same disp BC
this->applySameDispBC();
//
this->applyFixOnFace();
//periodic BC
this->applyPBCBetweenTwoGroups();
this->applyLinearConstraintBetweenTwoGroups();
// for pbc
if (_testFlag){
Msg::Info("initialize test with micro BC");
this->initialize_test();
this->initCornerBC();
}
}
};
void nonLinearMechSolver::init2()
{
// initialize the system and dofManager
this->createSystem();
this->initAllBCsOnDofs();
Msg::Info("Fix and number Dofs");
this->numberDofs();
printf("total number of unknown Dofs = %d\n",pAssembler->sizeOfR());
printf("total number of fixed Dofs = %d\n",pAssembler->sizeOfF());
Msg::Info("Dofs are fixed and numbered");
/* MPI init */
#if defined(HAVE_MPI)
if(whatScheme!=StaticLinear and Msg::GetCommSize()>1)
{
Msg::Info("MPI initialization begins");
pAssembler->systemMPIComm(); // To initiate the MPI Communication
Msg::Info("MPI initialization OK");
}
#endif // HAVE_MPI
// make data as previous if exists
this->updateDataFromPreviousSolver();
/* initialization of Dof value */
// so now initial condition can be given to system
this->setInitialCondition();
#if defined(HAVE_MPI)
if (Msg::GetCommSize()>1){
bool isRootRank =false;
for (int i=0; i<domainVector.size(); i++){
partDomain* dom = domainVector[i];
if (dom->getRootRank() == Msg::GetCommRank()){
isRootRank = true;
break;
}
}
if (!isRootRank){
// no view and energy computation
unknownView.clear();
ipView.clear();
ipViewInterface.clear();
energyView.clear();
_energyComputation = 0;
_fractureEnergyComputation = 0;
}
}
#endif // HAVE_MPI
bool stiffcomputation=true;
if(whatScheme==Explicit) stiffcomputation=false;
if(!_previousInit){
/* fields creation */
if(_ufield) delete _ufield;
_ufield = new unknownField(this,3,anoded,unknownView);
Msg::Info("Creation of IPVariable");
_ipf = new IPField(this,vaip,ipView,ipViewInterface); // Field for GaussPoint
Msg::Info("IPVariable are created");
_ipf->compute1state(IPStateBase::initial,stiffcomputation);
_ipf->initialBroken(pModel, initbrokeninter);
_ipf->initialBrokenDomain(pModel,initbrokeninterInDomains);
// starting state
_ipf->copy(IPStateBase::initial,IPStateBase::previous);
_ipf->copy(IPStateBase::initial,IPStateBase::current);
if(_energField) delete _energField;
_energField = new energeticField(this, energyView,_energyComputation,_fractureEnergyComputation,getScheme());
//
#if defined(HAVE_MPI)
if (Msg::GetCommSize() > 1){
if (_dataVolumeIntegral.size() > 0){
// because all average values are computed independently in each procs
// the volume in chech procs must be estimated
std::string fname = getFileSavingPrefix()+"VolumeOnProc";
std::ostringstream oss;
oss << Msg::GetCommRank();
fname += oss.str();
fname += ".csv";
FILE* fileVolumeProc = fopen(fname.c_str(),"w");
double volume = 0.;
for (int i=0; i<domainVector.size(); i++){
volume += domainVector[i]->computeVolumeDomain(_ipf);
};
fprintf(fileVolumeProc,"%e",volume);
fclose(fileVolumeProc);
}
}
#endif //HAVE_MPI
}
else
{
_ipf->resetArchiving();
if (_ufield) delete _ufield;
_ufield = new unknownField(this,3,anoded,unknownView);
if (_energField)
{
_energField->resetArchiving();
}
}
/* terms initialization */
this->initTerms();
_previousInit = true;
Msg::Info("End of initialization");
#if defined(HAVE_MPI) && defined(_DEBUG)
if (getNumRanks() > 1)
{
printf("End init OK from rank %d wait all in debug\n",Msg::GetCommRank());
Msg::Barrier();
}
#endif // HAVE_MPI
}
void nonLinearMechSolver::endOfScheme(const double curtime, const int step)
{
this->postproFragment();
if (_strainMap !=NULL)
{
_strainMap->buildDisplacementViewAndStrainView(step,true);
}
_ufield->archive(curtime,step,true);
_ipf->archive(curtime,step,true);
_energField->archive(curtime,step,true);
forceArchiving(curtime,step,true);
internalForceArchiving(curtime,step,true);
this->IPVolumeIntegralArchiving(curtime,step,true);
this->IPDataOnPhysicalArchiving(curtime,step,true);
this->averageClusterArchiving(curtime,step,true);
#if defined(HAVE_MPI)
if (getNumRanks() > 1)
Msg::Barrier(); // Wait all before new computation (MPI problem ??)
#endif // HAVE_MPI
}
void nonLinearMechSolver::oneStepPreSolve(const double curtime, const double timestep, const int numstep)
{
this->setTimeForBC(curtime);
this->setTimeForLaw(curtime,timestep,numstep);
//for periodic BC
this->fixNodalDofs();
if (_testFlag){
if (_pbcGroup != NULL){
this->fixDofCorner();
}
}
}
void nonLinearMechSolver::oneStepPreSolvePathFollowing(const double curtime, const double timestep, const int numstep){
static std::string name = "A";
linearSystem<double>* lsys =pAssembler->getLinearSystem(name);
pathFollowingSystem<double>* pathsys = dynamic_cast<pathFollowingSystem<double>*>(lsys);
if (_pfManager._pathFollowingMethod == pathFollowingManager::LOCAL_BASED )
{
if (!_pfManager._switchedControlType)
{
pathsys->setControlType(pathFollowingSystemBase::LOAD_CONTROL);
}
else
{
pathsys->setControlType(pathFollowingSystemBase::LOCAL_CONTROL);
}
}
// if
double currentPathFollowingIncr = _pfManager.getCurrentPathFollowingIncrement();
//
pathsys->setPathFollowingIncrement(currentPathFollowingIncr);
Msg::Info("path following step: %e ",currentPathFollowingIncr);
double loadParam = pathsys->getControlParameter();
double dloadParam = fabs(pathsys->getControlParameterStep());
this->oneStepPreSolve(loadParam,dloadParam, numstep);
}
void nonLinearMechSolver::oneStepPostSolve(const double curtime, const int numstep)
{
// must be check first
this->checkElementErosion(IPStateBase::current);
if (_bulkElementErosionFlag or _interfaceElementErosionFlag)
{
_elementErosionFilter.print();
}
/*writing deformed mesh */
if (_isWriteDeformedMeshToFile){
this->writeDeformedMesh(numstep);
}
this->crackTracking(curtime);
/* Archiving */
if (_timeManager->willArchive(curtime,numstep))
{
_ufield->archive(curtime,numstep,false);
_ipf->archive(curtime,numstep,false);
_energField->archive(curtime,numstep,false);
this->forceArchiving(curtime,numstep,false); // Edge force value;
this->internalForceArchiving(curtime,numstep,false);
this->pathFollowingArchiving(curtime,numstep);
this->IPVolumeIntegralArchiving(curtime,numstep,false);
this->IPDataOnPhysicalArchiving(curtime,numstep,false);
this->averageClusterArchiving(curtime,numstep,false);
}
if (_strainMap !=NULL){
_strainMap->buildDisplacementViewAndStrainView(numstep,false);
}
if (_microFlag)
{
// copy current to initial state
(*_initialState) = (*_currentState);
this->extractAverageProperties(_tangentflag);
if (getDamageToCohesiveJumpFlag() and !_multiscaleFlag){
this->checkFailureOnset();
}
if (_microBC->getTotalNumberOfMechanicalDofs() > 0){
if (_stressflag){
_currentState->getHomogenizedStress().print("Stress ");
if (_microBC->getOrder() == 2)
_currentState->getHomogenizedSecondOrderStress().print("hostress ");
}
}
for (int index=0; index < _microBC->getTotalNumberOfConDofs(); index++){
_currentState->getHomogenizedConstitutiveExtraDofFlux(index).print("con extra dof flux");
printf("double con extra dof %d internal energy %f\n",index,_currentState->getHomogenizedConstitutiveExtraDofInternalEnergy(index));
}
if (_tangentflag){
_currentState->getHomogenizedTangentOperator_F_F().print("tangent");
}
if (_extractPerturbationToFile){
_pAl->getPBCConstraintGroup()->writePertBoundaryToFile(numstep);
}
if (_isWriteDeformedMeshToFile){
this->writeDeformedMesh(numstep);
}
if (withEnergyDissipation()){
_ipf->checkActiveDissipation();
if (_ipf->getNumOfActiveDissipationIPsCurrent() > 0){
// store historical value
_homogenizedStressLastActiveDissipation = this->getHomogenizationState(IPStateBase::current)->getHomogenizedStress();
_homogenizedStrainLastActiveDissipation = this->getMicroBC()->getFirstOrderKinematicalVariable();
_homogenizedDissipationStrainLastActiveDissipation = this->getHomogenizationState(IPStateBase::current)->getHomogenizedActiveDissipationDeformationGradient();
_homogenizedCohesiveJumpLastActiveDissipation = this->getHomogenizationState(IPStateBase::current)->getHomogenizedCohesiveJump();
}
}
// save files
this->homogenizedDataToFile(curtime);
}
//
if (!_stiffnessModification)
{
if (_stiffnessModificationMonitoring->willModify(numstep,curtime))
{
_stiffEstimation = true;
}
}
else
{
_stiffEstimation = true; // alway estimating stiffness matrix at the begining of the NR step
}
// next step
this->nextStep(curtime,numstep);
// restart at end if not need to redo next step when reading restart
if(this->mustRestart(numstep))
{
// special operation for the GModel to avoid libGmsh modifications
pModel->writeMSH(_restartMshFileName, CTX::instance()->mesh.mshFileVersion,CTX::instance()->mesh.binary, CTX::instance()->mesh.saveAll,
CTX::instance()->mesh.saveParametric, CTX::instance()->mesh.scalingFactor);
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
restartManager::createRestartFile("nonLinearMechSolver");
restartManager::restart(this);
//
restartManager::closeRestartFile();
//move output file for restart (if not the stress and disp files have duplicated steps)
moveFiles("beforeRestart","cp");
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
}
}
void nonLinearMechSolver::checkElementErosion(const IPStateBase::whichState ws){
if (_bulkElementErosionFlag or _interfaceElementErosionFlag){
elementGroup* allg = new elementGroup();
// add element to check
for (int idom=0; idom< domainVector.size(); idom++){
partDomain* dom = domainVector[idom];
if (_bulkElementErosionFlag){
for (elementGroup::elementContainer::const_iterator it = dom->element_begin(); it!= dom->element_end(); it++){
allg->insert(it->second);
};
}
if (_interfaceElementErosionFlag){
if (dom->getFormulation()){
dgPartDomain* dgdom = static_cast<dgPartDomain*>(dom);
for (elementGroup::elementContainer::const_iterator it = dgdom->gi->begin(); it!= dgdom->gi->end(); it++){
allg->insert(it->second);
};
}
}
}
//
for (elementGroup::elementContainer::const_iterator it = allg->begin(); it!= allg->end(); it++){
MElement* ele = it->second;
AllIPState::ipstateElementContainer* ips = _ipf->getAips()->getIPstate(ele->getNum());
if (_erosionType == FIRST_IP_FAILED){
bool willBeEroded = false;
for (int ip=0; ip < (*ips).size(); ip++){
const IPVariable* ipvprev = (*ips)[ip]->getState(IPStateBase::previous);
const IPVariable* ipv = (*ips)[ip]->getState(ws);
// check element
if (_erosionGlobalCriterion!=NULL){
// global check
if (_erosionGlobalCriterion->isFailed(ipvprev,ipv)){
willBeEroded = true;
break;
}
}
else if (ipv->isDeleted()){
// local criterion
willBeEroded = true;
break;
}
}
if (willBeEroded){
// add element
_elementErosionFilter.addErodedElement(ele);
// delete all remaining IP
for (int ip=0; ip < (*ips).size(); ip++){
IPVariable* ipv = (*ips)[ip]->getState(ws);
if (!ipv->isDeleted()){
ipv->Delete(true);
}
}
}
}
else if (_erosionType == ALL_IP_FAILED){
int numberNoFailedIP= 0;
for (int ip=0; ip < (*ips).size(); ip++){
const IPVariable* ipv = (*ips)[ip]->getState(ws);
const IPVariable* ipvprev = (*ips)[ip]->getState(IPStateBase::previous);
if (_erosionGlobalCriterion!=NULL){
if (!_erosionGlobalCriterion->isFailed(ipvprev,ipv)){
numberNoFailedIP++;
break;
}
}
else if (!ipv->isDeleted()){
numberNoFailedIP++;
break;
}
}
if (numberNoFailedIP == 0){
for (int ip=0; ip < (*ips).size(); ip++){
IPVariable* ipv = (*ips)[ip]->getState(ws);
if (!ipv->isDeleted()){
ipv->Delete(true);
}
}
_elementErosionFilter.addErodedElement(ele);
}
}
else{
Msg::Error("_erosionType = %d is not defined nonLinearMechSolver::checkElementErosion",_erosionType);
}
}
delete allg;
}
};
void nonLinearMechSolver::restart()
{
int newtag = _tag;
restartManager::restart(newtag);
restartErosion();
if(_tag != newtag) Msg::Error("The solver tag has change so restart cannot be done!");
restartManager::restart(_ufield);
restartManager::restart(_ipf);
restartManager::restart(_energField);
pAssembler->restart();
//
int newSolver = (int)whatSolver;
restartManager::restart(newSolver);
if(newSolver != (int)whatSolver) Msg::Error("You cannot change the solver at restart!");
int newScheme = (int)whatScheme;
restartManager::restart(newScheme);
if(newScheme != (int)whatScheme) Msg::Error("You cannot change the scheme at restart!");
_timeManager->restart();
_pfManager.restart();
restartDefoDefoContact();
return;
}
void nonLinearMechSolver::restartErosion()
{
//restartManager::restart(_maxAllowedNewlyBrokenElement); // Max number of allowed newly cracked elements during one step (for implicit case)
// Erosion control
//restartManager::restart(_bulkElementErosionFlag); // true if bulk element erosion
//restartManager::restart(_interfaceElementErosionFlag); // true if interface element erosion
//restartManager::restart(_erosionType); // all ip failed
//FailureCriterionBase* _erosionGlobalCriterion;
_elementErosionFilter.restart(); // a set consists of all erosion elements
_elementErosionFilter.print();
}
void nonLinearMechSolver::restartDefoDefoContact()
{
for(defoDefoContactContainer::iterator it = _allDefoDefoContact.begin(); it!=_allDefoDefoContact.end(); ++it){
defoDefoContactDomain *cdom = *it;
cdom->restart();
}
}
void nonLinearMechSolver::saveInternalState(const std::vector<int> tag)
{
if (!tag.empty()) Msg::Info("Saving Internal State");
//if (tag.empty())
//{
// Msg::Error("Domain tag not initialized for saving InternalState during restart!");
//}
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
// if file existing, open and append???
if(tag.size()>0)
restartManager::createInternalStateRestartFile("restartInternalState");
// to check element ordering between
// two different meshses for same domain
// outputing elem number and vertex coords
//std::ofstream outfile;
//outfile.open("Elem_order_"+std::to_string(this->getDomainVector()->size())+".txt");
for (int t = 0; t < tag.size(); ++t)
{
std::vector<bool> flagFoundDomain(tag.size(),false);
std::vector<partDomain*>* domainVec = this->getDomainVector();
for(std::vector<partDomain*>::iterator it = domainVec->begin(); it!=domainVec->end(); ++it)
{
const partDomain *dom = *it;
if(dom->getPhysical() == tag[t])
{
AllIPState * aips = _ipf->getAips();
dom->restartIPState(aips);
flagFoundDomain[t] = true;
/*
const elementGroup* elems = dom->elements();
for (elementGroup::elementContainer::const_iterator eleIt = elems->begin(); eleIt != elems->end(); ++eleIt)
{
MElement *e = eleIt->second;
outfile << "Elem num: " << e->getNum() << std::endl;
const int numVertices = e->getNumVertices();
outfile << "Vertices coords: " << std::endl;
for(unsigned int v = 0; v < numVertices; ++v)
{
outfile << e->getVertex(v)->x() << ", " << e->getVertex(v)->y() << ", " << e->getVertex(v)->z() << std::endl;
}
}
*/
}
}
if(!flagFoundDomain[t])
{
Msg::Error("Cannot find the parsed domain tag in the domain vector!");
}
}
if (tag.size() > 0)
restartManager::closeRestartFile();
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
//outfile.close();
if (!tag.empty()) Msg::Info("Done saving Internal State");
}
void nonLinearMechSolver::loadInternalState(const std::vector<int> tag)
{
Msg::Info("Loading Internal State");
if(tag.empty())
{
Msg::Error("Domain tag not initialized for loading InternalState during restart!");
}
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
const std::string fname("restartInternalState");
if (tag.size() > 0)
restartManager::openInternalStateRestartFile(fname);
// to check element ordering between
// two different meshses for same domain
// outputing elem number and vertex coords
//std::ofstream outfile;
//outfile.open("Elem_order_"+std::to_string(this->getDomainVector()->size())+".txt");
for (int t = 0; t < tag.size(); ++t)
{
std::vector<bool> flagFoundDomain(tag.size(),false);
std::vector<partDomain*>* domainVec = this->getDomainVector();
for(std::vector<partDomain*>::iterator it = domainVec->begin(); it!=domainVec->end(); ++it)
{
const partDomain *dom = *it;
if (dom->getPhysical() == tag[t])
{
AllIPState * aips = _ipf->getAips();
dom->restartIPState(aips);
flagFoundDomain[t] = true;
/*
const elementGroup* elems = dom->elements();
for (elementGroup::elementContainer::const_iterator eleIt = elems->begin(); eleIt != elems->end(); ++eleIt)
{
MElement *e = eleIt->second;
outfile << "Elem num: " << e->getNum() << std::endl;
const int numVertices = e->getNumVertices();
outfile << "Vertices coords: " << std::endl;
for(unsigned int v = 0; v < numVertices; ++v)
{
outfile << e->getVertex(v)->x() << ", " << e->getVertex(v)->y() << ", " << e->getVertex(v)->z() << std::endl;
}
}
*/
}
}
if(!flagFoundDomain[t])
{
Msg::Info("Cannot find the parsed domain tag in the domain vector!");
}
}
if(tag.size() > 0)
restartManager::closeRestartFile();
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
//outfile.close();
Msg::Info("Done loading Internal State");
}
void nonLinearMechSolver::initArchiveInternalForce()
{
for (std::list<archiveInternalForce>::iterator itf = vafIntenal.begin(); itf != vafIntenal.end(); itf++)
{
archiveInternalForce& af = *itf;
printf("init archiving internal force at physical %d dim %d\n",af.phys,af.dim);
elementGroup g(af.dim, af.phys);
if (g.vsize() > 0)
{
af.openFile(getFileSavingPrefix());
fprintf(af.FP,"Time");
}
for (elementGroup::vertexContainer::const_iterator itv = g.vbegin(); itv != g.vend(); itv++)
{
MVertex* v = itv->second;
std::map<archiveInternalForce::elementDomain,int>& sharedElements = af.sharedElements[v->getNum()];
fprintf(af.FP,";F_%ld_X;F_%ld_Y;F_%ld_Z",v->getNum(),v->getNum(),v->getNum());
for (int i=0; i< domainVector.size(); i++)
{
partDomain* dom = domainVector[i];
for (elementGroup::elementContainer::const_iterator ite = dom->element_begin(); ite != dom->element_end(); ite++)
{
MElement* e = ite->second;
for (int iv=0; iv < e->getNumVertices(); iv++)
{
if (e->getVertex(iv)->getNum() == v->getNum())
{
sharedElements.insert(std::pair<archiveInternalForce::elementDomain,int>(archiveInternalForce::elementDomain(dom,e),iv));
}
}
}
}
}
if (g.vsize() > 0)
{
fprintf(af.FP,"\n");
}
}
}
void nonLinearMechSolver::internalForceArchiving(const double curtime,const int numstep, const bool forceSave)
{
for (std::list<archiveInternalForce>::iterator itf = vafIntenal.begin(); itf != vafIntenal.end(); itf++)
{
archiveInternalForce& af = *itf;
if (numstep > af.lastSaveStep)
{
if((numstep%(af.nstep)==0 or forceSave))
{
af.lastSaveStep = numstep;
fprintf(af.FP,"%e",curtime);
fprintf(af.FPTotal,"%e",curtime);
// getData
double FXtol = 0.;
double FYtol = 0.;
double FZtol = 0.;
for (std::map<int,std::map<archiveInternalForce::elementDomain,int> >::iterator its = af.sharedElements.begin(); its != af.sharedElements.end(); its++)
{
double FX(0.), FY(0.), FZ(0.);
int vnum = its->first;
std::map<archiveInternalForce::elementDomain,int>& eleDom = its->second;
for (std::map<archiveInternalForce::elementDomain,int>::iterator iteled = eleDom.begin(); iteled != eleDom.end(); iteled++)
{
partDomain* dom = iteled->first.dom;
MElement* ele = iteled->first.ele;
int vertexPos = iteled->second;
std::vector<Dof> R;
dom->getFunctionSpace()->getKeys(ele,R);
IntPt *GP;
int npts = dom->getBulkGaussIntegrationRule()->getIntPoints(ele, &GP);
fullVector<double> val;
dom->getLinearBulkTerm()->get(ele,npts,GP,val);
int nbFF = ele->getNumShapeFunctions();
FX += val(vertexPos);
FY += val(vertexPos+nbFF);
FZ += val(vertexPos+2*nbFF);
}
FXtol += FX;
FYtol += FY;
FZtol += FZ;
//printf("internal force at node %d is FX = %e FY = %e FZ = %e\n",vnum,FX,FY,FZ);
fprintf(af.FP,";%.16g;%.16g;%.16g",FX,FY,FZ);
}
fprintf(af.FP,"\n");
fflush(af.FP);
fprintf(af.FPTotal,";%.16g;%.16g;%.16g\n",FXtol,FYtol,FZtol);
fflush(af.FPTotal);
}
}
}
};
std::string nonLinearMechSolver::getFileSavingPrefix() const
{
if (_microFlag)
{
if (_enumMinus == _enumPlus)
{
return "E_"+int2str(_enumMinus)+"_GP_"+int2str(_gnum)+"_";
}
else
{
return "E_Interface_"+int2str(_enumMinus)+"_"+int2str(_enumPlus)+"_GP_"+int2str(_gnum)+"_";
}
}
else
{
return "";
}
}
void nonLinearMechSolver::initContactInteraction(){
// find a common element between slave group of element and the group of element of partdomain
bool flagfind;
for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){
contactDomain *cdom = *it;
// get physical of domain
int physSlave = cdom->getPhysSlave();
flagfind=false;
for(int kk=0;kk<_mpiUserDom; kk++){
partDomain *dom = domainVector[kk];
if(dom->getPhysical() == physSlave){
flagfind =true;
cdom->setDomainAndFunctionSpace(dom);
break;
}
}
if(!flagfind){
#if defined(HAVE_MPI)
// find the domain in the Ghosted domain (the search on an empty group OK)
for(int kk=0; kk<_ghostDomainMPI.size(); kk++)
{
partDomain *dom = _ghostDomainMPI[kk];
if(dom->getPhysical() == physSlave){
flagfind =true;
cdom->setDomainAndFunctionSpace(dom);
break;
}
}
if(!flagfind)
#endif // HAVE_MPI
{
Msg::Error("The contact interaction %d can't be initiated because the domain is not find on rank %d",cdom->getPhys(),Msg::GetCommRank());
}
}
}
// now init the contact boundary conditions
//for(rigidContactBC &diri : allContactBC){
for(std::list<rigidContactBC>::iterator diri = allContactBC.begin(); diri!=allContactBC.end(); ++diri){
if(diri->onWhat == nonLinearBoundaryCondition::RIGIDCONTACT){
for(contactContainer::iterator itcdom = _allContact.begin(); itcdom!=_allContact.end(); ++itcdom){
contactDomain *cdom = *itcdom;
if(cdom->getPhys() == diri->_tag){ // we can have some slave domain with the same master --> don't put a break in the loop !
rigidContactSpaceBase *sp = static_cast<rigidContactSpaceBase*>(cdom->getSpace());
diri->setSpace(sp);
diri->_filter = cdom->getDomain()->createFilterDof(diri->_comp);
}
}
}
}
// Idem for defo defo contact. MPI not implemented
// for parallel we need to define the master faces as ghost faces in all the other partitions
for(defoDefoContactContainer::iterator it = _allDefoDefoContact.begin(); it!=_allDefoDefoContact.end(); ++it){
defoDefoContactDomain *cdom = (*it);
bool domfindSlave=false;
int physSlave = cdom->getPhysSlave();
elementGroup gSlave(cdom->getDimSlave(), physSlave); //will not be insterted, so delete it at the end
// map
std::map<partDomain*,std::vector<MElement*> > mapfindSlave;
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain *dom = *itdom;
if(physSlave == dom->getPhysical()){
domfindSlave = true;
for(elementGroup::elementContainer::const_iterator it2=dom->element_begin(); it2!=dom->element_end(); ++it2)
mapfindSlave[dom].push_back(it2->second);
break;
}
}
#if defined(HAVE_MPI)
// look if the BC is applied on a vertex
if(!domfindSlave){
if(cdom->getDimSlave() == 1){
// loop on dof of other partition (if the dof is included only on this partition it will be find after)
elementGroup::vertexContainer::const_iterator itvBC = gSlave.vbegin();
MVertex *verBC = NULL;
if (gSlave.vsize() > 0)
verBC = itvBC->second;
for(std::map<int,std::vector<elementGroup> >::iterator it=_mapOtherDomain.begin(); it!=_mapOtherDomain.end(); ++it){
std::vector<elementGroup> & groupOtherPart = it->second;
for(int j=0;j<Msg::GetCommRank(); j++){ // look on domain with a lower partition number
for(elementGroup::vertexContainer::const_iterator itv = groupOtherPart[j].vbegin(); itv!=groupOtherPart[j].vend(); ++itv){
MVertex *ver = itv->second;
if(verBC == ver){
domfindSlave=true; // the BC will be applied on an other partition
break;
}
}
}
}
}
}
#endif //HAVE_MPI
if(!domfindSlave){
// loop on element
std::map<partDomain*,MElement*> mapelemtype; // need for gauss quadrature rule TODO group with mapfind in a structure but no time benefit
for(elementGroup::elementContainer::const_iterator it=gSlave.begin(); it!=gSlave.end();++it){
MElement *e = it->second;
bool flagfind = false;
// Loop on all Domain to find on which domain the BC is applied
for(int j=0; j<_mpiUserDom; j++){
// if Dimensions are the same the element can be find with a comparison to element
partDomain *dom = domainVector[j];
// otherwise the vertex must be identified separately
MElement *etest = NULL;
if (dom->elementGroupSize() > 0)
{
etest = dom->element_begin()->second;
mapelemtype[dom] = etest;
}
if( (etest != NULL) and (etest->getDim() == e->getDim())){
for(elementGroup::elementContainer::const_iterator it2=dom->element_begin(); it2!=dom->element_end(); ++it2){
if(it2->second == e){ // The Element is contained in the domain
mapfindSlave[dom].push_back(e);
flagfind = true;
break;
}
}
}
else{ // loop on Vertex identify the BC with first vertex of e
// an element is included in one domain --> one vertex of Element is OK
// in mpi the BC can be included in another partition
#if defined(HAVE_MPI)
for(int j=_mpiUserDom; j<domainVector.size(); j++){ // loop only on interface domain "added by mpi"
dgPartDomain *dgdom = static_cast<dgPartDomain*>(domainVector[j]);
// get the two partition number
// Neumann BC cannot be applied on ghost element (will not be assembled in the end)
// do not applied on ghost element AS THEY WILL NOT BE ABLE TO BE ASSEMBLED!
// loop over ghost element and see if there is a match
for(elementGroup::elementContainer::const_iterator iteleDom = dgdom->gi->begin(); iteleDom != dgdom->gi->end();++iteleDom)
{
MInterfaceElement *ie = dynamic_cast<MInterfaceElement*>(iteleDom->second);
int numMinus = ie->getElem(0)->getPartition();
int numPlus = ie->getElem(1)->getPartition();
// identify the Ghost
MElement* eleGhost = (numMinus == Msg::GetCommRank()+1) ? ie->getElem(1) : ie->getElem(0);
// loop over nodes to see if they match
int nmatch = 0;
for(int i=0;i<eleGhost->getNumVertices();++i)
{
MVertex* verGhost = eleGhost->getVertex(i);
for(int jj=0;jj<e->getNumVertices();jj++){
MVertex *verBC = e->getVertex(jj);
if(verBC == verGhost)
{
nmatch++;
if(nmatch == e->getNumVertices())
{
flagfind = true; // the BC will be applied on another partition as on ghost here
break;
}
}
}
if(flagfind) break;
}
if(flagfind) break;
}
}
#endif // HAVE_MPI
if(!flagfind){
// check all vertex of the BC (node 0 could be on another partition)
int ncount = 0;
for(elementGroup::vertexContainer::const_iterator itv=dom->vertex_begin(); itv!=dom->vertex_end(); ++itv){
for(int jj=0; jj<e->getNumVertices();++jj)
{
MVertex *ver = e->getVertex(jj);
if((itv->second) == ver){
ncount ++;
if(ncount == e->getNumVertices())
{
mapfindSlave[dom].push_back(e);
flagfind = true;
break;
}
}
}
if(flagfind) break;
}
}
}
if(flagfind)
break;
}
}
}
bool domfindMaster=false;
int physMaster = cdom->getPhysMaster();
//elementGroup *gMaster = new elementGroup (cdom->getDimMaster(), physMaster);
elementGroup gMaster(cdom->getDimMaster(), physMaster); //will not be insterted, so delete it at the end
// map
std::map<partDomain*,std::vector<MElement*> > mapfindMaster;
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain *dom = *itdom;
if(physMaster == dom->getPhysical()){
domfindMaster = true;
for(elementGroup::elementContainer::const_iterator it2=dom->element_begin(); it2!=dom->element_end(); ++it2)
mapfindMaster[dom].push_back(it2->second);
break;
}
}
#if defined(HAVE_MPI)
// look if the BC is applied on a vertex
if(!domfindMaster){
if(cdom->getDimMaster() == 1){
// loop on dof of other partition (if the dof is included only on this partition it will be find after)
elementGroup::vertexContainer::const_iterator itvBC = gMaster.vbegin();
MVertex *verBC = NULL;
if (gMaster.vsize() > 0)
verBC = itvBC->second;
for(std::map<int,std::vector<elementGroup> >::iterator it=_mapOtherDomain.begin(); it!=_mapOtherDomain.end(); ++it){
std::vector<elementGroup> & groupOtherPart = it->second;
for(int j=0;j<Msg::GetCommRank(); j++){ // look on domain with a lower partition number
for(elementGroup::vertexContainer::const_iterator itv = groupOtherPart[j].vbegin(); itv!=groupOtherPart[j].vend(); ++itv){
MVertex *ver = itv->second;
if(verBC == ver){
domfindMaster=true; // the BC will be applied on an other partition
break;
}
}
}
}
}
}
#endif //HAVE_MPI
if(!domfindMaster){
// loop on element
std::map<partDomain*,MElement*> mapelemtype; // need for gauss quadrature rule TODO group with mapfind in a structure but no time benefit
for(elementGroup::elementContainer::const_iterator it=gMaster.begin(); it!=gMaster.end();++it){
MElement *e = it->second;
bool flagfind = false;
// Loop on all Domain to find on which domain the BC is applied
for(int j=0; j<_mpiUserDom; j++){
// if Dimensions are the same the element can be find with a comparison to element
partDomain *dom = domainVector[j];
// otherwise the vertex must be identified separately
MElement *etest = NULL;
if (dom->elementGroupSize() > 0)
{
etest = (dom->element_begin()->second);
mapelemtype[dom] = etest;
}
if( (etest != NULL) and (etest->getDim() == e->getDim())){
for(elementGroup::elementContainer::const_iterator it2=dom->element_begin(); it2!=dom->element_end(); ++it2){
if(it2->second == e){ // The Element is contained in the domain
mapfindMaster[dom].push_back(e);
flagfind = true;
break;
}
}
}
else{ // loop on Vertex identify the BC with first vertex of e
// an element is included in one domain --> one vertex of Element is OK
// in mpi the BC can be included in another partition
#if defined(HAVE_MPI)
for(int j=_mpiUserDom; j<domainVector.size(); j++){ // loop only on interface domain "added by mpi"
dgPartDomain *dgdom = static_cast<dgPartDomain*>(domainVector[j]);
// get the two partition number
// Neumann BC cannot be applied on ghost element (will not be assembled in the end)
// do not applied on ghost element AS THEY WILL NOT BE ABLE TO BE ASSEMBLED!
// loop over ghost element and see if there is a match
for(elementGroup::elementContainer::const_iterator iteleDom = dgdom->gi->begin(); iteleDom != dgdom->gi->end();++iteleDom)
{
MInterfaceElement *ie = dynamic_cast<MInterfaceElement*>(iteleDom->second);
int numMinus = ie->getElem(0)->getPartition();
int numPlus = ie->getElem(1)->getPartition();
// identify the Ghost
MElement* eleGhost = (numMinus == Msg::GetCommRank()+1) ? ie->getElem(1) : ie->getElem(0);
// loop over nodes to see if they match
int nmatch = 0;
for(int i=0;i<eleGhost->getNumVertices();++i)
{
MVertex* verGhost = eleGhost->getVertex(i);
for(int jj=0;jj<e->getNumVertices();jj++){
MVertex *verBC = e->getVertex(jj);
if(verBC == verGhost)
{
nmatch++;
if(nmatch == e->getNumVertices())
{
flagfind = true; // the BC will be applied on another partition as on ghost here
break;
}
}
}
if(flagfind) break;
}
if(flagfind) break;
}
}
#endif // HAVE_MPI
if(!flagfind){
// check all vertex of the BC (node 0 could be on another partition)
int ncount = 0;
for(elementGroup::vertexContainer::const_iterator itv=dom->vertex_begin(); itv!=dom->vertex_end(); ++itv){
for(int jj=0; jj<e->getNumVertices();++jj)
{
MVertex *ver = e->getVertex(jj);
if((itv->second) == ver){
ncount ++;
if(ncount == e->getNumVertices())
{
mapfindMaster[dom].push_back(e);
flagfind = true;
break;
}
}
}
if(flagfind) break;
}
}
}
if(flagfind)
break;
}
}
}
// now the map Space Element is filled for the BC
for(std::map<partDomain*,std::vector<MElement*> >::iterator it=mapfindMaster.begin(); it!=mapfindMaster.end(); ++it)
{
elementGroup mast(it->second);
for(std::map<partDomain*,std::vector<MElement*> >::iterator itslave=mapfindSlave.begin(); itslave!=mapfindSlave.end(); ++itslave)
{
elementGroup slav(itslave->second);
cdom->insertSlaveMasterDomainsAndFunctionSpace(itslave->first,&slav,it->first,&mast);
}
}
}
}
void nonLinearMechSolver::setPairSpaceElementForBoundaryConditions()
{
// The current GModel has to be selected to create the BC
GModel* save_current_model = GModel::current();
GModel::setCurrent(pModel);
// loop on BC
// BC which are prescribed weakly (the interfaceElement has to be finded in vinter)
// to prescribed the BC
// Theta (normally on Boundary only --> impossible that the condition be on 2 partitions)
for(std::list<nonLinearNeumannBC>::iterator ittheta=allTheta.begin(); ittheta!=allTheta.end(); ++ittheta){
for(elementGroup::elementContainer::const_iterator ite=ittheta->g->begin(); ite!=ittheta->g->end(); ++ite){
MVertex *vv = (ite->second)->getVertex(2);
for(int k=0;k<domainVector.size(); k++){
partDomain *dom = domainVector[k];
if(dom->IsInterfaceTerms()){ // change this (virtual interface has to be defined on domain)
// Ok because 2nd degree min BoundaryInterfaceElement is created only for this vertex
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
elementGroup *gvi = dgdom->giv;
for(elementGroup::elementContainer::const_iterator it_inter = gvi->begin(); it_inter!=gvi->end();++it_inter){
MElement *minter = it_inter->second;
//loop on component of map_edge
int numvertexminus1 = minter->getNumVertices()-1;
if((vv == minter->getVertex(2)) or (vv == minter->getVertex(numvertexminus1))){
dgdom->gib->insert(minter);
break;
}
}
}
}
}
}
#if 1
//Dirichlet (can be applied on each domain look on ghost element to prescribed BC on them avoid a search in unknown map at each iteration)
for(std::list<nonLinearDirichletBC>::iterator itbc = allDirichlet.begin(); itbc != allDirichlet.end();++itbc){
// first look if the BC is not applied on whole domain
bool domfind=false;
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain *dom = *itdom;
if(itbc->_tag == dom->getPhysical()){
domfind = true;
if(dom->_groupGhostMPI->size() > 0) // save BC to applied an other groupOfElement
{
FunctionSpaceBase *spdbc = dom->getSpaceForBC(nonLinearBoundaryCondition::DIRICHLET,itbc->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itbc->_comp,itbc->getDofType(),dom->_groupGhostMPI);
FilterDof *fdof = dom->createFilterDof(itbc->_comp);
itbc->_vspace.push_back(spdbc);
itbc->_vgroup.push_back(dom->_groupGhostMPI);
itbc->_vfilter.push_back(fdof);
itbc->_vdg.push_back(dom->getFormulation());
}
FunctionSpaceBase *spdbc = dom->getSpaceForBC(nonLinearBoundaryCondition::DIRICHLET,itbc->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itbc->_comp,itbc->getDofType(),dom->elements());
FilterDof *fdof = dom->createFilterDof(itbc->_comp);
itbc->_vspace.push_back(spdbc);
itbc->_vgroup.push_back(dom->elements());
itbc->_vfilter.push_back(fdof);
itbc->_vdg.push_back(dom->getFormulation());
break;
}
}
#if defined(HAVE_MPI)
// same on ghost domain (be aware copy past of loop on domain !!)
bool ghostdomfind=false;
for(std::vector<partDomain*>::iterator itdom=_ghostDomainMPI.begin(); itdom!=_ghostDomainMPI.end(); ++itdom){
partDomain *dom = *itdom;
if(itbc->_tag == dom->getPhysical() and dom->_groupGhostMPI->size()>0){
ghostdomfind = true;
FunctionSpaceBase *spdbc = dom->getSpaceForBC(nonLinearBoundaryCondition::DIRICHLET,itbc->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itbc->_comp,itbc->getDofType(),dom->_groupGhostMPI);
FilterDof* fdof = dom->createFilterDof(itbc->_comp);
itbc->_vspace.push_back(spdbc);
itbc->_vgroup.push_back(dom->_groupGhostMPI);
itbc->_vfilter.push_back(fdof);
itbc->_vdg.push_back(dom->getFormulation());
break;
}
}
#endif // HAVE_MPI
if(!domfind){
// loop on element
// map
std::map<partDomain*,std::vector<MElement*> > mapfind;
std::map<partDomain*,std::vector<MElement*> > mapfindGhost;
for(elementGroup::elementContainer::const_iterator it=itbc->g->begin(); it!=itbc->g->end();++it){
MElement *e = it->second;
// Loop on all Domain to find on which domain the BC is applied
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){
// if Dimensions are the same the element can be find with a comparison to element
partDomain *dom = *itdom;
// otherwise the vertex must be identified separately
const MElement *etest = NULL;
if (dom->elementGroupSize() > 0)
{
etest = (dom->element_begin()->second);
}
if( (etest !=NULL) and (etest->getDim() == e->getDim())){
for(elementGroup::elementContainer::const_iterator it2=dom->element_begin(); it2!=dom->element_end(); ++it2){
if(it2->second == e){ // The Element is contained in the domain
mapfind[dom].push_back(e);
break;
}
}
#if defined(HAVE_MPI)
for(elementGroup::elementContainer::const_iterator it2=dom->_groupGhostMPI->begin(); it2!=dom->_groupGhostMPI->end(); ++it2){
if(it2->second == e){ // The Element is contained in the domain
mapfind[dom].push_back(e);
break;
}
}
#endif // HAVE_MPI
}
else{
// an element is included in one domain --> one vertex of Element is OK
// On interface the BC is put on the first met domain
fillMapOfInterfaceElementsInOneDomain(e, mapfind[(*itdom)], dom->elements());
#if defined(HAVE_MPI)
// change map in mapFindGhost???
fillMapOfInterfaceElementsInOneDomain(e, mapfind[(*itdom)], dom->_groupGhostMPI);
// check on element which are not included in _groupGhostMPI as there is no interface element with the element
for(int j=0;j<Msg::GetCommSize();j++)
{
if(j!=Msg::GetCommRank() and !(*itdom)->getFormulation() ) // no ghost with itself
fillMapOfInterfaceElementsInOneDomain(e, mapfindGhost[(*itdom)], &(_mapOtherDomain[(*itdom)->getPhysical()][j]));
}
#endif // HAVE_MPI
}
}
}
// now the space element map of the BC is filled
for(std::map<partDomain*,std::vector<MElement*> >::iterator it=mapfind.begin(); it!=mapfind.end(); ++it){
if(it->second.size() !=0){
elementGroup* dirig = new elementGroup(it->second);
FunctionSpaceBase *spdbc = it->first->getSpaceForBC(nonLinearBoundaryCondition::DIRICHLET,itbc->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itbc->_comp,itbc->getDofType(),dirig);
FilterDof *fdof = it->first->createFilterDof(itbc->_comp);
itbc->_vspace.push_back(spdbc);
itbc->_vgroup.push_back(dirig);
itbc->_vfilter.push_back(fdof);
itbc->_vdg.push_back(it->first->getFormulation());
}
}
// same with mapfindGhost
#if defined(HAVE_MPI)
for(std::map<partDomain*,std::vector<MElement*> >::iterator it=mapfindGhost.begin(); it!=mapfindGhost.end(); ++it){
if(it->second.size() !=0){
elementGroup* dirig = new elementGroup(it->second);
FunctionSpaceBase *spdbc = it->first->getSpaceForBC(nonLinearBoundaryCondition::DIRICHLET,itbc->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itbc->_comp,itbc->getDofType(),dirig);
FilterDof *fdof = it->first->createFilterDof(itbc->_comp);
itbc->_vspace.push_back(spdbc);
itbc->_vgroup.push_back(dirig);
itbc->_vfilter.push_back(fdof);
itbc->_vdg.push_back(it->first->getFormulation());
}
}
#endif // HAVE_MPI
}
#if defined(HAVE_MPI)
// same on ghostDomain (be aware copy past of loop on domain !!)
if(!ghostdomfind){
// loop on element
// map
std::map<partDomain*,std::vector<MElement*> > ghostmapfind;
for(elementGroup::elementContainer::const_iterator it=itbc->g->begin(); it!=itbc->g->end();++it){
MElement *e = it->second;
// Loop on all Domain to find on which domain the BC is applied
for(std::vector<partDomain*>::iterator itdom=_ghostDomainMPI.begin(); itdom!=_ghostDomainMPI.end(); ++itdom){
// if Dimensions are the same the element can be find with a comparison to element
partDomain *dom = *itdom;
// otherwise the vertex must be identified separately
MElement *etest = NULL;
if (dom->elementGroupSize() > 0)
{
etest = (dom->element_begin()->second);
}
if( (etest !=NULL) and (etest->getDim() == e->getDim())){
for(elementGroup::elementContainer::const_iterator it2=dom->_groupGhostMPI->begin(); it2!=dom->_groupGhostMPI->end(); ++it2){
if(it2->second == e){ // The Element is contained in the domain
ghostmapfind[dom].push_back(e);
break;
}
}
}
else
{
// an element is included in one domain --> one vertex of Element is OK
// On interface the BC is put on the first met domain
fillMapOfInterfaceElementsInOneDomain(e, ghostmapfind[(*itdom)], dom->_groupGhostMPI);
// check on element which are not included in _groupGhostMPI as there is no interface element with the element
for(int j=0;j<Msg::GetCommSize();j++)
{
if(j!=Msg::GetCommRank() and !(*itdom)->getFormulation() ) // no ghost with itself
fillMapOfInterfaceElementsInOneDomain(e, ghostmapfind[(*itdom)], &(_mapOtherDomain[(*itdom)->getPhysical()][j]));
}
}
}
}
// now the space element of the BC is filled
for(std::map<partDomain*,std::vector<MElement*> >::iterator it=ghostmapfind.begin(); it!=ghostmapfind.end(); ++it){
if(it->second.size() !=0){
elementGroup *dirig = new elementGroup(it->second);
FunctionSpaceBase *spdbc = it->first->getSpaceForBC(nonLinearBoundaryCondition::DIRICHLET,itbc->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itbc->_comp,itbc->getDofType(),dirig);
FilterDof* fdof = it->first->createFilterDof(itbc->_comp);
itbc->_vspace.push_back(spdbc);
itbc->_vgroup.push_back(dirig);
itbc->_vfilter.push_back(fdof);
itbc->_vdg.push_back(it->first->getFormulation());
}
}
}
#endif // HAVE_MPI
}
// Idem for Neumann BC APPLY ON FIRST FOUNDED DOM. MPI problem the condition has be applied once (on the partition with the lowest number)
for(std::list<nonLinearNeumannBC>::iterator itbc = allNeumann.begin(); itbc!=allNeumann.end();++itbc){
// first look if the BC is not applied on whole domain
bool domfind=false;
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain *dom = *itdom;
if(itbc->_tag == dom->getPhysical()){
domfind = true;
FunctionSpaceBase *spnbc = dom->getSpaceForBC(nonLinearBoundaryCondition::NEUMANN,itbc->onWhat, itbc->_NeumannBCType,
itbc->_comp,itbc->getDofType(),dom->elements());
QuadratureBase *integ = dom->getQuadratureRulesForNeumannBC(*itbc);
itbc->_vspace.push_back(spnbc);
itbc->_vgroup.push_back(dom->elements());
itbc->_vquadrature.push_back(integ);
itbc->_vdom.push_back(dom);
break;
}
}
// map
std::map<partDomain*,std::vector<MElement*> > mapfind;
#if defined(HAVE_MPI)
// look if the BC is applied on a vertex
if(!domfind){
if(itbc->g->vsize() == 1){
// loop on dof of other partition (if the dof is included only on this partition it will be find after)
elementGroup::vertexContainer::const_iterator itvBC = itbc->g->vbegin();
MVertex *verBC = NULL;
if (itbc->g->vsize() > 0)
{
verBC = itvBC->second;
}
for(std::map<int,std::vector<elementGroup> >::iterator it=_mapOtherDomain.begin(); it!=_mapOtherDomain.end(); ++it){
std::vector<elementGroup> & groupOtherPart = it->second;
for(int j=0;j<Msg::GetCommRank(); j++){ // look on domain with a lower partition number
for(elementGroup::vertexContainer::const_iterator itv = groupOtherPart[j].vbegin(); itv!=groupOtherPart[j].vend(); ++itv){
MVertex *ver = itv->second;
if(verBC == ver){
domfind=true; // the BC will be applied on an other partition
break;
}
}
}
}
}
}
#endif //HAVE_MPI
if(!domfind){
// loop on element
std::map<partDomain*,MElement*> mapelemtype; // need for gauss quadrature rule TODO group with mapfind in a structure but no time benefit
for(elementGroup::elementContainer::const_iterator it=itbc->g->begin(); it!=itbc->g->end();++it){
MElement *e = it->second;
bool flagfind = false;
// Loop on all Domain to find on which domain the BC is applied
for(int j=0; j<_mpiUserDom; j++){
// if Dimensions are the same the element can be find with a comparison to element
partDomain *dom = domainVector[j];
// otherwise the vertex must be identified separately
MElement *etest = NULL;
if (dom->elementGroupSize() > 0)
{
etest = (dom->element_begin()->second);
mapelemtype[dom] = etest;
}
if( (etest != NULL) and (etest->getDim() == e->getDim())){
for(elementGroup::elementContainer::const_iterator it2=dom->element_begin(); it2!=dom->element_end(); ++it2){
if(it2->second == e){ // The Element is contained in the domain
mapfind[dom].push_back(e);
flagfind = true;
break;
}
}
}
else{ // loop on Vertex identify the BC with first vertex of e
// an element is included in one domain --> one vertex of Element is OK
// in mpi the BC can be included in another partition
#if defined(HAVE_MPI)
for(int j=_mpiUserDom; j<domainVector.size(); j++){ // loop only on interface domain "added by mpi"
dgPartDomain *dgdom = static_cast<dgPartDomain*>(domainVector[j]);
// get the two partition number
// Neumann BC cannot be applied on ghost element (will not be assembled in the end)
// do not applied on ghost element AS THEY WILL NOT BE ABLE TO BE ASSEMBLED!
#if 0 // old code
elementGroup::elementContainer::const_iterator iteleDom = dgdom->gi->begin();
MInterfaceElement *ie = dynamic_cast<MInterfaceElement*>(*iteleDom);
int numPlus = ie->getElem(1)->getPartition();
// if this partition is the one of numPlus it is the partition with the highest number and
// it has been look if the BC appear in the other partition
if(Msg::GetCommRank()+1 == numPlus){
// loop on element of the domain
for(elementGroup::vertexContainer::const_iterator itv=dgdom->gi->vbegin(); itv!=dgdom->gi->vend(); ++itv){
MVertex *verDom = *itv;
for(int jj=0;jj<e->getNumVertices();jj++){
MVertex *verBC = e->getVertex(jj);
if(verBC == verDom){
flagfind = true; // the BC will be applied on another partition
break;
}
}
if(flagfind) break;
}
}
#else
// loop over ghost element and see if there is a match
for(elementGroup::elementContainer::const_iterator iteleDom = dgdom->gi->begin(); iteleDom != dgdom->gi->end();++iteleDom)
{
MInterfaceElement *ie = dynamic_cast<MInterfaceElement*>(iteleDom->second);
int numMinus = ie->getElem(0)->getPartition();
int numPlus = ie->getElem(1)->getPartition();
// identify the Ghost
MElement* eleGhost = (numMinus == Msg::GetCommRank()+1) ? ie->getElem(1) : ie->getElem(0);
// loop over nodes to see if they match
int nmatch = 0;
for(int i=0;i<eleGhost->getNumVertices();++i)
{
MVertex* verGhost = eleGhost->getVertex(i);
for(int jj=0;jj<e->getNumVertices();jj++){
MVertex *verBC = e->getVertex(jj);
if(verBC == verGhost)
{
nmatch++;
if(nmatch == e->getNumVertices())
{
flagfind = true; // the BC will be applied on another partition as on ghost here
break;
}
}
}
if(flagfind) break;
}
if(flagfind) break;
}
#endif //0
}
#endif // HAVE_MPI
if(!flagfind){
// check all vertex of the BC (node 0 could be on another partition)
int ncount = 0;
for(elementGroup::vertexContainer::const_iterator itv=dom->vertex_begin(); itv!=dom->vertex_end(); ++itv){
for(int jj=0; jj<e->getNumVertices();++jj)
{
MVertex *ver = e->getVertex(jj);
if((itv->second) == ver){
ncount ++;
if(ncount == e->getNumVertices())
{
mapfind[dom].push_back(e);
flagfind = true;
break;
}
}
}
if(flagfind) break;
}
}
}
if(flagfind)
break;
}
}
// now the map Space Element is filled for the BC
for(std::map<partDomain*,std::vector<MElement*> >::iterator it=mapfind.begin(); it!=mapfind.end(); ++it){
//nonLinearNeumannBC *neu = new nonLinearNeumannBC(allNeumann[i]);
elementGroup *neug = new elementGroup(it->second);
FunctionSpaceBase *spnbc = it->first->getSpaceForBC(nonLinearBoundaryCondition::NEUMANN,itbc->onWhat, itbc->_NeumannBCType,
itbc->_comp,itbc->getDofType(),neug);
QuadratureBase *integ = it->first->getQuadratureRulesForNeumannBC(*itbc);
itbc->_vspace.push_back(spnbc);
itbc->_vgroup.push_back(neug);
itbc->_vquadrature.push_back(integ);
itbc->_vdom.push_back(it->first);
}
}
}
for(std::list<initialCondition>::iterator itic = allinitial.begin(); itic != allinitial.end();++itic){
// first look if the BC is not applied on whole domain
bool domfind=false;
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain *dom = *itdom;
if(itic->_tag == dom->getPhysical()){
domfind = true;
if(dom->_groupGhostMPI->size() > 0) // save BC to applied an other groupOfElement
{
FunctionSpaceBase *spdbc = dom->getSpaceForBC(nonLinearBoundaryCondition::INITIAL,itic->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itic->_comp,itic->getDofType(),dom->_groupGhostMPI);
FilterDof *fdof = dom->createFilterDof(itic->_comp);
itic->_vspace.push_back(spdbc);
itic->_vgroup.push_back(dom->_groupGhostMPI);
itic->_vfilter.push_back(fdof);
itic->_vdg.push_back(dom->getFormulation());
}
FunctionSpaceBase *spdbc = dom->getSpaceForBC(nonLinearBoundaryCondition::INITIAL,itic->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itic->_comp,itic->getDofType(),dom->elements());
FilterDof *fdof = dom->createFilterDof(itic->_comp);
itic->_vspace.push_back(spdbc);
itic->_vgroup.push_back(dom->elements());
itic->_vfilter.push_back(fdof);
itic->_vdg.push_back(dom->getFormulation());
break;
}
}
#if defined(HAVE_MPI)
// same on ghost domain (be aware copy past of loop on domain !!)
bool ghostdomfind=false;
for(std::vector<partDomain*>::iterator itdom=_ghostDomainMPI.begin(); itdom!=_ghostDomainMPI.end(); ++itdom){
partDomain *dom = *itdom;
if(itic->_tag == dom->getPhysical() and dom->_groupGhostMPI->size()>0){
ghostdomfind = true;
FunctionSpaceBase *spdbc = dom->getSpaceForBC(nonLinearBoundaryCondition::INITIAL,itic->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itic->_comp,itic->getDofType(),dom->_groupGhostMPI);
FilterDof* fdof = dom->createFilterDof(itic->_comp);
itic->_vspace.push_back(spdbc);
itic->_vgroup.push_back(dom->_groupGhostMPI);
itic->_vfilter.push_back(fdof);
itic->_vdg.push_back(dom->getFormulation());
break;
}
}
#endif // HAVE_MPI
if(!domfind){
// loop on element
// map
std::map<partDomain*,std::vector<MElement*> > mapfind;
std::map<partDomain*,std::vector<MElement*> > mapfindGhost;
for(elementGroup::elementContainer::const_iterator it=itic->g->begin(); it!=itic->g->end();++it){
MElement *e = it->second;
// Loop on all Domain to find on which domain the BC is applied
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){
// if Dimensions are the same the element can be find with a comparison to element
partDomain *dom = *itdom;
// otherwise the vertex must be identified separately
MElement *etest = NULL;
if (dom->elementGroupSize() > 0)
{
etest = (dom->element_begin()->second);
}
if( (etest !=NULL) and (etest->getDim() == e->getDim())){
for(elementGroup::elementContainer::const_iterator it2=dom->element_begin(); it2!=dom->element_end(); ++it2){
if(it2->second == e){ // The Element is contained in the domain
mapfind[dom].push_back(e);
break;
}
}
#if defined(HAVE_MPI)
for(elementGroup::elementContainer::const_iterator it2=dom->_groupGhostMPI->begin(); it2!=dom->_groupGhostMPI->end(); ++it2){
if(it2->second == e){ // The Element is contained in the domain
mapfind[dom].push_back(e);
break;
}
}
#endif // HAVE_MPI
}
else{
// an element is included in one domain --> one vertex of Element is OK
// On interface the BC is put on the first met domain
fillMapOfInterfaceElementsInOneDomain(e, mapfind[(*itdom)], dom->elements());
#if defined(HAVE_MPI)
// change map in mapFindGhost???
fillMapOfInterfaceElementsInOneDomain(e, mapfind[(*itdom)], dom->_groupGhostMPI);
// check on element which are not included in _groupGhostMPI as there is no interface element with the element
for(int j=0;j<Msg::GetCommSize();j++)
{
if(j!=Msg::GetCommRank() and !(*itdom)->getFormulation() ) // no ghost with itself
fillMapOfInterfaceElementsInOneDomain(e, mapfindGhost[(*itdom)], &(_mapOtherDomain[(*itdom)->getPhysical()][j]));
}
#endif // HAVE_MPI
}
}
}
// now the space element map of the BC is filled
for(std::map<partDomain*,std::vector<MElement*> >::iterator it=mapfind.begin(); it!=mapfind.end(); ++it){
if(it->second.size() !=0){
elementGroup* dirig = new elementGroup(it->second);
FunctionSpaceBase *spdbc = it->first->getSpaceForBC(nonLinearBoundaryCondition::INITIAL,itic->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itic->_comp,itic->getDofType(),dirig);
FilterDof *fdof = it->first->createFilterDof(itic->_comp);
itic->_vspace.push_back(spdbc);
itic->_vgroup.push_back(dirig);
itic->_vfilter.push_back(fdof);
itic->_vdg.push_back(it->first->getFormulation());
}
}
// same with mapfindGhost
#if defined(HAVE_MPI)
for(std::map<partDomain*,std::vector<MElement*> >::iterator it=mapfindGhost.begin(); it!=mapfindGhost.end(); ++it){
if(it->second.size() !=0){
elementGroup* dirig = new elementGroup(it->second);
FunctionSpaceBase *spdbc = it->first->getSpaceForBC(nonLinearBoundaryCondition::INITIAL,itic->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itic->_comp,itic->getDofType(),dirig);
FilterDof *fdof = it->first->createFilterDof(itic->_comp);
itic->_vspace.push_back(spdbc);
itic->_vgroup.push_back(dirig);
itic->_vfilter.push_back(fdof);
itic->_vdg.push_back(it->first->getFormulation());
}
}
#endif // HAVE_MPI
}
#if defined(HAVE_MPI)
// same on ghostDomain (be aware copy past of loop on domain !!)
if(!ghostdomfind){
// loop on element
// map
std::map<partDomain*,std::vector<MElement*> > ghostmapfind;
for(elementGroup::elementContainer::const_iterator it=itic->g->begin(); it!=itic->g->end();++it){
MElement *e = it->second;
// Loop on all Domain to find on which domain the BC is applied
for(std::vector<partDomain*>::iterator itdom=_ghostDomainMPI.begin(); itdom!=_ghostDomainMPI.end(); ++itdom){
// if Dimensions are the same the element can be find with a comparison to element
partDomain *dom = *itdom;
// otherwise the vertex must be identified separately
const MElement *etest = NULL;
if (dom->elementGroupSize() >0)
{
etest =(dom->element_begin()->second);
}
if( (etest !=NULL) and (etest->getDim() == e->getDim())){
for(elementGroup::elementContainer::const_iterator it2=dom->_groupGhostMPI->begin(); it2!=dom->_groupGhostMPI->end(); ++it2){
if(it2->second == e){ // The Element is contained in the domain
ghostmapfind[dom].push_back(e);
break;
}
}
}
else
{
// an element is included in one domain --> one vertex of Element is OK
// On interface the BC is put on the first met domain
fillMapOfInterfaceElementsInOneDomain(e, ghostmapfind[(*itdom)], dom->_groupGhostMPI);
}
}
}
// now the space element of the BC is filled
for(std::map<partDomain*,std::vector<MElement*> >::iterator it=ghostmapfind.begin(); it!=ghostmapfind.end(); ++it){
if(it->second.size() !=0){
elementGroup *dirig = new elementGroup(it->second);
FunctionSpaceBase *spdbc = it->first->getSpaceForBC(nonLinearBoundaryCondition::INITIAL,itic->onWhat, nonLinearNeumannBC::NEUMANN_UNDEF,
itic->_comp,itic->getDofType(),dirig);
FilterDof* fdof = it->first->createFilterDof(itic->_comp);
itic->_vspace.push_back(spdbc);
itic->_vgroup.push_back(dirig);
itic->_vfilter.push_back(fdof);
itic->_vdg.push_back(it->first->getFormulation());
}
}
}
#endif // HAVE_MPI
}
#endif // 0
// put back the curent GModel
GModel::setCurrent(save_current_model);
};
void nonLinearMechSolver::setTimeForBC(double time){
for(std::list<nonLinearDirichletBC>::iterator it = allDirichlet.begin(); it != allDirichlet.end();++it)
{
it->_f->setTime(time);
}
for(std::list<nonLinearNeumannBC>::iterator it = allNeumann.begin(); it!= allNeumann.end();++it)
{
it->_f->setTime(time);
}
// set time for rigid contact BC
for(std::list<rigidContactBC>::iterator it = allContactBC.begin(); it!=allContactBC.end(); ++it){
it->_f->setTime(time);
}
if (_testFlag){
for (std::list<nonLinearDirichletBCAtCorner>::iterator it = allCornerConstraint.begin(); it != allCornerConstraint.end(); it++){
it->_f->setTime(time);
}
for (std::list<nonLinearNeumannBCAtCorner>::iterator it = allCornerForce.begin(); it != allCornerForce.end(); it++){
it->_f->setTime(time);
}
}
// for periodic BC
this->setTimeForMicroBC(time);
}
void nonLinearMechSolver::setTimeForLaw(const double t,const double dt, const int numstep)
{
for(std::map<int,materialLaw*>::iterator it=maplaw.begin(); it!=maplaw.end();++it)
{
if (_microFlag){
double mtime = _macroTime- (1-t)*_macroTimeStep;
double tstep = dt*_macroTimeStep; // because
it->second->setTime(mtime,tstep);
}
else{
it->second->setTime(t,dt);
}
}
};
void nonLinearMechSolver::fixNodalDofs()
{
// Fixation (prescribed displacement)
for(std::list<nonLinearDirichletBC>::iterator it = allDirichlet.begin(); it!=allDirichlet.end();++it )
{
nonLinearDirichletBC &diri = *it;
// select the system if required
nlsDofManager* currentManager = pAssembler->getManagerByComp(diri._comp);
if(diri._mycondition==nonLinearBoundaryCondition::position)
{
for(int j=0; j<diri._vspace.size();j++)
{
FunctionSpaceBase *spdiri = diri._vspace[j];
const elementGroup *gdiri = diri._vgroup[j];
FilterDof* fdofdiri = diri._vfilter[j];
bool fdg = diri._vdg[j];
FixNodalDofs(spdiri,gdiri->begin(),gdiri->end(),*currentManager,*diri._f,*(fdofdiri),fdg,diri._dofType);
}
}
else
{
for(int j=0;j<diri._vspace.size();j++){
// allow to prescribed a velocity or acceleration over time using a dirichlet BC
SetInitialDofs(diri._vspace[j],diri._vgroup[j]->begin(),diri._vgroup[j]->end(),diri._mycondition,*currentManager,diri._f,*(diri._vfilter[j]),diri._vdg[j],diri._dofType);
}
}
}
// prescribed displacement of rigid bodies (CG)
//for(rigidContactBC &rcbc : allContactBC){
for(std::list<rigidContactBC>::iterator rcbc = allContactBC.begin(); rcbc!=allContactBC.end(); ++rcbc)
{
nlsDofManager* currentManager = pAssembler->getManagerByComp(rcbc->_comp);
FixNodalDofs(rcbc->space,*rcbc->_f,*(rcbc->_filter),*currentManager);
}
}
void nonLinearMechSolver::updateDataFromPreviousSolver()
{
// solver must be used previously
if (_previousInit and _resetRestart)
{
if (_collection==NULL)
{
Msg::Warning("previous system is used but data is not collected");
}
else
{
pAssembler->updateDataFromCollection(*_collection);
}
}
}
void nonLinearMechSolver::numberDofs(){
// we number the dofs : when a dof is numbered, it cannot be numbered
// again with another number.
for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom)
{
partDomain *dom = *itdom;
if(dom->elementGroupSize() > 0)
{
NumberDofsByVector(*(dom->getFunctionSpace()), dom->element_begin(), dom->element_end(),*pAssembler);
}
#if defined(HAVE_MPI)
// create the mpi communication on interface domain
// no element in g --> interfaceDomain
else if(Msg::GetCommSize()>1)
{
dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(dom);
if (dgdom)
{
NumberInterfaceDofsMPI(dom->getFunctionSpace(), dgdom->gi->begin(), dgdom->gi->end(), pAssembler);
}
}
#endif // HAVE_MPI
}
if (_testFlag and (_pbcGroup != NULL)){
// number new dof coming from microBC if existing
_pbcGroup->numberDof_virtualVertices(pAssembler);
}
// contact
pAssembler->setFirstRigidContactUnknowns(); // store the number of usual Dof in ech system
// NumberDofs of Rigid Contact Entities (Dofs for GC)
for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it)
{
contactDomain* cdom = *it;
if(cdom->isRigid())
{
rigidContactSpaceBase *rcspace = static_cast<rigidContactSpaceBase*>(cdom->getSpace());
NumberDofs(*rcspace,*pAssembler);
}
}
//HERE DO WE NEED SOMETHING FOR DEFODEFO? SHOULD NOT BE BECAUSE IT S FOR CG
// allocate system
if (whatScheme == Eigen)
{
int nunk = pAssembler->sizeOfR();
static std::string A("A");
pAssembler->getLinearSystem(A)->allocate(nunk);
if (_eigOpts.type == eigenSolverOptions::Dynamic)
{
static std::string B("B");
pAssembler->getLinearSystem(B)->allocate(nunk);
};
}
else
{
pAssembler->allocateSystem();
}
// Try to fill the matrix sparsity if needed
// this has to be done after the system allocation
for(int i=0; i<_mpiUserDom;++i)
{
partDomain *dom = domainVector[i];
if(dom->elementGroupSize() > 0)
{
SparsityDofs(*(dom->getFunctionSpace()), dom->element_begin(), dom->element_end(),*pAssembler);
}
// account also interface
dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(dom);
if (dgdom)
{
#if defined(HAVE_MPI)
if(Msg::GetCommSize()>1 && dom->elementGroupSize() == 0)
SparsityInterfaceDofsMPI(dgdom->getFunctionSpace(), dgdom->gi->begin(), dgdom->gi->end(),pAssembler);
#endif
SparsityDofs(*(dgdom->getFunctionSpace()), dgdom->gi->begin(), dgdom->gi->end(),*pAssembler);
}
}
#if defined(HAVE_MPI)
// MPI interface sparsity
if(Msg::GetCommSize()>1)
{
for(int i=_mpiUserDom; i<domainVector.size();++i)
{
dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(domainVector[i]);
if (dgdom)
{
SparsityInterfaceDofsMPI(dgdom->getFunctionSpace(), dgdom->gi->begin(), dgdom->gi->end(),pAssembler);
}
}
}
#endif //HAVE_MPI
// pre allocate entry
if (whatScheme == Eigen)
{
// allocate system
static std::string A("A");
pAssembler->getLinearSystem(A)->preAllocateEntries();
if (_eigOpts.type == eigenSolverOptions::Dynamic)
{
static std::string B("B");
pAssembler->setCurrentMatrix(B);
//
for(int i=0; i<_mpiUserDom;++i)
{
partDomain *dom = domainVector[i];
if(dom->elementGroupSize() > 0)
{
SparsityDofs(*(dom->getFunctionSpace()), dom->element_begin(), dom->element_end(),*pAssembler);
}
// account also interface
dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(dom);
if (dgdom)
{
#if defined(HAVE_MPI)
if(Msg::GetCommSize()>1 && dom->elementGroupSize() == 0)
SparsityInterfaceDofsMPI(dgdom->getFunctionSpace(), dgdom->gi->begin(), dgdom->gi->end(),pAssembler);
#endif
SparsityDofs(*(dgdom->getFunctionSpace()), dgdom->gi->begin(), dgdom->gi->end(),*pAssembler);
}
}
#if defined(HAVE_MPI)
// MPI interface sparsity
if(Msg::GetCommSize()>1)
{
for(int i=_mpiUserDom; i<domainVector.size();++i)
{
dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(domainVector[i]);
if (dgdom)
{
SparsityInterfaceDofsMPI(dgdom->getFunctionSpace(), dgdom->gi->begin(), dgdom->gi->end(),pAssembler);
}
}
}
#endif //HAVE_MPI
//
pAssembler->getLinearSystem(B)->preAllocateEntries();
pAssembler->setCurrentMatrix(A);
};
}
else
{
pAssembler->preAllocateEntries();
}
//
if (_pathFollowing and (_pfManager._pathFollowingMethod == pathFollowingManager::HYPERELLIPTIC_BASED))
{
static std::string A("A");
pathFollowingSystemBase* pfsysBase = dynamic_cast<pathFollowingSystemBase*>(pAssembler->getLinearSystem(A));
if (pfsysBase != NULL){
for (int i=0; i< _pfManager._hyperellipticControlComp.size(); i++){
int comp = _pfManager._hyperellipticControlComp[i];
for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom)
{
partDomain *dom = *itdom;
if (dom->getAccountPathFollowingFlag()){
FunctionSpaceBase* space = dom->getFunctionSpace();
FilterDof* filter = dom->createFilterDof(comp);
for (elementGroup::elementContainer::const_iterator ite = dom->element_begin(); ite != dom->element_end(); ite++){
MElement* ele = ite->second;
std::vector<Dof> keys;
space->getKeys(ele,keys);
for (int k=0; k< keys.size(); k++){
if ((pAssembler->isAnUnknown(keys[k])) and (filter->operator ()(keys[k]))){
int num = pAssembler->getDofNumber(keys[k]);
if (num >=0){
pfsysBase->addToHyperellipticMatrix(num,num,1.);
}
}
}
}
delete filter;
}
}
}
}
else{
Msg::Error("path following system must be used");
}
};
return;
}
void nonLinearMechSolver::addDomain(partDomain* dom){
pModel->setAsCurrent();
// initialization of ElementGroup
int dim = dom->getDim();
int phys = dom->getPhysical();
#if defined(HAVE_MPI)
std::vector<elementGroup> groupOtherPart(Msg::GetCommSize());
elementFilterMPI elemfil(&groupOtherPart) ;
dom->addPhysicalGroup(dim,phys,elemfil);
// add to map (to construct later interface domain)
_mapOtherDomain.insert(std::pair<int,std::vector<elementGroup> >(phys,groupOtherPart));
if (_microFlag == false){
if (dom->isDistributedOtherRanks()){
// if multiscale material is used
// at root ranks
if (_mapRanks.find(Msg::GetCommRank()) != _mapRanks.end()){
int addFlag = 0;
if(dom->elementGroupSize()!= 0){ // otherwise the domain is include totally on an other partition
dom->setWorkingRanks(Msg::GetCommRank(),_mapRanks[Msg::GetCommRank()]);
domainVector.push_back(dom);
addFlag= 1;
}
else if(dom->IsInterfaceTerms()){ // take into account for pure interface domain which have dom->g.size()=0
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
if(dgdom->getMinusDomain()->getPhysical() != dgdom->getPlusDomain()->getPhysical()){ // pure interface --> add
dom->setWorkingRanks(Msg::GetCommRank(),_mapRanks[Msg::GetCommRank()]);
domainVector.push_back(dom);
addFlag = 2;
}
else{ // add the domain in ghostDomain vector to prescribed Dirichlet BC (applied on all cpu)
_ghostDomainMPI.push_back(dom);
addFlag = 3;
}
}
std::set<int>& otherRanks = _mapRanks[Msg::GetCommRank()];
for (std::set<int>::iterator its = otherRanks.begin(); its != otherRanks.end(); its++)
MPI_Send(&addFlag,1,MPI_INT,*its,*its,MPI_COMM_WORLD);
}
// in other ranks
else{
for (std::map<int,std::set<int> >::iterator it = _mapRanks.begin(); it!= _mapRanks.end(); it++){
std::set<int>& other = it->second;
if (other.find(Msg::GetCommRank()) != other.end()){
int rank = it->first;
int addFlag = 0;
MPI_Status status;
MPI_Recv(&addFlag,1,MPI_INT,rank,Msg::GetCommRank(),MPI_COMM_WORLD,&status);
if (addFlag == 1 or addFlag == 2){
domainVector.push_back(dom);
dom->setWorkingRanks(rank,other);
dom->clearElementGroup();
}
}
}
}
}
else{
// if normal Domain is used
if (_mapRanks.find(Msg::GetCommRank()) != _mapRanks.end()){
std::set<int> nullSet;
if(dom->elementGroupSize() != 0){ // otherwise the domain is include totally on an other partition
dom->setWorkingRanks(Msg::GetCommRank(),nullSet);
domainVector.push_back(dom);
}
else if(dom->IsInterfaceTerms()){ // take into account for pure interface domain which have dom->g.size()=0
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
if(dgdom->getMinusDomain()->getPhysical() != dgdom->getPlusDomain()->getPhysical()){ // pure interface --> add
dom->setWorkingRanks(Msg::GetCommRank(),nullSet);
domainVector.push_back(dom);
}
else{ // add the domain in ghostDomain vector to prescribed Dirichlet BC (applied on all cpu)
_ghostDomainMPI.push_back(dom);
}
}
}
}
}
else {
if(dom->elementGroupSize() != 0){ // otherwise the domain is include totally on an other partition
domainVector.push_back(dom);
}
else if(dom->IsInterfaceTerms()){ // take into account for pure interface domain which have dom->g.size()=0
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
if(dgdom->getMinusDomain()->getPhysical() != dgdom->getPlusDomain()->getPhysical()){ // pure interface --> add
domainVector.push_back(dom);
}
else{ // add the domain in ghostDomain vector to prescribed Dirichlet BC (applied on all cpu)
_ghostDomainMPI.push_back(dom);
}
}
}
#else
elementFilterTrivial elemfil;
dom->addPhysicalGroup(dim,phys,elemfil);
domainVector.push_back(dom);
#endif // HAVE_MPI
}
void nonLinearMechSolver::addMaterialLaw(materialLaw* mlaw){
maplaw.insert(std::pair<int,materialLaw*>(mlaw->getNum(),mlaw));
}
materialLaw* nonLinearMechSolver::getMaterialLaw(const int num){
return (maplaw.find(num)->second);
}
void nonLinearMechSolver::thetaBC(const int numphys){
elementGroup *goe = new elementGroup(1,numphys);
this->insertTheta(numphys,goe);
}
void nonLinearMechSolver::stiffnessModification(const bool flag){
_stiffnessModification = flag;
if (!_stiffnessModification)
{
_stiffnessModificationMonitoring = new StiffnessModificationMonitoring(0);
}
};
void nonLinearMechSolver::stiffnessModification(const StiffnessModificationMonitoring& stiffModifMonitor)
{
_stiffnessModification = false;
if (_stiffnessModificationMonitoring) delete _stiffnessModificationMonitoring;
_stiffnessModificationMonitoring = stiffModifMonitor.clone();
};
void nonLinearMechSolver::iterativeProcedure(const bool flag){
_iterativeNR = flag;
};
void nonLinearMechSolver::lineSearch(const bool lin){
_lineSearch = lin;
}
void nonLinearMechSolver::pathFollowing(const bool p, const int method){
_pathFollowing = p;
_pfManager._pathFollowingMethod = (pathFollowingManager::pathFollowingMethod)method;
}
void nonLinearMechSolver::setPathFollowingIncrementAdaptation(const bool stepAdap, const int numNROptimal, const double exp)
{
_pfManager._numNROptimal = numNROptimal;
_pfManager._numNROptimalLocal = numNROptimal;
_pfManager._expNROptimal = exp;
_pfManager._pfStepAdaptation = stepAdap;
if (_pfManager._pfStepAdaptation) {
Msg::Info("path following increment is adapted with number of NR iterations");
}
};
void nonLinearMechSolver::setPathFollowingIncrementAdaptationLocal(const bool stepAdap, const int numNROptimalLoad, const int numNROptimalLocal, const double exp){
_pfManager._numNROptimal = numNROptimalLoad;
_pfManager._numNROptimalLocal = numNROptimalLocal;
_pfManager._expNROptimal = exp;
_pfManager._pfStepAdaptation = stepAdap;
if (_pfManager._pfStepAdaptation) {
Msg::Info("path following increment is adapted with number of NR iterations");
}
};
void nonLinearMechSolver::setPathFollowingControlType(const int i){
_pfManager._controlTypePathFollowing = i;
}
void nonLinearMechSolver::setPathFollowingCorrectionMethod(const int i){
_pfManager._correctionMethodPathFollowing = i;
};
void nonLinearMechSolver::setPathFollowingTranversalCriterion(const int i){
_pfManager._tranversalCriterionPathFollowing = i;
};
void nonLinearMechSolver::setPathFollowingSolverType( const int i, const double eqRatio){
_pfManager._solverTypePathFollowing = i;
_pfManager._pathFollowingEqRatio = eqRatio;
};
void nonLinearMechSolver::setPathFollowingLocalSteps(const double loadStep, const double localCrStep){
_pfManager._arcLengthStep = loadStep;
_pfManager._arcLengthStepPrev = loadStep;
_pfManager._localStep = localCrStep;
_pfManager._localStepPrev = localCrStep;
}
void nonLinearMechSolver::setPathFollowingArcLengthStep(const double arcStep){
_pfManager._arcLengthStep = arcStep;
_pfManager._arcLengthStepPrev = arcStep;
};
void nonLinearMechSolver::setBoundsOfPathFollowingLocalSteps(const double lowerBound, const double upperBound){
_pfManager._localStepMinimal = lowerBound;
_pfManager._localStepMaximal = upperBound;
Msg::Info("path following local step is bounded by lowerbound %e and by upper bound %e",lowerBound,upperBound);
};
void nonLinearMechSolver::setBoundsOfPathFollowingLoadSteps(const double lowerBound, const double upperBound){
_pfManager._arcLengthStepMinimal = lowerBound;
_pfManager._arcLengthStepMaximal = upperBound;
Msg::Info("path following load step is bounded by lowerbound %e and by upper bound %e",lowerBound,upperBound);
};
void nonLinearMechSolver::setBoundsOfPathFollowingArcLengthSteps(const double lowerBound, const double upperBound){
_pfManager._arcLengthStepMinimal = lowerBound;
_pfManager._arcLengthStepMaximal = upperBound;
Msg::Info("path following local step is bounded by lowerbound %e and by upper bound %e",lowerBound,upperBound);
};
void nonLinearMechSolver::setPathFollowingLocalIncrementType(const int i){
_pfManager._pathFollowingIncrementType = (pathFollowingManager::pathFollowingLocalIncrementType)i;
if (i == 0) {
Msg::Info("pf increment with defo energy");
}
else if (i == 1){
Msg::Info("pf increment with dissipation energy");
}
else if (i == 2){
Msg::Info("pf increment with plastic energy");
}
else if (i == 3){
Msg::Info("pf increment with damage energy");
}
else{
Msg::Error("missing case nonLinearMechSolver::setPathFollowingLocalIncrementType %d",i);
}
};
void nonLinearMechSolver::setPathFollowingLocation(const int loc){
_pfManager._pathFollowingLocation = (pathFollowingManager::pathFollowingLocation)loc;
if (_pfManager._pathFollowingLocation == pathFollowingManager::BULK_INTERFACE){
Msg::Info("path following constraint is contructed from bulk and interfaces elements");
}
else if (_pfManager._pathFollowingLocation == pathFollowingManager::BULK){
Msg::Info("path following constraint is contructed from bulk elements");
}
else if (_pfManager._pathFollowingLocation == pathFollowingManager::INTERFACE){
Msg::Info("path following constraint is contructed from interfaces elements");
}
else{
Msg::Error("case missing %d nonLinearMechSolver::setPathFollowingLocation ",loc);
}
};
void nonLinearMechSolver::setPathFollowingSwitchCriterion(const double cr){
_pfManager._pathFollowingSwitchCriterion = cr;
};
void nonLinearMechSolver::clearAllHyperellipticControlComp(){
_pfManager._hyperellipticControlComp.resize(0);
};
void nonLinearMechSolver::setHyperellipticControlComp(const int comp){
_pfManager._hyperellipticControlComp.push_back(comp);
Msg::Info("path following with comp %d",comp);
};
/*
void nonLinearMechSolver::setInitOrRestartFileName(const std::string fname){
initOrResartfname =fname;
_restart = true;
}
void nonLinearMechSolver::restart(unknownField *ufield){
if(!_restart) // no file to restart
return;
// create a map between elem number and adress
std::map<long int,std::pair<partDomain*,MElement*> > allelem;
for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain *dom = *itdom;
for(elementGroup::elementContainer::iterator ite = dom->g->begin(); ite!=dom->g->end(); ++ite){
MElement *ele = *ite;
std::pair<partDomain*,MElement*> pa(dom,ele);
allelem.insert(std::pair<long int,std::pair<partDomain*,MElement*> >(ele->getNum(),pa));
}
}
// read data in file
FILE *f = fopen(initOrResartfname.c_str(), "r");
char what[256];
while(!feof(f)){
fscanf(f, "%s", what);
if(!strcmp(what,"$ElementNodeData")){
int nstring;
fscanf(f,"%d",&nstring);
int i=0;
char what2[256];
while(i<nstring){
fscanf(f,"%s",&what2);
i++;
}
int nint, n;
fscanf(f,"%d",&nint);
i=0;
while(i<nint){
fscanf(f,"%d",&n);
i++;
}
fscanf(f,"%d",&nint);
if(nint != 4)
{
Msg::Error("Your restart file hasn't the good format since the number of int (!=4) is not good. The number of element is taken from the third one!");
}
int nelem;
i=0;
while(i<nint){
fscanf(f,"%d",&n);
if(i == 2)
nelem = n;
i++;
}
int elemnum,elemtype,ndofs,nvertex,ncomp;
i = 0;
int n2 = nelem; // because n is modified by fscanf(f,"%ld %d",&elemnum,&elemtype); WHY ??
while(i<n2){
fscanf(f,"%d %d",&elemnum,&elemtype);
//MElement *ele = allelem[elemnum].second;
//partDomain *dom = allelem[elem]
std::map<long int,std::pair<partDomain*,MElement*> >::iterator it = allelem.find(elemnum);
MElement *ele = (it->second).second;
partDomain *dom = (it->second).first;
FunctionSpaceBase *space = dom->getFunctionSpace();
std::vector<Dof> R;
space->getKeys(ele,R);
ndofs = space->getNumKeys(ele);
nvertex = ele->getNumVertices();
ncomp = ndofs/nvertex;
int j=0;
std::vector<double> disp;
disp.resize(ndofs);
//double temp;
while(j<nvertex){
for(int k=0;k<ncomp;k++){
fscanf(f,"%lf",&disp[j+k*nvertex]);
}
j++;
}
// set displacement in displacement field
ufield->setInitial(R,disp);
i++;
}
}
}
fclose(f);
ufield->buildAllView(domainVector,0.,0);
}
*/
void nonLinearMechSolver::insertTheta(const int numphys, elementGroup *goe){
allTheta.emplace_back();
nonLinearNeumannBC& neu = allTheta.back();
neu.g = goe;
neu.onWhat = nonLinearBoundaryCondition::UNDEF;
neu._tag = numphys;
neu._f = new simpleFunctionTimeWithConstant<double>(0.);
}
void nonLinearMechSolver::physInitBroken(const int dim, const int numphys){
initbrokeninter.push_back(std::pair<int,int>(dim,numphys));
};
void nonLinearMechSolver::initialBrokenDomain(const int phys)
{
initbrokeninterInDomains.push_back(std::pair<int,int>(phys,phys));
}
void nonLinearMechSolver::initialBrokenInterfaceDomain(const int physMinus, const int phyPlus)
{
initbrokeninterInDomains.push_back(std::pair<int,int>(physMinus,phyPlus));
}
void nonLinearMechSolver::createInterfaceElement(){
// Compute and add interface element to the model
// Loop on mesh element and store each edge (which will be distributed between InterfaceElement, Boundary InterfaceElement and VirtualInterfaceElement)
// A tag including the vertex number is used to identified the edge common to two elements. In this case a interface element is created
// manage creation of interface between 2 domains
pModel->setAsCurrent();
#if defined(HAVE_MPI)
if (getNumRanks() > 1 && ipViewInterface.size() > 0)
{
Msg::Barrier();
if (Msg::GetCommRank() > 0)
{
int maximalNumberEle = 0;
MPI_Status status;
MPI_Recv(&maximalNumberEle,1,MPI_INT,Msg::GetCommRank()-1,Msg::GetCommRank(),MPI_COMM_WORLD,&status);
pModel->setMaxElementNumber(maximalNumberEle);
}
}
#endif //HAVE_MPI
manageInterface maninter(&domainVector);
// loop on element
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom !=domainVector.end(); ++itdom)
{
partDomain *dom = *itdom;
dom->createInterface(maninter);
// remove interface element if domain is not DG ??
// there is other way do that
dgPartDomain* dgdom = dynamic_cast<dgPartDomain*>(dom);
if (dgdom){
if (!dgdom->IsInterfaceTerms()){
dgdom->gi->clearAll();
}
}
}
// virtual interface
for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain *dom = *itdom;
int phys = dom->getPhysical();
for(manageInterface::IelementContainer::iterator it=maninter.begin(); it!=maninter.end(); ++it){
IElement *ie = it->second;
if(ie->getPhys() == phys){
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
MElement* interel = dom->createVirtualInterface(ie);
dgdom->giv->insert(interel);
}
}
}
_mpiUserDom = domainVector.size();
#if defined(HAVE_MPI)
if(Msg::GetCommSize() > 1 and (_mapRanks.find(Msg::GetCommRank()) != _mapRanks.end())){
// first add interface to the interdomain defined by the user
for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom != domainVector.end(); ++itdom){
// find interdomain (g->size==0)
partDomain *dom = *itdom;
if(dom->elementGroupSize()==0){
int phys1,phys2;
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
manageInterface::getPhysDom(dom->getPhysical(),phys1,phys2);
// find both domains
partDomain *dom1=NULL;
partDomain *dom2=NULL;
for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom != domainVector.end(); ++itdom){
partDomain* domtmp = *itdom;
if(domtmp->getPhysical() == phys1) dom1=domtmp;
else if(domtmp->getPhysical() == phys2) dom2=domtmp;
if((dom1!=NULL) and(dom2!=NULL)) break;
}
if(dom1!=NULL){ // otherwise no element of dom1 on the partition
// find the group of ghosted element of dom2
std::map<int,std::vector<elementGroup> >::iterator itg= _mapOtherDomain.find(phys2);
if(itg!=_mapOtherDomain.end()){
for(int i=0; i< itg->second.size(); i++){
elementGroup &group = itg->second[i];
if(group.size()!=0)
dom1->createInterfaceMPI(i,group,dgdom);
}
}
}
if(dom2!=NULL){ // otherwise no element of dom1 on partition
// find the group of ghosted element of dom1
std::map<int,std::vector<elementGroup> >::iterator itg= _mapOtherDomain.find(phys1);
if(itg!=_mapOtherDomain.end()){
for(int i=0; i< itg->second.size(); i++){
elementGroup &group = itg->second[i];
if(group.size()!=0)
dom2->createInterfaceMPI(i,group,dgdom);
}
}
}
}
}
// create pure interface domain for MPI
for(std::map<int,std::vector<elementGroup> >::iterator it=_mapOtherDomain.begin(); it!=_mapOtherDomain.end(); ++it){
int physdom = it->first;
// get the domain
partDomain *dom = NULL;
for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom != domainVector.end(); ++itdom){
if(physdom == (*itdom)->getPhysical()){
dom = *itdom;
break;
}
}
if(dom != NULL){
std::vector<elementGroup> & groupOtherPart = it->second;
dgPartDomain* newInterDom = NULL;
int gsize = groupOtherPart.size();
for(int i=0; i< gsize; i++){
if(i!=Msg::GetCommRank()){
elementGroup &group = groupOtherPart[i];
if(group.size() != 0){ // otherwise no domain to create
dom->createInterfaceMPI(i,group,newInterDom);
}
}
}
if((newInterDom!=NULL) and (newInterDom->gi->size() > 0)){
// law are set before (change this ??)
newInterDom->setMaterialLaw(maplaw);
domainVector.push_back(newInterDom); // otherwise no interface element
}
else{
if(newInterDom!=NULL) delete newInterDom;
}
}
}
}
#endif // HAVE_MPI
// save to file
if (ipViewInterface.size() > 0)
{
elementGroup gr;
for (int i=0; i< domainVector.size(); i++)
{
dgPartDomain* dom = dynamic_cast<dgPartDomain*>(domainVector[i]);
if (dom != NULL)
{
for (elementGroup::elementContainer::const_iterator it = dom->gi->begin(); it != dom->gi->end(); it++)
{
gr.insert(it->second);
}
}
}
if (gr.size() > 0)
{
std::string fname = "allInterfaceElements.msh";
#if defined(HAVE_MPI)
if (getNumRanks() > 1)
{
fname = "allInterfaceElements_part"+std::to_string(Msg::GetCommRank())+".msh";
}
#endif //HAVE_MPI
InterpolationOperations::write_MSH2(&gr,fname);
};
}
#if defined(HAVE_MPI)
if (getNumRanks() > 1 && (ipViewInterface.size() > 0))
{
if (Msg::GetCommRank() < getNumRanks()-1)
{
int maximalNumberEle = pModel->getMaxElementNumber();
MPI_Send(&maximalNumberEle,1,MPI_INT,Msg::GetCommRank()+1,Msg::GetCommRank()+1,MPI_COMM_WORLD);
}
printf("rankd %d numximal element id = %ld \n",Msg::GetCommRank(),pModel->getMaxElementNumber());
}
#endif //HAVE_MPI
};
void nonLinearMechSolver::createInterfaceElement_2()
{
// The contructor of dgGroupCollection create automatically the GroupsOfElements
/* _groups = dgGroupCollection(this->pModel,this->_dim,1); // TODO ?? Add parameter to model to store order
_groups.buildGroupsOfInterfaces();
// Affichage temporaire pour vérification
int nn = _groups.getNbFaceGroups();
printf("Number of group of faces : %d\n",nn);
for(int i=0;i<nn;i++){
printf("Group of face number %d\n",i);
dgGroupOfFaces *inter = _groups.getFaceGroup(i);
int nnn = inter->getNbGroupOfConnections();
printf("Number of connection group %d \n",nnn);
for(int j=0;j<nnn;j++){
const dgGroupOfConnections connec = inter->getGroupOfConnections(j);
printf("Connection's group number %d\n",j);
int nnnn = connec.getNbClosures();
printf("Number of closures %d\n",nnnn);
for(int k=0;k<nnnn;k++){
printf("Closure number %d\n",k);
std::vector<int> vec = connec.getClosure(k);
for(int kk=0;kk<vec.size();kk++){
printf(" %d ",vec[kk]);
}
printf("\n");
}
}
}*/
}
void nonLinearMechSolver::rotateModel(const SVector3& n1, const SVector3& n2, const SVector3& n3){
if (!_GModelIsRotated){
_GModelIsRotated = true;
GeometryRotation::rotateGModel(getFileSavingPrefix(),pModel,n1,n2,n3);
}
};
int nonLinearMechSolver::getInterfaceElementNumber(const int em, const int ep) const{
TwoNum tn(em,ep);
std::map<TwoNum,int>::const_iterator itF = _interfaceElements.find(tn);
if ( itF != _interfaceElements.end())
{
return itF->second;
}
else{
Msg::Error("interface element with negative %d positive %d is not found nonLinearMechSolver::getInterfaceElementNumber!",em,ep);
}
return 0;
};
TwoNum nonLinearMechSolver::getMinusAndPlusElementNumber(const int elnum) const{
std::map<int,TwoNum>::const_iterator itF = _interfaceElementsInverseMap.find(elnum);
if (itF != _interfaceElementsInverseMap.end()){
return itF->second;
}
else{
#if defined (HAVE_MPI)
if (Msg::GetCommSize() > 1)
Msg::Error("interface element %d is not found nonLinearMechSolver::getMinusAndPlusElementNumber at rank %d",elnum,Msg::GetCommRank());
else
#endif // HAVE_MPI
Msg::Error("interface element %d is not found nonLinearMechSolver::getMinusAndPlusElementNumber",elnum);
}
return TwoNum(0,0);
};
void nonLinearMechSolver::initTerms(){
// resize _vterm in NeumannBC
if(_previousInit){ // if previous computation delete first the terms
// BC
for(std::list<nonLinearNeumannBC>::iterator itbc = allNeumann.begin(); itbc != allNeumann.end();++itbc)
{
for(int j=0;j<itbc->_vterm.size();j++)
{
delete itbc->_vterm[j];
}
}
// domain
for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain *dom = *itdom;
if(dom->getBilinearBulkTerm() != NULL) delete dom->getBilinearBulkTerm();
if(dom->getBilinearMassTerm() != NULL) delete dom->getBilinearMassTerm();
if(dom->getLinearBulkTerm() != NULL) delete dom->getLinearBulkTerm();
if(dom->IsInterfaceTerms()){
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
if(dgdom->getBilinearInterfaceTerm() != NULL) delete dgdom->getBilinearInterfaceTerm();
if(dgdom->getBilinearVirtualInterfaceTerm() !=NULL) delete dgdom->getBilinearVirtualInterfaceTerm();
if(dgdom->getLinearInterfaceTerm() != NULL) delete dgdom->getLinearInterfaceTerm();
if(dgdom->getLinearVirtualInterfaceTerm() != NULL) delete dgdom->getLinearVirtualInterfaceTerm();
}
}
}
for(std::list<nonLinearNeumannBC>::iterator itbc = allNeumann.begin(); itbc != allNeumann.end();++itbc)
{
nonLinearNeumannBC &neu = *itbc;
int nsize = neu._vspace.size();
neu._vterm.resize(nsize);
neu._vmatrix_term.resize(nsize);
for(int j=0;j<nsize;++j)
{
neu._vterm[j] = neu._vdom[j]->createNeumannTerm(static_cast<FunctionSpace<double>*>(neu._vspace[j]), neu._vgroup[j],
neu._f,_ufield, _ipf,neu.onWhat,neu._NeumannBCType, neu._comp);
neu._vmatrix_term[j] = neu._vdom[j]->createNeumannMatrixTerm(static_cast<FunctionSpace<double>*>(neu._vspace[j]), neu._vgroup[j],
neu._f,_ufield, _ipf,neu.onWhat,neu._NeumannBCType, neu._comp);
}
}
for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain *dom = *itdom;
dom->initializeTerms(_ufield,_ipf);
}
// contact domain
for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){
contactDomain *cdom = *it;
cdom->initializeTerms(_ufield);
}
// contact domain
for(defoDefoContactContainer::iterator it = _allDefoDefoContact.begin(); it!=_allDefoDefoContact.end(); ++it){
defoDefoContactDomain *cdom = *it;
cdom->initializeTerms(_ufield);
}
}
double nonLinearMechSolver::solveStaticLinear()
{
this->init();
this->init2();
/* time initialization */
double curtime = 1.;
double timestep = 1.;
int step = 1;
/* solving */
this->setTimeForLaw(curtime,timestep,step);
std::cout << "Neumann BC"<< std::endl;
double tsystresol = Cpu();
this->computeExternalForces();
this->computeStiffMatrix();
printf("-- done assembling!\n");
pAssembler->systemSolve();
printf("-- done solving!\n");
/* compute stress after solve */
_ipf->compute1state(IPStateBase::current,true);
double normRHS = computeRightHandSide(); // to make all archiving possible
/* end of scheme */
tsystresol = Cpu() - tsystresol;
Msg::Info("Time of resolution: %f",tsystresol);
this->endOfScheme(curtime,step);
Msg::Info("StaticLinear OK");
return curtime;
}
double nonLinearMechSolver::solveEigen()
{
// no view
unknownView.clear();
ipView.clear();
_energyComputation = 0;
_fractureEnergyComputation = 0;
/* init data */
this->init();
this->init2();
/* time initialization */
double curtime = 1.;
double timestep = 1.;
int step = 1;
/* solving */
this->setTimeForLaw(curtime,timestep,step);
printf("--begin assembling \n");
double tsystresol = Cpu();
if (_eigOpts.type == eigenSolverOptions::Dynamic)
{
this->computeMassMatrix();
}
this->computeStiffMatrix();
printf("-- done assembling!\n");
if (_eigOpts.MKToFile){
#if defined(HAVE_PETSC)
std::string Aname("A");
linearSystem<double>* lsysA = pAssembler->getLinearSystem(Aname);
std::string Bname("B");
linearSystem<double>* lsysB = pAssembler->getLinearSystem(Bname);
linearSystemPETSc<double>* Apet = dynamic_cast<linearSystemPETSc<double>*>(lsysA);
if (Apet!= NULL) {
functionPETSc::MatToFile(Apet->getMatrix(),"Mat_Stiffness.txt");
linearSystemPETSc<double>* Bpet = dynamic_cast<linearSystemPETSc<double>*>(lsysB);
if (Bpet!= NULL) {
functionPETSc::MatToFile(Bpet->getMatrix(),"Mat_Mass.txt");
};
}
#endif
}
#if defined (HAVE_SLEPC)
eigenSolver* eigSolver = this->eigenSolve(step);
eigenVectorField eigfield(this,eigSolver,3,_eigview,"eigenMode");
eigfield.archive(curtime,step,false);
// save perturbe file
if (_eigOpts.isPerturbedEigenMode)
{
if (eigSolver!=NULL)
{
writeDisturbedMeshByEigenVector(*eigSolver,_eigOpts.numberPerturbedMode,_eigOpts.valPerturbedMode);
}
}
delete eigSolver;
#else
Msg::Error("Slepc is not intalled");
#endif // HAVE_SLEPC
printf("-- done solving!\n");
/* end of scheme */
this->endOfScheme(curtime,step);
tsystresol = Cpu() - tsystresol;
Msg::Info("Time of Eigen Value resolution resolution: %f",tsystresol);
Msg::Info("EigenSolve OK");
return curtime;
}
void nonLinearMechSolver::computeLoadVector()
{
this->setTimeForBC(1.);
for(std::list<nonLinearNeumannBC>::iterator itbc = allNeumann.begin(); itbc != allNeumann.end();++itbc)
{
nonLinearNeumannBC &neu = *itbc;
// select the system if required
for(int j=0;j<neu._vspace.size();j++)
{
FunctionSpaceBase *spn = neu._vspace[j];
const elementGroup *gneu = neu._vgroup[j];
QuadratureBase *qneu = neu._vquadrature[j];
Assemble(neu._vterm[j],*spn,gneu->begin(),
gneu->end(),*(qneu),_ufield,*pAssembler,nonLinearSystemBase::LoadVector, _elementErosionFilter);
}
}
//
if (_testFlag){
if (_pbcGroup != NULL)
{
for (std::list<nonLinearNeumannBCAtCorner>::iterator itc = allCornerForce.begin(); itc != allCornerForce.end();++itc){
nonLinearNeumannBCAtCorner& con = *itc;
// select the system if required
std::vector<Dof>& allDof = con.constraintDofs;
int size = allDof.size();
MVertex* v = _pbcGroup->getCornerVertex(con._cornerNumber);
fullVector<double> F;
F.resize(size,true);
double val = con._f->operator ()(v->x(),v->y(),v->z());
F.setAll(val);
pAssembler->assemble(allDof,F,nonLinearSystemBase::LoadVector);
};
};
};
this->setTimeForBC(0.);
}
// for path following on RVE
void nonLinearMechSolver::computeBodyForceVector(){
_pAl->zeroBodyForceVector();
static STensor33 G0;
static STensor33 G1;
double curtime = this->getMicroBC()->getTime();
this->getMicroBC()->setTime(0.);
G0 = this->getMicroBC()->getSecondOrderKinematicalVariable();
this->getMicroBC()->setTime(1.);
G1 = this->getMicroBC()->getSecondOrderKinematicalVariable();
this->getMicroBC()->setTime(curtime);
G1 -=G0;
for (int idom=0; idom<domainVector.size(); idom++){
partDomain* dom = domainVector[idom];
dom->setSecondOrderKinematic(G1);
if (dom->elementGroupSize()>0){
AssembleBodyForceVector(*dom->getLinearTermPFBodyForce(),*dom->getFunctionSpace(),dom->element_begin(),
dom->element_end(),*dom->getBulkGaussIntegrationRule(),*pAssembler,_elementErosionFilter);
}
}
}
void nonLinearMechSolver::setHomogeneousTangentToDomain(homogenizedData* homoData){
static STensor43 Homogeneous_K;
Homogeneous_K = homoData->getHomogenizedTangentOperator_F_F();
double volume = 0.;
for (int i=0; i<domainVector.size(); i++){
volume += domainVector[i]->computeVolumeDomain(_ipf);
};
Homogeneous_K *= _rveVolume/volume;
for (int idom=0; idom<domainVector.size(); idom++){
partDomain* dom = domainVector[idom];
dom->setHomogeneousTangent(Homogeneous_K);
}
}
void nonLinearMechSolver::computePathFollowingConstraint()
{
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end();++itdom)
{
partDomain *dom = *itdom;
if (dom->getMaterialLaw() != NULL){
if (dom->getMaterialLaw()->withEnergyDissipation()){
AssemblerPathFollowingConstraint(*(dom->getScalarTermPFBulk()),dom->element_begin(),dom->element_end(),*(dom->getBulkGaussIntegrationRule()),*pAssembler,_elementErosionFilter);
}
}
if (dom->IsInterfaceTerms()){
dgPartDomain* dgDom = static_cast<dgPartDomain*>(dom);
if (dgDom->getMaterialLawMinus()->withEnergyDissipation() or dgDom->getMaterialLawPlus()->withEnergyDissipation()){
AssemblerPathFollowingConstraint(*(dgDom->getScalarTermPFBound()),dgDom->gi->begin(),dgDom->gi->end(),
*(dgDom->getInterfaceGaussIntegrationRule()),*pAssembler,_elementErosionFilter);
}
}
}
};
void nonLinearMechSolver::computeDPathFollowingConstraintDUnknowns(){
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end();++itdom)
{
partDomain *dom = *itdom;
if (dom->getMaterialLaw() != NULL){
if (dom->getMaterialLaw()->withEnergyDissipation()){
AssemblerDPathFollowingConstraintDUnknowns(*(dom->getLinearTermPFBulk()),*(dom->getFunctionSpace()),
dom->element_begin(),dom->element_end(),*(dom->getBulkGaussIntegrationRule()),*pAssembler,_elementErosionFilter);
}
}
if (dom->IsInterfaceTerms())
{
dgPartDomain* dgDom = static_cast<dgPartDomain*>(dom);
if (dgDom->getMaterialLawMinus()->withEnergyDissipation() or dgDom->getMaterialLawPlus()->withEnergyDissipation()){
AssemblerDPathFollowingConstraintDUnknowns(*(dgDom->getLinearTermPFBound()),*(dgDom->getFunctionSpace()),
dgDom->gi->begin(),dgDom->gi->end(),*(dgDom->getInterfaceGaussIntegrationRule()),*pAssembler,_elementErosionFilter);
}
}
}
};
void nonLinearMechSolver::computeExternalForces()
{
if(this->getScheme() != StaticLinear)
{
for (std::list<nonLinearNeumannBC>::iterator itbc = allNeumann.begin(); itbc != allNeumann.end();++itbc)
{
nonLinearNeumannBC &neu = *itbc;
for(int j=0;j<neu._vspace.size();j++)
{
FunctionSpaceBase *spn = neu._vspace[j];
const elementGroup *gneu = neu._vgroup[j];
QuadratureBase *qneu = neu._vquadrature[j];
Assemble(neu._vterm[j],*spn,gneu->begin(),
gneu->end(),*(qneu),_ufield,*pAssembler,nonLinearSystemBase::Fext,_elementErosionFilter);
}
}
//
if (_testFlag)
{
if (_pbcGroup != NULL)
{
for (std::list<nonLinearNeumannBCAtCorner>::iterator itc = allCornerForce.begin(); itc != allCornerForce.end();++itc)
{
nonLinearNeumannBCAtCorner& con = *itc;
// select the system if required
std::vector<Dof>& allDof = con.constraintDofs;
int size = allDof.size();
MVertex* v = _pbcGroup->getCornerVertex(con._cornerNumber);
fullVector<double> F;
F.resize(size,true);
double val = con._f->operator ()(v->x(),v->y(),v->z());
F.setAll(val);
pAssembler->assemble(allDof,F,nonLinearSystemBase::Fext);
};
};
};
}
else{
for(std::list<nonLinearNeumannBC>::iterator itbc = allNeumann.begin(); itbc != allNeumann.end();++itbc)
{
nonLinearNeumannBC &neu = *itbc;
for(int j=0;j<neu._vspace.size();j++)
{
FunctionSpaceBase *spn = neu._vspace[j];
const elementGroup *gneu = neu._vgroup[j];
QuadratureBase *qneu = neu._vquadrature[j];
AssembleItMap(*(neu._vterm[j]),*spn,gneu->begin(),gneu->end(),*(qneu),*pAssembler,_elementErosionFilter);
}
}
if (_testFlag)
{
if (_pbcGroup != NULL){
for (std::list<nonLinearNeumannBCAtCorner>::iterator itc = allCornerForce.begin(); itc != allCornerForce.end();++itc){
nonLinearNeumannBCAtCorner& con = *itc;
std::vector<Dof>& allDof = con.constraintDofs;
int size = allDof.size();
MVertex* v = _pbcGroup->getCornerVertex(con._cornerNumber);
fullVector<double> F;
F.resize(size,true);
double val = con._f->operator ()(v->x(),v->y(),v->z());
F.setAll(val);
pAssembler->assemble(allDof,F);
};
};
};
}
}
void nonLinearMechSolver::snlData(const int ns, const double et, const double reltol, const double absTol){
if(whatScheme==StaticNonLinear or whatScheme==Multi or whatScheme== Implicit)
{
_timeManager->setEndTime(et);
_timeManager->setNumSteps(ns);
// tolerance
_tol=reltol;
_absTol=absTol;
if (whatScheme==Multi)
{
// if implicit-explict scheme is used
_explicitOpts.numstepImpl = ns;
}
}
else
{
Msg::Error("Impossible to set data for Static Non Linear scheme because another is chosen to solve the problem");
_timeManager->setEndTime(et);
_timeManager->setNumSteps(1);
}
};
void nonLinearMechSolver::clearNumStepSeries()
{
_timeManager->clearNumStepSeries();
}
void nonLinearMechSolver::setNumStepTimeInterval(double t, int nstep)
{
if (whatScheme==Multi || whatScheme==Explicit)
{
Msg::Error("setNumStepTimeInterval is applicable in case of Static Non Linear scheme");
}
else
{
_timeManager->setNumStepTimeInterval(t,nstep);
}
}
void nonLinearMechSolver::clearMultiSystem()
{
_vcompBySys.clear();
_vschemeBySys.clear();
}
void nonLinearMechSolver::addSystem(const int comp,const int s)
{
_vcompBySys.push_back(comp);
_vschemeBySys.push_back((scheme)s);
}
void nonLinearMechSolver::switchSystem(const int sysindex,const int s)
{
_vschemeBySys[sysindex] = (scheme)s;
}
void nonLinearMechSolver::setTimeIncrementAdaptation(const bool adap, const int numNROptimal, const double exp, const double maximalStep, const double minTimeStep, const int maxFailtIn)
{
_timeManager->activateTimeStepAdaptation(adap,numNROptimal,exp,maximalStep,minTimeStep);
_timeManager->setMaximalNumberOfFails(maxFailtIn);
}
void nonLinearMechSolver::snlManageTimeStep(const int miteNR,const int iteIncreaseTS, const double redfactor, const int maxAttemptRedFactor)
{
_timeManager->setManageTimeStepSafeguard(miteNR,iteIncreaseTS,redfactor,maxAttemptRedFactor);
}
void nonLinearMechSolver::explicitData(const double ftime, const double gams, const double beta, const double gamma, const double alpham,const bool benson){
//
_timeManager->setEndTime(ftime);
_explicitOpts.timeStepByBenson = benson;
_explicitOpts.beta=beta;
_explicitOpts.gamma=gamma;
_explicitOpts.alpham = alpham;
// depends on numerical damping
double _rhoinfty = (alpham+1.)/(2.-alpham);
double omegas = sqrt((12.*(1.+_rhoinfty)*(1.+_rhoinfty)*(1.+_rhoinfty)*(2.-_rhoinfty))/(10.+15.*_rhoinfty-_rhoinfty*_rhoinfty+_rhoinfty*_rhoinfty*_rhoinfty-_rhoinfty*_rhoinfty*_rhoinfty*_rhoinfty));
_explicitOpts.gammas = gams*omegas;
}
void nonLinearMechSolver::implicitData(const double beta, const double gamma, const double alpham , const double alphaf){
_implicitOpts.beta = beta;
_implicitOpts.gamma = gamma;
_implicitOpts.alphaf = alphaf;
_implicitOpts.alpham = alpham;
};
void nonLinearMechSolver::explicitSpectralRadius(const double ftime,const double gams, const double rho,const bool benson){
_timeManager->setEndTime(ftime); // set end time
_explicitOpts.timeStepByBenson = benson;
double _rhoinfty=rho;
_explicitOpts.beta = (5.-3.*_rhoinfty)/((1.+_rhoinfty)*(1.+_rhoinfty)*(2.-_rhoinfty));
_explicitOpts.alpham = (2.*_rhoinfty-1.)/(1.+_rhoinfty);
_explicitOpts.gamma = 1.5-_explicitOpts.alpham;
double omegas = sqrt((12.*(1.+_rhoinfty)*(1.+_rhoinfty)*(1.+_rhoinfty)*(2.-_rhoinfty))/(10.+15.*_rhoinfty-_rhoinfty*_rhoinfty+_rhoinfty*_rhoinfty*_rhoinfty-_rhoinfty*_rhoinfty*_rhoinfty*_rhoinfty));
_explicitOpts.gammas = gams*omegas;
}
void nonLinearMechSolver::options(const std::string &options)
{
if(!strcmp("petsc_direct",options.c_str()))
{
_solver_options = std::string("-pc_type lu -ksp_type preonly");
}
else if(!strcmp("petsc_gmres",options.c_str()))
{
_solver_options = std::string("-pc_type jacobi -ksp_gmres_restart 200");
}
else if(!strcmp("petsc_mumps",options.c_str()))
{
_solver_options = std::string("-pc_mat_solver_package mumps");
}
else
{
_solver_options = std::string(options);
}
return;
}
void nonLinearMechSolver::implicitSpectralRadius(const double rho){
double _rhoinfty = rho;
_implicitOpts.alpham = (2.*_rhoinfty-1.)/(1.+_rhoinfty);
_implicitOpts.alphaf = _rhoinfty/(_rhoinfty +1.);
_implicitOpts.beta = 1./((_rhoinfty +1.)*(_rhoinfty +1.));
_implicitOpts.gamma = (3.-_rhoinfty)/(2.+2.*_rhoinfty);
};
void nonLinearMechSolver::explicitTimeStepEvaluation(const int nst){
_explicitOpts.numstepExpl = nst;
}
double nonLinearMechSolver::solve(){
double tstart=Cpu();
double reachtime=0.;
if (_microFlag == false){
switch(whatScheme){
case StaticLinear :
reachtime = this->solveStaticLinear();
break;
case StaticNonLinear :
reachtime = this->solveSNL();
break;
case Implicit:
reachtime = this->solveSNL();
break;
case Explicit:
reachtime = this->solveExplicit();
break;
case Multi:
reachtime = this->solveMulti();
break;
case Eigen:
reachtime = this->solveEigen();
break;
}
}
else{
switch(whatScheme){
case StaticLinear:
reachtime = this->microSolveStaticLinear();
break;
case StaticNonLinear :
reachtime = this->microSolveSNL();
break;
}
};
if (getNumRanks() > 1)
Msg::Barrier(); // wait all before end (for MPI)
_notResetedBC = true;
_notResetedContact = true;
_explicitOpts.dynamicRelaxation = false;
Msg::Info("Total time consuming %.6f (s) ",Cpu()-tstart);
return reachtime;
}
void nonLinearMechSolver::resetBoundaryConditions()
{
for(std::list<nonLinearDirichletBC>::iterator itbc = allDirichlet.begin(); itbc != allDirichlet.end();++itbc)
{
itbc->clear();
}
allDirichlet.clear();
for(std::list<nonLinearNeumannBC>::iterator itbc = allNeumann.begin(); itbc != allNeumann.end();++itbc)
{
itbc->clear();
}
allNeumann.clear();
for(std::list<initialCondition>::iterator itic = allinitial.begin(); itic !=allinitial.end();++itic)
{
itic->clear();
}
allinitial.clear();
allCornerConstraint.clear();
allCornerForce.clear();
// clear all other BC
// as objects created, destructor leading to clean the objects
_nodePeriodicPhysicals.clear();
_edgePeriodicPhysicals.clear();
allPeriodic.clear();
allAveragePeriodic.clear();
allSameDisp.clear();
allFixAllFace.clear();
allConstraint.clear();
_testFlag = false;
if (_pbcGroup) {
delete _pbcGroup;
_pbcGroup = NULL;
}
_notResetedBC = false;
}
void nonLinearMechSolver::resetContactInteraction()
{
// for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){
// contactDomain *cdom = *it;
// delete cdom;
// }
_allContact.clear();
//HERE NOT SURE WE NEED TO RESET THE DEFO DEFO CONTACT; DO ANOTHER FUNCTION?
_notResetedContact = false;
}
void nonLinearMechSolver::disableResetRestart() //to avoid restart at a change of solver
{
_disableResetRestart = true;
}
// to set tag of domain that needs restart to save/load InternalState
void nonLinearMechSolver::setRestartDomainTag(const int tag)
{
_restartDomainTag.push_back(tag);
}
// get domain tag for restart InternalState set by user
const std::vector<int> nonLinearMechSolver::getRestartDomainTag()
{
return _restartDomainTag;
}
void nonLinearMechSolver::dynamicRelaxation(const double gams,const double ftime,const double tol,const int wsolver,const bool benson)
{
_explicitOpts.timeStepByBenson = true;
_explicitOpts.dynamicRelaxation = true;
whatScheme = Explicit;
if(wsolver == 2)
whatSolver = Petsc;
_tol = tol;
this->explicitSpectralRadius(ftime,gams,0.99); //rho_infty == 0 for dynamic relaxtion (no influence ??)
}
double nonLinearMechSolver::getCoordinatesOfNodePhysical(const int numphys, const int comp)
{
elementGroup gr(0,numphys);
if (gr.vsize() != 1)
{
Msg::Error("physical %d consisting of %d nodes",gr.vsize());
}
else
{
MVertex* v = gr.vbegin()->second;
if (comp ==0) return v->x();
else if (comp == 1) return v->y();
else if (comp == 2) return v->z();
else
Msg::Error("comp %d does not exist",comp);
}
return 0.;
};
void nonLinearMechSolver::displacementBC(std::string onwhat, const int numphys, const int comp, const double value)
{
simpleFunctionTime<double> *fct = new simpleFunctionTime<double>(value);
elementFilterTrivial filter = elementFilterTrivial();
this->displacementBC(onwhat,numphys,comp,&filter,fct,mixedFunctionSpaceBase::DOF_STANDARD);
}
void nonLinearMechSolver::displacementBC(std::string onwhat, const int numphys, const int comp, const double valueDiff, const double valueInit){
simpleFunctionTime<double> *fct = new simpleFunctionTimeWithConstant<double>(valueDiff,true,1.,valueInit);
elementFilterTrivial filter = elementFilterTrivial();
this->displacementBC(onwhat,numphys,comp,&filter,fct,mixedFunctionSpaceBase::DOF_STANDARD);
};
void nonLinearMechSolver::velocityBC(std::string onwhat, const int numphys, const int comp, const double value)
{
this->displacementBC(onwhat,numphys,comp,value);
allDirichlet.back()._mycondition = nonLinearBoundaryCondition::velocity;
}
void nonLinearMechSolver::accelerationBC(std::string onwhat, const int numphys, const int comp, const double value)
{
this->displacementBC(onwhat,numphys,comp,value);
allDirichlet.back()._mycondition = nonLinearBoundaryCondition::acceleration;
}
void nonLinearMechSolver::displacementBC(std::string onwhat, const int numphys, const int comp, const double value, elementFilter *filter)
{
simpleFunctionTime<double> *fct = new simpleFunctionTime<double>(value);
this->displacementBC(onwhat,numphys,comp,filter,fct,mixedFunctionSpaceBase::DOF_STANDARD);
}
void nonLinearMechSolver::velocityBC(std::string onwhat, const int numphys, const int comp, const double value, elementFilter *filter)
{
this->displacementBC(onwhat,numphys,comp,value,filter);
allDirichlet.back()._mycondition = nonLinearBoundaryCondition::velocity;
}
void nonLinearMechSolver::displacementBC(std::string onwhat, const int numphys, const int comp,simpleFunctionTime<double> *fct)
{
elementFilterTrivial filter = elementFilterTrivial();
this->displacementBC(onwhat,numphys,comp,&filter,fct,mixedFunctionSpaceBase::DOF_STANDARD);
}
void nonLinearMechSolver::velocityBC(std::string onwhat, const int numphys, const int comp,simpleFunctionTime<double> *fct)
{
this->displacementBC(onwhat,numphys,comp,fct);
allDirichlet.back()._mycondition = nonLinearBoundaryCondition::velocity;
}
void nonLinearMechSolver::curlDisplacementBC(std::string onwhat, const int numphys, const int comp, const double value)
{
simpleFunctionTime<double> *fct = new simpleFunctionTime<double>(value);
elementFilterTrivial filter = elementFilterTrivial();
this->displacementBC(onwhat,numphys,comp,&filter,fct,mixedFunctionSpaceBase::DOF_CURL);
}
void nonLinearMechSolver::displacementBC(std::string onwhat, const int numphys, const int comp, elementFilter *filter,
simpleFunctionTime<double> *fct, const mixedFunctionSpaceBase::DofType dofType)
{
allDirichlet.emplace_back();
nonLinearDirichletBC& diri = allDirichlet.back();
const std::string node("Node");
const std::string edge("Edge");
const std::string face("Face");
const std::string volume("Volume");
diri.g = new elementGroup();
if(onwhat==node){
if(dofType !=mixedFunctionSpaceBase::DOF_STANDARD)
Msg::Error("nonLinearMechSolver::displacementBC: impossible to constrain a non vertex dof on a node");
diri.g->addPhysical(0, numphys,*filter);
diri.onWhat=nonLinearBoundaryCondition::ON_VERTEX;
}
else if(onwhat==edge){
diri.g->addPhysical(1, numphys,*filter);
diri.onWhat=nonLinearBoundaryCondition::ON_EDGE;
}
else if(onwhat==face){
diri.g->addPhysical(2, numphys,*filter);
diri.onWhat=nonLinearBoundaryCondition::ON_FACE;
}
else if(onwhat==volume){
diri.g->addPhysical(3, numphys,*filter);
diri.onWhat=nonLinearBoundaryCondition::ON_VOLUME;
}
else{
Msg::Error("Impossible to prescribe a displacement on a %s\n",onwhat.c_str());
delete diri.g;
return;
}
diri._f= static_cast<simpleFunctionTime<double>*>(fct);
diri._comp=comp;
diri._tag=numphys;
diri._dofType=dofType;
};
void nonLinearMechSolver::velocityBC(std::string onwhat, const int numphys, const int comp, elementFilter *filter,
simpleFunctionTime<double> *fct)
{
this->displacementBC(onwhat,numphys,comp,filter,fct,mixedFunctionSpaceBase::DOF_STANDARD);
allDirichlet.back()._mycondition = nonLinearBoundaryCondition::velocity;
}
void nonLinearMechSolver::displacementRigidContactBC(const int numphys, const int comp_, const double value)
{
simpleFunctionTime<double> *fct = new simpleFunctionTime<double>(value);
this->displacementRigidContactBC(numphys,comp_,fct);
}
void nonLinearMechSolver::displacementRigidContactBC(const int numphys, const int comp_, simpleFunctionTime<double> *fct)
{
allContactBC.emplace_back(numphys);
rigidContactBC& diri = allContactBC.back();
diri.onWhat = nonLinearBoundaryCondition::RIGIDCONTACT;
diri._comp = comp_;
diri._f = static_cast<simpleFunctionTime<double>*>(fct);
}
void nonLinearMechSolver::initialBC(std::string onwhat, std::string whichC, const int numphys,
const int comp, const double value)
{
elementFilterTrivial filter = elementFilterTrivial();
this->initialBC(onwhat,whichC,numphys,comp,value,&filter);
}
void nonLinearMechSolver::initialBC(std::string onwhat, std::string whichC, const int numphys,
const int comp, const double value,
elementFilter *filter)
{
simpleFunctionTime<double>* sfunction = new simpleFunctionTime<double>(value,false,0.);
this->initialBC(onwhat,whichC,numphys,comp,sfunction,filter);
}
void nonLinearMechSolver::initialBC(std::string onwhat, std::string whichC, const int numphys, const int comp,
simpleFunctionTime<double> *fct,elementFilter* filter)
{
bool nullfilter=false;
if(filter==NULL)
{
filter = new elementFilterTrivial();
nullfilter = true;
}
const std::string node("Node");
const std::string edge("Edge");
const std::string face("Face");
const std::string volume("Volume");
const std::string rigid("Rigid");
const std::string position("Position");
const std::string velocity("Velocity");
const std::string acceleration("Acceleration");
nonLinearBoundaryCondition::location ow;
elementGroup *gr = new elementGroup();
if(onwhat == node){
ow = nonLinearBoundaryCondition::ON_VERTEX;
gr->addPhysical(0,numphys,*filter);
}
else if(onwhat == edge){
ow = nonLinearBoundaryCondition::ON_EDGE;
gr->addPhysical(1,numphys,*filter);
}
else if(onwhat == face){
ow = nonLinearBoundaryCondition::ON_FACE;
gr->addPhysical(2,numphys,*filter);
}
else if(onwhat == volume){
ow = nonLinearBoundaryCondition::ON_VOLUME;
gr->addPhysical(3,numphys,*filter);
}
else if(onwhat == rigid)
{
ow = nonLinearBoundaryCondition::RIGIDCONTACT;
// empty group insert gravity center later
}
else{
ow = nonLinearBoundaryCondition::UNDEF;
gr->addPhysical(2,numphys,*filter);
}
nonLinearBoundaryCondition::whichCondition wc;
if(whichC == position)
wc = nonLinearBoundaryCondition::position;
else if(whichC == velocity)
wc = nonLinearBoundaryCondition::velocity;
else if(whichC == acceleration)
wc = nonLinearBoundaryCondition::acceleration;
else{
Msg::Warning("Impossible to prescribed an initial condition %d",numphys);
//return;
}
allinitial.emplace_back(comp,wc);
initialCondition& initc = allinitial.back();
initc.onWhat = ow;
initc.g = gr;
initc._tag = numphys;
initc._f = fct;
if(nullfilter)
{
delete filter;
}
}
void nonLinearMechSolver::initialDCBVeloBC(std::string onwhat,const int numphys,const int axiscomp, const int deflcomp,const double length, const double value)
{
const std::string edge("Edge");
const std::string face("Face");
const std::string volume("Volume");
allinitial.emplace_back(deflcomp,nonLinearBoundaryCondition::velocity);
initialCondition initc = allinitial.back();
initc._f = new functionVelocityDCB(value,axiscomp,length);
initc.g = new elementGroup();
initc._tag = numphys;
if(onwhat == edge){
initc.onWhat = nonLinearBoundaryCondition::ON_EDGE;
initc.g->addPhysical(1,numphys);
}
else if(onwhat == face){
initc.onWhat = nonLinearBoundaryCondition::ON_FACE;
initc.g->addPhysical(2,numphys);
}
else if(onwhat == volume){
initc.onWhat = nonLinearBoundaryCondition::ON_VOLUME;
initc.g->addPhysical(3,numphys);
}
else{
Msg::Error("The initial velocity BC can be applied only on an edge or on a face");
}
}
void nonLinearMechSolver::independentDisplacementBC(std::string onwhat, const int numphys, const int comp, const double value){
allDirichlet.emplace_back();
nonLinearDirichletBC& diri = allDirichlet.back();
const std::string node("Node");
const std::string edge("Edge");
const std::string face("Face");
const std::string volume("Volume");
if(onwhat==node){
diri.g = new elementGroup (0, numphys);
diri.onWhat=nonLinearBoundaryCondition::ON_VERTEX;
}
else if(onwhat==edge){
diri.g = new elementGroup (1, numphys);
diri.onWhat=nonLinearBoundaryCondition::ON_EDGE;
}
else if(onwhat==face){
diri.g = new elementGroup (2, numphys);
diri.onWhat=nonLinearBoundaryCondition::ON_FACE;
}
else if(onwhat==volume){
diri.g = new elementGroup (3, numphys);
diri.onWhat=nonLinearBoundaryCondition::ON_VOLUME;
}
else Msg::Error("Impossible to prescribe a displacement on a %s\n",onwhat.c_str());
diri._f= new simpleFunctionTime<double>(value,false);
diri._comp=comp;
diri._tag=numphys;
}
void nonLinearMechSolver::forceBC(std::string onwhat, const int numphys, const int comp, const double val)
{
simpleFunctionTime<double> *fct = new simpleFunctionTime<double>(val,true,0.);
this->forceBC(onwhat,numphys,comp,fct);
}
void nonLinearMechSolver::forceBC(std::string onwhat, const int numphys, const int comp, simpleFunctionTime<double> *fct)
{
// in general, forceBC is applied for the flux of and arbitrary unknown field
// (force in case of displacement, extradof field in case of extraDof, ...) in REFERENCE CONFIGURATION.
// in case of using CURRENT CONFIGURATION, as pressure or scalar flux,
// pressureOnPhysicalGroupBC for presurre or
// scalarFluxBC for scalar flux should be used
const std::string node("Node");
const std::string edge("Edge");
const std::string face("Face");
const std::string volume("Volume");
const std::string facevertex("FaceVertex");
allNeumann.emplace_back();
nonLinearNeumannBC& neu = allNeumann.back();
if(onwhat==node){
neu.g = new elementGroup (0, numphys);
neu.onWhat=nonLinearBoundaryCondition::ON_VERTEX;
}
else if(onwhat==edge){
neu.g = new elementGroup (1, numphys);
neu.onWhat=nonLinearBoundaryCondition::ON_EDGE;
}
else if(onwhat==face){
neu.g = new elementGroup (2, numphys);
neu.onWhat=nonLinearBoundaryCondition::ON_FACE;
}
else if(onwhat==facevertex)
{
neu.g = new elementGroup(2,numphys);
neu.onWhat=nonLinearBoundaryCondition::ON_FACE_VERTEX;
}
else if(onwhat==volume){
neu.g = new elementGroup (3, numphys);
neu.onWhat=nonLinearBoundaryCondition::ON_VOLUME;
}
else {
Msg::Error("Impossible to prescribe a force on a %s\n",onwhat.c_str());
if (onwhat == "Pressure"){
Msg::Error("pressureOnPhysicalGroupBC should be used instead of forceBC when applying pressure on a BC \n Applying pressure by this function has been removed");
}
else if (onwhat == "Flux"){
Msg::Error("scalarFluxBC should be used instead of forceBC when applying scalar flux on a BC \n Applying scalar flux by this function has been removed");
}
};
neu._NeumannBCType = nonLinearNeumannBC::FORCE;
neu._f= fct;
neu._tag=numphys;
neu._comp=comp;
};
void nonLinearMechSolver::scalarFluxBC(std::string onwhat, const int numphys, const int comp, const double val){
simpleFunctionTime<double> *fct = new simpleFunctionTime<double>(val,true,0.);
this->scalarFluxBC(onwhat,numphys,comp,fct);
};
void nonLinearMechSolver::scalarFluxBC(std::string onwhat, const int numphys, const int comp, simpleFunctionTime<double> *fct){
const std::string edge("Edge");
const std::string face("Face");
allNeumann.emplace_back();
nonLinearNeumannBC& neu = allNeumann.back();
if(onwhat==edge){
neu.g = new elementGroup (1, numphys);
neu.onWhat=nonLinearBoundaryCondition::ON_EDGE;
}
else if(onwhat==face){
neu.g = new elementGroup (2, numphys);
neu.onWhat=nonLinearBoundaryCondition::ON_FACE;
}
else Msg::Error("Impossible to prescribe a scalar flux on a %s\n",onwhat.c_str());
neu._NeumannBCType = nonLinearNeumannBC::SCALAR_FLUX;
neu._f= fct;
neu._tag=numphys;
neu._comp=comp;
};
void nonLinearMechSolver::independentForceBC(std::string onwhat, const int numphys, const int comp, const double val){
allNeumann.emplace_back();
nonLinearNeumannBC& neu = allNeumann.back();
const std::string node("Node");
const std::string edge("Edge");
const std::string face("Face");
const std::string volume("Volume");
if(onwhat==node){
neu.g = new elementGroup (0, numphys);
neu.onWhat=nonLinearBoundaryCondition::ON_VERTEX;
}
else if(onwhat==edge){
neu.g = new elementGroup (1, numphys);
neu.onWhat=nonLinearBoundaryCondition::ON_EDGE;
}
else if(onwhat==face){
neu.g = new elementGroup (2, numphys);
neu.onWhat=nonLinearBoundaryCondition::ON_FACE;
}
else if(onwhat==volume){
neu.g = new elementGroup (3, numphys);
neu.onWhat=nonLinearBoundaryCondition::ON_VOLUME;
}
else Msg::Error("Impossible to prescribe a force on a %s\n",onwhat.c_str());
neu._NeumannBCType = nonLinearNeumannBC::FORCE;
neu._f= new simpleFunctionTimeWithConstant<double>(val,false);
neu._tag=numphys;
neu._comp = comp;
}
void nonLinearMechSolver::pressureOnPhysicalGroupBC(const int numphys, const double press, const double p0){
Msg::Warning("applying pressure on surface");
this->pressureOnPhysicalGroupBC("Face",numphys,press,p0);
}
void nonLinearMechSolver::pressureOnPhysicalGroupBC(const int numphys, simpleFunctionTime<double> *fct){
Msg::Warning("applying pressure on surface");
this->pressureOnPhysicalGroupBC("Face",numphys,fct);
};
void nonLinearMechSolver::pressureOnPhysicalGroupBC(std::string onwhat, const int numphys, const double pressDiff, const double p0){
simpleFunctionTime<double> *fct = new simpleFunctionTimeWithConstant<double>(pressDiff,true,1.,p0);
this->pressureOnPhysicalGroupBC(onwhat,numphys,fct);
};
void nonLinearMechSolver::pressureOnPhysicalGroupBC(std::string onwhat, const int numphys, simpleFunctionTime<double> *fct){
allNeumann.emplace_back();
nonLinearNeumannBC& neu = allNeumann.back();
const std::string edge("Edge");
const std::string face("Face");
if (onwhat == face){
neu.g = new elementGroup(2,numphys);
neu.onWhat = nonLinearBoundaryCondition::ON_FACE;
}
else if (onwhat == edge){
neu.g = new elementGroup(1,numphys);
neu.onWhat = nonLinearBoundaryCondition::ON_EDGE;
}
else{
Msg::Error("Impossible to prescribe a pressure on a %s\n",onwhat.c_str());
}
neu._NeumannBCType = nonLinearNeumannBC::PRESSURE;
neu._f = fct;
neu._tag=numphys;
};
void nonLinearMechSolver::blastPressureBC(std::string onwhat, const int numphys,const double p0,const double p1, const double plexp,
const double t0, const double t1){
simpleFunctionTime<double> *fct = new powerDecreasingFunctionTime(p0,p1,plexp,t0,t1,_timeManager->getEndTime());
this->pressureOnPhysicalGroupBC(onwhat,numphys,fct);
};
void nonLinearMechSolver::blastPressureBC(const int numphys,const double p0,const double p1, const double plexp,
const double t0, const double t1){
Msg::Warning("applying pressure on surface");
this->blastPressureBC("Face",numphys,p0,p1,plexp,t0,t1);
};
void nonLinearMechSolver::archivingInternalForceOnPhysicalGroup(const std::string onwhat, const int numphys,const int nstep)
{
static std::string node("Node");
static std::string edge("Edge");
static std::string face("Face");
static std::string volu("Volume");
int dim=0;
if(onwhat == node )
dim = 0;
else if(onwhat == edge)
dim = 1;
else if(onwhat == face)
dim = 2;
else if(onwhat == volu)
dim = 3;
int ns = nstep;
if (nstep <1) ns = 1;
vafIntenal.emplace_back(numphys,dim,ns);
}
void nonLinearMechSolver::archivingForceOnPhysicalGroup(const std::string onwhat, const int numphys, const int comp,const int nstep){
// get the node of the edge
static std::string node("Node");
static std::string edge("Edge");
static std::string face("Face");
static std::string volu("Volume");
int dim=0;
if(onwhat == node )
dim = 0;
else if(onwhat == edge)
dim = 1;
else if(onwhat == face)
dim = 2;
else if(onwhat == volu)
dim = 3;
// check if
bool found = false;
for (int i=0; i< vaf.size(); i++)
{
if ((vaf[i].numphys == numphys) and (vaf[i].comp == comp))
{
found = true;
break;
}
}
if (!found)
{
vaf.emplace_back(numphys,dim,comp,nstep);
}
}
void nonLinearMechSolver::archivingRigidContactForce(const int numphys, const int comp,const int nstep){
// check if
bool found = false;
for (int i=0; i< vaf.size(); i++)
{
if ((vaf[i].numphys == numphys) and (vaf[i].comp == comp))
{
found = true;
break;
}
}
if (!found)
{
vaf.emplace_back(numphys,0,comp,nstep);
}
}
void nonLinearMechSolver::initArchiveReactionForceOnFixedPhysical(archiveForce& aforce){
if(_previousInit) {
aforce.vdof.clear();
};
std::vector<MVertex*> vv;
pModel->getMeshVerticesForPhysicalGroup(aforce.dim,aforce.numphys,vv);
if(vv.size() > 0) {
elementGroup grForce(aforce.dim,aforce.numphys);
for(int idom = 0; idom < _mpiUserDom;++idom){ // Do not consider Ghost domain when archiving forces
partDomain *dom = domainVector[idom];
if (dom->getFunctionSpaceType() == functionSpaceType::Hierarchical)
{
HierarchicalFunctionSpace *hasp = dynamic_cast<HierarchicalFunctionSpace*>(dom->getFunctionSpace());
std::vector<int> forcecomp(1,aforce.comp);
std::vector<Dof> R;
for (elementGroup::elementContainer::const_iterator iteF = grForce.begin(); iteF != grForce.end(); iteF++)
{
MElement* eleF = iteF->second;
for(elementGroup::elementContainer::const_iterator ite = dom->element_begin(); ite!=dom->element_end(); ++ite)
{
MElement *ele = ite->second;
if (checkInterfaceElementBelongToBulkElement(eleF,ele))
{
//hasp->getKeysOnLowerDimensionPart(ele,eleF,forcecomp,R);
for (int iev=0; iev< eleF->getNumVertices(); iev++)
{
hasp->getKeysOnVertex(ele,eleF->getVertex(iev),forcecomp,R);
}
break;
}
}
}
for (int ir=0; ir< R.size(); ir++)
{
aforce.vdof.insert(R[ir]);
}
}
else
{
FunctionSpaceBase *sp = dom->getFunctionSpace();
std::vector<Dof> R;
for(elementGroup::elementContainer::const_iterator ite = dom->element_begin(); ite!=dom->element_end(); ++ite){
MElement *ele = ite->second;
int nbvertex = ele->getNumVertices();
sp->getKeys(ele,R);
for(std::vector<MVertex*>::iterator it=vv.begin(); it!=vv.end(); ++it){
for(int j=0;j<nbvertex; j++){
if(ele->getVertex(j) == *it){
aforce.vdof.insert(R[j+nbvertex*aforce.comp]);
break;
}
}
}
R.clear();
}
}
}
}
};
void nonLinearMechSolver::initArchiveForce(){
#if defined(HAVE_MPI)
std::vector<int> has_this_contact(Msg::GetCommSize(),0);
#endif // HAVE_MPI
for(std::vector<archiveForce>::iterator itf=vaf.begin(); itf!=vaf.end(); ++itf){
archiveForce &af = *itf;
if(af.vdof.size()==0){// otherwise it has already be initialized before in a previous computation
std::vector<MVertex*> vv;
pModel->getMeshVerticesForPhysicalGroup(af.dim,af.numphys,vv);
// loop on domain (to find the domain where the force is applied)
if(vv.size() > 0)
{// otherwise rigid contact force
elementGroup grForce(af.dim,af.numphys);
for(int idom = 0; idom < _mpiUserDom;++idom){ // Do not consider Ghost domain when archiving forces
partDomain *dom = domainVector[idom];
if (dom->getFunctionSpaceType() == functionSpaceType::Hierarchical)
{
HierarchicalFunctionSpace *hasp = dynamic_cast<HierarchicalFunctionSpace*>(dom->getFunctionSpace());
std::vector<int> forcecomp(1,af.comp);
std::vector<Dof> R;
for (elementGroup::elementContainer::const_iterator iteF = grForce.begin(); iteF != grForce.end(); iteF++)
{
MElement* eleF = iteF->second;
for(elementGroup::elementContainer::const_iterator ite = dom->element_begin(); ite!=dom->element_end(); ++ite)
{
MElement *ele = ite->second;
if (checkInterfaceElementBelongToBulkElement(eleF,ele))
{
//hasp->getKeysOnLowerDimensionPart(ele,eleF,forcecomp,R);
for (int iev=0; iev< eleF->getNumVertices(); iev++)
{
hasp->getKeysOnVertex(ele,eleF->getVertex(iev),forcecomp,R);
}
break;
}
}
}
for (int ir=0; ir< R.size(); ir++)
{
af.vdof.insert(R[ir]);
}
}
else
{
FunctionSpaceBase *sp = dom->getFunctionSpace();
std::vector<Dof> R;
for(elementGroup::elementContainer::const_iterator ite = dom->element_begin(); ite!=dom->element_end(); ++ite){
MElement *ele = ite->second;
int nbvertex = ele->getNumVertices();
sp->getKeys(ele,R);
for(std::vector<MVertex*>::iterator it=vv.begin(); it!=vv.end(); ++it){
for(int j=0;j<nbvertex; j++){
if(ele->getVertex(j) == *it){
af.vdof.insert(R[j+nbvertex*af.comp]);
break;
}
}
}
R.clear();
}
}
}
}
else {
for(nonLinearMechSolver::contactContainer::const_iterator itc = _allContact.begin(); itc!=_allContact.end(); ++itc){
contactDomain *cdom = *itc;
if(cdom->getPhys() != af.numphys)
continue;
partDomain* domf=NULL;
int physDom = cdom->getPhysSlave();
for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain *dom = *itdom;
if(dom->getPhysical() == physDom){
domf = dom;
break;
}
}
#if defined(HAVE_MPI)
if(false) // domf == NULL)
{
for(std::vector<partDomain*>::iterator itdom = _ghostDomainMPI.begin(); itdom!=_ghostDomainMPI.end(); ++itdom)
{
partDomain *dom = *itdom;
if(dom->getPhysical() == physDom)
{
domf = dom;
break;
}
}
}
#endif // HAVE_MPI
if(domf==NULL)
continue;
std::vector<Dof> R;
(const_cast<rigidContactSpaceBase*>(static_cast<const rigidContactSpaceBase*>(cdom->getSpace())))->getKeysOfGravityCenter(R);
FilterDof *fdof = domf->createFilterDof(af.comp);
for(int j=0;j<R.size(); j++) {
if(fdof->operator()(R[j])){
af.vdof.insert(R[j]);
break; // only 1 dof allow...
}
}
delete fdof;
}
#if defined(HAVE_MPI)
if(!af.vdof.empty()){
has_this_contact[Msg::GetCommRank()] = 1;
}
MPI_Allreduce(MPI_IN_PLACE,has_this_contact.data(),Msg::GetCommSize(),MPI_INT,MPI_SUM,MPI_COMM_WORLD);
int root_rank = 0;
for(; root_rank< Msg::GetCommSize();++root_rank)
{
if(has_this_contact[root_rank]==1)
break;
}
if(root_rank == Msg::GetCommSize())
Msg::Error("cannot find a contact on any of the partition...");
af.contact_root = root_rank;
std::fill(has_this_contact.begin(),has_this_contact.end(),0);
#endif // HAVE_MPI
}
}
if(!af.vdof.empty() && (af.contact_root == -1 || af.contact_root==Msg::GetCommRank()))
af.openFile(getFileSavingPrefix());
}
}
void nonLinearMechSolver::initAverageCluster()
{
if (_clusterData.size() > 0)
{
Msg::Info("init initAverageCluster");
// initialize cluster data
for (std::list<clustersData>::iterator itclData = _clusterData.begin(); itclData != _clusterData.end(); itclData++)
{
clustersData& clData = *itclData;
if (clData.clusterIndexMap.size() ==0)
{
Msg::Error("clusters data were not corrrectly loaded");
}
if (!clData.isInitialized && clData.clusterIndexMap.size() > 0)
{
clData.isInitialized = true;
for (int i=0; i< domainVector.size(); i++)
{
IntPt* GP;
partDomain* dom = domainVector[i];
for (elementGroup::elementContainer::const_iterator ite = dom->element_begin(); ite!= dom->element_end(); ite++)
{
MElement* ele = ite->second;
int npts = dom->getBulkGaussIntegrationRule()->getIntPoints(ele,&GP);
for (int j=0; j< npts; j++)
{
double u = GP[j].pt[0]; double v = GP[j].pt[1]; double w = GP[j].pt[2];
double weight = GP[j].weight;
double detJ = ele->getJacobianDeterminant(u,v,w);
int type = numericalMaterialBase::createTypeWithTwoInts(ele->getNum(),j);
clData.weightMap[type] = weight*detJ;
}
}
}
//
for (std::map<int,int>::const_iterator itm=clData.clusterIndexMap.begin(); itm != clData.clusterIndexMap.end(); itm++)
{
// first- eleNum + gpNum
// second- clusterIndex
std::map<int,double>& cluster_i = clData.clusterMap[itm->second];
// in cluster_i
// key is eleNum + gpNum
// value is weight
cluster_i[itm->first] = clData.weightMap[itm->first];
}
}
}
std::list<AvergageCluster> averageClustersFromOptions(_averageClusters.begin(),_averageClusters.end());
_averageClusters.clear();
for (std::list<clustersData>::const_iterator itclData = _clusterData.begin(); itclData != _clusterData.end(); itclData++)
{
const clustersData& clusterData = *itclData;
if (clusterData.isInitialized)
{
// creat save file for each cluster
for (std::list<AvergageCluster>::const_iterator it = averageClustersFromOptions.begin(); it!= averageClustersFromOptions.end(); it++)
{
const AvergageCluster& opts = *it;
_averageClusters.emplace_back(opts.ipVal,opts.nbArch);
AvergageCluster& cur = _averageClusters.back();
cur.clusterData = &clusterData;
cur.openFile(getFileSavingPrefix());
}
}
}
Msg::Info("done initAverageCluster");
}
};
void nonLinearMechSolver::averageClusterArchiving(const double curtime, const int numstep, const bool forceSave)
{
for (std::list<AvergageCluster>::iterator it = _averageClusters.begin(); it != _averageClusters.end(); it++)
{
AvergageCluster& ac = *it;
if (numstep > ac.lastSaveStep)
{
if (numstep%ac.nbArch==0 or forceSave)
{
ac.lastSaveStep = numstep;
std::vector<double> val;
ac.getAverageValue(getIPField(),val);
if (ac.fp == NULL) ac.openFile(getFileSavingPrefix());
fprintf(ac.fp,"%e",curtime);
for (int i=0; i< val.size(); i++)
{
fprintf(ac.fp,";%e",val[i]);
}
fprintf(ac.fp,"\n");
fflush(ac.fp);
}
}
}
}
void nonLinearMechSolver::initPathFollowingArchiving()
{
if (_pathFollowing)
{
#if defined(HAVE_MPI)
if (Msg::GetCommRank() == 0)
#endif // HAVE_MPI
{
std::string filename = getFileSavingPrefix()+"pathResult_Time_ControlParameter_StateParameter.csv";
FILE* file = fopen(filename.c_str(),"w");
fclose(file);
}
}
}
void nonLinearMechSolver::pathFollowingArchiving(const double curtime, const int numstep){
if (_pathFollowing){
std::string name = "A";
linearSystem<double>* lsys = pAssembler->getLinearSystem(name);
nonLinearSystem<double>* nsys = dynamic_cast<nonLinearSystem<double>*>(lsys);
pathFollowingSystem<double>* psys = dynamic_cast<pathFollowingSystem<double>*>(lsys);
double control = psys->getControlParameter();
double state = psys->getStateParameter();
#if defined(HAVE_MPI)
if (Msg::GetCommRank() == 0)
#endif // HAVE_MPI
{
std::string filename = getFileSavingPrefix()+"pathResult_Time_ControlParameter_StateParameter.csv";
FILE* file = fopen(filename.c_str(),"a");
fprintf(file,"%e; %e; %e; \n",curtime,control,state);
fclose(file);
}
}
};
void nonLinearMechSolver::archivingNodeDisplacement(const int numphys, const int comp,const int nstep){
this->archivingNode(numphys,comp,nonLinearBoundaryCondition::position,nstep);
}
void nonLinearMechSolver::archivingNodeDisplacementOnControlNode(const int pos, const int comp,const int nstep){
anoded.push_back(unknownField::archiveNode(pos,0,comp,nonLinearBoundaryCondition::position,nstep));
}
void nonLinearMechSolver::archivingMeshVertexDisplacement(const int num, const int comp,const int nstep){
// no distinction between cG/dG and full Dg formulation. class Displacement Field manage it
MVertex* v = NULL;
v = pModel->getMeshVertexByTag(num);
nonLinearBoundaryCondition::whichCondition wc = nonLinearBoundaryCondition::position;
if(v != NULL){
anoded.push_back(unknownField::archiveNode(0,v->getNum(),comp,wc,nstep));
}
else{
Msg::Warning("No mesh vertex %d So it is impossible to archive nodal displacement",num);
}
};
void nonLinearMechSolver::archivingVolumeIntegralValue(const int num, const int nstep)
{
_dataVolumeIntegral.emplace_back(IntegralVolume::VolumeIntegral,num,-1,nstep);
};
void nonLinearMechSolver::archivingVolumeIntegralValueOnPhysical(const int phy, const int num, const int nstep)
{
_dataVolumeIntegral.emplace_back(IntegralVolume::VolumeIntegral,num,phy,nstep);
};
void nonLinearMechSolver::archivingAverageValue(const int num, const int nstep){
_dataVolumeIntegral.emplace_back(IntegralVolume::VolumeAverage,num,-1,nstep);
};
void nonLinearMechSolver::archivingAverageValueOnPhysical(const int phy, const int num, const int nstep){
_dataVolumeIntegral.emplace_back(IntegralVolume::VolumeAverage,num,phy,nstep);
};
void nonLinearMechSolver::archivingAverageValueActiveDissipation(const int num, const int nstep){
_dataVolumeIntegral.emplace_back(IntegralVolume::ActiveDissipationAverage,num,-1,nstep);
};
void nonLinearMechSolver::archivingIncrementBasedAverageValueActiveDissipation(const int num, const int nstep){
_dataVolumeIntegral.emplace_back(IntegralVolume::ActiveDissipationIncrementAverage,num,-1,nstep);
};
void nonLinearMechSolver::loadClustersDataFile(const std::string fileName)
{
_clusterData.emplace_back();
clustersData& ob = _clusterData.back();
ob.loadFromFile(fileName);
};
void nonLinearMechSolver::archivingAverageValueOverClusters(const int num, const int nstep)
{
_averageClusters.emplace_back(num,nstep);
};
void nonLinearMechSolver::IPVolumeIntegralArchiving(const double curtime, const int numstep, const bool forceSave)
{
for (std::list<IntegralVolume>::iterator it = _dataVolumeIntegral.begin(); it != _dataVolumeIntegral.end(); it++)
{
IntegralVolume& iv = *it;
if (numstep > iv.lastSaveStep)
{
if (numstep%iv.nbArch==0 or forceSave)
{
iv.lastSaveStep = numstep;
double& val= iv.value;
if (iv.integType == IntegralVolume::VolumeIntegral)
{
if (iv.physical > 0)
{
this->getTotalIntegralByVolumeIntegralOnPhysical(iv.physical,iv.ipVal,val);
}
else
{
this->getTotalIntegralByVolumeIntegral(iv.ipVal,val);
}
}
else if (iv.integType == IntegralVolume::VolumeAverage)
{
if (iv.physical > 0)
{
this->getHomogenizedPropertyByVolumeIntegralOnPhysical(iv.physical,iv.ipVal,val);
}
else
{
this->getHomogenizedPropertyByVolumeIntegral(iv.ipVal,val);
}
}
else if (iv.integType == IntegralVolume::ActiveDissipationAverage)
{
this->getHomogenizedPropertyByVolumeIntegralOnActiveDissipationDomain(iv.ipVal,val,IPStateBase::current);
}
else if (iv.integType == IntegralVolume::ActiveDissipationIncrementAverage)
{
double incrementVal = 0.;
this->getHomogenizedIncrementalPropertyByVolumeIntegralOnActiveDissipationDomain(iv.ipVal,incrementVal);
val += incrementVal;
}
else
{
Msg::Error("integType has not been defined");
}
if (iv.fp == NULL) iv.openFile(getFileSavingPrefix());
fprintf(iv.fp,"%.16g;%.16g\n",curtime,val);
fflush(iv.fp);
}
}
}
}
void nonLinearMechSolver::IPDataOnPhysicalArchiving(const double curtime, const int numstep, const bool forceSave)
{
for (std::list<IPDataOnPhysical>::iterator idt = _dataOnPhysical.begin(); idt != _dataOnPhysical.end(); idt++)
{
IPDataOnPhysical& ipdata = *idt;
int dim = ipdata.dim;
int phys = ipdata.physical;
int ipval = ipdata.ipValue;
// file name
std::string savefname = getFileSavingPrefix()+"IPDdata_"+ IPField::ToString(ipval)+ "_OnPhysical_"+int2str(phys);
#if defined(HAVE_MPI)
if ( getNumRanks() > 1){
savefname += "_part"+int2str(Msg::GetCommRank());
}
#endif //HAVE_MPIim
if (ipdata.oneFileForAllStep)
{
savefname += ".csv";
}
else
{
savefname += "_step"+int2str(numstep)+".csv";
}
if (!ipdata.isInitialized)
{
FILE* savefile=NULL;
if (ipdata.oneFileForAllStep)
{
savefile = fopen(savefname.c_str(),"w");
fprintf(savefile,"Time");
}
ipdata.isInitialized = true;
elementGroup g;
#if defined(HAVE_MPI)
elementFilterMPI elemfil(NULL);
g.addPhysical(dim,phys,elemfil);
#else
g.addPhysical(dim,phys);
#endif // HAVE_MPI
std::string fname = getFileSavingPrefix()+"coordinate_"+ IPField::ToString(ipval)+ "_OnPhysical_"+int2str(phys);
#if defined(HAVE_MPI)
if (this->getNumRanks() > 1){
fname += "_part"+int2str(Msg::GetCommRank());
}
#endif //HAVE_MPIim
fname += ".csv";
FILE* coordinateFile = fopen(fname.c_str(),"w");
ipdata.element.resize(g.size());
int index= 0;
SPoint3 p;
for (elementGroup::elementContainer::const_iterator it = g.begin(); it!= g.end(); it++)
{
MElement* ele = it->second;
ipdata.element[index] = ele->getNum(); index++;
for (int idom = 0; idom < domainVector.size(); idom++){
partDomain* dom = domainVector[idom];
if (dom->g_find(ele)){
IntPt* GP;
int npts = dom->getBulkGaussIntegrationRule()->getIntPoints(ele,&GP);
for (int j=0; j< npts; j++){
double u = GP[j].pt[0]; double v = GP[j].pt[1]; double w = GP[j].pt[2];
double weight = GP[j].weight;
double detJ = ele->getJacobianDeterminant(u,v,w);
ele->pnt(u,v,w,p);
fprintf(coordinateFile,"%ld; %e; %e; %e; %d; %e\n",ele->getNum(),p.x(),p.y(),p.z(),j,weight*detJ);
bool willSave = false;
if (ipdata.ipIndex == -1 or ipdata.ipIndex==j)
{
willSave = true;
}
if (willSave)
{
if (ipdata.oneFileForAllStep)
{
fprintf(savefile,";%s_P%dE%ldG%d",IPField::ToString(ipval).c_str(), phys,ele->getNum(),j);
}
}
}
break;
}
}
}
fclose(coordinateFile);
if (ipdata.oneFileForAllStep)
{
fprintf(savefile,"\n");
fclose(savefile);
}
}
if (numstep > ipdata.lastSaveStep)
{
if (numstep%ipdata.nbArch==0 or forceSave)
{
ipdata.lastSaveStep = numstep;
//
FILE* file =NULL;
if (ipdata.oneFileForAllStep)
{
file = fopen(savefname.c_str(),"a");
// add time
fprintf(file,"%e",curtime);
for (int i=0; i< ipdata.element.size(); i++){
int elnum = ipdata.element[i];
const std::vector<IPStateBase*>& ips = (*(_ipf->getAips()->getIPstate(elnum)));
for (int j=0; j< ips.size(); j++)
{
bool willSave = false;
if (ipdata.ipIndex == -1 or ipdata.ipIndex==j)
{
willSave = true;
}
if (willSave)
{
double val = ips[j]->getState(IPStateBase::current)->get(IPField::Output(ipval));
fprintf(file,";%e",val);
}
}
}
fprintf(file,"\n");
fclose(file);
}
else
{
file = fopen(savefname.c_str(),"w");
for (int i=0; i< ipdata.element.size(); i++){
int elnum = ipdata.element[i];
const std::vector<IPStateBase*>& ips = (*(_ipf->getAips()->getIPstate(elnum)));
for (int j=0; j< ips.size(); j++)
{
bool willSave = false;
if (ipdata.ipIndex == -1 or ipdata.ipIndex==j)
{
willSave= true;
}
if (willSave)
{
double val = ips[j]->getState(IPStateBase::current)->get(IPField::Output(ipval));
fprintf(file,"%e\n",val);
}
}
}
fclose(file);
}
}
}
}
};
void nonLinearMechSolver::archivingIPDataOnPhysical(const int ipval, const int phys, const int dim, const int nstep, bool oneFileForAllStep, int ipLoc){
if (oneFileForAllStep)
{
Msg::Info("archivingIPDataOnPhysical all steps are stored in one file");
}
if (ipLoc >= 0)
{
Msg::Info("archivingIPDataOnPhysical ip %d is stored",ipLoc);
}
else if (ipLoc == -1)
{
Msg::Info("archivingIPDataOnPhysical all IPs are stored");
}
else
{
Msg::Error("archivingIPDataOnPhysical IP number %s does not exist",ipLoc);
}
_dataOnPhysical.emplace_back(ipval,phys,dim,nstep,oneFileForAllStep,ipLoc);
};
void nonLinearMechSolver::archivingNodeDisplacementOnPhysical(const int dim, const int physical, const int comp,const int nstep){
nonLinearBoundaryCondition::whichCondition wc = nonLinearBoundaryCondition::position;
archivingNode(physical,dim,comp,wc,nstep);
};
void nonLinearMechSolver::archivingNodeVelocity(const int numphys, const int comp,const int nstep){
this->archivingNode(numphys,comp,nonLinearBoundaryCondition::velocity,nstep);
}
void nonLinearMechSolver::archivingNodeAcceleration(const int numphys, const int comp, const int nstep){
this->archivingNode(numphys,comp,nonLinearBoundaryCondition::acceleration,nstep);
}
void nonLinearMechSolver::constraintBC(std::string onwhat, const int numphys, const int comp)
{
allConstraint.emplace_back();
nonLinearConstraintBC& uc = allConstraint.back();
const std::string node("Node");
const std::string edge("Edge");
const std::string face("Face");
const std::string volume("Volume");
if(onwhat==node){
uc.g = new elementGroup (0, numphys);
uc.onWhat=nonLinearBoundaryCondition::ON_VERTEX;
}
else if(onwhat==edge){
uc.g = new elementGroup (1, numphys);
uc.onWhat=nonLinearBoundaryCondition::ON_EDGE;
}
else if(onwhat==face){
uc.g = new elementGroup (2, numphys);
uc.onWhat=nonLinearBoundaryCondition::ON_FACE;
}
else if(onwhat==volume){
uc.g = new elementGroup(3, numphys);
uc.onWhat=nonLinearBoundaryCondition::ON_VOLUME;
}
else Msg::Error("Impossible to prescribe a constraint on a %s in constraintBC\n",onwhat.c_str());
uc._comp=comp;
uc._tag=numphys;
}
void nonLinearMechSolver::createTreeForBC(const std::string &PhysicalCurve, const std::string &PhysicalSurface, const std::string &PhysicalVolume, const int OutputPhysical)
{
#if defined(HAVE_PLUGINS)
try
{
PluginManager::instance()->setPluginOption("SpanningTree", "PhysicalCurves", PhysicalCurve);
PluginManager::instance()->setPluginOption("SpanningTree", "PhysicalSurfaces", PhysicalSurface);
PluginManager::instance()->setPluginOption("SpanningTree", "PhysicalVolumes", PhysicalVolume);
PluginManager::instance()->setPluginOption("SpanningTree", "OutputPhysical", OutputPhysical);
PluginManager::instance()->action("SpanningTree", "Run", 0);
}
catch(...)
{
Msg::Error("Failure in running the GMSH plugin: SpanningTree in nonLinearMechSolver::createTreeForBC()");
throw -1;
}
#else
Msg::Error("HAVE_PLUGINS must be activated");
#endif //HAVE_PLUGINS
}
void nonLinearMechSolver::linearConstraintBCBetweenTwoGroups(std::string onwhat, const int physMater, const int physSlave, const int comp, const double slFactor,
const linearCombinationOfVertices* rh,
const vertexGroupOperation* op,
const setInt* exclVertices)
{
Msg::Info("linear constraint BC comp %d on physical %d physical %d",comp,physMater,physSlave);
allLinearConstraintBC.emplace_back();
nonLinearLinearConstraintBCBetweenTwoGroups& bc = allLinearConstraintBC.back();
bc.phyMaster = physMater;
bc.phySlave = physSlave;
if(onwhat=="Node"){
bc.gMaster = new elementGroup (0, physMater);
if (physSlave > 0)
bc.gSlave = new elementGroup (0, physSlave);
else
bc.gSlave = new elementGroup ();
bc.onWhat=nonLinearBoundaryCondition::ON_VERTEX;
}
else if(onwhat=="Edge"){
bc.gMaster = new elementGroup (1, physMater);
if (physSlave > 0)
bc.gSlave = new elementGroup (1, physSlave);
else
bc.gSlave = new elementGroup ();
bc.onWhat=nonLinearBoundaryCondition::ON_EDGE;
}
else if(onwhat=="Face"){
bc.gMaster = new elementGroup (2, physMater);
if (physSlave > 0)
bc.gSlave = new elementGroup (2, physSlave);
else
bc.gSlave = new elementGroup ();
bc.onWhat=nonLinearBoundaryCondition::ON_FACE;
}
else if(onwhat=="Volume"){
bc.gMaster = new elementGroup (3, physMater);
if (physSlave > 0)
bc.gSlave = new elementGroup (3, physSlave);
else
bc.gSlave = new elementGroup ();
bc.onWhat=nonLinearBoundaryCondition::ON_VOLUME;
}
else Msg::Error("Impossible to prescribe a constraint on a %s in linearConstraintBCBetweenTwoGroups\n",onwhat.c_str());
bc.comp = comp;
if (rh !=NULL)
{
bc.rightHandSide = rh->clone();
}
else
{
Msg::Error("linearCombinationOfVertices must be set");
Msg::Exit(0);
}
if (op!=NULL)
{
bc.vgOperation = op->clone();
}
else
{
bc.vgOperation = new vertexGroupOperation_trivial();
}
bc.slaveFactor = slFactor;
if (exclVertices != NULL)
{
bc.excludedVertices.copyData(*exclVertices);
}
}
void nonLinearMechSolver::linearConstraintBCBetweenTwoGroups(std::string onwhat, const int physMater, const int comp,
const linearCombinationOfVertices* rh,
const setInt* exclVertices)
{
linearConstraintBCBetweenTwoGroups(onwhat,physMater,0,comp,0.,rh,NULL,exclVertices);
}
void nonLinearMechSolver::addPeriodicEdgePhysicals(int edge)
{
_edgePeriodicPhysicals.push_back(edge);
}
void nonLinearMechSolver::addPeriodicNodePhysicals(int node)
{
_nodePeriodicPhysicals.push_back(node);
}
void nonLinearMechSolver::periodicBC(std::string onwhat, const int phys1, const int phys2, const int v1, const int v2, const int comp)
{
if (v1 > 0 && v2 > 0)
{
Msg::Info("Periodic BC comp %d on physical %d physical %d versur vertex %d %d",comp,phys1,phys2,v1,v2);
}
else
{
Msg::Info("Displacement comp %d on physical %d is the same as on physical %d",comp,phys1,phys2);
}
const std::string node("Node");
const std::string edge("Edge");
const std::string face("Face");
nonLinearBoundaryCondition::location loc;
if(onwhat==node){
loc=nonLinearBoundaryCondition::ON_VERTEX;
}
else if(onwhat==edge){
loc=nonLinearBoundaryCondition::ON_EDGE;
}
else if(onwhat==face){
loc=nonLinearBoundaryCondition::ON_FACE;
}
bool found = false;
for (std::list<nonLinearPeriodicBCBetweenTwoGroups>::iterator pbctg=allPeriodic.begin(); pbctg!=allPeriodic.end(); pbctg++)
{
nonLinearPeriodicBCBetweenTwoGroups& bc = *pbctg;
if ((bc.onWhat == loc) && (bc.phys1 == phys1) && (bc.phys2 == phys2) && (bc.physVer1 == v1) && (bc.physVer2 == v2))
{
bc.comp.push_back(comp);
found = true;
break;
}
}
if (!found)
{
allPeriodic.emplace_back();
nonLinearPeriodicBCBetweenTwoGroups& pbc = allPeriodic.back();
if(onwhat==node){
pbc.g1 = new elementGroup (0, phys1);
pbc.g2 = new elementGroup (0, phys2);
pbc.onWhat=nonLinearBoundaryCondition::ON_VERTEX;
}
else if(onwhat==edge){
pbc.g1 = new elementGroup (1, phys1);
pbc.g2 = new elementGroup (1, phys2);
pbc.onWhat=nonLinearBoundaryCondition::ON_EDGE;
}
else if(onwhat==face){
pbc.g1 = new elementGroup (2, phys1);
pbc.g2 = new elementGroup (2, phys2);
pbc.onWhat=nonLinearBoundaryCondition::ON_FACE;
}
else Msg::Error("Impossible to prescribe a constraint on a %s in periodicBC\n",onwhat.c_str());
if (v1 > 0 && v2 > 0)
{
elementGroup grv1(0,v1);
elementGroup grv2(0,v2);
if (grv1.vsize() > 0 and grv2.vsize() > 0)
{
pbc.v1 = (grv1.vbegin()->second);
pbc.v2 = (grv2.vbegin()->second);
}
else
{
Msg::Error("periodic root vertices have not been correctly defined");
pbc.v1 = NULL;
pbc.v2 = NULL;
}
}
else
{
pbc.v1 = NULL;
pbc.v2 = NULL;
}
pbc.comp.push_back(comp);
pbc.phys1 = phys1;
pbc.phys2 = phys2;
pbc.physVer1 = v1;
pbc.physVer2 = v2;
}
};
void nonLinearMechSolver::averagePeriodicBC(std::string onwhat, const int phys1, const int phys2, const int v1, const int v2, const int comp)
{
if (v1 > 0 && v2 > 0)
{
Msg::Info("average periodic BC comp %d on physical %d physical %d versur vertex %d %d",comp,phys1,phys2,v1,v2);
}
else
{
Msg::Info("average comp %d on physical %d is the same as on physical %d",comp,phys1,phys2);
}
const std::string edge("Edge");
const std::string face("Face");
nonLinearBoundaryCondition::location loc;
if(onwhat==edge)
{
loc=nonLinearBoundaryCondition::ON_EDGE;
}
else if(onwhat==face)
{
loc=nonLinearBoundaryCondition::ON_FACE;
}
bool found = false;
for (std::list<nonLinearAveragePeriodicBCBetweenTwoGroups>::iterator pbctg=allAveragePeriodic.begin(); pbctg!=allAveragePeriodic.end(); pbctg++)
{
nonLinearAveragePeriodicBCBetweenTwoGroups& bc = *pbctg;
if ((bc.onWhat == loc) && (bc.phys1 == phys1) && (bc.phys2 == phys2) && (bc.physVer1 == v1) && (bc.physVer2 == v2))
{
bc.comp.push_back(comp);
found = true;
break;
}
}
if (!found)
{
allAveragePeriodic.emplace_back();
nonLinearAveragePeriodicBCBetweenTwoGroups& pbc = allAveragePeriodic.back();
if(onwhat==edge){
pbc.g1 = new elementGroup (1, phys1);
pbc.g2 = new elementGroup (1, phys2);
pbc.onWhat=nonLinearBoundaryCondition::ON_EDGE;
}
else if(onwhat==face){
pbc.g1 = new elementGroup (2, phys1);
pbc.g2 = new elementGroup (2, phys2);
pbc.onWhat=nonLinearBoundaryCondition::ON_FACE;
}
else Msg::Error("Impossible to prescribe an average PBC constraint on a %s\n",onwhat.c_str());
if (v1 > 0 && v2 > 0)
{
elementGroup grv1(0,v1);
elementGroup grv2(0,v2);
if (grv1.vsize() > 0 and grv2.vsize() > 0){
pbc.v1 = (grv1.vbegin()->second);
pbc.v2 = (grv2.vbegin()->second);
}
else{
Msg::Error("periodic root vertices have not been correctly defined");
pbc.v1 = NULL;
pbc.v2 = NULL;
}
}
else
{
pbc.v1 = NULL;
pbc.v2 = NULL;
}
pbc.comp.push_back(comp);
pbc.phys1 = phys1;
pbc.phys2 = phys2;
pbc.physVer1 = v1;
pbc.physVer2 = v2;
}
};
void nonLinearMechSolver::sameDisplacementBC(std::string onwhat, const int phy, const int rootphy, const int comp, const double fac){
Msg::Info("Displacement comp %d on physical %d is the same as on node %d",comp,phy,rootphy);
allSameDisp.emplace_back();
nonLinearSameDisplacementBC& bc = allSameDisp.back();
bc.comp = comp;
bc.tagRoot = rootphy;
bc.gRoot = new elementGroup(0,rootphy);
bc._tag = phy;
bc.fac = fac;
const std::string node("Node");
const std::string edge("Edge");
const std::string face("Face");
const std::string volume("Volume");
if(onwhat==node){
bc.onWhat=nonLinearBoundaryCondition::ON_VERTEX;
bc.g = new elementGroup(0,phy);
}
else if (onwhat == edge){
bc.onWhat=nonLinearBoundaryCondition::ON_EDGE;
bc.g = new elementGroup(1,phy);
}
else if (onwhat == face){
bc.onWhat=nonLinearBoundaryCondition::ON_FACE;
bc.g = new elementGroup(2,phy);
}
else if (onwhat == volume){
bc.onWhat=nonLinearBoundaryCondition::ON_VOLUME;
bc.g = new elementGroup(3,phy);
}
else{
Msg::Error("Impossible to prescribe a constraint on a %s in sameDisplacementBC\n",onwhat.c_str());
}
}
void nonLinearMechSolver::sameDisplacementBCBetweenTwoGroups(std::string onwhat, const int phy1, const int phy2, const int comp){
periodicBC(onwhat,phy1,phy2,0,0,comp);
};
void nonLinearMechSolver::sameAverageDisplacementBCBetweenTwoGroups(std::string onwhat, const int phy1, const int phy2, const int comp)
{
averagePeriodicBC(onwhat,phy1,phy2,0,0,comp);
}
void nonLinearMechSolver::fixOnFace(std::string onwhat, const int phy, const double A, const double B, const double C, const double D){
allFixAllFace.emplace_back(A,B,C,D);
nonLinearFixOnFaceBC& bc = allFixAllFace.back();
const std::string node("Node");
const std::string edge("Edge");
const std::string face("Face");
const std::string volume("Volume");
bc._tag = phy;
if(onwhat==node){
bc.onWhat=nonLinearBoundaryCondition::ON_VERTEX;
bc.g = new elementGroup(0,phy);
}
else if (onwhat == edge){
bc.onWhat=nonLinearBoundaryCondition::ON_EDGE;
bc.g = new elementGroup(1,phy);
}
else if (onwhat == face){
bc.onWhat=nonLinearBoundaryCondition::ON_FACE;
bc.g = new elementGroup(2,phy);
}
else if (onwhat == volume){
bc.onWhat=nonLinearBoundaryCondition::ON_VOLUME;
bc.g = new elementGroup(3,phy);
}
else{
Msg::Error("Impossible to prescribe a constraint on a %s in fixOnFace\n",onwhat.c_str());
}
};
void nonLinearMechSolver::symetryBC(std::string onwhat, const int phy){
allFixAllFace.emplace_back();
nonLinearFixOnFaceBC& bc = allFixAllFace.back();
const std::string face("Face"); // for 3D
bc._tag = phy;
if (onwhat == face){
bc.onWhat=nonLinearBoundaryCondition::ON_FACE;
bc.g = new elementGroup(2,phy);
MElement* ele = NULL;
if (bc.g->size() == 0)
Msg::Error("physical %d has not element",phy);
else
ele = (bc.g->begin()->second);
SPoint3 p1 = ele->getVertex(0)->point();
SPoint3 p2 = ele->getVertex(1)->point();
SVector3 u12(p2,p1);
SPoint3 p3 = ele->getVertex(2)->point();
SVector3 u13(p3,p1);
SVector3 n = crossprod(u12,u13);
if (n.norm() <= 0.) Msg::Info("zero normal to fixed face");
n.normalize();
bc.A = n(0);
bc.B = n(1);
bc.C = n(2);
bc.D = -(n(0)*p1.x()+n(1)*p1.y()+n(2)*p1.z());
}
else{
Msg::Error("Impossible to prescribe a constraint on a %s in symetryBC\n",onwhat.c_str());
}
};
void nonLinearMechSolver::applySameDispBC(){
for(std::list<nonLinearSameDisplacementBC>::const_iterator sdbc=allSameDisp.begin(); sdbc!=allSameDisp.end(); ++sdbc){
if (isDgDomain()){
MElement* e = NULL;
if (sdbc->gRoot->size() ==0)
{
Msg::Error("applySameDispBC has no gRoot");
Msg::Exit(0);
}
else
e = (sdbc->gRoot->begin()->second);
MVertex* vroot = e->getVertex(0);
MElement* eleRoot = NULL;
FunctionSpaceBase* spaceRoot = NULL;
int vpos = 0.;
for (int i=0; i< domainVector.size(); i++){
partDomain* dom = domainVector[i];
for (elementGroup::elementContainer::const_iterator it = dom->element_begin(); it != dom->element_end(); it++){
MElement* ele = it->second;
for (int j=0; j< ele->getNumVertices(); j++){
MVertex* vj = ele->getVertex(j);
if (vj->getNum() == vroot->getNum()){
eleRoot = ele;
spaceRoot = dom->getFunctionSpace();
vpos = j;
Msg::Info("found root element %d for root node %d vpos = %d",eleRoot->getNum(),vroot->getNum(),vpos);
break;
}
}
if (eleRoot != NULL) break;
}
if (eleRoot != NULL) break;
}
if (eleRoot == NULL) Msg::Error("root vertex is wrongly defined in nonLinearMechSolver::applySameDispBC");
std::vector<Dof> RRoot;
std::vector<Dof> dofRoot;
spaceRoot->getKeys(eleRoot,RRoot);
dofRoot.push_back(RRoot[vpos+eleRoot->getNumVertices()*sdbc->comp]);
// fill domain
std::set<Dof> others;
for (elementGroup::elementContainer::const_iterator itg = sdbc->g->begin(); itg!=sdbc->g->end(); itg++){
MElement* eleBound = itg->second;
std::vector<int> vvBound(eleBound->getNumPrimaryVertices());
for (int iv=0; iv < eleBound->getNumPrimaryVertices(); iv++){
vvBound[iv] = eleBound->getVertex(iv)->getNum();
}
// find bulk element
MElement* eleBulk = NULL;
FunctionSpaceBase* spaceBulk = NULL;
for (int i=0; i< domainVector.size(); i++){
partDomain* dom = domainVector[i];
for (elementGroup::elementContainer::const_iterator it = dom->element_begin(); it != dom->element_end(); it++){
MElement* eleb = it->second;
std::set<int> vvb;
for (int iv=0; iv < eleb->getNumPrimaryVertices(); iv++){
vvb.insert(eleb->getVertex(iv)->getNum());
}
bool isFound = true;
for (int iv=0; iv< vvBound.size(); iv++){
if (vvb.find(vvBound[iv]) == vvb.end()){
isFound = false;
break;
}
}
if (isFound){
eleBulk = eleb;
spaceBulk = dom->getFunctionSpace();
break;
}
}
if (eleBulk != NULL) break;
}
if (eleBulk == NULL) Msg::Error("nonLinearSameDisplacementBC is wrongly defined nonLinearMechSolver::applySameDispBC");
std::vector<Dof> R;
spaceBulk->getKeys(eleBulk,R);
int nbFFb = eleBulk->getNumShapeFunctions();
std::vector<int> positionBulk;
for (int iv=0; iv< eleBound->getNumVertices(); iv++){
MVertex* vi = eleBound->getVertex(iv);
//
if (vi->getNum() != vroot->getNum()){
for (int jv=0; jv < eleBulk->getNumVertices(); jv++){
MVertex* vj = eleBulk->getVertex(jv);
if (vi->getNum() == vj->getNum()){
positionBulk.push_back(jv);
break;
}
}
}
}
for (int k=0; k<positionBulk.size(); k++){
Dof* D = &R[positionBulk[k]+nbFFb*sdbc->comp];
if (others.find(*D) == others.end()){
others.insert(*D);
}
}
}
DofAffineConstraint<double> dof;
dof.linear.push_back(std::pair<Dof,double>(dofRoot[0],sdbc->fac));
dof.shift = 0.;
for (std::set<Dof>::iterator itd = others.begin(); itd != others.end(); itd++){
if (!pAssembler->isConstrained(*itd) and !pAssembler->isFixed(*itd)){
pAssembler->setLinearConstraint(*itd,dof);
}
};
}
else{
// because of CG
FunctionSpaceBase* spb = domainVector[0]->getFunctionSpace();
FilterDof* fiterDof = domainVector[0]->createFilterDof(sdbc->comp);
// get Root Dof
MElement* e = (sdbc->gRoot->begin()->second);
MVertex* vroot = e->getVertex(0);
std::vector<Dof> R, dofRoot;
spb->getKeys(e,R);
for (int idof=0; idof<R.size(); idof++){
if (fiterDof->operator()(R[idof])){
dofRoot.push_back(R[idof]);
break;
}
}
std::vector<Dof> others;
// get constraint Dof
for (elementGroup::vertexContainer::const_iterator it = sdbc->g->vbegin(); it!=sdbc->g->vend(); it++){
MVertex* vv = it->second;
if (vv->getNum() != vroot->getNum()){
MPoint point(it->second);
R.clear();
spb->getKeys(&point,R);
for (int idof=0; idof<R.size(); idof++){
if (fiterDof->operator()(R[idof])){
others.push_back(R[idof]);
break;
}
}
}
}
DofAffineConstraint<double> dof;
dof.linear.push_back(std::pair<Dof,double>(dofRoot[0],sdbc->fac));
dof.shift = 0.;
for (int j =0; j<others.size(); j++){
if (!pAssembler->isConstrained(others[j]) and !pAssembler->isFixed(others[j])){
pAssembler->setLinearConstraint(others[j],dof);
}
};
};
};
};
void nonLinearMechSolver::applyFixOnFace(){
if (allFixAllFace.size() > 0){
Msg::Info("begin applying fix on face BC");
}
if (isDgDomain()){
//for (const nonLinearFixOnFaceBC & fofbc : allFixAllFace){
for(std::list<nonLinearFixOnFaceBC>::const_iterator fofbc=allFixAllFace.begin(); fofbc!=allFixAllFace.end(); fofbc++){
double A = fofbc->A;
double B = fofbc->B;
double C = fofbc->C;
double D = fofbc->D;
for (elementGroup::elementContainer::const_iterator it = fofbc->g->begin();
it!= fofbc->g->end(); it++){
MElement* ele = it->second;
MElement* eleFound = NULL;
partDomain* domFound = NULL;
bool found = false;
std::vector<MVertex*> vvMaster;
ele->getVertices(vvMaster);
for (int idom =0; idom< domainVector.size(); idom ++){
partDomain* aldo = domainVector[idom];
for (elementGroup::elementContainer::const_iterator itedom = aldo->element_begin(); itedom != aldo->element_end(); itedom++){
MElement* receiveEle = itedom->second;
int numFace = receiveEle->getNumFaces();
for (int kk=0; kk<numFace; kk++){
std::vector<MVertex*> faceVer;
receiveEle->getFaceVertices(kk,faceVer);
if (ele->getType() == TYPE_TRI){
if ((vvMaster[0] == faceVer[0] and vvMaster[1] == faceVer[1] and vvMaster[2] == faceVer[2]) or
(vvMaster[0] == faceVer[0] and vvMaster[1] == faceVer[2] and vvMaster[2] == faceVer[1]) or
(vvMaster[0] == faceVer[1] and vvMaster[1] == faceVer[0] and vvMaster[2] == faceVer[2]) or
(vvMaster[0] == faceVer[1] and vvMaster[1] == faceVer[2] and vvMaster[2] == faceVer[0]) or
(vvMaster[0] == faceVer[2] and vvMaster[1] == faceVer[1] and vvMaster[2] == faceVer[0]) or
(vvMaster[0] == faceVer[2] and vvMaster[1] == faceVer[0] and vvMaster[2] == faceVer[1])){
found = true;
eleFound = receiveEle;
domFound = aldo;
break;
}
}
else if (ele->getType() == TYPE_QUA){
if ((vvMaster[0] == faceVer[0] and vvMaster[1] == faceVer[1] and vvMaster[2] == faceVer[2]) or
(vvMaster[0] == faceVer[1] and vvMaster[1] == faceVer[2] and vvMaster[2] == faceVer[3]) or
(vvMaster[0] == faceVer[2] and vvMaster[1] == faceVer[3] and vvMaster[2] == faceVer[0]) or
(vvMaster[0] == faceVer[3] and vvMaster[1] == faceVer[0] and vvMaster[2] == faceVer[1]) or
(vvMaster[0] == faceVer[0] and vvMaster[1] == faceVer[3] and vvMaster[2] == faceVer[2]) or
(vvMaster[0] == faceVer[3] and vvMaster[1] == faceVer[2] and vvMaster[2] == faceVer[1]) or
(vvMaster[0] == faceVer[2] and vvMaster[1] == faceVer[1] and vvMaster[2] == faceVer[0]) or
(vvMaster[0] == faceVer[1] and vvMaster[1] == faceVer[0] and vvMaster[2] == faceVer[3])){
found = true;
eleFound = receiveEle;
domFound = aldo;
break;
};
}
else{
Msg::Warning("Element type %d is not implemented",ele->getType());
}
}
if (found) break;
}
if (found) break;
};
if (!found) Msg::Error("ele %d is not found",ele->getNum());
int nbFF = eleFound->getNumShapeFunctions();
std::vector<Dof> keys;
domFound->getFunctionSpace()->getKeys(eleFound,keys);
for (int iver = 0; iver < vvMaster.size(); iver++){
MVertex* v = vvMaster[iver];
int idex = -1;
for (int ii=0; ii < eleFound->getNumVertices(); ii++){
if (eleFound->getVertex(ii)->getNum() == v->getNum()){
idex = ii;
break;
}
}
std::vector<Dof> R;
R.push_back(keys[idex]);
R.push_back(keys[idex+nbFF]);
R.push_back(keys[idex+2*nbFF]);
DofAffineConstraint<double> dof;
double val = -1.*(A*v->x()+B*v->y()+C*v->z()+D);
if (fabs(A) > 1e-10 and !pAssembler->isFixed(R[0])){
if (!pAssembler->isFixed(R[1]) or !pAssembler->isFixed(R[2])){
dof.shift = val/A;
dof.linear.push_back(std::pair<Dof,double>(R[1],-B/A));
dof.linear.push_back(std::pair<Dof,double>(R[2],-C/A));
pAssembler->setLinearConstraint(R[0],dof);
}
}
else if (fabs(B) > 1e-10 and !pAssembler->isFixed(R[1])){
if (!pAssembler->isFixed(R[0]) or !pAssembler->isFixed(R[2])){
dof.shift = val/B;
dof.linear.push_back(std::pair<Dof,double>(R[0],-A/B));
dof.linear.push_back(std::pair<Dof,double>(R[2],-C/B));
pAssembler->setLinearConstraint(R[1],dof);
}
}
else if (fabs(C) > 1e-10 and !pAssembler->isFixed(R[2])){
if (!pAssembler->isFixed(R[0]) or !pAssembler->isFixed(R[1])){
dof.shift = val/C;
dof.linear.push_back(std::pair<Dof,double>(R[0],-A/C));
dof.linear.push_back(std::pair<Dof,double>(R[1],-B/C));
pAssembler->setLinearConstraint(R[2],dof);
}
}
//else
// Msg::Error("error in nonLinearMechSolver::applyFixOnFace");
}
}
}
}
else{
for(std::list<nonLinearFixOnFaceBC>::const_iterator fofBC=allFixAllFace.begin(); fofBC!=allFixAllFace.end(); fofBC++){
double A = fofBC->A;
double B = fofBC->B;
double C = fofBC->C;
double D = fofBC->D;
// because of CG
for (elementGroup::vertexContainer::const_iterator it = fofBC->g->vbegin();
it!= fofBC->g->vend(); it++){
MVertex* v = it->second;
int idex = -1;
MElement* ele = NULL;
partDomain* dom = NULL;
bool found = false;
for (int idom =0; idom< domainVector.size(); idom ++){
partDomain* aldo = domainVector[idom];
for (elementGroup::elementContainer::const_iterator itedom = aldo->element_begin(); itedom != aldo->element_end(); itedom++){
MElement* etemp = itedom->second;
for (int iv = 0; iv < etemp->getNumVertices(); iv++){
if (etemp->getVertex(iv)->getNum() == v->getNum()){
found = true;
ele = etemp;
dom = aldo;
idex = iv;
break;
}
}
if (found) break;
}
if (found) break;
};
if (!found) Msg::Error("vertex %d is not found",v->getNum());
int nbFF = ele->getNumShapeFunctions();
std::vector<Dof> keys;
dom->getFunctionSpace()->getKeys(ele,keys);
std::vector<Dof> R;
R.push_back(keys[idex]);
R.push_back(keys[idex+nbFF]);
R.push_back(keys[idex+2*nbFF]);
DofAffineConstraint<double> dof;
double val = -1.*(A*v->x()+B*v->y()+C*v->z()+D);
if (fabs(A) > 1e-10 and !pAssembler->isFixed(R[0])){
if (!pAssembler->isFixed(R[1]) or !pAssembler->isFixed(R[2])){
dof.shift = val/A;
dof.linear.push_back(std::pair<Dof,double>(R[1],-B/A));
dof.linear.push_back(std::pair<Dof,double>(R[2],-C/A));
pAssembler->setLinearConstraint(R[0],dof);
}
}
else if (fabs(B) > 1e-10 and !pAssembler->isFixed(R[1])){
if (!pAssembler->isFixed(R[0]) or !pAssembler->isFixed(R[2])){
dof.shift = val/B;
dof.linear.push_back(std::pair<Dof,double>(R[0],-A/B));
dof.linear.push_back(std::pair<Dof,double>(R[2],-C/B));
pAssembler->setLinearConstraint(R[1],dof);
}
}
else if (fabs(C) > 1e-10 and !pAssembler->isFixed(R[2])){
if (!pAssembler->isFixed(R[0]) or !pAssembler->isFixed(R[1])){
dof.shift = val/C;
dof.linear.push_back(std::pair<Dof,double>(R[0],-A/C));
dof.linear.push_back(std::pair<Dof,double>(R[1],-B/C));
pAssembler->setLinearConstraint(R[2],dof);
}
}
}
};
};
if (allFixAllFace.size() > 0){
Msg::Info("end applying fix on face BC");
}
};
void nonLinearMechSolver::archivingNode(const int numphys, const int comp, nonLinearBoundaryCondition::whichCondition wc,const int nstep){
// no distinction between cG/dG and full Dg formulation. class Displacement Field manage it
elementGroup g(0,numphys);
if(g.vsize() >0){
for (elementGroup::vertexContainer::const_iterator it =g.vbegin(); it!= g.vend(); it++){
MVertex* v = it->second;
bool found = false;
for (int i=0; i< anoded.size(); i++)
{
if (anoded[i].physnum == numphys and anoded[i].nodenum == v->getNum() and anoded[i]._comp == comp and anoded[i].wc == wc)
{
found = true;
break;
}
}
if (!found)
{
anoded.emplace_back(numphys,v->getNum(),comp,wc,nstep);
}
}
}
else{
Msg::Warning("No physical group %d So it is impossible to archive nodal displacement",numphys);
}
}
void nonLinearMechSolver::archivingNode(const int numpphys, const int dim, const int comp, nonLinearBoundaryCondition::whichCondition wc,const int nstep){
elementGroup g(dim,numpphys);
FILE* file = NULL;
#if defined(HAVE_MPI)
if (Msg::GetCommRank() == 0)
#endif
{
std::ostringstream ossnumver;
ossnumver << numpphys;
std::string ss = ossnumver.str();
std::string fnam = getFileSavingPrefix()+ "numver" + ss+ ".csv";
file = fopen(fnam.c_str(),"w");
}
for (elementGroup::vertexContainer::const_iterator it =g.vbegin(); it!= g.vend(); it++){
MVertex* vv = it->second;
bool found = false;
for (int i=0; i< anoded.size(); i++)
{
if (anoded[i].physnum == numpphys and anoded[i].nodenum == vv->getNum() and anoded[i]._comp == comp and anoded[i].wc == wc)
{
found = true;
break;
}
}
if (!found)
{
anoded.emplace_back(numpphys,vv->getNum(),comp,wc,nstep);
}
#if defined(HAVE_MPI)
if (Msg::GetCommRank() == 0)
#endif
{
fprintf(file,"%ld ;%f;%f;%f\n",vv->getNum(),vv->x(),vv->y(),vv->z());
}
}
#if defined(HAVE_MPI)
if (Msg::GetCommRank() == 0)
#endif
{
fclose(file);
}
};
void nonLinearMechSolver::archivingRigidContact(const int numphys, const int comp, const int wc,const int nstep){
// For rigid contact the value are disponible on all rank --> archiving only on last rank
#if defined(HAVE_MPI)
if(Msg::GetCommRank() == Msg::GetCommSize() -1)
#endif// HAVE_MPI
{
nonLinearBoundaryCondition::whichCondition whc;
switch(wc){
case 0:
whc = nonLinearBoundaryCondition::position;
break;
case 1:
whc = nonLinearBoundaryCondition::velocity;
break;
case 2:
whc = nonLinearBoundaryCondition::acceleration;
break;
default:
whc = nonLinearBoundaryCondition::position;
}
bool found = false;
for (int i=0; i< anoded.size(); i++)
{
if (anoded[i].physnum == numphys and anoded[i].nodenum == numphys and
anoded[i]._comp == comp and anoded[i].wc == whc and
anoded[i].iscontact)
{
found = true;
break;
}
}
if (!found)
{
anoded.emplace_back(numphys,numphys,comp,whc,nstep,true);
}
}
}
void nonLinearMechSolver::archivingNodeIP(const int numphys, const int ipval,const int elemval,const int nstep){
vaip.push_back(IPField::ip2archive(0, numphys,ipval,elemval,nstep));
}
void nonLinearMechSolver::archivingNodeIPOnPhysicalGroup(const int dim, const int numphys, const int ipval, const int nstep){
elementGroup g(dim,numphys);
if (g.vsize() > 0){
FILE* ff = NULL;
#if defined(HAVE_MPI)
if (Msg::GetCommRank() ==0)
#endif // HAVE_MPI
{
std::string filename = getFileSavingPrefix()+"archivingNodeIPOnPhysicalGroup_vertexList.csv";
ff = fopen(filename.c_str(),"w");
fprintf(ff,"Num;X;Y;Z\n");
}
for (elementGroup::vertexContainer::const_iterator it = g.vbegin(); it!= g.vend(); it++){
MVertex* v = it->second;
vaip.push_back(IPField::ip2archive(ipval,nstep,v));
if (ff != NULL){
fprintf(ff,"%ld;%.16g;%.16g;%.16g\n",v->getNum(),v->x(),v->y(),v->z());
}
}
if (ff != NULL){
fclose(ff);
}
}
};
/**
* @brief Archiving a value IP on an interface element. The result is stored under a csv file.
* @param elenumMinus, elenumPlus: interface between two bulk elements
* @param ipval: a quantity specified in IPField::Ouput
* @param elemval: an operation to perform: 1 - mean value, 2 - min value, 3 - max value, and aribtrary another value - value at a specific Gausspoint specifyied by numip
* @param elemval: an operation to perform: 1 - mean value, 2 - min value, 3 - max value, and aribtrary another value - value at a specific Gausspoint specifyied by numip
* @param numip (0 by default): specifying a IP to archive, ranging from 0 to npts-1. This optiton is considered if elemval is not 1, 2, or 3
* @param nstep (1 by default): archiving frequence after each nstep time steps
*/
void nonLinearMechSolver::archivingInterfaceElementIP(const int elenumMinus,const int elenumPlus, const int ipval,const int elemval, const int numip, const int nstep){
vaip.push_back(IPField::ip2archive(-1, elenumMinus, elenumPlus,ipval,elemval,nstep,numip));
};
/**
* @brief Archiving a value IP on a bulk element. . The result is stored under a csv file.
* @param elenum: element number
* @param ipval: a quantity specified in IPField::Ouput
* @param elemval: an operation to perform between 1 - mean value, 2 - min value, 3 - max value, and aribtrary another value - the value at a specific Gausspoint specifyied by numip
* @param numip (0 by default): specifying a IP to archive, ranging from 0 to npts-1. This optiton is considered if elemval is not 1, 2, or 3
* @param nstep (1 by default): archiving frequence after each nstep time steps
*/
void nonLinearMechSolver::archivingElementIP(const int elenum,const int ipval,const int elemval, const int numip, const int nstep){
// save data on numip on elemement elenum
vaip.push_back(IPField::ip2archive(-1, elenum, elenum,ipval,elemval,nstep,numip));
};
/**
* @brief Archiving a value on a physical (only mean, min, max over this physical are available).
* @param onwhat: entity identification between Node, Edge, Face, or Volume
* @param numphys: physical number of the entity
* @param ipval: a quantity specified in IPField::Ouput
* @param elemval: an operation to perform between 1 - mean value, 2 - min value, 3 - max value
* @param nstep (1 by default): archiving frequence after each nstep time steps
*/
void nonLinearMechSolver::archivingIPOnPhysicalGroup(std::string onwhat, const int numphys, const int ipval,const int elemval, const int nstep){
const std::string node("Node");
const std::string edge("Edge");
const std::string face("Face");
const std::string volume("Volume");
int dim= 0;
if(onwhat==node){
dim =0;
}
else if(onwhat==edge){
dim =1;
}
else if(onwhat==face){
dim =2;
}
else if(onwhat==volume){
dim =3;
}
else Msg::Error("Impossible to archive on a %s\n",onwhat.c_str());
vaip.push_back(IPField::ip2archive(dim, numphys,ipval,elemval,nstep));
}
void nonLinearMechSolver::archivingNodeIPShell(int loc, const int numphys, const int ipval,const int elemval,const int nstep){
vaip.push_back(IPField::ip2archive(0, numphys,ipval,elemval,nstep));
vaip.back().setTag(loc);
}
void nonLinearMechSolver::archivingNodeIPShellOnPhysicalGroup(int loc, const int dim, const int numphys, const int ipval, const int nstep){
elementGroup g(dim,numphys);
if (g.vsize() > 0){
FILE* ff = NULL;
#if defined(HAVE_MPI)
if (Msg::GetCommRank() ==0)
#endif // HAVE_MPI
{
std::string filename = getFileSavingPrefix()+"archivingNodeIPOnPhysicalGroup_vertexList.csv";
ff = fopen(filename.c_str(),"w");
fprintf(ff,"Num;X;Y;Z\n");
}
for (elementGroup::vertexContainer::const_iterator it = g.vbegin(); it!= g.vend(); it++){
MVertex* v = it->second;
vaip.push_back(IPField::ip2archive(ipval,nstep,v));
vaip.back().setTag(loc);
if (ff != NULL){
fprintf(ff,"%ld;%.16g;%.16g;%.16g\n",v->getNum(),v->x(),v->y(),v->z());
}
}
if (ff != NULL){
fclose(ff);
}
}
};
void nonLinearMechSolver::archivingInterfaceElementIPShell(int loc, const int elenumMinus,const int elenumPlus, const int ipval,const int elemval, const int numip, const int nstep){
vaip.push_back(IPField::ip2archive(-1, elenumMinus, elenumPlus,ipval,elemval,nstep,numip));
vaip.back().setTag(loc);
};
void nonLinearMechSolver::archivingElementIPShell(int loc, const int elenum,const int ipval,const int elemval, const int numip, const int nstep){
// save data on numip on elemement elenum
vaip.push_back(IPField::ip2archive(-1, elenum, elenum,ipval,elemval,nstep,numip));
vaip.back().setTag(loc);
};
void nonLinearMechSolver::archivingIPShellOnPhysicalGroup(int loc, std::string onwhat, const int numphys, const int ipval,const int elemval, const int nstep){
const std::string node("Node");
const std::string edge("Edge");
const std::string face("Face");
const std::string volume("Volume");
int dim= 0;
if(onwhat==node){
dim =0;
}
else if(onwhat==edge){
dim =1;
}
else if(onwhat==face){
dim =2;
}
else if(onwhat==volume){
dim =3;
}
else Msg::Error("Impossible to archive on a %s\n",onwhat.c_str());
vaip.push_back(IPField::ip2archive(dim, numphys,ipval,elemval,nstep));
vaip.back().setTag(loc);
}
void nonLinearMechSolver::contactInteraction(contactDomain *cdom){
_allContact.insert(cdom);
}
void nonLinearMechSolver::defoDefoContactInteraction(defoDefoContactDomain *cdom){
_allDefoDefoContact.insert(cdom);
}
// create an element for each element type
// which will be used to compute the time step
void nonLinearMechSolver::initMapMElementToComputeTimeStep()
{
MElementFactory factory;
std::vector<MVertex*> vver;
std::map<int,MElement*>::iterator ite;
for(int i=0;i< _mpiUserDom;i++)
{
partDomain * dom = domainVector[i];
for(elementGroup::elementContainer::const_iterator it=dom->element_begin(); it!=dom->element_end(); ++it){
MElement *ele = it->second;
ite = _mapMElementTmp.find(ele->getTypeForMSH());
if(ite==_mapMElementTmp.end()) // create one new element all vertex are in (0,0,0) They will be filled later
{
vver.clear();
for(int j=0;j<ele->getNumVertices();j++)
{
vver.push_back(new MVertex(0.,0.,0.));
}
_mapMElementTmp.insert(std::pair<int,MElement*>(ele->getTypeForMSH(),factory.create(ele->getTypeForMSH(),vver)));
}
ite = _mapMElementFirstOrder.find(ele->getType());
if(ite == _mapMElementFirstOrder.end())
{
vver.clear();
for(int j=0;j<ele->getNumPrimaryVertices();j++)
{
vver.push_back(new MVertex(0.,0.,0.));
}
MElement *eletmp;
switch(ele->getType())
{
case TYPE_PNT:
eletmp = new MPoint(vver[0]); break;
case TYPE_LIN:
eletmp = factory.create(MSH_LIN_2,vver); break;
case TYPE_TRI:
eletmp = factory.create(MSH_TRI_3,vver); break;
case TYPE_QUA:
eletmp = factory.create(MSH_QUA_4,vver); break;
case TYPE_TET:
eletmp = factory.create(MSH_TET_4,vver); break;
case TYPE_PYR:
eletmp = factory.create(MSH_PYR_5,vver); break;
case TYPE_PRI:
eletmp = factory.create(MSH_PRI_6,vver); break;
case TYPE_HEX:
eletmp = factory.create(MSH_HEX_8,vver); break;
case TYPE_POLYG:
eletmp = factory.create(MSH_POLYG_,vver); break;
case TYPE_POLYH:
eletmp = factory.create(MSH_POLYH_,vver); break;
default:
Msg::Error("unknown element type %d",ele->getType());
}
_mapMElementFirstOrder.insert(std::pair<int,MElement*>(ele->getType(),eletmp));
}
}
}
}
double nonLinearMechSolver::initialCriticalExplicitTimeStep(){
// evaluate the critical time step carachteristic length = hs
double hs;
double dtmin=1.e100; // Initialization to infinity
for(int i=0; i< _mpiUserDom; i++){
partDomain *dom = domainVector[i];
if(dom->elementGroupSize() > 0){ // otherwise no element (interface domain and no need to compute time step)
double hsmin= 1.e100; // Initialization to infinity
FunctionSpaceBase *spdom = dom->getFunctionSpace();
std::vector<Dof> R;
std::vector<double> disp;
materialLaw *mlt = dom->getMaterialLaw();
double celerity = mlt->soundSpeed();
double scaleTimeStep = dom->scaleTimeStep();
for(elementGroup::elementContainer::const_iterator it=dom->element_begin(); it!=dom->element_end(); ++it){
MElement *e = it->second;
// nodal displacement 3 per nodes FIX THIS ASSUMPTION
spdom->getKeys(e,R);
int nkeys = spdom->getNumKeys(e);
int nbvertex = e->getNumVertices();
disp.resize(R.size());
for (int iR = 0; iR < R.size(); iR++){
disp[iR] = 0.;
}
MElement *etmp = NULL;
if((e->getTypeForMSH()!=MSH_TET_10) and (e->getTypeForMSH()!=MSH_TET_20) and (e->getTypeForMSH()!=MSH_HEX_27)) // some functions are undefined in 3D so cannot use new method!
{
etmp = _mapMElementTmp[e->getTypeForMSH()];
for(int j=0;j<nbvertex;j++)
{
//for(int jj=0;jj<nkeyspernodes;jj++){}
MVertex *ver = e->getVertex(j);
MVertex *vertmp = etmp->getVertex(j);
vertmp->x() = ver->x();
vertmp->y() = ver->y();
vertmp->z() = ver->z();
}
}
// Unfortunally, computation of characteristic length depends on the element type
// ADD THIS FUNCTIONS directly in gmsh (method of MELEMENT)
// Problem as inner radius is defined only for 1st order element
switch(e->getTypeForMSH()){
case MSH_QUA_9 :
hs = quadrangle2orderCharacteristicSize(etmp,_mapMElementFirstOrder);
break;
case MSH_QUA_16:
hs = quadrangle3orderCharacteristicSize(etmp,_mapMElementFirstOrder);
break;
case MSH_TRI_6 :
hs = triangular2orderCharacteristicSize(etmp,_mapMElementFirstOrder);
break;
case MSH_TRI_10:
hs = triangular3orderCharacteristicSize(etmp,_mapMElementFirstOrder);
break;
case MSH_TET_10:
hs = tetrahedron2orderCharacteristicSize(e,disp);
break;
case MSH_TET_20:
hs = tetrahedron3orderCharacteristicSize(e,disp);
break;
case MSH_HEX_27:
hs = hexahedron2orderCharacteristicSize(e,disp);
break;
default :
//default criteria innerRadius()/polynomialOrder() as innerRAdius is defined for first order only !!
// keep divide by polynomialOrder to be general for undefined case and add 2 for security
hs = etmp->getInnerRadius()/e->getPolynomialOrder()/2.;
}
if(hs<0)
{
Msg::Error("Negative characteristic size for element %d on rank %d",e->getNum(),Msg::GetCommRank());
}
if(hs<hsmin) hsmin = hs;
R.clear(); disp.clear();
}
double dt = scaleTimeStep*hsmin/celerity;
if(dt < dtmin ) dtmin = dt;
}
}
return dtmin;
};
bool nonLinearMechSolver::considerForTimeStep(const partDomain* dom, MElement* ele) const
{
if (!getElementErosionFilter()(ele)) return false; // if element already eliminate--> do not account for
bool cons = true;
if (dom->getMaterialLaw()->withEnergyDissipation())
{
cons = false;
const AllIPState::ipstateElementContainer *vips = _ipf->getAips()->getIPstate(ele->getNum()); // if one damage element is still work
for(int j=0;j<vips->size();j++){
IPVariable *ipv = (*vips)[j]->getState(IPStateBase::current);
if(ipv->get(IPField::DAMAGE)<0.9)
{
cons = true;
break;
}
}
}
return cons;
};
double nonLinearMechSolver::criticalExplicitTimeStep(){
// evaluate the critical time step carachteristic length = hs
double hs;
double dtmin=1.e100; // Initialization to infinity
for(int i=0; i< _mpiUserDom; i++){
partDomain *dom = domainVector[i];
if(dom->elementGroupSize() > 0){ // otherwise no element (interface domain and no need to compute time step)
double hsmin= 1.e100; // Initialization to infinity
FunctionSpaceBase *spdom = dom->getFunctionSpace();
std::vector<Dof> R;
std::vector<double> disp;
materialLaw *mlt = dom->getMaterialLaw();
double celerity = mlt->soundSpeed();
double scaleTimeStep = dom->scaleTimeStep();
for(elementGroup::elementContainer::const_iterator it=dom->element_begin(); it!=dom->element_end(); ++it){
MElement *e = it->second;
// nodal displacement 3 per nodes FIX THIS ASSUMPTION
if(this->considerForTimeStep(dom,e))
{
spdom->getKeys(e,R);
int nkeys = spdom->getNumKeys(e);
int nbvertex = e->getNumVertices();
_ufield->get(R,disp);
MElement *etmp = NULL;
if((e->getTypeForMSH()!=MSH_TET_10) and (e->getTypeForMSH()!=MSH_TET_20) and (e->getTypeForMSH()!=MSH_HEX_27)) // some functions are undefined in 3D so cannot use new method!
{
etmp = _mapMElementTmp[e->getTypeForMSH()];
for(int j=0;j<nbvertex;j++)
{
//for(int jj=0;jj<nkeyspernodes;jj++){}
MVertex *ver = e->getVertex(j);
MVertex *vertmp = etmp->getVertex(j);
vertmp->x() = ver->x() + disp[j];
vertmp->y() = ver->y() + disp[j+nbvertex];
vertmp->z() = ver->z() + disp[j+nbvertex+nbvertex];
}
}
// Unfortunally, computation of characteristic length depends on the element type
// ADD THIS FUNCTIONS directly in gmsh (method of MELEMENT)
// Problem as inner radius is defined only for 1st order element
switch(e->getTypeForMSH()){
case MSH_QUA_9 :
hs = quadrangle2orderCharacteristicSize(etmp,_mapMElementFirstOrder);
break;
case MSH_QUA_16:
hs = quadrangle3orderCharacteristicSize(etmp,_mapMElementFirstOrder);
break;
case MSH_TRI_6 :
hs = triangular2orderCharacteristicSize(etmp,_mapMElementFirstOrder);
break;
case MSH_TRI_10:
hs = triangular3orderCharacteristicSize(etmp,_mapMElementFirstOrder);
break;
case MSH_TET_10:
hs = tetrahedron2orderCharacteristicSize(e,disp);
break;
case MSH_TET_20:
hs = tetrahedron3orderCharacteristicSize(e,disp);
break;
case MSH_HEX_27:
hs = hexahedron2orderCharacteristicSize(e,disp);
break;
default :
//default criteria innerRadius()/polynomialOrder() as innerRAdius is defined for first order only !!
// keep divide by polynomialOrder to be general for undefined case and add 2 for security
hs = etmp->getInnerRadius()/e->getPolynomialOrder()/2.;
}
if(hs<0)
{
Msg::Error("Negative characteristic size for element %d on rank %d",e->getNum(),Msg::GetCommRank());
}
if(hs<hsmin) hsmin = hs;
R.clear(); disp.clear();
}
}
double dt = scaleTimeStep*hsmin/celerity;
if(dt < dtmin ) dtmin = dt;
}
}
return dtmin;
}
void nonLinearMechSolver::setInitialCondition(){
for(std::list<initialCondition>::iterator itic = allinitial.begin() ; itic != allinitial.end(); ++itic){
initialCondition &initC = *itic;
if(initC._comp != -1){
// select the system if required
nlsDofManager* currentManager = pAssembler->getManagerByComp(initC._comp);
for(int j=0;j<initC._vspace.size();j++)
{
SetInitialDofs(initC._vspace[j],initC._vgroup[j]->begin(),initC._vgroup[j]->end(),initC._mycondition,*currentManager,initC._f,*(initC._vfilter[j]),initC._vdg[j],initC._dofType);
}
}
else
{
// contact if exist always at first system
nlsDofManager* currentManager = pAssembler->getManager(0);
for(int j=0;j<initC._vspace.size();j++){
elementGroup *groupDom = NULL;
if(initC._vgroup[j] != initC._vDomGroup[j])
{
groupDom = initC._vDomGroup[j];
}
SetNormalInitialDofs(initC._vspace[j],initC._vgroup[j]->begin(),initC._vgroup[j]->end(),initC._mycondition,*currentManager,initC._f,*(initC._vfilter[j]),initC._vdg[j],groupDom);
}
}
}
}
double nonLinearMechSolver::solveExplicit(){
_timeManager->initializeTimeSteppingPlan();
this->initializeExplicitScheme();
//
bool forceTimeStepEvaluation=false; // if restart, the time step is forced to be re-estimated
if(restartManager::available() and !_resetRestart)
{
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
restartManager::openRestartFile("nonLinearMechSolver");
restartManager::restart(this);
// restart takes only nonm const argument! So convert numstep and curtime
//
restartManager::closeRestartFile();
Msg::Barrier(); // To wait rank0 before end
restartManager::InitFromRestartFile();
Msg::Barrier(); // To wait rank0 before end
struct stat st;
if(stat("beforeRestart",&st) == 0)
{
std::ostringstream oss;
oss << _timeManager->getLastIterationIndex();
std::string cpDir="mv beforeRestart restart"+oss.str();
int oks =system(cpDir.c_str());
}
forceTimeStepEvaluation=true;
}
_resetRestart=false;
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
/* time loop */
double curtime = _timeManager->getLastTime();
while(curtime<_timeManager->getEndTime()){ // end via break for dynamic relaxation
curtime = this->oneExplicitStep(curtime,forceTimeStepEvaluation);
}
/* end of scheme */
return this->finalizeExplicitScheme(curtime);
}
void nonLinearMechSolver::initializeExplicitScheme()
{
Msg::Info("Explicit Data: endtime = %e beta=%f gamma=%f alpha_m=%f",_timeManager->getEndTime(), this->_explicitOpts.beta, this->_explicitOpts.gamma, this->_explicitOpts.alpham);
/* init data */
this->init();
this->init2();
/* mass matrix computation outside the loop */
for(std::vector<partDomain*>::iterator it = domainVector.begin(); it!=domainVector.end(); ++it){
partDomain *dom = *it;
AssembleMass(dom->getBilinearMassTerm(),*(dom->getFunctionSpace()),dom->element_begin(),dom->element_end(),
*(dom->getBulkGaussIntegrationRule()),*pAssembler);
}
if(_notResetedContact){
for(nonLinearMechSolver::contactContainer::iterator itc = _allContact.begin(); itc!= _allContact.end(); ++itc){
contactDomain *cdom = *itc;
if(cdom->isRigid()){
rigidContactSpaceBase *rcsp = static_cast<rigidContactSpaceBase*>(cdom->getSpace());
AssembleMass(cdom->getMassTerm(),rcsp,pAssembler);
}
}
}
/* time initialization */
pAssembler->nextStep();
};
double nonLinearMechSolver::oneExplicitStep(const double curtime, bool &forceTimeStepEvaluation)
{
// Make these to variables static as they have to be kept
// betwwen 2 calls to this function
static double timeStep=0.;
// compute time step and current time
if(_timeManager->getLastIterationIndex()%_explicitOpts.numstepExpl ==0 || forceTimeStepEvaluation){
timeStep = _explicitOpts.gammas * this->criticalExplicitTimeStep();
#if defined(HAVE_MPI)
if(Msg::GetCommSize()>1){
// in case of mpi the time step is choosen as the minimal value compute on each partition
double mpiTimeStep;
MPI_Allreduce(&timeStep,&mpiTimeStep,1,MPI_DOUBLE,MPI_MIN,MPI_COMM_WORLD);
timeStep = mpiTimeStep;
}
#endif // HAVE_MPI
Msg::Info("time step value: %e at time %e",timeStep,curtime);
pAssembler->setTimeStep(timeStep);
_timeManager->setTimeStep(timeStep);
forceTimeStepEvaluation=false;
}
double mytime= curtime + timeStep;
if(mytime>_timeManager->getEndTime())
{
mytime = _timeManager->getEndTime();
timeStep = mytime - curtime;
pAssembler->setTimeStep(timeStep);
_timeManager->setTimeStep(timeStep);
}
this->oneStepPreSolve(mytime,timeStep,_timeManager->getLastIterationIndex()+1);
// solve via assembler to perform mpi operation (communication before and after systemSolve
pAssembler->systemSolve();
// compute the new forces
_ipf->compute1state(IPStateBase::current,false);
double normRHS = this->computeRightHandSide();
if(std::isnan(normRHS))
{
Msg::Error("Nan force value --> end");
return _timeManager->getEndTime(); // To finish the loop
}
if(_explicitOpts.dynamicRelaxation){
double norm0 = pAssembler->norm0Inf();
if(_timeManager->getLastIterationIndex()%_explicitOpts.numstepExpl ==0 ) Msg::Info("Rel norm for dynamic relaxation %e tol = %e",normRHS/norm0,_tol);
if(normRHS/norm0 < _tol){
Msg::Info("Dynamic relaxation procedure is converged. Return endtime to finish the loop");
return _timeManager->getEndTime();
}
if(mytime == _timeManager->getEndTime())
Msg::Info("Dynamic relaxation ended as the final time is reached. But convergence is not achieved!");
}
_timeManager->saveTimeHistory(); // time and step increase
this->oneStepPostSolve(mytime,_timeManager->getLastIterationIndex());
// current step
return mytime;
}
double nonLinearMechSolver::finalizeExplicitScheme(const double curtime)
{
pAssembler->nextStep(); // to make last current state at last explicit step
this->endOfScheme(curtime,_timeManager->getLastIterationIndex());
Msg::Info("Explicit OK");
return curtime;
}
void nonLinearMechSolver::initializeStaticScheme()
{
/* init data */
this->init();
this->init2();
// iterative scheme (loop on timestep)
std::string name = "A";
linearSystem<double>* lsys =pAssembler->getLinearSystem(name);
nonLinearSystem<double>* nlsys = dynamic_cast<nonLinearSystem<double>*>(lsys);
if (whatScheme == Implicit){
Msg::Info("begin assembling mass matrix");
/* mass matrix computation outside the loop */
// zero matrix first
nlsys->zeroMatrix(nonLinearSystemBase::mass);
for(std::vector<partDomain*>::iterator it = domainVector.begin(); it!=domainVector.end(); ++it){
partDomain *dom = *it;
AssembleMass(dom->getBilinearMassTerm(),*(dom->getFunctionSpace()),dom->element_begin(),dom->element_end(),
*(dom->getBulkGaussIntegrationRule()),*pAssembler);
}
if(_notResetedContact){
for(nonLinearMechSolver::contactContainer::iterator itc = _allContact.begin(); itc!= _allContact.end(); ++itc){
contactDomain *cdom = *itc;
if(cdom->isRigid()){
rigidContactSpaceBase *rcsp = static_cast<rigidContactSpaceBase*>(cdom->getSpace());
AssembleMass(cdom->getMassTerm(),rcsp,pAssembler);
}
}
}
Msg::Info("done assembling mass matrix");
}
if (whatScheme == Implicit){ //now only for implicit and dgdomain
if (_implicitOpts.noMassPredictorWithoutVelocityAndAcceleration)
{
Msg::Info("start no mass DOFs collecting");
// collect all no mass DOFs
std::set<Dof> nomassDOf;
/// Loop on all domains
for(std::vector<partDomain*>::iterator it=domainVector.begin(); it!=domainVector.end(); ++it){
partDomain *dom = *it;
// take back the keys of dofs
dom->getNoMassDofs(nomassDOf);
}
Msg::Info("done collecting no mass DOF, total %d DOFs ",nomassDOf.size());
std::vector<int> noMasPosInGlobalVec(nomassDOf.size(),0);
int idex = 0;
for (std::set<Dof>::const_iterator itd = nomassDOf.begin(); itd != nomassDOf.end(); itd++){
noMasPosInGlobalVec[idex] = pAssembler->getDofNumber(*itd);
idex ++;
}
// transfer dof to non-linear system
nlsys->setNoMassDofKeys(noMasPosInGlobalVec);
}
}
if (_pathFollowing){
this->computeLoadVector();
}
/* time initialization */
// save solution of previous (initially last step == initial step BEAWARE FOR RESTART)
pAssembler->nextStep();
};
bool nonLinearMechSolver::localPathFollowingSwitching() const{
// for test
double pfCr = _ipf->computePathFollowingLocalValue(IPStateBase::current);
double Defor = _ipf->computeDeformationEnergy(IPStateBase::current);
#if defined(HAVE_MPI)
if (Msg::GetCommSize()> 1){
double Cr[2];
Cr[0] = pfCr;
Cr[1] = Defor;
double totalCr[2];
MPI_Allreduce(&Cr[0],&totalCr[0],2,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
if (totalCr[1] > 0.)
Msg::Info("pf = %e, deforEnerg = %e cr = %e impose value %e ",totalCr[0],totalCr[1],totalCr[0]/totalCr[1],_pfManager._pathFollowingSwitchCriterion);
if (totalCr[0] > _pfManager._pathFollowingSwitchCriterion*totalCr[1]) return true;
else return false;
}
else
#endif //HAVE_MPI
{
if (fabs(Defor) > 0.)
printf("rank %d pf = %e, deforEnerg = %e cr = %e impose value %e \n",Msg::GetCommRank(),pfCr,fabs(Defor),pfCr/fabs(Defor),_pfManager._pathFollowingSwitchCriterion);
if (pfCr > _pfManager._pathFollowingSwitchCriterion*fabs(Defor)) return true;
else return false;
}
};
double nonLinearMechSolver::computeLocalPathFollowingStep() const{
// for adaptive purpose
double localStep = _ipf->computePathFollowingLocalValue(IPStateBase::current) - _ipf->computePathFollowingLocalValue(IPStateBase::previous);
// accumulate from all procs
#if defined(HAVE_MPI)
if (Msg::GetCommSize() > 1){
double totalStep = 0;
MPI_Allreduce(&localStep,&totalStep,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
return totalStep;
}
else
#endif //HAVE_MPI
{
return localStep;
}
};
int nonLinearMechSolver::oneStaticStep(const double curtime,const double dt, const int numstep)
{
double tsystresol = Cpu();
int niteNR = 0;
if (_pathFollowing){
this->oneStepPreSolvePathFollowing(curtime,dt,numstep);
niteNR = NewtonRaphsonPathFollowing(numstep);
}
else{
this->oneStepPreSolve(curtime,dt,numstep);
niteNR = NewtonRaphson(numstep);
}
tsystresol = Cpu() - tsystresol;
Msg::Info("Time of Newton-Raphson resolution %f",tsystresol);
return niteNR;
}
double nonLinearMechSolver::finalizeStaticScheme(const double curtime, const int step)
{
this->endOfScheme(curtime,step);
Msg::Info("NonLinearStatic OK");
return curtime;
}
void nonLinearMechSolver::createOnelabViewOption(const std::string &fname,const int displayType) const
{
std::string optfname(fname);
optfname += ".opt";
FILE * fopt = fopen(optfname.c_str(),"w");
fprintf(fopt,"n = %d;\n",_GmshOneLabViewNum);
fprintf(fopt,"View[n].VectorType = %d;\n",displayType);
fclose(fopt);
_GmshOneLabViewNum++;
return;
}
void nonLinearMechSolver::createOnelabDisplacementView(const std::string &fname, const double time) const
{
static bool initialized = false;
// ask the unknown field to create the view
_ufield->onelabView(_meshFileName,fname,this,std::string("displacement"),0,time,_timeManager->getLastIterationIndex());
if(!initialized)
{
this->createOnelabViewOption(fname,5); // 5 for displacement view type
initialized = true;
}
}
void nonLinearMechSolver::createOnelabVelocityView(const std::string &fname, const double time) const
{
static bool initialized = false;
// ask the unknown field to create the view
_ufield->onelabView(_meshFileName,fname,this,std::string("velocity"),1,time,_timeManager->getLastIterationIndex());
if(!initialized)
{
this->createOnelabViewOption(fname,4); // 4 for 3D arrow view type
initialized = true;
}
}
void nonLinearMechSolver::getOnelabArchiveNodalUnknowns(fullVector<double> &nodalValues) const
{
_ufield->valuesForOnelab(nodalValues);
return;
}
void nonLinearMechSolver::setTimeManager(const TimeManager& tm)
{
//
//double endt = _timeManager->getEndTime();
//double numStep = _timeManager->getNumSteps();
//
if (_timeManager) delete _timeManager;
_timeManager = tm.clone();
// need to transfer the time and other values
//_timeManager->setEndTime(endt);
//_timeManager->setNumSteps(numStep);
};
bool nonLinearMechSolver::checkVertexBelongToDomains(const int phyVer) const{
elementGroup gV(0,phyVer);
MVertex* v = NULL;
if (gV.vsize() > 0)
{
v = (gV.vbegin()->second);
}
if (v == NULL) {
Msg::Error("vertex does not exist");
return true;
}
for (int i=0; i< domainVector.size(); i++){
if (domainVector[i]->elementGroupSize() == 0){
Msg::Error("domain vector must be initialized firts");
}
for (elementGroup::vertexContainer::const_iterator it = domainVector[i]->vertex_begin(); it!= domainVector[i]->vertex_end(); it++){
MVertex* vv = it->second;
if (vv->getNum() == v->getNum()) return true;
}
}
return false;
};
double nonLinearMechSolver::getArchivedNodalValue(const int numphys,const int comp,nonLinearBoundaryCondition::whichCondition wc) const
{
bool found = false;
double dofvalue = 0;
for(std::vector<unknownField::archiveNode>::const_iterator itn = _ufield->getArchiveNodeContainer().begin(); itn!=_ufield->getArchiveNodeContainer().end();++itn)
{
if (itn->physnum == numphys && itn->_comp == comp &&itn->wc == wc)
{
found = true;
if (whatScheme == StaticLinear)
{
pAssembler->getDofValue(itn->D,dofvalue);
}
else
{
pAssembler->getDofValue(itn->D,dofvalue,itn->wc);
}
break;
}
}
#if defined(HAVE_MPI)
if (getNumRanks() > 1)
{
double sumValue;
MPI_Allreduce(&dofvalue,&sumValue, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
return sumValue;
}
else
#endif // HAVE_MPI
{
if (!found){
Msg::Error("Cannot get a value in getArchivedNodalValue.\nTo get a value, the disp archiving on node with physical %d must be defined with archivingNodeDisplacement",numphys);
return 0.;
}
else
return dofvalue;
}
};
double nonLinearMechSolver::getArchivedForceOnPhysicalGroup(std::string onwhat, const int numphys,const int comp) const
{
static std::string node("Node");
static std::string edge("Edge");
static std::string face("Face");
static std::string volu("Volume");
int dim=0;
if(onwhat == node )
dim = 0;
else if(onwhat == edge)
dim = 1;
else if(onwhat == face)
dim = 2;
else if(onwhat == volu)
dim = 3;
double force =0.;
bool found = false;
for(std::vector<archiveForce>::const_iterator itf = vaf.begin(); itf != vaf.end();++itf)
{
if(itf->numphys != numphys) continue;
if(itf->comp != comp) continue;
if(itf->dim != dim) continue;
force = itf->fval; found = true; break;
}
#if defined(HAVE_MPI)
if (getNumRanks() > 1){
double sumValue;
MPI_Allreduce(&force,&sumValue, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
return sumValue;
}
else
#endif // HAVE_MPI
{
if (!found){
Msg::Error("Cannot found a force value in getarchivedForceOnPhysicalGroup");
return 0.;
}
else
return force;
}
}
double nonLinearMechSolver::getEnergy(int we) const
{
double eneryPart =_energField->get(energeticField::whichEnergy(we));
#if defined(HAVE_MPI)
if(Msg::GetCommSize() > 1){
double totalEnerg= 0.;;
MPI_Allreduce(&eneryPart,&totalEnerg,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
return totalEnerg;
}
#endif // HAVE_MPI
return eneryPart;
}
void nonLinearMechSolver::forceArchiving(const double curtime,const int numstep, const bool forceSave)
{
pAssembler->getForces(vaf); // get force value from system
for(int i=0;i<vaf.size();i++){
if (vaf[i].vdof.size()!=0 && (vaf[i].contact_root == -1 || vaf[i].contact_root == Msg::GetCommRank()))
{
if (numstep > vaf[i].lastSaveStep){
if((numstep%(vaf[i].nstep)==0 or forceSave))
{
vaf[i].lastSaveStep = numstep;
fprintf(vaf[i].FP,"%.16g;%.16g\n",curtime,vaf[i].fval);
fflush(vaf[i].FP);
}
}
}
}
}
double nonLinearMechSolver::getHomogenizedStress(const int i, const int j) const{
return _currentState->getHomogenizedStress()(i,j);
};
double nonLinearMechSolver::getHomogenizedTangent(const int i, const int j, const int k, const int l) const{
return _currentState->getHomogenizedTangentOperator_F_F()(i,j,k,l);
};
std::string nonLinearMechSolver::getHomogenizedTangentCompNameInMatrixForm(int row, int col) const
{
int i, j, k, l;
Tensor23::getIntsFromIndex(row,i,j);
Tensor23::getIntsFromIndex(col,k,l);
return "L"+std::to_string(i)+std::to_string(j)+std::to_string(k)+std::to_string(l);
};
void nonLinearMechSolver::getHomogenizedTangent(fullMatrix<double>& Cel) const
{
const STensor43& L = _currentState->getHomogenizedTangentOperator_F_F();
if (Cel.size1() != 9 || Cel.size2() !=9)
{
Cel.resize(9,9,true);
}
for (int row = 0; row <9; row ++)
{
int i, j;
Tensor23::getIntsFromIndex(row,i,j);
for (int col = 0; col < 9; col ++)
{
int k,l;
Tensor23::getIntsFromIndex(col,k,l);
Cel(row,col) = L(i,j,k,l);
}
}
};
void nonLinearMechSolver::getAcousticTensor(double n0, double n1, double n2, fullMatrix<double>& A) const
{
if (A.size1() != 3 || A.size2() != 3)
{
A.resize(3,3,true);
}
else
{
A.setAll(0.);
};
SVector3 n;
n(0) = n0;
n(1) = n1;
n(2) = n2;
const STensor43& L = _currentState->getHomogenizedTangentOperator_F_F();
for (int i=0; i< 3; i++)
{
for (int j=0; j<3; j++)
{
for (int k=0; k<3; k++)
{
for (int l=0; l<3; l++)
{
A(i,k) += n(j)*L(i,j,k,l)*n(l);
}
}
}
}
}
double nonLinearMechSolver::getHomogenizedSecondTangent(const int i, const int j, const int k, const int p, const int q, const int r) const{
return _currentState->getHomogenizedTangentOperator_G_G()(i,j,k,p,q,r);
};
double nonLinearMechSolver::getHomogenizedSecondStress(const int i, const int j, const int k) const{
return _currentState->getHomogenizedSecondOrderStress()(i,j,k);
};
double nonLinearMechSolver::getHomogenizedFirstSecondTangent(const int i, const int j, const int p, const int q, const int r) const{
return _currentState->getHomogenizedTangentOperator_F_G()(i,j,p,q,r);
};
double nonLinearMechSolver::getHomogenizedSecondFirstTangent(const int i, const int j, const int k, const int p, const int q) const{
return _currentState->getHomogenizedTangentOperator_G_F()(i,j,k,p,q);
};
double nonLinearMechSolver::getHomogenizedCohesiveJump(const int i) const{
return _currentState->getHomogenizedCohesiveJump()(i);
};
double nonLinearMechSolver::getNodeIP(const int physical, const int ipVal) const{
return _ipf->getIPValueOnPhysical(0,physical,ipVal);
};
void nonLinearMechSolver::setSelectiveUpdate(const selectiveUpdateBase& selectiveObj){
_failureBasedOnPreviousState = false;
if (_selectiveObject) delete _selectiveObject;
_selectiveObject = selectiveObj.clone();
};
void nonLinearMechSolver::endSchemeMonitoring(const EndSchemeMonitoringBase& endObj){
if (_endSchemeMonitoringObject != NULL) delete _endSchemeMonitoringObject;
_endSchemeMonitoringObject = endObj.clone();
};
bool nonLinearMechSolver::solverEndedByMornitoring() const
{
if (_endSchemeMonitoringObject != NULL)
{
return _endSchemeMonitoringObject->solverEndedByMornitoring();
}
return false;
};
void nonLinearMechSolver::setNoMassPredictorWithoutVelocityAndAcceleration(const bool fl){
_implicitOpts.noMassPredictorWithoutVelocityAndAcceleration = fl;
if (fl)
{
Msg::Info("no velocity and acceleration in predictor of nomass dof with Implicit CH scheme");
}
};
// for crack insertion control
void nonLinearMechSolver::setMaxAllowedCrackInsertionAtOneStep(const int maxNum)
{
if(maxNum < 0) Msg::Error("broken number must be positive nonLinearMechSolver::setMaxAllowedCrackInsertionAtOneStep");
Msg::Info("Only %d interface elements are allowed to be cracked during one step", maxNum);
ReduceTimeStepWithMaximalNumberOfBrokenElements endObj(maxNum);
this->endSchemeMonitoring(endObj);
}
// for element erosion
void nonLinearMechSolver::setElementErosion(const bool bulkErosion, const bool interfaceErosion, const int method){
_bulkElementErosionFlag = bulkErosion;
_interfaceElementErosionFlag = interfaceErosion;
if (_bulkElementErosionFlag or _interfaceElementErosionFlag){
_erosionType = (elementErosionType)method;
if (_erosionType == nonLinearMechSolver::FIRST_IP_FAILED){
Msg::Info("An element is removed when first IP reaches failure state");
}
else if (_erosionType == nonLinearMechSolver::ALL_IP_FAILED){
Msg::Info("An element is removed when all IPs reach failure state");
}
else{
Msg::Error("_erosionType is not defined nonLinearMechSolver::setElementErosion");
}
}
};
void nonLinearMechSolver::setGlobalErosionCheck(const bool flag, const FailureCriterionBase* fcr){
if (flag){
Msg::Info("erosion is checked globally based on a global criterion");
if (_erosionGlobalCriterion!=NULL) delete _erosionGlobalCriterion;
_erosionGlobalCriterion = fcr->clone();
}
};
//
// C++ Interface: terms Quasi Static
//
// Description: Files with definition of function : nonLinearMechSolver::solveSNL()
//
//
// Author: <Gauthier BECKER>, (C) 2010
//
// Copyright: See COPYING file that comes with this distribution
//
//
// compute Fext-Fint
double nonLinearMechSolver::computeRightHandSide()
{
pAssembler->clearRHSfixed();
this->computeInternalForces();
// compute ext forces
this->computeExternalForces();
// compute contact forces
this->computeContactForces();
// for periodic BC
if (_microFlag){
if (_systemType == nonLinearMechSolver::MULT_ELIM){
_pAl->assembleConstraintResidualToSystem();
this->computeStiffMatrix();
if(computedUdF() and _pathFollowing and useWhichModuliForBF()==partDomain::Present){
this->computeBodyForceVector();
}
}
else if (_systemType == nonLinearMechSolver::DISP_MULT) {
_pAl->computeLinearConstraints();
}
}
if (_pathFollowing and _pfManager._pathFollowingMethod == pathFollowingManager::LOCAL_BASED){
this->computePathFollowingConstraint();
}
// save Fint component to archive ( write in file when Fint = Fext)
// return lsys->normInfRightHandSide();
return pAssembler->normInfRightHandSide();
}
void nonLinearMechSolver::computeInternalForces()
{
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end();++itdom)
{
partDomain *dom = *itdom;
Assemble(dom->getLinearBulkTerm(),*(dom->getFunctionSpace()),dom->element_begin(),dom->element_end(),
*(dom->getBulkGaussIntegrationRule()),_ufield, *pAssembler,
nonLinearSystemBase::Fint,_elementErosionFilter);
if(dom->IsInterfaceTerms()){
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
Assemble(dgdom->getLinearInterfaceTerm(),*(dgdom->getFunctionSpace()),dgdom->gi->begin(),dgdom->gi->end(),*(dgdom->getInterfaceGaussIntegrationRule()),
_ufield,*pAssembler,nonLinearSystemBase::Fint,_elementErosionFilter); // Use the same GaussQuadrature rule than on the boundary
// Assembling loop on elementary boundary interface terms
Assemble(dgdom->getLinearVirtualInterfaceTerm(),*(dgdom->getFunctionSpace()),dgdom->gib->begin(),dgdom->gib->end(),
*(dgdom->getInterfaceGaussIntegrationRule()),_ufield,*pAssembler,nonLinearSystemBase::Fint,_elementErosionFilter); // Use the same GaussQuadrature rule than on the boundary
}
}
}
void nonLinearMechSolver::computeContactForces()
{
for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){
contactDomain *cdom = *it;
contactLinearTermBase<double> *cterm = static_cast<contactLinearTermBase<double>*>(cdom->getForceTerm());
cterm->clearContactNodes();
Assemble(*(cterm),*(cdom->getSpace()),cdom->gSlave->begin(),
cdom->gSlave->end(),*(cdom->getGaussIntegration()),*pAssembler,nonLinearSystemBase::Fext,_elementErosionFilter);
}
for(defoDefoContactContainer::iterator it = _allDefoDefoContact.begin(); it!=_allDefoDefoContact.end(); ++it){
defoDefoContactDomain *cdom = *it;
std::vector< LinearTermBase<double> *> &term = cdom->getRefToForceTerm(); //we might need to change the class
for(int i=0;i<term.size(); i++)
{
contactLinearTermBase<double>* cterm=static_cast< contactLinearTermBase<double>* > (term[i]);
cterm->clearContactNodes();
AssembleDefoDefoContact(*(cterm),*((cdom->getRefToVSpace())[i]),((cdom->getRefToGroup())[i]).begin(),
((cdom->getRefToGroup())[i]).end(),
*((cdom->getRefToVQuadratureMaster())[i]),*pAssembler,nonLinearSystemBase::Fint,_elementErosionFilter); // put in internal forces for path following
}
}
}
void nonLinearMechSolver::computeMassMatrix(){
static std::string Bname("B");
pAssembler->getLinearSystem(Bname)->zeroMatrix();
pAssembler->setCurrentMatrix(Bname);
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom)
{
partDomain* dom = *itdom;
// Assembling loop on Elementary terms
AssembleItMap(*(dom->getBilinearMassTerm()),*(dom->getFunctionSpace()),dom->element_begin(),dom->element_end(),
*(dom->getBulkGaussIntegrationRule()),*pAssembler,_elementErosionFilter);
};
static std::string Aname("A");
pAssembler->setCurrentMatrix(Aname);;
};
void nonLinearMechSolver::computeStiffMatrix()
{
if (_stiffEstimation)
{
if (!_stiffnessModification)
{
_stiffEstimation = false;
if (_stiffnessModificationMonitoring->tangentType() == IPStateBase::previous)
{
_ipf->copy(IPStateBase::current,IPStateBase::temp);
_ipf->copy(IPStateBase::previous,IPStateBase::current);
}
}
//Msg::Info("call nonLinearMechSolver::computeStiffMatrix");
pAssembler->zeroMatrix();
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom)
{
partDomain* dom = *itdom;
// Assembling loop on Elementary terms
AssembleItMap(*(dom->getBilinearBulkTerm()),*(dom->getFunctionSpace()),dom->element_begin(),dom->element_end(),
*(dom->getBulkGaussIntegrationRule()),*pAssembler,_elementErosionFilter);
if(dom->IsInterfaceTerms())
{
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
// Assembling loop on elementary interface terms
AssembleItMap(*(dgdom->getBilinearInterfaceTerm()),*(dom->getFunctionSpace()),dgdom->gi->begin(),dgdom->gi->end(),
*(dgdom->getInterfaceGaussIntegrationRule()),*pAssembler,_elementErosionFilter);
// Assembling loop on elementary boundary interface terms
AssembleItMap(*(dgdom->getBilinearVirtualInterfaceTerm()),*(dom->getFunctionSpace()),dgdom->gib->begin(),dgdom->gib->end(),
*(dgdom->getInterfaceGaussIntegrationRule()),*pAssembler,_elementErosionFilter);
}
}
// NeumannBC (non linear flux)
if(this->getScheme() != StaticLinear)
{
for(std::list<nonLinearNeumannBC>::iterator itbc = allNeumann.begin(); itbc != allNeumann.end();++itbc){
nonLinearNeumannBC &neu = *itbc;
for(int j=0;j<neu._vspace.size();j++)
{
FunctionSpaceBase *spn = neu._vspace[j];
const elementGroup *gneu = neu._vgroup[j];
QuadratureBase *qneu = neu._vquadrature[j];
AssembleSkipEmpty(*(neu._vmatrix_term[j]),*spn,gneu->begin(),gneu->end(),*(qneu),*pAssembler,_elementErosionFilter);
}
}
}
else{
for(std::list<nonLinearNeumannBC>::iterator itbc = allNeumann.begin(); itbc != allNeumann.end();++itbc){
nonLinearNeumannBC &neu = *itbc;
for(int j=0;j<neu._vspace.size();j++)
{
FunctionSpaceBase *spn = neu._vspace[j];
const elementGroup *gneu = neu._vgroup[j];
QuadratureBase *qneu = neu._vquadrature[j];
AssembleSkipEmpty(*(neu._vmatrix_term[j]),*spn,gneu->begin(),gneu->end(),*(qneu),*pAssembler,_elementErosionFilter);
}
}
}
// Contact
// little particular because it the term itself which know (via its linked linear term) the element
// where there is contact and so a bilinearterm != 0 as to be computed
for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){
contactDomain *cdom = *it;
contactBilinearTermBase<double> *sterm = static_cast<contactBilinearTermBase<double>*>(cdom->getStiffnessTerm());
AssembleItMap(*sterm,*(cdom->getSpace()),sterm->getContactNodes()->elemBegin(),
sterm->getContactNodes()->elemEnd(),*(cdom->getGaussIntegration()),*pAssembler,_elementErosionFilter);
// sterm->clearContactNodes();
}
for(defoDefoContactContainer::iterator it = _allDefoDefoContact.begin(); it!=_allDefoDefoContact.end(); ++it){
defoDefoContactDomain *cdom = *it;
const std::vector<BilinearTermBase*> &sterm = static_cast< const std::vector<BilinearTermBase* > >(cdom->getConstRefToStiffnessTerm()); //we might need to change the class
for(int i=0; i<sterm.size(); i++)
{
AssembleSkipEmptyDefoDefoContact(*(sterm[i]),*(cdom->getRefToVSpace()[i]),((cdom->getRefToGroup())[i]).begin(),
((cdom->getRefToGroup())[i]).end(),
*(cdom->getRefToVQuadratureMaster()[i]),*pAssembler,_elementErosionFilter);
}
}
// for periodic BC
if (_microFlag)
if (_systemType == nonLinearMechSolver::DISP_MULT)
_pAl->assembleConstraintMatrix();
if (!_stiffnessModification)
{
if (_stiffnessModificationMonitoring->tangentType() == IPStateBase::previous)
{
// copy back to current state
_ipf->copy(IPStateBase::temp,IPStateBase::current);
}
}
}
if (_pathFollowing and _pfManager._pathFollowingMethod == pathFollowingManager::LOCAL_BASED){
this->computeDPathFollowingConstraintDUnknowns();
}
}
void nonLinearMechSolver::computeElasticStiffMatrix(){
if (_stiffEstimation)
{
if (!_stiffnessModification)
{
_stiffEstimation = false;
}
pAssembler->zeroMatrix();
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom)
{
partDomain* dom = *itdom;
// Assembling loop on Elementary terms
AssembleItMap(*(dom->getBilinearElasticBulkTerm()),*(dom->getFunctionSpace()),dom->element_begin(),dom->element_end(),
*(dom->getBulkGaussIntegrationRule()),*pAssembler,_elementErosionFilter);
}
// Contact
// little particular because it the term itself which know (via its linked linear term) the element
// where there is contact and so a bilinearterm != 0 as to be computed
for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){
contactDomain *cdom = *it;
contactBilinearTermBase<double> *sterm = static_cast<contactBilinearTermBase<double>*>(cdom->getStiffnessTerm());
AssembleItMap(*sterm,*(cdom->getSpace()),sterm->getContactNodes()->elemBegin(),
sterm->getContactNodes()->elemEnd(),*(cdom->getGaussIntegration()),*pAssembler,_elementErosionFilter);
// sterm->clearContactNodes();
}
for(defoDefoContactContainer::iterator it = _allDefoDefoContact.begin(); it!=_allDefoDefoContact.end(); ++it){
defoDefoContactDomain *cdom = *it;
const std::vector<BilinearTermBase*> &sterm = static_cast< const std::vector<BilinearTermBase* > >(cdom->getConstRefToStiffnessTerm()); //we might need to change the class
for(int i=0; i<sterm.size(); i++)
{
AssembleSkipEmptyDefoDefoContact(*(sterm[i]),*(cdom->getRefToVSpace()[i]),((cdom->getRefToGroup())[i]).begin(),
((cdom->getRefToGroup())[i]).end(),
*(cdom->getRefToVQuadratureMaster()[i]),*pAssembler,_elementErosionFilter);
}
}
// for periodic BC
if (_microFlag)
if (_systemType == nonLinearMechSolver::DISP_MULT)
_pAl->assembleConstraintMatrix();
}
if (_pathFollowing and _pfManager._pathFollowingMethod == pathFollowingManager::LOCAL_BASED){
this->computeDPathFollowingConstraintDUnknowns();
}
}
// Newton Raphson scheme to solve one step
int nonLinearMechSolver::NewtonRaphson(const int numstep){
if (whatScheme == Implicit){
// dynamic predictor
pAssembler->systemSolveIntReturn();
}
// compute ipvariable
if(computedUdF()){
_ipf->setDeformationGradientGradient(this->getMicroBC()->getSecondOrderKinematicalVariable(), IPStateBase::current);
}
_ipf->compute1state(IPStateBase::current, true);
// Compute Right Hand Side (Fext-Fint)
double normFinf = this->computeRightHandSide();
// norm0 = norm(Fext) + norm(Fint) to have a relative convergence
double norm0 = pAssembler->norm0Inf();
// loop until convergence
int iter=0;
if(norm0 == 0){ // no force (can append if contact )
Msg::Info("no force go next step");
if (_microFlag) this->computeStiffMatrix();
return 0;
}
double relnorm = normFinf/norm0;
Msg::Info("iteration n %d : residu : %e, absolute residu : %e",iter,relnorm,normFinf);
while ((relnorm>_tol and normFinf>_absTol) or iter == 0){ // ensure 1 iteration min
iter++;
// Compute Stiffness Matrix
this->computeStiffMatrix();
// Solve KDu = Fext-Fint
double t = Cpu();
int succeed = pAssembler->systemSolveIntReturn();
t = Cpu() - t;
if(!succeed)
{
iter = _timeManager->getMaxNbIterations();
break;
}
// update ipvariable
_ipf->compute1state(IPStateBase::current,true);
if (!_iterativeNR) break;
// new forces
normFinf = this->computeRightHandSide();
// Check of convergence
relnorm = normFinf/norm0;
Msg::Info("iteration n %d : residu : %e, absolute residu : %e, solving time: %f",iter,relnorm, normFinf,t);
// perform line search if activate (default)
while((relnorm>_tol and normFinf>_absTol) and (iter > 1)) // avoid line search for linear case
{
int ls = pAssembler->lineSearch();
if(ls == 1) break; // processus is converged or failed
// update ipvariable
_ipf->compute1state(IPStateBase::current,true);
// new RightHandSide
this->computeRightHandSide();
}
if((iter == _timeManager->getMaxNbIterations()) or std::isnan(relnorm))
{
// reset system value
iter = _timeManager->getMaxNbIterations(); // for isnan case
break;
}
}
return iter;
}
linearSystem<double>* nonLinearMechSolver::createSNLSystem()
{
// Select the solver for linear system Ax=b (KDeltau = Fext-Fint)
linearSystem<double> *lsys = NULL;
if(nonLinearMechSolver::whatSolver == Taucs){
#if defined(HAVE_TAUCS)
lsys = new nonLinearSystemCSRTaucs<double>(_lineSearch);
Msg::Info("Taucs is chosen to solve");
#else
lsys = new nonLinearSystemGmm<double>(_lineSearch);
dynamic_cast<nonLinearSystemGmm<double>*>(lsys)->setNoisy(2);
Msg::Error("Taucs is not installed\n Gmm is chosen to solve");
#endif
}
else if(nonLinearMechSolver::whatSolver == Petsc){
#if defined(HAVE_PETSC)
if (_pathFollowing){
if ((!_isPartitioned) and (Msg::GetCommSize()>1)){
if (_pfManager._pathFollowingMethod == pathFollowingManager::GLOBAL_ARC_LENGTH_BASED){
lsys = new pathFollowingSystemPETSC<double>(PETSC_COMM_SELF);
}
else if (_pfManager._pathFollowingMethod == pathFollowingManager::LOCAL_BASED){
lsys = new generalLocalControlBasedPathFollowingSystemPETSc<double>(PETSC_COMM_SELF);
}
else if (_pfManager._pathFollowingMethod == pathFollowingManager::HYPERELLIPTIC_BASED){
lsys = new generalHyperellipticPathFollowingSystemPETSC<double>(PETSC_COMM_SELF);
}
else
Msg::Error("path following method %d is not defined",_pfManager._pathFollowingMethod);
}
else{
if (_pfManager._pathFollowingMethod == pathFollowingManager::GLOBAL_ARC_LENGTH_BASED){
lsys = new pathFollowingSystemPETSC<double>(PETSC_COMM_WORLD);
}
else if (_pfManager._pathFollowingMethod == pathFollowingManager::LOCAL_BASED){
lsys = new generalLocalControlBasedPathFollowingSystemPETSc<double>(PETSC_COMM_WORLD);
}
else if (_pfManager._pathFollowingMethod == pathFollowingManager::HYPERELLIPTIC_BASED){
lsys = new generalHyperellipticPathFollowingSystemPETSC<double>(PETSC_COMM_WORLD);
}
else
Msg::Error("path following method %d is not defined", _pfManager._pathFollowingMethod);
}
// set path following options
// paramater remains default if it is negative
pathFollowingSystemBase* pfsysBase = dynamic_cast<pathFollowingSystemBase*>(lsys);
if (_pfManager._controlTypePathFollowing >=0){
pfsysBase->setControlType(_pfManager._controlTypePathFollowing);
}
if (_pfManager._correctionMethodPathFollowing>=0){
pfsysBase->setCorrectionMethod(_pfManager._correctionMethodPathFollowing);
}
if (_pfManager._tranversalCriterionPathFollowing>=0){
pfsysBase->setTranversalCriterion(_pfManager._tranversalCriterionPathFollowing);
}
if (_pfManager._solverTypePathFollowing >=0){
pfsysBase->setSolverType(_pfManager._solverTypePathFollowing,_pfManager._pathFollowingEqRatio);
}
}
else{
if ((!_isPartitioned) and (Msg::GetCommSize()>1)){
lsys = new nonLinearSystemPETSc<double>(PETSC_COMM_SELF,_lineSearch);
}
else
{
lsys = new nonLinearSystemPETSc<double>(PETSC_COMM_WORLD,_lineSearch);
}
}
if(_solver_options.size())
lsys->setParameter(std::string("petsc_solver_options"),_solver_options);
Msg::Info("PETSc is chosen to solve");
#else
Msg::Error("PETSc is not installed\n Gmm is chosen to solve");
if (_pathFollowing){
Msg::Error("path following has not been implemented with Gmm, load control is considered");
}
lsys = new nonLinearSystemGmm<double>(_lineSearch);
dynamic_cast<nonLinearSystemGmm<double>*>(lsys)->setNoisy(2);
#endif
}
else if(nonLinearMechSolver::whatSolver == GMRESk){
lsys = new nonLinearSystemGMRESk<double>(_lineSearch);
Msg::Info("GMRESk is chosen to solve");
}
else{
lsys = new nonLinearSystemGmm<double>(_lineSearch);
static_cast<nonLinearSystemGmm<double>*>(lsys)->setNoisy(2);
Msg::Info("Gmm is chosen to solve");
}
nonLinearSystem<double>* nlsys = dynamic_cast<nonLinearSystem<double>*>(lsys);
if (nlsys != NULL){
// initialization data
#if defined(HAVE_MPI)
int rootRank = 0;
std::set<int> OtherRanks;
if ((!_isPartitioned) and (Msg::GetCommSize() >1) ){
// if sequential mesh in mpi run
if (!_microFlag){
// if macro problem
rootRank = 0;
for (int i=1; i< Msg::GetCommSize(); i++){
OtherRanks.insert(i);
}
}
else{
// if micro problem
rootRank = Msg::GetCommRank();
}
}
else{
rootRank = Msg::GetCommRank();
}
nlsys->setWorkingRanks(rootRank,OtherRanks);
#endif // HAVE_MPI
}
return lsys;
}
linearSystem<double>* nonLinearMechSolver::createExplicitSystem()
{
linearSystem<double> *esys;
if(nonLinearMechSolver::whatSolver == Petsc){
#if defined(HAVE_PETSC)
Msg::Info("Explicit scheme based on PETSc");
esys = new explicitHulbertChungPetsc<double>(_explicitOpts.alpham,_explicitOpts.beta,_explicitOpts.gamma,_explicitOpts.timeStepByBenson,_explicitOpts.dynamicRelaxation);
#else
Msg::Warning("petsc is not install on this computer. Use blas explicit system");
#if !defined(HAVE_BLAS)
Msg::Warning("blas is not installed. Use not optimized default implementation");
#endif // HAVE_BLAS
esys = new explicitHulbertChungBlas<double>(_explicitOpts.alpham,_explicitOpts.beta,_explicitOpts.gamma,_explicitOpts.timeStepByBenson,_explicitOpts.dynamicRelaxation);
#endif // HAVE_PETSC
}
else{
#if !defined(HAVE_BLAS)
Msg::Warning("blas is not installed. Use not optimized default implementation. Maybe you can use PETSc ?");
#else
Msg::Info("Explicit scheme based on BLAS");
#endif // HAVE_BLAS
esys = new explicitHulbertChungBlas<double>(_explicitOpts.alpham,_explicitOpts.beta,_explicitOpts.gamma,_explicitOpts.timeStepByBenson,_explicitOpts.dynamicRelaxation);
}
return esys;
}
linearSystem<double>* nonLinearMechSolver::createImplicitSystem(){
linearSystem<double> *esys;
if(nonLinearMechSolver::whatSolver == Petsc){
#if defined(HAVE_PETSC)
Msg::Info("Implicit scheme based on PETSc");
esys = new implicitHulbertChungPetsc<double>(_implicitOpts.alpham,_implicitOpts.alphaf,_implicitOpts.beta,_implicitOpts.gamma);
#else
Msg::Warning("petsc is not install on this computer. Use blas explicit system");
#endif // HAVE_PETSC
}
else{
Msg::Error("Petsc is not installed");
}
return esys;
}
linearSystem<double>* nonLinearMechSolver::createEigenSystem(){
linearSystem<double> *sys = NULL;
#if defined(HAVE_PETSC)
sys = new linearSystemPETSc<double>();
if(_solver_options.size())
sys->setParameter(std::string("petsc_solver_options"),_solver_options);
#else
Msg::Error("Petsc is not intalled");
#endif // HAVE_PETSC
return sys;
}
void nonLinearMechSolver::createSystem()
{
if (_previousInit and _resetRestart)
{
// collect if previous dof exists
if (_collection==NULL)
{
_collection = new DofCollection();
}
_collection->collect(pAssembler);
// clear data
delete pAssembler;
pAssembler = NULL;
}
if(_vcompBySys.size()==0)
{
// create mono system and manager
linearSystem<double> *lsys=NULL;
linearSystem<double> *lsys2 = NULL;
if(whatScheme==Explicit)
{
lsys = this->createExplicitSystem();
pAssembler = new staticDofManager(lsys,whatScheme,false,true);
}
else if (whatScheme == Implicit)
{
lsys = this->createImplicitSystem();
pAssembler = new staticDofManager(lsys,whatScheme,true,true);
}
else if (whatScheme == StaticLinear or whatScheme == StaticNonLinear)
{
lsys = this->createSNLSystem();
if (whatScheme == StaticLinear)
{
pAssembler = new staticDofManager(lsys,whatScheme,true,true);
}
else
{
pAssembler = new staticDofManager(lsys,whatScheme,true,true);
}
}
else if (whatScheme == Eigen)
{
lsys = this->createEigenSystem();
if (_eigOpts.type == eigenSolverOptions::Dynamic)
{
lsys2 = this->createEigenSystem();
}
if (lsys2 != NULL and lsys != NULL)
{
pAssembler = new staticDofManager(lsys,lsys2,true);
}
else
{
pAssembler = new staticDofManager(lsys,whatScheme,true,true);
}
}
else
{
Msg::Error("scheme %d has not been implemented",whatScheme);
}
}
else
{
// create multisystem and manager
pAssembler = new dofManagerMultiSystems();
dofManagerMultiSystems* allManager = static_cast<dofManagerMultiSystems*>(pAssembler);
for(int i=0;i<_vcompBySys.size();i++)
{
linearSystem<double> *lsys;
bool globalPos = true;
if(_vschemeBySys[i] == Explicit)
{
lsys = this->createExplicitSystem();
globalPos = false;
}
else
lsys = this->createSNLSystem();
nlsDofManager* currentAssembler = new staticDofManager(lsys,_vschemeBySys[i],globalPos,true);
allManager->add(currentAssembler,_vcompBySys[i]);
}
}
// initial time step
if(whatScheme==Explicit or whatScheme==Multi)
{
double timeStep = _explicitOpts.gammas * this->initialCriticalExplicitTimeStep();
#if defined(HAVE_MPI)
if(Msg::GetCommSize()>1){
// in case of mpi the time step is choosen as the minimal value compute on each partition
double mpiTimeStep;
MPI_Allreduce(&timeStep,&mpiTimeStep,1,MPI_DOUBLE,MPI_MIN,MPI_COMM_WORLD);
timeStep = mpiTimeStep;
}
#endif // HAVE_MPI
bool oneExplicitScheme=true;
if (whatScheme==Multi)
{
oneExplicitScheme = false;
for(int i=0;i<_vschemeBySys.size();i++)
{
if(_vschemeBySys[i]==Explicit)
{
oneExplicitScheme = true;
break;
}
}
}
if (oneExplicitScheme)
{
Msg::Info("initial time step: %e",timeStep);
pAssembler->setTimeStep(timeStep);
_timeManager->setTimeStep(timeStep);
}
}
}
int nonLinearMechSolver::NewtonRaphsonPathFollowing(const int numstep)
{
std::string name = "A";
linearSystem<double>* lsys =pAssembler->getLinearSystem(name);
nonLinearSystem<double>* nonsys = dynamic_cast<nonLinearSystem<double>*>(lsys);
pathFollowingSystem<double>* pathsys = dynamic_cast<pathFollowingSystem<double>*>(lsys);
if(computedUdF()){
_ipf->setDeformationGradientGradient(this->getMicroBC()->getSecondOrderKinematicalVariable(), IPStateBase::current);
_ipf->setValuesForBodyForce(IPStateBase::current);
}
// copy state from previous
//_ipf->copy(IPStateBase::previous,IPStateBase::current);
double normFinf= this->computeRightHandSide();
// loop until convergence
int iter=0;
double relnorm = 0.;
double norm0 = pAssembler->norm0Inf();
if (norm0 > 0) relnorm = normFinf/norm0;
double pfRef = pathsys->getPathFollowingConstraintRelativeRedidual();
Msg::Info("iteration n %d : residu : %e, absolute residu : %e norm0: %e pf residual: %e",iter,relnorm,normFinf,norm0,pfRef);
while (((relnorm>_tol) and (normFinf>_absTol)) or ((pfRef> _tol) and (pfRef> _absTol)) or (iter == 0)){
iter++;
// Compute Stiffness Matrix
this->computeStiffMatrix();
// Solve KDu = Fext-Fint
double t = Cpu();
int succeed = pAssembler->systemSolveIntReturn();
t = Cpu()-t;
if(!succeed)
{
iter = _timeManager->getMaxNbIterations();
break;
}
// update ipvariable
_ipf->compute1state(IPStateBase::current,true);
// update load
double loadParam = pathsys->getControlParameter();
double dloadParam = fabs(pathsys->getControlParameterStep());
this->oneStepPreSolve(loadParam,dloadParam,numstep);
if (!_iterativeNR) break;
// new forces
normFinf = this->computeRightHandSide();
if (norm0 == 0.) {
norm0 = pAssembler->norm0Inf();
}
// Check of convergence
relnorm = normFinf/norm0;
pfRef = pathsys->getPathFollowingConstraintRelativeRedidual();
Msg::Info("iteration n %d : residu : %e, absolute residu : %e pf residual: %e solving time: %f ", iter,relnorm,normFinf,pfRef,t);
if((iter == _timeManager->getMaxNbIterations()) or std::isnan(relnorm))
{
iter = _timeManager->getMaxNbIterations(); // for isnan case
break;
}
}
return iter;
};
double nonLinearMechSolver::solveSNL()
{
_timeManager->initializeTimeSteppingPlan(); // start time stepping plan
Msg::Info("Data : nstep =%d endtime=%f",_timeManager->getNumSteps(),_timeManager->getEndTime());
this->initializeStaticScheme(); // init everything
static std::string name = "A";
linearSystem<double>* lsys =pAssembler->getLinearSystem(name);
pathFollowingSystem<double>* pathsys = dynamic_cast<pathFollowingSystem<double>*>(lsys);
// if restart
if(restartManager::available() and !_resetRestart)
{
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
restartManager::openRestartFile("nonLinearMechSolver");
restartManager::restart(this);
// add restart other vars here if necessary
//
//
restartManager::closeRestartFile();
restartManager::InitFromRestartFile();
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
struct stat st;
if(stat("beforeRestart",&st) == 0)
{
std::ostringstream oss;
oss << _timeManager->getLastIterationIndex();
std::string cpDir="mv beforeRestart restart"+oss.str();
int oks = system(cpDir.c_str());
}
#if defined(HAVE_MPI)
if(Msg::GetCommSize()>1)
{ //we need to reinitializae after the restart of the nonLinearSolver
Msg::Info("MPI restart initialization begins");
pAssembler->systemMPIComm(); // To initiate the MPI Communication
Msg::Info("MPI restart initialization OK");
}
#endif // HAVE_MPI
}
if(restartManager::internalStateRestartAvailable())
{
loadInternalState(this->getRestartDomainTag());
// to debug the loading of internal state
// write the stress*.msh and disp*.msh files to check
// loaded values
/*
double DT = _timeManager->getTimeStep();
double CURtime = DT+_timeManager->getLastTime();
int NStep = _timeManager->getLastIterationIndex();
_ufield->archive(CURtime,NStep+1,false);
_ipf->archive(CURtime,NStep+1,false);
*/
}
_resetRestart=false;
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
while (!_timeManager->reachEndTime())
{
double endtime = _timeManager->getEndTime(); // endtime
double dt = _timeManager->getTimeStep(); // current timestep
double curtime = dt+_timeManager->getLastTime(); // current time = lastime + timeStep
int ii = _timeManager->getLastIterationIndex(); // last num step index
// set dofmananger and ipfield
pAssembler->setTimeStep(dt);
_ipf->setTime(curtime,dt,ii+1);
// start solving
Msg::Info("t= %e on %e (step = %d)",curtime,endtime,ii);
int niteNR = this->oneStaticStep(curtime,dt,ii+1);
// after solving
bool redoStepWithSelectiveUpdate = false;
bool willEnd = false;
if (niteNR < _timeManager->getMaxNbIterations())
{
// check for monitoring or selective update
if (!_ipf->isAllChecked() or (_endSchemeMonitoringObject!=NULL) or (_selectiveObject != NULL)){
_ipf->checkAll();
}
if (_selectiveObject != NULL){
_selectiveObject->checkSelectiveUpdate(this);
if (_selectiveObject->solverIterateBySelectiveUpdate()){
redoStepWithSelectiveUpdate = true;
}
}
if (_endSchemeMonitoringObject!=NULL ){
// check of end cr is satisfy
_endSchemeMonitoringObject->checkEnd(this);
willEnd = _endSchemeMonitoringObject->solverEndedByMornitoring();
if (!willEnd){
if (_endSchemeMonitoringObject->reduceTimeStepByMornitoring()){
Msg::Warning("reduce by monitoring");
niteNR = _timeManager->getMaxNbIterations();
}
}
}
}
if(niteNR >= _timeManager->getMaxNbIterations()) // time step reduction
{
// reduce time step for next solve
_timeManager->reduceTimeStep(); // solver fails counter in _timeManager is increased by 1
if (_pathFollowing)
{
_pfManager.reducePathFollowingStep(_timeManager);
}
// reset everything to previous step
pAssembler->resetUnknownsToPreviousTimeStep();
_ipf->copy(IPStateBase::previous,IPStateBase::current);
if (_selectiveObject != NULL)
{
_selectiveObject->resetToPreviousStep();
}
if (_endSchemeMonitoringObject!=NULL){
_endSchemeMonitoringObject->resetToPreviousStep();
}
//
if(_timeManager->getNbFails() > _timeManager->getMaxNbFails()) // end of simulation
{
Msg::Error("Simulation end due to convergence problem! Values are set to the last converged time step in case you want to switch to another scheme");
break;
}
else
{
Msg::Warning("Convergence of Newton-Raphson failed (%d fails on %d allowable fails) --> reduced time step",_timeManager->getNbFails(),_timeManager->getMaxNbFails());
}
}
else if (redoStepWithSelectiveUpdate)
{
// redo simulation without time change
Msg::Warning("redo solving with selective update");
_selectiveObject->selectiveUpdate(this);
}
else
{
if (_pathFollowing){
_pfManager.saveIncrementHistory(this);
}
// as simulation go wells
_timeManager->saveTimeHistory();
// for arching
this->oneStepPostSolve(curtime,ii+1);
// estimate time step for next solve
_timeManager->computeTimeStepForNextSolving(niteNR);
if (_pathFollowing)
{
_pfManager.computePathFollowingIncrementForNextSolving(this,niteNR,_timeManager);
}
if (willEnd)
{
Msg::Info("Computation is finished following _endSchemeMonitoring");
_endSchemeMonitoringObject->endSolverByMonitoring(true);
break;
}
}
}
saveInternalState(this->getRestartDomainTag());
/* end of scheme */
return this->finalizeStaticScheme(_timeManager->getLastTime(),_timeManager->getLastIterationIndex());
};
double nonLinearMechSolver::solveMulti()
{
_timeManager->initializeTimeSteppingPlan();
Msg::Info("Mixed static and dynamic solving: endtime=%e",_timeManager->getEndTime());
Msg::Info("Static Data: tolerance: %lf",_tol);
Msg::Info("Dynamic Data: beta=%f gamma=%f alpha_m=%f",_explicitOpts.beta, _explicitOpts.gamma, _explicitOpts.alpham);
/* init data */
this->init();
this->init2();
// iterative scheme (loop on timestep)
/* mass matrix computation outside the loop */
for(std::vector<partDomain*>::iterator it = domainVector.begin(); it!=domainVector.end(); ++it){
partDomain *dom = *it;
AssembleMass(dom->getBilinearMassTerm(),*(dom->getFunctionSpace()),dom->element_begin(),dom->element_end(),
*(dom->getBulkGaussIntegrationRule()),*pAssembler);
}
if(_notResetedContact){
for(nonLinearMechSolver::contactContainer::iterator itc = _allContact.begin(); itc!= _allContact.end(); ++itc){
contactDomain *cdom = *itc;
if(cdom->isRigid()){
rigidContactSpaceBase *rcsp = static_cast<rigidContactSpaceBase*>(cdom->getSpace());
AssembleMass(cdom->getMassTerm(),rcsp,pAssembler);
}
}
}
pAssembler->nextStep(); // save solution of previous (initially last step == initial step BEAWARE FOR RESTART)
//
bool forceTimeStepEvaluation=false;
if(restartManager::available() and !_resetRestart)
{
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
restartManager::openRestartFile("nonLinearMechSolver");
restartManager::restart(this);
//
//
restartManager::closeRestartFile();
restartManager::InitFromRestartFile();
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
struct stat st;
if(stat("beforeRestart",&st) == 0)
{
std::ostringstream oss;
oss << _timeManager->getLastIterationIndex();
std::string cpDir="mv beforeRestart restart"+oss.str();
int oks = system(cpDir.c_str());
}
#if defined(HAVE_MPI)
if(Msg::GetCommSize()>1)
{ //we need to reinitializae after the restart of the nonLinearSolver
Msg::Info("MPI restart initialization begins");
pAssembler->systemMPIComm(); // To initiate the MPI Communication
Msg::Info("MPI restart initialization OK");
}
#endif // HAVE_MPI
forceTimeStepEvaluation=true;
};
_resetRestart=false;
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
//
bool oneExplicitScheme=false;
for(int i=0;i<_vschemeBySys.size();i++)
{
if(_vschemeBySys[i]==Explicit)
{
oneExplicitScheme = true;
break;
}
}
double dt =0.; // shear during simulation
/* time loop */
while(!_timeManager->reachEndTime())
{
double endtime = _timeManager->getEndTime();
double lasttime = _timeManager->getLastTime();
int step = _timeManager->getLastIterationIndex();
// compute the time step (explicit limitation)
if(((step% _explicitOpts.numstepExpl ==0) || forceTimeStepEvaluation) && oneExplicitScheme)
{
dt = _explicitOpts.gammas * this->criticalExplicitTimeStep();
#if defined(HAVE_MPI)
if(Msg::GetCommSize()>1){
// in case of mpi the time step is choosen as the minimal value compute on each partition
double mpiTimeStep;
MPI_Allreduce(&dt,&mpiTimeStep,1,MPI_DOUBLE,MPI_MIN,MPI_COMM_WORLD);
dt = mpiTimeStep;
}
#endif // HAVE_MPI
Msg::Info("explicit time step value: %e at time %e",dt,lasttime);
pAssembler->setTimeStep(dt);
_timeManager->setTimeStep(dt);
forceTimeStepEvaluation = false;
}
else if(!oneExplicitScheme)
{
dt = _timeManager->getTimeStep();
pAssembler->setTimeStep(dt);
Msg::Info("implicit time step value: %e at time %e",dt,lasttime);
}
//
double curtime = lasttime+dt;
if(curtime > endtime)
{
curtime = endtime;
dt = curtime-lasttime;
pAssembler->setTimeStep(dt);
_timeManager->setTimeStep(dt);
};
this->oneStepPreSolve(curtime,dt,step+1);
// Solve one step by NR scheme
int niteNR=0;
if((step>0 && (step%_explicitOpts.numstepImpl==0)) or !oneExplicitScheme)
{
// not solve if step = 0, to make sure if explicit solver present, it starts first
Msg::Info("Solve implicit system(s): step = %d, t = %e, dt = %e",step,curtime,dt);
double tsystresol = Cpu();
niteNR = NewtonRaphson(step+1);
tsystresol = Cpu() - tsystresol;
Msg::Info("Time of Newton-Raphson resolution: %f: ",tsystresol);
if(niteNR >= _timeManager->getMaxNbIterations()) // time step reduction
{
if (!oneExplicitScheme) // if no explicit, time step reduce as normal
{
// reduce time step for next solve
_timeManager->reduceTimeStep(); // solver fails counter in _timeManager is increased by 1
// reset everything to previous step
pAssembler->resetUnknownsToPreviousTimeStep();
_ipf->copy(IPStateBase::previous,IPStateBase::current);
if(_timeManager->getNbFails() > _timeManager->getMaxNbFails()) // end of simulation
{
Msg::Error("Simulation end due to convergence problem! Values are set to the last converged time step in case you want to switch to another scheme");
break;
}
else
{
Msg::Warning("Convergence of Newton-Raphson failed (%d fails on %d allowable fails) --> reduced time step",_timeManager->getNbFails(),_timeManager->getMaxNbFails());
}
}
else
{
Msg::Error("Simulation end due to convergence problem! Values are set to the last converged time step in case you want to switch to another scheme");
break;
}
}
else if(niteNR!=0)
{
_timeManager->saveTimeHistory();
this->oneStepPostSolve(curtime,step+1);
if (!oneExplicitScheme)
{
// time step is adapted if no explict
_timeManager->computeTimeStepForNextSolving(niteNR);
}
}
}
if(niteNR==0) // no Implicit computation or no force on the implicit systems
{
// solve only the Explicit scheme
int globalsuc = 0;
for(int i=0;i<_vschemeBySys.size();i++)
{
nlsDofManager *nlass = pAssembler->getManager(i);
if(nlass->getScheme()==Explicit)
globalsuc = nlass->systemSolveIntReturn();
}
if(globalsuc){ // otherwise no resolution (QS scheme only with no forces) !!
// compute the new forces
_ipf->compute1state(IPStateBase::current,false);
double normRHS = this->computeRightHandSide();
if(std::isnan(normRHS))
{
Msg::Error("Nan force value --> end");
break;
}
if(_explicitOpts.dynamicRelaxation)
{
double norm0 = pAssembler->norm0Inf();
if(step%_explicitOpts.numstepExpl ==0 ) Msg::Info("Rel norm for dynamic relaxation %e tol = %e",normRHS/norm0,_tol);
if(normRHS/norm0 < _tol){
Msg::Info("Dynamic relaxation procedure is achieved");
break;
}
if(curtime == _timeManager->getEndTime())
Msg::Info("Dynamic relaxation ended as the final time is reached. But convergence is not achieved!");
}
}
_timeManager->saveTimeHistory();
this->oneStepPostSolve(curtime,step+1);
}
}
/* end of scheme */
this->endOfScheme(_timeManager->getLastTime(),_timeManager->getLastIterationIndex());
Msg::Info("Multi OK");
return _timeManager->getLastTime();
}
void nonLinearMechSolver::unknownBuildView(const int comp,const int nbstep)
{
int nstep_;
nsba==0 ? nstep_ = nbstep : nstep_=nsba;
switch(comp){
case 1:
unknownView.emplace_back("velocity",1,nlsField::crude,0,nlsField::val, nstep_);
break;
case 2:
unknownView.emplace_back("acceleration",2,nlsField::crude,0,nlsField::val,nstep_);
break;
default:
unknownView.emplace_back("displacement",0,nlsField::crude,0,nlsField::val,nstep_);
}
}
void nonLinearMechSolver::OneUnknownBuildView(const std::string vname, const int comp,const int nbstep)
{
int nstep_;
nsba==0 ? nstep_ = nbstep : nstep_=nsba;
int unknownComp = -1 - comp;
unknownView.emplace_back(vname,unknownComp,nlsField::crude,0,nlsField::val,nstep_);
};
void nonLinearMechSolver::internalPointBuildView(const std::string vname,const int comp,
const int nbstep,const int ev, const int gp)
{
nlsField::ElemValue ev_;
switch(ev){
case 0:
ev_ = nlsField::crude;
break;
case 1:
ev_ = nlsField::mean;
break;
case 2 :
ev_ = nlsField::min;
break;
case 3 :
ev_ = nlsField::max;
break;
default:
ev_ = nlsField::mean;
}
int nstep_;
nsba==0 ? nstep_ = nbstep : nstep_=nsba;
ipView.emplace_back(vname,comp,ev_,gp,nlsField::val,nstep_);
}
void nonLinearMechSolver::internalPointBuildViewInterface(const std::string vname,const int comp,
const int nbstep,const int ev, const int gp)
{
nlsField::ElemValue ev_;
switch(ev){
case 0:
ev_ = nlsField::crude;
break;
case 1:
ev_ = nlsField::mean;
break;
case 2 :
ev_ = nlsField::min;
break;
case 3 :
ev_ = nlsField::max;
break;
default:
ev_ = nlsField::mean;
}
int nstep_;
nsba==0 ? nstep_ = nbstep : nstep_=nsba;
ipViewInterface.emplace_back(vname,comp,ev_,gp,nlsField::val,nstep_);
}
void nonLinearMechSolver::internalPointBuildViewIncrement(const std::string vname,const int comp,
const int nbstep,const int ev,const int gp)
{
nlsField::ElemValue ev_;
switch(ev){
case 0:
ev_ = nlsField::crude;
break;
case 1:
ev_ = nlsField::mean;
break;
case 2 :
ev_ = nlsField::min;
break;
case 3 :
ev_ = nlsField::max;
break;
default:
ev_ = nlsField::mean;
}
int nstep_;
nsba==0 ? nstep_ = nbstep : nstep_=nsba;
ipView.emplace_back("Increment_"+vname,comp,ev_,gp,nlsField::increment,nstep_);
}
void nonLinearMechSolver::internalPointBuildViewRate(const std::string vname,const int comp,
const int nbstep,const int ev, const int gp)
{
nlsField::ElemValue ev_;
switch(ev){
case 0:
ev_ = nlsField::crude;
break;
case 1:
ev_ = nlsField::mean;
break;
case 2 :
ev_ = nlsField::min;
break;
case 3 :
ev_ = nlsField::max;
break;
default:
ev_ = nlsField::mean;
}
int nstep_;
nsba==0 ? nstep_ = nbstep : nstep_=nsba;
ipView.emplace_back("Rate_"+vname,comp,ev_,gp,nlsField::rate,nstep_);
}
void nonLinearMechSolver::energyBuildView(const std::string vname,const int comp,const int nbstep)
{
int nstep_;
nsba==0 ? nstep_ = nbstep : nstep_=nsba;
switch(comp){
case 1:
energyView.emplace_back("kinetic",1,nlsField::crude,0,nlsField::val,nstep_);
break;
case 2:
energyView.emplace_back("deformation",2,nlsField::crude,0,nlsField::val,nstep_);
break;
case 3:
energyView.emplace_back("external work",3,nlsField::crude,0,nlsField::val,nstep_);
break;
default:
energyView.emplace_back("total",4,nlsField::crude,0,nlsField::val,nstep_);
}
}
void nonLinearMechSolver::internalPointBuildViewShell(int loc, const std::string vname,const int comp,
const int nbstep,const int ev, const int gp)
{
nlsField::ElemValue ev_;
switch(ev){
case 0:
ev_ = nlsField::crude;
break;
case 1:
ev_ = nlsField::mean;
break;
case 2 :
ev_ = nlsField::min;
break;
case 3 :
ev_ = nlsField::max;
break;
default:
ev_ = nlsField::mean;
}
int nstep_;
nsba==0 ? nstep_ = nbstep : nstep_=nsba;
ipView.emplace_back(vname,comp,ev_,gp,nlsField::val,nstep_,loc);
}
void nonLinearMechSolver::internalPointBuildViewIncrementShell(int loc, const std::string vname,const int comp,
const int nbstep,const int ev,const int gp)
{
nlsField::ElemValue ev_;
switch(ev){
case 0:
ev_ = nlsField::crude;
break;
case 1:
ev_ = nlsField::mean;
break;
case 2 :
ev_ = nlsField::min;
break;
case 3 :
ev_ = nlsField::max;
break;
default:
ev_ = nlsField::mean;
}
int nstep_;
nsba==0 ? nstep_ = nbstep : nstep_=nsba;
ipView.emplace_back("Increment_"+vname,comp,ev_,gp,nlsField::increment,nstep_,loc);
}
void nonLinearMechSolver::internalPointBuildViewRateShell(int loc, const std::string vname,const int comp,
const int nbstep,const int ev, const int gp)
{
nlsField::ElemValue ev_;
switch(ev){
case 0:
ev_ = nlsField::crude;
break;
case 1:
ev_ = nlsField::mean;
break;
case 2 :
ev_ = nlsField::min;
break;
case 3 :
ev_ = nlsField::max;
break;
default:
ev_ = nlsField::mean;
}
int nstep_;
nsba==0 ? nstep_ = nbstep : nstep_=nsba;
ipView.emplace_back("Rate_"+vname,comp,ev_,gp,nlsField::rate,nstep_,loc);
}
void nonLinearMechSolver::energyComputation(const int val)
{
_energyComputation=val;
}
void nonLinearMechSolver::fractureEnergy(const int val)
{
_fractureEnergyComputation=val;
}
void nonLinearMechSolver::fillConstraintDof()
{
//for(nonLinearConstraintBC& cbc : allConstraint)
for(std::list<nonLinearConstraintBC>::iterator cbc=allConstraint.begin(); cbc!=allConstraint.end(); cbc++)
{
cbc->constraintDofs.clear();
std::vector<MVertex*> vv;
int dim=0;
switch(cbc->onWhat){
case nonLinearBoundaryCondition::ON_VERTEX:
dim = 0;
break;
case nonLinearBoundaryCondition::ON_EDGE:
dim = 1;
break;
case nonLinearBoundaryCondition::ON_FACE:
dim = 2;
break;
case nonLinearBoundaryCondition::ON_VOLUME:
dim = 3;
break;
}
pModel->getMeshVerticesForPhysicalGroup(dim,cbc->_tag,vv);
// loop on domain (to find the domain where the force is applied)
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain *dom = *itdom;
FunctionSpaceBase *sp = dom->getFunctionSpace();
std::vector<Dof> R;
if(!(dom->getFormulation())){ // Cg/Dg
FilterDof* filter = dom->createFilterDof(cbc->_comp);
for(elementGroup::vertexContainer::const_iterator itv=dom->vertex_begin(); itv!=dom->vertex_end(); ++itv){
MVertex *ver = itv->second;
for(std::vector<MVertex*>::iterator it=vv.begin(); it!=vv.end(); ++it){
MVertex *vver = *it;
if(ver == vver){
MPoint ele(ver);
// build the dof
R.clear();
sp->getKeys(&ele,R);
for(int j=0;j<R.size(); j++)
if(filter->operator()(R[j]))
cbc->constraintDofs.push_back(R[j]);
break;
}
}
}
delete filter;
}
else{ // full Dg
for(elementGroup::elementContainer::const_iterator ite = dom->element_begin(); ite!=dom->element_end(); ++ite){
MElement *ele = ite->second;
int nbvertex = ele->getNumVertices();
sp->getKeys(ele,R);
for(std::vector<MVertex*>::iterator it=vv.begin(); it!=vv.end(); ++it){
for(int j=0;j<nbvertex; j++){
if(ele->getVertex(j) == *it){
cbc->constraintDofs.push_back(R[j+nbvertex*cbc->_comp]);
break;
}
}
}
R.clear();
}
}
}
cbc->constraintDofs.unique();
}
};
void nonLinearMechSolver::applyConstraintBC()
{
//for(const nonLinearConstraintBC& cbc: allConstraint){
for(std::list<nonLinearConstraintBC>::const_iterator cbc=allConstraint.begin(); cbc!=allConstraint.end(); cbc++){
for (std::list<Dof>::const_iterator it =cbc->constraintDofs.begin(); it != cbc->constraintDofs.end(); it++)
{
if (it!=cbc->constraintDofs.begin())
{
DofAffineConstraint<double> cons;
cons.linear.push_back(std::pair<Dof,double>(*(cbc->constraintDofs.begin()),1));
cons.shift=0;
pAssembler->setLinearConstraint(*it,cons);
cons.linear.clear();
}
};
}
};
void nonLinearMechSolver::initCornerBC(){
if (!_testFlag) {
Msg::Warning("fix corner Dof is only used for microscopic test only");
return;
}
if (_pbcGroup != NULL){
for(std::list<nonLinearDirichletBCAtCorner>::iterator cbc=allCornerConstraint.begin(); cbc!=allCornerConstraint.end(); cbc++){
std::vector<Dof>& allDof = cbc->constraintDofs;
std::vector<Dof> R;
MVertex* v = _pbcGroup->getCornerVertex(cbc->_cornerNumber);
_pbcGroup->getDofsOfCornerVertex(cbc->_cornerNumber,R);
allDof.push_back(R[cbc->_comp]);
double val = cbc->_f->operator()(v->x(),v->y(),v->z());
pAssembler->fixDof(R[cbc->_comp],val);
}
for(std::list<nonLinearNeumannBCAtCorner>::iterator cbc=allCornerForce.begin(); cbc!=allCornerForce.end(); cbc++){
std::vector<Dof>& allDof = cbc->constraintDofs;
std::vector<Dof> R;
MVertex* v = _pbcGroup->getCornerVertex(cbc->_cornerNumber);
_pbcGroup->getDofsOfCornerVertex(cbc->_cornerNumber,R);
allDof.push_back(R[cbc->_comp]);
}
}
};
void nonLinearMechSolver::fixDofCorner(){
if (!_testFlag) {
Msg::Warning("fix corner Dof is only used for microscopic test only");
return;
}
if (_pbcGroup != NULL){
for(std::list<nonLinearDirichletBCAtCorner>::const_iterator cbc=allCornerConstraint.begin(); cbc!=allCornerConstraint.end(); cbc++){
const std::vector<Dof>& allDof = cbc->constraintDofs;
MVertex* v = _pbcGroup->getCornerVertex(cbc->_cornerNumber);
for (int i=0; i< allDof.size(); i++){
double val = cbc->_f->operator()(v->x(),v->y(),v->z());
pAssembler->fixDof(allDof[i],val);
}
}
}
};
void nonLinearMechSolver::applyLinearConstraintBetweenTwoGroups()
{
if (isDgDomain())
{
if (allLinearConstraintBC.size() > 0)
{
Msg::Error("linear constraint BC between two groups is not implemented");
Msg::Exit(0);
}
}
else
{
FunctionSpaceBase* sp = domainVector[0]->getFunctionSpace();
for (std::list<nonLinearLinearConstraintBCBetweenTwoGroups>::iterator itbc=allLinearConstraintBC.begin(); itbc!=allLinearConstraintBC.end(); itbc++)
{
nonLinearLinearConstraintBCBetweenTwoGroups& bc = *itbc;
const linearCombinationOfVertices* rh = bc.rightHandSide;
const setInt& excludeVertices = bc.excludedVertices;
double factNeg = bc.slaveFactor;
// get right hand side term
std::vector<int> comp(1,bc.comp);
std::vector<std::pair<Dof,double> > Rroot;
for (std::map<MVertex*,std::pair<int,double> >::const_iterator itvroot = rh->combinationV.begin(); itvroot != rh->combinationV.end(); itvroot++)
{
MVertex* vr = itvroot->first;
const std::pair<int,double>& compFact = itvroot->second;
//
std::vector<Dof> R;
std::vector<int> compR(1,compFact.first);
getKeysFromVertex(sp,vr,compR,R);
Rroot.push_back(std::pair<Dof,double>(R[0],compFact.second));
}
for (elementGroup::vertexContainer::const_iterator itvmaster = bc.gMaster->vbegin(); itvmaster != bc.gMaster->vend(); itvmaster++)
{
MVertex* vmaster = itvmaster->second;
if (rh->combinationV.find(vmaster) == rh->combinationV.end() and !(excludeVertices.included(vmaster->getNum())))
{
SPoint3 pp;
bc.vgOperation->apply(vmaster,pp);
MElement* eleSlave = NULL;
for (elementGroup::elementContainer::const_iterator ite = bc.gSlave->begin(); ite != bc.gSlave->end(); ite++)
{
MElement* es = ite->second;
if (es->getDim() == 0)
{
eleSlave = es;
}
else if (isInside(pp,es)){
eleSlave = es;
Msg::Info("found slave element %d for vertex %d",eleSlave->getNum(),vmaster->getNum());
break;
}
}
std::vector<MVertex*> vv;
int size = 0;
std::vector<double> fVal;
if (eleSlave != NULL)
{
SPoint3 point;
size = eleSlave->getNumVertices();
eleSlave->getVertices(vv);
if (eleSlave->getDim() == 0)
{
point = vv[0]->point();
}
else if (eleSlave->getDim() == 1)
{
point = project(pp,vv[0]->point(),vv[1]->point());
}
else if (eleSlave->getDim() == 2)
{
point = project(pp,vv[0]->point(),vv[1]->point(),vv[2]->point());
};
double xyz[3]={point[0],point[1],point[2]};
double uvw[3];
eleSlave->xyz2uvw(xyz,uvw);
fVal.resize(size);
eleSlave->getShapeFunctions(uvw[0],uvw[1],uvw[2],&fVal[0]);
}
std::vector<Dof> RMaster, RSlave;
getKeysFromVertex(sp,vmaster,comp,RMaster);
for (int iv=0; iv < size; iv++)
{
getKeysFromVertex(sp,vv[iv],comp,RSlave);
}
if (!pAssembler->isConstrained(RMaster[0]) and !pAssembler->isFixed(RMaster[0]))
{
DofAffineConstraint<double> cons;
cons.shift = 0.;
for (int ivf=0; ivf< size; ivf++)
{
cons.linear.push_back(std::pair<Dof,double>(RSlave[ivf],factNeg*fVal[ivf]));
}
for (int ivf = 0; ivf < Rroot.size(); ivf++)
{
cons.linear.push_back(Rroot[ivf]);
}
pAssembler->setLinearConstraint(RMaster[0],cons);
}
}
}
}
}
};
void nonLinearMechSolver::applyPBCBetweenTwoGroups()
{
std::set<MVertex*> edgeVertices;
std::set<MVertex*> cornerVertices;
if (allPeriodic.size() > 0)
{
for (int i=0; i< _edgePeriodicPhysicals.size(); i++)
{
elementGroup gr(1,_edgePeriodicPhysicals[i]);
for (elementGroup::vertexContainer::const_iterator it = gr.vbegin(); it != gr.vend(); it++)
{
edgeVertices.insert(it->second);
}
}
for (int i=0; i< _nodePeriodicPhysicals.size(); i++)
{
elementGroup gr(0,_nodePeriodicPhysicals[i]);
for (elementGroup::vertexContainer::const_iterator it = gr.vbegin(); it != gr.vend(); it++)
{
cornerVertices.insert(it->second);
}
}
}
// create pbcmap
if (isDgDomain())
{
// apply constraint
if (allPeriodic.size() > 0)
{
Msg::Info("begin accounting PBC rank %d",Msg::GetCommRank());
}
for (std::list<nonLinearPeriodicBCBetweenTwoGroups>::iterator pbctg=allPeriodic.begin(); pbctg!=allPeriodic.end(); pbctg++)
{
nonLinearPeriodicBCBetweenTwoGroups& bc = *pbctg;
elementGroup* gMaster = bc.g2;
elementGroup* gSlave = bc.g1;
MVertex* vRootMaster = bc.v2;
MVertex* vRootSlave = bc.v1;
auto checkConsider = [&bc, &vRootMaster, &vRootSlave, &edgeVertices, &cornerVertices](MVertex* vMaster)
{
if ((vRootMaster != NULL) && (vRootSlave !=NULL))
{
if (vMaster->getNum() == vRootMaster->getNum())
{
return false;
}
}
//
if (bc.onWhat == nonLinearBoundaryCondition::ON_FACE)
{
if (edgeVertices.find(vMaster) != edgeVertices.end())
{
return false;
}
}
else if (bc.onWhat == nonLinearBoundaryCondition::ON_EDGE)
{
if (cornerVertices.find(vMaster) != cornerVertices.end())
{
return false;
}
}
return true;
};
std::set<pbcElement*> allSlaveElements;
pbcElement::createPBCElements(*gSlave,domainVector,allSlaveElements);
for (elementGroup::elementContainer::const_iterator itg = gMaster->begin(); itg != gMaster->end(); itg++)
{
MElement* eleMaster = itg->second;
SPoint3 masterBaryCenter = eleMaster->barycenter();
//
// projection element is first found if periodic meshes are used
std::set<pbcElement*>::iterator foundSlaveIt = allSlaveElements.begin();
pbcElement* closestSlave = *(foundSlaveIt);
double length = masterBaryCenter.distance(closestSlave->getSubElement()->barycenter());
// find closest bary center as slave element
std::set<pbcElement*>::iterator slaveIt = foundSlaveIt;
slaveIt++;
for (slaveIt; slaveIt != allSlaveElements.end(); slaveIt++)
{
pbcElement* es = *slaveIt;
double lengthtemp = masterBaryCenter.distance(es->getSubElement()->barycenter());
if (lengthtemp < length){
closestSlave = es;
length = lengthtemp;
foundSlaveIt = slaveIt;
};
}
// check if two elements are fitted
auto checkFittingElements = [&bc, &length](MElement* eleMaster, MElement* eleclosest)
{
if (bc.onWhat == nonLinearBoundaryCondition::ON_VERTEX)
{
return true;
}
if (eleMaster->getNumPrimaryVertices() != eleclosest->getNumPrimaryVertices())
{
return false;
}
int N = eleMaster->getNumPrimaryVertices();
std::vector<MVertex*> allVerticesMaster(N,NULL);
std::vector<MVertex*> allVerticesClosest(N,NULL);
for (int iv=0; iv< N; iv++)
{
allVerticesMaster[iv] = eleMaster->getVertex(iv);
allVerticesClosest[iv] = eleclosest->getVertex(iv);
}
fullVector<double> distanceTwoVer(N);
for (int iv=0; iv< N; iv++)
{
auto findNearestVertex = [&allVerticesClosest](MVertex* vp)
{
MVertex* vinit = allVerticesClosest[0];
double dist=vinit->distance(vp);
for (int j=1; j< allVerticesClosest.size(); j++)
{
MVertex* v=allVerticesClosest[j];
double tempDist=v->distance(vp);
if (tempDist<dist)
{
dist=tempDist;
vinit=v;
};
};
return vinit;
};
MVertex* temp = findNearestVertex(allVerticesMaster[iv]);
distanceTwoVer(iv) = temp->distance(allVerticesMaster[iv]) - length;
};
if (distanceTwoVer.norm() < 1e-4*length)
{
//Msg::Info("found two pbc elements master %d slave %d",eleMaster->getNum(),eleclosest->getNum());
return true;
}
else
{
return false;
}
return false;
};
pbcElement* pbcElementSlave = NULL;
if (checkFittingElements(eleMaster,closestSlave->getSubElement()))
{
pbcElementSlave = closestSlave;
}
//
for (int iv =0; iv < eleMaster->getNumVertices(); iv ++)
{
MVertex* vMaster = eleMaster->getVertex(iv);
if (checkConsider(vMaster))
{
std::vector<pbcVertex*> allMasterVertices;
pbcVertex::createPBCVertices(vMaster,domainVector,allMasterVertices);
for (int ic=0; ic< allMasterVertices.size(); ic++)
{
// find negative in allSlaveElements
pbcVertex* pbcVertexMaster = allMasterVertices[ic];
if (pbcElementSlave == NULL)
{
if (bc.onWhat == nonLinearBoundaryCondition::ON_VERTEX)
{
pbcElementSlave = *(allSlaveElements.begin());
}
else
{
for (std::set<pbcElement*>::const_iterator ite = allSlaveElements.begin(); ite != allSlaveElements.end(); ite++)
{
pbcElement* es = *ite;
if (InterpolationOperations::isInside(pbcVertexMaster->getVertex(),es->getSubElement()))
{
pbcElementSlave = es;
break;
}
}
}
}
//
if (pbcElementSlave == NULL)
{
Msg::Error("slave element is not found nonLinearMechSolver::nonLinearPeriodicBCBetweenTwoGroups");
}
else
{
MElement* eleSlave = pbcElementSlave->getSubElement();
SPoint3 point;
std::vector<MVertex*> vv;
int size = eleSlave->getNumVertices();
eleSlave->getVertices(vv);
SPoint3 pp = vMaster->point();
if (eleSlave->getDim() == 0){
point = vv[0]->point();
}
else if (eleSlave->getDim() == 1){
point = project(pp,vv[0]->point(),vv[1]->point());
}
else if (eleSlave->getDim() == 2){
point = project(pp,vv[0]->point(),vv[1]->point(),vv[2]->point());
};
double xyz[3]={point[0],point[1],point[2]};
double uvw[3];
eleSlave->xyz2uvw(xyz,uvw);
double fVal[size];
eleSlave->getShapeFunctions(uvw[0],uvw[1],uvw[2],fVal);
//
std::vector<Dof> keyRootMaster, keyRootSlave;
if ((vRootMaster != NULL) && (vRootSlave != NULL))
{
// find space for master and slave domain
std::vector<pbcVertex*> vRootMasterPBC;
std::vector<pbcVertex*> vRootSlavePBC;
pbcVertex::createPBCVertices(vRootMaster,domainVector,vRootMasterPBC);
pbcVertex::createPBCVertices(vRootSlave,domainVector,vRootSlavePBC);
vRootMasterPBC[0]->getKeys(bc.comp,keyRootMaster);
vRootSlavePBC[0]->getKeys(bc.comp,keyRootSlave);
}
//
std::vector<Dof> RMaster;
pbcVertexMaster->getKeys(bc.comp,RMaster);
for (int icomp =0; icomp < bc.comp.size(); icomp++)
{
std::vector<int> comp(1, bc.comp[icomp]);
std::vector<Dof> RSlave;
pbcElementSlave->getKeys(comp,RSlave);
if (!pAssembler->isConstrained(RMaster[icomp]) and !pAssembler->isFixed(RMaster[icomp]))
{
DofAffineConstraint<double> cons;
cons.shift = 0.;
for (int ivf=0; ivf< size; ivf++){
cons.linear.push_back(std::pair<Dof,double>(RSlave[ivf],fVal[ivf]));
}
if ((vRootMaster != NULL) && (vRootSlave !=NULL))
{
cons.linear.push_back(std::pair<Dof,double>(keyRootMaster[icomp],1.));
cons.linear.push_back(std::pair<Dof,double>(keyRootSlave[icomp],-1.));
}
pAssembler->setLinearConstraint(RMaster[icomp],cons);
}
}
}
//
}
}
}
}
}
if (allPeriodic.size() > 0)
Msg::Info("end accounting PBC");
for (std::list<nonLinearAveragePeriodicBCBetweenTwoGroups>::iterator itpbc = allAveragePeriodic.begin(); itpbc != allAveragePeriodic.end(); itpbc++)
{
nonLinearAveragePeriodicBCBetweenTwoGroups& pbc = *itpbc;
Msg::Error("nonLinearAveragePeriodicBCBetweenTwoGroups has not been implemented for fullDG case");
break;
}
}
else
{
// apply constraint
if (allPeriodic.size() > 0)
Msg::Info("begin accounting PBC rank %d",Msg::GetCommRank());
std::map<MVertex*,partDomain*> vertexDomainMap;
std::map<MElement*, partDomain*> boundElementDomainMap;
auto getVertexDomain =[&vertexDomainMap] (std::vector<partDomain*>& allDom, MVertex* v)
{
std::map<MVertex*,partDomain*>::iterator itF = vertexDomainMap.find(v);
if (itF != vertexDomainMap.end()) return itF->second;
partDomain* foundDom = NULL;
for (int idom =0; idom < allDom.size(); idom++)
{
partDomain* dom = allDom[idom];
if (dom->g_vfind(v))
{
foundDom = dom;
vertexDomainMap[v] = dom;
return foundDom;
}
}
return foundDom;
};
auto getBoundElementDomain = [&boundElementDomainMap](std::vector<partDomain*>& allDom, MElement* ele)
{
std::map<MElement*, partDomain*>::iterator itF = boundElementDomainMap.find(ele);
if (itF != boundElementDomainMap.end()) return itF->second;
partDomain* foundDom = NULL;
for (int idom =0; idom < allDom.size(); idom++)
{
partDomain* dom = allDom[idom];
for (elementGroup::elementContainer::const_iterator itedom = dom->element_begin(); itedom != dom->element_end(); itedom++)
{
if (checkInterfaceElementBelongToBulkElement(ele,itedom->second))
{
foundDom = dom;
boundElementDomainMap[ele] = dom;
return foundDom;
}
}
}
return foundDom;
};
for (std::list<nonLinearPeriodicBCBetweenTwoGroups>::iterator pbctg=allPeriodic.begin(); pbctg!=allPeriodic.end(); pbctg++)
{
nonLinearPeriodicBCBetweenTwoGroups& bc = *pbctg;
elementGroup* gMaster = bc.g2;
elementGroup* gSlave = bc.g1;
MVertex* vRootMaster = bc.v2;
MVertex* vRootSlave = bc.v1;
//
partDomain* vRootMasterDom = NULL;
partDomain* vRootSlaveDom = NULL;
if ((vRootMaster != NULL) && (vRootSlave !=NULL))
{
vRootMasterDom = getVertexDomain(domainVector,vRootMaster);
vRootSlaveDom = getVertexDomain(domainVector,vRootSlave);
}
for (elementGroup::vertexContainer::const_iterator itvm = gMaster->vbegin(); itvm != gMaster->vend(); itvm++)
{
MVertex* vMaster = itvm->second;
bool willConsider = true;
if ((vRootMaster != NULL) && (vRootSlave !=NULL))
{
if (vMaster->getNum() == vRootMaster->getNum())
{
willConsider = false;
}
}
//
if (willConsider)
{
if (bc.onWhat == nonLinearBoundaryCondition::ON_FACE)
{
if (edgeVertices.find(vMaster) != edgeVertices.end())
{
willConsider = false;
}
}
else if (bc.onWhat == nonLinearBoundaryCondition::ON_EDGE)
{
if (cornerVertices.find(vMaster) != cornerVertices.end())
{
willConsider = false;
}
}
}
if (willConsider)
{
MElement* eleSlave = NULL;
if (bc.onWhat == nonLinearBoundaryCondition::ON_VERTEX)
{
eleSlave = NULL;
if (gSlave->size() > 0)
{
eleSlave = gSlave->begin()->second;
}
}
else
{
for (elementGroup::elementContainer::const_iterator ite = gSlave->begin(); ite != gSlave->end(); ite++)
{
MElement* es = ite->second;
if (InterpolationOperations::isInside(vMaster,es))
{
eleSlave = es;
break;
}
}
}
if (eleSlave == NULL)
{
Msg::Error("slave element is not found nonLinearMechSolver::nonLinearPeriodicBCBetweenTwoGroups between %d %d",bc.phys1,bc.phys2);
}
else
{
SPoint3 point;
std::vector<MVertex*> vv;
int size = eleSlave->getNumVertices();
eleSlave->getVertices(vv);
SPoint3 pp = vMaster->point();
if (eleSlave->getDim() == 0){
point = vv[0]->point();
}
else if (eleSlave->getDim() == 1){
point = project(pp,vv[0]->point(),vv[1]->point());
}
else if (eleSlave->getDim() == 2){
point = project(pp,vv[0]->point(),vv[1]->point(),vv[2]->point());
};
double xyz[3]={point[0],point[1],point[2]};
double uvw[3];
eleSlave->xyz2uvw(xyz,uvw);
double fVal[size];
eleSlave->getShapeFunctions(uvw[0],uvw[1],uvw[2],fVal);
// find space for master and slave domain
partDomain* masterDom = getVertexDomain(domainVector,vMaster);
partDomain* slaveDom = getBoundElementDomain(domainVector,eleSlave);
std::vector<Dof> keyRootMaster, keyRootSlave;
if ((vRootMaster != NULL) && (vRootSlave != NULL))
{
getKeysFromVertex(vRootMasterDom->getFunctionSpace(),vRootMaster,bc.comp,keyRootMaster);
getKeysFromVertex(vRootSlaveDom->getFunctionSpace(),vRootSlave,bc.comp,keyRootSlave);
}
//
std::vector<Dof> RMaster;
getKeysFromVertex(masterDom->getFunctionSpace(),vMaster,bc.comp,RMaster);
for (int icomp =0; icomp < bc.comp.size(); icomp++)
{
std::vector<int> comp(1, bc.comp[icomp]);
std::vector<Dof> RSlave;
for (int iv=0; iv < size; iv++)
{
getKeysFromVertex(slaveDom->getFunctionSpace(),vv[iv],comp,RSlave);
}
if (!pAssembler->isConstrained(RMaster[icomp]) and !pAssembler->isFixed(RMaster[icomp]))
{
DofAffineConstraint<double> cons;
cons.shift = 0.;
for (int ivf=0; ivf< size; ivf++){
cons.linear.push_back(std::pair<Dof,double>(RSlave[ivf],fVal[ivf]));
}
if ((vRootMaster != NULL) && (vRootSlave !=NULL))
{
cons.linear.push_back(std::pair<Dof,double>(keyRootMaster[icomp],1.));
cons.linear.push_back(std::pair<Dof,double>(keyRootSlave[icomp],-1.));
}
pAssembler->setLinearConstraint(RMaster[icomp],cons);
}
}
}
}
};
};
if (allPeriodic.size() > 0)
Msg::Info("end accounting PBC");
// for all average PBC
if (allAveragePeriodic.size() > 0)
Msg::Info("begin accounting average PBC rank %d",Msg::GetCommRank());
//
for (std::list<nonLinearAveragePeriodicBCBetweenTwoGroups>::iterator itpbc = allAveragePeriodic.begin(); itpbc != allAveragePeriodic.end(); itpbc++)
{
nonLinearAveragePeriodicBCBetweenTwoGroups& pbc = *itpbc;
elementGroup* gMaster = pbc.g2;
elementGroup* gSlave = pbc.g1;
MVertex* vRootMaster = pbc.v2;
MVertex* vRootSlave = pbc.v1;
std::vector<MVertex*> vecMaster, vecSlave;
fullVector<double> weightMaster, weightSlave;
supplementConstraint::computeWeight(gMaster,vecMaster,weightMaster);
supplementConstraint::computeWeight(gSlave,vecSlave,weightSlave);
int sizeDofMaster = vecMaster.size();
int sizeDofSlave = vecSlave.size();
fullVector<double> weight;
if ((vRootMaster != NULL) && (vRootSlave != NULL))
{
weight.resize(sizeDofMaster+sizeDofSlave+2,true);
weight(sizeDofMaster+sizeDofSlave) = -1.;
weight(sizeDofMaster+sizeDofSlave+1) = 1.;
}
else
{
weight.resize(sizeDofMaster+sizeDofSlave,true);
}
for (int i=0; i< sizeDofMaster; i++){
weight(i) = weightMaster(i);
}
for (int i=0; i< sizeDofSlave; i++){
weight(i+sizeDofMaster) = -weightSlave(i);
}
for (int icomp =0; icomp < pbc.comp.size(); icomp ++)
{
std::vector<int> comp(1,pbc.comp[icomp]);
std::vector<Dof> allDof;
for (int i=0; i< sizeDofMaster; i++)
{
partDomain* dom = getVertexDomain(domainVector,vecMaster[i]);
getKeysFromVertex(dom->getFunctionSpace(),vecMaster[i],comp,allDof);
}
for (int i=0; i< sizeDofSlave; i++)
{
partDomain* dom = getVertexDomain(domainVector,vecSlave[i]);
getKeysFromVertex(dom->getFunctionSpace(),vecSlave[i],comp,allDof);
}
if ((vRootMaster != NULL) && (vRootSlave != NULL))
{
partDomain* vRootMasterDom = getVertexDomain(domainVector,vRootMaster);
partDomain* vRootSlaveDom = getVertexDomain(domainVector,vRootSlave);
getKeysFromVertex(vRootMasterDom->getFunctionSpace(),vRootMaster,comp,allDof);
getKeysFromVertex(vRootSlaveDom->getFunctionSpace(),vRootSlave,comp,allDof);
}
// find positive dof
int positive = -1;
double maxWeight = 0.;
for (int i=0; i< sizeDofMaster+sizeDofSlave; i++)
{
bool checkRoot = true;
if ((vRootMaster != NULL) && (vRootSlave != NULL))
{
if ((allDof[i] == allDof[sizeDofMaster+sizeDofSlave]) || (allDof[i] == allDof[sizeDofMaster+sizeDofSlave+1]))
{
checkRoot = false;
}
}
if ((!pAssembler->isConstrained(allDof[i])) and (!pAssembler->isFixed(allDof[i])) and checkRoot)
{
if (fabs(weight(i)) > fabs(maxWeight))
{
positive = i;
maxWeight = weight(i);
}
}
}
Msg::Info("positive = %d weigth = %e v1 = %d v2 = %d comp = %d",positive,maxWeight,pbc.v1->getNum(),pbc.v2->getNum(),pbc.comp[icomp]);
if (positive == -1)
{
Msg::Error("nonLinearAveragePeriodicBCBetweenTwoGroups can not be used since all Dofs are constrained or fixed in other BCs");
}
else
{
double fact = 1./maxWeight;
weight.scale(fact);
DofAffineConstraint<double> cons;
cons.shift = 0.;
for (int i=0; i< sizeDofMaster+sizeDofSlave+2; i++){
if (i != positive){
cons.linear.push_back(std::pair<Dof,double>(allDof[i],-weight(i)));
}
}
pAssembler->setLinearConstraint(allDof[positive],cons);
}
}
if (allAveragePeriodic.size() > 0)
Msg::Info("end accounting average PBC");
};
};
};
void nonLinearMechSolver::crackTracking(std::string fname)
{
_crackTrackingName = fname;
#if defined(HAVE_MPI)
if(Msg::GetCommSize() > 1){
std::ostringstream oss;
oss << Msg::GetCommRank();
fname += oss.str();
}
#endif // HAVE_MPI
fname = getFileSavingPrefix()+ fname;
_crackTrackingFile = fopen(fname.c_str(),"w");
fprintf(_crackTrackingFile,"time0,time1;inter num;num minus;num plus;x0;y0;z0;x1;y1;z1\n");
}
// In MPI only 1 final file on rank 0
void nonLinearMechSolver::postproFragment(std::string fname)
{
_fragmentationName = fname;
#if defined(HAVE_MPI)
if(Msg::GetCommSize()>1)
{
// change file name (include the part number in it
std::ostringstream oss;
oss << Msg::GetCommRank();
std::string partnum = oss.str();
// retrieve file extension
size_t ext_pos;
ext_pos = fname.find_last_of('.');
std::string ext(fname,ext_pos+1,fname.size());
// set file name
std::string newname(fname,0,ext_pos);
std::string fileName = newname + "_part" + partnum +"." + ext;
// open file
fileName = getFileSavingPrefix()+fileName;
_fragmentationFile = fopen(fileName.c_str(),"w");
}
else
#endif //HAVE_MPI
{
fname = getFileSavingPrefix()+fname;
_fragmentationFile = fopen(fname.c_str(),"w");
}
}
void nonLinearMechSolver::crackTracking(const double curtime)
{
if(_crackTrackingFile != NULL) // do nothing otherwise
{
// loop on domain
for(std::vector<partDomain*>::const_iterator itdom = domainVector.begin(); itdom != domainVector.end(); ++itdom)
{
partDomain *dom = *itdom;
if(dom->IsInterfaceTerms())
{
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
if((dgdom->getMaterialLawMinus()->getType() == materialLaw::fracture)
and (dgdom->getMaterialLawPlus()->getType() == materialLaw::fracture)
and (dgdom->getDim() == 2))
{
// loop on interface element
QuadratureBase *integBound = dgdom->getInterfaceGaussIntegrationRule();
IntPt *GP;
const materialLaw2LawsInitializer *mfminus = dynamic_cast<const materialLaw2LawsInitializer*>(dgdom->getMaterialLawMinus());
const materialLaw2LawsInitializer *mfplus = dynamic_cast<const materialLaw2LawsInitializer*>(dgdom->getMaterialLawPlus());
for(elementGroup::elementContainer::const_iterator itele = dgdom->gi->begin(); itele != dgdom->gi->end(); ++itele)
{
MElement *ele = itele->second;
AllIPState::ipstateElementContainer *vips = _ipf->getAips()->getIPstate(ele->getNum());
int npts_inter = integBound->getIntPoints(ele,&GP);
int jj;
/* Assume same value on minus and plus element !!*/
bool prevOther = false; // other previous Gauss point already broken
for(jj=0;jj<npts_inter;jj++)
{
IPStateBase *ipsm = (*vips)[jj];
IPVariable *ipvmcur = ipsm->getState(IPStateBase::current);
IPVariable *ipvmprev= ipsm->getState(IPStateBase::previous);
bool fbmp = mfminus->fullBroken(ipvmprev);
bool fbmc = mfminus->fullBroken(ipvmcur);
if((fbmc==false))
break;
else if(fbmp==false){
if(prevOther==false)
prevOther = true;
else
break;
}
}
if( (jj==npts_inter) and (prevOther==true))// element is broken when all Gauss points are broken
{
/* get the time of crack initialization at extremities !! */
IPStateBase *ipsm = (*vips)[0];
IPVariable *ipvmcur = ipsm->getState(IPStateBase::current);
double time00 = mfminus->timeInitBroken(ipvmcur);
ipsm = (*vips)[npts_inter-1];
ipvmcur = ipsm->getState(IPStateBase::current);
double time01 = mfminus->timeInitBroken(ipvmcur);
double time0;
int index1,index0; // 0 or 1
if(time00 < time01){
time0 = time00;
index0 = 0;
index1 = 1;
}
else{
time0 = time01;
index0 = 1;
index1 = 0;
}
/* find current position of element */
FunctionSpaceBase *sp = dgdom->getFunctionSpace();
std::vector<Dof> R;
MInterfaceLine *iele = dynamic_cast<MInterfaceLine*>(ele); // track a 2D crack--> interface == line
MElement *minusele = iele->getElem(0);
MElement *plusele = iele->getElem(1);
int totalnodes = minusele->getNumVertices() + plusele->getNumVertices();
// number of dimension
sp->getKeys(iele,R); // can't only get keys of elem minus on interDomain !!
int dimMinus = R.size()/totalnodes;
int numdofsMinus = dimMinus*minusele->getNumVertices();
int numdofsPlus = dimMinus*plusele->getNumVertices();
// limit R to the dofs of minus elem (can't resize as Dof() is not defined)
for(int kk=0;kk<numdofsPlus;kk++)
{
R.pop_back();
}
fullVector<double> disp(R.size());
_ufield->get(R,disp);
std::vector<double> elempos;
currentConfig::elementPositionXYZ(minusele,disp,elempos);
std::vector<int> vn(2);
iele->getLocalVertexNum(0,vn);
int numvertex = minusele->getNumVertices();
fprintf(_crackTrackingFile,"%.16g;%.16g;%ld;%ld;%ld;%.16g;%.16g;%.16g;%.16g;%.16g;%.16g\n",time0,curtime,ele->getNum(),iele->getElem(index0)->getNum(),iele->getElem(index1)->getNum(),elempos[vn[index0]],elempos[vn[index0]+numvertex],elempos[vn[index0]+2*numvertex],elempos[vn[index1]],elempos[vn[index1]+numvertex],elempos[vn[index1]+2*numvertex]);
}
}
}
}
}
fflush(_crackTrackingFile);
}
}
void nonLinearMechSolver::postproFragment()
{
if(_fragmentationFile!=NULL)
{
std::set<interfaceFragment> sfrag; // contains interface element not broken
std::set<pairMassElem> isolatedfrag; // contains elements of broken interface
// loop on domain
for(std::vector<partDomain*>::const_iterator itdom = domainVector.begin(); itdom != domainVector.end(); ++itdom)
{
partDomain *dom = *itdom;
if(dom->IsInterfaceTerms())
{
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
if((dgdom->getMaterialLawMinus()->getType() == materialLaw::fracture)
and (dgdom->getMaterialLawPlus()->getType() == materialLaw::fracture)) // same for dim 3 normally. But not tested
{
// loop on interface element
QuadratureBase *integBound = dgdom->getInterfaceGaussIntegrationRule();
IntPt *GP;
const materialLaw2LawsInitializer *mfminus = dynamic_cast<const materialLaw2LawsInitializer*>(dgdom->getMaterialLawMinus());
const materialLaw2LawsInitializer *mfplus = dynamic_cast<const materialLaw2LawsInitializer*>(dgdom->getMaterialLawPlus());
for(elementGroup::elementContainer::const_iterator itele = dgdom->gi->begin(); itele != dgdom->gi->end(); ++itele)
{
MElement *ele = itele->second;
AllIPState::ipstateElementContainer *vips = _ipf->getAips()->getIPstate(ele->getNum());
int npts_inter = integBound->getIntPoints(ele,&GP);
int jj;
/* Assume same value on minus and plus element !!*/
for(jj=0;jj<npts_inter;jj++)
{
IPStateBase *ipsm = (*vips)[jj];
IPVariable *ipvmcur = ipsm->getState(IPStateBase::current);
if(!(mfminus->fullBroken(ipvmcur)))
break;
}
MInterfaceElement *miel = dynamic_cast<MInterfaceElement*>(ele);
if(!(jj==npts_inter))// element is not broken
{
sfrag.insert(interfaceFragment(miel,dgdom->getMaterialLawMinus()->density(),dgdom->getMaterialLawPlus()->density()));
}
else
{
#if defined(HAVE_MPI)
if((miel->getElem(0)->getPartition() == Msg::GetCommRank()+1) or (Msg::GetCommSize()==1)) // insert only the element that is on the partition
#endif // HAVE_MPI
{
isolatedfrag.insert(pairMassElem(miel->getElem(0),dgdom->getMaterialLawMinus()->density()));
}
#if defined(HAVE_MPI)
if((miel->getElem(1)->getPartition() == Msg::GetCommRank()+1) or (Msg::GetCommSize()==1)) // insert only the element that is on the partition
#endif // HAVE_MPI
{
isolatedfrag.insert(pairMassElem(miel->getElem(1),dgdom->getMaterialLawPlus()->density()));
}
}
}
}
}
}
// loop on interelement
std::set<fragment> fragmentlist;
std::set<fragment>::iterator it1=fragmentlist.end();
std::set<fragment>::iterator it2=fragmentlist.end();
for(std::set<interfaceFragment>::iterator it=sfrag.begin(); it!=sfrag.end();++it)
{
it1=fragmentlist.end();
it2=fragmentlist.end();
for(std::set<fragment>::iterator itf=fragmentlist.begin(); itf!=fragmentlist.end(); ++itf)
{
if((*itf).match(*it))
{
if(it1==fragmentlist.end())
{
it1 = itf;
}
else
{
it2 = itf;
break; // can only found 2 elements;
}
}
}
// insert fragment
if((it1!=fragmentlist.end()) and(it2==fragmentlist.end())) // match with one --> insert interfacefragment to the fragment
{
(*it1).add(*it);
}
else if(it2!=fragmentlist.end()) // match twice --> regroup both fragment
{
(*it1).add(*it2);
fragmentlist.erase(it2);
}
else // no match --> create a new one
{
fragmentlist.insert(fragment(*it));
}
}
// Loop on isolated fragment. If not founded the fragment contains only 1 element which has to be inserted in fragmentlist
for(std::set<pairMassElem>::iterator it=isolatedfrag.begin(); it!=isolatedfrag.end();++it)
{
std::set<fragment>::iterator itfound=fragmentlist.end();
for(std::set<fragment>::iterator itf=fragmentlist.begin(); itf!=fragmentlist.end();++itf)
{
if((*itf).match(*it))
{
itfound = itf;
break;
}
}
if(itfound==fragmentlist.end())
{
fragmentlist.insert(fragment(*it));
}
}
// at this point fragmentlist contains all fragment of the partition
// the file can be written except for fragment defined on more than 1
// partition which have to be regrouped.
double massallfrag=0.;
int fragnum=1;
fprintf(_fragmentationFile,"number;number of element;mass\n");
#if defined(HAVE_MPI)
std::set<fragmentMPI> fragmentlistMPI;
int mysizeMPI = 0; // compute the size of data to transfert
#endif // HAVE_MPI
std::vector<std::set<fragment>::iterator> fragmypart;
for(std::set<fragment>::iterator it=fragmentlist.begin(); it!=fragmentlist.end();++it)
{
#if defined(HAVE_MPI)
if((Msg::GetCommSize()>1) and ((*it).definedOnMoreThanOneRank())){
fragmentlistMPI.insert(fragmentMPI(*it));
mysizeMPI +=(*it).numberOfValueToCommunicateMPI();
}
else // fragment is totally included on this rank so can be written into the files
#endif // HAVE_MPI
{
fprintf(_fragmentationFile,"%d;%d;%e\n",fragnum,(*it).numberOfElements(),(*it).mass());
fragnum++;
massallfrag+= (*it).mass();
fragmypart.push_back(it);
}
}
#if defined(HAVE_MPI)
// regroup inter rank fragment (the data is send to rank 0 which do the job (change this ??))
// size to transfert
int *alldatasize;
double* allfragMPI;
double** allfragMPIrank0;
MPI_Status mpistatus;
if(Msg::GetCommRank()==0){
// get fragment of the other ranks
alldatasize = new int[Msg::GetCommSize()];
allfragMPIrank0 = new double*[Msg::GetCommSize()];
alldatasize[0] = mysizeMPI;
for(int i=1;i<Msg::GetCommSize();i++)
{
MPI_Recv(&alldatasize[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&mpistatus);
allfragMPIrank0[i] = new double[alldatasize[i]];
MPI_Recv(allfragMPIrank0[i],alldatasize[i],MPI_DOUBLE,i,i,MPI_COMM_WORLD,&mpistatus);
}
// double loop to avoid wait of other rank for MPI_comm ??
// insert fragment of each rank
std::set<fragmentMPI>::iterator it1;
std::set<fragmentMPI>::iterator it2;
for(int i=1;i<Msg::GetCommSize();i++)
{
int curpos=0;
while(curpos<alldatasize[i])
{
fragmentMPI newfrag = fragmentMPI(allfragMPIrank0[i],curpos);
curpos += newfrag.memorySize();
// add fragment in the list
std::vector<std::set<fragmentMPI>::iterator> vit;
for(std::set<fragmentMPI>::iterator itf=fragmentlistMPI.begin(); itf!=fragmentlistMPI.end(); ++itf)
{
if((*itf).match(newfrag))
{
newfrag.add(*itf);
vit.push_back(itf);
}
}
// delete matched fragment
for(int i=vit.size()-1; i>=0;i--)
{
fragmentlistMPI.erase(vit[i]);
}
// insert the new one
fragmentlistMPI.insert(newfrag);
}
}
// write to files
for(std::set<fragmentMPI>::iterator it=fragmentlistMPI.begin(); it!=fragmentlistMPI.end();++it)
{
fprintf(_fragmentationFile,"%d;%d;%e\n",fragnum,(*it).numberOfElements(),(*it).mass());
fragnum++;
massallfrag+= (*it).mass();
}
// free memory
for(int i=1;i<Msg::GetCommSize();i++)
delete[] allfragMPIrank0[i];
delete[] allfragMPIrank0;
}
else
{
// build a double vector to transfert all data to node 0
allfragMPI = new double[mysizeMPI];
int vecpos = 0;
for(std::set<fragmentMPI>::iterator it=fragmentlistMPI.begin(); it!=fragmentlistMPI.end(); ++it)
{
vecpos +=(*it).fillMPIvector(&allfragMPI[vecpos]);
}
MPI_Send(&mysizeMPI,1,MPI_INT,0,Msg::GetCommRank(),MPI_COMM_WORLD);
// send data
MPI_Send(allfragMPI,mysizeMPI,MPI_DOUBLE,0,Msg::GetCommRank(),MPI_COMM_WORLD);
delete[] allfragMPI;
}
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
#endif // HAVE_MPI
// total mass at the end
fprintf(_fragmentationFile,"total mass; %e\n number of fragment %d\n",massallfrag,fragnum-1);
fflush(_fragmentationFile);
/* create a view of fragment ( ie a mesh with a different physical number for each fragment) */
//filename
std::string fragmshname;
#if defined(HAVE_MPI)
if(Msg::GetCommSize()>1)
{
std::ostringstream oss;
oss << Msg::GetCommRank();
std::string partnum = oss.str();
fragmshname = getFileSavingPrefix()+ "fragview_part"+partnum+".msh";
}
else
#endif //HAVE_MPI
{
fragmshname = getFileSavingPrefix()+ "fragview.msh";
}
FILE *fpfragmsh = fopen(fragmshname.c_str(),"w");
FILE *fpmsh = fopen(_meshFileName.c_str(),"r");
fprintf(fpfragmsh,"$MeshFormat\n2.2 0 8\n$EndMeshFormat\n");
// The node are copy only on rank 0
char what[256];
// if(Msg::GetCommRank()==0)
{
while(1)
{
int oks = fscanf(fpmsh,"%s",what);
if(!strcmp(what,"$Nodes"))
{
fprintf(fpfragmsh,"$Nodes\n");
oks = fscanf(fpmsh,"%s",what);
fprintf(fpfragmsh,"%s\n",what);
break;
}
}
int j=1;
while(!feof(fpmsh))
{
int oks = fscanf(fpmsh,"%s",what);
fprintf(fpfragmsh,"%s",what);
if(!strcmp(what,"$EndNodes"))
{
fprintf(fpfragmsh,"\n");
break;
}
if(j%4==0)
{
fprintf(fpfragmsh,"\n");
}
else
{
fprintf(fpfragmsh," ");
}
j++;
}
}
/* else{
while(!feof(fpmsh))
{
fscanf(fpmsh,"%s",what);
if(!strcmp(what,"$EndNodes"))
{
break;
}
}
}
*/
int oks = fscanf(fpmsh,"%s",what);
fprintf(fpfragmsh,"%s\n",what);
int allelem; // total number of element in the mesh file
oks = fscanf(fpmsh,"%d",&allelem);
// compute the total number of element included on this partition
int totalelem=0;
for(int i=0;i<fragmypart.size();i++)
{
totalelem +=fragmypart[i]->numberOfElements();
}
#if defined(HAVE_MPI)
if(Msg::GetCommRank()==0)
{
for(std::set<fragmentMPI>::iterator it = fragmentlistMPI.begin(); it!=fragmentlistMPI.end();++it)
{
totalelem +=it->numberOfElements();
}
}
#endif // HAVE_MPI
fprintf(fpfragmsh,"%d\n",totalelem);
int num1,num2;
int physfrag;
int typemshint;
for(int k=0;k<allelem;k++)
{
int elenum;
oks = fscanf(fpmsh,"%d",&elenum);
// check if the element is in the fragment of this partition
bool writeelem=false;
physfrag=0;
for(int i=0;i<fragmypart.size();i++)
{
physfrag++;
if(fragmypart[i]->isElem(elenum))
{
writeelem=true;
break;
}
}
#if defined(HAVE_MPI)
if(Msg::GetCommRank()==0 and !writeelem)
{
for(std::set<fragmentMPI>::iterator it = fragmentlistMPI.begin(); it!=fragmentlistMPI.end();++it)
{
physfrag++;
if(it->isElem(elenum))
{
writeelem = true;
break;
}
}
}
#endif // HAVE_MPI
oks = fscanf(fpmsh,"%d %d",&typemshint,&num2);
if(writeelem) fprintf(fpfragmsh,"%d %d %d ",elenum,typemshint,num2);
oks = fscanf(fpmsh,"%d",&num1); // read the physical number which has to be replaced
if(writeelem) fprintf(fpfragmsh,"%d ",physfrag+1000000*Msg::GetCommRank());
int nver = MElement::getInfoMSH(typemshint); // get the number of vertices of the element
// the gentity has to be different for each fragment ie same as physical
oks = fscanf(fpmsh,"%d",&num1);
if(writeelem) fprintf(fpfragmsh,"%d ",physfrag+1000000*Msg::GetCommRank());
for(int i=2;i<num2;i++){
oks = fscanf(fpmsh,"%d",&num1);
if(writeelem) fprintf(fpfragmsh,"%d ",num1);
}
for(int i=0;i<nver;i++)
{
oks = fscanf(fpmsh,"%d",&num1);
if(writeelem){
if(i!=nver-1)
fprintf(fpfragmsh,"%d ",num1);
else
fprintf(fpfragmsh,"%d\n",num1);
}
}
//if(writeelem) fprintf(fpfragmsh,"\n");
}
fprintf(fpfragmsh,"$EndElements");
fclose(fpmsh);
fclose(fpfragmsh);
if (getNumRanks() > 1)
Msg::Barrier(); // wait all otherwise archiving problem ??
}
}
void nonLinearMechSolver::fillMapOfInterfaceElementsInOneDomain(MElement *e, std::vector<MElement*> &eleFound,
const elementGroup *g) const
{
// take only the primary vertex (avoid unnecessery check for element with order > 1
int nbVertex = e->getNumPrimaryVertices();
std::vector<MVertex*> vv;
for(int i=0;i<nbVertex;i++)
vv.push_back(e->getVertex(i));
// In 3D, in //, it is possible that all the nodes are in group g, but not from the same element
// We need to identify by face.
for(elementGroup::elementContainer::const_iterator ite=g->begin(); ite !=g->end(); ite++)
{
MElement *gele = ite->second;
int nbVertex2 = gele->getNumPrimaryVertices();
bool oneNotFound = false;
for(std::vector<MVertex*>::const_iterator itvv = vv.begin(); itvv!= vv.end(); itvv++)
{
oneNotFound = true;
for(int j=0;j<nbVertex2;j++)
{
if((gele->getVertex(j)) == (*itvv))
{
oneNotFound = false;
break;
}
}
if(oneNotFound) break;
}
if(!oneNotFound)
{
eleFound.push_back(e);
break;
}
}
}
void nonLinearMechSolver::fillLocalReferenceBasisForAllInterfaceElement(){
//printf("begin filling reference local basis\n");
for (int idom= 0; idom < domainVector.size(); idom++){
const dgPartDomain* dgdom = dynamic_cast<const dgPartDomain*>(domainVector[idom]);
if (dgdom != NULL){
IntPt* GP;
for (elementGroup::elementContainer::const_iterator ite = dgdom->gi->begin(); ite != dgdom->gi->end(); ite++){
MElement* ele = ite->second;
int npts = dgdom->getInterfaceGaussIntegrationRule()->getIntPoints(ele,&GP);
for (int i=0; i< npts; i++){
int type = numericalMaterialBase::createTypeWithTwoInts(ele->getNum(), i);
SVector3 n, b, t;
computeInterfaceReferenceLocalBasis(ele,&GP[i],n,t,b);
STensor3 mat;
mat(0,0) = n(0); mat(1,0) = n(1); mat(2,0) = n(2);
mat(0,1) = t(0); mat(1,1) = t(1); mat(2,1) = t(2);
mat(0,2) = b(0); mat(1,2) = b(1); mat(2,2) = b(2);
_allInterfaceLocalBasis[type] = mat; // negative
type = numericalMaterialBase::createTypeWithTwoInts(ele->getNum(), i+npts);
_allInterfaceLocalBasis[type] = mat; // positive
}
}
}
}
//printf("done filling reference local basis size = %d\n",allInterfaceLocalBasis.size());
};
void nonLinearMechSolver::getLocalBasis(const MElement* ele, const int gpt, SVector3& n, SVector3& t, SVector3& b) const {
int type = numericalMaterialBase::createTypeWithTwoInts(ele->getNum(), gpt);
std::map<int,STensor3>::const_iterator itfind = _allInterfaceLocalBasis.find(type);
if ( itfind == _allInterfaceLocalBasis.end()){
Msg::Error(" rank %d local basis at interface element %d gpt %d does not exist",Msg::GetCommRank(), ele->getNum(),gpt);
}
else{
const STensor3& mat = itfind->second;
n(0) = mat(0,0); n(1) = mat(1,0); n(2) = mat(2,0);
t(0) = mat(0,1); t(1) = mat(1,1); t(2) = mat(2,1);
b(0) = mat(0,2); b(1) = mat(1,2); b(2) = mat(2,2);
//mat.print("found basis");
}
};
void nonLinearMechSolver::createStrainMapping(const std::string filename, const int nbstepArch){
if (_strainMap) delete _strainMap;
_strainMap = new strainMapping(*this,nbstepArch);
_strainMap->readMesh(filename);
GModel::setCurrent(pModel);
};
void nonLinearMechSolver::blockDissipation(const IPStateBase::whichState ws, const bool fl){
if (_ipf){
if (fl and !_damageIsBlocked){
printf("rank %d damage is blocked %s \n",Msg::GetCommRank(),getFileSavingPrefix().c_str());
}
else if (fl and _damageIsBlocked){
printf("rank %d damage is reblocked %s \n",Msg::GetCommRank(),getFileSavingPrefix().c_str());
}
else if (!fl and _damageIsBlocked){
printf("rank %d damage is unblocked %s \n",Msg::GetCommRank(),getFileSavingPrefix().c_str());
}
_damageIsBlocked = fl;
}
else
Msg::Error("IPField has not been initialized");
}
bool nonLinearMechSolver::dissipationIsBlocked() const{
return _damageIsBlocked;
};
void nonLinearMechSolver::setTimeForMicroBC(const double time){
if (_microBC!=NULL){
_microBC->setTime(time);
}
};
void nonLinearMechSolver::microNumberDof(){
if (_pathFollowing){
_systemType = MULT_ELIM;
_pAl->numberDof(MULT_ELIM);
}
else{
if (_controlType == LOAD_CONTROL){
// number normally dof
_pAl->numberDof(_systemType);
// allocate micro system
}
else if (_controlType == ARC_CONTROL_EULER){
_systemType = DISP_MULT;
_pAl->numberDof(DISP_MULT);
}
else{
Msg::Error("control Type must be correct defined");
}
}
std::string A("A");
if (_systemType == DISP_ELIM_UNIFIED){
// PAL has to be set before allocating linear system
pbcSystemConden<double>* pbc = dynamic_cast<pbcSystemConden<double>*>(pAssembler->getLinearSystem(A));
if (pbc){
pbc->setPBCAlgorithm(_pAl);
}
}
// allocate system
int systemSize = pAssembler->sizeOfR();
if (_pathFollowing){
// if path following and one rhs resolution
if (_pfManager._pathFollowingMethod == pathFollowingManager::GLOBAL_ARC_LENGTH_BASED){
}
else if (_pfManager._pathFollowingMethod == pathFollowingManager::LOCAL_BASED){
// add 1 DOF to total system as load factor unknown
if (_pfManager._solverTypePathFollowing == pathFollowingSystemBase::ONE_RHS){
systemSize++;
}
}
else{
Msg::Error("_pathFollowingMethod = %d has not been implemented",_pfManager._pathFollowingMethod);
}
}
pAssembler->getLinearSystem(A)->allocate(systemSize);
if (_systemType == DISP_ELIM_UNIFIED){
// initial kinematic variable for this method
pbcSystemConden<double>* pbc = dynamic_cast<pbcSystemConden<double>*>(pAssembler->getLinearSystem(A));
if (pbc){
fullVector<double> kinVec;
_pAl->getMBC()->getKinematicalVector(kinVec);
for (int i=0; i< kinVec.size(); i++){
double val = kinVec(i);
pbc->initialKinematicVector(i,val);
}
}
}
// preallocated system
for(int i=0; i<_mpiUserDom;++i)
{
partDomain *dom = domainVector[i];
if(dom->elementGroupSize() > 0){
SparsityDofs(*(dom->getFunctionSpace()), dom->element_begin(), dom->element_end(),*pAssembler);
}
// account also interface
dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(dom);
if (dgdom){
#if defined(HAVE_MPI)
if(Msg::GetCommSize()>1)
SparsityInterfaceDofsMPI(dgdom->getFunctionSpace(), dgdom->gi->begin(), dgdom->gi->end(),pAssembler);
#endif
SparsityDofs(*(dgdom->getFunctionSpace()), dgdom->gi->begin(), dgdom->gi->end(),*pAssembler);
}
}
#if defined(HAVE_MPI)
// MPI interface sparsity
if(Msg::GetCommSize()>1){
for(int i=_mpiUserDom; i<domainVector.size();++i)
{
dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(domainVector[i]);
if (dgdom){
SparsityInterfaceDofsMPI(dgdom->getFunctionSpace(), dgdom->gi->begin(), dgdom->gi->end(),pAssembler);
}
}
}
#endif // HAVE_MPI
if (_systemType == nonLinearMechSolver::DISP_MULT){
_pAl->sparsityLagMultiplierDofs();
}
pAssembler->getLinearSystem(A)->preAllocateEntries();
// assemble all linear constraint matrix to system in case of using mult -elim method
int dimKin = _pAl->getNumberOfMacroToMicroKinematicVariables();
int dimStress = _pAl->getNumberMicroToMacroHomogenizedVariables();
bool insystemCondenFlag = false;
if (_tangentflag and (_homogenizeTangentMethod == INSYSTEMCONDEN or computedUdF()))
{
insystemCondenFlag = true;
};
if (_systemType == MULT_ELIM){
_pAl->allocateConstraintMatrixToSystem(dimKin,dimStress,insystemCondenFlag);
// assembleLinearConstraintMatrixToSystem must be called at least once
_pAl->assembleLinearConstraintMatrixToSystem();
if (insystemCondenFlag){
_pAl->assembleKinematicMatrix();
}
}
else if (_systemType == DISP_ELIM_UNIFIED ){
std::string A("A");
pbcSystemConden<double>* pbc = dynamic_cast<pbcSystemConden<double>*>(pAssembler->getLinearSystem(A));
if (pbc == NULL) Msg::Error("pbcSystemConden has to be used");
// computeConstraintProjectMatrices must be called at least once
pbc->computeConstraintProjectMatrices();
if (insystemCondenFlag){
// only stress matrix is necessary in this case
pbc->allocateStressMatrix(dimStress,pAssembler->sizeOfR());
if(computedUdF())
pbc->allocateBodyForceMatrix(pAssembler->sizeOfR());
}
if (_homogenizeTangentMethod == PERTURB and computedUdF()){
pbc->allocateStressMatrix(dimStress,pAssembler->sizeOfR());
pbc->allocateBodyForceMatrix(pAssembler->sizeOfR());
}
}
};
void nonLinearMechSolver::setPeriodicity(const double x, const double y, const double z, const std::string direction){
Msg::Warning(" nonLinearMechSolver::setPeriodicity is no longer necessary!");
};
void nonLinearMechSolver::addMicroBC(const nonLinearMicroBC* bc){
_microFlag = true;
if (_microBCOld) delete _microBCOld;
_microBCOld = _microBC;
_microBC = bc->clone();
if (_microBCOld != NULL){
_microBC->collecDataFromPrevious(*_microBCOld);
}
// add BC suppport
std::vector<elementGroup*>& bgroup = _microBC->getBoundaryElementGroup();
const std::vector<int>& bphysical = _microBC->getBoundaryPhysicals();
bgroup.clear();
for (int i=0; i< bphysical.size(); i++){
elementGroup* gr = new elementGroup(_dim-1,bphysical[i]);
bgroup.push_back(gr);
}
};
void nonLinearMechSolver::addMicroBCForFailure(const nonLinearMicroBC* mbc){
// this BC sleeps util failure
// once failure occurs, _microBC is replaced by _microFailureBC using addMicroBC
if (_microFailureBC!=NULL) delete _microFailureBC;
_microFailureBC = mbc->clone();
};
double nonLinearMechSolver::getRVEVolume() const{
return _rveVolume;
};
void nonLinearMechSolver::setRVEVolume(const double val){
_rveVolume = val;
}
const STensor3& nonLinearMechSolver::getRVEGeometricalInertia() const {
return _rveGeoInertia;
};
void nonLinearMechSolver::setRVEGeometricalInertia(const STensor3& val){
STensorOperation::zero(_rveGeoInertia);
_rveGeoInertia(0,0) = val(0,0);
_rveGeoInertia(1,1) = val(1,1);
_rveGeoInertia(2,2) = val(2,2);
}
const SVector3& nonLinearMechSolver::getRVEGeometry() const {
return _rveGeometry;
};
void nonLinearMechSolver::setRVEGeometry(const SVector3& val){
STensorOperation::zero(_rveGeometry);
_rveGeometry(0) = val(0);
_rveGeometry(1) = val(1);
_rveGeometry(2) = val(2);
}
double nonLinearMechSolver::getHomogenizedDensity() const{
return _rho;
};
double nonLinearMechSolver::getConstitutiveExtraDofDiffusionEquationRatio(const int index) const
{
double eqRatio=1.;
bool found=false;
for (int i=0; i<domainVector.size(); i++)
{
const partDomain* dom = domainVector[i];
double eqR=dom->getConstitutiveExtraDofDiffusionEqRatio(index);
if(eqR>0.)
{
if(!found)
{
eqRatio = eqR;
found=true;
}
else if(eqR!=eqRatio)
Msg::Error("not all the domains have the same EqRatio field %d",index);
}
}
return eqRatio;
};
double nonLinearMechSolver::getNonConstitutiveExtraDofEquationRatio(const int index) const
{
double eqRatio=1.;
bool found=false;
for (int i=0; i<domainVector.size(); i++)
{
const partDomain* dom = domainVector[i];
double eqR=dom->getNonConstitutiveExtraDofEqRatio(index);
if(eqR>0.)
{
if(!found)
{
eqRatio = eqR;
found=true;
}
else if(eqR!=eqRatio)
Msg::Error("not all the domains have the same EqRatio field %d",index);
}
}
return eqRatio;
};
bool nonLinearMechSolver::getExtractIrreversibleEnergyFlag() const{return _extractIrreversibleEnergy;};
bool nonLinearMechSolver::getDamageToCohesiveJumpFlag() const {return _damageToCohesiveJump;};
int nonLinearMechSolver::getHomogenizationOrder() const {
if (_microBC != NULL){
return _microBC->getOrder();
}
else{
return 0;
}
};
bool nonLinearMechSolver::inMultiscaleSimulation() const{return _multiscaleFlag;};
const SVector3& nonLinearMechSolver::getLostSolutionUniquenssNormal() const{
return _lostSolutionUniquenssNormal;
};
double& nonLinearMechSolver::getHomogenizedCrackFace(){
return _homogenizedCrackSurface;
};
const double& nonLinearMechSolver::getHomogenizedCrackFace() const{
return _homogenizedCrackSurface;
};
STensor3& nonLinearMechSolver::getFdamOnset() {return _FdamOnset;};
const STensor3& nonLinearMechSolver::getFdamOnset() const {return _FdamOnset;};
bool nonLinearMechSolver::withEnergyDissipation() const{
for (std::map<int, materialLaw*>::const_iterator it = maplaw.begin(); it!= maplaw.end(); it++){
if (it->second->withEnergyDissipation()){
return true;
}
}
return false;
};
bool nonLinearMechSolver::withFractureLaw() const{
for (std::map<int, materialLaw*>::const_iterator it = maplaw.begin(); it!= maplaw.end(); it++){
if (it->second->getType() == materialLaw::fracture){
return true;
}
}
return false;
};
const elementErosionFilter& nonLinearMechSolver::getElementErosionFilter() const{
return _elementErosionFilter;
};
bool nonLinearMechSolver::solverIsBroken() const{
return _solverIsBroken;
}
void nonLinearMechSolver::brokenSolver(const bool fl){
_solverIsBroken = fl;
};
void nonLinearMechSolver::getTotalIntegralByVolumeIntegralOnPhysical(const int phys, const int num, double& val) const{
val = 0.;
for (int i=0; i< domainVector.size(); i++){
partDomain* dom = domainVector[i];
if (dom->getPhysical() == phys){
double volumePart = 0;
double valPartAverage = dom->computeMeanValueDomain(num,_ipf,volumePart);
val += (valPartAverage*volumePart);
}
}
#if defined(HAVE_MPI)
if (_isPartitioned and (Msg::GetCommSize() > 1)){
double valTmp = val;
MPI_Allreduce(&valTmp,&val,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
}
#endif // HAVE_MPI
};
void nonLinearMechSolver::getTotalIntegralByVolumeIntegral(const int num, double& val) const{
val = 0.;
for (int i=0; i< domainVector.size(); i++){
partDomain* dom = domainVector[i];
double volumePart = 0;
double valPartAverage = dom->computeMeanValueDomain(num,_ipf,volumePart);
val += (valPartAverage*volumePart);
}
#if defined(HAVE_MPI)
if (_isPartitioned and (Msg::GetCommSize() > 1)){
double valTmp = val;
MPI_Allreduce(&valTmp,&val,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
}
#endif // HAVE_MPI
};
void nonLinearMechSolver::getHomogenizedPropertyByVolumeIntegral(const int num, double & val) const{
val = 0.;
double volume = 0.;
for (int i=0; i< domainVector.size(); i++){
partDomain* dom = domainVector[i];
double volumePart = 0;
double valPart = dom->computeMeanValueDomain(num,_ipf,volumePart);
val += (valPart*volumePart);
volume += volumePart;
}
#if defined(HAVE_MPI)
if (_isPartitioned and (Msg::GetCommSize() > 1)){
double send[2] = {volume, val };
double receive[2];
MPI_Allreduce(send,receive,2,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
volume = receive[0];
val = receive[1];
}
#endif // HAVE_MPI
double invV = (1./volume);
val *= invV;
};
void nonLinearMechSolver::getHomogenizedPropertyByVolumeIntegralOnPhysical(const int phys, const int num, double & val) const{
val = 0.;
double volume = 0.;
for (int i=0; i< domainVector.size(); i++){
partDomain* dom = domainVector[i];
if (dom->getPhysical() == phys){
double volumePart = 0;
double valPart = dom->computeMeanValueDomain(num,_ipf,volumePart);
val += (valPart*volumePart);
volume += volumePart;
}
}
#if defined(HAVE_MPI)
if (_isPartitioned and (Msg::GetCommSize() > 1)){
double send[2] = {volume, val };
double receive[2];
MPI_Allreduce(send,receive,2,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
volume = receive[0];
val = receive[1];
}
#endif // HAVE_MPI
double invV = (1./volume);
val *= invV;
};
void nonLinearMechSolver::getHomogenizedPropertyByVolumeIntegralOnActiveDissipationDomain(const int num, double& val, const IPStateBase::whichState ws) const{
val = 0.;
double dissipationVolume = 0.;
for (int i=0; i< domainVector.size(); i++)
{
partDomain* dom = domainVector[i];
double dissipationVolumePart = 0;
double valPart = dom->averagingOnActiveDissipationZone(num,_ipf,dissipationVolumePart,ws);
val += (valPart*dissipationVolumePart);
dissipationVolume += dissipationVolumePart;
}
if (dissipationVolume > 0)
{
val /= dissipationVolume;
}
};
void nonLinearMechSolver::getHomogenizedIncrementalPropertyByVolumeIntegralOnActiveDissipationDomain(const int num, double& val) const{
val = 0.;
double dissipationVolume = 0.;
for (int i=0; i< domainVector.size(); i++)
{
partDomain* dom = domainVector[i];
double dissipationVolumePart = 0;
double valPart = dom->averagingIncrementOnActiveDissipationZone(num,_ipf,dissipationVolumePart);
val += (valPart*dissipationVolumePart);
dissipationVolume += dissipationVolumePart;
}
if (dissipationVolume > 0)
{
val /= dissipationVolume;
}
};
void nonLinearMechSolver::extractAverageStressByVolumeIntegral(homogenizedData* homoData){
// in case of multiscale analyses, previous macro-state is initial micro-state
double volumeRVEInv = 1./this->getRVEVolume();
// basic mechanics quantities
if (_microBC->getTotalNumberOfMechanicalDofs()> 0){
double& damageVolume = homoData->getActiveDissipationVolume();
damageVolume = 0.;
double& clength = homoData->getAverageLocalizationBandWidth();
clength = 0.;
if (withEnergyDissipation()){
// compute current damage volume
for (int i=0; i<domainVector.size(); i++){
damageVolume += domainVector[i]->computeVolumeActiveDissipationDomain(_ipf);
}
// active damage center
if (damageVolume > 0.){
// compute homogenized crack length
this->computeHomogenizedCrackFace();
// true damage surface = _surfaceReductionRatio*_homogenizedCrackSurface
clength = damageVolume/(_surfaceReductionRatio*_homogenizedCrackSurface);
}
}
STensor3& P = homoData->getHomogenizedStress();
STensorOperation::zero(P);
for (int i=0; i<domainVector.size(); i++){
domainVector[i]->computeAverageStress(_ipf,P);
};
P *= (volumeRVEInv);
if (_microBC->getOrder() == 2){
STensor33& Q = homoData->getHomogenizedSecondOrderStress();
STensorOperation::zero(Q);
for (int i=0; i<domainVector.size(); i++){
domainVector[i]->computeAverageHighOrderStress(_ipf,Q);
};
if(computedUdF()){
/*static STensor3 BmX;
static STensor33 BmXoX;
STensorOperation::zero(BmX);
STensorOperation::zero(BmXoX);
for (int i=0; i<domainVector.size(); i++){
domainVector[i]->computeBodyForceMultiplyPosition(_ipf, BmX, BmXoX);
}
BmX.print("BmX");
BmXoX.print("bmXoX- BMoJ");*/
const STensor63& dQdG_correction = homoData->getHomogenizedCorrectionTerm_G_G();
static STensor33 GM;
static STensor33 modTerm_Q;
if(_pathFollowing){
GM = this->getMicroBC()->getSecondOrderKinematicalVariable();
}
else{
GM = this->getMicroBC()->getCurrentDeformationGradientGradient();
}
STensorOperation::STensor63ContractionSTensor33(dQdG_correction, GM, modTerm_Q);
if(useWhichModuliForBF()==partDomain::Present){
const STensor43& dPdF = homoData->getHomogenizedTangentOperator_F_F();
for (int i=0; i<3; i++){
for (int j=0; j<3; j++)
for (int k=0; k<3; k++)
for (int l=0; l<3; l++)
for (int p=0; p<3; p++)
for (int q=0; q<3; q++){
Q(i,j,q) -= 0.5*(dPdF(i,j,k,l)*(GM(k,l,p))*_rveGeoInertia(p,q)+dPdF(i,q,k,l)*(GM(k,l,p))*_rveGeoInertia(p,j));
}
}
}
else{
const STensor43& dPdF = this->getHomogenizationState(IPStateBase::previous)->getHomogenizedTangentOperator_F_F();
for (int i=0; i<3; i++){
for (int j=0; j<3; j++)
for (int k=0; k<3; k++)
for (int l=0; l<3; l++)
for (int p=0; p<3; p++)
for (int q=0; q<3; q++){
Q(i,j,q) -= 0.5*(dPdF(i,j,k,l)*(GM(k,l,p))*_rveGeoInertia(p,q)+dPdF(i,q,k,l)*(GM(k,l,p))*_rveGeoInertia(p,j));
}
}
}
Q += modTerm_Q*this->getRVEVolume();
}
Q *= (volumeRVEInv);
}
// extract cohesive law
if (this->withEnergyDissipation() and this->getDamageToCohesiveJumpFlag()){
// cohesive traction
SVector3& T = homoData->getHomogenizedCohesiveTraction();
STensorOperation::zero(T);
// cohesive traction
for (int i=0; i<3; i++){
for (int j=0; j<3; j++){
T(i) += P(i,j)*_lostSolutionUniquenssNormal(j);
}
}
// compute cohesive jump
STensor3& Fdam = homoData->getHomogenizedActiveDissipationDeformationGradient();
Fdam = _homogenizedDissipationStrainLastActiveDissipation;
STensor3 dFdam(0.);
if (damageVolume > 0.){
for (int i=0; i<domainVector.size(); i++){
domainVector[i]->computeActiveDissipationAverageStrainIncrement(_ipf,dFdam);
}
dFdam *= (1./damageVolume);
Fdam += dFdam;
}
// compute cohesive jump
SVector3& cjump = homoData->getHomogenizedCohesiveJump();
cjump = _homogenizedCohesiveJumpLastActiveDissipation;
if (_solverIsBroken){
STensor3 dFinterf = this->getMicroBC()->getFirstOrderKinematicalVariable();
dFinterf -= _homogenizedStrainLastActiveDissipation;
double beta = damageVolume*volumeRVEInv/_surfaceReductionRatio;
for (int i=0; i<3; i++){
for (int j=0; j<3; j++){
cjump(i) += (clength/(1.-beta))*(dFdam(i,j) - dFinterf(i,j))*_lostSolutionUniquenssNormal(j);
}
};
}
};
double& defoEnergy = homoData->getDeformationEnergy();
double& plasEnergy = homoData->getPlasticEnergy();
double& irrEnergy = homoData->getIrreversibleEnergy();
defoEnergy = 0.;
plasEnergy = 0.;
irrEnergy = 0.;
for (int i=0; i< domainVector.size(); i++){
defoEnergy += domainVector[i]->computeDeformationEnergy(_ipf);
plasEnergy += domainVector[i]->computePlasticEnergy(_ipf);
irrEnergy += domainVector[i]->computeIrreversibleEnergy(_ipf);
}
defoEnergy *= volumeRVEInv;
plasEnergy *= volumeRVEInv;
irrEnergy *= volumeRVEInv;
};
if (_microBC->getTotalNumberOfConDofs() > 0){
// for constitutive-extra Dof
for (int index=0; index< _microBC->getTotalNumberOfConDofs(); index++ ){
SVector3& fluxT = homoData->getHomogenizedConstitutiveExtraDofFlux(index);
double &internalEnergyExtraDof = homoData->getHomogenizedConstitutiveExtraDofInternalEnergy(index);
double &mecaSource = homoData->getHomogenizedConstitutiveExtraDofMechanicalSource(index);
double &fieldCapacityPerUnitField = homoData->getHomogenizedConstitutiveExtraDofFieldCapacityPerUnitField(index);
STensorOperation::zero(fluxT);
internalEnergyExtraDof = 0.;
mecaSource = 0.;
fieldCapacityPerUnitField = 0.;
for (int i=0; i<domainVector.size(); i++){
domainVector[i]->computeConstitutiveExtraDofAverageFlux(index,_ipf,fluxT);
domainVector[i]->computeConstitutiveExtraDofAverageInternalEnergy(index,_ipf,internalEnergyExtraDof);
domainVector[i]->computeConstitutiveExtraDofAverageMechanicalSource(index,_ipf,mecaSource);
domainVector[i]->computeConstitutiveExtraDofAverageFieldCapacityPerUnitField(index,_ipf,fieldCapacityPerUnitField);
};
fluxT *= volumeRVEInv;
internalEnergyExtraDof *= volumeRVEInv;
mecaSource *= volumeRVEInv;
fieldCapacityPerUnitField *= volumeRVEInv;
}
}
// non-constitutive extraDof
if (_microBC->getTotalNumberOfNonConDofs()> 0){
for (int index=0; index<_microBC->getTotalNumberOfNonConDofs(); index++){
SVector3& fluxV = homoData->getHomogenizedNonConstitutiveExtraDofFlux(index);
STensorOperation::zero(fluxV);
for (int i=0; i<domainVector.size(); i++){
domainVector[i]->computeNonConstitutiveExtraDofAverageFlux(index,_ipf,fluxV);
};
fluxV *= volumeRVEInv;
}
}
};
void nonLinearMechSolver::homogenizedDataToFile(const double time){
homogenizedData* data = this->getHomogenizationState(IPStateBase::current);
_homogenizedFiles->dataToFile(time, this, data);
if (_extractElasticTangentOperator){
Tensor43::writeData(_elasticDPDFTangentFile,_elasticState->getHomogenizedTangentOperator_F_F(),time);
}
};
void nonLinearMechSolver::extractAverageStressByCondensation(homogenizedData* homoData){
// condensation can compute conly only stresses and extraDof flux
// other homogenized properties can be directly computed from
// volumetric integrals
/**create object in case of NULL **/
if (_condensation == NULL){
_condensation = this->createStiffnessCondensation(true,false);
}
/** solve**/
fullVector<double> vecStress;
_condensation->stressSolve(vecStress,getRVEVolume());
int atRow = 0;
// mechanical parts
if (_microBC->getTotalNumberOfMechanicalDofs()> 0){
STensor3& P = homoData->getHomogenizedStress();
P*= (0.);
// mechanics stress
for (int row = atRow; row<atRow+9; row++){
int i,j;
Tensor23::getIntsFromIndex(row-atRow,i,j);
P(i,j) =vecStress(row);
};
atRow+= 9;
if (_microBC->getOrder() == 2){
STensor33& Q = homoData->getHomogenizedSecondOrderStress();
Q*= (0.);
// mechanics second order stress
for (int row = atRow; row<atRow+27; row++){
int i,j,k;
Tensor33::getIntsFromIndex(row-atRow,i,j,k);
Q(i,j,k) = vecStress(row);
};
atRow += 27;
}
// compute energy by volume integral
double& defoEnergy = homoData->getDeformationEnergy();
double& plasEnergy = homoData->getPlasticEnergy();
double& irrEnergy = homoData->getIrreversibleEnergy();
defoEnergy = 0.;
plasEnergy = 0.;
irrEnergy = 0.;
for (int i=0; i< domainVector.size(); i++){
defoEnergy += domainVector[i]->computeDeformationEnergy(_ipf);
plasEnergy += domainVector[i]->computePlasticEnergy(_ipf);
irrEnergy += domainVector[i]->computeIrreversibleEnergy(_ipf);
}
defoEnergy /= (this->getRVEVolume());
plasEnergy /= (this->getRVEVolume());
irrEnergy /= (this->getRVEVolume());
}
if (_microBC->getTotalNumberOfConDofs() > 0){
for (int index = 0; index < _microBC->getTotalNumberOfConDofs(); index++){
SVector3& extraDofFlux = homoData->getHomogenizedConstitutiveExtraDofFlux(index);
extraDofFlux*=(0.);
// extradofs
for (int row = atRow; row<atRow+3; row++){
extraDofFlux(row-atRow) = vecStress(row)/getConstitutiveExtraDofDiffusionEquationRatio(index);
};
atRow+=3;
//compute by volume integrals
double &internalEnergyExtraDof = homoData->getHomogenizedConstitutiveExtraDofInternalEnergy(index);
double &mecaSource = homoData->getHomogenizedConstitutiveExtraDofMechanicalSource(index);
double &fieldCapacityPerUnitField = homoData->getHomogenizedConstitutiveExtraDofFieldCapacityPerUnitField(index);
internalEnergyExtraDof =0.;
mecaSource = 0;
fieldCapacityPerUnitField = 0.;
for (int i=0; i<domainVector.size(); i++){
domainVector[i]->computeConstitutiveExtraDofAverageInternalEnergy(index,_ipf,internalEnergyExtraDof);
domainVector[i]->computeConstitutiveExtraDofAverageMechanicalSource(index,_ipf,mecaSource);
domainVector[i]->computeConstitutiveExtraDofAverageFieldCapacityPerUnitField(index,_ipf,fieldCapacityPerUnitField);
}
double vtotal = this->getRVEVolume();
double vin = 1./vtotal;
internalEnergyExtraDof*= vin;
mecaSource *= vin;
fieldCapacityPerUnitField *= vin;
}
}
if (_microBC->getTotalNumberOfNonConDofs()){
for (int index = 0; index < _microBC->getTotalNumberOfNonConDofs(); index++){
SVector3& extraDofFlux = homoData->getHomogenizedNonConstitutiveExtraDofFlux(index);
extraDofFlux*=(0.);
// extradofs
for (int row = atRow; row<atRow+3; row++){
extraDofFlux(row-atRow) = vecStress(row)/getNonConstitutiveExtraDofEquationRatio(index);
};
atRow+=3;
}
}
};
void nonLinearMechSolver::extractAveragePropertiesByCondensation(homogenizedData* homoData){
// condensation can compute conly only tangent operators of stresses and extraDof flux
// as surface integrals can be used
// other homogenized properties cannot be computed
// using other method to estimated tangent
// if considering mechanical source
/**create object in case of NULL **/
if (_condensation == NULL){
if (_homogenizeStressMethod == VOLUME)
_condensation = this->createStiffnessCondensation(false, true);
else
_condensation = this->createStiffnessCondensation(true, true);
}
if (_pAl->isModifiedConstraintMatrix()){
// recomputing all constraint matrix if necessary
_condensation->clear();
_pAl->setIsModifiedConstraintMatrixFlag(false);
}
/** compute splitted stiffness matrix**/
this->computeSplittedStiffnessMatrix(false); //to get the homogenized stress derivative with respect to FM we do not want the body force effect
/** solve**/
fullMatrix<double> L;
double t=Cpu();
if (_multiscaleFlag == false)
Msg::Info("Begin performing static condensation");
_condensation->tangentCondensationSolve(L,getRVEVolume());
if(computedUdF())
{
static STensor53 dPdG;
static STensor53 dQdF;
static STensor63 dQdG;
this->HOStressTangent_modificationTerm(dPdG, dQdF, dQdG);
this->modifyHOStressTangent(L,dPdG, dQdF, dQdG); //to get the homogenized stress derivative with respect to GM we want the body force effect
}
t = Cpu() -t;
if (_multiscaleFlag == false)
Msg::Info("Done performing static condensation (%f s)",t);
fillTangent(L,homoData);
if (_microBC->getTotalNumberOfConDofs() > 0) {
// re-estimate tangent values due to use eqRatio
for (int index=0; index < _microBC->getTotalNumberOfConDofs(); index++){
double eqRatio=1./getConstitutiveExtraDofDiffusionEquationRatio(index);
if (_microBC->getTotalNumberOfMechanicalDofs()>0){
homoData->getHomogenizedTangentOperator_gradT_F(index) *= eqRatio;
if (_microBC->getOrder() == 2){
homoData->getHomogenizedTangentOperator_gradT_G(index) *= eqRatio;
}
}
for (int j=0; j< _microBC->getTotalNumberOfConDofs(); j++){
homoData->getHomogenizedTangentOperator_gradT_gradT(index,j) *= eqRatio;
homoData->getHomogenizedTangentOperator_gradT_T(index,j) *= eqRatio;
}
for (int j=0; j< _microBC->getTotalNumberOfNonConDofs(); j++){
homoData->getHomogenizedTangentOperator_gradT_gradV(index,j) *= eqRatio;
}
}
}
if (_microBC->getTotalNumberOfNonConDofs() > 0) {
for (int index=0; index< _microBC->getTotalNumberOfNonConDofs(); index++){
double eqRatio=1./getNonConstitutiveExtraDofEquationRatio(index);
if (_microBC->getTotalNumberOfMechanicalDofs() >0){
homoData->getHomogenizedTangentOperator_gradV_F(index) *= eqRatio;
if (_microBC->getOrder() == 2){
homoData->getHomogenizedTangentOperator_gradV_G(index) *= eqRatio;
}
}
for (int j=0; j< _microBC->getTotalNumberOfNonConDofs(); j++){
homoData->getHomogenizedTangentOperator_gradV_gradV(index,j) *= eqRatio;
}
for (int j=0; j< _microBC->getTotalNumberOfConDofs(); j++){
homoData->getHomogenizedTangentOperator_gradV_T(index,j) *= eqRatio;
homoData->getHomogenizedTangentOperator_gradV_gradT(index,j) *= eqRatio;
}
}
};
if (_homogenizeStressMethod == VOLUME){
extractAverageStressByVolumeIntegral(homoData);
}
else{
extractAverageStressByCondensation(homoData);
}
};
void nonLinearMechSolver::extractAveragePropertiesByInSystemCondensationDISP_MULT(homogenizedData* homoData)
{
// extract tangent
_pAl->zeroMultipleRHS();
_pAl->assembmeToMultipleRHS();
double t = Cpu();
Msg::Info("start solving multiple RHS");
_pAl->systemSolveMultipleRHS();
Msg::Info("time to solve multiple RHS = %.5f",Cpu()-t);
double vRVE = this->getRVEVolume();
STensor43& L = homoData->getHomogenizedTangentOperator_F_F();
STensorOperation::zero(L);
//
double wtotal = 0;
for (int i=0; i< domainVector.size(); i++)
{
partDomain* dom = domainVector[i];
FunctionSpaceBase* space = dom->getFunctionSpace();
std::vector<Dof> R;
IntPt* GP;
for (elementGroup::elementContainer::const_iterator ite = dom->element_begin(); ite != dom->element_end(); ite++ )
{
MElement* e = ite->second;
int npts = dom->getBulkGaussIntegrationRule()->getIntPoints(e,&GP);
const AllIPState::ipstateElementContainer* ips =_ipf->getAips()->getIPstate(e->getNum());
R.clear();
space->getKeys(e,R);
int nbFF = e->getNumShapeFunctions();
std::vector<int> DofPos(R.size());
for (int iR=0; iR < R.size(); iR++)
{
DofPos[iR] = pAssembler->getDofNumber(R[iR]);
}
for (int j=0; j< npts; j++)
{
const ipFiniteStrain* ipv = dynamic_cast<const ipFiniteStrain*>((*ips)[j]->getState(IPStateBase::current));
const std::vector<TensorialTraits<double>::GradType> &Grads = ipv->gradf(space,e,GP[j]);
const STensor43& Llocal = ipv->getConstRefToTangentModuli();
wtotal += ipv->getJacobianDeterminant(e,GP[j])*GP[j].weight;
double wJ = ipv->getJacobianDeterminant(e,GP[j])*GP[j].weight/vRVE;
//L.axpy(wJ,Llocal);
for (int k=0; k<3; k++)
{
for (int l=0; l<3; l++)
{
for (int p=0; p<3; p++)
{
for (int q=0; q<3; q++)
{
int indexpq = Tensor23::getIndex(p,q);
for (int r=0; r< nbFF; r++)
{
for (int a=0; a<3; a++)
{
for (int b=0; b<3; b++)
{
L(k,l,p,q) += wJ*Llocal(k,l,a,b)*Grads[r+a*nbFF](b)*_pAl->getFromMultipleRHSSolution(DofPos[r+a*nbFF],indexpq);
}
}
}
}
}
}
}
}
}
}
Msg::Info("wtotal= %e vRVE = %e",wtotal,vRVE);
L.print("L");
// extract stress
this->extractAverageStress(homoData);
};
void nonLinearMechSolver::extractAveragePropertiesByInSystemCondensation(homogenizedData* homoData){
// extract tangent
bool needdUdF = false;
bool needdUdG = false;
if(computedUdF()){
needdUdF=true;
needdUdG=true;
}
double vRVE = this->getRVEVolume();
// estimation of stress matrix
_pAl->zeroStressMatrix();
_pAl->zeroBodyForceMatrix();
for (int idom=0; idom<domainVector.size(); idom++){
partDomain* dom = domainVector[idom];
if (dom->elementGroupSize()>0){
dom->setRVEGeometricalInertia(_rveGeoInertia);
dom->setRVEVolume(_rveVolume);
AssembleStressMatrix(*dom->getBilinearTangentTerm(),*dom->getFunctionSpace(),dom->element_begin(),
dom->element_end(),*dom->getBulkGaussIntegrationRule(),*pAssembler,_elementErosionFilter);
}
}
if(needdUdF){
for (int idom=0; idom<domainVector.size(); idom++){
partDomain* dom = domainVector[idom];
if (dom->elementGroupSize()>0){
AssembleBodyForceMatrix(*dom->getBilinearBodyForceTangentTerm(),*dom->getFunctionSpace(),dom->element_begin(),
dom->element_end(),*dom->getBulkGaussIntegrationRule(),*pAssembler,_elementErosionFilter);
}
}
}
fullMatrix<double> L;
double t= Cpu();
if (_multiscaleFlag == false)
Msg::Info("Begin performing in-system condensation");
int goodSolve = _pAl->condensationSolve(L,vRVE,needdUdF, needdUdG, pAssembler,&homoData->getdUnknowndF(),&homoData->getdUnknowndG());
t = Cpu() -t;
if (_multiscaleFlag == false)
Msg::Info("Done performing in-system condensation (%f s)",t);
if(needdUdF)
{
_ipf->setdFmdFM(homoData->getdUnknowndF(), IPStateBase::current);
if(needdUdG)
_ipf->setdFmdGM(homoData->getdUnknowndG(), IPStateBase::current);
static STensor53 dPdG;
static STensor53 dQdF;
static STensor63 dQdG;
this->HOStressTangent_modificationTerm(dPdG, dQdF, dQdG);
const STensor63& dQdG_correction = homoData->getHomogenizedCorrectionTerm_G_G();
dQdG += dQdG_correction;
this->modifyHOStressTangent(L,dPdG, dQdF, dQdG); //to get the homogenized stress derivative with respect to GM we want the body force effect
}
fillTangent(L,homoData);
this->setHomogeneousTangentToDomain(homoData);
// extract stress
this->extractAverageStress(homoData);
// extract cohesive law
if (withEnergyDissipation() and getDamageToCohesiveJumpFlag()){
STensor33& DcjumpDF = homoData->getHomogenizedTangentOperator_CohesiveJump_F();
STensorOperation::zero(DcjumpDF);
const double& clength = homoData->getAverageLocalizationBandWidth();
double beta = homoData->getActiveDissipationVolume()/(_surfaceReductionRatio*vRVE);
double fact = (clength/(1.-beta));
static STensor43 Ifourth(1.,1.);
if (_solverIsBroken){
const STensor43& dFdamDF = homoData->getHomogenizedTangentOperator_ActiveDissipationDeformationGradient_F();
for (int i=0; i<3; i++){
for (int j=0; j<3; j++){
for (int k=0; k<3; k++){
for (int l=0; l<3; l++){
DcjumpDF(i,j,k) += fact*(dFdamDF(i,l,j,k) - Ifourth(i,l,j,k))*_lostSolutionUniquenssNormal(l);
}
}
}
}
}
if (_microBC->getOrder() == 2){
STensor43& dcjumpdG = homoData->getHomogenizedTangentOperator_CohesiveJump_G();
STensorOperation::zero(dcjumpdG);
if (_solverIsBroken){
const STensor53& dFdamDG = homoData->getHomogenizedTangentOperator_ActiveDissipationDeformationGradient_G();
for (int i=0; i<3; i++){
for (int j=0; j<3; j++){
for (int k=0; k<3; k++){
for (int l=0; l<3; l++){
for (int r=0; r<3; r++){
dcjumpdG(i,j,k,r) += fact*dFdamDG(i,l,j,k,r)*_lostSolutionUniquenssNormal(l);
}
}
}
}
}
}
}
if (_microBC->getTotalNumberOfConDofs()> 0){
for (int index=0; index < _microBC->getTotalNumberOfConDofs(); index++){
STensor3& dcjumpdgradT = homoData->getHomogenizedTangentOperator_CohesiveJump_gradT(index);
STensorOperation::zero(dcjumpdgradT);
SVector3& dcjumpdT = homoData->getHomogenizedTangentOperator_CohesiveJump_T(index);
STensorOperation::zero(dcjumpdT);
if (_solverIsBroken){
const STensor3& dFdamDT = homoData->getHomogenizedTangentOperator_ActiveDissipationDeformationGradient_T(index);
const STensor33& dFdamDgradT = homoData->getHomogenizedTangentOperator_ActiveDissipationDeformationGradient_gradT(index);
for (int i=0; i<3; i++){
for (int j=0; j<3; j++){
dcjumpdT(i) += fact*dFdamDT(i,j)*_lostSolutionUniquenssNormal(j);
for (int k=0; k<3; k++){
dcjumpdgradT(i,k) += fact*dFdamDgradT(i,j,k)*_lostSolutionUniquenssNormal(j);
};
}
}
};
}
}
if (_microBC->getTotalNumberOfNonConDofs()> 0){
for (int index=0; index < _microBC->getTotalNumberOfNonConDofs(); index++){
STensor3& dcjumpdgradV = homoData->getHomogenizedTangentOperator_CohesiveJump_gradV(index);
STensorOperation::zero(dcjumpdgradV);
if (_solverIsBroken){
const STensor33& dFdamDgradV = homoData->getHomogenizedTangentOperator_ActiveDissipationDeformationGradient_gradV(index);
for (int i=0; i<3; i++){
for (int j=0; j<3; j++){
for (int k=0; k<3; k++){
dcjumpdgradV(i,k) += fact*dFdamDgradV(i,j,k)*_lostSolutionUniquenssNormal(j);
};
}
}
};
}
}
}
if (_extractElasticTangentOperator)
{
if (_multiscaleFlag == false)
Msg::Info("extract elastic tengent operator");
//estimating elastic stiffness matrix
this->computeElasticStiffMatrix();
// estimation of stress matrix
_pAl->zeroStressMatrix();
_pAl->zeroBodyForceMatrix();
for (int idom=0; idom<domainVector.size(); idom++){
partDomain* dom = domainVector[idom];
if (dom->elementGroupSize()>0){
dom->setRVEGeometricalInertia(_rveGeoInertia);
AssembleStressMatrix(*dom->getBilinearElasticTangentTerm(),*dom->getFunctionSpace(),dom->element_begin(),
dom->element_end(),*dom->getBulkGaussIntegrationRule(),*pAssembler,_elementErosionFilter);
}
}
if(needdUdF){
for (int idom=0; idom<domainVector.size(); idom++){
partDomain* dom = domainVector[idom];
if (dom->elementGroupSize()>0){
AssembleBodyForceMatrix(*dom->getBilinearBodyForceTangentTerm(),*dom->getFunctionSpace(),dom->element_begin(),
dom->element_end(),*dom->getBulkGaussIntegrationRule(),*pAssembler,_elementErosionFilter);
}
}
}
//
t= Cpu();
if (_multiscaleFlag == false)
Msg::Info("Begin performing in-system condensation");
int goodSolve = _pAl->condensationSolve(L,vRVE,needdUdF, needdUdG, pAssembler,&homoData->getdUnknowndF(),&homoData->getdUnknowndG());
t = Cpu() -t;
if (_multiscaleFlag == false)
Msg::Info("Done performing in-system condensation (%f s)",t);
fillTangent(L,_elasticState);
if (_multiscaleFlag == false){
_elasticState->getHomogenizedTangentOperator_F_F().print("Elastic tangent operator");
Msg::Info("done extracting elastic tengent operator");
}
};
};
void nonLinearMechSolver::extractdUdFByInSystemCondensation(homogenizedData* homoData){
// extract tangent
_pAl->zeroBodyForceMatrix();
for (int idom=0; idom<domainVector.size(); idom++){
partDomain* dom = domainVector[idom];
if (dom->elementGroupSize()>0){
AssembleBodyForceMatrix(*dom->getBilinearBodyForceTangentTerm(),*dom->getFunctionSpace(),dom->element_begin(),
dom->element_end(),*dom->getBulkGaussIntegrationRule(),*pAssembler,_elementErosionFilter);
}
}
double t= Cpu();
if (_multiscaleFlag == false)
Msg::Info("Begin performing in-system condensationfor dUdF");
int goodSolve = _pAl->condensationdUdF(pAssembler, &homoData->getdUnknowndF());
t = Cpu() -t;
if (_multiscaleFlag == false)
Msg::Info("Done performing in-system condensation (%f s)",t);
};
void nonLinearMechSolver::extractAverageStress(homogenizedData* homoData){
if (_homogenizeStressMethod == VOLUME)
this->extractAverageStressByVolumeIntegral(homoData);
else if (_homogenizeStressMethod == SURFACE)
this->extractAverageStressByCondensation(homoData);
else {
Msg::Error("This method is not implemented");
}
};
void nonLinearMechSolver::extractAverageStressAndTangent(homogenizedData* homoData){
if (_homogenizeTangentMethod == CONDEN or _homogenizeTangentMethod==UNIFIED_CONDEN){
this->extractAveragePropertiesByCondensation(homoData);
}
else if (_homogenizeTangentMethod == PERTURB){
this->extractAveragePropertiesPerturbation(homoData);
}
else if (_homogenizeTangentMethod == INSYSTEMCONDEN){
if (_systemType == DISP_MULT)
{
this->extractAveragePropertiesByInSystemCondensationDISP_MULT(homoData);
}
else
this->extractAveragePropertiesByInSystemCondensation(homoData);
}
else{
Msg::Error("Homogenization tangent method must be correctly defined");
}
// estimate loss of ellipticity
if (_checkFailureOnset){
const STensor43& L = homoData->getHomogenizedTangentOperator_F_F();
double& cr = homoData->getLostOfSolutionUniquenessCriterion();
cr = _lostSolutionUniquenssTolerance - 1.;
double detNLN = 0;
if (_checkWithNormal){
// check lost of solution uniqueness
if (_lostSolutionUniquenssNormal.norm() <=0.){
Msg::Error("can not check failure with zero normal");
}
//
FailureDetection::getLostSolutionUniquenessCriterionFollowingDirection(_dim,L,_lostSolutionUniquenssNormal,detNLN);
}
else{
// the material softening is not allowed in bulk IP
FailureDetection::getLostSolutionUniquenessCriterion(_dim,L,_lostSolutionUniquenssNormal,detNLN);
}
// maximal Cr
if (_maximalLostEllipticityCriterion < detNLN and detNLN > 0.){
_maximalLostEllipticityCriterion = detNLN;
}
if (_maximalLostEllipticityCriterion > 0){
cr = _lostSolutionUniquenssTolerance - detNLN/_maximalLostEllipticityCriterion;
}
}
};
void nonLinearMechSolver::extractAveragePropertiesPerturbation(homogenizedData* homoData){
// extract stress
this->extractAverageStress(homoData);
bool Extract_Qstress = this->computedUdF();
// mesh chracteristic size for perturbation
double elength = 0.;
for (int i=0; i< domainVector.size(); i++){
if (domainVector[i]->elementGroupSize() > 0){
const MElement* ele = (domainVector[0]->element_begin()->second);
double volume = const_cast<MElement*>(ele)->getVolume();
if (_dim == 2){
elength = sqrt(volume);
}
else if (_dim ==3){
elength = pow(volume,1.0/3.0);
}
break;
}
}
//
/** function for compute tangent by perturbation on current state**/
/*
save all computed current data to tmp step
*/
_ipf->copy(IPStateBase::current,IPStateBase::temp);
std::string Aname ="A";
linearSystem<double>* lsys = pAssembler->getLinearSystem(Aname);
nonLinearSystem<double>* nonlsys = dynamic_cast<nonLinearSystem<double>*>(lsys);
nonlsys->copy(IPStateBase::current,IPStateBase::temp);
homogenizedData homoDataPlus(*homoData);
homogenizedData homoDatadUdF(*homoData);
double t= Cpu();
if (_multiscaleFlag == false)
Msg::Info("Begin performing tangent by perturbation");
if (_microBC->getTotalNumberOfMechanicalDofs()> 0){
STensor3 F = _microBC->getFirstOrderKinematicalVariable();
const STensor3& P = homoData->getHomogenizedStress();
for (int i=0; i<_dim; i++){
for (int j=0; j<_dim; j++){
nonlsys->copy(IPStateBase::previous,IPStateBase::current);
/** perturbation in deformation gradient **/
STensor3 Fplus(F);
Fplus(i,j) += _tangentPerturbation;
_microBC->setFirstOrderKinematicalVariable(Fplus);
/** solve perturbated system**/
this->OneStep(0);
/** get homogenized stress in perturbed system **/
this->extractAverageStress(&homoDataPlus);
const STensor3& Pplus = homoDataPlus.getHomogenizedStress();
for (int k=0; k<3; k++){
for (int l=0; l<3; l++){
homoData->getHomogenizedTangentOperator_F_F()(k,l,i,j) = (Pplus(k,l) - P(k,l))/(_tangentPerturbation);
homoDataPlus.getHomogenizedTangentOperator_F_F()(k,l,i,j) = (Pplus(k,l) - P(k,l))/(_tangentPerturbation);
}
}
if (_microBC->getOrder() == 2 and !Extract_Qstress){
// extract stress
const STensor33& Q = homoData->getHomogenizedSecondOrderStress();
const STensor33& Qplus = homoDataPlus.getHomogenizedSecondOrderStress();
for (int k=0; k<3; k++)
for (int l=0; l<3; l++)
for (int m=0; m<3; m++)
homoData->getHomogenizedTangentOperator_G_F()(k,l,m,i,j) = (Qplus(k,l,m) - Q(k,l,m))/(_tangentPerturbation);
}
if (_damageToCohesiveJump){
const SVector3& cjump = homoData->getHomogenizedCohesiveJump();
const SVector3& cjumpplus = homoDataPlus.getHomogenizedCohesiveJump();
for (int k=0; k<3; k++){
homoData->getHomogenizedTangentOperator_CohesiveJump_F()(k,i,j) = (cjumpplus(k) - cjump(k))/(_tangentPerturbation);
}
}
if (_extractIrreversibleEnergy){
const double& irrEnerg = homoData->getIrreversibleEnergy();
const double& irrEnergPlus = homoDataPlus.getIrreversibleEnergy();
homoData->getHomogenizedTangentOperator_IrreversibleEnergy_F()(i,j) = (irrEnergPlus - irrEnerg)/_tangentPerturbation;
}
if (_microBC->getTotalNumberOfConDofs() > 0){
for (int index=0; index < _microBC->getTotalNumberOfConDofs(); index++){
const SVector3& flux = homoData->getHomogenizedConstitutiveExtraDofFlux(index);
const SVector3& fluxPlus = homoDataPlus.getHomogenizedConstitutiveExtraDofFlux(index);
for (int k=0; k<3; k++){
homoData->getHomogenizedTangentOperator_gradT_F(index)(k,i,j) = (fluxPlus(k)-flux(k))/(_tangentPerturbation);
}
const double& mecasrc = homoData->getHomogenizedConstitutiveExtraDofMechanicalSource(index);
const double& mecasrcPlus = homoDataPlus.getHomogenizedConstitutiveExtraDofMechanicalSource(index);
homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_F(index)(i,j) = (mecasrcPlus-mecasrc)/(_tangentPerturbation);
}
}
if (_microBC->getTotalNumberOfNonConDofs() > 0){
for (int index=0; index < _microBC->getTotalNumberOfNonConDofs(); index++){
const SVector3& flux = homoData->getHomogenizedNonConstitutiveExtraDofFlux(index);
const SVector3& fluxPlus = homoDataPlus.getHomogenizedNonConstitutiveExtraDofFlux(index);
for (int k=0; k<3; k++){
homoData->getHomogenizedTangentOperator_gradV_F(index)(k,i,j) = (fluxPlus(k)-flux(k))/(_tangentPerturbation);
}
}
}
}
}
/** back micro BC as before perturbation**/
_microBC->setFirstOrderKinematicalVariable(F);
if (_microBC->getOrder() == 2){
if(Extract_Qstress){
nonlsys->copy(IPStateBase::previous,IPStateBase::current);
this->OneStep(0);
this->extractAveragePropertiesByInSystemCondensation(&homoDatadUdF);
nonlsys->copy(IPStateBase::previous,IPStateBase::current);
_ipf->setdFmdFM(homoDatadUdF.getdUnknowndF(), IPStateBase::current);
this->OneStep(0);
this->extractAverageStress(homoData);
for (int i=0; i<_dim; i++){
for (int j=0; j<_dim; j++){
nonlsys->copy(IPStateBase::previous,IPStateBase::current);
_ipf->setdFmdFM(homoDatadUdF.getdUnknowndF(), IPStateBase::current);
/** perturbation in deformation gradient **/
STensor3 Fplus(F);
Fplus(i,j) += _tangentPerturbation;
_microBC->setFirstOrderKinematicalVariable(Fplus);
/** solve perturbated system**/
this->OneStep(0);
/** get homogenized stress in perturbed system **/
this->extractAverageStress(&homoDataPlus);
// extract stress
const STensor33& Q = homoData->getHomogenizedSecondOrderStress();
const STensor33& Qplus = homoDataPlus.getHomogenizedSecondOrderStress();
for (int k=0; k<3; k++)
for (int l=0; l<3; l++)
for (int m=0; m<3; m++)
homoData->getHomogenizedTangentOperator_G_F()(k,l,m,i,j) = (Qplus(k,l,m) - Q(k,l,m))/(_tangentPerturbation);
}
}
}
/**perturbation in gradient of deformation gradient **/
STensor33 G = _microBC->getSecondOrderKinematicalVariable();
double secondpert = _tangentPerturbation/elength;
for (int i=0; i<_dim; i++){
for (int j=0; j<_dim; j++){
for (int s=0; s<=j; s++){
nonlsys->copy(IPStateBase::previous,IPStateBase::current);
_ipf->setdFmdFM(homoDatadUdF.getdUnknowndF(), IPStateBase::current);
STensor33 Gplus(G);
Gplus(i,j,s) += secondpert;
Gplus(i,s,j) += secondpert;
_microBC->setSecondOrderKinematicalVariable(Gplus);
/** solve perturbed system**/
this->OneStep(0);
/** get homogenized stress in perturbed system **/
this->extractAverageStress(&homoDataPlus);
//
const STensor3& P = homoData->getHomogenizedStress();
const STensor3& Pplus = homoDataPlus.getHomogenizedStress();
for (int k=0; k<3; k++){
for (int l=0; l<3; l++){
homoData->getHomogenizedTangentOperator_F_G()(k,l,i,j,s) = (Pplus(k,l) - P(k,l))/(2.*secondpert);
homoData->getHomogenizedTangentOperator_F_G()(k,l,i,s,j) = homoData->getHomogenizedTangentOperator_F_G()(k,l,i,j,s);
}
}
const STensor33& Q = homoData->getHomogenizedSecondOrderStress();
const STensor33& Qplus = homoDataPlus.getHomogenizedSecondOrderStress();
for (int k=0; k<3; k++){
for (int l=0; l<3; l++){
for (int m=0; m<3; m++){
homoData->getHomogenizedTangentOperator_G_G()(k,l,m,i,j,s) = (Qplus(k,l,m) - Q(k,l,m))/(2.*secondpert);
homoData->getHomogenizedTangentOperator_G_G()(k,l,m,i,s,j) = homoData->getHomogenizedTangentOperator_G_G()(k,l,m,i,j,s);
}
}
}
if (_damageToCohesiveJump){
const SVector3& cjump = homoData->getHomogenizedCohesiveJump();
const SVector3& cjumpplus = homoDataPlus.getHomogenizedCohesiveJump();
for (int k=0; k<3; k++){
homoData->getHomogenizedTangentOperator_CohesiveJump_G()(k,i,j,s) = (cjumpplus(k) - cjump(k))/(2.*secondpert);
homoData->getHomogenizedTangentOperator_CohesiveJump_G()(k,i,s,j) = homoData->getHomogenizedTangentOperator_CohesiveJump_G()(k,i,j,s);
}
}
if (_extractIrreversibleEnergy){
const double& irrEnerg = homoData->getIrreversibleEnergy();
const double& irrEnergPlus = homoDataPlus.getIrreversibleEnergy();
homoData->getHomogenizedTangentOperator_IrreversibleEnergy_G()(i,j,s) = (irrEnergPlus - irrEnerg)/(2.*secondpert);
homoData->getHomogenizedTangentOperator_IrreversibleEnergy_G()(i,s,j) = homoData->getHomogenizedTangentOperator_IrreversibleEnergy_G()(i,j,s);
}
if (_microBC->getTotalNumberOfConDofs() > 0){
for (int index=0; index < _microBC->getTotalNumberOfConDofs(); index++){
const SVector3& flux = homoData->getHomogenizedConstitutiveExtraDofFlux(index);
const SVector3& fluxPlus = homoDataPlus.getHomogenizedConstitutiveExtraDofFlux(index);
for (int k=0; k<3; k++){
homoData->getHomogenizedTangentOperator_gradT_G(index)(k,i,j,s) = (fluxPlus(k)-flux(k))/(2.*secondpert);
homoData->getHomogenizedTangentOperator_gradT_G(index)(k,i,s,j) = homoData->getHomogenizedTangentOperator_gradT_G(index)(k,i,j,s);
}
const double& mecasrc = homoData->getHomogenizedConstitutiveExtraDofMechanicalSource(index);
const double& mecasrcPlus = homoDataPlus.getHomogenizedConstitutiveExtraDofMechanicalSource(index);
homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_G(index)(i,j,s) = (mecasrcPlus-mecasrc)/(2.*secondpert);
homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_G(index)(i,s,j) = homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_G(index)(i,j,s);
}
}
if (_microBC->getTotalNumberOfNonConDofs() > 0){
for (int index=0; index < _microBC->getTotalNumberOfNonConDofs(); index++){
const SVector3& flux = homoData->getHomogenizedNonConstitutiveExtraDofFlux(index);
const SVector3& fluxPlus = homoDataPlus.getHomogenizedNonConstitutiveExtraDofFlux(index);
for (int k=0; k<3; k++){
homoData->getHomogenizedTangentOperator_gradV_G(index)(k,i,j,s) = (fluxPlus(k)-flux(k))/(2.*secondpert);
homoData->getHomogenizedTangentOperator_gradV_G(index)(k,i,s,j) = homoData->getHomogenizedTangentOperator_gradV_G(index)(k,i,j,s);
}
}
}
}
}
}
_microBC->setSecondOrderKinematicalVariable(G);
}
}
if (_microBC->getTotalNumberOfConDofs() > 0){
for (int index = 0; index < _microBC->getTotalNumberOfConDofs(); index ++){
SVector3 gradT = _microBC->getConstitutiveExtraDofDiffusionKinematicalVariable(index);
double gradTpert = _tangentPerturbation*(_microBC->getInitialConstitutiveExtraDofDiffusionValue(index))/elength;
for (int i=0; i<_dim; i++){
nonlsys->copy(IPStateBase::previous,IPStateBase::current);
SVector3 gradTplus(gradT);
gradTplus(i) += gradTpert;
_microBC->setConstitutiveExtraDofDiffusionKinematicalVariable(index,gradTplus);
/** solve perturbed system**/
this->OneStep(0);
/** get homogenized stress in perturbed system **/
this->extractAverageStress(&homoDataPlus);
if (_microBC->getTotalNumberOfMechanicalDofs() > 0){
const STensor3& P = homoData->getHomogenizedStress();
const STensor3& Pplus = homoDataPlus.getHomogenizedStress();
for (int p=0; p<3; p++){
for (int q=0; q<3; q++){
homoData->getHomogenizedTangentOperator_F_gradT(index)(p,q,i) = (Pplus(p,q)- P(p,q))/(gradTpert);
}
}
if (_microBC->getOrder() == 2){
const STensor33& Q = homoData->getHomogenizedSecondOrderStress();
const STensor33& Qplus = homoDataPlus.getHomogenizedSecondOrderStress();
for (int p=0; p<3; p++)
for (int q=0; q<3; q++)
for (int r=0; r<3; r++)
homoData->getHomogenizedTangentOperator_G_gradT(index)(p,q,r,i) = (Qplus(p,q,r) - Q(p,q,r))/(gradTpert);
}
if (_damageToCohesiveJump){
const SVector3& cjump = homoData->getHomogenizedCohesiveJump();
const SVector3& cjumpplus = homoDataPlus.getHomogenizedCohesiveJump();
for (int p=0; p<3; p++){
homoData->getHomogenizedTangentOperator_CohesiveJump_gradT(index)(p,i) = (cjumpplus(p) - cjump(p))/(gradTpert);
}
}
if (_extractIrreversibleEnergy){
const double& irrEnerg = homoData->getIrreversibleEnergy();
const double& irrEnergPlus = homoDataPlus.getIrreversibleEnergy();
homoData->getHomogenizedTangentOperator_IrreversibleEnergy_gradT(index)(i) = (irrEnergPlus-irrEnerg)/gradTpert;
}
}
for (int fluxIndex = 0; fluxIndex < _microBC->getTotalNumberOfConDofs(); fluxIndex ++){
const SVector3& flux = homoData->getHomogenizedConstitutiveExtraDofFlux(fluxIndex);
const SVector3& fluxPlus = homoDataPlus.getHomogenizedConstitutiveExtraDofFlux(fluxIndex);
for (int p=0; p<3; p++){
homoData->getHomogenizedTangentOperator_gradT_gradT(fluxIndex,index)(p,i) = (fluxPlus(p) - flux(p))/(gradTpert);
}
const double& source = homoData->getHomogenizedConstitutiveExtraDofMechanicalSource(fluxIndex);
const double& sourcePlus = homoDataPlus.getHomogenizedConstitutiveExtraDofMechanicalSource(fluxIndex);
homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_gradT(fluxIndex,index)(i) = (sourcePlus-source)/gradTpert;
};
for (int fluxIndex = 0; fluxIndex < _microBC->getTotalNumberOfNonConDofs(); fluxIndex ++){
const SVector3& flux = homoData->getHomogenizedNonConstitutiveExtraDofFlux(fluxIndex);
const SVector3& fluxPlus = homoDataPlus.getHomogenizedNonConstitutiveExtraDofFlux(fluxIndex);
for (int p=0; p<3; p++){
homoData->getHomogenizedTangentOperator_gradV_gradT(fluxIndex,index)(p,i) = (fluxPlus(p) - flux(p))/(gradTpert);
}
}
_microBC->setConstitutiveExtraDofDiffusionKinematicalVariable(index,gradT);
}
// perturtabtion on T
const double T = _microBC->getConstitutiveExtraDofDiffusionConstantVariable(index);
double Tpert = _tangentPerturbation*(_microBC->getInitialConstitutiveExtraDofDiffusionValue(index));
nonlsys->copy(IPStateBase::previous,IPStateBase::current);
double Tplus = T+Tpert;
_microBC->setConstitutiveExtraDofDiffusionConstantVariable(index,Tplus);
/** solve perturbed system**/
this->OneStep(0);
/** get homogenized stress in perturbed system **/
this->extractAverageStress(&homoDataPlus);
if (_microBC->getTotalNumberOfMechanicalDofs() > 0){
const STensor3& P = homoData->getHomogenizedStress();
const STensor3& Pplus = homoDataPlus.getHomogenizedStress();
for (int p=0; p<3; p++){
for (int q=0; q<3; q++){
homoData->getHomogenizedTangentOperator_F_T(index)(p,q) = (Pplus(p,q)- P(p,q))/(Tpert);
}
}
if (_microBC->getOrder() == 2){
const STensor33& Q = homoData->getHomogenizedSecondOrderStress();
const STensor33& Qplus = homoDataPlus.getHomogenizedSecondOrderStress();
for (int p=0; p<3; p++)
for (int q=0; q<3; q++)
for (int r=0; r<3; r++)
homoData->getHomogenizedTangentOperator_G_T(index)(p,q,r) = (Qplus(p,q,r) - Q(p,q,r))/(Tpert);
}
if (_damageToCohesiveJump){
const SVector3& cjump = homoData->getHomogenizedCohesiveJump();
const SVector3& cjumpplus = homoDataPlus.getHomogenizedCohesiveJump();
for (int p=0; p<3; p++){
homoData->getHomogenizedTangentOperator_CohesiveJump_T(index)(p) = (cjumpplus(p) - cjump(p))/(Tpert);
}
}
if (_extractIrreversibleEnergy){
const double& irrEnerg = homoData->getIrreversibleEnergy();
const double& irrEnergPlus = homoDataPlus.getIrreversibleEnergy();
homoData->getHomogenizedTangentOperator_IrreversibleEnergy_T(index) = (irrEnergPlus-irrEnerg)/Tpert;
}
}
for (int fluxIndex = 0; fluxIndex < _microBC->getTotalNumberOfConDofs(); fluxIndex ++){
const SVector3& flux = homoData->getHomogenizedConstitutiveExtraDofFlux(fluxIndex);
const SVector3& fluxPlus = homoDataPlus.getHomogenizedConstitutiveExtraDofFlux(fluxIndex);
for (int p=0; p<3; p++){
homoData->getHomogenizedTangentOperator_gradT_T(fluxIndex,index)(p) = (fluxPlus(p) - flux(p))/(Tpert);
}
const double& source = homoData->getHomogenizedConstitutiveExtraDofMechanicalSource(fluxIndex);
const double& sourcePlus = homoDataPlus.getHomogenizedConstitutiveExtraDofMechanicalSource(fluxIndex);
homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_T(fluxIndex,index) = (sourcePlus-source)/Tpert;
};
for (int fluxIndex = 0; fluxIndex < _microBC->getTotalNumberOfNonConDofs(); fluxIndex ++){
const SVector3& flux = homoData->getHomogenizedNonConstitutiveExtraDofFlux(fluxIndex);
const SVector3& fluxPlus = homoDataPlus.getHomogenizedNonConstitutiveExtraDofFlux(fluxIndex);
for (int p=0; p<3; p++){
homoData->getHomogenizedTangentOperator_gradV_T(fluxIndex,index)(p) = (fluxPlus(p) - flux(p))/(Tpert);
}
}
_microBC->setConstitutiveExtraDofDiffusionConstantVariable(index,T);
}
}
if (_microBC->getTotalNumberOfNonConDofs() > 0){
for (int index = 0; index < _microBC->getTotalNumberOfNonConDofs(); index ++){
SVector3 gradV = _microBC->getNonConstitutiveExtraDofDiffusionKinematicalVariable(index);
double gradVpert = (1+gradV.norm())*_tangentPerturbation;
for (int i=0; i<_dim; i++){
nonlsys->copy(IPStateBase::previous,IPStateBase::current);
SVector3 gradVplus(gradV);
gradVplus(i) += gradVpert;
_microBC->setNonConstitutiveExtraDofDiffusionKinematicalVariable(index,gradVplus);
/** solve perturbed system**/
this->OneStep(0);
/** get homogenized stress in perturbed system **/
this->extractAverageStress(&homoDataPlus);
if (_microBC->getTotalNumberOfMechanicalDofs() > 0){
const STensor3& P = homoData->getHomogenizedStress();
const STensor3& Pplus = homoDataPlus.getHomogenizedStress();
for (int p=0; p<3; p++){
for (int q=0; q<3; q++){
homoData->getHomogenizedTangentOperator_F_gradV(index)(p,q,i) = (Pplus(p,q)- P(p,q))/(gradVpert);
}
}
if (_microBC->getOrder() == 2){
const STensor33& Q = homoData->getHomogenizedSecondOrderStress();
const STensor33& Qplus = homoDataPlus.getHomogenizedSecondOrderStress();
for (int p=0; p<3; p++)
for (int q=0; q<3; q++)
for (int r=0; r<3; r++)
homoData->getHomogenizedTangentOperator_G_gradV(index)(p,q,r,i) = (Qplus(p,q,r) - Q(p,q,r))/(gradVpert);
}
if (_damageToCohesiveJump){
const SVector3& cjump = homoData->getHomogenizedCohesiveJump();
const SVector3& cjumpplus = homoDataPlus.getHomogenizedCohesiveJump();
for (int p=0; p<3; p++){
homoData->getHomogenizedTangentOperator_CohesiveJump_gradV(index)(p,i) = (cjumpplus(p) - cjump(p))/(gradVpert);
}
}
if (_extractIrreversibleEnergy){
const double& irrEnerg = homoData->getIrreversibleEnergy();
const double& irrEnergPlus = homoDataPlus.getIrreversibleEnergy();
homoData->getHomogenizedTangentOperator_IrreversibleEnergy_gradV(index)(i) = (irrEnergPlus-irrEnerg)/gradVpert;
}
}
for (int fluxIndex = 0; fluxIndex < _microBC->getTotalNumberOfConDofs(); fluxIndex ++){
const SVector3& flux = homoData->getHomogenizedConstitutiveExtraDofFlux(fluxIndex);
const SVector3& fluxPlus = homoDataPlus.getHomogenizedConstitutiveExtraDofFlux(fluxIndex);
for (int p=0; p<3; p++){
homoData->getHomogenizedTangentOperator_gradT_gradV(fluxIndex,index)(p,i) = (fluxPlus(p) - flux(p))/(gradVpert);
}
const double& source = homoData->getHomogenizedConstitutiveExtraDofMechanicalSource(fluxIndex);
const double& sourcePlus = homoDataPlus.getHomogenizedConstitutiveExtraDofMechanicalSource(fluxIndex);
homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_gradV(fluxIndex,index)(i) = (sourcePlus-source)/gradVpert;
};
for (int fluxIndex = 0; fluxIndex < _microBC->getTotalNumberOfNonConDofs(); fluxIndex ++){
const SVector3& flux = homoData->getHomogenizedNonConstitutiveExtraDofFlux(fluxIndex);
const SVector3& fluxPlus = homoDataPlus.getHomogenizedNonConstitutiveExtraDofFlux(fluxIndex);
for (int p=0; p<3; p++){
homoData->getHomogenizedTangentOperator_gradV_gradV(fluxIndex,index)(p,i) = (fluxPlus(p) - flux(p))/(gradVpert);
}
}
_microBC->setNonConstitutiveExtraDofDiffusionKinematicalVariable(index,gradV);
}
}
}
t = Cpu() -t;
if (_multiscaleFlag == false)
Msg::Info("Done performing tangent by perturbation (%f s)",t);;
/**back to current step from temp state **/
_ipf->copy(IPStateBase::temp,IPStateBase::current);
nonlsys->copy(IPStateBase::temp,IPStateBase::current);
}
void nonLinearMechSolver::computeDensity(){
_rho = 0;
for (int i=0; i<domainVector.size(); i++){
partDomain* dom = domainVector[i];
// only on volumic domain
if (dom->elementGroupSize()>0){
double rhodom = dom->getMaterialLaw()->density();
double voldom =dom->computeVolumeDomain(_ipf);
_rho += (voldom*rhodom);
}
};
double vtotal = this->getRVEVolume();
_rho /= vtotal;
};
stiffnessCondensation* nonLinearMechSolver::createStiffnessCondensation(const bool sflag, const bool tflag){
stiffnessCondensation* stiffCon = NULL;
/**condensation require **/
if (_pAl == NULL){
_pAl = new pbcAlgorithm(this);
};
if (!_pAl->isSplittedDof()) _pAl->splitDofs();
if (_homogenizeTangentMethod == UNIFIED_CONDEN){
#if defined(HAVE_PETSC)
Msg::Info("stiffnessCondensationPETSc is used for nonLinearMixedBC");
stiffCon = new stiffnessCondensationPETSc(pAssembler,_pAl,sflag,tflag);
#else
Msg::Error("Petsc must be used");
#endif // HAVE_PETSC
}
else if (_homogenizeTangentMethod == CONDEN){
if (dynamic_cast<nonLinearMinimalKinematicBC*>(_microBC)){
#if defined(HAVE_PETSC)
Msg::Info("stiffnessCondensationPETScWithoutDirectConstraints is used for nonLinearMinimalKinematicBC");
stiffCon = new stiffnessCondensationPETScWithoutDirectConstraints(pAssembler,_pAl,sflag,tflag);
#else
Msg::Error("Petsc must be used");
#endif // HAVE_PETSC
}
else if (dynamic_cast<nonLinearDisplacementBC*>(_microBC)){
#if defined(HAVE_PETSC)
Msg::Info("stiffnessCondensationLDBCPETSc is used for nonLinearDisplacementBC");
stiffCon = new stiffnessCondensationLDBCPETSc(pAssembler,_pAl,sflag,tflag);
#else
Msg::Error("Petsc must be used");
#endif // HAVE_PETSC
}
else if (dynamic_cast<nonLinearPeriodicBC*>(_microBC)){
nonLinearPeriodicBC* pbc = dynamic_cast<nonLinearPeriodicBC*>(_microBC);
if (_pAl->getSplittedDof()->sizeOfVirtualDof() >0 and pbc->getOrder()==1){
#if defined(HAVE_PETSC)
Msg::Info("interpolationStiffnessCondensationPETSC is used for nonLinearPeriodicBC");
stiffCon = new interpolationStiffnessCondensationPETSC(pAssembler,_pAl,sflag,tflag);
#else
Msg::Error("Petsc must be used");
#endif
}
else if ((pbc->getPBCMethod() == nonLinearPeriodicBC::LIM) and (pbc->getMaxDegree() == 1)){
#if defined(HAVE_PETSC)
Msg::Info("stiffnessCondensationLDBCPETSc is used for nonLinearPeriodicBC as order = 1");
stiffCon = new stiffnessCondensationLDBCPETSc(pAssembler,_pAl,sflag,tflag);
#else
Msg::Error("Petsc must be used");
#endif
}
else{
#if defined(HAVE_PETSC)
if (_pAl->getNumberDirectConstraints()>0){
Msg::Info("stiffnessCondensationPETScWithDirectConstraints is used for nonLinearPeriodicBC");
stiffCon = new stiffnessCondensationPETScWithDirectConstraints(pAssembler,_pAl,sflag,tflag);
}
else{
Msg::Info("stiffnessCondensationPETScWithoutDirectConstraints is used for nonLinearPeriodicBC");
stiffCon = new stiffnessCondensationPETScWithoutDirectConstraints(pAssembler,_pAl,sflag,tflag);
}
#else
if (_pAl->getNumberDirectConstraints()>0){
Msg::Info("stiffnessCondensationFullMatrixWithDirectConstraints is used for nonLinearPeriodicBC");
stiffCon = new stiffnessCondensationFullMatrixWithDirectConstraints(pAssembler,_pAl,sflag,tflag);
}
else{
Msg::Error("Petsc must be used");
}
#endif // HAVE_PETSC
}
}
else if (dynamic_cast<nonLinearMixedBC*>(_microBC)){
#if defined(HAVE_PETSC)
if (_pAl->getNumberDirectConstraints()>0){
Msg::Info("stiffnessCondensationPETScWithDirectConstraints is used for nonLinearMixedBC");
stiffCon = new stiffnessCondensationPETScWithDirectConstraints(pAssembler,_pAl,sflag,tflag);
}
else{
Msg::Info("stiffnessCondensationPETScWithoutDirectConstraints is used for nonLinearMixedBC");
stiffCon = new stiffnessCondensationPETScWithoutDirectConstraints(pAssembler,_pAl,sflag,tflag);
}
#else
if (_pAl->getNumberDirectConstraints()>0){
Msg::Info("stiffnessCondensationFullMatrixWithDirectConstraints is used for nonLinearMixedBC");
stiffCon = new stiffnessCondensationFullMatrixWithDirectConstraints(pAssembler,_pAl,sflag,tflag);
}
else{
Msg::Error("Petsc must be used");
}
#endif // HAVE_PETSC
}
else{
Msg::Error("Micro BC type must be defined");
}
}
//
if (stiffCon == NULL){
Msg::Warning("only homogenized stress is computed by surface integral");
#if defined(HAVE_PETSC)
Msg::Info("stiffnessCondensationPETSc is used");
stiffCon = new stiffnessCondensationPETSc(pAssembler,_pAl,sflag,tflag);
#else
Msg::Error("Petsc must be used");
#endif // HAVE_PETSC
}
stiffCon->setSplittedDofSystem(_pAl);
if (tflag) {
_pAl->getSplittedDof()->allocateSplittedMatrix();
// preallocate
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain* dom = *itdom;
SparsityDofsSplittedStiffness(*(dom->getFunctionSpace()), dom->element_begin(), dom->element_end(),*_pAl->getSplittedDof());
dgPartDomain* dgdom = dynamic_cast<dgPartDomain*>(dom);
if (dgdom!=NULL){
SparsityDofsSplittedStiffness(*(dgdom->getFunctionSpace()), dgdom->gi->begin(), dgdom->gi->end(),*_pAl->getSplittedDof());
}
}
};
return stiffCon;
};
void nonLinearMechSolver::fillTangent(const fullMatrix<double>& L, homogenizedData* homoData){
// stress vector is arranged by this order
// S = [P Q FD fluxT1 mecaSrc1 -- fluxTn mecaSrcn fluxV1 --- fluxVm]
// K = [F G gradT1 T1 --- gradTn Tn gradV1 --- gradVm] see nonLinearMicroBC::getKinematicVector
// from dS/dK --> all tangents are explicitly given
// mechanics part
int atRow = 0;
if (_microBC->getTotalNumberOfMechanicalDofs() > 0){
for (int row = atRow; row<atRow+9; row++){
int i,j;
Tensor23::getIntsFromIndex(row-atRow,i,j);
// tangent P-F
int atCol = 0;
for (int col = atCol; col< atCol+9; col++){
int k,l;
Tensor23::getIntsFromIndex(col-atCol,k,l);
homoData->getHomogenizedTangentOperator_F_F()(i,j,k,l) = L(row,col);
}
atCol+= 9;
// tangent P-secondorder
if (_microBC->getOrder() == 2){
for (int col =atCol; col< atCol+27; col++){
int p,q,r;
Tensor33::getIntsFromIndex(col-atCol,p,q,r);
homoData->getHomogenizedTangentOperator_F_G()(i,j,p,q,r) = L(row,col);
};
atCol += 27;
}
if (_microBC->getTotalNumberOfConDofs()>0){
for (int index=0; index < _microBC->getTotalNumberOfConDofs(); index++){
// tangent P-GradextraDof
for (int col = atCol; col< atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_F_gradT(index)(i,j,p) = L(row,col);
}
atCol += 3;
// tangent P-ExtraDof
homoData->getHomogenizedTangentOperator_F_T(index)(i,j) =L(row,atCol);
atCol += 1;
}
};
if (_microBC->getTotalNumberOfNonConDofs() > 0){
for (int index=0; index < _microBC->getTotalNumberOfNonConDofs(); index++){
// tangent P-GradextraDof
for (int col = atCol; col< atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_F_gradV(index)(i,j,p) = L(row,col);
}
atCol += 3;
}
}
};
atRow += 9;
if (_microBC->getOrder() == 2){
// second order stress
for (int row = atRow; row<atRow+27; row++){
int i,j,k;
Tensor33::getIntsFromIndex(row-atRow,i,j,k);
// tangent Q-F
int atCol = 0;
for (int col = atCol; col<atCol+9; col++){
int p,q;
Tensor23::getIntsFromIndex(col-atCol,p,q);
homoData->getHomogenizedTangentOperator_G_F()(i,j,k,p,q) = L(row,col);
}
atCol+= 9;
// tangent Q-Q;
for (int col=atCol; col < atCol+27; col++){
int p,q,r;
Tensor33::getIntsFromIndex(col-atCol,p,q,r);
homoData->getHomogenizedTangentOperator_G_G()(i,j,k,p,q,r) = L(row,col);
}
atCol += 27;
if (_microBC->getTotalNumberOfConDofs()>0){
for (int index=0; index < _microBC->getTotalNumberOfConDofs(); index++){
// tangent P-GradextraDof
for (int col = atCol; col< atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_G_gradT(index)(i,j,k,p) = L(row,col);
}
atCol += 3;
// tangent P-ExtraDof
homoData->getHomogenizedTangentOperator_G_T(index)(i,j,k) =L(row,atCol);
atCol += 1;
}
};
if (_microBC->getTotalNumberOfNonConDofs() > 0){
for (int index=0; index < _microBC->getTotalNumberOfNonConDofs(); index++){
// tangent P-GradextraDof
for (int col = atCol; col< atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_G_gradV(index)(i,j,k,p) = L(row,col);
}
atCol += 3;
}
}
};
atRow += 27;
}
if (_extractIrreversibleEnergy and (_homogenizeTangentMethod == INSYSTEMCONDEN)){
for (int row = atRow; row<atRow+1; row++){
// tangent FD-F
int atCol = 0;
for (int col = atCol; col< atCol+9; col++){
int k,l;
Tensor23::getIntsFromIndex(col-atCol,k,l);
homoData->getHomogenizedTangentOperator_IrreversibleEnergy_F()(k,l) = L(row,col);
}
atCol+= 9;
// tangent FD-G
if (_microBC->getOrder() == 2){
for (int col = atCol; col< atCol+27; col++){
int p,q,r;
Tensor33::getIntsFromIndex(col-atCol,p,q,r);
homoData->getHomogenizedTangentOperator_IrreversibleEnergy_G()(p,q,r) = L(row,col);
}
atCol+= 27;
}
if (_microBC->getTotalNumberOfConDofs()>0){
for (int index=0; index < _microBC->getTotalNumberOfConDofs(); index++){
// tangent P-GradextraDof
for (int col = atCol; col< atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_IrreversibleEnergy_gradT(index)(p) = L(row,col);
}
atCol += 3;
// tangent P-ExtraDof
homoData->getHomogenizedTangentOperator_IrreversibleEnergy_T(index) =L(row,atCol);
atCol += 1;
}
};
if (_microBC->getTotalNumberOfNonConDofs() > 0){
for (int index=0; index < _microBC->getTotalNumberOfNonConDofs(); index++){
// tangent P-GradextraDof
for (int col = atCol; col< atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_IrreversibleEnergy_gradV(index)(p) = L(row,col);
}
atCol += 3;
}
}
}
atRow += 1;
}
// this tangent is only computed by using option INSYSTEMCONDEN
if (_damageToCohesiveJump and (_homogenizeTangentMethod == INSYSTEMCONDEN)){
// first order damage only
double Vd = homoData->getActiveDissipationVolume();
double vRve = this->getRVEVolume();
double fact = vRve/Vd;
for (int row = atRow; row<atRow+9; row++){
int i,j;
Tensor23::getIntsFromIndex(row-atRow,i,j);
// tangent FD-F
int atCol = 0;
for (int col = atCol; col< atCol+9; col++){
int k,l;
Tensor23::getIntsFromIndex(col-atCol,k,l);
homoData->getHomogenizedTangentOperator_ActiveDissipationDeformationGradient_F()(i,j,k,l) = fact*L(row,col);
}
atCol+= 9;
// tangent FD-G
if (_microBC->getOrder() == 2){
for (int col = atCol; col< atCol+27; col++){
int p,q,r;
Tensor33::getIntsFromIndex(col-atCol,p,q,r);
homoData->getHomogenizedTangentOperator_ActiveDissipationDeformationGradient_G()(i,j,p,q,r) = fact*L(row,col);
}
atCol+= 27;
}
if (_microBC->getTotalNumberOfConDofs()>0){
for (int index=0; index < _microBC->getTotalNumberOfConDofs(); index++){
// tangent P-GradextraDof
for (int col = atCol; col< atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_ActiveDissipationDeformationGradient_gradT(index)(i,j,p) = fact*L(row,col);
}
atCol += 3;
// tangent P-ExtraDof
homoData->getHomogenizedTangentOperator_ActiveDissipationDeformationGradient_T(index)(i,j) = fact*L(row,atCol);
atCol += 1;
}
};
if (_microBC->getTotalNumberOfNonConDofs() > 0){
for (int index=0; index < _microBC->getTotalNumberOfNonConDofs(); index++){
// tangent P-GradextraDof
for (int col = atCol; col< atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_ActiveDissipationDeformationGradient_gradV(index)(i,j,p) = fact*L(row,col);
}
atCol += 3;
}
}
}
atRow += 9;
}
}
if (_microBC->getTotalNumberOfConDofs() >0){
for (int index=0; index < _microBC->getTotalNumberOfConDofs(); index++){
for (int row = atRow; row<atRow+3; row++){
int i;
Tensor13::getIntsFromIndex(row-atRow, i);
int atCol = 0;
if (_microBC->getTotalNumberOfMechanicalDofs() > 0){
// // gradExtraDof - P
for (int col = atCol; col<atCol+9; col++){
int p,q;
Tensor23::getIntsFromIndex(col-atCol,p,q);
homoData->getHomogenizedTangentOperator_gradT_F(index)(i,p,q) = L(row,col);
}
atCol += 9;
// grad ExtraDof- Q --> need to complete
if (_microBC->getOrder() == 2){
for (int col = atCol; col<atCol+27; col++){
int p,q,r;
Tensor33::getIntsFromIndex(col-atCol,p,q,r);
homoData->getHomogenizedTangentOperator_gradT_G(index)(i,p,q,r) = L(row,col);
}
atCol += 27;
}
}
for (int fieldInx = 0; fieldInx < _microBC->getTotalNumberOfConDofs(); fieldInx++){
// gradExtraDOf- grad ExtraDof
for (int col = atCol; col < atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_gradT_gradT(index,fieldInx)(i,p) = L(row,col);
}
atCol += 3;
// gradExtraDof- ExtraDof
homoData->getHomogenizedTangentOperator_gradT_T(index,fieldInx)(i) = L(row,atCol);
atCol += 1;
}
if (_microBC->getTotalNumberOfNonConDofs() > 0){
for (int fieldInx = 0; fieldInx < _microBC->getTotalNumberOfNonConDofs(); fieldInx++){
for (int col = atCol; col < atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_gradT_gradV(index,fieldInx)(i,p) = L(row,col);
}
atCol += 3;
}
}
};
atRow+=3;
if (_homogenizeTangentMethod == INSYSTEMCONDEN){
// for mechanical source
for (int row = atRow; row<atRow+1; row++){
// mecasource - P
int atCol = 0;
if (_microBC->getTotalNumberOfMechanicalDofs() > 0){
for (int col = atCol; col<atCol+9; col++){
int p,q;
Tensor23::getIntsFromIndex(col-atCol,p,q);
homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_F(index)(p,q) = L(row,col);
}
atCol += 9;
// grad ExtraDof- Q --> need to complete
if (_microBC->getOrder() == 2){
for (int col = atCol; col<atCol+27; col++){
int p,q,r;
Tensor33::getIntsFromIndex(col-atCol,p,q,r);
homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_G(index)(p,q,r) = L(row,col);
}
atCol += 9;
}
}
// mecasource- grad ExtraDof
for (int fieldInx = 0; fieldInx < _microBC->getTotalNumberOfConDofs(); fieldInx++){
// grad ExtraDof
for (int col = atCol; col < atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_gradT(index,fieldInx)(p) = L(row,col);
}
atCol += 3;
// - ExtraDof
homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_T(index,fieldInx) = L(row,atCol);
atCol += 1;
}
if (_microBC->getTotalNumberOfNonConDofs() > 0){
for (int fieldInx = 0; fieldInx < _microBC->getTotalNumberOfNonConDofs(); fieldInx++){
// grad nonConExtraDof
for (int col = atCol; col < atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_ConstitutiveExtraDofMechanicalSource_gradV(index,fieldInx)(p) = L(row,col);
}
atCol += 3;
}
}
};
atRow+=1;
};
}
}
if (_microBC->getTotalNumberOfNonConDofs() > 0){
for (int index=0; index < _microBC->getTotalNumberOfNonConDofs(); index++){
for (int row = atRow; row<atRow+3; row++){
int i;
Tensor13::getIntsFromIndex(row-atRow, i);
int atCol = 0;
if (_microBC->getTotalNumberOfMechanicalDofs() > 0){
// // gradExtraDof - P
for (int col = atCol; col<atCol+9; col++){
int p,q;
Tensor23::getIntsFromIndex(col-atCol,p,q);
homoData->getHomogenizedTangentOperator_gradV_F(index)(i,p,q) = L(row,col);
}
atCol += 9;
// grad ExtraDof- Q --> need to complete
if (_microBC->getOrder() == 2){
for (int col = atCol; col<atCol+27; col++){
int p,q,r;
Tensor33::getIntsFromIndex(col-atCol,p,q,r);
homoData->getHomogenizedTangentOperator_gradV_G(index)(i,p,q,r) = L(row,col);
}
atCol += 27;
}
}
if (_microBC->getTotalNumberOfConDofs() > 0){
for (int fieldInx = 0; fieldInx < _microBC->getTotalNumberOfConDofs(); fieldInx++){
// gradExtraDOf- grad ExtraDof
for (int col = atCol; col < atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_gradV_gradT(index,fieldInx)(i,p) = L(row,col);
}
atCol += 3;
// gradExtraDof- ExtraDof
homoData->getHomogenizedTangentOperator_gradV_T(index,fieldInx)(i) = L(row,atCol);
atCol += 1;
}
}
for (int fieldInx = 0; fieldInx < _microBC->getTotalNumberOfNonConDofs(); fieldInx++){
// gradExtraDOf- grad ExtraDof
for (int col = atCol; col < atCol+3; col++){
int p;
Tensor13::getIntsFromIndex(col-atCol,p);
homoData->getHomogenizedTangentOperator_gradV_gradV(index,fieldInx)(i,p) = L(row,col);
}
atCol += 3;
}
};
atRow+=3;
}
}
};
void nonLinearMechSolver::set2ndOrderHomogenizedTangentOperatorWithCorrection(){
STensor63& dQdG = this->getHomogenizationState(IPStateBase::current)->getHomogenizedTangentOperator_G_G();
STensor63& dQdG_P = this->getHomogenizationState(IPStateBase::previous)->getHomogenizedTangentOperator_G_G();
STensor63& dQdG_I = this->getHomogenizationState(IPStateBase::initial)->getHomogenizedTangentOperator_G_G();
STensor63& dQdG_correction = this->getHomogenizationState(IPStateBase::current)->getHomogenizedCorrectionTerm_G_G();
STensor63& dQdG_correction_P = this->getHomogenizationState(IPStateBase::previous)->getHomogenizedCorrectionTerm_G_G();
STensor63& dQdG_correction_I = this->getHomogenizationState(IPStateBase::initial)->getHomogenizedCorrectionTerm_G_G();
STensorOperation::zero(dQdG_correction);
double delta = 1.0e-4;
/* for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
for(int k=0; k<3; k++){
if(dQdG(i,j,k,i,j,k) < 0.0){
dQdG_correction(i,j,k,i,j,k) = -dQdG(i,j,k,i,j,k) + delta;
dQdG(i,j,k,i,j,k) += dQdG_correction(i,j,k,i,j,k);
}
}*/
dQdG_P = dQdG;
dQdG_I = dQdG;
dQdG_correction_P = dQdG_correction;
dQdG_correction_I = dQdG_correction;
}
void nonLinearMechSolver::HOStressTangent_modificationTerm(STensor53& dPdG, STensor53& dQdF, STensor63& dQdG){
double volumeRVEInv = 1./this->getRVEVolume();
STensorOperation::zero(dQdG);
STensorOperation::zero(dQdF);
STensorOperation::zero(dPdG);
for (int i=0; i<domainVector.size(); i++){
domainVector[i]->computeAverageHighOrderStressTangentModification(_ipf,this->getRVEVolume(),dPdG,dQdF, dQdG);
};
dPdG *= (volumeRVEInv);
dQdF *= (volumeRVEInv);
dQdG *= (volumeRVEInv);
}
void nonLinearMechSolver::modifyHOStressTangent(fullMatrix<double>& L, const STensor53& dPdG, const STensor53& dQdF, const STensor63& dQdG){
// stress vector is arranged by this order
// S = [P Q FD fluxT1 mecaSrc1 -- fluxTn mecaSrcn fluxV1 --- fluxVm]
// K = [F G gradT1 T1 --- gradTn Tn gradV1 --- gradVm] see nonLinearMicroBC::getKinematicVector
// from dS/dK --> all tangents are explicitly given
int atRow = 0;
int atCol = 9;
for (int row = atRow; row<atRow+9; row++){
int i,j;
Tensor23::getIntsFromIndex(row-atRow,i,j);
// tangent P-G
for (int col =atCol; col< atCol+27; col++){
int p,q,r;
Tensor33::getIntsFromIndex(col-atCol,p,q,r);
L(row,col) += dPdG(i,j,p,q,r);
};
}
// tangent Q-F
atRow = 9;
atCol = 0;
for (int row = atRow; row<atRow+27; row++){
int i,j,k;
Tensor33::getIntsFromIndex(row-atRow,i,j,k);
for (int col=atCol; col < atCol+9; col++){
int p,q;
Tensor23::getIntsFromIndex(col-atCol,p,q);
L(row,col) += dQdF(i,j,k,p,q);
}
}
// tangent Q-G
atCol = 9;
for (int row = atRow; row<atRow+27; row++){
int i,j,k;
Tensor33::getIntsFromIndex(row-atRow,i,j,k);
for (int col=atCol; col < atCol+27; col++){
int p,q,r;
Tensor33::getIntsFromIndex(col-atCol,p,q,r);
L(row,col) += dQdG(i,j,k,p,q,r);
}
}
};
void nonLinearMechSolver::checkFailureOnset(){
if (_checkFailureOnset){
const homogenizedData* homoDataPrev = this->getHomogenizationState(IPStateBase::previous);
homogenizedData* homoData = this->getHomogenizationState(IPStateBase::current);
if (!_solverIsBroken){
const double cr = homoData->getLostOfSolutionUniquenessCriterion();
if (cr > 0.){
_solverIsBroken = true;
_FdamOnset = homoData->getHomogenizedActiveDissipationDeformationGradient();
if (_checkWithNormal){
printf("solver is broken %s at rank %d real tolearance = %e, following prescribed normal direction [%e %e %e] \n",
getFileSavingPrefix().c_str(),Msg::GetCommRank(),cr,_lostSolutionUniquenssNormal[0],_lostSolutionUniquenssNormal[1],_lostSolutionUniquenssNormal[2]);
}
else{
printf("solver is broken %s at rank %d real tolearance = %e, with minimal normal direction [%e %e %e] \n",
getFileSavingPrefix().c_str(),Msg::GetCommRank(),cr, _lostSolutionUniquenssNormal[0],_lostSolutionUniquenssNormal[1],_lostSolutionUniquenssNormal[2]);
}
}
else {
_solverIsBroken = false;
}
}
}
};
void nonLinearMechSolver::computeHomogenizedCrackFace(){
if (_pAl == NULL){
Msg::Error("pbcAlgorithm object must be created");
}
SVector3 Lx, Ly, Lz;
_pAl->getPBCConstraintGroup()->getPeriodicity(Lx, Ly, Lz);
if (_lostSolutionUniquenssNormal.norm() < 1e-6){
// normally, _lostSolutionUniquenssNormal.norm() == 1
_homogenizedCrackSurface = std::max(Lx.norm(),Ly.norm()); // nothing to do
return;
}
SPoint3 v1 = _pAl->getPBCConstraintGroup()->getRootPoint();
Msg::Info("rootPoint %f %f %f ",v1[0],v1[1],v1[2]);
SPoint3 damageVolumeCenter(0.,0.,0.);
double damageVolume = 0.;
for (int i=0; i<domainVector.size(); i++){
damageVolume += domainVector[i]->computeVolumeActiveDissipationDomain(_ipf);
}
if (damageVolume > 0.){
for (int i=0; i<domainVector.size(); i++){
domainVector[i]->computeActiveDissipationCenter(_ipf,damageVolumeCenter);
}
damageVolumeCenter *= (1./damageVolume);
Msg::Info("center of active damage zone : %f %f %f \n",damageVolumeCenter[0],damageVolumeCenter[1],damageVolumeCenter[2]);
}
_homogenizedCrackSurface = 0.;
if (getDim() == 2){
SPoint3 v2(v1);
v2 += (Lx.point());
SPoint3 v4(v1);
v4 += (Ly.point());
SPoint3 v3(v1);
v3 += (Lx.point());
v3 += (Ly.point());
if (dot(_lostSolutionUniquenssNormal,Lx)/(Lx.norm()) < 1e-8){
_homogenizedCrackSurface = Lx.norm();
Msg::Info("_homogenizedCrackSurface following Lx = %f",_homogenizedCrackSurface);
}
else if (dot(_lostSolutionUniquenssNormal,Ly)/(Ly.norm()) < 1e-8){
_homogenizedCrackSurface = Ly.norm();
Msg::Info("_homogenizedCrackSurface following Ly = %f",_homogenizedCrackSurface);
}
else{
std::vector<SPoint3> twoPoint;
SPoint3 prCenterTo12 = planeDirProject(damageVolumeCenter,v1,v2,_lostSolutionUniquenssNormal);
if (inside(prCenterTo12,v1,v2)){
twoPoint.push_back(prCenterTo12);
}
SPoint3 prCenterTo41 = planeDirProject(damageVolumeCenter,v1,v4,_lostSolutionUniquenssNormal);
if (inside(prCenterTo41,v1,v4)){
twoPoint.push_back(prCenterTo41);
}
if (twoPoint.size() < 2){
SPoint3 prCenterTo23 = planeDirProject(damageVolumeCenter,v2,v3,_lostSolutionUniquenssNormal);
if (inside(prCenterTo23,v2,v3)){
twoPoint.push_back(prCenterTo23);
}
}
if (twoPoint.size() < 2){
SPoint3 prCenterTo34 = planeDirProject(damageVolumeCenter,v3,v4,_lostSolutionUniquenssNormal);
if (inside(prCenterTo34,v3,v4)){
twoPoint.push_back(prCenterTo34);
}
}
if (twoPoint.size() == 2){
_homogenizedCrackSurface = twoPoint[0].distance(twoPoint[1]);
Msg::Info("_homogenizedCrackSurface = %f ",_homogenizedCrackSurface);
}
else{
Msg::Error("computeHomogenizedCrackLength is wrong %s _lostSolutionUniquenssNormal = [%f %f %f]",getFileSavingPrefix().c_str(),
_lostSolutionUniquenssNormal[0],_lostSolutionUniquenssNormal[1],_lostSolutionUniquenssNormal[2]);
}
}
_homogenizedCrackSurface *= (Lz.norm()); // generally, _LzNorm = 1
#ifdef _DEBUG
printf("%s _homogenizedCrackSurface = %e \n",getFileSavingPrefix().c_str(),_homogenizedCrackSurface);
#endif //_DEBUG
}
else if (getDim() == 3){
Msg::Info("nonLinearMechSolver::computeHomogenizedCrackFace for 3D has not been implemented");
}
else{
Msg::Info("computeHomogenizedCrackLength has not been implemented for %d D problems");
}
};
void nonLinearMechSolver::setMessageView(const bool view){
_messageView = view;
}
void nonLinearMechSolver::extractAverageProperties(bool stiff){
homogenizedData* homoData = this->getHomogenizationState(IPStateBase::current);
/* get homogenization value */
if (stiff){
this->extractAverageStressAndTangent(homoData);
}
else if (_stressflag){
this->extractAverageStress(homoData);
}
};
eigenSolver* nonLinearMechSolver::eigenSolve(const int numstep)
{
#if defined(HAVE_SLEPC)
// get system
// stiffness
std::string strA = "A";
linearSystem<double>* lsysA = pAssembler->getLinearSystem(strA);
linearSystemPETSc<double>* lpetA = dynamic_cast<linearSystemPETSc<double>*>(lsysA);
// mass
linearSystemPETSc<double>* lpetB = NULL;
if (_eigOpts.type == eigenSolverOptions::Dynamic)
{
std::string strB = "B";
linearSystem<double>* lsysB = pAssembler->getLinearSystem(strB);
lpetB = dynamic_cast<linearSystemPETSc<double>*>(lsysB);
}
if (lpetA==NULL)
{
Msg::Error("stiffness matrix is null");
return NULL;
}
eigenSolver* eigsol = new eigenSolver(lpetA,lpetB, _eigOpts.hermitian);
bool ok = eigsol->solve(_eigOpts.numeigenvalue,"smallestReal", _eigOpts.method,_eigOpts.convergenCriterion,_eigOpts.maxNumIteration);
// save eigenvalue to file
// first column is real part and second column is the imag part
std::string eigValueFileName = getFileSavingPrefix()+"eigenValues_step"+int2str(numstep)+".csv";
FILE* eigValueFile = fopen(eigValueFileName.c_str(),"w");
for (int i=0; i<_eigOpts.numeigenvalue; i++)
{
std::complex<double> val = eigsol->getEigenValue(i);
fprintf(eigValueFile,"%d\t%.16g \t %.16g \n",i,val.real(), val.imag());
}
fclose(eigValueFile);
// normalized mode with infinite norm
std::vector<int> modeView(_eigview.size());
for (int i=0; i< _eigview.size(); i++)
{
modeView[i] = _eigview[i].comp;
}
eigsol->normalize_mode(modeView,1.);
return eigsol;
#else
Msg::Error("SLEPs must be used");
return NULL;
#endif //HAVE_SLEPC
};
void nonLinearMechSolver::nextStep(const double curtime, const int step)
{
/* field next step */
if (_selectiveObject != NULL){
_selectiveObject->nextStep();
}
if (_endSchemeMonitoringObject!=NULL)
{
_endSchemeMonitoringObject->nextStep();
}
_ipf->nextStep(curtime); //ipvariable
pAssembler->nextStep();
// update for bodyforce
if(computedUdF()){
this->extractdUdFByInSystemCondensation(this->getHomogenizationState(IPStateBase::current));
}
// contact
for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){
contactDomain *cdom = *it;
cdom->nextStep();
}
for(defoDefoContactContainer::iterator it = _allDefoDefoContact.begin(); it!=_allDefoDefoContact.end(); ++it){
defoDefoContactDomain *cdom = *it;
cdom->nextStep();
}
};
void nonLinearMechSolver::computeSplittedStiffnessMatrix(bool accountBodyForceForHO){
_pAl->getSplitStiffness()->zeroSubMatrix();
for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){
partDomain* dom = *itdom;
BiNonLinearTermBase *term = static_cast<BiNonLinearTermBase *> (dom->getBilinearBulkTerm());
bool oldFlag=term->getAccountBodyForceForHO();
term->setAccountBodyForceForHO(accountBodyForceForHO);
AssembleSplittedStiffness(*term,*(dom->getFunctionSpace()),dom->element_begin(),dom->element_end(),
*(dom->getBulkGaussIntegrationRule()),*_pAl->getSplittedDof());
term->setAccountBodyForceForHO(oldFlag);
if(dom->IsInterfaceTerms()){
dgPartDomain *dgdom = static_cast<dgPartDomain*>(dom);
// Assembling loop on elementary interface terms
BiNonLinearTermBase *dgterm = static_cast<BiNonLinearTermBase *> (dgdom->getBilinearInterfaceTerm());
bool oldFlag=dgterm->getAccountBodyForceForHO();
dgterm->setAccountBodyForceForHO(accountBodyForceForHO);
AssembleSplittedStiffness(*(dgterm),*(dom->getFunctionSpace()),dgdom->gi->begin(),dgdom->gi->end(),
*(dgdom->getInterfaceGaussIntegrationRule()),*_pAl->getSplittedDof());
dgterm->setAccountBodyForceForHO(oldFlag);
// Assembling loop on elementary boundary interface terms
BiNonLinearTermBase *virtualdgterm = static_cast<BiNonLinearTermBase *> (dgdom->getBilinearVirtualInterfaceTerm());
oldFlag=virtualdgterm->getAccountBodyForceForHO();
virtualdgterm->setAccountBodyForceForHO(accountBodyForceForHO);
AssembleSplittedStiffness(*(virtualdgterm),*(dom->getFunctionSpace()),dgdom->gib->begin(),dgdom->gib->end(),
*(dgdom->getInterfaceGaussIntegrationRule()),*_pAl->getSplittedDof());
virtualdgterm->setAccountBodyForceForHO(oldFlag);
}
}
for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){
contactDomain *cdom = *it;
contactBilinearTermBase<double> *sterm = static_cast<contactBilinearTermBase<double>*>(cdom->getStiffnessTerm());
AssembleSplittedStiffness(*sterm,*(cdom->getSpace()),sterm->getContactNodes()->elemBegin(),
sterm->getContactNodes()->elemEnd(),*(cdom->getGaussIntegration()),*_pAl->getSplittedDof());
}
for(defoDefoContactContainer::iterator it = _allDefoDefoContact.begin(); it!=_allDefoDefoContact.end(); ++it){
defoDefoContactDomain *cdom = *it;
const std::vector<BilinearTermBase*> &sterm = static_cast< const std::vector<BilinearTermBase* > >(cdom->getConstRefToStiffnessTerm()); //we might need to change the class
for(int i=0; i<sterm.size(); i++)
{
AssembleSplittedStiffnessDefoDefoContact(*(sterm[i]),*(cdom->getRefToVSpace()[i]),((cdom->getRefToGroup())[i]).begin(),
((cdom->getRefToGroup())[i]).end(),
*(cdom->getRefToVQuadratureMaster()[i]),*_pAl->getSplittedDof());
}
}
};
homogenizedData* nonLinearMechSolver::getHomogenizationState(const IPStateBase::whichState state){
if (state == IPStateBase::initial or state == IPStateBase::previous){
return _initialState;
}
else if (state == IPStateBase::current){
return _currentState;
}
else{
Msg::Error("This state does not exist");
return NULL;
}
}
const homogenizedData* nonLinearMechSolver::getHomogenizationState(const IPStateBase::whichState state) const{
if (state == IPStateBase::initial or state == IPStateBase::previous){
return _initialState;
}
else if (state == IPStateBase::current){
return _currentState;
}
else{
Msg::Error("This state does not exist");
return NULL;
}
}
void nonLinearMechSolver::resetSolverToInitialStep(){
// system
std::string name = "A";
linearSystem<double>* lsys = pAssembler->getLinearSystem(name);
nonLinearSystem<double>* nonlsys = dynamic_cast<nonLinearSystem<double>*>(lsys);
if (nonlsys){
nonlsys->copy(IPStateBase::initial,IPStateBase::current);
nonlsys->copy(IPStateBase::initial,IPStateBase::previous);
}
pathFollowingSystem<double>* pathSys = dynamic_cast<pathFollowingSystem<double>*>(nonlsys);
if (pathSys){
pathSys->resetControlParameter();
}
// ipf field
_ipf->copy(IPStateBase::initial,IPStateBase::current);
_ipf->copy(IPStateBase::initial,IPStateBase::previous);
// homogenized data
(*_currentState) = (*_initialState);
if (_damageIsBlocked){
_ipf->blockDissipation(IPStateBase::current,true);
}
else{
_ipf->blockDissipation(IPStateBase::current,false);
}
};
void nonLinearMechSolver::prepareForNextMicroSolve(){
// in microBC
bool BCIsChanged = false;
if (_failureBCIsSwitched){
if (_microFailureBC == NULL) {
Msg::Error("_microFailureBC is null in nonLinearMechSolver::nextStep");
}
else{
const homogenizedData* homodataPrev = this->getHomogenizationState(IPStateBase::initial);
const homogenizedData* homodata = this->getHomogenizationState(IPStateBase::current);
if (_solverIsBroken){
this->switchMicroBC(_microFailureBC);
printf("ranks %d microBC has just been changed \n",Msg::GetCommRank());
BCIsChanged = true;
_failureBCIsSwitched = false; // pass one time
}
}
}
if (!BCIsChanged){
_microBC->nextStep();
}
// next step for solver
std::string name = "A";
linearSystem<double>* lsys = pAssembler->getLinearSystem(name);
nonLinearSystem<double>* nonlsys = dynamic_cast<nonLinearSystem<double>*>(lsys);
pathFollowingSystem<double>* pathSys = dynamic_cast<pathFollowingSystem<double>*>(nonlsys);
if (nonlsys){
nonlsys->copy(IPStateBase::current,IPStateBase::initial);
}
if (pathSys){
pathSys->resetControlParameter();
}
if (_damageIsBlocked){
_ipf->blockDissipation(IPStateBase::current,true);
}
else{
_ipf->blockDissipation(IPStateBase::current,false);
}
if (withEnergyDissipation()){
_ipf->checkActiveDissipation();
if (_ipf->getNumOfActiveDissipationIPsCurrent() > 0){
// store historical value
_homogenizedStressLastActiveDissipation = this->getHomogenizationState(IPStateBase::current)->getHomogenizedStress();
_homogenizedStrainLastActiveDissipation = this->getMicroBC()->getFirstOrderKinematicalVariable();
_homogenizedDissipationStrainLastActiveDissipation = this->getHomogenizationState(IPStateBase::current)->getHomogenizedActiveDissipationDeformationGradient();
_homogenizedCohesiveJumpLastActiveDissipation = this->getHomogenizationState(IPStateBase::current)->getHomogenizedCohesiveJump();
}
}
// save data for nex macroscopic step
_ipf->copy(IPStateBase::current,IPStateBase::initial);
// for homogenized data
(*_initialState)=(*_currentState);
};
linearSystem<double>* nonLinearMechSolver::createMicroSNLSystem(){
linearSystem<double>* lsys = NULL;
if (_pathFollowing){
_controlType = nonLinearMechSolver::LOAD_CONTROL; // this means compute until time = 1.
_systemType == nonLinearMechSolver::MULT_ELIM; // always multiplier elimination
#if defined(HAVE_PETSC)
Msg::Info("Path following is used");
lsys = new pbcPathFollowingSystemPETSC<double>(PETSC_COMM_SELF);
// set path following options
// paramater remains default if it is negative
pathFollowingSystemBase* pfsysBase = dynamic_cast<pathFollowingSystemBase*>(lsys);
if (_pfManager._controlTypePathFollowing >=0){
pfsysBase->setControlType(_pfManager._controlTypePathFollowing);
}
if (_pfManager._correctionMethodPathFollowing>=0){
pfsysBase->setCorrectionMethod(_pfManager._correctionMethodPathFollowing);
}
if (_pfManager._tranversalCriterionPathFollowing>=0){
pfsysBase->setTranversalCriterion(_pfManager._tranversalCriterionPathFollowing);
}
if (_pfManager._solverTypePathFollowing >=0){
pfsysBase->setSolverType(_pfManager._solverTypePathFollowing,_pfManager._pathFollowingEqRatio);
}
#else
Msg::Error("This option used with petsc only");
#endif
}
else{
if (_controlType == nonLinearMechSolver::LOAD_CONTROL){
if (_systemType == nonLinearMechSolver::MULT_ELIM){
if(nonLinearMechSolver::whatSolver == Petsc){
#if defined(HAVE_PETSC)
lsys = new pbcNonLinearSystemPETSc<double>(PETSC_COMM_SELF);
if(_solver_options.size())
lsys->setParameter(std::string("petsc_solver_options"),_solver_options);
if (_outputFile)
fprintf(_outputFile,"PETSc is chosen to solve \n");
#endif
}
else{
Msg::Error("Petsc is required");
}
}
else if (_systemType == nonLinearMechSolver::DISP_ELIM_UNIFIED){
if(nonLinearMechSolver::whatSolver == Petsc){
#if defined(HAVE_PETSC)
lsys = new pbcConstraintEliminationNonLinearSystemPETSc<double>(PETSC_COMM_SELF);
if(_solver_options.size())
lsys->setParameter(std::string("petsc_solver_options"),_solver_options);
if (_outputFile)
fprintf(_outputFile,"PETSc is chosen to solve \n");
#endif
}
else{
Msg::Error("Petsc is required");
}
}
else{
if(nonLinearMechSolver::whatSolver == Petsc){
#if defined(HAVE_PETSC)
lsys = new nonLinearSystemPETSc<double>(PETSC_COMM_SELF,_lineSearch);
if(_solver_options.size())
lsys->setParameter(std::string("petsc_solver_options"),_solver_options);
if (_outputFile)
fprintf(_outputFile,"PETSc is chosen to solve \n");
#else
lsys = new nonLinearSystemGmm<double>(_lineSearch);
dynamic_cast<nonLinearSystemGmm<double>*>(lsys)->setNoisy(2);
if (_outputFile)
fprintf(_outputFile,"PETSc is not installed\n Gmm is chosen to solve \n");
#endif
}
else
lsys= nonLinearMechSolver::createSNLSystem();
}
}
else if (_controlType == nonLinearMechSolver::ARC_CONTROL_EULER){
if (nonLinearMechSolver::whatSolver == Petsc){
#if defined(HAVE_PETSC)
lsys = new forwardEulerLinearSystemPETSc<double>();
if(_solver_options.size())
lsys->setParameter(std::string("petsc_solver_options"),_solver_options);
if (_outputFile)
fprintf(_outputFile,"PETSc is chosen to solve \n");
#else
Msg::Error("Petsc is not available");
#endif
}
else{
Msg::Error("This is not implemented without PETSc");
};
};
}
if (_outputFile)
fflush(_outputFile);
return lsys;
};
void nonLinearMechSolver::createMicroSystem(){
if (_previousInit and _resetRestart)
{
// collect if previous dof exists
if (_collection==NULL)
{
_collection = new DofCollection();
}
_collection->collect(pAssembler);
// clear data
delete pAssembler;
pAssembler = NULL;
}
linearSystem<double>* lsys = createMicroSNLSystem();
// create a new one
pAssembler = new staticDofManager(lsys,whatScheme,false,false);
};
void nonLinearMechSolver::init2Micro(){
// get quantities for micro BC
if (_microBC == NULL){
Msg::Error("Microscopic BC must be specified nonLinearMechSolver::init2Micro");
}
// create system, dofManager
this->createMicroSystem();
// init all other BC
this->initAllBCsOnDofs();
// create periodic algorithm
if (_pAl != NULL){
delete _pAl; Msg::Info("pbcAlgorithm is deleted");
}
_pAl = new pbcAlgorithm(this); // create all constraints, etc
// number Dof and allocate the system
this->microNumberDof();
// make data as previous if exists
this->updateDataFromPreviousSolver();
/* initialization of Dof value */
this->setInitialCondition();
if (!_archive){
unknownView.clear();
ipView.clear();
ipViewInterface.clear();
energyView.clear();
}
if (_ufield) delete _ufield;
_ufield = new unknownField(this,3,anoded,unknownView); // 3 components by nodes User choice ??
if (!_previousInit){
if (_ipf) delete _ipf;
_ipf = new IPField(this,vaip,ipView,ipViewInterface); // Field for GaussPoint
_ipf->compute1state(IPStateBase::current,true);
_ipf->copy(IPStateBase::current,IPStateBase::previous);
_ipf->copy(IPStateBase::current,IPStateBase::initial);
if (initbrokeninter.size() > 0 || initbrokeninterInDomains.size() > 0)
{
_ipf->initialBroken(pModel, initbrokeninter);
_ipf->initialBrokenDomain(pModel,initbrokeninterInDomains);
_ipf->compute1state(IPStateBase::current,true);
_ipf->copy(IPStateBase::current,IPStateBase::previous);
_ipf->copy(IPStateBase::current,IPStateBase::initial);
}
}
else{
_ipf->copy(IPStateBase::current,IPStateBase::initial);
_ipf->copy(IPStateBase::current,IPStateBase::previous);
}
if (_energField) delete _energField;
_energyComputation = 0;
_fractureEnergyComputation = 0;
_energField = new energeticField(this,energyView,_energyComputation,_fractureEnergyComputation,getScheme());
// init terms
this->initTerms();
if (_tangentflag and _homogenizeTangentMethod == INSYSTEMCONDEN){
this->computeStiffMatrix();
}
// rve_volume from periodicity
if (!_previousInit){
if (_rveVolume <=0.){
_rveVolume = _pAl->getRVEVolume();
this->setRVEGeometricalInertia(_pAl->getRVEGeometricalInertia());
this->setRVEGeometry(_pAl->getRVEGeometry());
}
Msg::Info("RVE volume used = %e",_rveVolume);
// compute density
this->computeDensity();
if (_isHommProSaveToFile){
std::string denfile = getFileSavingPrefix()+"density.csv";
FILE* fileden = fopen(denfile.c_str(),"w");
fprintf(fileden,"%e",this->_rho);
fclose(fileden);
}
_initialState = new homogenizedData(this,_damageToCohesiveJump,_extractIrreversibleEnergy);
_currentState = new homogenizedData(this,_damageToCohesiveJump,_extractIrreversibleEnergy);
if (_extractElasticTangentOperator){
_elasticState = new homogenizedData(this,_damageToCohesiveJump,_extractIrreversibleEnergy);
std::string elasticFileName = getFileSavingPrefix()+"elasticTangent.csv";
_elasticDPDFTangentFile = Tensor43::createFile(elasticFileName);
}
/** initial tangent**/
this->extractAverageProperties(_tangentflag);
// body force is applied, initial tangent need to be recomputed with correct dUdF
if(_homogenizeTangentMethod != PERTURB and computedUdF()){
_ipf->setdFmdFM(this->getHomogenizationState(IPStateBase::current)->getdUnknowndF(), IPStateBase::current);
_ipf->setValuesForBodyForce(IPStateBase::current);
_ipf->copy(IPStateBase::current,IPStateBase::previous);
_ipf->copy(IPStateBase::current,IPStateBase::initial);
this->extractAverageProperties(_tangentflag);
}
//
this->IPVolumeIntegralArchiving(0.,0,true);
this->IPDataOnPhysicalArchiving(0.,0,true);
this->averageClusterArchiving(0.,0,true);
(*_initialState) = (*_currentState);
if (_multiscaleFlag == false){
if (_microBC->getTotalNumberOfMechanicalDofs() > 0) {
if (_stressflag)
{
_currentState->getHomogenizedStress().print("stress");
}
if (_tangentflag){
_currentState->getHomogenizedTangentOperator_F_F().print("tangent");
}
if (_microBC->getOrder() == 2 && _stressflag)
_currentState->getHomogenizedSecondOrderStress().print("ho stress");
}
for (int index=0; index< _microBC->getTotalNumberOfConDofs(); index++){
_currentState->getHomogenizedConstitutiveExtraDofFlux(index).print("ConExtraDof flux");
printf("_currentState constitutive extra dof %d internal energy: %f \n", index, _currentState->getHomogenizedConstitutiveExtraDofInternalEnergy(index));
}
for (int index=0; index< _microBC->getTotalNumberOfNonConDofs(); index++){
_currentState->getHomogenizedNonConstitutiveExtraDofFlux(index).print("nonConExtraDof flux");
}
}
_homogenizedFiles = new homogenizedDataFiles(this);
bool saveCohesiveLawFile = (_isHommProSaveToFile and _damageToCohesiveJump);
_homogenizedFiles->openFiles(this,_isHommStrainSaveToFile,_isHommProSaveToFile,saveCohesiveLawFile);
this->homogenizedDataToFile(0.);
}
else{
// extract with new BC
this->extractAverageProperties(_tangentflag);
// initial data
this->IPVolumeIntegralArchiving(0.,0,true);
this->IPDataOnPhysicalArchiving(0.,0,true);
this->averageClusterArchiving(0.,0,true);
if (_multiscaleFlag == false){
if (_microBC->getTotalNumberOfMechanicalDofs() > 0) {
if (_stressflag)
_currentState->getHomogenizedStress().print("stress");
if (_tangentflag){
_currentState->getHomogenizedTangentOperator_F_F().print("tangent");
}
if (_microBC->getOrder() == 2 && _stressflag)
_currentState->getHomogenizedSecondOrderStress().print("ho stress");
}
for (int index=0; index< _microBC->getTotalNumberOfConDofs(); index++){
_currentState->getHomogenizedConstitutiveExtraDofFlux(index).print("ConExtraDof flux");
printf("_currentState constitutive extra dof %d internal energy: %f \n", index, _currentState->getHomogenizedConstitutiveExtraDofInternalEnergy(index));
}
for (int index=0; index< _microBC->getTotalNumberOfNonConDofs(); index++){
_currentState->getHomogenizedNonConstitutiveExtraDofFlux(index).print("nonConExtraDof flux");
}
}
bool saveCohesiveLawFile = (_isHommProSaveToFile and _damageToCohesiveJump);
_homogenizedFiles->openFiles(this,_isHommStrainSaveToFile,_isHommProSaveToFile,saveCohesiveLawFile);
this->homogenizedDataToFile(0.);
}
_previousInit = true;
};
void nonLinearMechSolver::initMicroSolver(){
if (_messageView){
std::string filename = getFileSavingPrefix()+"out.txt";
if (_outputFile != NULL) fclose(_outputFile);
_outputFile = fopen(filename.c_str(),"w");
fprintf(_outputFile,"Initializing on processor %d of %d \nMicro-problem: %s \nMicro SNL Data : nstep =%d endtime = %f\n",
Msg::GetCommRank(),Msg::GetCommSize(),getFileSavingPrefix().c_str(),
_timeManager->getNumSteps(),_timeManager->getEndTime());
}
// read mesh file
this->init();
this->init2Micro();
if (_outputFile) {
fprintf(_outputFile,"---------End of initialization-------- \n");
fflush(_outputFile);
}
};
bool nonLinearMechSolver::microSolve(bool forced){
double time = 0;
this->resetSolverToInitialStep();
if (_microBC->notSameState(_sameStateCriterion,_absTol) or forced)
{
_sucessMicroSolve = false;
if (_outputFile)
fprintf(_outputFile,"Solving in procs %d \n",Msg::GetCommRank());
// solve system
if (whatScheme ==StaticLinear){
time = solveMicroSolverStaticLinear();
}
else if (whatScheme == StaticNonLinear){
time = solveMicroSolverSNL();
}
else
Msg::Error("This scheme is not implemented");
if (_sucessMicroSolve)
{
this->extractAverageProperties(_tangentflag);
}
if (_outputFile)
fflush(_outputFile);
}
else
{
_sucessMicroSolve = true;
}
return _sucessMicroSolve;
};
void nonLinearMechSolver::OneStep(const int numstep){
int niteNR = 0;
if (_pathFollowing){
niteNR = pathFollowingPerturbation();
}
else{
if (_systemType == MULT_ELIM)
niteNR = microNewtonRaphson(numstep);
else {
if (_systemType == DISP_ELIM)
_pAl->applyPBCByConstraintElimination();
else if (_systemType == DISP_ELIM_UNIFIED){
_pAl->updateSystemUnknown();
}
niteNR = NewtonRaphson(numstep);
}
if(niteNR == _timeManager->getMaxNbIterations()) // time step reduction
{
Msg::Error("convergent fails in tangent perturbation %s",getFileSavingPrefix().c_str());
}
}
};
double nonLinearMechSolver::solveMicroSolverSNL(){
std::string name = "A";
linearSystem<double>* lsys =pAssembler->getLinearSystem(name);
nonLinearSystem<double>* nonsys = dynamic_cast<nonLinearSystem<double>*>(lsys);
pathFollowingSystem<double>* pathSys = dynamic_cast<pathFollowingSystem<double>*>(lsys);
//
if (_multiscaleFlag)
{
_timeManager->setEndTime(1.);
}
_timeManager->initializeTimeSteppingPlan();
//
if (_pathFollowing){
_pAl->computeLoadVector();
}
// if restart
if(restartManager::available() and !_resetRestart)
{
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
restartManager::openRestartFile("nonLinearMechSolver");
restartManager::restart(this);
// add restart other vars here if necessary
//
//
restartManager::closeRestartFile();
restartManager::InitFromRestartFile();
if (getNumRanks() > 1)
Msg::Barrier(); // To wait rank0 before end
struct stat st;
if(stat("beforeRestart",&st) == 0)
{
std::ostringstream oss;
oss << _timeManager->getLastIterationIndex();
std::string cpDir="mv beforeRestart restart"+oss.str();
int oks = system(cpDir.c_str());
}
#if defined(HAVE_MPI)
if(Msg::GetCommSize()>1)
{ //we need to reinitializae after the restart of the nonLinearSolver
Msg::Info("MPI restart initialization begins");
pAssembler->systemMPIComm(); // To initiate the MPI Communication
Msg::Info("MPI restart initialization OK");
}
#endif // HAVE_MPI
}
_resetRestart=false;
//
_sucessMicroSolve = false;
bool willFinish = false;
while(!_timeManager->reachEndTime())
{
// read-only values to make sure all this paramete cannot be change during step
const double endtime = _timeManager->getEndTime();
const double dt = _timeManager->getTimeStep();
const double curtime = dt +_timeManager->getLastTime();
const int ii = _timeManager->getLastIterationIndex();
const double tol = 1e-6;
double tsystresol = Cpu();
if (_outputFile)
fprintf(_outputFile,"MICRO t= %e on %e \n",curtime,endtime);
if (!_multiscaleFlag)
Msg::Info("MICRO t= %e on %e, step =%e",curtime,endtime,dt);
pAssembler->setTimeStep(dt);
_ipf->setTime(curtime,dt,ii+1);
if(computedUdF()){
_ipf->setdFmdFM(this->getHomogenizationState(IPStateBase::current)->getdUnknowndF(), IPStateBase::current);
}
// Solve one step by NR scheme
int niteNR = 0;
if (_pathFollowing)
{
pathSys->setPathFollowingIncrement(dt);
_pAl->updateConstraint(_ipf);
if(computedUdF() and useWhichModuliForBF() != partDomain::Present){
this->computeBodyForceVector();
}
niteNR = microNewtonRaphsonPathFollowing(ii+1);
if (niteNR < _timeManager->getMaxNbIterations())
{
double control = pathSys->getControlParameter();
if (_outputFile)
fprintf(_outputFile,"control variable %e \n",control);
if (control>1. and fabs(control-1) >tol)
{
if (_outputFile)
fprintf(_outputFile,"Load correction step\n");
willFinish = true;
nonsys->resetUnknownsToPreviousTimeStep();
_ipf->copy(IPStateBase::previous,IPStateBase::current);
// switch control to obtain the control parameter equal to 1
pathSys->setControlType(pathFollowingSystemBase::LOAD_CONTROL);
_timeManager->setTimeStep(1.-pathSys->getControlParameter());
continue;
}
else if (fabs(control-1) <=tol)
{
willFinish = true;
}
else if (control<0)
{
Msg::Error("path following is not converge %s !",getFileSavingPrefix().c_str());
_sucessMicroSolve = false;
break;
}
}
}
else
{
this->oneStepPreSolve(curtime,dt,ii+1);
_pAl->updateConstraint(_ipf);
if (_systemType == MULT_ELIM)
niteNR = microNewtonRaphson(ii+1);
else {
if (_systemType == DISP_ELIM){
_pAl->applyPBCByConstraintElimination();
}
else if (_systemType == DISP_ELIM_UNIFIED){
_pAl->updateSystemUnknown();
}
niteNR = NewtonRaphson(ii+1);
}
}
if(niteNR >= _timeManager->getMaxNbIterations()) // time step reduction
{
_sucessMicroSolve = false;
// reduce time step for next solve
_timeManager->reduceTimeStep(); // solver fails counter in _timeManager is increased by 1
// copy
nonsys->resetUnknownsToPreviousTimeStep();
_ipf->copy(IPStateBase::previous,IPStateBase::current);
this->getHomogenizationState(IPStateBase::current)->operator=(*this->getHomogenizationState(IPStateBase::previous));
//
if(_timeManager->getNbFails() > _timeManager->getMaxNbFails()) // end of simulation
{
Msg::Error("Simulation end due to convergence problem %s!!!", getFileSavingPrefix().c_str());
if (_outputFile)
fprintf(_outputFile,"Simulation end due to convergence problem %s !!!\n", getFileSavingPrefix().c_str());
break;
}
else
{
if (_outputFile)
fprintf(_outputFile,"Convergence of Newton-Raphson failed %s --> reduced time step\n",
getFileSavingPrefix().c_str());
printf("Convergence of Newton-Raphson failed %s --> reduced time step\n",
getFileSavingPrefix().c_str());
}
}
else
{
_sucessMicroSolve = true;
_timeManager->saveTimeHistory();
//
if (!_multiscaleFlag)
{
// if not multiscale analysis,
// check saving data all step
if (_outputFile)
fflush(_outputFile);
//
this->oneStepPostSolve(curtime,ii+1);
}
else
{
// get next step without saving
this->nextStep(curtime,ii+1);
}
if (_pathFollowing)
{
if (fabs(endtime-curtime) < tol*endtime and (pathSys->getControlParameter()<1.))
{
// extend endtime of the control parameter not yet reach 1
_timeManager->setEndTime(2.*endtime);
}
}
// move to next step in time manager
_timeManager->computeTimeStepForNextSolving(niteNR);
tsystresol = Cpu() - tsystresol;
if (!_multiscaleFlag)
Msg::Info("Time resolution for step %d equal to %f",ii+1,tsystresol);
}
if(_pathFollowing)
{
if (willFinish)
{
// last solve
pathSys->setControlType(_pfManager._controlTypePathFollowing);
_sucessMicroSolve = true;
break;
}
}
}
return _timeManager->getLastTime();
};
void nonLinearMechSolver::archiveData(const double curtime, const int numstep, const bool forceView){
// Archiving
if (_archive)
{
//printf("arching solver ele %d gpt %d\n",getElementSolverNumber(),getGaussPointSolverNumber());
/*writing deformed mesh */
if (_isWriteDeformedMeshToFile){
this->writeDeformedMesh(numstep);
}
/* Archiving */
_ufield->archive(curtime,numstep,forceView);
_ipf->archive(curtime,numstep,forceView);
_energField->archive(curtime,numstep,forceView);
this->crackTracking(curtime);
this->forceArchiving(curtime,numstep,forceView); // Edge force value;
this->pathFollowingArchiving(curtime,numstep);
this->IPVolumeIntegralArchiving(curtime,numstep,forceView);
this->IPDataOnPhysicalArchiving(curtime,numstep,forceView);
this->averageClusterArchiving(curtime,numstep,forceView);
if (_strainMap !=NULL){
_strainMap->buildDisplacementViewAndStrainView(numstep,forceView);
}
}
this->homogenizedDataToFile(curtime);
};
double nonLinearMechSolver::solveMicroSolverStaticLinear(){
/* time initialization */
double curtime = 1.;
double timestep = 1.;
int step = 1;
/* solving */
this->setTimeForBC(curtime);
this->setTimeForLaw(curtime,timestep,step);
if(computedUdF()){
_ipf->setDeformationGradientGradient(this->getMicroBC()->getSecondOrderKinematicalVariable(), IPStateBase::current);
}
if (_systemType == DISP_ELIM)
_pAl->applyPBCByConstraintElimination();
else if (_systemType == DISP_MULT)
_pAl->assembleRightHandSide();
else if (_systemType == MULT_ELIM)
_pAl->assembleConstraintResidualToSystem();
this->computeExternalForces();
this->computeStiffMatrix();
if (_outputFile)
fprintf(_outputFile,"-- done assembling!\n");
pAssembler->systemSolve();
if (_outputFile)
fprintf(_outputFile,"-- done solving!\n");
_ipf->compute1state(IPStateBase::current,true);
/* end of scheme */
_sucessMicroSolve = true;
return curtime;
};
double nonLinearMechSolver::solveMicroSolverForwardEuler(){
// external force vector // not change in function of time
_timeManager->initializeTimeSteppingPlan();
//
this->setTimeForBC(1.);
if(computedUdF()){
_ipf->setDeformationGradientGradient(this->getMicroBC()->getSecondOrderKinematicalVariable(), IPStateBase::current);
}
_pAl->assembleRightHandSide();
//
std::string Aname = "A";
linearSystem<double>* lsys = pAssembler->getLinearSystem(Aname);
forwardEulerArcLengthBase<double>* elsys = dynamic_cast<forwardEulerArcLengthBase<double>*>(lsys);
double endTime = _timeManager->getEndTime();
while (!_timeManager->reachEndTime())
{
double lastTime = _timeManager->getLastTime();
int lastIter = _timeManager->getLastIterationIndex();
double timeStep = _timeManager->getTimeStep();
if (lastTime+ timeStep > endTime)
{
timeStep = endTime-lastTime;
}
if (_outputFile)
fprintf(_outputFile,"iter = %d, time = %e, entime = %e\n",lastIter+1,lastTime+timeStep,endTime);
Msg::Info("iter = %d, time = %e, entime = %e",lastIter+1,lastTime+timeStep,endTime);
this->computeStiffMatrix();
elsys->setArcLengthControlIncrement(timeStep);
//pAssembler->systemSolve();
int ss = pAssembler->systemSolveIntReturn();
double control;
elsys->getControlParameter(control);
this->setTimeForBC(control);
// update ipvariable
if(computedUdF()){
_ipf->setDeformationGradientGradient(this->getMicroBC()->getSecondOrderKinematicalVariable(), IPStateBase::current);
}
_ipf->compute1state(IPStateBase::current,true);
_timeManager->saveTimeHistory();
if (!_multiscaleFlag)
{
this->oneStepPostSolve(control,lastIter+1);
}
else
{
this->nextStep(control,lastIter+1);
}
lsys->zeroMatrix();
elsys->nextStep();
_timeManager->computeTimeStepForNextSolving(1);
}
return _timeManager->getLastTime();
};
void nonLinearMechSolver::setTime(const double ctime,const double dtime, const int curstep){
_macroTimeStep = dtime;
_macroTime = ctime;
_macroStep = curstep;
}
double nonLinearMechSolver::microSolveStaticLinear(){
double t= Cpu();
initMicroSolver();
double time = 0;
if (_controlType == LOAD_CONTROL){
time= solveMicroSolverStaticLinear();
extractAverageProperties(_tangentflag);
if (_microBC->getTotalNumberOfMechanicalDofs() > 0){
if (_stressflag)
_currentState->getHomogenizedStress().print("stress");
if (_tangentflag)
_currentState->getHomogenizedTangentOperator_F_F().print("tangent");
}
for (int index =0; index < _microBC->getTotalNumberOfConDofs(); index++){
_currentState->getHomogenizedConstitutiveExtraDofFlux(index).print("con extra dof flux");
printf("double con extra dof %d internal energy %f\n",index,_currentState->getHomogenizedConstitutiveExtraDofInternalEnergy(index));
}
this->endOfScheme(time,_timeManager->getLastIterationIndex());
}
else if (_controlType == ARC_CONTROL_EULER)
Msg::Error("This is not exist");
Msg::Info("StaticLinear OK, total time = %e seconds",t);
return time;
};
double nonLinearMechSolver::microSolveSNL(){
double t= Cpu();
initMicroSolver();
double time = 0;
if (_controlType == LOAD_CONTROL or _pathFollowing)
time = solveMicroSolverSNL();
else if (_controlType == ARC_CONTROL_EULER)
time = solveMicroSolverForwardEuler();
this->endOfScheme(time,_timeManager->getLastIterationIndex());
t = Cpu() -t;
Msg::Info("StaticNonLinear OK, total time = %e seconds",t);
return time;
};
int nonLinearMechSolver::pathFollowingPerturbation(){
std::string name = "A";
linearSystem<double>* lsys = pAssembler->getLinearSystem(name);
pbcSystem<double> * pbcSys = dynamic_cast<pbcSystem<double>*>(lsys);
nonLinearSystem<double>* nlsys = dynamic_cast<nonLinearSystem<double>*>(lsys);
pathFollowingSystem<double>* pathsys = dynamic_cast<pathFollowingSystem<double>*>(lsys);
// compute ipvariable
if(computedUdF()){
_ipf->setDeformationGradientGradient(this->getMicroBC()->getSecondOrderKinematicalVariable(), IPStateBase::current);
}
_ipf->compute1state(IPStateBase::current, true);
double normFinfInit = this->computeRightHandSide();
// loop until convergence
int iter=0;
if(normFinfInit <_tol){ // no force (can append if contact )
if (_outputFile)
fprintf(_outputFile,"NO FORCE GO TO NEXT STEP\n");
Msg::Error("perturbation is too small!");
return 0;
}
double relnorm = 1;
if (_outputFile)
fprintf(_outputFile,"MICROITERATION n %d : RESIDU : %e \n",iter,relnorm);
while (relnorm>_tol){
iter++;
// Solve KDu = Fext-Fint
int succeed = pathsys->solvePerturbedSystem();
if(!succeed)
{
Msg::Error("solution is not converged in perturbed system");
iter = _timeManager->getMaxNbIterations();
break;
}
// update ipvariable
_ipf->compute1state(IPStateBase::current,true);
// break in case of non-iterative procedure
if (!_iterativeNR) break;
// check convergence criterion
double normFinf = this->computeRightHandSide();
relnorm = normFinf/normFinfInit;
if (_outputFile)
fprintf(_outputFile,"MICROITERATION n %d : RESIDU : %e \n",iter,relnorm);
if((iter == _timeManager->getMaxNbIterations()) or std::isnan(relnorm))
{
// reset system value
Msg::Error("solution is not converged in perturbed system");
iter = _timeManager->getMaxNbIterations(); // for isnan case
break;
}
}
return iter;
};
int nonLinearMechSolver::microNewtonRaphson(const int numstep){
std::string name = "A";
linearSystem<double>* lsys = pAssembler->getLinearSystem(name);
pbcSystem<double> * pbcSys = dynamic_cast<pbcSystem<double>*>(lsys);
nonLinearSystem<double>* nlsys = dynamic_cast<nonLinearSystem<double>*>(lsys);
// compute ipvariable
if(computedUdF()){
_ipf->setDeformationGradientGradient(this->getMicroBC()->getSecondOrderKinematicalVariable(), IPStateBase::current);
}
_ipf->compute1state(IPStateBase::current, true);
double normFinfInit = this->computeRightHandSide();
// loop until convergence
int iter=0;
if(normFinfInit <_tol){ // no force (can append if contact )
if (_outputFile)
fprintf(_outputFile,"NO FORCE GO TO NEXT STEP\n");
return 0;
}
double relnorm = 1;
double normFinf =1;
if (_outputFile)
fprintf(_outputFile,"MICROITERATION n %d : RESIDU : %e \n",iter,relnorm);
while ((relnorm>_tol and normFinf>_absTol)){
iter++;
// Solve KDu = Fext-Fint
double t = Cpu();
int succeed = pAssembler->systemSolveIntReturn();
t = Cpu() -t;
if(!succeed)
{
iter = _timeManager->getMaxNbIterations();
break;
}
// update ipvariable
_ipf->compute1state(IPStateBase::current,true);
// break in case of non-iterative procedure
if (!_iterativeNR) break;
// check convergence criterion
normFinf = this->computeRightHandSide();
relnorm = normFinf/normFinfInit;
if (_outputFile)
fprintf(_outputFile,"MICROITERATION n %d : RESIDU : %e COMPUTING TIME: %f\n",iter,relnorm,t);
if((iter == _timeManager->getMaxNbIterations()) or std::isnan(relnorm))
{
// reset system value
iter = _timeManager->getMaxNbIterations(); // for isnan case
break;
}
}
return iter;
}
int nonLinearMechSolver::microNewtonRaphsonPathFollowing(const int numstep){
std::string name = "A";
linearSystem<double>* lsys =pAssembler->getLinearSystem(name);
nonLinearSystem<double>* nonsys = dynamic_cast<nonLinearSystem<double>*>(lsys);
pathFollowingSystem<double>* pathSys = dynamic_cast<pathFollowingSystem<double>*>(lsys);
// copy state from previous
this->setTimeForBC(pathSys->getControlParameter());
if(computedUdF()){
_ipf->setDeformationGradientGradient(this->getMicroBC()->getSecondOrderKinematicalVariable(), IPStateBase::current);
}
_ipf->compute1state(IPStateBase::current,true);
double normFint = this->computeRightHandSide();
double norm0 = 0.;
// loop until convergence
int iter=0;
double relnorm = 1;
if (_outputFile)
fprintf(_outputFile,"iteration n %d : residu : %e, absolute residu : %e \n",iter,relnorm,normFint);
else if (!_multiscaleFlag)
Msg::Info("iteration n %d : residu : %e, absolute residu : %e ",iter,relnorm,normFint);
while ((relnorm>_tol and normFint>_absTol) or iter == 0){
iter++;
int succeed = pAssembler->systemSolveIntReturn();
if(!succeed)
{
iter = _timeManager->getMaxNbIterations();
break;
}
// update ipvariable
this->setTimeForBC(pathSys->getControlParameter());
if(computedUdF()){
_ipf->setDeformationGradientGradient(this->getMicroBC()->getSecondOrderKinematicalVariable(), IPStateBase::current);
}
_ipf->compute1state(IPStateBase::current,true);
if (!_iterativeNR) break;
normFint = this->computeRightHandSide();
if (norm0 == 0.) norm0 = nonsys->norm0Inf();
relnorm = normFint/norm0;
if (_outputFile)
fprintf(_outputFile,"iteration n %d : residu : %e, absolute residu : %e \n",iter,relnorm,normFint);
else if (!_multiscaleFlag)
Msg::Info("iteration n %d : residu : %e, absolute residu : %e",iter,relnorm,normFint);
if((iter == _timeManager->getMaxNbIterations()) or std::isnan(relnorm))
{
// reset system value
iter = _timeManager->getMaxNbIterations(); // for isnan case
break;
}
}
return iter;
};
void nonLinearMechSolver::setModeView(const int view, const int nbstepArch){
std::string str = "ModeShape" + int2str(view);
_eigview.emplace_back(str,view,nlsField::crude,0,nlsField::val,nbstepArch);
};
void nonLinearMechSolver::tangentAveragingFlag(const bool fl)
{
_tangentflag = fl;
#ifdef _DEBUG
if (_tangentflag) Msg::Info("Tangent averaging is activated");
else Msg::Info("Tangent averaging is desactivated");
#endif
};
void nonLinearMechSolver::stressAveragingFlag(const bool fl){
_stressflag = fl;
#ifdef _DEBUG
if (_stressflag) Msg::Info("Stress averaging is activated");
else Msg::Info("Stress averaging is desactivated");
#endif
};
void nonLinearMechSolver::setStressAveragingMethod(const int method){
_homogenizeStressMethod = STRESS_HOMO_TYPE(method);
};
void nonLinearMechSolver::setTangentAveragingMethod(const int method, const double prec){
_homogenizeTangentMethod = (TANGENT_HOMO_TYPE)method;
_tangentPerturbation = prec;
};
void nonLinearMechSolver::eigenValueSolver(const int num){
_eigOpts.numeigenvalue = num;
};
void nonLinearMechSolver::setEigenSolverParamerters(const int type, const int numiter, const std::string method, const double tol, const bool mktofile, const bool hem){
if (type == 0){
_eigOpts.type = eigenSolverOptions::Static;
Msg::Info("static eigen solver is used");
}
else if (type ==1){
_eigOpts.type = eigenSolverOptions::Dynamic;
Msg::Info("dynamic eigen solver is used");
}
else
Msg::Error("eigensolver type %d is not correctly defined",type);
_eigOpts.maxNumIteration = numiter;
_eigOpts.method = method;
_eigOpts.convergenCriterion = tol;
_eigOpts.MKToFile = mktofile;
_eigOpts.hermitian = hem;
};
void nonLinearMechSolver::setMicroProblemIndentification(int ele, int gpt){
_enumMinus = ele;
_enumPlus = ele;
_gnum = gpt;
};
void nonLinearMechSolver::setMicroProblemIndentification(int eleMinus, int elePlus, int gpt){
_enumMinus = eleMinus;
_enumPlus = elePlus;
_gnum = gpt;
};
void nonLinearMechSolver::setHomogenizationPropertyArchiveFlag(const bool flg){
_isHommProSaveToFile = flg;
};
void nonLinearMechSolver::setDisplacementAndIPArchiveFlag(const bool flg){
_archive = flg;
}
void nonLinearMechSolver::setStrainArchiveFlag(const bool flg){
_isHommStrainSaveToFile = flg;
};
void nonLinearMechSolver::setExtractPerturbationToFileFlag(const bool flag){
_extractPerturbationToFile = flag;
};
void nonLinearMechSolver::setSystemType(const int i){
_systemType = (SYSTEM_TYPE)i;
};
void nonLinearMechSolver::setControlType(const int i){
_controlType = (CONTROL_TYPE)i;
};
void nonLinearMechSolver::setMicroSolverFlag(const bool flag){
_microFlag = flag;
};
void nonLinearMechSolver::setMultiscaleFlag( const bool flag){
_multiscaleFlag = true;
};
void nonLinearMechSolver::setSameStateCriterion(const double cr){
Msg::Info("microscopic computation does not occurs if the strain diffrence is less than %e",cr);
_sameStateCriterion = cr;
};
void nonLinearMechSolver::saveStiffnessMatrixToFile(const int iter){
linearSystem<double>* lsys=NULL;
std::string name="A";
lsys=pAssembler->getLinearSystem(name);
#if defined(HAVE_PETSC)
linearSystemPETSc<double>* lpet=dynamic_cast<linearSystemPETSc<double>*>(lsys);
if(lpet==NULL)return;
else{
functionPETSc::MatToFile(lpet->getMatrix(),"data/Mat_Stiffness.txt");
}
implicitHulbertChungPetsc<double>* hcsys=dynamic_cast<implicitHulbertChungPetsc<double>*>(lsys);
if(hcsys==NULL)return;
else{
functionPETSc::MatToFile(hcsys->getMassMatrix(),"data/Mat_Mass.txt");
}
#endif
};
void nonLinearMechSolver::setDisturbedEigenMode(int num, double val, bool flag){
_eigOpts.isPerturbedEigenMode = flag;
_eigOpts.numberPerturbedMode = num;
_eigOpts.valPerturbedMode = val;
if (flag)
Msg::Info("Set disturbing by eigenmodes: num = %d, val = %f ",num,val);
};
void nonLinearMechSolver::writeDisturbedMeshByEigenVector(eigenSolver& eigS, int numberMode, double fact){
Msg::Info("Begin writing deformed mesh");
GModel* dispgmodel = new GModel();
dispgmodel->readMSH(_meshFileName.c_str());
std::set<MVertex*> computedVertex;
int numMode = eigS.getNumberEigenvectors();
if (numberMode >numMode)
numberMode = numMode;
eigenVectorData eigData(&eigS,pAssembler,numberMode,fact);
for (int i=0; i<domainVector.size(); i++){
partDomain* dom = domainVector[i];
FunctionSpaceBase* sp = dom->getFunctionSpace();
for (elementGroup::elementContainer::const_iterator it = dom->element_begin(); it!= dom->element_end(); it++){
MElement* e = it->second;
std::vector<Dof> keys;
sp->getKeys(e,keys);
// get displacement results
std::vector<double> vals;
eigData.get(keys,vals);
for (int iver =0; iver< e->getNumVertices(); iver++){
MVertex* v = e->getVertex(iver);
MVertex* vdisp = dispgmodel->getMeshVertexByTag(v->getNum());
// modify directly vertex coordinates
if (computedVertex.find(vdisp) == computedVertex.end()){
computedVertex.insert(vdisp);
double x = vals[iver];
double y = vals[iver+1*e->getNumVertices()];
double z = 0.;
if (_dim == 3)
z = vals[iver+2*e->getNumVertices()];
vdisp->x() += x;
vdisp->y() += y;
vdisp->z() += z;
}
}
}
}
// write deformed mesh to file
std::string filename = "Disturb_mesh.msh";
dispgmodel->writeMSH(filename, CTX::instance()->mesh.mshFileVersion,CTX::instance()->mesh.binary, CTX::instance()->mesh.saveAll,CTX::instance()->mesh.saveParametric, CTX::instance()->mesh.scalingFactor);
computedVertex.clear();
delete dispgmodel;
Msg::Info("End writing deformed mesh");
};
void nonLinearMechSolver::setWriteDeformedMeshToFile(bool flag){
_isWriteDeformedMeshToFile = flag;
};
void nonLinearMechSolver::writeDeformedMesh(int step){
Msg::Info("Begin writing deformed mesh");
GModel* dispgmodel = new GModel();
dispgmodel->readMSH(_meshFileName.c_str());
std::set<MVertex*> computedVertex;
for (int i=0; i<domainVector.size(); i++){
partDomain* dom = domainVector[i];
FunctionSpaceBase* sp = dom->getFunctionSpace();
for (elementGroup::elementContainer::const_iterator it = dom->element_begin(); it!= dom->element_end(); it++){
MElement* e = it->second;
std::vector<Dof> keys;
sp->getKeys(e,keys);
// get displacement results
std::vector<double> vals;
pAssembler->getDofValue(keys,vals);
for (int iver =0; iver< e->getNumVertices(); iver++){
MVertex* v = e->getVertex(iver);
MVertex* vdisp = dispgmodel->getMeshVertexByTag(v->getNum());
// modify directly vertex coordinates
if (computedVertex.find(vdisp) == computedVertex.end()){
computedVertex.insert(vdisp);
double x = vals[iver];
double y = vals[iver+1*e->getNumVertices()];
double z = 0.;
if (_dim == 3)
z = vals[iver+2*e->getNumVertices()];
vdisp->x() += x;
vdisp->y() += y;
vdisp->z() += z;
}
}
}
}
// write deformed mesh to file
std::string filename = "deformed_mesh_"+int2str(step)+ ".msh";
dispgmodel->writeMSH(filename, CTX::instance()->mesh.mshFileVersion,CTX::instance()->mesh.binary, CTX::instance()->mesh.saveAll,CTX::instance()->mesh.saveParametric, CTX::instance()->mesh.scalingFactor);
computedVertex.clear();
delete dispgmodel;
Msg::Info("End writing deformed mesh");
};
/** perform a particular test**/
void nonLinearMechSolver::activateTest(const bool fl){
_testFlag = fl;
if (_testFlag)
{
_microFlag = false; // desactive the microFlag
Msg::Info("activation test");
}
};
void nonLinearMechSolver::initialize_test(){
if (_microBC == NULL) {
Msg::Error("test with micro BC must be coupled with one micro BC");
};
if (_pbcGroup != NULL) delete _pbcGroup;
std::vector<elementGroup*>& bgroup = _microBC->getBoundaryElementGroup();
const std::vector<int>& bphysical = _microBC->getBoundaryPhysicals();
bgroup.clear();
for (int i=0; i< bphysical.size(); i++){
elementGroup* gr = new elementGroup(_dim-1,bphysical[i]);
bgroup.push_back(gr);
}
FunctionSpaceBase* lagspace = domainVector[0]->getFunctionSpace();
_pbcGroup = new pbcConstraintElementGroup(this,lagspace,NULL);
/*create all linear constraints*/
_pbcGroup->createConstraintForTest();
/*enforce constraints to system*/
_pbcGroup->applyLinearConstraintsToSystem(pAssembler);
/* init homogenized stress file*/
_rveVolume = _pbcGroup->getRVEVolume();
//this->setRVEGeometricalInertia(_pAl->getRVEGeometricalInertia());
//this->setRVEGeometry(_pAl->getRVEGeometry());
this->setRVEGeometricalInertia(_pbcGroup->getRVEGeometricalInertia());
this->setRVEGeometry(_pbcGroup->getRVEGeometry());
};
void nonLinearMechSolver::displacementBCOnControlNode(const int pos, const int comp, const double value){
allCornerConstraint.emplace_back();
nonLinearDirichletBCAtCorner& cornerConstraint = allCornerConstraint.back();
cornerConstraint._tag = pos;
cornerConstraint._comp = comp;
cornerConstraint._cornerNumber = pos;
cornerConstraint._f = new simpleFunctionTime<double>(value);
};
void nonLinearMechSolver::displacementBCOnControlNode(const int pos, const int comp, simpleFunctionTime<double> *fct)
{
allCornerConstraint.emplace_back();
nonLinearDirichletBCAtCorner& cornerConstraint = allCornerConstraint.back();
cornerConstraint._tag = pos;
cornerConstraint._comp = comp;
cornerConstraint._cornerNumber = pos;
cornerConstraint._f = fct;
}
void nonLinearMechSolver::forceBCOnControlNode(const int pos, const int comp, const double value){
allCornerForce.emplace_back();
nonLinearNeumannBCAtCorner& cornerConstraint = allCornerForce.back();
cornerConstraint._tag = pos;
cornerConstraint._comp = comp;
cornerConstraint._cornerNumber = pos;
cornerConstraint._f = new simpleFunctionTime<double>(value);
};
void nonLinearMechSolver::getDofOnControlNode(const int pos, std::vector<Dof>& R){
if (_testFlag){
if (_pbcGroup != NULL){
_pbcGroup->getDofsOfCornerVertex(pos,R);
}
}
};
void nonLinearMechSolver::setExtractCohesiveLawFromMicroDamage(const bool check){
_damageToCohesiveJump = check;
if (check){
_tangentflag = true;
Msg::Info("extract cohesive jump from microdamage, tangent computation has to be activated");
_checkFailureOnset = true;
}
};
void nonLinearMechSolver::setLostSolutionUniquenssTolerance(const double tol){
_lostSolutionUniquenssTolerance = tol;
}
void nonLinearMechSolver::setExtractIrreversibleEnergyFlag(const bool ex){
_extractIrreversibleEnergy =ex;
}
void nonLinearMechSolver::setLocalizationNormal(const SVector3& normal){
_lostSolutionUniquenssNormal = normal;
if (_lostSolutionUniquenssNormal.norm() == 0.){
Msg::Info("zero normal is set");
}
else{
_lostSolutionUniquenssNormal.normalize();
}
};
void nonLinearMechSolver::setLocalizationNormal(const double n1, const double n2, const double n3){
_lostSolutionUniquenssNormal(0) = n1;
_lostSolutionUniquenssNormal(1) = n2;
_lostSolutionUniquenssNormal(2) = n3;
if (_lostSolutionUniquenssNormal.norm() == 0.){
Msg::Info("zero normal is set");
}
else{
_lostSolutionUniquenssNormal.normalize();
}
};
void nonLinearMechSolver::setRVELengthInNormalDirection(const double l, const double sfR){
_RVELengthInCohesiveNormal = l;
_surfaceReductionRatio = sfR;
};
void nonLinearMechSolver::setVoidPartInLocalizationBand(const double vp){
_voidPartInLocalizationBand = vp;
};
void nonLinearMechSolver::setCheckFailureOnset(const bool fl, const bool withNormal){
_checkFailureOnset = fl;
_checkWithNormal = withNormal;
if (_checkFailureOnset){
if (_checkWithNormal){
printf("failure will check with prescribed normal\n");
}
else{
printf("failure will check without normal\n");
}
}
};
void nonLinearMechSolver::switchMicroBC(const nonLinearMicroBC* mbc){
this->addMicroBC(mbc);
// update data with solver
nonLinearMicroBC* microBC = this->getMicroBC();
microBC->updateWithSolver(this);
// recreate system,
this->createMicroSystem();
// init all other BC, fixed DOf, etc
this->initAllBCsOnDofs();
// create new pbcAlgorithm
if (_pAl != NULL){
delete _pAl;
}
_pAl = new pbcAlgorithm(this); // create all constraints, etc
// renumber Dof and reallocate the system
this->microNumberDof();
// make data as previous if exists
this->updateDataFromPreviousSolver();
_ipf->copy(IPStateBase::current,IPStateBase::initial);
_ipf->copy(IPStateBase::current,IPStateBase::previous);
};
void nonLinearMechSolver::setSwitchMicroBCFlag(const bool fl){
_failureBCIsSwitched = fl;
};
void nonLinearMechSolver::setExtractElasticTangentOperator(const bool fl){
_extractElasticTangentOperator = fl;
if (_extractElasticTangentOperator){
Msg::Info("extract elastic tangent works if setTangentAveragingMethod(2) is used ");
}
};
void nonLinearMechSolver::setBatchComputationsFlag(const bool fl){
_batchComputations = fl;
};