LCOV - code coverage report
Current view: top level - include/variables - MooseVariableDataFV.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 37 62 59.7 %
Date: 2025-07-17 01:28:37 Functions: 18 36 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #pragma once
      11             : 
      12             : #include "MooseArray.h"
      13             : #include "MooseTypes.h"
      14             : #include "MeshChangedInterface.h"
      15             : #include "MooseVariableDataBase.h"
      16             : #include "TheWarehouse.h"
      17             : 
      18             : #include "libmesh/tensor_tools.h"
      19             : #include "libmesh/vector_value.h"
      20             : #include "libmesh/tensor_value.h"
      21             : #include "libmesh/type_n_tensor.h"
      22             : #include "libmesh/fe_type.h"
      23             : #include "libmesh/dof_map.h"
      24             : #include "libmesh/enum_fe_family.h"
      25             : #include "SubProblem.h"
      26             : 
      27             : #include <functional>
      28             : #include <vector>
      29             : 
      30             : class FaceInfo;
      31             : class SystemBase;
      32             : class TimeIntegrator;
      33             : class Assembly;
      34             : 
      35             : template <typename>
      36             : class MooseVariableFV;
      37             : 
      38             : namespace libMesh
      39             : {
      40             : class QBase;
      41             : }
      42             : 
      43             : namespace Moose
      44             : {
      45             : template <typename T>
      46             : void
      47  1547756239 : initDofIndices(T & data, const Elem & elem)
      48             : {
      49  1547756239 :   if (data._prev_elem != &elem)
      50             :   {
      51   282976158 :     data._dof_map.dof_indices(&elem, data._dof_indices, data._var_num);
      52   282976158 :     data._prev_elem = &elem;
      53             :   }
      54  1547756239 : }
      55             : }
      56             : 
      57             : namespace
      58             : {
      59             : template <typename T, typename T2>
      60             : void
      61   195907008 : assignForAllQps(const T & value, T2 & array, const unsigned int nqp)
      62             : {
      63   393985036 :   for (const auto qp : make_range(nqp))
      64   198078028 :     array[qp] = value;
      65   195907008 : }
      66             : }
      67             : 
      68             : template <typename OutputType>
      69             : class MooseVariableDataFV : public MooseVariableDataBase<OutputType>, public MeshChangedInterface
      70             : {
      71             : public:
      72             :   // type for gradient, second and divergence of template class OutputType
      73             :   typedef typename libMesh::TensorTools::IncrementRank<OutputType>::type OutputGradient;
      74             :   typedef typename libMesh::TensorTools::IncrementRank<OutputGradient>::type OutputSecond;
      75             :   typedef typename libMesh::TensorTools::DecrementRank<OutputType>::type OutputDivergence;
      76             : 
      77             :   // shortcut for types storing values on quadrature points
      78             :   typedef MooseArray<OutputType> FieldVariableValue;
      79             :   typedef MooseArray<OutputGradient> FieldVariableGradient;
      80             :   typedef MooseArray<OutputSecond> FieldVariableSecond;
      81             :   typedef MooseArray<OutputType> FieldVariableCurl;
      82             :   typedef MooseArray<OutputDivergence> FieldVariableDivergence;
      83             : 
      84             :   // shape function type for the template class OutputType
      85             :   typedef typename Moose::ShapeType<OutputType>::type OutputShape;
      86             : 
      87             :   // type for gradient, second and divergence of shape functions of template class OutputType
      88             :   typedef typename libMesh::TensorTools::IncrementRank<OutputShape>::type OutputShapeGradient;
      89             :   typedef typename libMesh::TensorTools::IncrementRank<OutputShapeGradient>::type OutputShapeSecond;
      90             :   typedef typename libMesh::TensorTools::DecrementRank<OutputShape>::type OutputShapeDivergence;
      91             : 
      92             :   // DoF value type for the template class OutputType
      93             :   typedef typename Moose::DOFType<OutputType>::type OutputData;
      94             :   typedef MooseArray<OutputData> DoFValue;
      95             : 
      96             :   MooseVariableDataFV(const MooseVariableFV<OutputType> & var,
      97             :                       SystemBase & sys,
      98             :                       THREAD_ID tid,
      99             :                       Moose::ElementType element_type,
     100             :                       const Elem * const & elem);
     101             : 
     102           0 :   bool isNodal() const override { return false; }
     103           0 :   bool hasDoFsOnNodes() const override { return false; }
     104         344 :   libMesh::FEContinuity getContinuity() const override { return libMesh::DISCONTINUOUS; }
     105             : 
     106             :   /**
     107             :    * Returns whether this data structure needs automatic differentiation calculations
     108             :    */
     109           0 :   bool needsAD() const { return _need_ad; }
     110             : 
     111             :   /**
     112             :    * Set the geometry type before calculating variables values
     113             :    * @param gm_type The type type of geometry; either Volume or Face
     114             :    */
     115             :   void setGeometry(Moose::GeometryType gm_type);
     116             : 
     117             :   //////////////// Heavy lifting computational routines //////////////////////////////
     118             : 
     119             :   /**
     120             :    * compute the variable values
     121             :    */
     122             :   void computeValuesFace(const FaceInfo & fi);
     123             : 
     124             :   /**
     125             :    * compute the variable values
     126             :    */
     127             :   void computeValues();
     128             : 
     129             :   /**
     130             :    * compute AD things
     131             :    */
     132             :   void computeAD(const unsigned int num_dofs, const unsigned int nqp);
     133             : 
     134             :   ///////////////////////////// Shape functions /////////////////////////////////////
     135             : 
     136             :   /**
     137             :    * The current element
     138             :    */
     139         992 :   const Elem * const & currentElem() const { return _elem; }
     140             : 
     141             :   /**
     142             :    * prepare the initial condition
     143             :    */
     144             :   void prepareIC();
     145             : 
     146             :   //////////////////////////////////// Solution getters /////////////////////////////////////
     147             : 
     148             :   /**
     149             :    * Local solution value
     150             :    */
     151             :   const FieldVariableValue & sln(Moose::SolutionState state) const;
     152             : 
     153             :   /**
     154             :    * Local time derivative of solution gradient getter
     155             :    */
     156             :   const FieldVariableGradient & gradSlnDot() const;
     157             : 
     158             :   /**
     159             :    * Local second time derivative of solution gradient getter
     160             :    */
     161             :   const FieldVariableGradient & gradSlnDotDot() const;
     162             : 
     163             :   /**
     164             :    * Local solution second spatial derivative getter
     165             :    * @param state The state of the simulation: current, old, older, previous nl
     166             :    */
     167             :   const FieldVariableSecond & secondSln(Moose::SolutionState state) const;
     168             : 
     169             :   /**
     170             :    * Local solution curl getter
     171             :    * @param state The state of the simulation: current, old, older
     172             :    */
     173             :   const FieldVariableCurl & curlSln(Moose::SolutionState state) const;
     174             : 
     175       18370 :   const ADTemplateVariableValue<OutputType> & adSln() const
     176             :   {
     177       18370 :     _need_ad = _need_ad_u = true;
     178       18370 :     return _ad_u;
     179             :   }
     180             : 
     181        1310 :   const ADTemplateVariableGradient<OutputType> & adGradSln() const
     182             :   {
     183        1310 :     _need_ad = _need_ad_grad_u = true;
     184        1310 :     return _ad_grad_u;
     185             :   }
     186             : 
     187           0 :   const ADTemplateVariableGradient<OutputType> & adGradSlnDot() const
     188             :   {
     189           0 :     mooseError("Gradient of time derivative not yet implemented for FV");
     190             :   }
     191             : 
     192           0 :   const ADTemplateVariableSecond<OutputType> & adSecondSln() const
     193             :   {
     194           0 :     _need_ad = _need_ad_second_u = true;
     195           0 :     return _ad_second_u;
     196             :   }
     197             : 
     198             :   const ADTemplateVariableValue<OutputType> & adUDot() const;
     199             : 
     200             :   const ADTemplateVariableValue<OutputType> & adUDotDot() const;
     201             : 
     202             :   const FieldVariableValue & uDot() const;
     203             : 
     204             :   const FieldVariableValue & uDotDot() const;
     205             : 
     206             :   const FieldVariableValue & uDotOld() const;
     207             : 
     208             :   const FieldVariableValue & uDotDotOld() const;
     209             : 
     210           0 :   const VariableValue & duDotDu() const
     211             :   {
     212           0 :     _need_du_dot_du = true;
     213           0 :     return _du_dot_du;
     214             :   }
     215             : 
     216           0 :   const VariableValue & duDotDotDu() const
     217             :   {
     218           0 :     _need_du_dotdot_du = true;
     219           0 :     return _du_dotdot_du;
     220             :   }
     221             : 
     222             :   /**
     223             :    * Set local DOF values and evaluate the values on quadrature points
     224             :    */
     225             :   void setDofValues(const DenseVector<OutputData> & values);
     226             : 
     227             :   ///@{
     228             :   /**
     229             :    * dof value setters
     230             :    */
     231             :   void setDofValue(const OutputData & value, unsigned int index);
     232             :   ///@}
     233             : 
     234             :   OutputData
     235             :   getElementalValue(const Elem * elem, Moose::SolutionState state, unsigned int idx = 0) const;
     236             : 
     237             :   ///////////////////////////// dof indices ///////////////////////////////////////////////
     238             : 
     239             :   void getDofIndices(const Elem * elem, std::vector<dof_id_type> & dof_indices) const;
     240             :   const std::vector<dof_id_type> & dofIndices() const;
     241             :   unsigned int numberOfDofs() const;
     242    21029473 :   void clearDofIndices()
     243             :   {
     244    21029473 :     _dof_indices.clear();
     245    21029473 :     _prev_elem = nullptr;
     246    21029473 :   }
     247             : 
     248             :   /////////////////////////// DoF value getters /////////////////////////////////////
     249             : 
     250             :   const DoFValue & dofValuesDot() const;
     251             :   const DoFValue & dofValuesDotOld() const;
     252             :   const DoFValue & dofValuesDotDot() const;
     253             :   const DoFValue & dofValuesDotDotOld() const;
     254             :   const MooseArray<libMesh::Number> & dofValuesDuDotDu() const;
     255             :   const MooseArray<libMesh::Number> & dofValuesDuDotDotDu() const;
     256             : 
     257             :   /**
     258             :    * Return the AD dof values
     259             :    */
     260             :   const MooseArray<ADReal> & adDofValues() const;
     261             : 
     262             :   /**
     263             :    * Return the AD dof time derivatives
     264             :    */
     265             :   const MooseArray<ADReal> & adDofValuesDot() const;
     266             : 
     267             :   /////////////////////////////// Increment stuff ///////////////////////////////////////
     268             : 
     269             :   /**
     270             :    * Increment getter
     271             :    * @return The increment
     272             :    */
     273           0 :   const FieldVariableValue & increment() const { return _increment; }
     274             : 
     275             :   /**
     276             :    * Compute and store incremental change in solution at QPs based on increment_vec
     277             :    */
     278             :   void computeIncrementAtQps(const libMesh::NumericVector<libMesh::Number> & increment_vec);
     279             : 
     280             :   /// checks if a Dirichlet BC exists on this face
     281           0 :   bool hasDirichletBC() const { return _has_dirichlet_bc; }
     282             : 
     283             :   void meshChanged() override;
     284             : 
     285             : protected:
     286           0 :   virtual const MooseVariableFV<OutputType> & var() const override { return _var; }
     287             : 
     288             : private:
     289             :   void initializeSolnVars();
     290             : 
     291             :   /**
     292             :    * Helper methods for assigning nodal values from their corresponding solution values (dof
     293             :    * values as they're referred to here in this class). These methods are only truly meaningful
     294             :    * for nodal basis families
     295             :    */
     296             :   void fetchADDoFValues();
     297             : 
     298             :   /**
     299             :    * Helper method that tells us whether it's safe to compute _ad_u_dot
     300             :    */
     301             :   bool safeToComputeADUDot() const;
     302             : 
     303             :   /// A const reference to the owning MooseVariableFV object
     304             :   const MooseVariableFV<OutputType> & _var;
     305             : 
     306             :   const libMesh::FEType & _fe_type;
     307             : 
     308             :   const unsigned int _var_num;
     309             : 
     310             :   const Assembly & _assembly;
     311             : 
     312             :   /// The element type this object is storing data for. This is either Element, Neighbor, or Lower
     313             :   Moose::ElementType _element_type;
     314             : 
     315             :   /// Continuity type of the variable
     316             :   libMesh::FEContinuity _continuity;
     317             : 
     318             :   /// Increment in the variable used in dampers
     319             :   FieldVariableValue _increment;
     320             : 
     321             :   /// A zero AD variable
     322             :   const ADReal _ad_zero;
     323             : 
     324             :   /// SolutionState second_u flags
     325             :   mutable bool _need_second;
     326             :   mutable bool _need_second_old;
     327             :   mutable bool _need_second_older;
     328             :   mutable bool _need_second_previous_nl;
     329             : 
     330             :   /// curl flags
     331             :   mutable bool _need_curl;
     332             :   mutable bool _need_curl_old;
     333             :   mutable bool _need_curl_older;
     334             : 
     335             :   /// AD flags
     336             :   mutable bool _need_ad;
     337             :   mutable bool _need_ad_u;
     338             :   mutable bool _need_ad_u_dot;
     339             :   mutable bool _need_ad_u_dotdot;
     340             :   mutable bool _need_ad_grad_u;
     341             :   mutable bool _need_ad_grad_u_dot;
     342             :   mutable bool _need_ad_second_u;
     343             : 
     344             :   /// grad_u dots
     345             :   FieldVariableGradient _grad_u_dot;
     346             :   FieldVariableGradient _grad_u_dotdot;
     347             : 
     348             :   /// second_u
     349             :   FieldVariableSecond _second_u;
     350             :   FieldVariableSecond _second_u_old;
     351             :   FieldVariableSecond _second_u_older;
     352             :   FieldVariableSecond _second_u_previous_nl;
     353             : 
     354             :   /// curl_u
     355             :   FieldVariableCurl _curl_u;
     356             :   FieldVariableCurl _curl_u_old;
     357             :   FieldVariableCurl _curl_u_older;
     358             : 
     359             :   /// AD u
     360             :   ADTemplateVariableValue<OutputShape> _ad_u;
     361             :   ADTemplateVariableGradient<OutputShape> _ad_grad_u;
     362             :   ADTemplateVariableSecond<OutputShape> _ad_second_u;
     363             :   MooseArray<ADReal> _ad_dof_values;
     364             :   MooseArray<ADReal> _ad_dofs_dot;
     365             :   MooseArray<ADReal> _ad_dofs_dotdot;
     366             :   ADTemplateVariableValue<OutputShape> _ad_u_dot;
     367             :   ADTemplateVariableValue<OutputShape> _ad_u_dotdot;
     368             :   ADTemplateVariableGradient<OutputShape> _ad_grad_u_dot;
     369             : 
     370             :   // time derivatives
     371             : 
     372             :   /// u_dot (time derivative)
     373             :   FieldVariableValue _u_dot;
     374             : 
     375             :   /// u_dotdot (second time derivative)
     376             :   FieldVariableValue _u_dotdot;
     377             : 
     378             :   /// u_dot_old (time derivative)
     379             :   FieldVariableValue _u_dot_old;
     380             : 
     381             :   /// u_dotdot_old (second time derivative)
     382             :   FieldVariableValue _u_dotdot_old;
     383             : 
     384             :   /// derivative of u_dot wrt u
     385             :   VariableValue _du_dot_du;
     386             : 
     387             :   /// derivative of u_dotdot wrt u
     388             :   VariableValue _du_dotdot_du;
     389             : 
     390             :   /// Pointer to time integrator
     391             :   const TimeIntegrator * const _time_integrator;
     392             : 
     393             :   /// The current elem. This has to be a reference because the current elem will be constantly
     394             :   /// changing. If we initialized this to point to one elem, then in the next calculation we would
     395             :   /// be pointing to the wrong place!
     396             :   const Elem * const & _elem;
     397             :   /// used to keep track of when dof indices are out of date
     398             :   mutable const Elem * _prev_elem = nullptr;
     399             : 
     400             :   const std::vector<dof_id_type> & initDofIndices();
     401             : 
     402             :   /// if this variable has a dirichlet bc defined on a particular face
     403             :   bool _has_dirichlet_bc;
     404             : 
     405             :   /// Whether this variable is being calculated on a displaced system
     406             :   const bool _displaced;
     407             : 
     408             :   /// The quadrature rule
     409             :   const libMesh::QBase * _qrule;
     410             : 
     411             :   /// A dummy ADReal variable
     412       12748 :   ADReal _ad_real_dummy = 0;
     413             : 
     414             :   /// Cached warehouse query for FVElementalKernels
     415             :   TheWarehouse::QueryCache<> _fv_elemental_kernel_query_cache;
     416             :   /// Cached warehouse query for FVFluxKernels
     417             :   TheWarehouse::QueryCache<> _fv_flux_kernel_query_cache;
     418             : 
     419             :   using MooseVariableDataBase<OutputType>::_sys;
     420             :   using MooseVariableDataBase<OutputType>::_subproblem;
     421             :   using MooseVariableDataBase<OutputType>::_need_vector_tag_dof_u;
     422             :   using MooseVariableDataBase<OutputType>::_need_matrix_tag_dof_u;
     423             :   using MooseVariableDataBase<OutputType>::_vector_tags_dof_u;
     424             :   using MooseVariableDataBase<OutputType>::_matrix_tags_dof_u;
     425             :   using MooseVariableDataBase<OutputType>::_vector_tag_u;
     426             :   using MooseVariableDataBase<OutputType>::_need_vector_tag_u;
     427             :   using MooseVariableDataBase<OutputType>::_vector_tag_grad;
     428             :   using MooseVariableDataBase<OutputType>::_need_vector_tag_grad;
     429             :   using MooseVariableDataBase<OutputType>::_matrix_tag_u;
     430             :   using MooseVariableDataBase<OutputType>::_need_matrix_tag_u;
     431             :   using MooseVariableDataBase<OutputType>::_dof_indices;
     432             :   using MooseVariableDataBase<OutputType>::_has_dof_values;
     433             :   using MooseVariableDataBase<OutputType>::fetchDoFValues;
     434             :   using MooseVariableDataBase<OutputType>::assignNodalValue;
     435             :   using MooseVariableDataBase<OutputType>::zeroSizeDofValues;
     436             :   using MooseVariableDataBase<OutputType>::_solution_tag;
     437             :   using MooseVariableDataBase<OutputType>::_old_solution_tag;
     438             :   using MooseVariableDataBase<OutputType>::_older_solution_tag;
     439             :   using MooseVariableDataBase<OutputType>::_previous_nl_solution_tag;
     440             :   using MooseVariableDataBase<OutputType>::_dof_map;
     441             :   using MooseVariableDataBase<OutputType>::_need_u_dot;
     442             :   using MooseVariableDataBase<OutputType>::_need_u_dotdot;
     443             :   using MooseVariableDataBase<OutputType>::_need_u_dot_old;
     444             :   using MooseVariableDataBase<OutputType>::_need_u_dotdot_old;
     445             :   using MooseVariableDataBase<OutputType>::_need_du_dot_du;
     446             :   using MooseVariableDataBase<OutputType>::_need_du_dotdot_du;
     447             :   using MooseVariableDataBase<OutputType>::_need_grad_dot;
     448             :   using MooseVariableDataBase<OutputType>::_need_grad_dotdot;
     449             :   using MooseVariableDataBase<OutputType>::_need_dof_values_dot;
     450             :   using MooseVariableDataBase<OutputType>::_need_dof_values_dotdot;
     451             :   using MooseVariableDataBase<OutputType>::_need_dof_values_dot_old;
     452             :   using MooseVariableDataBase<OutputType>::_need_dof_values_dotdot_old;
     453             :   using MooseVariableDataBase<OutputType>::_need_dof_du_dot_du;
     454             :   using MooseVariableDataBase<OutputType>::_need_dof_du_dotdot_du;
     455             :   using MooseVariableDataBase<OutputType>::_dof_values_dot;
     456             :   using MooseVariableDataBase<OutputType>::_dof_values_dotdot;
     457             :   using MooseVariableDataBase<OutputType>::_dof_values_dot_old;
     458             :   using MooseVariableDataBase<OutputType>::_dof_values_dotdot_old;
     459             :   using MooseVariableDataBase<OutputType>::_dof_du_dot_du;
     460             :   using MooseVariableDataBase<OutputType>::_dof_du_dotdot_du;
     461             :   using MooseVariableDataBase<OutputType>::_tid;
     462             :   using MooseVariableDataBase<OutputType>::_nodal_value_dot;
     463             :   using MooseVariableDataBase<OutputType>::_nodal_value_dotdot;
     464             :   using MooseVariableDataBase<OutputType>::_nodal_value_dot_old;
     465             :   using MooseVariableDataBase<OutputType>::_nodal_value_dotdot_old;
     466             :   using MooseVariableDataBase<OutputType>::_required_vector_tags;
     467             : 
     468             :   friend void Moose::initDofIndices<>(MooseVariableDataFV<OutputType> &, const Elem &);
     469             : };
     470             : 
     471             : /////////////////////// General template definitions //////////////////////////////////////
     472             : 
     473             : template <typename OutputType>
     474             : const MooseArray<ADReal> &
     475           0 : MooseVariableDataFV<OutputType>::adDofValues() const
     476             : {
     477           0 :   _need_ad = true;
     478           0 :   return _ad_dof_values;
     479             : }
     480             : 
     481             : template <typename OutputType>
     482             : const MooseArray<ADReal> &
     483           0 : MooseVariableDataFV<OutputType>::adDofValuesDot() const
     484             : {
     485           0 :   _need_ad = _need_ad_u_dot = true;
     486           0 :   return _ad_dofs_dot;
     487             : }
     488             : 
     489             : template <typename OutputType>
     490             : inline bool
     491    28875299 : MooseVariableDataFV<OutputType>::safeToComputeADUDot() const
     492             : {
     493             :   // If we don't have a time integrator then we have no way to calculate _ad_u_dot because we rely
     494             :   // on calls to TimeIntegrator::computeADTimeDerivatives. Another potential situation where
     495             :   // _ad_u_dot computation is potentially troublesome is if we are an auxiliary variable which uses
     496             :   // the auxiliary system copy of the time integrator. Some derived time integrator classes do setup
     497             :   // in their solve() method, and that solve() method only happens for the nonlinear system copy of
     498             :   // the time integrator.
     499    28875299 :   return _time_integrator && (_var.kind() == Moose::VAR_SOLVER);
     500             : }
     501             : 
     502             : template <typename OutputType>
     503             : inline const ADTemplateVariableValue<OutputType> &
     504         380 : MooseVariableDataFV<OutputType>::adUDot() const
     505             : {
     506         380 :   _need_ad = _need_ad_u_dot = true;
     507             : 
     508         380 :   if (!safeToComputeADUDot())
     509             :     // We will just copy the value of _u_dot into _ad_u_dot
     510           0 :     _need_u_dot = true;
     511             : 
     512         380 :   return _ad_u_dot;
     513             : }
     514             : 
     515             : template <typename OutputType>
     516             : const ADTemplateVariableValue<OutputType> &
     517          13 : MooseVariableDataFV<OutputType>::adUDotDot() const
     518             : {
     519             :   // Generally speaking, we need u dot information when computing u dot dot
     520          13 :   adUDot();
     521             : 
     522          13 :   _need_ad = _need_ad_u_dotdot = true;
     523             : 
     524          13 :   if (!safeToComputeADUDot())
     525             :     // We will just copy the value of _u_dotdot into _ad_u_dotdot
     526           0 :     _need_u_dotdot = true;
     527             : 
     528          13 :   return _ad_u_dotdot;
     529             : }
     530             : 
     531             : template <typename OutputType>
     532             : const std::vector<dof_id_type> &
     533  1224270588 : MooseVariableDataFV<OutputType>::dofIndices() const
     534             : {
     535  1224270588 :   return const_cast<MooseVariableDataFV<OutputType> *>(this)->initDofIndices();
     536             : }
     537             : 
     538             : template <typename OutputType>
     539             : unsigned int
     540      176144 : MooseVariableDataFV<OutputType>::numberOfDofs() const
     541             : {
     542      176144 :   return dofIndices().size();
     543             : }

Generated by: LCOV version 1.14