void Diffusion::flux_matrix(const FEMesh *mesh, const Element *el, const ElementFuncNodeIterator &j, const Flux *flux, const MasterPosition &pt, double time, SmallSystem *fluxdata) const { // The atom flux matrix M_{ij} multiplies the vector of nodal // concentrations to give the vector atom current J at point pt. // M_{ij} = -D_{ik} grad_k N_j // J_i = -M_{ij} T_j // where N_j is the shapefunction at node j. // printf("flux"); if (*flux != *atom_flux) { throw ErrProgrammingError("Unexpected flux", __FILE__, __LINE__); } double sf = j.shapefunction( pt ); double dsf0 = j.dshapefunction( 0, pt ); double dsf1 = j.dshapefunction( 1, pt ); #if DIM==3 double dsf2 = j.dshapefunction( 2, pt ); #endif const SymmMatrix3 cond( conductivitytensor( mesh, el, pt ) ); // Loop over flux components. Loop over all components, even if // the flux is in-plane, because the out-of-plane components of // the flux matrix are used to construct the constraint equation. for(VectorFieldIterator i; !i.end(); ++i){ #if DIM==2 // in-plane concentration gradient contributions fluxdata->stiffness_matrix_element( i, concentration, j ) -= cond(i.integer(), 0) * dsf0 + cond(i.integer(), 1) * dsf1; // out-of-plane concentration gradient contribution if(!concentration->in_plane(mesh)) fluxdata->stiffness_matrix_element(i, concentration->out_of_plane(), j) -= cond(i.integer(), 2) * sf; #elif DIM==3 fluxdata->stiffness_matrix_element( i, concentration, j ) -= cond( i.integer(), 0 ) * dsf0 + cond( i.integer(), 1 ) * dsf1 + cond( i.integer(), 2 ) * dsf2; #endif } } // end of 'Diffusion::flux_matrix'
void AtomFluxJumpTest::force_deriv_matrix(const FEMesh* mesh, const Element* element, const Equation* eqn, const ElementFuncNodeIterator &efi, const MasterPosition& gpt, double time, SmallSystem *eqndata) const { std::cerr << "AtomFluxJumpTest::force_deriv_matrix called." << std::endl; FuncNode *left,*right; left = dynamic_cast<FuncNode*>(efi.leftnode()); right = dynamic_cast<FuncNode*>(efi.rightnode()); std::cerr << "Left: " << *left << std::endl; std::cerr << "Right: " << *right << std::endl; }
void MassDensityProp::second_time_deriv_matrix(const FEMesh *mesh, const Element *lmnt, const Equation *eqn, const ElementFuncNodeIterator &eni, const MasterPosition &mpos, double time, SmallSystem *eqdata) const { // Optional -- check that the equation is the right one. double shapeFuncVal = eni.shapefunction(mpos); for(IteratorP component = eqn->iterator(); !component.end(); ++component) { eqdata->mass_matrix_element(component, disp, component, eni) -= rho_ * shapeFuncVal; } }
void Mobility::first_time_deriv_matrix(const FEMesh *mesh, const Element *lmnt, const Equation *eqn, const ElementFuncNodeIterator &eni, const MasterPosition &mpos, double time, SmallSystem *eqdata) const { double shapeFuncVal = eni.shapefunction( mpos ); for(IteratorP eqncomp = eqn->iterator(); !eqncomp.end(); ++eqncomp) { // Kinetic coefficient is unity. eqdata->damping_matrix_element(eqncomp,concentration,eqncomp,eni) += \ shapeFuncVal; } }
void NonlinearHeatSource::force_deriv_matrix(const FEMesh *mesh, const Element *element, const Equation *eqn, const ElementFuncNodeIterator &j, const MasterPosition &point, double time, SmallSystem *eqndata ) const { double fieldVal, funcDerivVal, shapeFuncVal; Coord coord; // first compute the current value of the temperature field at the gauss point fieldVal = 0.0; for(CleverPtr<ElementFuncNodeIterator> node(element->funcnode_iterator()); !node->end(); ++*node){ shapeFuncVal = node->shapefunction( point ); fieldVal += shapeFuncVal * (*temperature)( *node )->value( mesh ); } // compute the value of the deriv of the nonlinear source function // using the world coordinates and the value of the temperature field coord = element->from_master( point ); #if DIM==2 funcDerivVal = nonlin_heat_source_deriv_wrt_temperature( coord.x, coord.y, 0.0, time, fieldVal ); #elif DIM==3 funcDerivVal = nonlin_heat_source_deriv_wrt_temperature( coord.x, coord.y, coord.z, time, fieldVal ); #endif // compute the value of the jth shape function at gauss point point and // add its contribution f(point)*phi_j(point) to the small stiffness-like matrix shapeFuncVal = j.shapefunction( point ); for (IteratorP eqncomp = eqn->iterator(); !eqncomp.end(); ++eqncomp) eqndata->force_deriv_matrix_element( eqncomp, temperature, j ) -= funcDerivVal * shapeFuncVal; } // NonlinearHeatSource::force_deriv_matrix
void NonlinearForceDensity::force_deriv_matrix(const FEMesh *mesh, const Element *element, const Equation *eqn, const ElementFuncNodeIterator &j, const MasterPosition &point, double time, SmallSystem *eqndata) const { SmallMatrix forceDeriv(3); DoubleVec fieldVal(3); double shapeFuncVal; Coord coord; // first compute the current value of the displacement field at the gauss point fieldVal[0] = fieldVal[1] = 0.0; #if DIM==3 fieldVal[2] = 0.0; #endif for(CleverPtr<ElementFuncNodeIterator> node(element->funcnode_iterator()); !node->end(); ++*node){ shapeFuncVal = node->shapefunction( point ); fieldVal[0] += shapeFuncVal * (*displacement)( *node, 0 )->value( mesh ); fieldVal[1] += shapeFuncVal * (*displacement)( *node, 1 )->value( mesh ); #if DIM==3 fieldVal[2] += shapeFuncVal * (*displacement)( *node, 2 )->value( mesh ); #endif } // now compute the value of the force density derivative function // for the current coordinate x,y,z, time and displacement, // the nonlinear force density derivative function returns the // corresponding force derivative value in the array 'forceDeriv', // the function definition is given in USER_CODE.C coord = element->from_master( point ); #if DIM==2 nonlin_force_density_deriv( coord.x, coord.y, 0.0, time, fieldVal, forceDeriv ); #elif DIM==3 nonlin_force_density_deriv( coord.x, coord.y, coord.z, time, fieldVal, forceDeriv ); #endif // compute the value of the jth shape function at gauss point point and add // its contribution Df(point,field)*phi_j(point) to the small mass-like matrix shapeFuncVal = j.shapefunction( point ); for(IteratorP eqncomp = eqn->iterator(); !eqncomp.end(); ++eqncomp) { int eqno = eqncomp.integer(); for (IteratorP fieldcomp = displacement->iterator(); !fieldcomp.end(); ++fieldcomp) { // TODO: get rid of this loop, and write component contributions explicitly int fieldno = fieldcomp.integer(); eqndata->force_deriv_matrix_element( eqncomp, displacement, fieldcomp, j ) -= forceDeriv( eqno, fieldno ) * shapeFuncVal; } } } // end of 'NonlinearForceDensity::force_deriv_matrix'
void CLargeStrainElasticity::flux_matrix(const FEMesh *mesh, const Element *element, const ElementFuncNodeIterator &node, const Flux *flux, const MasterPosition &pt, double time, SmallSystem *fluxmtx) const { int (*ij2voigt)(int,int) = &SymTensorIndex::ij2voigt; // shorter func name SmallMatrix dU(3); // gradient of displacement double Fval; // the value of the shape function (for node) DoubleVec dF(3); // and its derivative at the given pt bool inplane = false; // needed both in 2D & 3D versions regardless, // passed to contract_C_dU_dF #if DIM==2 // in 2D, check if it is an in-plane eqn or a plane-flux eqn. static CompoundField *displacement = dynamic_cast<CompoundField*>(Field::getField("Displacement")); inplane = displacement->in_plane( mesh ); #endif // check for unexpected flux, flux should be a stress flux if (*flux != *stress_flux) { throw ErrProgrammingError("Unexpected flux", __FILE__, __LINE__); } // evaluate the shape function and its gradient (of node) at the given pt Fval = node.shapefunction( pt ); // value of the shape function dF[0] = node.dshapefunction( 0, pt ); // x-deriv of the shape function dF[1] = node.dshapefunction( 1, pt ); // y-deriv of the shape function #if DIM==3 dF[2] = node.dshapefunction( 2, pt ); // z-deriv of the shape function #endif computeDisplacementGradient( mesh, element, pt, dU ); const Cijkl CC = cijkl( mesh, element, pt ); // elasticity modulus // add the flux contributions to stiffness matrix element // k_indx is needed for fluxmtx->stifness_matrix_element function, // which does not take int k as argument VectorFieldIndex k_indx; for (SymTensorIterator ij_iter; !ij_iter.end(); ++ij_iter) { int k0, k1, k2, ij = ij_iter.integer(); double nonlinear_part; // to store the sum from the nonlinear terms // TODO: Use tensor iterators for k0, k1, k2. #if DIM==2 // sum CC(i,j,k,l)*dF(l), k=0 over l=0,1, then add to stiffness_mtx k_indx.set( 0 ); k0 = ij2voigt( 0,0 ); k1 = ij2voigt( 0,1 ); nonlinear_part = contract_C_dU_dF(CC, dU, dF, ij, 0, inplane ); // at ij, k=0 fluxmtx->stiffness_matrix_element( ij_iter, displacement, k_indx, node ) += CC( ij,k0 ) * dF[0] + CC( ij,k1 ) * dF[1] + nonlinear_part; // sum CC(i,j,k,l)*dF(l), k=1 over l=0,1, then add to stiffness_mtx k_indx.set( 1 ); k0 = ij2voigt( 1,0 ); k1 = ij2voigt( 1,1 ); nonlinear_part = contract_C_dU_dF( CC, dU, dF, ij, 1, inplane ); // at ij, k=1 fluxmtx->stiffness_matrix_element( ij_iter, displacement, k_indx, node ) += CC( ij,k0 ) * dF[0] + CC( ij,k1 ) * dF[1] + nonlinear_part; #elif DIM==3 // sum CC(i,j,k,l)*dF(l), k=0 over l=0,1,2 then add to stiffness_mtx k_indx.set( 0 ); k0 = ij2voigt( 0,0 ); k1 = ij2voigt( 0,1 ); k2 = ij2voigt( 0,2 ); nonlinear_part = contract_C_dU_dF( CC, dU, dF, ij, 0, inplane ); // at ij, k=0 fluxmtx->stiffness_matrix_element( ij_iter, displacement, k_indx, node ) += CC( ij,k0 ) * dF[0] + CC( ij,k1 ) * dF[1] + CC( ij,k2 ) * dF[2] + nonlinear_part; // sum CC(i,j,k,l)*dF(l), k=1 over l=0,1,2 then add to stiffness_mtx k_indx.set( 1 ); k0 = ij2voigt( 1,0 ); k1 = ij2voigt( 1,1 ); k2 = ij2voigt( 1,2 ); nonlinear_part = contract_C_dU_dF( CC, dU, dF, ij, 1, inplane ); // at ij, k=1 fluxmtx->stiffness_matrix_element( ij_iter, displacement, k_indx, node ) += CC( ij,k0 ) * dF[0] + CC( ij,k1 ) * dF[1] + CC( ij,k2 ) * dF[2] + nonlinear_part; // sum CC(i,j,k,l)*dF(l), k=2 over l=0,1,2 then add to stiffness_mtx k_indx.set( 2 ); k0 = ij2voigt( 2,0 ); k1 = ij2voigt( 2,1 ); k2 = ij2voigt( 2,2 ); nonlinear_part = contract_C_dU_dF( CC, dU, dF, ij, 2, inplane ); // at ij, k=2 fluxmtx->stiffness_matrix_element( ij_iter, displacement, k_indx, node ) += CC( ij,k0 ) * dF[0] + CC( ij,k1 ) * dF[1] + CC( ij,k2 ) * dF[2] + nonlinear_part; #endif #if DIM==2 if ( !inplane ) // now contributions from z-deriv of displacement field { Field *disp_z_deriv = displacement->out_of_plane(); for(IteratorP k_iter = disp_z_deriv->iterator( ALL_INDICES ); !k_iter.end(); ++k_iter) { double diag_factor = ( k_iter.integer()==2 ? 1.0 : 0.5 ); k2 = ij2voigt( 2, k_iter.integer() ); fluxmtx->stiffness_matrix_element( ij_iter, disp_z_deriv, k_iter, node ) += diag_factor * Fval * CC( ij,k2 ); } } // end of 'if (!inplane)' #endif } // end of loop over ij } // end of 'CLargeStrainElasticity::flux_matrix'
void EqnProperty::force_deriv_matrix(const FEMesh *mesh, const Element *element, const Equation *eqn, const ElementFuncNodeIterator &node, const MasterPosition &pt, double time, SmallSystem *eqndata) const { int nrows = eqndata->nrows(); int ncols = eqndata->ncols(); DoubleVec forceVec0(nrows), forceVec1(nrows); SmallSystem eqndata0( nrows, ncols ); SmallSystem eqndata1( nrows, ncols ); // Get the current subproblem, to check if the fields are active CSubProblem *subproblem = mesh->getCurrentSubProblem(); if ( !subproblem ) throw ErrProgrammingError("Current subproblem not defined", __FILE__, __LINE__); // Loop over all the fields (that the node might have) for(std::vector<Field*>::size_type fi=0; fi<Field::all().size(); fi++) { Field *field = &( *Field::all()[fi] ); if (node.hasField( *field ) && field->is_active( subproblem )) { // Loop over field components for(IteratorP fieldcomp=field->iterator(ALL_INDICES); !fieldcomp.end(); ++fieldcomp) { DegreeOfFreedom *dof = (*field)(node, fieldcomp.integer()); double oldValue = dof->value( mesh ); // Scale eps by original value for robustness double eps = max(min_eps, fabs(oldValue) * deriv_eps); double upValue = oldValue + eps; double dnValue = oldValue - eps; // First compute forceVec0 = f(u-eps) dof->setValue( mesh, dnValue ); force_value(mesh, element, eqn, pt, time, &eqndata0); forceVec0 = eqndata0.forceVector(); // Now compute forceVec1 = f(u+eps) dof->setValue( mesh, upValue ); force_value(mesh, element, eqn, pt, time, &eqndata1); forceVec1 = eqndata1.forceVector(); dof->setValue( mesh, oldValue ); // Compute the numerical derivative: (f1 - f0) / (2*eps) forceVec1 -= forceVec0; forceVec1 /= (upValue - dnValue); // Assign the derivative value to force_deriv_matrix for(IteratorP eqncomp = eqn->iterator(); !eqncomp.end(); ++eqncomp) eqndata->force_deriv_matrix_element( eqncomp, field, fieldcomp, node ) += forceVec1[ eqncomp.integer() ]; zero( eqndata0.forceVector() ); zero( eqndata1.forceVector() ); } // loop over field components } // end if (node.hasfield()) } // loop over all fields } // end of force_deriv_matrix
void FluxProperty::flux_matrix(const FEMesh *mesh, const Element *element, const ElementFuncNodeIterator &node, const Flux *flux, const MasterPosition &pt, double time, SmallSystem *fluxdata) const { #ifdef _OPENMP bool& recurse = recurse_flags[omp_get_thread_num()]; #endif if(recurse) { return; } recurse = true; int nrows = fluxdata->nrows(); int ncols = fluxdata->ncols(); DoubleVec fluxVec0(nrows); DoubleVec fluxVec1(nrows); SmallSystem fluxdata0( nrows, ncols ); SmallSystem fluxdata1( nrows, ncols ); CSubProblem *subproblem = mesh->getCurrentSubProblem(); // Get the current subproblem, to check if the fields are active if ( !subproblem ) throw ErrProgrammingError("Current subproblem not defined", __FILE__, __LINE__); // Loop over all the fields (that the node might have) for (std::vector<Field*>::size_type fi=0; fi<Field::all().size(); fi++) { Field *field = &( *Field::all()[fi] ); if (node.hasField( *field ) && field->is_active( subproblem )) { // Loop over field components for(IteratorP fieldcomp=field->iterator(ALL_INDICES); !fieldcomp.end(); ++fieldcomp) { DegreeOfFreedom *dof = (*field)(node, fieldcomp.integer()); double oldValue = dof->value( mesh ); // Scale eps by original value for robustness double eps = max(min_eps, fabs(oldValue)* deriv_eps); double upValue = oldValue + eps; double dnValue = oldValue - eps; // First compute fluxVec0 = sigma(u-eps) dof->setValue( mesh, dnValue ); static_flux_value(mesh, element, flux, pt, time, &fluxdata0); fluxVec0 = fluxdata0.fluxVector(); // Now compute fluxVec1 = sigma(u+eps) dof->setValue( mesh, upValue ); static_flux_value(mesh, element, flux, pt, time, &fluxdata1); fluxVec1 = fluxdata1.fluxVector(); // Reset to original value! dof->setValue( mesh, oldValue ); // Compute the numerical derivative: (fluxVec1 - fluxVec0) / 2*eps fluxVec1 -= fluxVec0; fluxVec1 /= (upValue - dnValue); // Assign the derivative value to flux_matrix for(IteratorP fluxcomp = flux->iterator(ALL_INDICES); !fluxcomp.end(); ++fluxcomp) fluxdata->stiffness_matrix_element( fluxcomp, field, fieldcomp, node ) += fluxVec1[ fluxcomp.integer() ]; zero( fluxdata0.fluxVector() ); zero( fluxdata1.fluxVector() ); } // loop over field components } // end if (node.hasfield()) } // loop over all fields } // end of 'FluxProperty::flux_matrix'