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 : : All rights reserved. See the LICENSE file for details.
8 : : \brief Mesh converter driver
9 : : \details Mesh converter driver.
10 : : */
11 : : // *****************************************************************************
12 : :
13 : : #include "Types.hpp"
14 : : #include "Tags.hpp"
15 : : #include "MeshConvDriver.hpp"
16 : : #include "MeshFactory.hpp"
17 : : #include "Writer.hpp"
18 : :
19 : : #include "NoWarning/meshconv.decl.h"
20 : :
21 : : using meshconv::MeshConvDriver;
22 : :
23 : : extern CProxy_Main mainProxy;
24 : :
25 : 18 : MeshConvDriver::MeshConvDriver( const ctr::CmdLine& cmdline, int ) :
26 : 36 : m_print( cmdline.logname( cmdline.get< tag::io, tag::screen >(),
27 : 18 : cmdline.get< tag::io, tag::nrestart >() ),
28 : 36 : cmdline.get< tag::verbose >() ? std::cout : std::clog,
29 : : std::ios_base::app ),
30 : 18 : m_reorder( cmdline.get< tag::reorder >() ),
31 : : m_input(),
32 [ + - ][ + - ]: 54 : m_output()
33 : : // *****************************************************************************
34 : : // Constructor
35 : : //! \param[in] cmdline Command line object storing data parsed from the command
36 : : //! line arguments
37 : : // *****************************************************************************
38 : : {
39 : : // Save input file name
40 [ + - ]: 18 : m_input = cmdline.get< tag::io, tag::input >();
41 : : // Save output file name
42 [ + - ]: 18 : m_output = cmdline.get< tag::io, tag::output >();
43 : 18 : }
44 : :
45 : : void
46 : 18 : MeshConvDriver::execute() const
47 : : // *****************************************************************************
48 : : // Execute: Convert mesh file
49 : : // *****************************************************************************
50 : : {
51 [ + - ]: 18 : m_print.endsubsection();
52 : :
53 : 36 : std::vector< std::pair< std::string, tk::real > > times;
54 : :
55 : : // If input filename contains a '%', we aggregate multiple files
56 [ + + ]: 18 : if (m_input.find('%') == std::string::npos) {
57 : :
58 : : // Convert single mesh
59 : :
60 [ + - ]: 17 : times.push_back( {} );
61 [ + - ]: 34 : auto mesh = tk::readUnsMesh( m_print, m_input, times[0] );
62 [ + - ]: 17 : auto wtimes = tk::writeUnsMesh( m_print, m_output, mesh, m_reorder );
63 [ + - ]: 17 : times.insert( end(times), begin(wtimes), end(wtimes) );
64 : :
65 : : } else {
66 : :
67 : : // Aggregate multiple meshes containing surface output
68 : :
69 : : // Find a '%' sign in the input filename, and assuming a syntax of
70 : : // '.<nfile>.%', find '<nfile>' as the number of files to aggregate.
71 : 1 : auto percent_pos = m_input.find( '%' );
72 [ + - ]: 2 : auto input_basename = m_input.substr( 0, percent_pos );
73 : 1 : auto dot1 = m_input.find_last_of( '.', percent_pos );
74 : 1 : auto dot2 = m_input.find_last_of( '.', dot1-1 );
75 [ + - ]: 2 : auto nfile_str = m_input.substr( dot2+1, dot1-dot2-1 );
76 [ + - ]: 2 : std::stringstream ss( nfile_str );
77 [ - + ]: 1 : if (nfile_str.empty())
78 [ - - ][ - - ]: 0 : Throw( "The percent sign must be followed by an "
[ - - ]
79 : : "integer, the number of files to aggregate" );
80 : : std::size_t nfile;
81 [ + - ]: 1 : ss >> nfile;
82 [ + - ][ + - ]: 3 : m_print.diag( "Aggregating " + std::to_string(nfile) +
[ + - ][ + - ]
83 [ + - ][ + - ]: 2 : " files from base filename: '" + input_basename +'\'' );
84 : :
85 : 1 : const auto eps = std::numeric_limits< tk::real >::epsilon();
86 : :
87 : : // Lambda to echo some diagnostics on the mesh being processes to screen
88 : 10 : auto diag = [&]( const std::string& name, const tk::UnsMesh& mesh ){
89 [ + - ][ + - ]: 30 : m_print.diag( name + ": ntri: " +
[ + - ]
90 [ + - ][ + - ]: 40 : std::to_string(mesh.triinpoel().size()/3) +
91 [ + - ][ + - ]: 40 : ", ntime: " + std::to_string(mesh.vartimes().size()) +
[ + - ]
92 [ + - ][ + - ]: 30 : (!mesh.nodevars().empty() ? ", node_var: " +
[ - - ][ - + ]
[ - - ]
93 [ + - ][ + - ]: 40 : std::to_string(mesh.nodevars()[0].size()) : "") +
[ + - ][ - - ]
94 [ + - ][ + - ]: 30 : (!mesh.nodevars()[0].empty() ? ", npoin: " +
[ - - ][ - + ]
[ - - ]
95 [ + - ][ + - ]: 40 : std::to_string(mesh.nodevars()[0][0].size()) : "") +
[ + - ][ - - ]
96 [ + - ][ + - ]: 30 : (!mesh.elemvars().empty() ? ", elem_var: " +
[ - - ][ - + ]
[ - - ]
97 [ + - ][ + - ]: 40 : std::to_string(mesh.elemvars()[0].size()) : "") +
[ + - ][ - - ]
98 [ - + ][ - - ]: 20 : (!mesh.elemvars()[0].empty() ? ", nelem: " +
[ + - ][ + - ]
[ - - ]
99 [ - - ][ - + ]: 10 : std::to_string(mesh.elemvars()[0][0].size()) : "") );
[ - - ]
100 : 10 : };
101 : :
102 : : // Output-mesh containers, will store aggregated surface(s) and field output
103 : 2 : tk::UnsMesh::Coords coords;
104 : 1 : auto& X = coords[0];
105 : 1 : auto& Y = coords[1];
106 : 1 : auto& Z = coords[2];
107 : 1 : std::size_t npoin = 0;
108 : 1 : std::size_t nelem = 0;
109 : 2 : std::vector< std::size_t > otriinpoel;
110 : 2 : std::vector< std::string > nodevarnames;
111 : 2 : std::vector< std::string > elemvarnames;
112 : 2 : std::vector< tk::real > vartimes;
113 : 2 : std::vector< std::vector< std::vector< tk::real > > > nodevars;
114 : 2 : std::vector< std::vector< std::vector< tk::real > > > elemvars;
115 : : // Counter for number of non-empty meshes processed
116 : 1 : std::size_t k = 0;
117 [ + + ]: 31 : for (std::size_t m=0; m<nfile; ++m) {
118 [ + - ][ + - ]: 30 : std::string name = input_basename + std::to_string(m);
119 [ + - ]: 30 : times.push_back( {} );
120 [ + - ]: 30 : auto mesh = tk::readUnsMesh( m_print, name, times.back() );
121 : 30 : const auto& triinpoel = mesh.triinpoel();
122 : : // Skip meshes with a single triange cell
123 [ + + ]: 30 : if (triinpoel.size() == 3) continue;
124 : 9 : const auto& x = mesh.x();
125 : 9 : const auto& y = mesh.y();
126 : 9 : const auto& z = mesh.z();
127 [ + - ]: 9 : nodevarnames = mesh.nodevarnames();
128 [ + - ]: 9 : elemvarnames = mesh.elemvarnames();
129 [ + - ]: 9 : vartimes = mesh.vartimes();
130 : : // Echo some diagnostics on the mesh being processes to screen
131 [ + - ]: 9 : diag( name, mesh );
132 : : // Aggregate data from each triangle element in mesh
133 [ + + ]: 63693 : for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
134 [ + + ]: 254736 : for (std::size_t n=0; n<3; ++n) {
135 : 191052 : auto j = triinpoel[ e*3+n ];
136 : 191052 : bool visited = false;
137 : : // WARNING: linear search below, will not scale well
138 [ + + ]: 3378984362 : for (std::size_t i=0; i<X.size(); ++i) {
139 : : // If mesh point has already been seen (on a previous mesh)
140 [ + + ]: 3939506020 : if (std::abs(x[j]-X[i]) < eps &&
141 [ + + ][ + + ]: 3939506020 : std::abs(y[j]-Y[i]) < eps &&
[ + + ]
142 : 10327686 : std::abs(z[j]-Z[i]) < eps)
143 : : { // no point in connectivity but nothing else
144 : 159179 : visited = true;
145 [ + - ]: 159179 : otriinpoel.push_back( i );
146 : : }
147 : : }
148 [ + + ]: 191052 : if (!visited) { // Mesh point not yet seen
149 : : // save coordinates and (global) point id in aggregated connectivity
150 [ + - ]: 31873 : X.push_back( x[j] );
151 [ + - ]: 31873 : Y.push_back( y[j] );
152 [ + - ]: 31873 : Z.push_back( z[j] );
153 [ + - ]: 31873 : otriinpoel.push_back( npoin );
154 : : // aggregate nodal field data for all times and variables
155 : 31873 : std::size_t time = 0;
156 : 31873 : std::size_t varid = 0;
157 [ + + ]: 127492 : for (const auto& t : mesh.nodevars()) { // for all times
158 [ + + ][ + + ]: 95619 : if (k == 0 && npoin == 0) nodevars.push_back( {} );
[ + - ]
159 [ + + ]: 669333 : for (const auto& v : t) { // for all variables
160 [ + + ][ + + ]: 573714 : if (k == 0 && npoin == 0) nodevars.back().push_back( {} );
[ + - ]
161 [ + - ]: 573714 : nodevars[time][varid].push_back( v[j] );
162 : 573714 : ++varid;
163 : : }
164 : 95619 : ++time;
165 : 95619 : varid = 0;
166 : : }
167 : 31873 : ++npoin; // increase number of nodes in output mesh
168 : : }
169 : : }
170 : :
171 : : // aggregate elemental field data for all times and variables
172 : 63684 : std::size_t etime = 0;
173 : 63684 : std::size_t evarid = 0;
174 [ + + ]: 254736 : for (const auto& t : mesh.elemvars()) { // for all times
175 [ + + ][ + + ]: 191052 : if (k == 0 && nelem == 0) elemvars.push_back( {} );
[ + - ]
176 [ - + ]: 191052 : for (const auto& v : t) { // for all variables
177 [ - - ][ - - ]: 0 : if (k == 0 && nelem == 0) elemvars.back().push_back( {} );
[ - - ]
178 [ - - ]: 0 : elemvars[etime][evarid].push_back( v[e] );
179 : 0 : ++evarid;
180 : : }
181 : 191052 : ++etime;
182 : 191052 : evarid = 0;
183 : : }
184 : 63684 : ++nelem; // increase number of elements in output mesh
185 : : }
186 : 9 : ++k; // increase number of non-empty meshes processed
187 : : }
188 : :
189 : : // Construct aggregated output mesh
190 : : tk::UnsMesh outmesh( coords, otriinpoel, nodevarnames, elemvarnames,
191 [ + - ]: 2 : vartimes, nodevars, elemvars );
192 : : // Echo diagnostics on the aggreegate output mesh
193 [ + - ]: 1 : diag( m_output, outmesh );
194 : : // Write output mesh to file
195 [ + - ]: 1 : auto wtimes = tk::writeUnsMesh( m_print, m_output, outmesh, m_reorder );
196 : : // Collect wall-clock time data
197 [ + - ]: 1 : times.insert( end(times), begin(wtimes), end(wtimes) );
198 : :
199 : : }
200 : :
201 [ + - ]: 18 : mainProxy.timestamp( times );
202 : :
203 [ + - ]: 18 : mainProxy.finalize();
204 : 18 : }
|