コード例 #1
0
  void HeatTransfer::element_time_derivative( bool compute_jacobian,
					      libMesh::FEMContext& context,
					      CachedValues& /*cache*/ )
  {
#ifdef GRINS_USE_GRVY_TIMERS
    this->_timer->BeginTimer("HeatTransfer::element_time_derivative");
#endif

    // The number of local degrees of freedom in each variable.
    const unsigned int n_T_dofs = context.dof_indices_var[_T_var].size();
    const unsigned int n_u_dofs = context.dof_indices_var[_u_var].size();

    //TODO: check n_T_dofs is same as n_u_dofs, n_v_dofs, n_w_dofs

    // We get some references to cell-specific data that
    // will be used to assemble the linear system.

    // Element Jacobian * quadrature weights for interior integration.
    const std::vector<libMesh::Real> &JxW =
      context.element_fe_var[_T_var]->get_JxW();

    // The temperature shape functions at interior quadrature points.
    const std::vector<std::vector<libMesh::Real> >& T_phi =
      context.element_fe_var[_T_var]->get_phi();

    // The velocity shape functions at interior quadrature points.
    const std::vector<std::vector<libMesh::Real> >& vel_phi =
      context.element_fe_var[_u_var]->get_phi();

    // The temperature shape function gradients (in global coords.)
    // at interior quadrature points.
    const std::vector<std::vector<libMesh::RealGradient> >& T_gradphi =
      context.element_fe_var[_T_var]->get_dphi();

    const std::vector<libMesh::Point>& u_qpoint = 
      context.element_fe_var[this->_u_var]->get_xyz();

    // We do this in the incompressible Navier-Stokes class and need to do it here too
    // since _w_var won't have been defined in the global map.
    if (_dim != 3)
      _w_var = _u_var; // for convenience

    libMesh::DenseSubMatrix<libMesh::Number> &KTT = *context.elem_subjacobians[_T_var][_T_var]; // R_{T},{T}

    libMesh::DenseSubMatrix<libMesh::Number> &KTu = *context.elem_subjacobians[_T_var][_u_var]; // R_{T},{u}
    libMesh::DenseSubMatrix<libMesh::Number> &KTv = *context.elem_subjacobians[_T_var][_v_var]; // R_{T},{v}
    libMesh::DenseSubMatrix<libMesh::Number> &KTw = *context.elem_subjacobians[_T_var][_w_var]; // R_{T},{w}

    libMesh::DenseSubVector<libMesh::Number> &FT = *context.elem_subresiduals[_T_var]; // R_{T}

    // Now we will build the element Jacobian and residual.
    // Constructing the residual requires the solution and its
    // gradient from the previous timestep.  This must be
    // calculated at each quadrature point by summing the
    // solution degree-of-freedom values by the appropriate
    // weight functions.
    unsigned int n_qpoints = context.element_qrule->n_points();

    for (unsigned int qp=0; qp != n_qpoints; qp++)
      {
	// Compute the solution & its gradient at the old Newton iterate.
	libMesh::Number u, v, w;
	u = context.interior_value(_u_var, qp);
	v = context.interior_value(_v_var, qp);
	if (_dim == 3)
	  w = context.interior_value(_w_var, qp);

	libMesh::Gradient grad_T;
	grad_T = context.interior_gradient(_T_var, qp);

	libMesh::NumberVectorValue U (u,v);
	if (_dim == 3)
	  U(2) = w;

        const libMesh::Number r = u_qpoint[qp](0);

        libMesh::Real jac = JxW[qp];

        if( _is_axisymmetric )
          {
            jac *= r;
          }

	// First, an i-loop over the  degrees of freedom.
	for (unsigned int i=0; i != n_T_dofs; i++)
	  {
	    FT(i) += jac *
	      (-_rho*_Cp*T_phi[i][qp]*(U*grad_T)    // convection term
	       -_k*(T_gradphi[i][qp]*grad_T) );  // diffusion term

	    if (compute_jacobian)
	      {
		for (unsigned int j=0; j != n_T_dofs; j++)
		  {
		    // TODO: precompute some terms like:
		    //   _rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*T_grad_phi[j][qp])

		    KTT(i,j) += jac *
		      (-_rho*_Cp*T_phi[i][qp]*(U*T_gradphi[j][qp])  // convection term
		       -_k*(T_gradphi[i][qp]*T_gradphi[j][qp])); // diffusion term
		  } // end of the inner dof (j) loop

		// Matrix contributions for the Tu, Tv and Tw couplings (n_T_dofs same as n_u_dofs, n_v_dofs and n_w_dofs)
		for (unsigned int j=0; j != n_u_dofs; j++)
		  {
		    KTu(i,j) += jac*(-_rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*grad_T(0)));
		    KTv(i,j) += jac*(-_rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*grad_T(1)));
		    if (_dim == 3)
		      KTw(i,j) += jac*(-_rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*grad_T(2)));
		  } // end of the inner dof (j) loop

	      } // end - if (compute_jacobian && context.elem_solution_derivative)

	  } // end of the outer dof (i) loop
      } // end of the quadrature point (qp) loop

