This method projects an arbitrary boundary solution to the current mesh. The input function f gives the arbitrary solution, while the new_vector (which should already be correctly sized) gives the solution (to be computed) on the current mesh.
1536{
1537
1539
1547
1549
1550
1552
1553
1554 const BoundaryInfo & boundary_info =
1556
1557
1558
1559
1560
1562 DenseVector<Number> Fe;
1563
1564 DenseVector<Number> Ue;
1565
1566
1567
1569 {
1571
1572 const Variable & variable = dof_map.variable(var);
1573
1574 const FEType & fe_type = variable.type();
1575
1576 if (fe_type.family ==
SCALAR)
1577 continue;
1578
1579 const unsigned int var_component =
1581
1582
1584
1585
1586 std::unique_ptr<QBase> qedgerule (fe_type.default_quadrature_rule(1));
1587 std::unique_ptr<QBase> qsiderule (fe_type.default_quadrature_rule(
dim-1));
1588
1589
1590
1591 const std::vector<std::vector<Real>> & phi = fe->get_phi();
1592
1593
1594
1595 const std::vector<std::vector<RealGradient>> * dphi = nullptr;
1596
1598
1600 {
1601
1603
1604 const std::vector<std::vector<RealGradient>> &
1605 ref_dphi = fe->get_dphi();
1606 dphi = &ref_dphi;
1607 }
1608
1609
1610 const std::vector<Real> & JxW =
1611 fe->get_JxW();
1612
1613
1614 const std::vector<Point> & xyz_values =
1615 fe->get_xyz();
1616
1617
1618 std::vector<dof_id_type> dof_indices;
1619
1620 std::vector<unsigned int> side_dofs;
1621
1622
1623 std::vector<boundary_id_type> bc_ids;
1624
1625
1626 for (const auto & elem : range)
1627 {
1628
1629
1630 if (!variable.active_on_subdomain(elem->subdomain_id()))
1631 continue;
1632
1633 const unsigned short n_nodes = elem->n_nodes();
1634 const unsigned short n_edges = elem->n_edges();
1635 const unsigned short n_sides = elem->n_sides();
1636
1637
1638
1639 std::vector<bool> is_boundary_node(
n_nodes,
false),
1640 is_boundary_edge(n_edges, false),
1641 is_boundary_side(n_sides, false);
1642
1643
1644 std::vector<bool> is_boundary_nodeset(
n_nodes,
false);
1645
1646 for (unsigned char s=0; s != n_sides; ++s)
1647 {
1648
1649 boundary_info.boundary_ids (elem, s, bc_ids);
1650 bool do_this_side = false;
1651 for (const auto & bc_id : bc_ids)
1653 {
1654 do_this_side = true;
1655 break;
1656 }
1657 if (!do_this_side)
1658 continue;
1659
1660 is_boundary_side[s] = true;
1661
1662
1663 for (
unsigned int n=0; n !=
n_nodes; ++n)
1664 if (elem->is_node_on_side(n,s))
1665 is_boundary_node[n] = true;
1666 for (unsigned int e=0; e != n_edges; ++e)
1667 if (elem->is_edge_on_side(e,s))
1668 is_boundary_edge[e] = true;
1669 }
1670
1671
1672
1673 for (
unsigned int n=0; n !=
n_nodes; ++n)
1674 {
1675 boundary_info.boundary_ids (elem->node_ptr(n), bc_ids);
1676
1677 for (const auto & bc_id : bc_ids)
1679 {
1680 is_boundary_node[n] = true;
1681 is_boundary_nodeset[n] = true;
1682 }
1683 }
1684
1685
1686
1687 for (unsigned short e=0; e != n_edges; ++e)
1688 {
1689 boundary_info.edge_boundary_ids (elem, e, bc_ids);
1690
1691 for (const auto & bc_id : bc_ids)
1693 is_boundary_edge[e] = true;
1694 }
1695
1696
1697
1698 dof_map.dof_indices (elem, dof_indices, var);
1699
1700
1701 const unsigned int n_dofs =
1702 cast_int<unsigned int>(dof_indices.size());
1703
1704
1705 std::vector<char> dof_is_fixed(n_dofs, false);
1706 std::vector<int> free_dof(n_dofs, 0);
1707
1708
1709 Ue.resize (n_dofs); Ue.zero();
1710
1711
1712
1713
1714
1715
1716
1717
1718 unsigned int current_dof = 0;
1719 for (
unsigned short n = 0; n !=
n_nodes; ++n)
1720 {
1721
1722
1723
1724
1725 const unsigned int nc =
1727
1728 if ((!elem->is_vertex(n) || !is_boundary_node[n]) &&
1729 !is_boundary_nodeset[n])
1730 {
1731 current_dof += nc;
1732 continue;
1733 }
1735 {
1736 libmesh_assert_equal_to (nc, 0);
1737 }
1738
1739
1741 {
1742 libmesh_assert_equal_to (nc, 1);
1743 Ue(current_dof) =
f->component(var_component,
1744 elem->point(n),
1746 dof_is_fixed[current_dof] = true;
1747 current_dof++;
1748 }
1749
1750 else if (fe_type.family ==
HERMITE)
1751 {
1752 Ue(current_dof) =
f->component(var_component,
1753 elem->point(n),
1755 dof_is_fixed[current_dof] = true;
1756 current_dof++;
1757 Gradient grad =
g->component(var_component,
1758 elem->point(n),
1760
1761 Ue(current_dof) = grad(0);
1762 dof_is_fixed[current_dof] = true;
1763 current_dof++;
1764#if LIBMESH_DIM > 1
1766 {
1767
1768 Point nxminus = elem->point(n),
1769 nxplus = elem->point(n);
1772 Gradient gxminus =
g->component(var_component,
1773 nxminus,
1775 Gradient gxplus =
g->component(var_component,
1776 nxplus,
1778
1779 Ue(current_dof) = grad(1);
1780 dof_is_fixed[current_dof] = true;
1781 current_dof++;
1782
1783 Ue(current_dof) = (gxplus(1) - gxminus(1))
1785 dof_is_fixed[current_dof] = true;
1786 current_dof++;
1787
1788#if LIBMESH_DIM > 2
1790 {
1791
1792 Ue(current_dof) = grad(2);
1793 dof_is_fixed[current_dof] = true;
1794 current_dof++;
1795
1796 Ue(current_dof) = (gxplus(2) - gxminus(2))
1798 dof_is_fixed[current_dof] = true;
1799 current_dof++;
1800
1801 Point nyminus = elem->point(n),
1802 nyplus = elem->point(n);
1805 Gradient gyminus =
g->component(var_component,
1806 nyminus,
1808 Gradient gyplus =
g->component(var_component,
1809 nyplus,
1811
1812 Ue(current_dof) = (gyplus(2) - gyminus(2))
1814 dof_is_fixed[current_dof] = true;
1815 current_dof++;
1816
1817 Point nxmym = elem->point(n),
1818 nxmyp = elem->point(n),
1819 nxpym = elem->point(n),
1820 nxpyp = elem->point(n);
1829 Gradient gxmym =
g->component(var_component,
1830 nxmym,
1832 Gradient gxmyp =
g->component(var_component,
1833 nxmyp,
1835 Gradient gxpym =
g->component(var_component,
1836 nxpym,
1838 Gradient gxpyp =
g->component(var_component,
1839 nxpyp,
1841 Number gxzplus = (gxpyp(2) - gxmyp(2))
1843 Number gxzminus = (gxpym(2) - gxmym(2))
1845
1846 Ue(current_dof) = (gxzplus - gxzminus)
1848 dof_is_fixed[current_dof] = true;
1849 current_dof++;
1850 }
1851#endif
1852 }
1853#endif
1854 }
1855
1856
1857
1858 else if (cont ==
C_ONE)
1859 {
1860 libmesh_assert_equal_to (nc, 1 +
dim);
1861 Ue(current_dof) =
f->component(var_component,
1862 elem->point(n),
1864 dof_is_fixed[current_dof] = true;
1865 current_dof++;
1866 Gradient grad =
g->component(var_component,
1867 elem->point(n),
1869 for (
unsigned int i=0; i!=
dim; ++i)
1870 {
1871 Ue(current_dof) = grad(i);
1872 dof_is_fixed[current_dof] = true;
1873 current_dof++;
1874 }
1875 }
1876 else
1877 libmesh_error_msg("Unknown continuity " << cont);
1878 }
1879
1880
1882 for (unsigned short e = 0; e != n_edges; ++e)
1883 {
1884 if (!is_boundary_edge[e])
1885 continue;
1886
1888 side_dofs);
1889
1890 const unsigned int n_side_dofs =
1891 cast_int<unsigned int>(side_dofs.size());
1892
1893
1894
1895 unsigned int free_dofs = 0;
1897 if (!dof_is_fixed[side_dofs[i]])
1898 free_dof[free_dofs++] = i;
1899
1900
1901 if (!free_dofs)
1902 continue;
1903
1904 Ke.resize (free_dofs, free_dofs); Ke.zero();
1905 Fe.resize (free_dofs); Fe.zero();
1906
1907 DenseVector<Number> Uedge(free_dofs);
1908
1909
1910 fe->attach_quadrature_rule (qedgerule.get());
1911 fe->edge_reinit (elem, e);
1912 const unsigned int n_qp = qedgerule->n_points();
1913
1914
1915 for (unsigned int qp=0; qp<n_qp; qp++)
1916 {
1917
1918 Number fineval =
f->component(var_component,
1919 xyz_values[qp],
1921
1924 finegrad =
g->component(var_component,
1925 xyz_values[qp],
1927
1928
1929 for (unsigned int sidei=0, freei=0;
1930 sidei != n_side_dofs; ++sidei)
1931 {
1932 unsigned int i = side_dofs[sidei];
1933
1934 if (dof_is_fixed[i])
1935 continue;
1936 for (unsigned int sidej=0, freej=0;
1937 sidej != n_side_dofs; ++sidej)
1938 {
1939 unsigned int j = side_dofs[sidej];
1940 if (dof_is_fixed[j])
1941 Fe(freei) -= phi[i][qp] * phi[j][qp] *
1942 JxW[qp] * Ue(j);
1943 else
1944 Ke(freei,freej) += phi[i][qp] *
1945 phi[j][qp] * JxW[qp];
1947 {
1948 if (dof_is_fixed[j])
1949 Fe(freei) -= ((*dphi)[i][qp] *
1950 (*dphi)[j][qp]) *
1951 JxW[qp] * Ue(j);
1952 else
1953 Ke(freei,freej) += ((*dphi)[i][qp] *
1954 (*dphi)[j][qp])
1955 * JxW[qp];
1956 }
1957 if (!dof_is_fixed[j])
1958 freej++;
1959 }
1960 Fe(freei) += phi[i][qp] * fineval * JxW[qp];
1962 Fe(freei) += (finegrad * (*dphi)[i][qp]) *
1963 JxW[qp];
1964 freei++;
1965 }
1966 }
1967
1968 Ke.cholesky_solve(Fe, Uedge);
1969
1970
1971 for (unsigned int i=0; i != free_dofs; ++i)
1972 {
1973 Number & ui = Ue(side_dofs[free_dof[i]]);
1976 ui = Uedge(i);
1977 dof_is_fixed[side_dofs[free_dof[i]]] = true;
1978 }
1979 }
1980
1981
1983 for (unsigned short s = 0; s != n_sides; ++s)
1984 {
1985 if (!is_boundary_side[s])
1986 continue;
1987
1989 side_dofs);
1990
1991
1992
1993 unsigned int free_dofs = 0;
1995 if (!dof_is_fixed[side_dofs[i]])
1996 free_dof[free_dofs++] = i;
1997
1998
1999 if (!free_dofs)
2000 continue;
2001
2002 Ke.resize (free_dofs, free_dofs); Ke.zero();
2003 Fe.resize (free_dofs); Fe.zero();
2004
2005 DenseVector<Number> Uside(free_dofs);
2006
2007
2008 fe->attach_quadrature_rule (qsiderule.get());
2009 fe->reinit (elem, s);
2010 const unsigned int n_qp = qsiderule->n_points();
2011
2012 const unsigned int n_side_dofs =
2013 cast_int<unsigned int>(side_dofs.size());
2014
2015
2016 for (unsigned int qp=0; qp<n_qp; qp++)
2017 {
2018
2019 Number fineval =
f->component(var_component,
2020 xyz_values[qp],
2022
2025 finegrad =
g->component(var_component,
2026 xyz_values[qp],
2028
2029
2030 for (unsigned int sidei=0, freei=0;
2031 sidei != n_side_dofs; ++sidei)
2032 {
2033 unsigned int i = side_dofs[sidei];
2034
2035 if (dof_is_fixed[i])
2036 continue;
2037 for (unsigned int sidej=0, freej=0;
2038 sidej != n_side_dofs; ++sidej)
2039 {
2040 unsigned int j = side_dofs[sidej];
2041 if (dof_is_fixed[j])
2042 Fe(freei) -= phi[i][qp] * phi[j][qp] *
2043 JxW[qp] * Ue(j);
2044 else
2045 Ke(freei,freej) += phi[i][qp] *
2046 phi[j][qp] * JxW[qp];
2048 {
2049 if (dof_is_fixed[j])
2050 Fe(freei) -= ((*dphi)[i][qp] *
2051 (*dphi)[j][qp]) *
2052 JxW[qp] * Ue(j);
2053 else
2054 Ke(freei,freej) += ((*dphi)[i][qp] *
2055 (*dphi)[j][qp])
2056 * JxW[qp];
2057 }
2058 if (!dof_is_fixed[j])
2059 freej++;
2060 }
2061 Fe(freei) += (fineval * phi[i][qp]) * JxW[qp];
2063 Fe(freei) += (finegrad * (*dphi)[i][qp]) *
2064 JxW[qp];
2065 freei++;
2066 }
2067 }
2068
2069 Ke.cholesky_solve(Fe, Uside);
2070
2071
2072 for (unsigned int i=0; i != free_dofs; ++i)
2073 {
2074 Number & ui = Ue(side_dofs[free_dof[i]]);
2077 ui = Uside(i);
2078 dof_is_fixed[side_dofs[free_dof[i]]] = true;
2079 }
2080 }
2081
2085
2086
2087 {
2089
2090 for (unsigned int i = 0; i < n_dofs; i++)
2091 if (dof_is_fixed[i] &&
2092 (dof_indices[i] >= first) &&
2093 (dof_indices[i] < last))
2094 {
2096 }
2097 }
2098 }
2099 }
2100}
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
static void dofs_on_side(const Elem *const elem, const unsigned int dim, const FEType &fe_t, unsigned int s, std::vector< unsigned int > &di, const bool add_p_level=true)
Fills the vector di with the local degree of freedom indices associated with side s of element elem A...
static unsigned int n_dofs_at_node(const unsigned int dim, const FEType &fe_t, const ElemType t, const unsigned int n)
static void dofs_on_edge(const Elem *const elem, const unsigned int dim, const FEType &fe_t, unsigned int e, std::vector< unsigned int > &di, const bool add_p_level=true)
Fills the vector di with the local degree of freedom indices associated with edge e of element elem A...
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
unsigned int mesh_dimension() const
virtual void set(const numeric_index_type i, const T value)=0
Sets v(i) = value.
virtual numeric_index_type last_local_index() const =0
virtual numeric_index_type first_local_index() const =0
Real time
For time-dependent problems, this is the time t at the beginning of the current timestep.
unsigned int variable_scalar_number(std::string_view var, unsigned int component) const
const DofMap & get_dof_map() const
const MeshBase & get_mesh() const
spin_mutex spin_mtx
A convenient spin mutex object which can be used for obtaining locks.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
template class LIBMESH_EXPORT DenseMatrix< Real >
static constexpr Real TOLERANCE
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
const dof_id_type n_nodes