GetFEM  5.5
getfem_mesh_slice.cc
1 /*===========================================================================
2 
3  Copyright (C) 2003-2026 Julien Pommier
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see https://www.gnu.org/licenses/.
18 
19 ===========================================================================*/
20 
23 
24 namespace getfem {
25 
26  std::ostream& operator<<(std::ostream& o, const stored_mesh_slice& m) {
27  o << "stored_mesh_slice, containing " << m.nb_convex() << " convexes\n";
28  for (size_type ic = 0; ic < m.nb_convex(); ++ic) {
29  o << "slice convex #" << ic << " (original = " << m.convex_num(ic)
30  << ")\n";
31  for (size_type i = 0; i < m.nodes(ic).size(); ++i) {
32  o << "node " << i << ": " << m.nodes(ic)[i].pt << ", ref="
33  << m.nodes(ic)[i].pt_ref << " flist=" << m.nodes(ic)[i].faces
34  << endl;
35  }
36  for (size_type i = 0; i < m.simplexes(ic).size(); ++i) {
37  o << "simplex " << i << ", inodes=";
38  for (size_type j=0;j< m.simplexes(ic)[i].dim()+1;++j)
39  o << m.simplexes(ic)[i].inodes[j] << " ";
40  o << endl;
41  }
42  o << endl;
43  }
44  return o;
45  }
46 
47  void stored_mesh_slice::write_to_file(const std::string &name,
48  bool with_mesh) const {
49  std::ofstream o(name.c_str());
50  GMM_ASSERT1(o, "impossible to open file '" << name << "'");
51  o << "% GETFEM SLICE FILE " << '\n';
52  o << "% GETFEM VERSION " << GETFEM_VERSION << '\n' << '\n' << '\n';
53  if (with_mesh) linked_mesh().write_to_file(o);
54  write_to_file(o);
55  }
56 
57  void stored_mesh_slice::write_to_file(std::ostream &os) const {
58  os << "\nBEGIN MESH_SLICE\n";
59  os << " DIM " << int(dim()) << "\n";
60  for (unsigned i=0; i < cvlst.size(); ++i) {
61  const convex_slice &cs = cvlst[i];
62  os << " CONVEX " << cs.cv_num
63  << " " << int(cs.fcnt)
64  << " " << int(cs.discont) << "\n"
65  << " " << cs.nodes.size() << " " << cs.simplexes.size() << "\n";
66  for (unsigned j=0; j < cs.nodes.size(); ++j) {
67  os << "\t";
68  for (unsigned k=0; k < cs.nodes[j].pt.size(); ++k) {
69  if (k) os << " ";
70  os << cs.nodes[j].pt[k];
71  }
72  os << ";";
73  for (unsigned k=0; k < cs.nodes[j].pt_ref.size(); ++k)
74  os << " " << cs.nodes[j].pt_ref[k];
75  os << "; "; os << cs.nodes[j].faces.to_ulong();;
76  os << "\n";
77  }
78  for (unsigned j=0; j < cs.simplexes.size(); ++j) {
79  os << "\t" << cs.simplexes[j].inodes.size() << ":";
80  for (unsigned k=0; k < cs.simplexes[j].inodes.size(); ++k) {
81  os << " " << cs.simplexes[j].inodes[k];
82  }
83  os << "\n";
84  }
85  }
86  os << "END MESH_SLICE\n";
87  }
88 
89  void stored_mesh_slice::read_from_file(const std::string &name,
90  const getfem::mesh &m) {
91  std::ifstream o(name.c_str());
92  GMM_ASSERT1(o, "slice file '" << name << "' does not exist");
93  read_from_file(o,m);
94  }
95 
96  void stored_mesh_slice::read_from_file(std::istream &ist,
97  const getfem::mesh &m) {
98  if (!poriginal_mesh) {
99  poriginal_mesh = &m;
100  } else GMM_ASSERT1(poriginal_mesh == &m, "wrong mesh..");
101 
102  dim_ = m.dim();
103  cv2pos.clear();
104  cv2pos.resize(m.nb_allocated_convex(), size_type(-1));
105 
106  std::string tmp;
107  ist.precision(16);
108  ist.seekg(0);ist.clear();
109  bgeot::read_until(ist, "BEGIN MESH_SLICE");
110 
111  mesh_slicer::cs_nodes_ct nod;
112  mesh_slicer::cs_simplexes_ct sim;
113 
114 
115  while (true) {
116  ist >> std::ws; bgeot::get_token(ist, tmp);
117  if (bgeot::casecmp(tmp, "END")==0) {
118  break;
119  } else if (bgeot::casecmp(tmp, "DIM")==0) {
120  int d; ist >> d;
121  dim_ = d;
122  } else if (bgeot::casecmp(tmp, "CONVEX")==0) {
123  bgeot::get_token(ist,tmp);
124  size_type ic = atoi(tmp.c_str());
125  GMM_ASSERT1(m.convex_index().is_in(ic), "Convex " << ic <<
126  " does not exist, are you sure "
127  "that the mesh attached to this object is right one ?");
128  bgeot::pconvex_ref cvr = m.trans_of_convex(ic)->convex_ref();
129  unsigned fcnt, discont, nbn, nbs;
130  ist >> fcnt >> discont >> nbn >> nbs;
131  nod.resize(nbn);
132  sim.resize(nbs);
133  for (unsigned i=0; i < nbn; ++i) {
134  nod[i].pt.resize(dim());
135  nod[i].pt_ref.resize(cvr->structure()->dim());
136  for (unsigned j=0; j < dim(); ++j)
137  ist >> nod[i].pt[j];
138  ist >> bgeot::skip(";");
139  for (unsigned j=0; j < cvr->structure()->dim(); ++j)
140  ist >> nod[i].pt_ref[j];
141  ist >> bgeot::skip(";");
142  unsigned long ul; ist >> ul;
143  nod[i].faces = slice_node::faces_ct(int(ul));
144  }
145  for (unsigned i=0; i < nbs; ++i) {
146  unsigned np(0);
147  ist >> np >> bgeot::skip(":");
148  GMM_ASSERT1(np <= dim()+1, "invalid simplex..");
149  sim[i].inodes.resize(np);
150  for (unsigned j=0; j < np; ++j)
151  ist >> sim[i].inodes[j];
152  }
153  dal::bit_vector bv; bv.add(0, nbs);
154  set_convex(ic, cvr, nod, sim, dim_type(fcnt), bv, discont);
155  } else if (tmp.size()) {
156  GMM_ASSERT1(false, "Unexpected token '" << tmp <<
157  "' [pos=" << std::streamoff(ist.tellg()) << "]");
158  } else if (ist.eof()) {
159  GMM_ASSERT1(false, "Unexpected end of stream "
160  << "(missing BEGIN MESH_SLICE/END MESH_SLICE ?)");
161  }
162  }
163  }
164 
165  void slicer_build_stored_mesh_slice::exec(mesh_slicer &ms) {
166  if (!sl.poriginal_mesh) {
167  sl.poriginal_mesh = &ms.m;
168  sl.dim_ = sl.linked_mesh().dim();
169  sl.cv2pos.resize(sl.linked_mesh().nb_allocated_convex());
170  gmm::fill(sl.cv2pos, size_type(-1));
171  } else if (sl.poriginal_mesh != &ms.m) GMM_ASSERT1(false, "wrong mesh..");
172  sl.set_convex(ms.cv, ms.cvr, ms.nodes, ms.simplexes, dim_type(ms.fcnt),
173  ms.splx_in, ms.discont);
174  }
175 
176  void stored_mesh_slice::set_convex(size_type cv, bgeot::pconvex_ref cvr,
177  mesh_slicer::cs_nodes_ct cv_nodes,
178  mesh_slicer::cs_simplexes_ct cv_simplexes,
179  dim_type fcnt,
180  const dal::bit_vector& splx_in,
181  bool discont) {
182  /* push the used nodes and simplexes in the final list */
183  if (splx_in.card() == 0) return;
184  merged_nodes_available = false;
185  std::vector<size_type> nused(cv_nodes.size(), size_type(-1));
186  convex_slice *sc = 0;
187  GMM_ASSERT1(cv < cv2pos.size(), "internal error");
188  if (cv2pos[cv] == size_type(-1)) {
189  cv2pos[cv] = cvlst.size();
190  cvlst.push_back(convex_slice());
191  sc = &cvlst.back();
192  sc->cv_num = cv;
193  sc->cv_dim = cvr->structure()->dim();
194  sc->cv_nbfaces = dim_type(cvr->structure()->nb_faces());
195  sc->fcnt = fcnt;
196  sc->global_points_count = points_cnt;
197  sc->discont = discont;
198  } else {
199  sc = &cvlst[cv2pos[cv]];
200  assert(sc->cv_num == cv);
201  }
202  for (dal::bv_visitor snum(splx_in); !snum.finished(); ++snum) {
203  slice_simplex& s = cv_simplexes[snum];
204  for (size_type i=0; i < s.dim()+1; ++i) {
205  size_type lnum = s.inodes[i];
206  if (nused[lnum] == size_type(-1)) {
207  nused[lnum] = sc->nodes.size(); sc->nodes.push_back(cv_nodes[lnum]);
208  dim_ = std::max(int(dim_), int(cv_nodes[lnum].pt.size()));
209  points_cnt++;
210  }
211  s.inodes[i] = nused[lnum];
212  }
213  simplex_cnt.resize(dim_+1, 0);
214  simplex_cnt[cv_simplexes[snum].dim()]++;
215  sc->simplexes.push_back(cv_simplexes[snum]);
216  }
217  }
218 
219  struct get_edges_aux {
220  size_type iA, iB;
221  mutable bool slice_edge;
222  get_edges_aux(size_type a, size_type b, bool slice_edge_) :
223  iA(std::min(a,b)), iB(std::max(a,b)), slice_edge(slice_edge_) {}
224  bool operator<(const get_edges_aux& other) const {
225  /* ignore the slice_edge on purpose */
226  return (iA < other.iA || (iA == other.iA && iB < other.iB));
227  }
228  };
229 
230  void stored_mesh_slice::get_edges(std::vector<size_type> &edges,
231  dal::bit_vector &slice_edges,
232  bool from_merged_nodes) const {
233  if (from_merged_nodes && !merged_nodes_available) merge_nodes();
234  std::set<get_edges_aux> e;
235  for (cvlst_ct::const_iterator it=cvlst.begin(); it != cvlst.end(); ++it) {
236  for (size_type is=0; is < it->simplexes.size(); ++is) {
237  const slice_simplex &s = it->simplexes[is];
238  for (size_type i=0; i < s.dim(); ++i) {
239  for (size_type j=i+1; j <= s.dim(); ++j) {
240  const slice_node& A = it->nodes[s.inodes[i]];
241  const slice_node& B = it->nodes[s.inodes[j]];
242  /* duplicate with slicer_build_edges_mesh which also
243  builds a list of edges */
244  if ((A.faces & B.faces).count() >= unsigned(it->cv_dim-1)) {
245  slice_node::faces_ct fmask((1 << it->cv_nbfaces)-1);
246  fmask.flip();
247  size_type iA, iB;
248  iA = it->global_points_count + s.inodes[i];
249  iB = it->global_points_count + s.inodes[j];
250  if (from_merged_nodes) {
251  iA = to_merged_index[iA]; iB = to_merged_index[iB];
252  }
253  get_edges_aux a(iA,iB,((A.faces & B.faces) & fmask).any());
254  std::set<get_edges_aux>::iterator p=e.find(a);
255  if (p != e.end()) {
256  if (p->slice_edge && !a.slice_edge) p->slice_edge = false;
257  } else e.insert(a);
258  }
259  }
260  }
261  }
262  }
263  slice_edges.clear(); slice_edges.sup(0, e.size());
264  edges.clear(); edges.reserve(2*e.size());
265  for (std::set<get_edges_aux>::const_iterator p=e.begin();
266  p != e.end(); ++p) {
267  if (p->slice_edge) slice_edges.add(edges.size()/2);
268  edges.push_back(p->iA);edges.push_back(p->iB);
269  }
270  }
271 
272  void stored_mesh_slice::build(const getfem::mesh& m,
273  const slicer_action *a,
274  const slicer_action *b,
275  const slicer_action *c,
276  size_type nrefine) {
277  clear();
278  mesh_slicer slicer(m);
279  slicer.push_back_action(*const_cast<slicer_action*>(a));
280  if (b) slicer.push_back_action(*const_cast<slicer_action*>(b));
281  if (c) slicer.push_back_action(*const_cast<slicer_action*>(c));
282  slicer_build_stored_mesh_slice sbuild(*this);
283  slicer.push_back_action(sbuild);
284  slicer.exec(nrefine);
285  }
286 
287  void stored_mesh_slice::replay(slicer_action *a, slicer_action *b,
288  slicer_action *c) const {
289  mesh_slicer slicer(linked_mesh());
290  slicer.push_back_action(*a);
291  if (b) slicer.push_back_action(*b);
292  if (c) slicer.push_back_action(*c);
293  slicer.exec(*this);
294  }
295 
297  dim_ = newdim;
298  for (size_type ic=0; ic < nb_convex(); ++ic) {
299  for (mesh_slicer::cs_nodes_ct::iterator it=nodes(ic).begin();
300  it != nodes(ic).end(); ++it) {
301  it->pt.resize(newdim);
302  }
303  }
304  }
305 
307  GMM_ASSERT1(dim()==sl.dim(), "inconsistent dimensions for slice merging");
308  clear_merged_nodes();
309  cv2pos.resize(std::max(cv2pos.size(), sl.cv2pos.size()), size_type(-1));
310  for (size_type i=0; i < sl.nb_convex(); ++i)
311  GMM_ASSERT1(cv2pos[sl.convex_num(i)] == size_type(-1) ||
312  cvlst[cv2pos[sl.convex_num(i)]].cv_dim == sl.cvlst[i].cv_num,
313  "inconsistent dimensions for convex " << sl.cvlst[i].cv_num
314  << " on the slices");
315  for (size_type i=0; i < sl.nb_convex(); ++i) {
316  size_type cv = sl.convex_num(i);
317  if (cv2pos[cv] == size_type(-1)) {
318  cv2pos[cv] = cvlst.size();
319  cvlst.push_back(convex_slice());
320  }
321  const stored_mesh_slice::convex_slice *src = &sl.cvlst[i];
322  stored_mesh_slice::convex_slice *dst = &cvlst[cv2pos[cv]];
323  size_type n = dst->nodes.size();
324  dst->nodes.insert(dst->nodes.end(), src->nodes.begin(),
325  src->nodes.end());
326  for (mesh_slicer::cs_simplexes_ct::const_iterator
327  it = src->simplexes.begin(); it != src->simplexes.end(); ++it) {
328  dst->simplexes.push_back(*it);
329  for (size_type j = 0; j < (*it).dim()+1; ++j)
330  dst->simplexes.back().inodes[j] += n;
331  simplex_cnt[dst->simplexes.back().dim()]++;
332  }
333  points_cnt += src->nodes.size();
334  }
335  size_type count = 0;
336  for (size_type ic=0; ic < nb_convex(); ++ic) {
337  cvlst[ic].global_points_count = count; count += nodes(ic).size();
338  }
339  assert(count == points_cnt);
340  }
341 
342  void stored_mesh_slice::clear_merged_nodes() const {
343  merged_nodes_idx.clear(); merged_nodes.clear();
344  to_merged_index.clear();
345  merged_nodes_available = false;
346  }
347 
349  size_type count = 0;
350  mesh mp;
351  clear_merged_nodes();
352  std::vector<size_type> iv;
353  std::vector<const slice_node*> nv(nb_points());
354  to_merged_index.resize(nb_points());
355  for (cvlst_ct::const_iterator it = cvlst.begin(); it != cvlst.end(); ++it) {
356  for (size_type i=0; i < it->nodes.size(); ++i) {
357  nv[count] = &it->nodes[i];
358  to_merged_index[count++] = mp.add_point(it->nodes[i].pt);
359  // cout << "orig[" << count-1 << "] = " << nv[count-1]->pt
360  // << ", idx=" << to_merged_index[count-1] << "\n";
361  }
362  }
363  gmm::sorted_indexes(to_merged_index,iv);
364  //cout << "to_merged_index = " << iv << "\n";
365  merged_nodes.resize(nb_points());
366  merged_nodes_idx.reserve(nb_points()/8);
367 
368  merged_nodes_idx.push_back(0);
369  for (size_type i=0; i < nb_points(); ++i) {
370  merged_nodes[i].P = nv[iv[i]];
371  merged_nodes[i].pos = unsigned(iv[i]);
372  // cout << "i=" << i << " -> {" << merged_nodes[i].P->pt
373  // << "," << merged_nodes[i].pos << "}\n";
374  if (i == nb_points()-1 ||
375  to_merged_index[iv[i+1]] != to_merged_index[iv[i]])
376  merged_nodes_idx.push_back(i+1);
377  }
378  //cout << "merged_nodes_idx = " << merged_nodes_idx << "\n";
379  merged_nodes_available = true;
380  }
381 
382  size_type stored_mesh_slice::memsize() const {
383  size_type sz = sizeof(stored_mesh_slice);
384  for (cvlst_ct::const_iterator it = cvlst.begin();
385  it != cvlst.end(); ++it) {
386  sz += sizeof(size_type);
387  // cerr << "memsize: convex " << it->cv_num << " nodes:"
388  // << it->nodes.size() << ", splxs:" << it->simplexes.size()
389  // << ", sz=" << sz << "\n";
390  for (size_type i=0; i < it->nodes.size(); ++i) {
391  // cerr << " point " << i << ": size+= " << sizeof(slice_node)
392  // << "+" << it->nodes[i].pt.memsize() << "+"
393  // << it->nodes[i].pt_ref.memsize() << "-"
394  // << sizeof(it->nodes[i].pt)*2 << "\n";*/
395  sz += sizeof(slice_node) +
396  (it->nodes[i].pt.memsize()+it->nodes[i].pt_ref.memsize())
397  - sizeof(it->nodes[i].pt)*2;
398  }
399  for (size_type i=0; i < it->simplexes.size(); ++i) {
400  // cerr << " simplex " << i << ": size+= " << sizeof(slice_simplex)
401  // << "+" << it->simplexes[i].inodes.size()*sizeof(size_type)
402  // << "\n";*/
403  sz += sizeof(slice_simplex) +
404  it->simplexes[i].inodes.size()*sizeof(size_type);
405  }
406  }
407  sz += cv2pos.size() * sizeof(size_type);
408  return sz;
409  }
410 
411 }
Inversion of geometric transformations.
const dal::bit_vector & convex_index() const
Return the list of valid convex IDs.
size_type nb_allocated_convex() const
The number of convex indexes from 0 to the index of the last convex.
Apply a serie a slicing operations to a mesh.
Describe a mesh (collection of convexes (elements) and points).
Definition: getfem_mesh.h:98
void write_to_file(const std::string &name) const
Write the mesh to a file.
Definition: getfem_mesh.cc:708
generic slicer class.
a getfem::mesh_slicer whose side effect is to build a stored_mesh_slice object.
The output of a getfem::mesh_slicer which has been recorded.
size_type dim() const
return the slice dimension
void replay(slicer_action &a) const
Apply the listed slicer_action(s) to the slice object.
void set_dim(size_type newdim)
change the slice dimension (append zeros or truncate node coordinates..)
const mesh_slicer::cs_nodes_ct & nodes(size_type ic) const
Return the list of nodes for the 'ic'th convex of the slice.
void merge(const stored_mesh_slice &sl)
merge with another mesh slice.
const mesh & linked_mesh() const
return a pointer to the original mesh
void write_to_file(std::ostream &os) const
Save a slice content to a text file.
size_type nb_points() const
Return the number of nodes in the slice.
size_type nb_convex() const
return the number of convexes of the original mesh referenced in the slice
void read_from_file(std::istream &ist, const getfem::mesh &m)
Read a slice from a file.
void merge_nodes() const
build a list of merged nodes.
void get_edges(std::vector< size_type > &edges, dal::bit_vector &slice_edges, bool from_merged_nodes) const
Extract the list of mesh edges.
size_type convex_num(size_type ic) const
return the original convex number of the 'ic'th convex referenced in the slice
void build(const getfem::mesh &m, const slicer_action &a, size_type nrefine=1)
Build the slice, by applying a slicer_action operation.
Define the class getfem::stored_mesh_slice.
std::ostream & operator<<(std::ostream &o, const convex_structure &cv)
Print the details of the convex structure cvs to the output stream o.
int get_token(std::istream &ist, std::string &st, bool ignore_cr, bool to_up, bool read_un_pm, int *linenb)
Very simple lexical analysis of general interest for reading small languages with a "MATLAB like" syn...
Definition: bgeot_ftool.cc:49
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:48
GEneric Tool for Finite Element Methods.