Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Main/MeshConvDriver.cpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.,
7 : : 2022-2024 J. Bakosi
8 : : All rights reserved. See the LICENSE file for details.
9 : : \brief Mesh converter driver
10 : : */
11 : : // *****************************************************************************
12 : :
13 : : #include "Types.hpp"
14 : : #include "MeshConvDriver.hpp"
15 : : #include "MeshFactory.hpp"
16 : : #include "ProcessException.hpp"
17 : : #include "MeshConvConfig.hpp"
18 : :
19 : : #include "NoWarning/meshconv.decl.h"
20 : :
21 : : using meshconv::MeshConvDriver;
22 : :
23 : : extern CProxy_Main mainProxy;
24 : :
25 : : void
26 [ + - ]: 20 : MeshConvDriver::convert( const std::string& inf,
27 : : const std::string& outf,
28 : : bool reorder ) const
29 : : // *****************************************************************************
30 : : // Execute: Convert mesh file
31 : : //! \param[in] inf Input file
32 : : //! \param[in] outf Output file
33 : : //! \param[in] reorder True to also reorder mesh nodes
34 : : // *****************************************************************************
35 : : {
36 : : std::vector< std::pair< std::string, tk::real > > times;
37 : :
38 : : tk::Print print;
39 : :
40 [ + - ][ + - ]: 20 : print.section( "Converting mesh" );
41 : :
42 : : // If input filename contains a '%', we aggregate multiple files
43 [ + + ]: 20 : if (inf.find('%') == std::string::npos) {
44 : :
45 : : // Convert single mesh
46 [ + - ]: 18 : times.push_back( {} );
47 [ + - ]: 18 : auto mesh = tk::readUnsMesh( print, inf, times[0] );
48 [ + - ]: 18 : auto wtimes = tk::writeUnsMesh( print, outf, mesh, reorder );
49 [ + - ]: 18 : times.insert( end(times), begin(wtimes), end(wtimes) );
50 : :
51 : 18 : } else {
52 : :
53 : : // Aggregate multiple meshes containing surface output
54 : :
55 : : // Find a '%' sign in the input filename, and assuming a syntax of
56 : : // '.<nfile>.%', find '<nfile>' as the number of files to aggregate.
57 : 2 : auto percent_pos = inf.find( '%' );
58 [ + - ]: 2 : auto input_basename = inf.substr( 0, percent_pos );
59 : : auto dot1 = inf.find_last_of( '.', percent_pos );
60 : 2 : auto dot2 = inf.find_last_of( '.', dot1-1 );
61 [ + - ]: 2 : auto nfile_str = inf.substr( dot2+1, dot1-dot2-1 );
62 [ + - ]: 2 : std::stringstream ss( nfile_str );
63 : : std::size_t nfile;
64 : : ss >> nfile;
65 [ + + ][ + - ]: 3 : ErrChk( nfile > 0, "The percent sign must be preceded by an integer, as in "
[ + - ][ + - ]
[ - + ][ - + ]
[ - - ][ - - ]
66 : : "'.<nfile>.%', with <nfile> the number of files to aggregate" );
67 [ + - ]: 1 : print << "Aggregating " + std::to_string(nfile) +
68 [ + - ][ + - ]: 1 : " files from base filename: '" << input_basename << "\'\n";
69 : :
70 : : const auto eps = std::numeric_limits< tk::real >::epsilon();
71 : :
72 : : // Lambda to echo some diagnostics on the mesh being processes to screen
73 : 10 : auto diag = [&]( const std::string& name, const tk::UnsMesh& mesh ){
74 [ + - ][ + - ]: 30 : print << name + ": ntri: " +
[ + - ][ - + ]
[ - - ]
75 [ + - ][ - + ]: 20 : std::to_string(mesh.triinpoel().size()/3) +
[ - - ]
76 [ + - ][ + - ]: 30 : ", ntime: " + std::to_string(mesh.vartimes().size()) +
[ + - ][ - + ]
[ - - ]
77 [ + - ][ - - ]: 10 : (!mesh.nodevars().empty() ? ", nvar: " +
78 [ + - ][ + - ]: 40 : std::to_string(mesh.nodevars()[0].size()) : "") +
[ + - ][ - + ]
[ - - ][ - - ]
79 [ + - ][ - - ]: 10 : (!mesh.nodevars()[0].empty() ? ", npoin: " +
80 [ + - ][ + - ]: 30 : std::to_string(mesh.nodevars()[0][0].size()) : "") << '\n';
[ + - ][ - - ]
81 : 11 : };
82 : :
83 : : // Output-mesh containers, will store aggregated surface(s) and field output
84 : : tk::UnsMesh::Coords coords;
85 : : auto& X = coords[0];
86 : : auto& Y = coords[1];
87 : : auto& Z = coords[2];
88 : 1 : std::size_t npoin = 0;
89 : : std::vector< std::size_t > otriinpoel;
90 : : std::vector< std::string > nodevarnames;
91 : : std::vector< tk::real > vartimes;
92 : : std::vector< std::vector< std::vector< tk::real > > > nodevars;
93 : : // Counter for number of non-empty meshes processed
94 : : std::size_t k = 0;
95 [ + + ]: 31 : for (std::size_t m=0; m<nfile; ++m) {
96 [ + - ][ + - ]: 60 : std::string name = input_basename + std::to_string(m);
[ + - ]
97 [ + - ][ - - ]: 30 : times.push_back( {} );
98 [ + - ]: 30 : auto mesh = tk::readUnsMesh( print, name, times.back() );
99 : : const auto& triinpoel = mesh.triinpoel();
100 : : // Skip meshes with a single triange cell
101 [ + + ]: 30 : if (triinpoel.size() == 3) continue;
102 : : tk::Timer aggrtime;
103 : : const auto& x = mesh.x();
104 : : const auto& y = mesh.y();
105 : : const auto& z = mesh.z();
106 [ + - ]: 9 : nodevarnames = mesh.nodevarnames();
107 [ + - ]: 9 : vartimes = mesh.vartimes();
108 : : // Echo some diagnostics on the mesh being processes to screen
109 [ + - ]: 9 : diag( name, mesh );
110 : : // Aggregate data from each triangle element in mesh
111 [ + + ]: 63693 : for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
112 [ + + ]: 254736 : for (std::size_t n=0; n<3; ++n) {
113 : 191052 : auto j = triinpoel[ e*3+n ];
114 : : bool visited = false;
115 : : // WARNING: linear search below, will not scale well
116 [ + + ]: 3378984362 : for (std::size_t i=0; i<X.size(); ++i) {
117 : : // If mesh point has already been seen (on a previous mesh)
118 [ + + ][ + + ]: 3378793310 : if (std::abs(x[j]-X[i]) < eps &&
119 [ + + ][ + + ]: 3378793310 : std::abs(y[j]-Y[i]) < eps &&
[ + + ]
120 [ + + ]: 10327686 : std::abs(z[j]-Z[i]) < eps)
121 : : { // no point in connectivity but nothing else
122 : : visited = true;
123 [ + - ]: 159179 : otriinpoel.push_back( i );
124 : : }
125 : : }
126 [ + + ]: 191052 : if (!visited) { // Mesh point not yet seen
127 : : // save coordinates and (global) point id in aggregated connectivity
128 [ + - ]: 31873 : X.push_back( x[j] );
129 [ + - ]: 31873 : Y.push_back( y[j] );
130 [ + - ]: 31873 : Z.push_back( z[j] );
131 [ + - ]: 31873 : otriinpoel.push_back( npoin );
132 : : // aggregate nodal field data for all times and variables
133 : : std::size_t time = 0;
134 : : std::size_t varid = 0;
135 [ + + ]: 127492 : for (const auto& t : mesh.nodevars()) { // for all times
136 [ + + ][ + + ]: 95622 : if (k == 0 && npoin == 0) nodevars.push_back( {} );
137 [ + + ]: 669333 : for (const auto& v : t) { // for all variables
138 [ + + ][ + + ]: 573732 : if (k == 0 && npoin == 0) nodevars.back().push_back( {} );
139 [ + - ]: 573714 : nodevars[time][varid].push_back( v[j] );
140 : 573714 : ++varid;
141 : : }
142 : 95619 : ++time;
143 : : varid = 0;
144 : : }
145 : 31873 : ++npoin; // increase number of nodes in output mesh
146 : : }
147 : : }
148 : : }
149 : 9 : ++k; // increase number of non-empty meshes processed
150 [ + - ]: 9 : times.emplace_back(
151 : 18 : "Aggregate surface output from file " + std::to_string(m),
152 [ + - ]: 9 : aggrtime.dsec() );
153 : 30 : }
154 : :
155 : : // Construct aggregated output mesh
156 [ + - ]: 1 : tk::UnsMesh outmesh( coords, otriinpoel, nodevarnames, vartimes, nodevars );
157 : : // Echo diagnostics on the aggreegate output mesh
158 [ + - ]: 1 : diag( outf, outmesh );
159 : : // Write output mesh to file
160 [ + - ]: 1 : auto wtimes = tk::writeUnsMesh( print, outf, outmesh, reorder );
161 : : // Collect wall-clock time data
162 [ + - ]: 1 : times.insert( end(times), begin(wtimes), end(wtimes) );
163 : :
164 : 4 : }
165 : :
166 [ + - ]: 19 : mainProxy.timestamp( times );
167 : :
168 [ + - ]: 19 : mainProxy.finalize();
169 : 20 : }
|