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 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'