KASKADE 7 development version
marcwriter.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) 2020-2021 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 MARCWRITER_HH
14#define MARCWRITER_HH
15
16#include <algorithm>
17#include <cassert>
18#include <cstdio>
19#include <fstream>
20#include <map>
21
23
24namespace Kaskade
25{
26
28 namespace MarcWriterDetail
29 {
30
31 int marcElementIdFromGeometryType(Dune::GeometryType gt)
32 {
33 // These are listed in Marc Volume B as "heat conduction elements"
34 if (gt.isTriangle()) return 37;
35 if (gt.isTetrahedron()) return 135;
36 throw LookupException("Unhandled cell type encountered in Marc output.",__FILE__,__LINE__);
37 return 0;
38 }
39
40 // MARC wants floating point numbers as -1.234+5, i.e. without the usual 'e' denoting the
41 // exponent.
42 std::string marcFloatNumber(double x)
43 {
44 int const n = 50;
45 char buf[n];
46 std::snprintf(buf,n,"%E",x);
47// std::remove(buf,buf+n,'e');
48 return std::string(buf);
49 }
50 }
52
68 template <class Material>
69 void writeMarc(Material const& material, std::string const& filename, double const scale=1.0, IoOptions options=IoOptions())
70 {
71 using namespace MarcWriterDetail;
72
73 // open file
74 std::ofstream out(filename+".marc");
75 if (!out)
76 throw FileIOException("File " + filename + ".marc could not be opened for writing Marc output.",
77 filename+".marc",__FILE__,__LINE__);
78
79
80 using GridView = typename Material::GridView;
81 auto const& gridView = material.space().gridView();
82 auto const& is = gridView.indexSet();
83 constexpr int dim = GridView::dimension;
84 constexpr int dimworld = GridView::dimensionworld;
85
86 int const nCells = gridView.size(0);
87 int const nVertices = gridView.size(dim);
88
89 // Make sure the material function is piecewise constant and scalar
90 assert(material.space().mapper().maxOrder()==0);
91 static_assert(Material::components==1);
92 assert(material.dim()==nCells);
93
94
95 // Get the geometry (of first cell, which must coincide with all other cells)
96 Dune::GeometryType gt = gridView.template begin<0>()->geometry().type();
97 if (gridView.size(gt) != nCells)
98 throw GridException("Marc output implemented for grids with a single cell geometry type only.",
99 __FILE__,__LINE__);
100
101 int elementId = marcElementIdFromGeometryType(gt);
102
103 // Marc requires floating point data to be formatted as float.
104 out << std::scientific << std::setprecision(10);
105
106 // Marc input is organized in three groups: parameter data, model definition data,
107 // and history definition data. First write parameter data.
108
109 out << "TITLE " << "Kaskade 7 output file " << filename << "\n";
110 out << "EXTENDED\n"; // necessary for long float mantissa
111 out << "ELEMENTS," << elementId << ",\n"; // number of grid cells
112 out << "SIZING\n";
113 out << "VERSION, 15, 1, 0, 1\n"; // necessary for correct interpretation by MARC
114 out << "HEAT, 0, 0, 1, 0, 1, 1\n"; // necessary for interpretation as heat problem (not mechanics)
115 out << "END\n";
116
117
118 // Next gather cells by their material id.
119 std::map<int,std::vector<std::vector<int>>> id;
120 for (auto const& cell: Dune::elements(gridView))
121 {
122 int cellIdx = is.index(cell);
123 std::vector<int> c;
124 c.push_back(cellIdx+1);
125 for (int i=0; i<cell.subEntities(dim); ++i)
126 c.push_back(is.index(cell.template subEntity<dim>(i))+1);
127
128 int idi = static_cast<int>(std::round(material.coefficients()[cellIdx]));
129 id[idi].push_back(c);
130 }
131
132
133 // Next the model definition data. First the grid topology, with one "CONNECTIVITY" section
134 // per material id. Marc appears not to accept arbitrary material ids, only contiguous numbers
135 // starting at 1. We therefore skip the material id and count the number up.
136 int materialNumber = 1;
137 for (auto const& [_,cs]: id)
138 {
139 out << "CONNECTIVITY\n";
140 out << "0, 0, 1, 0, 0, " << materialNumber << ", \n"; // this encodes the material id of subsequent cells
141 for (auto const& c: cs)
142 {
143 out << c[0] << ", " << elementId;
144 for (int i=1; i<c.size(); ++i)
145 out << ", " << c[i];
146 out << "\n";
147 }
148 ++materialNumber;
149 }
150
151 // Write out vertex coordinates
152 out << "COORDINATES\n";
153 out << dimworld << ", " << nVertices << "\n";
154 for (auto const& v: Dune::entities(gridView,Dune::Codim<dim>()))
155 {
156 out << is.index(v)+1;
157 auto x = v.geometry().center();
158 for (int i=0; i<dimworld; ++i)
159 out << ", " << marcFloatNumber(scale*x[i]);
160 out << "\n";
161 }
162
163 // Then write out dummy (thermal) material properties for each material.
164 // The odd blank lines in the output appear to be necessary for MARC not to choke.
165 for (int i=1; i<=size(id); ++i)
166 out << "ISOTROPIC\n\n"
167 << i << ", 0, 0, 0, 0, mati" << i << "\n"
168 << "8.00000-2, 1.00000+3, 4.70000+2, 0.00000+0, 9.00000-1, 0.00000+0, 0.00000+0\n\n";
169
170
171 out << "END OPTION\n";
172
173 }
174
175}
176
177#endif
An exception class for file IO errors.
An exception class for grid related errors.
constexpr StaticIndexRange< 0, std::numeric_limits< int >::max()> _
Convenience static range denoting the full available range, analogous to Matlab's :.
Definition: tensor.hh:74
void writeMarc(Material const &material, std::string const &filename, double const scale=1.0, IoOptions options=IoOptions())
Writes grid and material IDs given as FE function to a Marc input file.
Definition: marcwriter.hh:69
options for VTK/AMIRA output
Definition: iobase.hh:77