1 #ifndef VERTEXCFD_CLOSURE_EXTERNALINTERPOLATION_IMPL_HPP
2 #define VERTEXCFD_CLOSURE_EXTERNALINTERPOLATION_IMPL_HPP
4 #include <Panzer_HierarchicParallelism.hpp>
5 #include <Panzer_Workset_Utilities.hpp>
9 #include <ArborX_InterpMovingLeastSquares.hpp>
13 namespace ClosureModel
21 template<
typename SourceView,
typename CoordsView,
int NumSpaceDim>
24 KOKKOS_FUNCTION
void operator()(
int i)
const
26 for (
int dim = 0; dim < NumSpaceDim; ++dim)
27 _source_points(i)[dim] = _coords(i, dim);
30 SourceView _source_points;
36 template<
class EvalType,
class Traits,
int NumSpaceDim>
37 ExternalInterpolation<EvalType, Traits, NumSpaceDim>::ExternalInterpolation(
38 const panzer::IntegrationRule& ir,
39 const Teuchos::ParameterList& closure_params)
40 : _ir_degree(ir.cubature_degree)
41 , _interpolated_values(
"ExternalInterpolation::interpolated_values", 0)
43 const std::string output_field_name
44 = closure_params.get<std::string>(
"output field name");
45 _scalar_field = PHX::MDField<scalar_type, panzer::Cell, panzer::Point>(
46 output_field_name, ir.dl_scalar);
47 const std::string input_field_name
48 = closure_params.get<std::string>(
"input field name");
49 _file_name = closure_params.get<std::string>(
"file name");
51 this->addEvaluatedField(_scalar_field);
53 _name = std::string(
"External Interpolation ")
54 + std::to_string(NumSpaceDim) +
"D" +
" for " + output_field_name;
63 int CPU_word_size =
sizeof(double);
65 const int exoid = ex_open(
66 _file_name.c_str(), EX_READ, &CPU_word_size, &IO_word_size, &version);
68 const std::size_t num_nodes = ex_inquire_int(exoid, EX_INQ_NODES);
70 const Kokkos::View<double* [NumSpaceDim], Kokkos::LayoutLeft, Kokkos::HostSpace>
71 coords_host(Kokkos::view_alloc(Kokkos::WithoutInitializing,
72 "ExternalInterpolation::coords"),
75 int error = ex_get_coord(
77 Kokkos::subview(coords_host, Kokkos::ALL, 0).data(),
78 Kokkos::subview(coords_host, Kokkos::ALL, 1).data(),
79 NumSpaceDim == 2 ?
nullptr
80 : Kokkos::subview(coords_host, Kokkos::ALL, 2).data());
83 const std::string message = _name +
": Error reading coordinates!";
84 Kokkos::abort(message.c_str());
88 error = ex_get_variable_param(exoid, EX_NODAL, &num_nodal_vars);
91 const std::string message = _name +
": Error getting variable params!";
92 Kokkos::abort(message.c_str());
95 const int name_len = ex_inquire_int(exoid, EX_INQ_MAX_READ_NAME_LENGTH);
97 std::vector<char> var_names_buffer(num_nodal_vars * (name_len + 1));
98 std::vector<char*> var_names(num_nodal_vars);
99 for (
int i = 0; i < num_nodal_vars; ++i)
100 var_names[i] = var_names_buffer.data() + i * (name_len + 1);
102 error = ex_get_variable_names(
103 exoid, EX_NODAL, num_nodal_vars, var_names.data());
106 const std::string message = _name +
": Error getting variable names!";
107 Kokkos::abort(message.c_str());
111 = std::find(var_names.begin(), var_names.end(), input_field_name);
112 if (it == var_names.end())
114 std::stringstream ss;
115 ss << _name +
": Error finding field with name <" << input_field_name
116 <<
">. Available fields are: ";
117 for (
auto& file_field_name : var_names)
118 ss <<
"- <" << file_field_name <<
">\n";
119 Kokkos::abort(ss.str().c_str());
121 _var_index = std::distance(var_names.begin(), it) + 1;
123 _nodal_values_host = Kokkos::View<double*, Kokkos::HostSpace>(
124 Kokkos::view_alloc(Kokkos::WithoutInitializing,
125 "ExternalInterpolation::nodal_values"),
128 int num_time_steps = ex_inquire_int(exoid, EX_INQ_TIME);
129 _time_values.resize(num_time_steps);
130 error = ex_get_all_times(exoid, _time_values.data());
133 const std::string message = _name
134 +
": Error reading extracting time steps!";
135 Kokkos::abort(message.c_str());
138 error = ex_close(exoid);
141 const std::string message = _name +
": Error closing exodus file!";
142 Kokkos::abort(message.c_str());
146 _reduced_to_global.resize(num_nodes);
148 _reduced_to_global.begin(), _reduced_to_global.end(), std::size_t(0));
150 std::sort(_reduced_to_global.begin(),
151 _reduced_to_global.end(),
152 [&](std::size_t i, std::size_t j) {
153 for (int dim = 0; dim < NumSpaceDim; ++dim)
155 if (coords_host(i, dim) < coords_host(j, dim))
157 if (coords_host(i, dim) > coords_host(j, dim))
162 _reduced_to_global.erase(
163 std::unique(_reduced_to_global.begin(),
164 _reduced_to_global.end(),
165 [&](std::size_t i, std::size_t j) {
166 for (int dim = 0; dim < NumSpaceDim; ++dim)
167 if (coords_host(i, dim) != coords_host(j, dim))
171 _reduced_to_global.end());
172 const std::size_t num_unique_nodes = _reduced_to_global.size();
174 const Kokkos::View<double* [NumSpaceDim], Kokkos::LayoutLeft, Kokkos::HostSpace>
175 coords_host_reduced(Kokkos::view_alloc(Kokkos::WithoutInitializing,
176 "ExternalInterpolation::"
180 _nodal_values_host_reduced = Kokkos::View<double*, Kokkos::HostSpace>(
181 Kokkos::view_alloc(Kokkos::WithoutInitializing,
182 "ExternalInterpolation::nodal_values"),
185 for (
size_t i = 0; i < num_unique_nodes; ++i)
187 for (
int dim = 0; dim < NumSpaceDim; ++dim)
188 coords_host_reduced(i, dim)
189 = coords_host(_reduced_to_global[i], dim);
195 _source_points = Kokkos::View<
196 ArborX::ExperimentalHyperGeometry::Point<NumSpaceDim, double>*,
198 Kokkos::view_alloc(Kokkos::WithoutInitializing,
"source_points"),
200 const auto coords = Kokkos::create_mirror_view_and_copy(
201 MemorySpace{}, coords_host_reduced);
202 _nodal_values = Kokkos::create_mirror_view(MemorySpace{},
203 _nodal_values_host_reduced);
205 ExecutionSpace exec_space;
206 Kokkos::parallel_for(
207 Kokkos::RangePolicy<ExecutionSpace>(exec_space, 0, num_unique_nodes),
208 Impl::ConvertExodusToArborXLayout<decltype(_source_points),
210 NumSpaceDim>{_source_points, coords});
217 template<
class EvalType,
class Traits,
int NumSpaceDim>
218 void ExternalInterpolation<EvalType, Traits, NumSpaceDim>::read_node_values(
222 int CPU_word_size =
sizeof(double);
223 int IO_word_size = 0;
224 const int exoid = ex_open(
225 _file_name.c_str(), EX_READ, &CPU_word_size, &IO_word_size, &version);
227 int error = ex_get_var(exoid,
232 _nodal_values_host.size(),
233 _nodal_values_host.data());
237 const std::string message = _name +
": Error reading nodal values!";
238 Kokkos::abort(message.c_str());
240 error = ex_close(exoid);
243 const std::string message = _name +
": Error closing exodus file!";
244 Kokkos::abort(message.c_str());
247 for (
size_t i = 0; i < _reduced_to_global.size(); ++i)
248 _nodal_values_host_reduced(i)
249 = _nodal_values_host(_reduced_to_global[i]);
252 Kokkos::deep_copy(exec, _nodal_values, _nodal_values_host_reduced);
257 template<
class EvalType,
class Traits,
int NumSpaceDim>
258 void ExternalInterpolation<EvalType, Traits, NumSpaceDim>::postRegistrationSetup(
259 typename Traits::SetupData sd, PHX::FieldManager<Traits>&)
261 _ir_index = panzer::getIntegrationRuleIndex(_ir_degree, (*sd.worksets_)[0]);
265 template<
class EvalType,
class Traits,
int NumSpaceDim>
266 void ExternalInterpolation<EvalType, Traits, NumSpaceDim>::evaluateFields(
267 typename Traits::EvalData workset)
271 size_t time_step_index = std::min<int>(
272 (std::lower_bound(_time_values.begin(), _time_values.end(), workset.time)
273 - _time_values.begin()),
274 _time_values.size() - 1);
279 if ((time_step_index != 0)
280 && (workset.time - _time_values[time_step_index - 1])
281 < (_time_values[time_step_index] - workset.time))
284 if (time_step_index != _last_time_step_index)
285 read_node_values(time_step_index);
287 _last_time_step_index = time_step_index;
289 const auto ip_coords = workset.int_rules[_ir_index]->ip_coordinates;
290 const int n_points = ip_coords.extent(1);
291 const int n_cells = workset.num_cells;
293 ExecutionSpace exec_space;
296 ArborX::ExperimentalHyperGeometry::Point<NumSpaceDim, double>*,
298 target_points(Kokkos::view_alloc(Kokkos::WithoutInitializing,
299 "ExternalInterpolation::targets"),
301 Kokkos::parallel_for(
302 Kokkos::MDRangePolicy<ExecutionSpace, Kokkos::Rank<2>>(
303 exec_space, {0, 0}, {n_cells, n_points}),
304 KOKKOS_LAMBDA(
int cell,
int point) {
305 for (
int dim = 0; dim < NumSpaceDim; ++dim)
306 target_points(cell * n_points + point)[dim]
307 = ip_coords(cell, point, dim);
310 const ArborX::Interpolation::MovingLeastSquares<MemorySpace> mls(
311 exec_space, _source_points, target_points);
313 Kokkos::realloc(Kokkos::view_alloc(Kokkos::WithoutInitializing),
314 _interpolated_values,
315 target_points.size());
317 mls.interpolate(exec_space, _nodal_values, _interpolated_values);
321 = panzer::HP::inst().teamPolicy<scalar_type, PHX::Device>(n_cells);
322 Kokkos::parallel_for(this->getName(), policy, *
this);
326 template<
class EvalType,
class Traits,
int NumSpaceDim>
327 KOKKOS_INLINE_FUNCTION
void
328 ExternalInterpolation<EvalType, Traits, NumSpaceDim>::operator()(
329 const Kokkos::TeamPolicy<PHX::exec_space>::member_type& team)
const
331 const int cell = team.league_rank();
332 const int num_point = _scalar_field.extent(1);
334 Kokkos::parallel_for(
335 Kokkos::TeamThreadRange(team, 0, num_point), [&](
const int point) {
336 _scalar_field(cell, point)
337 = _interpolated_values(cell * num_point + point);
345 #endif // end VERTEXCFD_CLOSURE_EXTERNALINTERPOLATION_IMPL_HPP