2
/// This file is part of Rheolef.
4
/// Copyright (C) 2000-2009 Pierre Saramito <Pierre.Saramito@imag.fr>
6
/// Rheolef is free software; you can redistribute it and/or modify
7
/// it under the terms of the GNU General Public License as published by
8
/// the Free Software Foundation; either version 2 of the License, or
9
/// (at your option) any later version.
11
/// Rheolef is distributed in the hope that it will be useful,
12
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
/// GNU General Public License for more details.
16
/// You should have received a copy of the GNU General Public License
17
/// along with Rheolef; if not, write to the Free Software
18
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
/// =========================================================================
22
#include "rheolef/space.h"
23
#include "rheolef/space_mult.h"
24
#include "rheolef/piola.h"
28
// ======================================================================
30
// ======================================================================
31
template <class T, class M>
32
space_base_rep<T,M>::space_base_rep (
33
const geo_basic<T,M>& omega_in,
36
: _constit(omega_in,approx,valued),
43
// omega_in is compressed by space_scalar_constitution() allocator
44
// when it is a domain: then it becomes a geo_domain, with compressed numbering
45
// so, omega_in can be different from omega:
46
if (approx == "") return; // empty element => default cstor
47
_idof2blk_iub.resize (_constit.ownership());
50
template <class T, class M>
51
space_base_rep<T,M>::space_base_rep (const space_constitution<T,M>& constit)
59
distributor idof_ownership = _constit.ownership();
60
_idof2blk_iub.resize (idof_ownership);
63
template <class T, class M>
64
space_base_rep<T,M>::space_base_rep (const space_mult_list<T,M>& expr)
72
_idof2blk_iub.resize (_constit.ownership());
75
template <class T, class M>
77
space_base_rep<T,M>::init_xdof()
79
if (_constit.valued_tag() == space_constant::mixed) {
80
trace_macro ("init_xdof and mixed valued space: not yet");
83
// precompute one time for all all dof nodes, for an easy interpolation
84
// apply only to nodal fem basis (eg. Lagrange) only
85
// TODO: in a lasy way: at first call to xdof(idof), call this initialization
86
const geo_basic<T,M>& omega = get_geo();
87
const numbering<T,M>& fem = get_numbering();
88
bool is_isoparametric = (fem.name() == omega.get_piola_basis().name());
89
if (is_isoparametric) {
90
// 1.a) geometric nodes coincides to fem dof nodes:
91
_xdof = omega.get_nodes();
94
// 1.b) here is the non-isoparametric case: eg. P0 fem space on a P1 geo
95
distributor xdof_ownership;
96
if (_constit.valued_tag() == space_constant::scalar) {
97
xdof_ownership = ownership();
99
// get xdof sizes from any component:
100
xdof_ownership = _constit[0].ownership();
102
_xdof.resize (xdof_ownership);
103
std::vector<bool> marked (ndof(), false);
104
size_type count_mark = 0;
105
std::vector<size_type> dis_idof;
106
std::vector<size_type> dis_inod;
107
size_type first_dis_idof = xdof_ownership.first_index();
108
basis_on_nodal_basis b (fem.get_basis(), omega.get_piola_basis());
109
for (typename geo_basic<T,M>::const_iterator iter = omega.begin(), last = omega.end(); iter != last; iter++) {
110
const geo_element& K = *iter;
111
fem.dis_idof (omega.sizes(), K, dis_idof);
112
omega.dis_inod (K, dis_inod);
113
for (size_type loc_idof = 0, loc_ndof = dis_idof.size(); loc_idof < loc_ndof; loc_idof++) {
114
assert_macro (dis_idof[loc_idof] < xdof_ownership.dis_size(),
115
"dis_idof " << dis_idof[loc_idof] << " out of range [0:" << xdof_ownership.dis_size() << "[");
116
if (! xdof_ownership.is_owned (dis_idof[loc_idof])) continue;
117
size_type idof = dis_idof[loc_idof] - first_dis_idof;
118
if (marked [idof]) continue;
119
marked [idof] = true;
121
_xdof[idof] = piola_transformation (omega, b, K.variant(), dis_inod, loc_idof);
124
size_type dis_n_missing = marked.size() - count_mark;
125
#ifdef _RHEOLEF_HAVE_MPI
126
dis_n_missing = mpi::all_reduce (comm(), dis_n_missing, std::plus<size_type>());
127
#endif // _RHEOLEF_HAVE_MPI
128
if (dis_n_missing == 0) {
132
// 2) on some rare 3d bdry geo_domains with distributed nproc > 1, there are missing xdofs...
133
// => second pass: assembly only external xdofs, an performs some comms
134
for (typename geo_basic<T,M>::const_iterator iter = omega.begin(), last = omega.end(); iter != last; iter++) {
135
const geo_element& K = *iter;
136
fem.dis_idof (omega.sizes(), K, dis_idof);
137
omega.dis_inod (K, dis_inod);
138
for (size_type loc_idof = 0, loc_ndof = dis_idof.size(); loc_idof < loc_ndof; loc_idof++) {
139
if (xdof_ownership.is_owned (dis_idof[loc_idof])) continue;
140
_xdof.dis_entry (dis_idof[loc_idof]) = piola_transformation (omega, b, K.variant(), dis_inod, loc_idof);
143
_xdof.dis_entry_assembly();
145
template <class T, class M>
147
space_base_rep<T,M>::base_freeze_body () const
149
// -----------------------------------------------------------------------
150
// 1) loop on domains: mark blocked dofs
151
// -----------------------------------------------------------------------
152
array<size_type,M> blocked_flag = _constit.build_blocked_flag();
154
// copy the blocked_flag into the iub array, as the "blocked" bit:
155
for (size_type idof = 0, ndof = blocked_flag.size(); idof < ndof; idof++) {
156
_idof2blk_iub [idof].set_blocked (blocked_flag[idof]);
158
// -----------------------------------------------------------------------
160
// -----------------------------------------------------------------------
161
size_type n_unknown = 0;
162
size_type n_blocked = 0;
163
for (size_type idof = 0, ndof = _idof2blk_iub.size(); idof < ndof; idof++) {
164
bool blk = _idof2blk_iub [idof].is_blocked();
166
_idof2blk_iub[idof].set_iub (n_unknown);
169
_idof2blk_iub[idof].set_iub (n_blocked);
173
size_type dis_n_unknown = n_unknown;
174
size_type dis_n_blocked = n_blocked;
175
#ifdef _RHEOLEF_HAVE_MPI
176
if (is_distributed<M>::value) {
177
dis_n_unknown = mpi::all_reduce (comm(), dis_n_unknown, std::plus<T>());
178
dis_n_blocked = mpi::all_reduce (comm(), dis_n_blocked, std::plus<T>());
180
#endif // // _RHEOLEF_HAVE_MPI
181
_iu_ownership = distributor (dis_n_unknown, comm(), n_unknown);
182
_ib_ownership = distributor (dis_n_blocked, comm(), n_blocked);
184
// ----------------------------------------------------------------------------
185
// used by field & form_assembly
186
// ----------------------------------------------------------------------------
187
template <class T, class M>
189
space_base_rep<T,M>::dis_idof (const geo_element& K, std::vector<size_type>& dis_idof) const
192
_constit.dis_idof (K, dis_idof);
194
// ----------------------------------------------------------------------------
195
// stamp : e.g. "P1(square)", for field_expr<Expr> checks
196
// ----------------------------------------------------------------------------
197
template <class T, class M>
199
space_base_rep<T,M>::stamp() const
201
if (get_geo().name() == "*nogeo*") return "";
202
return get_numbering().name() + "(" + get_geo().name() + ")";
204
// ----------------------------------------------------------------------------
206
// => build here the requiresd temporary indirect array
207
// ----------------------------------------------------------------------------
209
Implementation note: there is two numbering styles
211
bgd_idof : from the current space
212
dom_idof : from a space compacted to the domain "dom", as geo_domain does
214
This function returns the renumbering array "dom_idof2bgd_idof".
215
It is a temporary, used at the fly when using the u[dom] syntax.
217
template <class T, class M>
218
array<typename space_base_rep<T,M>::size_type, M>
219
space_base_rep<T,M>::build_indirect_array (
220
const space_base_rep<T,M>& Wh, // Wh = space on domain
221
const std::string& dom_name // redundant: contained in Wh.get_geo()
224
const space_base_rep<T,M>& Vh = *this; // Vh = space on background mesh
227
const geo_basic<T,M>& dom_gamma = Wh.get_geo();
228
const geo_basic<T,M>& bgd_gamma = Vh.get_geo()[dom_name];
229
size_type map_dim = dom_gamma.map_dimension();
230
check_macro (dom_gamma.size() == bgd_gamma.size(), "incompatible domains");
231
distributor dom_ownership = Wh.ownership();
232
distributor bgd_ownership = Vh.ownership();
233
size_type first_dom_dis_idof = dom_ownership.first_index();
234
size_type first_bgd_dis_idof = bgd_ownership.first_index();
235
std::vector<size_type> dom_dis_idofs, bgd_dis_idofs;
236
array<size_type, M> dom_idof2bgd_idof (dom_ownership, std::numeric_limits<size_type>::max());
237
for (size_type ige = 0, nge = dom_gamma.size(); ige < nge; ige++) {
238
const geo_element& dom_S = dom_gamma[ige];
239
const geo_element& bgd_S = bgd_gamma[ige];
240
Wh.dis_idof (dom_S, dom_dis_idofs);
241
Vh.dis_idof (bgd_S, bgd_dis_idofs);
242
for (size_type loc_idof = 0, loc_ndof = dom_dis_idofs.size(); loc_idof < loc_ndof; loc_idof++) {
243
size_type dom_dis_idof = dom_dis_idofs [loc_idof];
244
size_type bgd_dis_idof = bgd_dis_idofs [loc_idof];
245
dom_idof2bgd_idof.dis_entry (dom_dis_idof) = bgd_dis_idof;
248
dom_idof2bgd_idof.dis_entry_assembly();
249
// move to local numbering:
250
for (size_type dom_idof = 0, dom_ndof = dom_idof2bgd_idof.size(); dom_idof < dom_ndof; dom_idof++) {
251
size_type bgd_dis_idof = dom_idof2bgd_idof [dom_idof];
252
size_type dom_dis_idof = dom_idof + first_dom_dis_idof;
253
check_macro (bgd_ownership.is_owned (bgd_dis_idof), "unexpected external dom2bgd("<<dom_dis_idof<<")="<<bgd_dis_idof);
254
size_type bgd_idof = bgd_dis_idof - first_bgd_dis_idof;
255
dom_idof2bgd_idof [dom_idof] = bgd_idof;
257
return dom_idof2bgd_idof;
259
// ----------------------------------------------------------------------------
260
// instanciation in library
261
// ----------------------------------------------------------------------------
262
template class space_base_rep<Float,sequential>;
264
#ifdef _RHEOLEF_HAVE_MPI
265
template class space_base_rep<Float,distributed>;
266
#endif // _RHEOLEF_HAVE_MPI
268
} // namespace rheolef