@@ -173,14 +173,14 @@ void sample_MFsurfchem(MultiFab& cu, MultiFab& prim, MultiFab& surfcov, MultiFab
173173 const GpuArray<Real, AMREX_SPACEDIM > dx = geom.CellSizeArray ();
174174
175175#ifdef AMREX_USE_ML
176- bool model_loaded = false ;
177- torch::jit::script::Module model;
176+ static bool model_loaded = false ;
177+ static torch::jit::script::Module model;
178178 auto dtype0 = torch::kFloat64 ;
179179
180180 // Default tensoropt to CPU
181- auto tensoropt = torch::TensorOptions ().dtype (dtype0);
181+ static auto tensoropt = torch::TensorOptions ().dtype (dtype0);
182182 BL_PROFILE_VAR (" load_ML_model" , p_load);
183- if (use_ml_mfsurfchem > 0 ) {
183+ if (use_ml_mfsurfchem > 0 && !model_loaded ) {
184184 try {
185185 model = torch::jit::load (model_filename);
186186 model.eval ();
@@ -215,37 +215,42 @@ void sample_MFsurfchem(MultiFab& cu, MultiFab& prim, MultiFab& surfcov, MultiFab
215215#else
216216 BL_PROFILE_VAR_START (p_compute_ml);
217217
218+ if (!model_loaded) {
219+ Abort (" ML model requested but not loaded" );
220+ }
221+ // number of inputs and outputs of the pytorch model
222+ int Nc_in = 3 ;
223+ int Nc_out = 2 ;
224+
225+ // calculate total cells across all boxes to get size of the batch
226+ long total_cells = 0 ;
227+ std::vector<long > box_offsets;
218228 for (MFIter mfi (*surfcov_slice,false ); mfi.isValid (); ++mfi)
219229 {
230+ box_offsets.push_back (total_cells);
220231 const Box& bx = mfi.tilebox ();
221- const Array4<Real> & cu_arr = cu.array (mfi);
222- const Array4<Real> & prim_arr = prim.array (mfi);
223- const Array4<Real> & surfcov_arr = surfcov_slice->array (mfi);
224- const Array4<Real> & dNadsdes_arr = dNadsdes.array (mfi);
225- const Array4<Real> & dNads_arr = dNads.array (mfi);
226- const Array4<Real> & dNdes_arr = dNdes.array (mfi);
227-
228- amrex::Real Ntot = surf_site_num_dens*dx[(ads_wall_dir+1 )%3 ]*dx[(ads_wall_dir+2 )%3 ]; // total number of reactive sites
229-
230- if (!model_loaded) {
231- Abort (" ML model requested but not loaded" );
232- }
233- // number of inputs and outputs of the pytorch model
234- int Nc_in = 3 ;
235- int Nc_out = 2 ;
236-
237- // retrieve smallend and size of box
238- const IntVect bx_lo = bx.smallEnd ();
239232 const IntVect nbox = bx.size ();
240233 int ncell = AMREX_SPACEDIM == 2 ?
241234 nbox[0 ] * nbox[1 ] : nbox[0 ] * nbox[1 ] * nbox[2 ];
242- int nsample = ncell * n_ads_spec;
235+ total_cells += ncell;
236+ }
237+
238+ int total_samples = total_cells * n_ads_spec;
243239
244- // creates a flattened buffer of total sample points on box times number of inputs on each point (total number of inputs)
245- amrex::Gpu::ManagedVector<Real> aux (nsample * Nc_in);
240+ // creates a flattened buffer of total sample points
241+ amrex::Gpu::ManagedVector<Real> aux (total_samples * Nc_in);
242+ Real* AMREX_RESTRICT auxPtr = aux.dataPtr ();
246243
247- // gives pointer access to the buffer
248- Real* AMREX_RESTRICT auxPtr = aux.dataPtr ();
244+ // pack data from all boxes into the single buffer
245+ int box_idx = 0 ;
246+ for (MFIter mfi (*surfcov_slice,false ); mfi.isValid (); ++mfi, ++box_idx)
247+ {
248+ const Box& bx = mfi.tilebox ();
249+ const Array4<Real> & prim_arr = prim.array (mfi);
250+ const Array4<Real> & surfcov_arr = surfcov_slice->array (mfi);
251+ const IntVect bx_lo = bx.smallEnd ();
252+ const IntVect nbox = bx.size ();
253+ long offset = box_offsets[box_idx];
249254
250255 amrex::ParallelFor (bx, n_ads_spec, [=] AMREX_GPU_DEVICE (int i, int j, int k, int m) noexcept
251256 {
@@ -256,32 +261,47 @@ void sample_MFsurfchem(MultiFab& cu, MultiFab& prim, MultiFab& surfcov, MultiFab
256261 int kk = k - bx_lo[2 ];
257262 cell += kk*nbox[0 ]*nbox[1 ];
258263#endif
259- int index = cell * n_ads_spec + m;
264+ long index = (offset + cell) * n_ads_spec + m;
260265
261266 amrex::Real pres = 0.0 ;
262267 amrex::Real tempratio = prim_arr (i,j,k,4 ) / T_init[0 ];
263268 amrex::Real theta = 0.0 ;
264269
265- pres = prim_arr (i,j,k,5 );
266- pres *= prim_arr (i,j,k,6 + nspecies + m);
267- theta = surfcov_arr (i,j,k,m);
270+ pres = prim_arr (i,j,k,5 );
271+ pres *= prim_arr (i,j,k,6 + nspecies + m);
272+ theta = surfcov_arr (i,j,k,m);
268273
269274 auxPtr[index*Nc_in + 0 ] = pres;
270275 auxPtr[index*Nc_in + 1 ] = tempratio;
271276 auxPtr[index*Nc_in + 2 ] = theta;
272277 });
278+ }
273279
274-
275- at::Tensor inputs_torch = torch::from_blob (auxPtr, {nsample, Nc_in}, tensoropt);
276-
277- at::Tensor outputs_torch = model.forward ({inputs_torch}).toTensor ();
278- outputs_torch = outputs_torch.to (dtype0).contiguous ();
280+ // run pytorch model once for all data
281+ at::Tensor inputs_torch = torch::from_blob (auxPtr, {total_samples, Nc_in}, tensoropt);
282+ at::Tensor outputs_torch = model.forward ({inputs_torch}).toTensor ();
283+ outputs_torch = outputs_torch.to (dtype0).contiguous ();
279284
280285#ifdef AMREX_USE_CUDA
281- auto outputs_torch_acc = outputs_torch.packed_accessor64 <Real,2 >();
286+ auto outputs_torch_acc = outputs_torch.packed_accessor64 <Real,2 >();
282287#else
283- auto outputs_torch_acc = outputs_torch.accessor <Real,2 >();
288+ auto outputs_torch_acc = outputs_torch.accessor <Real,2 >();
284289#endif
290+
291+ amrex::Real Ntot = surf_site_num_dens*dx[(ads_wall_dir+1 )%3 ]*dx[(ads_wall_dir+2 )%3 ];
292+
293+ // unpack data from pytorch results back to the amrex arrays
294+ box_idx = 0 ;
295+ for (MFIter mfi (*surfcov_slice,false ); mfi.isValid (); ++mfi, ++box_idx)
296+ {
297+ const Box& bx = mfi.tilebox ();
298+ const Array4<Real> & dNadsdes_arr = dNadsdes.array (mfi);
299+ const Array4<Real> & dNads_arr = dNads.array (mfi);
300+ const Array4<Real> & dNdes_arr = dNdes.array (mfi);
301+ const IntVect bx_lo = bx.smallEnd ();
302+ const IntVect nbox = bx.size ();
303+ long offset = box_offsets[box_idx];
304+
285305 amrex::ParallelForRNG (bx, [=] AMREX_GPU_DEVICE (int i, int j, int k, RandomEngine const & engine) noexcept
286306 {
287307 int ii = i - bx_lo[0 ];
@@ -291,32 +311,30 @@ void sample_MFsurfchem(MultiFab& cu, MultiFab& prim, MultiFab& surfcov, MultiFab
291311 int kk = k - bx_lo[2 ];
292312 cell += kk*nbox[0 ]*nbox[1 ];
293313#endif
314+ for (int m=0 ;m<n_ads_spec;m++) {
315+ long index = (offset + cell) * n_ads_spec + m;
294316
295- for (int m=0 ;m<n_ads_spec;m++) {
296- int index = cell * n_ads_spec + m;
297-
298- amrex::Real pred_ads = static_cast <amrex::Real>(outputs_torch_acc[index][0 ]);
299- amrex::Real pred_des = static_cast <amrex::Real>(outputs_torch_acc[index][1 ]);
317+ amrex::Real pred_ads = static_cast <amrex::Real>(outputs_torch_acc[index][0 ]);
318+ amrex::Real pred_des = static_cast <amrex::Real>(outputs_torch_acc[index][1 ]);
300319
301- amrex::Real meanNads = pred_ads * Ntot * dt;
302- amrex::Real meanNdes = pred_des * Ntot * dt;
320+ amrex::Real meanNads = pred_ads * Ntot * dt;
321+ amrex::Real meanNdes = pred_des * Ntot * dt;
303322
304- amrex::Real Nads = (stoch_MFsurfchem == 0 ) ? meanNads : amrex::RandomPoisson (meanNads,engine);
305- amrex::Real Ndes = (stoch_MFsurfchem == 0 ) ? meanNdes : amrex::RandomPoisson (meanNdes,engine);
323+ amrex::Real Nads = (stoch_MFsurfchem == 0 ) ? meanNads : amrex::RandomPoisson (meanNads,engine);
324+ amrex::Real Ndes = (stoch_MFsurfchem == 0 ) ? meanNdes : amrex::RandomPoisson (meanNdes,engine);
306325
307- if (conversion_MFsurfchem > 0 ) {
308- dNads_arr (i,j,k,m) = Nads;
309- dNdes_arr (i,j,k,m) = Ndes;
310- } else {
326+ if (conversion_MFsurfchem > 0 ) {
327+ dNads_arr (i,j,k,m) = Nads;
328+ dNdes_arr (i,j,k,m) = Ndes;
329+ } else {
311330 dNadsdes_arr (i,j,k,m) = Nads - Ndes;
312- }
313331 }
332+ }
314333 });
315334 }
316335
317336 BL_PROFILE_VAR_STOP (p_compute_ml);
318337#endif
319-
320338 } else { // use_ml_mfsurfchem <= 0
321339
322340 BL_PROFILE_VAR_START (p_compute_std);
0 commit comments