* and TensorProductMatrixSymmetricSumBase::eigenvectors, respectively.
* Note that the current implementation requires each $M_{d}$ to be symmetric
* and positive definite and every $A_{d}$ to be symmetric and invertible but
- * not necessarily positive definite.
+ * not necessarily positive definite. Columns and rows filled with zero are
+ * ignored.
*/
void
reinit(const std::array<Table<2, Number>, dim> &mass_matrix,
{
Assert(n_rows == n_cols, ExcNotImplemented());
- auto &&transpose_fill_nm = [](Number * out,
- const Number * in,
- const unsigned int n,
- const unsigned int m) {
- for (unsigned int mm = 0; mm < m; ++mm)
- for (unsigned int nn = 0; nn < n; ++nn)
- out[mm + nn * m] = *(in++);
+ std::vector<bool> constrained_dofs(n_rows, false);
+
+ for (unsigned int i = 0; i < n_rows; ++i)
+ {
+ if (mass_matrix[i + i * n_rows] == 0.0)
+ {
+ Assert(derivative_matrix[i + i * n_rows] == 0.0,
+ ExcInternalError());
+
+ for (unsigned int j = 0; j < n_rows; ++j)
+ {
+ Assert(derivative_matrix[i + j * n_rows] == 0,
+ ExcInternalError());
+ Assert(derivative_matrix[j + i * n_rows] == 0,
+ ExcInternalError());
+ }
+
+ constrained_dofs[i] = true;
+ }
+ }
+
+ const auto transpose_fill_nm = [&constrained_dofs](Number * out,
+ const Number * in,
+ const unsigned int n,
+ const unsigned int m) {
+ for (unsigned int mm = 0, c = 0; mm < m; ++mm)
+ for (unsigned int nn = 0; nn < n; ++nn, ++c)
+ out[mm + nn * m] =
+ (mm == nn && constrained_dofs[mm]) ? Number(1.0) : in[c];
};
std::vector<dealii::Vector<Number>> eigenvecs(n_rows);
deriv_copy.compute_generalized_eigenvalues_symmetric(mass_copy,
eigenvecs);
AssertDimension(eigenvecs.size(), n_rows);
- for (unsigned int i = 0; i < n_rows; ++i)
- for (unsigned int j = 0; j < n_cols; ++j, ++eigenvectors)
- *eigenvectors = eigenvecs[j][i];
+ for (unsigned int i = 0, c = 0; i < n_rows; ++i)
+ for (unsigned int j = 0; j < n_cols; ++j, ++c)
+ if (constrained_dofs[i] == false)
+ eigenvectors[c] = eigenvecs[j][i];
for (unsigned int i = 0; i < n_rows; ++i, ++eigenvalues)
*eigenvalues = deriv_copy.eigenvalue(i).real();
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Test TensorProductMatrixSymmetricSum for zero (constrained) rows and colums.
+// We consider a single cell with DBC applied to face 2*(dim-1).
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_dgq.h>
+#include <deal.II/fe/fe_values.h>
+#include <deal.II/fe/mapping_q1.h>
+
+#include <deal.II/grid/grid_generator.h>
+
+#include <deal.II/lac/full_matrix.h>
+#include <deal.II/lac/tensor_product_matrix.h>
+#include <deal.II/lac/vector.h>
+
+#include "../tests.h"
+
+#include "../testmatrix.h"
+
+template <int dim, typename Number>
+std::tuple<FullMatrix<Number>, FullMatrix<Number>>
+compute_reference_matrices(const unsigned int fe_degree)
+{
+ MappingQ1<dim> mapping;
+ QGauss<dim> quadrature(fe_degree + 1);
+ FE_DGQ<dim> fe(fe_degree);
+
+ Triangulation<dim> tria;
+ GridGenerator::hyper_cube(tria);
+
+ DoFHandler<dim> dof_handler(tria);
+ dof_handler.distribute_dofs(fe);
+
+ const unsigned int n_dofs = fe.n_dofs_per_cell();
+
+ FullMatrix<Number> mass_matrix_reference(n_dofs, n_dofs);
+ FullMatrix<Number> derivative_matrix_reference(n_dofs, n_dofs);
+
+ FEValues<dim> fe_values(mapping,
+ fe,
+ quadrature,
+ update_values | update_gradients | update_JxW_values);
+
+ fe_values.reinit(dof_handler.begin());
+
+ for (const unsigned int q_index : fe_values.quadrature_point_indices())
+ for (const unsigned int i : fe_values.dof_indices())
+ for (const unsigned int j : fe_values.dof_indices())
+ {
+ mass_matrix_reference(i, j) +=
+ (fe_values.shape_value(i, q_index) *
+ fe_values.shape_value(j, q_index) * fe_values.JxW(q_index));
+
+ derivative_matrix_reference(i, j) +=
+ (fe_values.shape_grad(i, q_index) *
+ fe_values.shape_grad(j, q_index) * fe_values.JxW(q_index));
+ }
+
+
+
+ return std::tuple<FullMatrix<Number>, FullMatrix<Number>>{
+ mass_matrix_reference, derivative_matrix_reference};
+}
+
+template <typename Number>
+void
+print(const FullMatrix<Number> &matrix, const std::string label)
+{
+ deallog << label << std::endl;
+ matrix.print_formatted(deallog.get_file_stream(), 10, true, 15);
+ deallog << std::endl << std::endl;
+}
+
+
+void
+do_test(const bool zero_out_constraints)
+{
+ using Number = double;
+ const unsigned int dim = 2;
+ const unsigned int n_rows_1d = 4;
+
+ // compute 2D stiffness matrix
+ const auto reference_matrices_2D =
+ compute_reference_matrices<dim, Number>(n_rows_1d - 1);
+ auto K_2D = std::get<1>(reference_matrices_2D);
+
+ // ... and apply DBC on face 2*(dim-1)
+ for (unsigned int j = 0; j < Utilities::pow(n_rows_1d, dim); ++j)
+ for (unsigned int i = 0; i < Utilities::pow(n_rows_1d, dim - 1); ++i)
+ {
+ K_2D[i][j] = 0.0;
+ K_2D[j][i] = 0.0;
+ }
+
+ if (zero_out_constraints == false)
+ for (unsigned int i = 0; i < Utilities::pow(n_rows_1d, dim - 1); ++i)
+ K_2D[i][i] = 1.0;
+
+ // ... print
+ print(K_2D, "K_2D:");
+
+ if (zero_out_constraints)
+ for (unsigned int i = 0; i < Utilities::pow(n_rows_1d, dim - 1); ++i)
+ K_2D[i][i] = 1.0;
+
+ K_2D.gauss_jordan();
+
+ if (zero_out_constraints)
+ for (unsigned int i = 0; i < Utilities::pow(n_rows_1d, dim - 1); ++i)
+ K_2D[i][i] = 0.0;
+
+ // ... print
+ print(K_2D, "K_2D^-1:");
+
+ // compute 1D stiffness and mass matrix
+ const auto reference_matrices_1D =
+ compute_reference_matrices<1, Number>(n_rows_1d - 1);
+
+ // ... setup FDM
+ std::array<Table<2, Number>, dim> mass_matrix;
+ std::array<Table<2, Number>, dim> derivative_matrix;
+
+ for (unsigned int d = 0; d < dim; ++d)
+ {
+ mass_matrix[d] = std::get<0>(reference_matrices_1D);
+ derivative_matrix[d] = std::get<1>(reference_matrices_1D);
+
+ // apply constraints
+ if ((d + 1) == dim)
+ {
+ for (unsigned int i = 0; i < n_rows_1d; ++i)
+ {
+ mass_matrix[d][i][0] = 0.0;
+ mass_matrix[d][0][i] = 0.0;
+ derivative_matrix[d][i][0] = 0.0;
+ derivative_matrix[d][0][i] = 0.0;
+ }
+
+ if (zero_out_constraints == false)
+ {
+ mass_matrix[d][0][0] = 1.0;
+ derivative_matrix[d][0][0] = 1.0;
+ }
+ }
+ }
+
+ // ... print matrix
+ TensorProductMatrixSymmetricSum<dim, Number, -1> fdm;
+ fdm.reinit(mass_matrix, derivative_matrix);
+
+ FullMatrix<Number> matrix(fdm.m(), fdm.m());
+
+ for (unsigned int i = 0; i < fdm.m(); ++i)
+ {
+ Vector<Number> dst(fdm.m());
+ Vector<Number> src(fdm.n());
+
+ src[i] = 1.0;
+
+ fdm.vmult(make_array_view(dst), make_array_view(src));
+
+ for (unsigned int j = 0; j < fdm.m(); ++j)
+ matrix[j][i] = dst[j];
+ }
+
+ print(matrix, "K_FDM:");
+
+ // ... print inverse matrix
+ for (unsigned int i = 0; i < fdm.m(); ++i)
+ {
+ Vector<Number> dst(fdm.m());
+ Vector<Number> src(fdm.n());
+
+ src[i] = 1.0;
+
+ fdm.apply_inverse(make_array_view(dst), make_array_view(src));
+
+ for (unsigned int j = 0; j < fdm.m(); ++j)
+ matrix[j][i] = dst[j];
+ }
+
+ print(matrix, "K_FDM^-1:");
+}
+
+
+int
+main()
+{
+ initlog();
+
+ do_test(true);
+
+ return 0;
+}
--- /dev/null
+
+DEAL::K_2D:
+
+
+
+
+ 2.1428571429e+00 -1.5204601112e+00 3.2364873140e-02 3.9682539683e-02 -3.9682539683e-02 -4.0129811229e-01 1.5328223927e-01 -5.9523809524e-02 -6.4513310372e-02 1.4880952381e-01 -3.7893453497e-02 1.2909876605e-02
+ -1.5204601112e+00 5.9523809524e+00 -9.9206349206e-01 3.2364873140e-02 -4.0129811229e-01 -9.9206349206e-01 -4.9603174603e-01 1.5328223927e-01 1.4880952381e-01 3.2364873140e-02 1.5328223927e-01 -3.7893453497e-02
+ 3.2364873140e-02 -9.9206349206e-01 5.9523809524e+00 -1.5204601112e+00 1.5328223927e-01 -4.9603174603e-01 -9.9206349206e-01 -4.0129811229e-01 -3.7893453497e-02 1.5328223927e-01 3.2364873140e-02 1.4880952381e-01
+ 3.9682539683e-02 3.2364873140e-02 -1.5204601112e+00 2.1428571429e+00 -5.9523809524e-02 1.5328223927e-01 -4.0129811229e-01 -3.9682539683e-02 1.2909876605e-02 -3.7893453497e-02 1.4880952381e-01 -6.4513310372e-02
+ -3.9682539683e-02 -4.0129811229e-01 1.5328223927e-01 -5.9523809524e-02 2.1428571429e+00 -1.5204601112e+00 3.2364873140e-02 3.9682539683e-02 -2.3310573725e-01 -2.5972559412e-01 1.4880952381e-01 -6.2513051208e-02
+ -4.0129811229e-01 -9.9206349206e-01 -4.9603174603e-01 1.5328223927e-01 -1.5204601112e+00 5.9523809524e+00 -9.9206349206e-01 3.2364873140e-02 -2.5972559412e-01 -1.5204601112e+00 -4.0129811229e-01 1.4880952381e-01
+ 1.5328223927e-01 -4.9603174603e-01 -9.9206349206e-01 -4.0129811229e-01 3.2364873140e-02 -9.9206349206e-01 5.9523809524e+00 -1.5204601112e+00 1.4880952381e-01 -4.0129811229e-01 -1.5204601112e+00 -2.5972559412e-01
+ -5.9523809524e-02 1.5328223927e-01 -4.0129811229e-01 -3.9682539683e-02 3.9682539683e-02 3.2364873140e-02 -1.5204601112e+00 2.1428571429e+00 -6.2513051208e-02 1.4880952381e-01 -2.5972559412e-01 -2.3310573725e-01
+ -6.4513310372e-02 1.4880952381e-01 -3.7893453497e-02 1.2909876605e-02 -2.3310573725e-01 -2.5972559412e-01 1.4880952381e-01 -6.2513051208e-02 6.1904761905e-01 -2.3310573725e-01 -6.4513310372e-02 3.9682539683e-02
+ 1.4880952381e-01 3.2364873140e-02 1.5328223927e-01 -3.7893453497e-02 -2.5972559412e-01 -1.5204601112e+00 -4.0129811229e-01 1.4880952381e-01 -2.3310573725e-01 2.1428571429e+00 -3.9682539683e-02 -6.4513310372e-02
+ -3.7893453497e-02 1.5328223927e-01 3.2364873140e-02 1.4880952381e-01 1.4880952381e-01 -4.0129811229e-01 -1.5204601112e+00 -2.5972559412e-01 -6.4513310372e-02 -3.9682539683e-02 2.1428571429e+00 -2.3310573725e-01
+ 1.2909876605e-02 -3.7893453497e-02 1.4880952381e-01 -6.4513310372e-02 -6.2513051208e-02 1.4880952381e-01 -2.5972559412e-01 -2.3310573725e-01 3.9682539683e-02 -6.4513310372e-02 -2.3310573725e-01 6.1904761905e-01
+DEAL::
+DEAL::
+DEAL::K_2D^-1:
+
+
+
+
+ 7.1398913857e-01 2.7936057528e-01 1.2595048784e-01 9.6173972846e-02 3.5466634519e-01 3.3341836231e-01 2.2437530470e-01 2.1636531977e-01 3.7849889433e-01 2.9761957985e-01 2.4739510402e-01 2.1314611331e-01
+ 2.7936057528e-01 3.3864576440e-01 1.4763570837e-01 1.2595048784e-01 3.3341836231e-01 3.1114491295e-01 2.4929635364e-01 2.2437530470e-01 2.9761957985e-01 3.0390259267e-01 2.5043815595e-01 2.4739510402e-01
+ 1.2595048784e-01 1.4763570837e-01 3.3864576440e-01 2.7936057528e-01 2.2437530470e-01 2.4929635364e-01 3.1114491295e-01 3.3341836231e-01 2.4739510402e-01 2.5043815595e-01 3.0390259267e-01 2.9761957985e-01
+ 9.6173972846e-02 1.2595048784e-01 2.7936057528e-01 7.1398913857e-01 2.1636531977e-01 2.2437530470e-01 3.3341836231e-01 3.5466634519e-01 2.1314611331e-01 2.4739510402e-01 2.9761957985e-01 3.7849889433e-01
+ 3.5466634519e-01 3.3341836231e-01 2.2437530470e-01 2.1636531977e-01 1.2712646737e+00 7.9275803884e-01 5.0423937608e-01 4.4702982470e-01 1.0548034198e+00 8.7872567784e-01 5.4153032266e-01 5.2719815068e-01
+ 3.3341836231e-01 3.1114491295e-01 2.4929635364e-01 2.2437530470e-01 7.9275803884e-01 8.2875711684e-01 5.5249971478e-01 5.0423937608e-01 8.7872567784e-01 8.3420787522e-01 6.1839723928e-01 5.4153032266e-01
+ 2.2437530470e-01 2.4929635364e-01 3.1114491295e-01 3.3341836231e-01 5.0423937608e-01 5.5249971478e-01 8.2875711684e-01 7.9275803884e-01 5.4153032266e-01 6.1839723928e-01 8.3420787522e-01 8.7872567784e-01
+ 2.1636531977e-01 2.2437530470e-01 3.3341836231e-01 3.5466634519e-01 4.4702982470e-01 5.0423937608e-01 7.9275803884e-01 1.2712646737e+00 5.2719815068e-01 5.4153032266e-01 8.7872567784e-01 1.0548034198e+00
+ 3.7849889433e-01 2.9761957985e-01 2.4739510402e-01 2.1314611331e-01 1.0548034198e+00 8.7872567784e-01 5.4153032266e-01 5.2719815068e-01 2.7334715515e+00 1.0955555964e+00 6.6133919416e-01 4.8205449545e-01
+ 2.9761957985e-01 3.0390259267e-01 2.5043815595e-01 2.4739510402e-01 8.7872567784e-01 8.3420787522e-01 6.1839723928e-01 5.4153032266e-01 1.0955555964e+00 1.3563953245e+00 6.9222571734e-01 6.6133919416e-01
+ 2.4739510402e-01 2.5043815595e-01 3.0390259267e-01 2.9761957985e-01 5.4153032266e-01 6.1839723928e-01 8.3420787522e-01 8.7872567784e-01 6.6133919416e-01 6.9222571734e-01 1.3563953245e+00 1.0955555964e+00
+ 2.1314611331e-01 2.4739510402e-01 2.9761957985e-01 3.7849889433e-01 5.2719815068e-01 5.4153032266e-01 8.7872567784e-01 1.0548034198e+00 4.8205449545e-01 6.6133919416e-01 1.0955555964e+00 2.7334715515e+00
+DEAL::
+DEAL::
+DEAL::K_FDM:
+
+
+
+
+ 2.1428571429e+00 -1.5204601112e+00 3.2364873140e-02 3.9682539683e-02 -3.9682539683e-02 -4.0129811229e-01 1.5328223927e-01 -5.9523809524e-02 -6.4513310372e-02 1.4880952381e-01 -3.7893453497e-02 1.2909876605e-02
+ -1.5204601112e+00 5.9523809524e+00 -9.9206349206e-01 3.2364873140e-02 -4.0129811229e-01 -9.9206349206e-01 -4.9603174603e-01 1.5328223927e-01 1.4880952381e-01 3.2364873140e-02 1.5328223927e-01 -3.7893453497e-02
+ 3.2364873140e-02 -9.9206349206e-01 5.9523809524e+00 -1.5204601112e+00 1.5328223927e-01 -4.9603174603e-01 -9.9206349206e-01 -4.0129811229e-01 -3.7893453497e-02 1.5328223927e-01 3.2364873140e-02 1.4880952381e-01
+ 3.9682539683e-02 3.2364873140e-02 -1.5204601112e+00 2.1428571429e+00 -5.9523809524e-02 1.5328223927e-01 -4.0129811229e-01 -3.9682539683e-02 1.2909876605e-02 -3.7893453497e-02 1.4880952381e-01 -6.4513310372e-02
+ -3.9682539683e-02 -4.0129811229e-01 1.5328223927e-01 -5.9523809524e-02 2.1428571429e+00 -1.5204601112e+00 3.2364873140e-02 3.9682539683e-02 -2.3310573725e-01 -2.5972559412e-01 1.4880952381e-01 -6.2513051208e-02
+ -4.0129811229e-01 -9.9206349206e-01 -4.9603174603e-01 1.5328223927e-01 -1.5204601112e+00 5.9523809524e+00 -9.9206349206e-01 3.2364873140e-02 -2.5972559412e-01 -1.5204601112e+00 -4.0129811229e-01 1.4880952381e-01
+ 1.5328223927e-01 -4.9603174603e-01 -9.9206349206e-01 -4.0129811229e-01 3.2364873140e-02 -9.9206349206e-01 5.9523809524e+00 -1.5204601112e+00 1.4880952381e-01 -4.0129811229e-01 -1.5204601112e+00 -2.5972559412e-01
+ -5.9523809524e-02 1.5328223927e-01 -4.0129811229e-01 -3.9682539683e-02 3.9682539683e-02 3.2364873140e-02 -1.5204601112e+00 2.1428571429e+00 -6.2513051208e-02 1.4880952381e-01 -2.5972559412e-01 -2.3310573725e-01
+ -6.4513310372e-02 1.4880952381e-01 -3.7893453497e-02 1.2909876605e-02 -2.3310573725e-01 -2.5972559412e-01 1.4880952381e-01 -6.2513051208e-02 6.1904761905e-01 -2.3310573725e-01 -6.4513310372e-02 3.9682539683e-02
+ 1.4880952381e-01 3.2364873140e-02 1.5328223927e-01 -3.7893453497e-02 -2.5972559412e-01 -1.5204601112e+00 -4.0129811229e-01 1.4880952381e-01 -2.3310573725e-01 2.1428571429e+00 -3.9682539683e-02 -6.4513310372e-02
+ -3.7893453497e-02 1.5328223927e-01 3.2364873140e-02 1.4880952381e-01 1.4880952381e-01 -4.0129811229e-01 -1.5204601112e+00 -2.5972559412e-01 -6.4513310372e-02 -3.9682539683e-02 2.1428571429e+00 -2.3310573725e-01
+ 1.2909876605e-02 -3.7893453497e-02 1.4880952381e-01 -6.4513310372e-02 -6.2513051208e-02 1.4880952381e-01 -2.5972559412e-01 -2.3310573725e-01 3.9682539683e-02 -6.4513310372e-02 -2.3310573725e-01 6.1904761905e-01
+DEAL::
+DEAL::
+DEAL::K_FDM^-1:
+
+
+
+
+ 7.1398913857e-01 2.7936057528e-01 1.2595048784e-01 9.6173972846e-02 3.5466634519e-01 3.3341836231e-01 2.2437530470e-01 2.1636531977e-01 3.7849889433e-01 2.9761957985e-01 2.4739510402e-01 2.1314611331e-01
+ 2.7936057528e-01 3.3864576440e-01 1.4763570837e-01 1.2595048784e-01 3.3341836231e-01 3.1114491295e-01 2.4929635364e-01 2.2437530470e-01 2.9761957985e-01 3.0390259267e-01 2.5043815595e-01 2.4739510402e-01
+ 1.2595048784e-01 1.4763570837e-01 3.3864576440e-01 2.7936057528e-01 2.2437530470e-01 2.4929635364e-01 3.1114491295e-01 3.3341836231e-01 2.4739510402e-01 2.5043815595e-01 3.0390259267e-01 2.9761957985e-01
+ 9.6173972846e-02 1.2595048784e-01 2.7936057528e-01 7.1398913857e-01 2.1636531977e-01 2.2437530470e-01 3.3341836231e-01 3.5466634519e-01 2.1314611331e-01 2.4739510402e-01 2.9761957985e-01 3.7849889433e-01
+ 3.5466634519e-01 3.3341836231e-01 2.2437530470e-01 2.1636531977e-01 1.2712646737e+00 7.9275803884e-01 5.0423937608e-01 4.4702982470e-01 1.0548034198e+00 8.7872567784e-01 5.4153032266e-01 5.2719815068e-01
+ 3.3341836231e-01 3.1114491295e-01 2.4929635364e-01 2.2437530470e-01 7.9275803884e-01 8.2875711684e-01 5.5249971478e-01 5.0423937608e-01 8.7872567784e-01 8.3420787522e-01 6.1839723928e-01 5.4153032266e-01
+ 2.2437530470e-01 2.4929635364e-01 3.1114491295e-01 3.3341836231e-01 5.0423937608e-01 5.5249971478e-01 8.2875711684e-01 7.9275803884e-01 5.4153032266e-01 6.1839723928e-01 8.3420787522e-01 8.7872567784e-01
+ 2.1636531977e-01 2.2437530470e-01 3.3341836231e-01 3.5466634519e-01 4.4702982470e-01 5.0423937608e-01 7.9275803884e-01 1.2712646737e+00 5.2719815068e-01 5.4153032266e-01 8.7872567784e-01 1.0548034198e+00
+ 3.7849889433e-01 2.9761957985e-01 2.4739510402e-01 2.1314611331e-01 1.0548034198e+00 8.7872567784e-01 5.4153032266e-01 5.2719815068e-01 2.7334715515e+00 1.0955555964e+00 6.6133919416e-01 4.8205449545e-01
+ 2.9761957985e-01 3.0390259267e-01 2.5043815595e-01 2.4739510402e-01 8.7872567784e-01 8.3420787522e-01 6.1839723928e-01 5.4153032266e-01 1.0955555964e+00 1.3563953245e+00 6.9222571734e-01 6.6133919416e-01
+ 2.4739510402e-01 2.5043815595e-01 3.0390259267e-01 2.9761957985e-01 5.4153032266e-01 6.1839723928e-01 8.3420787522e-01 8.7872567784e-01 6.6133919416e-01 6.9222571734e-01 1.3563953245e+00 1.0955555964e+00
+ 2.1314611331e-01 2.4739510402e-01 2.9761957985e-01 3.7849889433e-01 5.2719815068e-01 5.4153032266e-01 8.7872567784e-01 1.0548034198e+00 4.8205449545e-01 6.6133919416e-01 1.0955555964e+00 2.7334715515e+00
+DEAL::
+DEAL::