Example #1
0
void
Kernel::computeJacobian()
{
  DenseMatrix<Number> & ke = _assembly.jacobianBlock(_var.number(), _var.number());
  _local_ke.resize(ke.m(), ke.n());
  _local_ke.zero();

  precalculateJacobian();
  for (_i = 0; _i < _test.size(); _i++)
    for (_j = 0; _j < _phi.size(); _j++)
      for (_qp = 0; _qp < _qrule->n_points(); _qp++)
        _local_ke(_i, _j) += _JxW[_qp] * _coord[_qp] * computeQpJacobian();

  ke += _local_ke;

  if (_has_diag_save_in)
  {
    unsigned int rows = ke.m();
    DenseVector<Number> diag(rows);
    for (unsigned int i = 0; i < rows; i++)
      diag(i) = _local_ke(i, i);

    Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    for (const auto & var : _diag_save_in)
      var->sys().solution().add_vector(diag, var->dofIndices());
  }
}
void
PorousFlowFluxLimitedTVDAdvection::computeJacobian()
{
  prepareMatrixTag(_assembly, _var.number(), _var.number());
  precalculateJacobian();

  // Run through the nodes of this element using "i", getting the Jacobian contributions
  // d(residual_i)/du(node_j) for all nodes j that can have a nonzero Jacobian contribution.  Some
  // of these node_j will live in this element, but some will live in other elements connected with
  // node "i", and some will live in the next layer of nodes (eg, in 1D residual_3 could have
  // contributions from node1, node2, node3, node4 and node5).
  for (unsigned i = 0; i < _current_elem->n_nodes(); ++i)
  {
    // global id of node "i"
    const dof_id_type node_id_i = _current_elem->node_id(i);
    // dof number of _var on node "i"
    std::vector<dof_id_type> idof_indices(
        1, _current_elem->node_ref(i).dof_number(_sys.number(), _var.number(), 0));
    // number of times node "i" is encountered in a sweep over elements
    const unsigned valence = _fluo.getValence(node_id_i);

    // retrieve the derivative information from _fluo
    const std::map<dof_id_type, std::vector<Real>> derivs = _fluo.getdFluxOut_dvars(node_id_i);

    // now build up the dof numbers of all the "j" nodes and the derivative matrix
    // d(residual_i)/d(var_j)
    for (unsigned pvar = 0; pvar < _dictator.numVariables(); ++pvar)
    {
      const unsigned varnum = _dictator.mooseVariableNum(pvar);
      std::vector<dof_id_type> jdof_indices(derivs.size());
      DenseMatrix<Number> deriv_matrix(1, derivs.size());
      unsigned j = 0;
      for (const auto & node_j_deriv : derivs)
      {
        // global id of j:
        const dof_id_type node_id_j = node_j_deriv.first;
        // dof of pvar at node j:
        jdof_indices[j] = _mesh.getMesh().node_ref(node_id_j).dof_number(_sys.number(), varnum, 0);
        // derivative must be divided by valence, otherwise the loop over elements will
        // multiple-count
        deriv_matrix(0, j) = node_j_deriv.second[pvar] / valence;
        j++;
      }
      // Add the result to the system's Jacobian matrix
      _assembly.cacheJacobianBlock(deriv_matrix, idof_indices, jdof_indices, _var.scalingFactor());
    }
  }
}