TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Coarsen_Operator_K.tpp
1/****************************************************************************
2* Copyright (c) 2025, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15#ifndef Coarsen_Operator_K_TPP_H
16#define Coarsen_Operator_K_TPP_H
17
18#include <Domaine_IJK.h>
19#include <EFichier.h>
20#include <communications.h>
21#include <TRUSTTab.h>
22#include <Perf_counters.h>
23
24template<typename _TYPE_>
25void Coarsen_Operator_K::initialize_grid_data_(const Grid_Level_Data_template<_TYPE_>& fine,
27 int additional_k_layers)
28{
29 //IntTab src_dest_index;
30
31 src_dest_index_.resize(0, 2);
32
33 coarsen_coefficients_.resize_array(0);
34
35 avg_coefficients_.resize_array(0);
36
37 const Domaine_IJK& src_grid_geom = fine.get_domaine();
38 const ArrOfDouble& coord_z_fine = src_grid_geom.get_node_coordinates(2 /* k direction */);
39 const ArrOfDouble& coord_z_coarse = z_coord_all_;
40
41 const double epsilon = precision_geom;
42 const int n_coord_fine = coord_z_fine.size_array();
43 const int n_coord_coarse = coord_z_coarse.size_array();
44 if (std::fabs(coord_z_fine[0] - coord_z_coarse[0]) > epsilon
45 || std::fabs(coord_z_fine[n_coord_fine-1] - coord_z_coarse[n_coord_coarse-1]) > epsilon)
46 {
47 Cerr << "Error in Coarsen_Operator_K::initialize_grid_data: coarse and fine grids have wrong size" << finl;
48 Cerr << " fine grid: " << coord_z_fine[0] << " .. " << coord_z_fine[n_coord_fine-1] << finl;
49 Cerr << " coarse grid: " << coord_z_coarse[0] << " .. " << coord_z_coarse[n_coord_coarse-1] << finl;
51 }
52
53 ArrOfDouble coarse_delta_k(n_coord_coarse - 1);
54
55 for (int i = 0; i < n_coord_coarse - 1; i++)
56 coarse_delta_k[i] = coord_z_coarse[i+1] - coord_z_coarse[i];
57
58 int current_coarse_cell = 0;
59 int current_fine_cell = 0;
60 Journal() << "Coarsen_Operator_K: global coarsening coefficients:\nfine_k coarse_k coarsen_coeff avg_coeff:" << endl;
61 while (1)
62 {
63 const int nlines = src_dest_index_.dimension(0);
64 src_dest_index_.resize(nlines + 1, 2);
65 src_dest_index_(nlines, 0) = current_fine_cell;
66 src_dest_index_(nlines, 1) = current_coarse_cell;
67 double fine_cell_size = coord_z_fine[current_fine_cell+1] - coord_z_fine[current_fine_cell];
68 double coarse_cell_size = coarse_delta_k[current_coarse_cell];
69 const double zmin = std::max(coord_z_fine[current_fine_cell], coord_z_coarse[current_coarse_cell]);
70 const double zmax = std::min(coord_z_fine[current_fine_cell+1], coord_z_coarse[current_coarse_cell+1]);
71 double intersection = zmax - zmin;
72 if (fine_cell_size <= 0. || coarse_cell_size <= 0. || intersection <= 0.)
73 {
74 Cerr << "Error in Coarsen_Operator_K::initialize_grid_data: wrong cell sizes" << finl
75 << " fine cell " << current_fine_cell << " zmin=" << coord_z_fine[current_fine_cell] ;
76 Cerr << " zmax=" << coord_z_fine[current_fine_cell+1] << finl;
77 Cerr << " coarse cell " << current_coarse_cell << " zmin=" << coord_z_coarse[current_coarse_cell]
78 << " zmax=" << coord_z_coarse[current_coarse_cell+1] << finl;
80 }
81 // Compute contribution of this cell/cell intersection
82 coarsen_coefficients_.append_array(intersection / fine_cell_size);
83 avg_coefficients_.append_array(intersection / coarse_cell_size);
84 Journal() << current_fine_cell << " " << current_coarse_cell << " "
85 << coarsen_coefficients_[nlines] << " " << avg_coefficients_[nlines] << endl;
86
87 // Advance to next cell/cell intersection:
88 if (std::fabs(coord_z_fine[current_fine_cell + 1] - coord_z_coarse[current_coarse_cell+1]) < epsilon)
89 {
90 // advance in fine mesh and coarse mesh
91 current_fine_cell++;
92 current_coarse_cell++;
93 }
94 else if (coord_z_fine[current_fine_cell + 1] < coord_z_coarse[current_coarse_cell+1])
95 {
96 // advance in the fine mesh
97 current_fine_cell++;
98 }
99 else
100 {
101 // advance in the coarse mesh
102 current_coarse_cell++;
103 }
104 // If beyond last cell, exit:
105 if (current_coarse_cell == n_coord_coarse-1)
106 {
107 assert(current_fine_cell == n_coord_fine-1);
108 break;
109 }
110 assert(current_fine_cell < n_coord_fine - 1);
111 }
112
113 Domaine_IJK grid_geom;
114 grid_geom.initialize_origin_deltas(src_grid_geom.get_origin(0),
115 src_grid_geom.get_origin(1),
116 src_grid_geom.get_origin(2),
117 src_grid_geom.get_delta(0),
118 src_grid_geom.get_delta(1),
119 coarse_delta_k,
120 src_grid_geom.get_periodic_flag(0),
121 src_grid_geom.get_periodic_flag(1),
122 src_grid_geom.get_periodic_flag(2));
123
124 // For the moment, the algorithm cannot interpolate data across processors so the mesh boundaries on each processor
125 // on the coarse and on the fine meshes must coincide (message "cannot merge")
126 // Compute the splitting of the coarse mesh: coarsened cells are on the same processor than the fine cells
127 // they come from:
128 Domaine_IJK coarse_splitting;
129 // Same processor mapping as fine mesh
130 IntTab processor_mapping;
131 fine.get_domaine().get_processor_mapping(processor_mapping);
132 // Same splitting in i and j directions
133 ArrOfInt slice_size_i, slice_size_j, fine_slice_size_k, coarse_slice_size_k;
134 fine.get_domaine().get_slice_size(0, Domaine_IJK::ELEM, slice_size_i);
135 fine.get_domaine().get_slice_size(1, Domaine_IJK::ELEM, slice_size_j);
136 fine.get_domaine().get_slice_size(2, Domaine_IJK::ELEM, fine_slice_size_k);
137 coarse_slice_size_k.resize_array(fine_slice_size_k.size_array());
138 // compute sizes of slices in the k direction:
139 {
140 int slice_num = 0;
141 bool error = false;
142 int end_of_fine_slice = fine_slice_size_k[0];
143 int previous_coarse_cell = -1;
144 for (int i = 0; i < src_dest_index_.dimension(0); i++)
145 {
146 // Index of the first cell of the next slice in the fine mesh:
147 int next_coarse_cell = src_dest_index_(i,1);
148 if (src_dest_index_(i,0) >= end_of_fine_slice)
149 {
150 // Finished a slice in the fine mesh: go to next slice
151 // Check if we go to a new cell in the coarse mesh right here:
152 if (previous_coarse_cell == next_coarse_cell)
153 {
154 // The current and the next slice have an intersection with the same coarse cell.
155 // This is currently not supported
156 Cerr << "Error in Coarsen_Operator_K::initialize_grid_data: "
157 << " cannot merge cells across processors, you must put a coarse node at z=";
158 Cerr << coord_z_fine[src_dest_index_(i,0)] << " (or modify processor splitting)" << finl;
159 error = true;
160 }
161 slice_num++;
162 end_of_fine_slice += fine_slice_size_k[slice_num];
163 }
164 if (previous_coarse_cell != next_coarse_cell)
165 coarse_slice_size_k[slice_num]++;
166 previous_coarse_cell = next_coarse_cell;
167 }
168 // Display all errors before exiting:
169 if (error)
171 }
172
173 coarse_splitting.initialize_mapping(grid_geom, slice_size_i, slice_size_j, coarse_slice_size_k, processor_mapping);
174 const int ghost_domaine_size = fine.get_ghost_size();
175 coarse.initialize(coarse_splitting, ghost_domaine_size, additional_k_layers);
176
177 // Build "local" intersection data:
178 {
179 src_dest_index_local_.reset();
180
182
184
185
186 const int fine_k_offset = fine.get_domaine().get_offset_local(DIRECTION_K);
187 const int fine_start = fine_k_offset;
188 const int fine_nlocal = fine.get_domaine().get_nb_elem_local(DIRECTION_K);
189 const int coarse_k_offset = coarse.get_domaine().get_offset_local(DIRECTION_K);
190 const int coarse_start = coarse_k_offset;
191 const int coarse_nlocal = coarse.get_domaine().get_nb_elem_local(DIRECTION_K);
192
193 const int n = src_dest_index_.dimension(0);
194 Journal() << "Coarsen_Operator_K: local coarsening coefficients:\nfine_k coarse_k coarsen_coeff avg_coeff:" << endl;
195 for (int i = 0; i < n; i++)
196 {
197 const int fine_k = src_dest_index_(i, 0);
198 const int coarse_k = src_dest_index_(i, 1);
199 // Find coefficients that affect the local values on this processor,
200 // either at interpolation step or at coarsening step
201 if ((fine_k >= fine_start && fine_k < fine_start + fine_nlocal)
202 || (coarse_k >= coarse_start && coarse_k < coarse_start + coarse_nlocal))
203 {
204 const int sz = src_dest_index_local_.dimension(0);
205 src_dest_index_local_.resize(sz+1, 2);
206 src_dest_index_local_(sz, 0) = fine_k - fine_k_offset;
207 src_dest_index_local_(sz, 1) = coarse_k - coarse_k_offset;
210 Journal() << fine_k - fine_k_offset << " " << coarse_k - coarse_k_offset << " "
211 << coarsen_coefficients_[i] << " " << avg_coefficients_[i] << endl;
212 }
213 }
214 }
215}
216
217template <typename _TYPE_, typename _TYPE_ARRAY_>
218void Coarsen_Operator_K::coarsen_(const IJK_Field_template<_TYPE_, _TYPE_ARRAY_>& fine,
220 int compute_weighted_average) const
221{
222 statistics().create_custom_counter("multigrid: K coarsening",2,"IJK");
223 statistics().begin_count("multigrid: K coarsening",statistics().get_last_opened_counter_level()+1);
224
225 const int index_start = 0;
226 const int index_end = src_dest_index_local_.dimension(0);
227 const int delta_index = 1;
228
229 const int ni = coarse.ni();
230 const int nj = coarse.nj();
231
232 const ArrOfDouble& coef_array = compute_weighted_average ? avg_coefficients_local_ : coarsen_coefficients_local_;
233
234 int previous_coarse_k = -10;
235
236 for (int index = index_start; index != index_end; index += delta_index)
237 {
238 // Source layer and destination layer (src_dest_index_ contains an index in the entire mesh)
239 const int fine_k = src_dest_index_local_(index, 0);
240 const int coarse_k = src_dest_index_local_(index, 1);
241
242 const _TYPE_ coef = (_TYPE_)coef_array[index];
243 if (coarse_k != previous_coarse_k)
244 {
245 // Start a new layer, overwrite value
246 for (int j = 0; j < nj; j++)
247 for (int i = 0; i < ni; i++)
248 coarse(i, j, coarse_k) = coef * fine(i, j, fine_k);
249 previous_coarse_k = coarse_k;
250 }
251 else
252 {
253 // Contribution to the same layer, add to previous value:
254 for (int j = 0; j < nj; j++)
255 for (int i = 0; i < ni; i++)
256 coarse(i, j, coarse_k) += coef * fine(i, j, fine_k);
257 }
258 }
259 statistics().end_count("multigrid: K coarsening");
260}
261
262template <typename _TYPE_, typename _TYPE_ARRAY_>
263void Coarsen_Operator_K::interpolate_sub_shiftk_(const IJK_Field_template<_TYPE_, _TYPE_ARRAY_>& coarse,
265 const int kshift) const
266{
267 statistics().create_custom_counter("multigrid: interpolate K",2,"IJK");
268 statistics().begin_count("multigrid: interpolate K",statistics().get_last_opened_counter_level()+1);
269 const int index_start = kshift <= 0 ? 0 : src_dest_index_local_.dimension(0) - 1;
270 const int index_end = kshift <= 0 ? src_dest_index_local_.dimension(0) : -1;
271 const int delta_index = kshift <= 0 ? 1 : -1;
272
273 const int ni = coarse.ni();
274 const int nj = coarse.nj();
275
276 const ArrOfDouble& coef_array = coarsen_coefficients_local_;
277 int previous_fine_k = -10;
278
279 for (int index = index_start; index != index_end; index += delta_index)
280 {
281 const int fine_k = src_dest_index_local_(index, 0);
282 const int coarse_k = src_dest_index_local_(index, 1);
283 const _TYPE_ coef = (_TYPE_)coef_array[index];
284 if (fine_k != previous_fine_k)
285 {
286 previous_fine_k = fine_k;
287 // Start a new layer from the fine mesh, take data from shifted position:
288 for (int J = 0; J < nj; J++)
289 for (int I = 0; I < ni; I++)
290 fine.get_in_allocated_area(I, J, fine_k + kshift) = fine(I,J,fine_k) - coef*coarse(I, J, coarse_k);
291 }
292 else
293 {
294 // Continue on the same layer, data already shifted:
295 for (int J = 0; J < nj; J++)
296 for (int I = 0; I < ni; I++)
297 fine.get_in_allocated_area(I, J, fine_k + kshift) -= coef * coarse(I, J, coarse_k);
298 }
299 }
300 fine.shift_k_origin(kshift);
301 //flop_count += ni*nj*src_dest_index_.dimension(0) * 2;
302 statistics().end_count("multigrid: interpolate K");
303}
304
305#endif
ArrOfDouble coarsen_coefficients_local_
ArrOfDouble avg_coefficients_
ArrOfDouble avg_coefficients_local_
ArrOfDouble coarsen_coefficients_
int get_offset_local(int direction) const
Returns the local offset in requested direction.
int get_nb_elem_local(int direction) const
Returns the number of elements owned by this processor in the given direction.
bool get_periodic_flag(int direction) const
Method returns true if periodic in this direction.
void get_processor_mapping(IntTab &mapping) const
Fills an array containing the mapping of processors.
const ArrOfDouble & get_delta(int direction) const
Returns the array of mesh cell sizes in requested direction.
double get_origin(int direction) const
Returns the coordinate of the first node (global) of the mesh in the requested direction.
void initialize_mapping(Domaine_IJK &dom, const ArrOfInt &slice_size_i, const ArrOfInt &slice_size_j, const ArrOfInt &slice_size_k, const IntTab &processor_mapping)
Creates a splitting of the domain by specifying the slice sizes and the processor mapping.
void get_slice_size(int direction, Localisation loc, ArrOfInt &tab) const
Returns the number of items of given location (elements, nodes, faces...) for all slices in the reque...
const ArrOfDouble & get_node_coordinates(int direction) const
Returns an array with the coordinates of all nodes in the mesh in requested direction.
void initialize_origin_deltas(double x0, double y0, double z0, const ArrOfDouble &delta_x, const ArrOfDouble &delta_y, const ArrOfDouble &delta_z, bool perio_x, bool perio_y, bool perio_z)
Initializes class elements given dataset's parameters.
void initialize(const Domaine_IJK &, int ghost, int additional_k_layers)
const Domaine_IJK & get_domaine() const
_TYPE_ & get_in_allocated_area(int i, int j, int k)
: This class is an IJK_Field_local with parallel informations.
static double precision_geom
Definition Objet_U.h:86
void begin_count(const STD_COUNTERS &std_cnt, int counter_lvl=-100000)
void end_count(const std::string &custom_count_name, int count_increment=1, long int quantity_increment=0)
End the count of a counter and update the counter values.
void create_custom_counter(std::string counter_description, int counter_level, std::string counter_family="None", bool is_comm=false, bool is_gpu=false)
Create a new counter and add it to the map of custom counters.
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
_SIZE_ size_array() const
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)