KASKADE 7 development version
amirameshreader.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2002-2023 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef AMIRAMESHREADER_HH
14#define AMIRAMESHREADER_HH
15
16#include <algorithm>
17#include <cstdint>
18#include <iostream>
19#include <memory>
20#include <string>
21#include <fstream>
22#include <sstream>
23#include <vector>
24#include <cassert>
25#include <stdexcept>
26
27#include <boost/timer/timer.hpp>
28#include <boost/lexical_cast.hpp>
29
30#include <dune/common/fvector.hh>
31
32#include <amiramesh/AmiraMesh.h>
33#include "fem/lagrangespace.hh"
34#include "io/ioTools.hh"
35#include "io/vtk.hh"
37
38// forward declaration
39template <> class std::complex<float>;
40
41namespace Kaskade
42{
52 namespace AmiraMeshReader
53 {
54 namespace ImplementationDetails
55 {
56 std::string exceptionMessage(std::string const& function, std::string const& gridfile, int line)
57 {
58 return std::string("In AmiraMeshReader::") + function + ", line " + boost::lexical_cast<std::string>(line) + ": Error reading " + gridfile + "\n";
59 }
60
61 std::string exceptionMessage(std::string const& function, std::string const& location, std::string const& component, int line)
62 {
63 return std::string("In AmiraMeshReader::") + function + ", line " + boost::lexical_cast<std::string>(line) + std::string(": Error reading ") + component + " of " + location + "\n";
64 }
65
66
67 template <class Source, class value_type, int components>
68 void extractData(size_t const n, Source const* source,
70 bool verbose=false)
71 {
72 if(verbose)
73 {
74 std::cout << n << " entries...\n";
75 std::cout.flush();
76 }
77 data.clear();
78 data.reserve(n);
79 data.insert(data.begin(),n,Dune::FieldVector<value_type,components>(0));
80
81 for (size_t i=0; i<n; ++i)
82 for (int j=0; j<components; ++j)
83 data[i][j] = static_cast<value_type>(source[i*components+j]);
84 }
85
86 template <class value_type, int components>
87 bool readData(AmiraMesh& am, char const* location, char const* name,
89 bool verbose=false)
90 {
91 if(verbose)
92 std::cout << "Looking for " << name << " at " << location << " with " << components << " components\n";
93
94 // Scan the contained data for the desired field
95 for (int i=0; i<am.dataList.size(); ++i)
96 {
97 auto const& data = *am.dataList[i];
98 if ( components==data.dim() // correct number of components
99 && std::strcmp(name, data.name())==0 // correct name
100 && std::strcmp(location,data.location()->name())==0 ) // correct location
101 {
102 // Number of nodes contained in the data set
103 size_t const n = data.location()->nNodes();
104
105 // Check which basic type actually is contained within the
106 // data set and convert the pointer type accordingly.
107 if (data.primType()==MC_FLOAT)
108 extractData(n,static_cast<float const*>(data.dataPtr()),out);
109 else if (data.primType()==MC_DOUBLE)
110 extractData(n,static_cast<double const*>(data.dataPtr()),out);
111 else if (data.primType()==MC_UINT8)
112 extractData(n,static_cast<std::uint8_t const*>(data.dataPtr()),out);
113 else if (data.primType()==MC_INT16)
114 extractData(n,static_cast<std::int16_t const*>(data.dataPtr()),out);
115 else if (data.primType()==MC_UINT16)
116 extractData(n,static_cast<std::uint16_t const*>(data.dataPtr()),out);
117 else if (data.primType()==MC_INT32)
118 extractData(n,static_cast<std::int32_t const*>(data.dataPtr()),out);
119 else
120 continue; // didn't find a known data type - look on
121
122 return true; // found
123 }
124 }
125
126 // nothing appropriate found
127 if(verbose)
128 std::cout << "Did not find specified data.\n";
129 for (int i=0; i<am.dataList.size(); ++i)
130 {
131 auto const& data = *am.dataList[i];
132 if(verbose)
133 std::cout << "data " << data.name() << " at " << data.location()->name()
134 << " with " << data.dim() << " components of type " << (int)data.primType() << "\n";
135 }
136 return false;
137 }
138
139
140 // Checks whether BoundaryTriangleData in the Amira mesh file is of type "byte" (true) or "int" (false).
141 bool boundaryIdByByte(std::string const& gridFile)
142 {
143 using namespace std;
144
145 ifstream infile(gridFile);
146 string line;
147 while(getline(infile, line)) {
148 istringstream iss(line);
149 string firstWord;
150 if((iss >> firstWord) && (firstWord == "BoundaryTriangleData")) {
151 string bracket, type;
152 if(iss >> bracket >> type) {
153 if(type == "byte") return true;
154 if(type == "int") return false;
155 }
156 throw Kaskade::LookupException("Wrong data type for BoundaryTriangleData. Has to be either byte or int.",__FILE__,__LINE__);
157 }
158 }
159 return false;
160 }
161
162 template <class Scalar, class Grid, class ScalarEd>
163 void readEdgePositions(Grid const& grid, Dune::GridFactory<Grid> const& factory, AmiraMesh & am, std::vector<Dune::FieldVector<ScalarEd, Grid::dimension>> & edgeDisplacement)
164 {
165 int const dim = Grid::dimension;
166 std::vector<Dune::FieldVector<unsigned int, 2>> edges;
167 std::vector<Dune::FieldVector<Scalar, dim>> edgePos;
168
169 bool exists = AmiraMeshReader::ImplementationDetails::readData(am,"Edges","fromTo",edges);
170 if (!exists)
171 {
172 throw Kaskade::LookupException("Could not read edges.",__FILE__,__LINE__);
173 }
174 exists = AmiraMeshReader::ImplementationDetails::readData(am,"Edges","Coordinates",edgePos);
175 if (!exists)
176 {
177 throw Kaskade::LookupException("Could not read edge positions.",__FILE__,__LINE__);
178 }
179
180 edgeDisplacement.resize(edges.size());
181
182 std::vector<std::pair<std::array<unsigned int, 2>,
183 Dune::FieldVector<Scalar, dim>>> edgeTable (edges.size());
184 for (int i=0; i<edges.size(); ++i)
185 {
186 edgeTable[i].first[0] = edges[i][0]-1;
187 edgeTable[i].first[1] = edges[i][1]-1;
188 if(edgeTable[i].first[0] > edgeTable[i].first[1]) std::swap(edgeTable[i].first[0], edgeTable[i].first[1]);
189
190 edgeTable[i].second = edgePos[i];
191 }
192 std::sort(edgeTable.begin(), edgeTable.end(), [](auto const& a, auto const& b) {return a.first < b.first;});
193
194 std::vector<bool> edgeRead(grid.size(dim-1), false);
195
196 for (auto const& element : elements(grid.leafGridView()))
197 {
198 auto const& refElement = Dune::ReferenceElements<double, dim>::general(element.type());
199 for (int j=0; j<refElement.size(dim-1); j++)
200 {
201 size_t edgeIndex = grid.leafGridView().indexSet().subIndex(element,j,dim-1);
202 if (!edgeRead[edgeIndex])
203 {
204 auto c0 = element.template subEntity<dim>(refElement.subEntity(j, dim-1, 0, dim));
205 auto c1 = element.template subEntity<dim>(refElement.subEntity(j, dim-1, 1, dim));
206
207 std::array<unsigned int, 2> wantedEdge { factory.insertionIndex(c0),
208 factory.insertionIndex(c1) };
209 if(wantedEdge[0] > wantedEdge[1])
210 std::swap(wantedEdge[0], wantedEdge[1]);
211
212 auto edge = std::lower_bound(edgeTable.begin(), edgeTable.end(), wantedEdge,
213 [] (auto const& a, auto const& b) { return a.first < b;});
214
215 if (edge == edgeTable.end() || edge->first != wantedEdge)
216 {
217 throw Kaskade::LookupException("Could not find edge.",__FILE__,__LINE__);
218 }
219
220 auto edgePosition = c0.geometry().corner(0);
221 edgePosition += c1.geometry().corner(0);
222 edgePosition /= 2.0;
223
224 edgeDisplacement[edgeIndex] = edge->second;
225 edgeDisplacement[edgeIndex] -= edgePosition;
226
227 edgeRead[edgeIndex] = true;
228 }
229 }
230 }
231 }
232
233 } // End of ImplementationDetails
234
235 // --------------------------------------------------------------------------------------------
236 // --------------------------------------------------------------------------------------------
237
239
260 template<class Grid, class Scalar, class ScalarEd = Scalar>
261 std::unique_ptr<Grid> readGrid(std::string const& gridfile, int initialGridSize = 0,
262 std::vector<int>* boundaryIds = nullptr,
263 std::vector<Dune::FieldVector<ScalarEd, Grid::dimension>>* edgeDisplacement = nullptr,
264 double scale = 1.0)
265 {
266 // we apply no transformation, i.e. the identity to
267 // each vertex of the grid
268 auto identity = [] (auto x) {return x;};
269 return readGrid<Grid,Scalar>(gridfile,identity,initialGridSize,boundaryIds,edgeDisplacement,scale);
270 }
271
273
295 template<class Grid, class Scalar, class ScalarEd = Scalar, class Deformation>
296 std::unique_ptr<Grid> readGrid(std::string const& gridfile,
297 Deformation const& deformation,
298 int initialGridSize = 0,
299 std::vector<int>* boundaryIds = nullptr,
300 std::vector<Dune::FieldVector<ScalarEd, Grid::dimension>>* edgeDisplacement = nullptr,
301 double scale = 1.0)
302 {
303 int const dim = Grid::dimension;
304 std::vector<Dune::FieldVector<Scalar,dim>> vertices;
305 std::vector<Dune::FieldVector<int,dim+1>> cells;
306 std::vector<Dune::FieldVector<int,dim>> boundary;
307
308 // open grid file.
309 std::cout << "Opening " << gridfile << " ...\n";
310 std::unique_ptr<AmiraMesh> am(AmiraMesh::read(gridfile.c_str()));
311 if(!am)
312 throw DetailedException(ImplementationDetails::exceptionMessage("readGrid(std::string const&, std::vector<int>&, int)", gridfile, __LINE__),__FILE__,__LINE__);
313
314 // read vertices
315 if (!ImplementationDetails::readData(*am,"Nodes","Coordinates",vertices))
316 throw std::runtime_error(ImplementationDetails::exceptionMessage("readGrid(std::string const&, std::vector<int>&, int)", "Nodes", "Coordinates", __LINE__));
317
318 // read cells
319 std::string cellName;
320 if(dim == 2) cellName = "Triangles";
321 if(dim == 3) cellName = "Tetrahedra";
322 if(dim != 2 && dim != 3)
323 throw std::runtime_error("Sorry!\nOnly 2D and 3D grids are supported.");
324
325 if(!ImplementationDetails::readData(*am,cellName.c_str(),"Nodes",cells))
326 throw std::runtime_error(ImplementationDetails::exceptionMessage("readGrid(std::string const&, std::vector<int>&, int)", cellName, "Nodes", __LINE__));
327
328 // read boundary segments if defined
329 bool boundaryExists = ImplementationDetails::readData(*am,"BoundaryTriangles","Nodes",boundary);
330 if (boundaryIds && !boundaryExists)
331 throw Kaskade::LookupException("No boundary triangle nodes found in AmiraMesh file.",__FILE__,__LINE__);
332
333 std::vector<Dune::FieldVector<int,1>> boundaryID;
334 if (boundaryIds)
335 {
336 bool exists;
338 std::vector<Dune::FieldVector<unsigned char,1>> boundaryIDchar;
339 exists = ImplementationDetails::readData(*am,"BoundaryTriangles","Id",boundaryIDchar);
340 if (exists)
341 {
342 std::transform(begin(boundaryIDchar),end(boundaryIDchar),back_inserter(boundaryID),
343 [](auto id) { return Dune::FieldVector<int,1>(id[0]); });
344 }
345 }
346 else
347 exists = ImplementationDetails::readData(*am,"BoundaryTriangles","Id",boundaryID);
348
349 if(!exists)
350 throw Kaskade::LookupException("No boundary triangle ids found in AmiraMesh file [neither of type char nor int].",__FILE__,__LINE__);
351 }
352
353 // Look for length scale parameter.
354 if (auto* unitLength = am->parameters.find("UnitLength"))
355 {
356 scale = unitLength->getReal();
357 std::cout << "Found unit length of " << scale << "m.\n";
358 if (scale <= 0)
359 throw Kaskade::FileIOException("Nonpositive unit length specified.",gridfile,__FILE__,__LINE__);
360 }
361
362
363 // We use start indices 0. Amira uses 1. Correct indices.
364 for (size_t i=0; i<cells.size(); ++i)
365 {
366 for (int j=0; j<dim+1; ++j)
367 {
368 cells[i][j] -= 1;
369 if (cells[i][j]>=vertices.size())
370 {
371 std::string message = std::string("In ") + __FILE__ + " line " + boost::lexical_cast<std::string>(__LINE__) + ": cell node " + boost::lexical_cast<std::string>(i) + "[" + boost::lexical_cast<std::string>(j) + "]=" + boost::lexical_cast<std::string>(cells[i][j]) + " exceeds vertex numbers!\n";
372 throw std::runtime_error(message);
373 }
374 }
375 }
376
377 if (boundaryExists)
378 {
379 for (size_t i=0; i<boundary.size(); ++i)
380 for (int j=0; j<dim; ++j)
381 boundary[i][j] -= 1;
382 }
383
384
385 // Create grid.
386 Dune::GridFactory<Grid> factory = IOTools::FactoryGenerator<Grid>::createFactory(initialGridSize);
387 std::cout << "inserting vertices...";
388 for (size_t i=0; i<vertices.size(); ++i)
389 {
391 for(int j=0; j<dim; ++j)
392 pos[j] = scale*(double)vertices[i][j];
393 factory.insertVertex(deformation(pos)); // apply deformation to each vertex
394 }
395 std::cout << "done. ";
396
397 if (boundaryExists && boundaryIds)
398 {
399 std::cout << "inserting boundary segments...";
400 for(size_t i=0; i<boundary.size(); ++i){
401 std::vector<unsigned int> tmp(dim);
402 for(size_t j=0; j<dim; ++j){
403 assert(boundary[i][j]>=0 && boundary[i][j]<vertices.size());
404 tmp[j] = boundary[i][j];
405 }
406 factory.insertBoundarySegment(tmp);
407 }
408 std::cout << "done. ";
409 }
410
411 std::cout << "inserting elements...";
412 for (size_t i=0; i<cells.size(); ++i) {
413 std::vector<unsigned int> tmp(dim+1);
414 for (int j=0; j<dim+1; ++j) {
415 assert(cells[i][j]>=0 && cells[i][j]<vertices.size());
416 tmp[j] = cells[i][j];
417 }
418 factory.insertElement(Dune::GeometryType(Dune::GeometryType::simplex,dim),tmp);
419 }
420 std::cout << "done. " << std::endl;
421
422 boost::timer::cpu_timer timer;
423 std::unique_ptr<Grid> grid(factory.createGrid());
424 std::cout << "grid creation finished in " << boost::timer::format(timer.elapsed()) << std::endl;
425
426 if (boundaryIds) {
427 // get boundary segment indices
428 std::cout << "sorting boundary ids...";
429 IOTools::BoundarySegmentIndexWrapper<Grid>::readBoundarySegmentIndices(*grid, factory, vertices, boundary, boundaryID, *boundaryIds);
430 std::cout << "done." << std::endl;
431 }
432
433 if (edgeDisplacement)
434 ImplementationDetails::readEdgePositions<Scalar>(*grid, factory, *am, *edgeDisplacement);
435
436 return grid;
437 }
438
439
441
466 template<class Grid, class Scalar, class ScalarEd = Scalar>
467 std::unique_ptr<Grid> mergeGrids(std::string const& gridfile1, std::string const& gridfile2,
468 int initialGridSize = 0,
469 std::vector<int>* boundaryIds = nullptr,
470 // std::vector<Dune::FieldVector<ScalarEd, Grid::dimension>>* edgeDisplacement = nullptr,
471 double scale1 = 1.0, double scale2 = 1.0)
472 {
473 int const dim = Grid::dimension;
474 std::vector<Dune::FieldVector<Scalar,dim>> vertices1, vertices2;
475 std::vector<Dune::FieldVector<int,dim+1>> cells1, cells2;
476 std::vector<Dune::FieldVector<int,dim>> boundary1, boundary2;
477
478 // open and read the two files grid file.
479 std::cout << "Reading first amira mesh\n";
480 std::cout << "opening " << gridfile1 << '\n';
481 std::unique_ptr<AmiraMesh> am1(AmiraMesh::read(gridfile1.c_str()));
482 if(!am1)
483 throw DetailedException(ImplementationDetails::exceptionMessage("readGrid(std::string const&, std::vector<int>&, int)", gridfile1, __LINE__),__FILE__,__LINE__);
484 std::cout << "Reading second amira mesh\n";
485 std::cout << "opening " << gridfile2 << '\n';
486 std::unique_ptr<AmiraMesh> am2(AmiraMesh::read(gridfile2.c_str()));
487 if(!am2)
488 throw DetailedException(ImplementationDetails::exceptionMessage("readGrid(std::string const&, std::vector<int>&, int)", gridfile2, __LINE__),__FILE__,__LINE__);
489
490 // read vertices in both Amira files
491 // and store in vertices1 and vertices2
492 if(!ImplementationDetails::readData(*am1,"Nodes","Coordinates",vertices1))
493 throw std::runtime_error(ImplementationDetails::exceptionMessage("readGrid(std::string const&, std::vector<int>&, int)", "Nodes", "Coordinates", __LINE__));
494 if(!ImplementationDetails::readData(*am2,"Nodes","Coordinates",vertices2))
495 throw std::runtime_error(ImplementationDetails::exceptionMessage("readGrid(std::string const&, std::vector<int>&, int)", "Nodes", "Coordinates", __LINE__));
496
497 // read cells in both Amira files
498 // and store in cells1 and cells2
499 std::string cellName;
500 if(dim == 2) cellName = "Triangles";
501 if(dim == 3) cellName = "Tetrahedra";
502 if(dim != 2 && dim != 3)
503 throw std::runtime_error("Sorry!\nOnly 2D and 3D grids are supported.");
504
505 if(!ImplementationDetails::readData(*am1,cellName.c_str(),"Nodes",cells1))
506 throw std::runtime_error(ImplementationDetails::exceptionMessage("readGrid(std::string const&, std::vector<int>&, int)", cellName, "Nodes", __LINE__));
507 if(!ImplementationDetails::readData(*am2,cellName.c_str(),"Nodes",cells2))
508 throw std::runtime_error(ImplementationDetails::exceptionMessage("readGrid(std::string const&, std::vector<int>&, int)", cellName, "Nodes", __LINE__));
509
510
511 // read boundary segments if defined
512 bool boundaryExists1 = ImplementationDetails::readData(*am1,"BoundaryTriangles","Nodes",boundary1);
513 if(boundaryIds && !boundaryExists1)
514 throw Kaskade::LookupException("No boundary triangle nodes found in first AmiraMesh file.",__FILE__,__LINE__);
515 bool boundaryExists2 = ImplementationDetails::readData(*am2,"BoundaryTriangles","Nodes",boundary2);
516 if(boundaryIds && !boundaryExists2)
517 throw Kaskade::LookupException("No boundary triangle nodes found in second AmiraMesh file.",__FILE__,__LINE__);
518
519 // std::vector<Dune::FieldVector<int,1>> boundaryID;
520 // if (boundaryIds)
521 // {
522 // bool exists;
523 // if(ImplementationDetails::boundaryIdByByte(gridfile)) {
524 // std::vector<Dune::FieldVector<unsigned char,1>> boundaryIDchar;
525 // exists = ImplementationDetails::readData(*am,"BoundaryTriangles","Id",boundaryIDchar);
526 // if (exists)
527 // {
528 // std::transform(begin(boundaryIDchar),end(boundaryIDchar),back_inserter(boundaryID),
529 // [](auto id) { return Dune::FieldVector<int,1>(id[0]); });
530 // }
531 // }
532 // else
533 // exists = ImplementationDetails::readData(*am,"BoundaryTriangles","Id",boundaryID);
534
535 // if(!exists)
536 // throw Kaskade::LookupException("No boundary triangle ids found in AmiraMesh file [neither of type char nor int].",__FILE__,__LINE__);
537 // }
538
539 // Look for length scale parameter in both files.
540 if (auto* unitLength = am1->parameters.find("UnitLength"))
541 {
542 scale1 = unitLength->getReal();
543 std::cout << "Found unit length of " << scale1 << "m in first Amira file.\n";
544 if (scale1 <= 0)
545 throw Kaskade::FileIOException("Nonpositive unit length specified.",gridfile1,__FILE__,__LINE__);
546 }
547 if (auto* unitLength = am2->parameters.find("UnitLength"))
548 {
549 scale2 = unitLength->getReal();
550 std::cout << "Found unit length of " << scale2 << "m in second Amira file.\n";
551 if (scale2 <= 0)
552 throw Kaskade::FileIOException("Nonpositive unit length specified.",gridfile2,__FILE__,__LINE__);
553 }
554
555
556 // We use start indices 0. Amira uses 1. Correct indices.
557 for (size_t i=0; i<cells1.size(); ++i)
558 {
559 for (int j=0; j<dim+1; ++j)
560 {
561 cells1[i][j] -= 1;
562 if (cells1[i][j]>=vertices1.size())
563 {
564 std::string message = std::string("In ") + __FILE__ + " line " + boost::lexical_cast<std::string>(__LINE__) + ": cell node " + boost::lexical_cast<std::string>(i) + "[" + boost::lexical_cast<std::string>(j) + "]=" + boost::lexical_cast<std::string>(cells1[i][j]) + " exceeds vertex numbers!\n";
565 throw std::runtime_error(message);
566 }
567 }
568 }
569 for (size_t i=0; i<cells2.size(); ++i)
570 {
571 for (int j=0; j<dim+1; ++j)
572 {
573 cells2[i][j] -= 1;
574 if (cells2[i][j]>=vertices2.size())
575 {
576 std::string message = std::string("In ") + __FILE__ + " line " + boost::lexical_cast<std::string>(__LINE__) + ": cell node " + boost::lexical_cast<std::string>(i) + "[" + boost::lexical_cast<std::string>(j) + "]=" + boost::lexical_cast<std::string>(cells2[i][j]) + " exceeds vertex numbers!\n";
577 throw std::runtime_error(message);
578 }
579 }
580 }
581
582 // if (boundaryExists)
583 // {
584 // for (size_t i=0; i<boundary.size(); ++i)
585 // for (int j=0; j<dim; ++j)
586 // boundary[i][j] -= 1;
587 // }
588
589
590 // Create grid.
591 std::cout << std::endl;
592 std::cout << "preparing grid creation\n";
593
594 Dune::GridFactory<Grid> factory = IOTools::FactoryGenerator<Grid>::createFactory(initialGridSize);
595 std::cout << "inserting vertices of first mesh...";
596 for (size_t i=0; i<vertices1.size(); ++i)
597 {
599 for(int j=0; j<dim; ++j)
600 pos[j] = scale1*(double)vertices1[i][j];
601 factory.insertVertex(pos);
602 }
603 std::cout << "done.\n";
604 std::cout << "inserting vertices of second mesh...";
605 for (size_t i=0; i<vertices2.size(); ++i)
606 {
608 for(int j=0; j<dim; ++j)
609 pos[j] = scale2*(double)vertices2[i][j];
610 factory.insertVertex(pos);
611 }
612 std::cout << "done." << std::endl;
613
614 // if (boundaryExists && boundaryIds)
615 // {
616 // std::cout << "inserting boundary segments...";
617 // for(size_t i=0; i<boundary.size(); ++i){
618 // std::vector<unsigned int> tmp(dim);
619 // for(size_t j=0; j<dim; ++j){
620 // assert(boundary[i][j]>=0 && boundary[i][j]<vertices.size());
621 // tmp[j] = boundary[i][j];
622 // }
623 // factory.insertBoundarySegment(tmp);
624 // }
625 // std::cout << "done." << std::endl;
626 // }
627
628 std::cout << "inserting elements of first mesh...";
629 for (size_t i=0; i<cells1.size(); ++i) {
630 std::vector<unsigned int> tmp(dim+1);
631 for (int j=0; j<dim+1; ++j) {
632 assert(cells1[i][j]>=0 && cells1[i][j]<vertices1.size());
633 tmp[j] = cells1[i][j];
634 }
635 factory.insertElement(Dune::GeometryType(Dune::GeometryType::simplex,dim),tmp);
636 }
637 std::cout << "done.\n";
638 std::cout << "inserting elements of second mesh...";
639 for (size_t i=0; i<cells2.size(); ++i) {
640 std::vector<unsigned int> tmp(dim+1);
641 for (int j=0; j<dim+1; ++j) {
642 assert(cells2[i][j]>=0 && cells2[i][j]<vertices2.size());
643 tmp[j] = cells2[i][j] + vertices1.size(); // shift indices by number of vertices of the first mesh
644 }
645 factory.insertElement(Dune::GeometryType(Dune::GeometryType::simplex,dim),tmp);
646 }
647 std::cout << "done." << std::endl;
648
649 boost::timer::cpu_timer timer;
650 std::unique_ptr<Grid> grid(factory.createGrid());
651 std::cout << "grid creation finished in " << boost::timer::format(timer.elapsed()) << std::endl;
652
653 // if (boundaryIds) {
654 // // get boundary segment indices
655 // std::cout << "sorting boundary ids...";
656 // IOTools::BoundarySegmentIndexWrapper<Grid>::readBoundarySegmentIndices(*grid, factory, vertices, boundary, boundaryID, *boundaryIds);
657 // std::cout << "done." << std::endl;
658 // }
659
660 // if (edgeDisplacement)
661 // ImplementationDetails::readEdgePositions<Scalar>(*grid, factory, *am, *edgeDisplacement);
662
663 return grid;
664 }
665
666
667
669
677 template<class DataType, class FunctionSpaceElement>
678 void readData(std::string const& datafile, std::string const& dataname, std::string const& componentname,
679 FunctionSpaceElement& data, bool verbose=false)
680 {
681 constexpr int numberOfComponents = FunctionSpaceElement::StorageValueType::dimension;
682 // FunctionSpaceElement::StorageValueType in general uses floating point precision.
683 // Thus, in order to read integer values or characters, the data vector is defined manually.
684 // When reading the information into the function space element the data is
685 // casted to the desired type.
686 std::vector<Dune::FieldVector<DataType, numberOfComponents>> dataVector;
687
688 // open data file
689 std::cout << "Reading additional data." << std::endl;
690 std::cout << "Opening " << datafile << " ...\n";
691 std::unique_ptr<AmiraMesh> am(AmiraMesh::read(datafile.c_str()));
692
693 if(!am)
694 throw FileIOException("could not open Amira mesh file for reading",datafile,__FILE__,__LINE__);
695
696
697 bool exists = ImplementationDetails::readData(*am, dataname.c_str(), componentname.c_str(), dataVector);
698 if(!exists)
699 throw LookupException("data " + componentname + " not found at location " + dataname + " in Amira mesh file " + datafile,
700 __FILE__,__LINE__);
701
702 if(verbose)
703 {
704 std::cout << "number of entries: " << dataVector.size() << std::endl;
705 std::cout << "number of components: " << numberOfComponents << std::endl;
706 std::cout << "data object: " << data.coefficients().size() << "x" << data.coefficients()[0].size() << std::endl;
707 }
708
709 // reading prescribed data into function space element
710 for(size_t i=0; i<dataVector.size(); ++i)
711 for(size_t j=0; j<numberOfComponents; ++j)
712 data.coefficients()[i][j] = static_cast<typename FunctionSpaceElement::Scalar>(dataVector[i][j]);
713
714 std::cout << "\n";
715 }
716
718
726 template<class Scalar, int numberOfComponents>
727 void readData(std::string const& datafile, std::string const& dataname, std::string const& componentname,
729 {
730 // open data file
731 std::cout << std::endl;
732 std::cout << "Reading additional vertex data" << std::endl;
733 std::cout << "opening " << datafile << std::endl;
734 AmiraMesh* am = AmiraMesh::read(datafile.c_str());
735 if(!am)
736 throw std::runtime_error(ImplementationDetails::exceptionMessage("readData(std::string const&, std::string const&, std::string const&, std::vector<Dune::FieldVector>&)", datafile, __LINE__));
737
738 bool exists = ImplementationDetails::readData(*am, dataname.c_str(), componentname.c_str(), data);
739 if(!exists)
740 {
741 delete(am);
742 throw std::runtime_error(ImplementationDetails::exceptionMessage("readData(std::string const&, std::string const&, std::string const&, std::vector<Dune::FieldVector>&)", dataname, componentname, __LINE__));
743 }
744
745 // close data file
746 delete(am);
747 }
748
750
760 template <class VarSetDesc>
761 void readDeformationIntoVariableSetRepresentation(std::string const& gridfile, std::string const& datafile,
762 typename VarSetDesc::VariableSet& data){
763 using namespace boost::fusion;
764 int const numberOfComponents = result_of::at_c<typename VarSetDesc::VariableSet::Functions, 0>::type::Components;
765 typedef std::vector<Dune::FieldVector<float,numberOfComponents> > DataVector;
766 std::vector<Dune::FieldVector<float,numberOfComponents> > vertices;
767 DataVector nodeData;
768
769 // open grid file.
770 std::cout << "Reading undeformed geometry\n";
771 std::cout << "opening " << gridfile << '\n';
772 AmiraMesh* am = AmiraMesh::read(gridfile.c_str());
773 if(!am) throw std::runtime_error(ImplementationDetails::exceptionMessage("readDeformationIntoVariableSetRepresentation(std::string const&, std::string const&, VariableSet::VariableSet&)", gridfile, __LINE__));
774
775 // read vertices
776 bool exists = ImplementationDetails::readData(*am,"Nodes","Coordinates",vertices);
777 if(!exists){
778 delete(am);
779 throw std::runtime_error(ImplementationDetails::exceptionMessage("readDeformationIntoVariableSetRepresentation(std::string const&, std::string const&, VariableSet::VariableSet&)","Nodes","Coordinates",__LINE__));
780 }
781
782 // close grid file
783 delete(am);
784
785 // open data file
786 std::cout << std::endl;
787 std::cout << "Reading deformed geometry" << std::endl;
788 std::cout << "opening " << datafile << std::endl;
789 am = AmiraMesh::read(datafile.c_str());
790 if(!am) throw std::runtime_error(ImplementationDetails::exceptionMessage("readDeformationIntoVariableSetRepresentation(std::string const&, std::string const&, VariableSet::VariableSet&)", datafile, __LINE__));
791
792 exists = ImplementationDetails::readData(*am,"Nodes","Coordinates",nodeData);
793 if(!exists){
794 delete(am);
795 throw std::runtime_error("readDeformationIntoVariableSetRepresentation(std::string const&, std::string const&, VariableSet::VariableSet&)", "Nodes", "Coordinates", __LINE__);
796 }
797
798 // close data file
799 delete(am);
800
801 // check for correct sizes
802 assert(nodeData.size()==vertices.size());
803
804 // get deformation
805 for(size_t i=0; i<nodeData.size(); ++i)
806 nodeData[i]=nodeData[i]-vertices[i];
807
808 // reading prescribed data into function space
809 std::vector<double> tmpVec(nodeData.size()*numberOfComponents);
810 for(size_t i=0; i<nodeData.size(); ++i)
811 for(size_t j=0; j<numberOfComponents; ++j)
812 tmpVec[numberOfComponents*i+j] = (double)nodeData[i][j];
813
814 data.read(tmpVec.begin());
815 }
816
818
828 template<class FunctionSpaceElement, class FileScalar=float>
829 void readDeformation(std::string const& gridfile, std::string const& datafile, FunctionSpaceElement &data) {
830 int const numberOfComponents = FunctionSpaceElement::Components;
831 typedef std::vector<Dune::FieldVector<FileScalar,numberOfComponents> > DataVector;
832 typedef typename FunctionSpaceElement::Scalar Scalar;
833 std::vector<Dune::FieldVector<FileScalar,numberOfComponents> > vertices;
834 DataVector nodeData;
835
836 // open grid file.
837 std::cout << "Reading undeformed geometry\n";
838 std::cout << "opening " << gridfile << '\n';
839 AmiraMesh* am = AmiraMesh::read(gridfile.c_str());
840 if(!am) throw std::runtime_error(ImplementationDetails::exceptionMessage("readDeformation(std::string const&, std::string const&, FunctionSpaceElement&)", gridfile, __LINE__));
841
842 // read vertices
843 bool exists = ImplementationDetails::readData(*am,"Nodes","Coordinates",vertices);
844 if(!exists){
845 delete(am);
846 throw std::runtime_error(ImplementationDetails::exceptionMessage("readDeformation(std::string const&, std::string const&, FunctionSpaceElement&)", "Nodes", "Coordinates", __LINE__));
847 }
848
849 // close grid file
850 delete(am);
851
852 // open data file
853 std::cout << std::endl;
854 std::cout << "Reading deformed geometry" << std::endl;
855 std::cout << "opening " << datafile << std::endl;
856 am = AmiraMesh::read(datafile.c_str());
857 if(!am) throw std::runtime_error(ImplementationDetails::exceptionMessage("readDeformation(std::string const&, std::string const&, FunctionSpaceElement&)", datafile, __LINE__));
858
859 exists = ImplementationDetails::readData(*am,"Nodes","Coordinates",nodeData);
860 if(!exists){
861 delete(am);
862 throw std::runtime_error(ImplementationDetails::exceptionMessage("readDeformation(std::string const&, std::string const&, FunctionSpaceElement&)", "Nodes", "Coordinates", __LINE__));
863 }
864
865 // close data file
866 delete(am);
867
868 // check for correct sizes
869 assert(nodeData.size()==vertices.size());
870
871 // get deformation
872 for(size_t i=0; i<nodeData.size(); ++i)
873 nodeData[i]=nodeData[i]-vertices[i];
874
875 // reading prescribed data into function space
876 std::vector<Scalar> tmpVec(nodeData.size()*numberOfComponents);
877 for(size_t i=0; i<nodeData.size(); ++i)
878 for(size_t j=0; j<FunctionSpaceElement::Components; ++j)
879 data.coefficients()[i][j] = (Scalar) nodeData[i][j];
880 }
881
882
883 template<class GridView, class FunctionSpaceElement, class FileScalar=float>
884 void readDeformation2(GridView const& gridView, std::string const& datafile, FunctionSpaceElement &data){
885 int const numberOfComponents = FunctionSpaceElement::Components;
886 typedef std::vector<Dune::FieldVector<FileScalar,numberOfComponents> > DataVector;
887 typedef typename FunctionSpaceElement::Scalar Scalar;
888 std::vector<Dune::FieldVector<FileScalar,numberOfComponents> > vertices;
889 DataVector nodeData;
890
891 // open data file
892 std::cout << "Reading deformed geometry" << std::endl;
893 std::cout << "opening " << datafile << std::endl;
894 AmiraMesh *am = AmiraMesh::read(datafile.c_str());
895 if(!am) throw std::runtime_error(ImplementationDetails::exceptionMessage("readDeformation(std::string const&, std::string const&, FunctionSpaceElement&)", datafile, __LINE__));
896
897 bool exists = ImplementationDetails::readData(*am,"Nodes","Coordinates",nodeData);
898 if(!exists){
899 delete(am);
900 throw std::runtime_error(ImplementationDetails::exceptionMessage("readDeformation(std::string const&, std::string const&, FunctionSpaceElement&)", "Nodes", "Coordinates", __LINE__));
901 }
902
903 // close data file
904 delete(am);
905
906 // check for correct sizes
907 assert(nodeData.size()==vertices.size());
908
909 // get deformation
910 auto vIter = gridView.template begin<GridView::dimension>();
911 auto vend = gridView.template end<GridView::dimension>();
912 size_t i=0;
913 for(;vIter!=vend;++vIter)
914 {
915 nodeData[i] -= vIter->geometry().corner(0);
916 ++i;
917 }
918 // for(size_t i=0; i<nodeData.size(); ++i)
919// nodeData[i]=nodeData[i]-vertices[i];
920
921 // reading prescribed data into function space
922 std::vector<Scalar> tmpVec(nodeData.size()*numberOfComponents);
923 for(size_t i=0; i<nodeData.size(); ++i)
924 for(size_t j=0; j<FunctionSpaceElement::Components; ++j)
925 data.coefficients()[i][j] = (Scalar) nodeData[i][j];
926 }
927
928
930
935 template <class Grid>
936 void boundaryConditionsToScalarField(std::string const& gridfile, std::string const& savefilename=std::string("boundaryConditions"), int initialGridSize = 0) {
937
938 int const dim = Grid::dimension;
939 // read grid
940 typedef typename Grid::LeafGridView LeafView;
941 std::vector<int> boundaryIndices;
942 std::unique_ptr<Grid> grid = readGrid<Grid,float>(gridfile, boundaryIndices);
943 GridManager<Grid> gridManager(grid);
944
945 // create variable set
947 Space space(gridManager, gridManager.grid().leafGridView(), 1);
948 typedef boost::fusion::vector<Space const*> Spaces;
949 Spaces spaces(&space);
950 typedef boost::fusion::vector< VariableDescription<0,1,0> > VariableDescriptions;
952 std::string name[1] = { "boundary ids" };
953 VarSetDesc varSetDesc(spaces, name);
954 typename VarSetDesc::VariableSet indices(varSetDesc);
955
956 // read boundary indices
957 std::vector<Dune::FieldVector<int,dim> > boundaryVertices;
958
959 std::string const comp_name("BoundaryTriangles");
960 std::string const node_name("Nodes");
961
962 ImplementationDetails::readData<int,dim>(gridfile, comp_name, node_name, boundaryVertices);
963 std::vector<double> tmp(gridManager.grid().size(dim),0);
964 for(int i=0; i<boundaryIndices.size(); ++i){
965 tmp[boundaryVertices[i][0]-1] = boundaryIndices[i];
966 tmp[boundaryVertices[i][1]-1] = boundaryIndices[i];
967 tmp[boundaryVertices[i][2]-1] = boundaryIndices[i];
968 }
969 indices.read(tmp.begin());
970
971 // write file
972 IoOptions options;
974 writeVTKFile(gridManager.grid().leafGridView(), varSetDesc, indices, savefilename,options);
975 }
976 }
977} // namespace Kaskade
978#endif
A wrapper class for conveniently providing exceptions with context information.
A representation of a finite element function space defined over a domain covered by a grid.
An exception class for file IO errors.
A class for representing finite element functions.
StorageType const & coefficients() const
Provides read-only access to the coefficients of the finite element basis functions.
Space::Scalar Scalar
scalar field type
Grid const & grid() const
Returns a const reference on the owned grid.
Definition: gridmanager.hh:292
An exception that can be thrown whenever a key lookup fails.
A class that stores information about a set of variables.
Definition: variables.hh:537
Lagrange Finite Elements.
bool boundaryIdByByte(std::string const &gridFile)
std::string exceptionMessage(std::string const &function, std::string const &gridfile, int line)
bool readData(AmiraMesh &am, char const *location, char const *name, std::vector< Dune::FieldVector< value_type, components > > &out, bool verbose=false)
void extractData(size_t const n, Source const *source, std::vector< Dune::FieldVector< value_type, components > > &data, bool verbose=false)
void readEdgePositions(Grid const &grid, Dune::GridFactory< Grid > const &factory, AmiraMesh &am, std::vector< Dune::FieldVector< ScalarEd, Grid::dimension > > &edgeDisplacement)
std::unique_ptr< Grid > readGrid(std::string const &gridfile, int initialGridSize=0, std::vector< int > *boundaryIds=nullptr, std::vector< Dune::FieldVector< ScalarEd, Grid::dimension > > *edgeDisplacement=nullptr, double scale=1.0)
function reading an Amira mesh file in ASCII format.
void readDeformation(std::string const &gridfile, std::string const &datafile, FunctionSpaceElement &data)
function reading return a fe-function describing the deformation.
void boundaryConditionsToScalarField(std::string const &gridfile, std::string const &savefilename=std::string("boundaryConditions"), int initialGridSize=0)
Read boundary indices and save as scalar field in .vtu-file.
std::unique_ptr< Grid > mergeGrids(std::string const &gridfile1, std::string const &gridfile2, int initialGridSize=0, std::vector< int > *boundaryIds=nullptr, double scale1=1.0, double scale2=1.0)
function joining two Amira mesh files in ASCII format into one grid.
void readData(std::string const &datafile, std::string const &dataname, std::string const &componentname, FunctionSpaceElement &data, bool verbose=false)
function reading additional data from an Amira mesh file in ASCII format.
void readDeformationIntoVariableSetRepresentation(std::string const &gridfile, std::string const &datafile, typename VarSetDesc::VariableSet &data)
function reading return a FE-function describing the deformation.
void readDeformation2(GridView const &gridView, std::string const &datafile, FunctionSpaceElement &data)
auto & component(LinearProductSpace< Scalar, Sequence > &x)
Definition: linearspace.hh:463
options for VTK/AMIRA output
Definition: iobase.hh:77
OutputType outputType
Definition: iobase.hh:149
Output of mesh and solution for visualization software.