File: SlipConstraint.h

package info (click to toggle)
dolfinx-mpc 0.9.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,188 kB
  • sloc: python: 7,263; cpp: 5,462; makefile: 69; sh: 4
file content (174 lines) | stat: -rw-r--r-- 6,274 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Copyright (C) 2019-2021 Jorgen S. Dokken
//
// This file is part of DOLFINX_MPC
//
// SPDX-License-Identifier:    MIT

#include "ContactConstraint.h"
#include <dolfinx/fem/DirichletBC.h>
#include <dolfinx/fem/FunctionSpace.h>
#include <dolfinx/mesh/MeshTags.h>
namespace dolfinx_mpc
{

//
template <typename T, std::floating_point U>
mpc_data<T> create_slip_condition(
    std::shared_ptr<dolfinx::fem::FunctionSpace<U>>& space,
    const dolfinx::mesh::MeshTags<std::int32_t>& meshtags, std::int32_t marker,
    const dolfinx::fem::Function<T>& v,
    std::vector<std::shared_ptr<const dolfinx::fem::DirichletBC<T>>> bcs,
    const bool sub_space)
{
  // Map from collapsed sub space to parent space
  std::function<const std::int32_t(const std::int32_t&)> parent_map;

  // Interpolate input function into suitable space
  std::shared_ptr<dolfinx::fem::Function<T>> n;
  if (sub_space)
  {
    std::pair<dolfinx::fem::FunctionSpace<U>, std::vector<int32_t>>
        collapsed_space = space->collapse();
    auto V_ptr = std::make_shared<dolfinx::fem::FunctionSpace<U>>(
        std::move(collapsed_space.first));
    n = std::make_shared<dolfinx::fem::Function<T>>(V_ptr);
    n->interpolate(v);
    parent_map = [sub_map = collapsed_space.second](const std::int32_t dof)
    { return sub_map[dof]; };
  }
  else
  {
    parent_map = [](const std::int32_t dof) { return dof; };
    n = std::make_shared<dolfinx::fem::Function<T>>(space);
    n->interpolate(v);
  }

  // Info from parent space
  auto W_imap = space->dofmap()->index_map;
  std::span<const int> W_ghost_owners = W_imap->owners();

  const int W_bs = space->dofmap()->index_map_bs();
  const int W_local_size = W_imap->size_local();

  const std::vector<std::int32_t> slave_facets = meshtags.find(marker);

  auto mesh = space->mesh();
  MPI_Comm comm = mesh->comm();
  const int rank = dolfinx::MPI::rank(comm);

  // Array containing blocks of the MPC slaves
  std::vector<std::int32_t> slave_blocks;
  std::int32_t num_normal_components;

  // Find blocks in collapsed space and remove DirichletBC dofs
  if (sub_space)
  {

    // Get all degrees of freedom in the sub-space on the given facets
    std::array<std::vector<std::int32_t>, 2> entity_dofs
        = dolfinx::fem::locate_dofs_topological(
            *space->mesh()->topology_mutable(),
            {*space->dofmap(), *n->function_space()->dofmap()}, meshtags.dim(),
            slave_facets);

    // Remove Dirichlet BC dofs
    const std::vector<std::int8_t> bc_marker
        = dolfinx_mpc::is_bc<T>(*space, entity_dofs[0], bcs);
    num_normal_components = n->function_space()->dofmap()->index_map_bs();
    slave_blocks.reserve(entity_dofs[0].size());
    for (std::size_t i = 0; i < bc_marker.size(); i++)
      if (!bc_marker[i])
        slave_blocks.push_back(entity_dofs[1][i] / num_normal_components);
    // Erase blocks duplicate blocks
    dolfinx::radix_sort(std::span<std::int32_t>(slave_blocks));
    slave_blocks.erase(std::unique(slave_blocks.begin(), slave_blocks.end()),
                       slave_blocks.end());
  }
  else
  {
    num_normal_components = W_bs;
    std::vector<std::int32_t> all_slave_blocks
        = dolfinx::fem::locate_dofs_topological(
            *space->mesh()->topology_mutable(), *space->dofmap(),
            meshtags.dim(), slave_facets);
    // Remove Dirichlet BC dofs
    const std::vector<std::int8_t> bc_marker
        = dolfinx_mpc::is_bc<T>(*space, all_slave_blocks, bcs);
    for (std::size_t i = 0; i < bc_marker.size(); i++)
      if (!bc_marker[i])
        slave_blocks.push_back(all_slave_blocks[i]);
  }

  const std::span<const T>& n_vec = n->x()->array();

  // Arrays holding MPC data
  std::vector<std::int32_t> slaves;
  std::vector<std::int64_t> masters;
  std::vector<T> coeffs;
  std::vector<std::int32_t> owners;
  std::vector<std::int32_t> offsets(1, 0);
  // Temporary arrays used to hold information about masters
  std::vector<std::int64_t> pair_m;
  for (auto block : slave_blocks)
  {
    std::span<const T> normal(
        std::next(n_vec.begin(), block * num_normal_components),
        num_normal_components);

    // Determine slave dof by component with biggest normal vector (to avoid
    // issues with grids aligned with coordiante system)
    auto max_el = std::ranges::max_element(
        normal, [](T a, T b) { return std::norm(a) < std::norm(b); });
    auto slave_index = std::distance(normal.begin(), max_el);
    assert(slave_index < num_normal_components);
    std::int32_t parent_slave
        = parent_map(block * num_normal_components + slave_index);
    slaves.push_back(parent_slave);

    std::vector<std::int32_t> parent_masters;
    std::vector<T> pair_c;
    std::vector<std::int32_t> pair_o;
    for (std::int32_t i = 0; i < num_normal_components; ++i)
    {
      if (i != slave_index)
      {
        const std::int32_t parent_dof
            = parent_map(block * num_normal_components + i);
        T coeff = -normal[i] / normal[slave_index];
        parent_masters.push_back(parent_dof);
        pair_c.push_back(coeff);
        const std::int32_t m_rank
            = parent_dof < W_local_size * W_bs
                  ? rank
                  : W_ghost_owners[parent_dof / W_bs - W_local_size];
        pair_o.push_back(m_rank);
      }
    }
    // Convert local parent dof to local parent block
    std::vector<std::int32_t> parent_blocks = parent_masters;
    std::ranges::for_each(parent_blocks, [W_bs](auto& b) { b /= W_bs; });
    // Map blocks from local to global
    pair_m.resize(parent_masters.size());
    W_imap->local_to_global(parent_blocks, pair_m);
    // Convert global parent block to the dofs
    for (std::size_t i = 0; i < parent_masters.size(); ++i)
    {
      std::div_t div = std::div(parent_masters[i], W_bs);
      pair_m[i] = pair_m[i] * W_bs + div.rem;
    }
    masters.insert(masters.end(), pair_m.begin(), pair_m.end());
    coeffs.insert(coeffs.end(), pair_c.begin(), pair_c.end());
    offsets.push_back((std::int32_t)masters.size());
    owners.insert(owners.end(), pair_o.begin(), pair_o.end());
  }
  mpc_data<T> data;
  data.slaves = slaves;

  data.masters = masters;
  data.offsets = offsets;
  data.owners = owners;
  data.coeffs = coeffs;
  return data;
}

} // namespace dolfinx_mpc