#ifdef GRINS_USE_GRVY_TIMERS
    this->_timer->EndTimer("HeatTransfer::element_time_derivative");
#endif

    return;
  }
コード例 #2
0
  void AxisymmetricHeatTransfer<Conductivity>::element_time_derivative( bool compute_jacobian,
									AssemblyContext& context,
									CachedValues& /*cache*/ )
  {
#ifdef GRINS_USE_GRVY_TIMERS
    this->_timer->BeginTimer("AxisymmetricHeatTransfer::element_time_derivative");
#endif

    // The number of local degrees of freedom in each variable.
    const unsigned int n_T_dofs = context.get_dof_indices(_T_var).size();
    const unsigned int n_u_dofs = context.get_dof_indices(_u_r_var).size();

    //TODO: check n_T_dofs is same as n_u_dofs, n_v_dofs, n_w_dofs

    // We get some references to cell-specific data that
    // will be used to assemble the linear system.

    // Element Jacobian * quadrature weights for interior integration.
    const std::vector<libMesh::Real> &JxW =
      context.get_element_fe(_T_var)->get_JxW();

    // The temperature shape functions at interior quadrature points.
    const std::vector<std::vector<libMesh::Real> >& T_phi =
      context.get_element_fe(_T_var)->get_phi();

    // The velocity shape functions at interior quadrature points.
    const std::vector<std::vector<libMesh::Real> >& vel_phi =
      context.get_element_fe(_u_r_var)->get_phi();

    // The temperature shape function gradients (in global coords.)
    // at interior quadrature points.
    const std::vector<std::vector<libMesh::RealGradient> >& T_gradphi =
      context.get_element_fe(_T_var)->get_dphi();

    // Physical location of the quadrature points
    const std::vector<libMesh::Point>& u_qpoint =
      context.get_element_fe(_u_r_var)->get_xyz();

    // The subvectors and submatrices we need to fill:
    libMesh::DenseSubVector<libMesh::Number> &FT = context.get_elem_residual(_T_var); // R_{T}

    libMesh::DenseSubMatrix<libMesh::Number> &KTT = context.get_elem_jacobian(_T_var, _T_var); // R_{T},{T}

    libMesh::DenseSubMatrix<libMesh::Number> &KTr = context.get_elem_jacobian(_T_var, _u_r_var); // R_{T},{r}
    libMesh::DenseSubMatrix<libMesh::Number> &KTz = context.get_elem_jacobian(_T_var, _u_z_var); // R_{T},{z}


    // Now we will build the element Jacobian and residual.
    // Constructing the residual requires the solution and its
    // gradient from the previous timestep.  This must be
    // calculated at each quadrature point by summing the
    // solution degree-of-freedom values by the appropriate
    // weight functions.
    unsigned int n_qpoints = context.get_element_qrule().n_points();

    for (unsigned int qp=0; qp != n_qpoints; qp++)
      {
	const libMesh::Number r = u_qpoint[qp](0);
      
	// Compute the solution & its gradient at the old Newton iterate.
	libMesh::Number u_r, u_z;
	u_r = context.interior_value(_u_r_var, qp);
	u_z = context.interior_value(_u_z_var, qp);

	libMesh::Gradient grad_T;
	grad_T = context.interior_gradient(_T_var, qp);

	libMesh::NumberVectorValue U (u_r,u_z);

	libMesh::Number k = this->_k( context, qp );

        // FIXME - once we have T-dependent k, we'll need its
        // derivatives in Jacobians
	// libMesh::Number dk_dT = this->_k.deriv( T );

	// First, an i-loop over the  degrees of freedom.
	for (unsigned int i=0; i != n_T_dofs; i++)
	  {
	    FT(i) += JxW[qp]*r*
	      (-_rho*_Cp*T_phi[i][qp]*(U*grad_T)    // convection term
	       -k*(T_gradphi[i][qp]*grad_T) );  // diffusion term

	    if (compute_jacobian)
	      {
		libmesh_assert (context.get_elem_solution_derivative() == 1.0);

		for (unsigned int j=0; j != n_T_dofs; j++)
		  {
		    // TODO: precompute some terms like:
		    //   _rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*T_grad_phi[j][qp])

		    KTT(i,j) += JxW[qp] * context.get_elem_solution_derivative() *r*
		      (-_rho*_Cp*T_phi[i][qp]*(U*T_gradphi[j][qp])  // convection term
		       -k*(T_gradphi[i][qp]*T_gradphi[j][qp])); // diffusion term
		  } // end of the inner dof (j) loop

#if 0
		if( dk_dT != 0.0 )
		{
		  for (unsigned int j=0; j != n_T_dofs; j++)
		    {
		      // TODO: precompute some terms like:
		      KTT(i,j) -= JxW[qp] * context.get_elem_solution_derivative() *r*( dk_dT*T_phi[j][qp]*T_gradphi[i][qp]*grad_T );
		    }
		}
#endif

		// Matrix contributions for the Tu, Tv and Tw couplings (n_T_dofs same as n_u_dofs, n_v_dofs and n_w_dofs)
		for (unsigned int j=0; j != n_u_dofs; j++)
		  {
		    KTr(i,j) += JxW[qp] * context.get_elem_solution_derivative() *r*(-_rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*grad_T(0)));
		    KTz(i,j) += JxW[qp] * context.get_elem_solution_derivative() *r*(-_rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*grad_T(1)));
		  } // end of the inner dof (j) loop

	      } // end - if (compute_jacobian && context.get_elem_solution_derivative())

	  } // end of the outer dof (i) loop
      } // end of the quadrature point (qp) loop

