IRResultType Delamination :: initializeFrom(InputRecord *ir) { IRResultType result; // Required by IR_GIVE_FIELD macro result = EnrichmentItem :: initializeFrom(ir); if ( result != IRRT_OK ) return result; // Compute the delamination xi-coord IR_GIVE_FIELD(ir, this->interfaceNum, _IFT_Delamination_interfacenum); // interface number from the bottom IR_GIVE_FIELD(ir, this->crossSectionNum, _IFT_Delamination_csnum); LayeredCrossSection *layeredCS = dynamic_cast< LayeredCrossSection * >( this->giveDomain()->giveCrossSection(this->crossSectionNum) ); if ( layeredCS == NULL ) { OOFEM_WARNING("Delamination EI requires a valid layered cross section number input: see record '%s'.", _IFT_Delamination_csnum); return IRRT_BAD_FORMAT; } else if ( this->interfaceNum.giveSize() < 1 || this->interfaceNum.giveSize() > 2 ) { OOFEM_WARNING("Size of record 'interfacenum' must be 1 or 2"); return IRRT_BAD_FORMAT; } // check that interface numbers are valid interfaceNum.printYourself("interface num"); for ( int i = 1; i <= this->interfaceNum.giveSize(); i++ ) { if ( this->interfaceNum.at(i) < 1 || this->interfaceNum.at(i) >= layeredCS->giveNumberOfLayers() ) { OOFEM_WARNING( "Cross section does not contain the interface number (%d) specified in the record '%s' since number of layers is %d.", this->interfaceNum.at(i), _IFT_Delamination_interfacenum, layeredCS->giveNumberOfLayers() ); return IRRT_BAD_FORMAT; } } // compute xi-coord of the delamination this->delamXiCoord = -1.0; double totalThickness = layeredCS->give(CS_Thickness, FloatArray(), NULL, false); // no position available for ( int i = 1; i <= this->interfaceNum.at(1); i++ ) { this->delamXiCoord += layeredCS->giveLayerThickness(i) / totalThickness * 2.0; this->xiBottom += layeredCS->giveLayerThickness(i) / totalThickness * 2.0; } if ( this->interfaceNum.giveSize() == 2 ) { if ( this->interfaceNum.at(1) >= this->interfaceNum.at(2) ) { OOFEM_WARNING("second intercfacenum must be greater than the first one"); return IRRT_BAD_FORMAT; } for ( int i = 1; i <= this->interfaceNum.at(2); i++ ) { this->xiTop += layeredCS->giveLayerThickness(i) / totalThickness * 2.0; } } else { this->xiTop = 1.0; // default is the top surface } IR_GIVE_OPTIONAL_FIELD(ir, this->matNum, _IFT_Delamination_CohesiveZoneMaterial); if ( this->matNum > 0 ) { this->mat = this->giveDomain()->giveMaterial(this->matNum); } return IRRT_OK; }
void StructuralMaterialEvaluator :: solveYourself() { Domain *d = this->giveDomain(1); MaterialMode mode = _3dMat; FloatArray initialStrain(6); gps.clear(); gps.reserve(d->giveNumberOfMaterialModels()); for ( int i = 1; i <= d->giveNumberOfMaterialModels(); i++ ) { std :: unique_ptr< GaussPoint > gp = std::make_unique<GaussPoint>(nullptr, i, FloatArray(0), 1, mode); gps.emplace_back( std :: move(gp) ); // Initialize the strain vector; StructuralMaterialStatus *status = static_cast< StructuralMaterialStatus * >( d->giveMaterial(i)->giveStatus( gps[i-1].get() ) ); status->letStrainVectorBe(initialStrain); } std :: string outname = this->giveOutputBaseFileName() + ".matdata"; this->outfile.open( outname.c_str() ); this->timer.startTimer(EngngModelTimer :: EMTT_AnalysisTimer); TimeStep *tStep = giveNextStep(); // Note, strain == strain-rate (kept as strain for brevity) int maxiter = 100; // User input? FloatArray stressC, deltaStrain, strain, stress, res; stressC.resize( sControl.giveSize() ); res.resize( sControl.giveSize() ); FloatMatrix tangent, reducedTangent; for ( int istep = 1; istep <= this->numberOfSteps; ++istep ) { this->timer.startTimer(EngngModelTimer :: EMTT_SolutionStepTimer); for ( int imat = 1; imat <= d->giveNumberOfMaterialModels(); ++imat ) { GaussPoint *gp = gps[imat-1].get(); StructuralMaterial *mat = static_cast< StructuralMaterial * >( d->giveMaterial(imat) ); StructuralMaterialStatus *status = static_cast< StructuralMaterialStatus * >( mat->giveStatus(gp) ); strain = status->giveStrainVector(); // Update the controlled parts for ( int j = 1; j <= eControl.giveSize(); ++j ) { int p = eControl.at(j); strain.at(p) = d->giveFunction( cmpntFunctions.at(p) )->evaluateAtTime( tStep->giveIntrinsicTime() ); } for ( int j = 1; j <= sControl.giveSize(); ++j ) { int p = sControl.at(j); stressC.at(j) = d->giveFunction( cmpntFunctions.at(p) )->evaluateAtTime( tStep->giveIntrinsicTime() ); } //strain.add(-100, {6.27e-06, 6.27e-06, 6.27e-06, 0, 0, 0}); for ( int iter = 1; iter < maxiter; iter++ ) { #if 0 // Debugging: mat->give3dMaterialStiffnessMatrix(tangent, TangentStiffness, gp, tStep); tangent.printYourself("# tangent"); strain.zero(); mat->giveRealStressVector_3d(stress, gp, strain, tStep); FloatArray strain2; tangent.solveForRhs(stress, strain2); strain2.printYourself("# thermal expansion"); break; #endif strain.printYourself("Macro strain guess"); mat->giveRealStressVector_3d(stress, gp, strain, tStep); for ( int j = 1; j <= sControl.giveSize(); ++j ) { res.at(j) = stressC.at(j) - stress.at( sControl.at(j) ); } OOFEM_LOG_INFO("*** Time step: %d (t = %.2e), Material %d, Iteration: %d, Residual = %e (tolerance %.2e)\n", istep, tStep->giveIntrinsicTime(), imat, iter, res.computeNorm(), tolerance); if ( res.computeNorm() <= tolerance ) { break; } else { if ( tangent.giveNumberOfRows() == 0 || !keepTangent ) { mat->give3dMaterialStiffnessMatrix(tangent, TangentStiffness, gp, tStep); } // Pick out the stress-controlled part; reducedTangent.beSubMatrixOf(tangent, sControl, sControl); // Update stress-controlled part of the strain reducedTangent.solveForRhs(res, deltaStrain); //deltaStrain.printYourself("deltaStrain"); for ( int j = 1; j <= sControl.giveSize(); ++j ) { strain.at( sControl.at(j) ) += deltaStrain.at(j); } } } if ( res.computeNorm() > tolerance ) { OOFEM_WARNING("Residual did not converge!"); } // This material model has converged, so we update it and go on to the next. gp->updateYourself(tStep); } this->timer.stopTimer(EngngModelTimer :: EMTT_SolutionStepTimer); this->doStepOutput(tStep); tStep = giveNextStep(); } this->timer.stopTimer(EngngModelTimer :: EMTT_AnalysisTimer); this->outfile.close(); }
FloatArray FloatArray::subArray(int offset, int length){ ASSERT(size >= offset+length, "Array too small"); return FloatArray(data+offset, length); }
FloatArray getSamples(int channel) { return FloatArray(buffer[channel], size); }
boost::shared_ptr<PrimVars> EmitterMesh::particlesOnFace(int faceIdx) { const MeshFace& face = m_faces[faceIdx]; boost::shared_ptr<PrimVars> interpVars(new PrimVars()); float numParticlesCts = face.weight*m_totParticles; int numParticles = Aqsis::lfloor(face.weight*m_totParticles); if(numParticlesCts - numParticles > uRand()) ++numParticles; if(numParticles == 0) return boost::shared_ptr<PrimVars>(); std::vector<int> storageCounts; // Create storage for all interpolated output parameters. for(PrimVars::const_iterator i = m_primVars->begin(), end = m_primVars->end(); i != end; ++i) { if(i->token.Class() == Aqsis::class_constant || i->token.Class() == Aqsis::class_uniform) { storageCounts.push_back(0); // uniform and constant primvars on the mesh interpolate to // constant primvars on the curves interpVars->append(Aqsis::CqPrimvarToken(Aqsis::class_constant, i->token.type(), i->token.count(), i->token.name() + "_emit")); // We can just copy over constant/uniform data; no interpolation needed. if(i->token.Class() == Aqsis::class_constant) *interpVars->back().value = *i->value; else { int stride = i->token.storageCount(); interpVars->back().value->assign( i->value->begin() + stride*faceIdx, i->value->begin() + stride*(faceIdx+1)); } } else { storageCounts.push_back(i->token.storageCount()); // varying, vertex, facevarying and facevertex primvars interpolate // to uniform primvars on the curves interpVars->append(Aqsis::CqPrimvarToken(Aqsis::class_uniform, i->token.type(), i->token.count(), i->token.name() + "_emit")); // Allocate storage interpVars->back().value->assign(numParticles*storageCounts.back(), 0); } } // Float offsets for randomized quasi Monte-Carlo distribution float uOffset = float(std::rand())/RAND_MAX; float vOffset = float(std::rand())/RAND_MAX; // loop over child particles for(int particleNum = 0; particleNum < numParticles; ++particleNum) { // get random weights for the vertices of the current face. float u = uOffset + m_lowDiscrep.Generate(0, particleNum); if(u > 1) u -= 1; float v = vOffset + m_lowDiscrep.Generate(1, particleNum); if(v > 1) v -= 1; float weights[4]; if(face.numVerts == 3) { if(u + v > 1) { u = 1-u; v = 1-v; } weights[0] = 1 - u - v; weights[1] = u; weights[2] = v; weights[3] = 0.0f; } else { weights[0] = (1-u)*(1-v); weights[1] = (1-u)*v; weights[2] = u*v; weights[3] = u*(1-v); } // loop over primitive variables. Each varying/vertex/facevarying // /facevertex primvar is interpolated from the parent mesh to the // current child particle. int storageIndex = 0; PrimVars::iterator destVar = interpVars->begin(); for(PrimVars::const_iterator srcVar = m_primVars->begin(), end = m_primVars->end(); srcVar != end; ++srcVar, ++storageIndex, ++destVar) { int storageStride = storageCounts[storageIndex]; // Get pointers to source parameters for the vertices const float* src[4] = {0,0,0,0}; switch(srcVar->token.Class()) { case Aqsis::class_varying: case Aqsis::class_vertex: for(int i = 0; i < face.numVerts; ++i) src[i] = &(*srcVar->value)[storageStride*face.v[i]]; break; case Aqsis::class_facevarying: case Aqsis::class_facevertex: for(int i = 0; i < face.numVerts; ++i) src[i] = &(*srcVar->value)[ storageStride*(face.faceVaryingIndex+i) ]; break; default: // Other classes don't need any interpolation, so we just // go to the next primvar in m_primVars continue; } // Interpolate the primvar pointed to by srcVar to the current // particle position. This is just a a weighted average of values // attached to vertices of the current face. float* dest = &(*destVar->value)[storageStride*particleNum]; for(int k = 0; k < storageStride; ++k, ++dest) { *dest = 0; for(int i = 0; i < face.numVerts; ++i) { *dest += *src[i] * weights[i]; ++src[i]; } } } } // Finally, add extra face-constant parameters. Vec3 Ng_emitVec = faceNormal(face); float Ng_emit[] = {Ng_emitVec.x(), Ng_emitVec.y(), Ng_emitVec.z()}; interpVars->append(Aqsis::CqPrimvarToken(Aqsis::class_constant, Aqsis::type_normal, 1, "Ng_emit"), FloatArray(Ng_emit, Ng_emit+3)); return interpVars; }
IRResultType Delamination :: initializeFrom(InputRecord *ir) { IRResultType result; // Required by IR_GIVE_FIELD macro result = EnrichmentItem :: initializeFrom(ir); if ( result != IRRT_OK ) return result; // Compute the delamination xi-coord IR_GIVE_FIELD(ir, this->interfaceNum, _IFT_Delamination_interfacenum); // interface number from the bottom IR_GIVE_FIELD(ir, this->crossSectionNum, _IFT_Delamination_csnum); if ( ir->hasField(_IFT_Delamination_averageStresses) ) { this->recoverStresses = false; //printf("averageStresses"); } #if 1 // update: csnum is now an IntArray of cross sections viable for delamination bool checkCS = false; double totalThickness(0.0); FloatArray layerThicknesses; int numberOfLayers(0); for (int iCS : this->crossSectionNum) { LayeredCrossSection *layeredCS = dynamic_cast< LayeredCrossSection * >( this->giveDomain()->giveCrossSection(iCS) ); if ( layeredCS == NULL ) { OOFEM_WARNING("Delamination EI requires a valid layered cross section number input: see record '%s'.", _IFT_Delamination_csnum); return IRRT_BAD_FORMAT; } else if ( this->interfaceNum.giveSize() < 1 || this->interfaceNum.giveSize() > 2 ) { OOFEM_WARNING("Size of record 'interfacenum' must be 1 or 2"); return IRRT_BAD_FORMAT; } // check that interface numbers are valid //interfaceNum.printYourself("interface num"); for ( int i = 1; i <= this->interfaceNum.giveSize(); i++ ) { if ( this->interfaceNum.at(i) < 1 || this->interfaceNum.at(i) >= layeredCS->giveNumberOfLayers() ) { OOFEM_WARNING( "Cross section does not contain the interface number (%d) specified in the record '%s' since number of layers is %d.", this->interfaceNum.at(i), _IFT_Delamination_interfacenum, layeredCS->giveNumberOfLayers() ); return IRRT_BAD_FORMAT; } } if (checkCS) { if ( layeredCS->give(CS_Thickness, FloatArray(), NULL, false) != totalThickness ) { OOFEM_WARNING("Delamination cross section have different totalThickness: see record '%s'.", _IFT_Delamination_csnum); return IRRT_BAD_FORMAT; } if ( layeredCS->giveNumberOfLayers() != numberOfLayers ) { OOFEM_WARNING("Delamination cross section have different number of layers: see record '%s'.", _IFT_Delamination_csnum); return IRRT_BAD_FORMAT; } } else numberOfLayers = layeredCS->giveNumberOfLayers(); totalThickness = layeredCS->give(CS_Thickness, FloatArray(), NULL, false); // no position available for ( int i = 1 ; i <= numberOfLayers ; i++) { double layerThickness = layeredCS->giveLayerThickness(i); if (checkCS) { if ( layerThickness != layerThicknesses.at(i) ) { OOFEM_WARNING("Delamination cross section have different layer thicknesses: see record '%s'.", _IFT_Delamination_csnum); return IRRT_BAD_FORMAT; } layerThicknesses.at(i) = layerThickness; } else { layerThicknesses.append(layeredCS->giveLayerThickness(i)); } } // compute xi-coord of the delamination this->delamXiCoord = -1.0; this->xiBottom = -1.0; for ( int i = 1; i <= this->interfaceNum.at(1); i++ ) { this->delamXiCoord += layeredCS->giveLayerThickness(i) / totalThickness * 2.0; this->xiBottom += layeredCS->giveLayerThickness(i) / totalThickness * 2.0; } if ( this->interfaceNum.giveSize() == 2 ) { if ( this->interfaceNum.at(1) >= this->interfaceNum.at(2) ) { OOFEM_WARNING("second intercfacenum must be greater than the first one"); return IRRT_BAD_FORMAT; } this->xiTop = -1.0; for ( int i = 1; i <= this->interfaceNum.at(2); i++ ) { this->xiTop += layeredCS->giveLayerThickness(i) / totalThickness * 2.0; } } else { this->xiTop = 1.0; // default is the top surface } checkCS = true; } #else // old csnum (int version). NB: this was a bug since element nodes that where not part of the cross section could be enriched. LayeredCrossSection *layeredCS = dynamic_cast< LayeredCrossSection * >( this->giveDomain()->giveCrossSection(this->crossSectionNum) ); if ( layeredCS == NULL ) { OOFEM_WARNING("Delamination EI requires a valid layered cross section number input: see record '%s'.", _IFT_Delamination_csnum); return IRRT_BAD_FORMAT; } else if ( this->interfaceNum.giveSize() < 1 || this->interfaceNum.giveSize() > 2 ) { OOFEM_WARNING("Size of record 'interfacenum' must be 1 or 2"); return IRRT_BAD_FORMAT; } // check that interface numbers are valid //interfaceNum.printYourself("interface num"); for ( int i = 1; i <= this->interfaceNum.giveSize(); i++ ) { if ( this->interfaceNum.at(i) < 1 || this->interfaceNum.at(i) >= layeredCS->giveNumberOfLayers() ) { OOFEM_WARNING( "Cross section does not contain the interface number (%d) specified in the record '%s' since number of layers is %d.", this->interfaceNum.at(i), _IFT_Delamination_interfacenum, layeredCS->giveNumberOfLayers() ); return IRRT_BAD_FORMAT; } } // compute xi-coord of the delamination this->delamXiCoord = -1.0; double totalThickness = layeredCS->give(CS_Thickness, FloatArray(), NULL, false); // no position available for ( int i = 1; i <= this->interfaceNum.at(1); i++ ) { this->delamXiCoord += layeredCS->giveLayerThickness(i) / totalThickness * 2.0; this->xiBottom += layeredCS->giveLayerThickness(i) / totalThickness * 2.0; } if ( this->interfaceNum.giveSize() == 2 ) { if ( this->interfaceNum.at(1) >= this->interfaceNum.at(2) ) { OOFEM_WARNING("second intercfacenum must be greater than the first one"); return IRRT_BAD_FORMAT; } for ( int i = 1; i <= this->interfaceNum.at(2); i++ ) { this->xiTop += layeredCS->giveLayerThickness(i) / totalThickness * 2.0; } } else { this->xiTop = 1.0; // default is the top surface } #endif IR_GIVE_OPTIONAL_FIELD(ir, this->matNum, _IFT_Delamination_CohesiveZoneMaterial); if ( this->matNum > 0 ) { this->mat = this->giveDomain()->giveMaterial(this->matNum); } IR_GIVE_OPTIONAL_FIELD(ir, this->initiationFactor, _IFT_Delamination_initiationFactor); if ( this->initiationFactor <= 0 ) { OOFEM_ERROR("initiation scale factor must be greater than 0."); return IRRT_BAD_FORMAT; } IR_GIVE_OPTIONAL_FIELD(ir, this->initiationRadius, _IFT_Delamination_initiationRadius); if ( this->initiationRadius < 0 ) { OOFEM_ERROR("initiation radius must be greater or equal than 0."); return IRRT_BAD_FORMAT; } return IRRT_OK; }
Matrix::Matrix(){ FloatArray(); }