Real INSChorinPredictor::computeQpResidual() { // Vector object for test function RealVectorValue test; test(_component) = _test[_i][_qp]; // Tensor object for test function gradient RealTensorValue grad_test; for (unsigned k=0; k<3; ++k) grad_test(_component, k) = _grad_test[_i][_qp](k); // Decide what velocity vector, gradient to use: RealVectorValue U; RealTensorValue grad_U; switch (_predictor_enum) { case OLD: { U = RealVectorValue(_u_vel_old[_qp], _v_vel_old[_qp], _w_vel_old[_qp]); grad_U = RealTensorValue(_grad_u_vel_old[_qp], _grad_v_vel_old[_qp], _grad_w_vel_old[_qp]); break; } case NEW: { U = RealVectorValue(_u_vel[_qp], _v_vel[_qp], _w_vel[_qp]); grad_U = RealTensorValue(_grad_u_vel[_qp], _grad_v_vel[_qp], _grad_w_vel[_qp]); break; } case STAR: { // Note: Donea and Huerta's book says you are supposed to use "star" velocity to make Chorin implicit, not U^{n+1}. U = RealVectorValue(_u_vel_star[_qp], _v_vel_star[_qp], _w_vel_star[_qp]); grad_U = RealTensorValue(_grad_u_vel_star[_qp], _grad_v_vel_star[_qp], _grad_w_vel_star[_qp]); break; } default: mooseError("Unrecognized Chorin predictor type requested."); } // // Compute the different parts // // Note: _u is the component'th entry of "u_star" in Chorin's method. RealVectorValue U_old(_u_vel_old[_qp], _v_vel_old[_qp], _w_vel_old[_qp]); Real symmetric_part = (_u[_qp] - U_old(_component)) * _test[_i][_qp]; // Convective part. Remember to multiply by _dt! Real convective_part = _dt * (grad_U * U) * test; // Viscous part - we are using the Laplacian form here for simplicity. // Remember to multiply by _dt! Real viscous_part = _dt * (_mu/_rho) * grad_U.contract(grad_test); return symmetric_part + convective_part + viscous_part; }
Real INSSplitMomentum::computeQpResidual() { // Vector object for a RealVectorValue a(_a1[_qp], _a2[_qp], _a3[_qp]); // Vector object for test function RealVectorValue test; test(_component) = _test[_i][_qp]; // Tensor object for "grad U" = d(u_i)/d(x_j) RealTensorValue grad_U(_grad_u_vel[_qp], _grad_v_vel[_qp], _grad_w_vel[_qp]); // Vector object for U RealVectorValue U(_u_vel[_qp], _v_vel[_qp], _w_vel[_qp]); // Viscous stress tensor object RealTensorValue tau( // Row 1 2. * _grad_u_vel[_qp](0), _grad_u_vel[_qp](1) + _grad_v_vel[_qp](0), _grad_u_vel[_qp](2) + _grad_w_vel[_qp](0), // Row 2 _grad_v_vel[_qp](0) + _grad_u_vel[_qp](1), 2. * _grad_v_vel[_qp](1), _grad_v_vel[_qp](2) + _grad_w_vel[_qp](1), // Row 3 _grad_w_vel[_qp](0) + _grad_u_vel[_qp](2), _grad_w_vel[_qp](1) + _grad_v_vel[_qp](2), 2. * _grad_w_vel[_qp](2)); // Tensor object for test function gradient RealTensorValue grad_test; for (unsigned k = 0; k < 3; ++k) grad_test(_component, k) = _grad_test[_i][_qp](k); // // Compute the different pieces... // // "Symmetric" part, a.test Real symmetric_part = a(_component) * _test[_i][_qp]; // The convection part, (u.grad) * u_component * test_scalar. Which can also be // written as (grad_U * U) * test_vec Real convective_part = (grad_U * U) * test; // The viscous part, tau : grad(v) Real viscous_part = (_mu[_qp] / _rho[_qp]) * tau.contract(grad_test); return symmetric_part + convective_part + viscous_part; }
Real INSSplitMomentum::computeQpOffDiagJacobian(unsigned jvar) { if ((jvar == _u_vel_var_number) || (jvar == _v_vel_var_number) || (jvar == _w_vel_var_number)) { // Derivative of viscous stress tensor RealTensorValue dtau; // Initialize to invalid value, then determine correct value. unsigned vel_index = 99; // Set index and build dtau for that index if (jvar == _u_vel_var_number) { vel_index = 0; dtau(0, 0) = 2. * _grad_phi[_j][_qp](0); dtau(0, 1) = _grad_phi[_j][_qp](1); dtau(0, 2) = _grad_phi[_j][_qp](2); dtau(1, 0) = _grad_phi[_j][_qp](1); dtau(2, 0) = _grad_phi[_j][_qp](2); } else if (jvar == _v_vel_var_number) { vel_index = 1; /* */ dtau(0, 1) = _grad_phi[_j][_qp](0); dtau(1, 0) = _grad_phi[_j][_qp](0); dtau(1, 1) = 2. * _grad_phi[_j][_qp](1); dtau(1, 2) = _grad_phi[_j][_qp](2); /* */ dtau(2, 1) = _grad_phi[_j][_qp](2); } else if (jvar == _w_vel_var_number) { vel_index = 2; /* */ dtau(0, 2) = _grad_phi[_j][_qp](0); /* */ dtau(1, 2) = _grad_phi[_j][_qp](1); dtau(2, 0) = _grad_phi[_j][_qp](0); dtau(2, 1) = _grad_phi[_j][_qp](1); dtau(2, 2) = 2. * _grad_phi[_j][_qp](2); } // Vector object for test function RealVectorValue test; test(_component) = _test[_i][_qp]; // Vector object for U RealVectorValue U(_u_vel[_qp], _v_vel[_qp], _w_vel[_qp]); // Tensor object for test function gradient RealTensorValue grad_test; for (unsigned k = 0; k < 3; ++k) grad_test(_component, k) = _grad_test[_i][_qp](k); // Compute the convective part RealVectorValue convective_jac = _phi[_j][_qp] * RealVectorValue(_grad_u_vel[_qp](vel_index), _grad_v_vel[_qp](vel_index), _grad_w_vel[_qp](vel_index)); // Extra contribution in vel_index component convective_jac(vel_index) += U * _grad_phi[_j][_qp]; Real convective_part = convective_jac * test; // Compute the viscous part Real viscous_part = (_mu[_qp] / _rho[_qp]) * dtau.contract(grad_test); // Return the result return convective_part + viscous_part; } else return 0; }
Real INSChorinPredictor::computeQpOffDiagJacobian(unsigned jvar) { switch (_predictor_enum) { case OLD: { return 0.; } case NEW: { if ((jvar == _u_vel_var_number) || (jvar == _v_vel_var_number) || (jvar == _w_vel_var_number)) { // Derivative of grad_U wrt the velocity component RealTensorValue dgrad_U; // Initialize to invalid value, then determine correct value. unsigned vel_index = 99; // Map jvar into the indices (0,1,2) if (jvar == _u_vel_var_number) vel_index = 0; else if (jvar == _v_vel_var_number) vel_index = 1; else if (jvar == _w_vel_var_number) vel_index = 2; // Fill in the vel_index'th row of dgrad_U with _grad_phi[_j][_qp] for (unsigned k=0; k<3; ++k) dgrad_U(vel_index,k) = _grad_phi[_j][_qp](k); // Vector object for test function RealVectorValue test; test(_component) = _test[_i][_qp]; // Vector object for U RealVectorValue U(_u_vel[_qp], _v_vel[_qp], _w_vel[_qp]); // Tensor object for test function gradient RealTensorValue grad_test; for (unsigned k=0; k<3; ++k) grad_test(_component, k) = _grad_test[_i][_qp](k); // Compute the convective part RealVectorValue convective_jac = _phi[_j][_qp] * RealVectorValue(_grad_u_vel[_qp](vel_index), _grad_v_vel[_qp](vel_index), _grad_w_vel[_qp](vel_index)); // Extra contribution in vel_index component convective_jac(vel_index) += U*_grad_phi[_j][_qp]; // Be sure to scale by _dt! Real convective_part = _dt * (convective_jac * test); // Compute the viscous part, be sure to scale by _dt. Note: the contracted // value should be zero unless vel_index and _component match. Real viscous_part = _dt * (_mu/_rho) * dgrad_U.contract(grad_test); // Return the result return convective_part + viscous_part; } else return 0; } case STAR: { if (jvar == _u_vel_star_var_number) { return _dt * _phi[_j][_qp] * _grad_u[_qp](0) * _test[_i][_qp]; } else if (jvar == _v_vel_star_var_number) { return _dt * _phi[_j][_qp] * _grad_u[_qp](1) * _test[_i][_qp]; } else if (jvar == _w_vel_star_var_number) { return _dt * _phi[_j][_qp] * _grad_u[_qp](2) * _test[_i][_qp]; } else return 0; } default: mooseError("Unrecognized Chorin predictor type requested."); } }