#ifdef GRINS_USE_GRVY_TIMERS
    this->_timer->EndTimer("AxisymmetricHeatTransfer::element_time_derivative");
#endif

    return;
  }
コード例 #3
0
  void ReactingLowMachNavierStokesStabilizationBase<Mixture,Evaluator>::compute_res_steady( AssemblyContext& context,
                                                                                            unsigned int qp,
                                                                                            libMesh::Real& RP_s,
                                                                                            libMesh::RealGradient& RM_s,
                                                                                            libMesh::Real& RE_s,
                                                                                            std::vector<libMesh::Real>& Rs_s )
  {
    Rs_s.resize(this->n_species(),0.0);

    // Grab r-coordinate for axisymmetric terms
    // We're assuming all variables are using the same quadrature rule
    libMesh::Real r = (context.get_element_fe(this->_flow_vars.u())->get_xyz())[qp](0);

    libMesh::RealGradient grad_p = context.interior_gradient(this->_press_var.p(), qp);

    libMesh::RealGradient grad_u = context.interior_gradient(this->_flow_vars.u(), qp);
    libMesh::RealGradient grad_v = context.interior_gradient(this->_flow_vars.v(), qp);

    libMesh::RealGradient U( context.interior_value(this->_flow_vars.u(), qp),
                             context.interior_value(this->_flow_vars.v(), qp) );
    libMesh::Real divU = grad_u(0) + grad_v(1);

    if( this->_is_axisymmetric )
      divU += U(0)/r;

    if(this->mesh_dim(context) == 3)
      {
        U(2) = context.interior_value(this->_flow_vars.w(), qp);
        divU += (context.interior_gradient(this->_flow_vars.w(), qp))(2);
      }

    // We don't add axisymmetric terms here since we don't directly use hess_{u,v}
    // axisymmetric terms are built into divGradU, etc. functions below
    libMesh::RealTensor hess_u = context.interior_hessian(this->_flow_vars.u(), qp);
    libMesh::RealTensor hess_v = context.interior_hessian(this->_flow_vars.v(), qp);

    libMesh::Real T = context.interior_value(this->_temp_vars.T(), qp);

    libMesh::Gradient grad_T = context.interior_gradient(this->_temp_vars.T(), qp);
    libMesh::Tensor hess_T = context.interior_hessian(this->_temp_vars.T(), qp);

    libMesh::Real hess_T_term = hess_T(0,0) + hess_T(1,1);
#if LIBMESH_DIM > 2
    hess_T_term += hess_T(2,2);
#endif
    // Add axisymmetric terms, if needed
    if( this->_is_axisymmetric )
      hess_T_term += grad_T(0)/r;

    std::vector<libMesh::Real> ws(this->n_species());
    std::vector<libMesh::RealGradient> grad_ws(this->n_species());
    std::vector<libMesh::RealTensor> hess_ws(this->n_species());
    for(unsigned int s=0; s < this->_n_species; s++ )
      {
        ws[s] = context.interior_value(this->_species_vars.species(s), qp);
        grad_ws[s] = context.interior_gradient(this->_species_vars.species(s), qp);
        hess_ws[s] = context.interior_hessian(this->_species_vars.species(s), qp);
      }

    Evaluator gas_evaluator( this->_gas_mixture );
    const libMesh::Real R_mix = gas_evaluator.R_mix(ws);
    const libMesh::Real p0 = this->get_p0_steady(context,qp);
    libMesh::Real rho = this->rho(T, p0, R_mix );
    libMesh::Real cp = gas_evaluator.cp(T,p0,ws);
    libMesh::Real M = gas_evaluator.M_mix( ws );

    std::vector<libMesh::Real> D( this->n_species() );
    libMesh::Real mu, k;

    gas_evaluator.mu_and_k_and_D( T, rho, cp, ws, mu, k, D );


    // grad_rho = drho_dT*gradT + \sum_s drho_dws*grad_ws
    const libMesh::Real drho_dT = -p0/(R_mix*T*T);
    libMesh::RealGradient grad_rho = drho_dT*grad_T;
    for(unsigned int s=0; s < this->_n_species; s++ )
      {
        libMesh::Real Ms = gas_evaluator.M(s);
        libMesh::Real R_uni = Constants::R_universal/1000.0; /* J/kmol-K --> J/mol-K */

        // drho_dws = -p0/(T*R_mix*R_mix)*dR_dws
        // dR_dws = R_uni*d_dws(1/M)
        // d_dws(1/M) = d_dws(\sum_s w_s/Ms) =  1/Ms
        const libMesh::Real drho_dws = -p0/(R_mix*R_mix*T)*R_uni/Ms;
        grad_rho += drho_dws*grad_ws[s];
      }

    libMesh::RealGradient rhoUdotGradU;
    libMesh::RealGradient divGradU;
    libMesh::RealGradient divGradUT;
    libMesh::RealGradient divdivU;

    if( this->mesh_dim(context) < 3 )
      {
        rhoUdotGradU = rho*_stab_helper.UdotGradU( U, grad_u, grad_v );

        // Call axisymmetric versions if we are doing an axisymmetric run
        if( this->_is_axisymmetric )
          {
            divGradU  = _stab_helper.div_GradU_axi( r, U, grad_u, grad_v, hess_u, hess_v );
            divGradUT = _stab_helper.div_GradU_T_axi( r, U, grad_u, hess_u, hess_v );
            divdivU   = _stab_helper.div_divU_I_axi( r, U, grad_u, hess_u, hess_v );
          }
        else
          {
            divGradU  = _stab_helper.div_GradU( hess_u, hess_v );
            divGradUT = _stab_helper.div_GradU_T( hess_u, hess_v );
            divdivU   = _stab_helper.div_divU_I( hess_u, hess_v );
          }
      }
    else
      {
        libMesh::RealGradient grad_w = context.interior_gradient(this->_flow_vars.w(), qp);
        libMesh::RealTensor hess_w = context.interior_hessian(this->_flow_vars.w(), qp);

        rhoUdotGradU = rho*_stab_helper.UdotGradU( U, grad_u, grad_v, grad_w );

        divGradU  = _stab_helper.div_GradU( hess_u, hess_v, hess_w );
        divGradUT = _stab_helper.div_GradU_T( hess_u, hess_v, hess_w );
        divdivU   = _stab_helper.div_divU_I( hess_u, hess_v, hess_w );
      }



    // Terms if we have vicosity derivatives w.r.t. temp.
    /*
    if( this->_mu.deriv(T) != 0.0 )
      {
        libMesh::Gradient gradTgradu( grad_T*grad_u, grad_T*grad_v );

        libMesh::Gradient gradTgraduT( grad_T(0)*grad_u(0) + grad_T(1)*grad_u(1),
                                       grad_T(0)*grad_v(0) + grad_T(1)*grad_v(1) );

        libMesh::Real divU = grad_u(0) + grad_v(1);

        libMesh::Gradient gradTdivU( grad_T(0)*divU, grad_T(1)*divU );

        if(this->mesh_dim(context) == 3)
          {
            libMesh::Gradient grad_w = context.interior_gradient(this->_flow_vars.w(), qp);

            gradTgradu(2) = grad_T*grad_w;

            gradTgraduT(0) += grad_T(2)*grad_u(2);
            gradTgraduT(1) += grad_T(2)*grad_v(2);
            gradTgraduT(2) = grad_T(0)*grad_w(0) + grad_T(1)*grad_w(1) + grad_T(2)*grad_w(2);

            divU += grad_w(2);
            gradTdivU(0) += grad_T(0)*grad_w(2);
            gradTdivU(1) += grad_T(1)*grad_w(2);
            gradTdivU(2) += grad_T(2)*divU;
          }

        divT += this->_mu.deriv(T)*( gradTgradu + gradTgraduT - 2.0/3.0*gradTdivU );
      }
    */

    // Axisymmetric terms already built in
    libMesh::RealGradient div_stress = mu*(divGradU + divGradUT - 2.0/3.0*divdivU);

    std::vector<libMesh::Real> omega_dot(this->n_species());
    gas_evaluator.omega_dot(T,rho,ws,omega_dot);

    libMesh::Real chem_term = 0.0;
    libMesh::Gradient mass_term(0.0,0.0,0.0);
    for(unsigned int s=0; s < this->_n_species; s++ )
      {
        // Start accumulating chemistry term for energy residual
        libMesh::Real h_s=gas_evaluator.h_s(T,s);
        chem_term += h_s*omega_dot[s];

        /* Accumulate mass term for continuity residual
           mass_term = grad_M/M */
        mass_term += grad_ws[s]/this->_gas_mixture.M(s);

        libMesh::Real hess_s_term = hess_ws[s](0,0) + hess_ws[s](1,1);
#if LIBMESH_DIM > 2
        hess_s_term += hess_ws[s](2,2);
#endif
        // Add axisymmetric terms, if needed
        if( this->_is_axisymmetric )
          hess_s_term += grad_ws[s](0)/r;

        // Species residual
        /*! \todo Still missing derivative of species diffusion coefficient.
                  rho*grad_D[s]*grad_ws[s] */
        Rs_s[s] = rho*U*grad_ws[s] - rho*D[s]*hess_s_term - grad_rho*D[s]*grad_ws[s]
                  - omega_dot[s];
      }
    mass_term *= M;

    // Continuity residual
    RP_s = divU - (U*grad_T)/T - U*mass_term;

    // Momentum residual
    RM_s = rhoUdotGradU + grad_p - div_stress - rho*(this->_g);

    // Energy residual
    // - this->_k.deriv(T)*(grad_T*grad_T)
    RE_s = rho*U*cp*grad_T  - k*(hess_T_term) + chem_term;

    return;
  }