Build and append the incompressible flow stages.
Appends in the order: self-advection, buoyancy, diffusion, wall, divergence, pressure, solenoidal, wall, then one advection per carried scalar. Carriers run last so they are transported by the projected velocity.
Stages added to the chain before this call keep their position ahead of it, which is where an influx stage belongs.
275{
276 FlowStages stages;
277
278 auto self = std::dynamic_pointer_cast<VolumeGridBuffer>(shared_from_this());
280
281 if (!chain) {
283 "setup_flow: no processing chain, call after registration");
284 return stages;
285 }
286
287 const auto require = [this](const std::string& name, const char* role) {
288 if (name.empty()) {
290 "setup_flow: no field supplied for '{}'", role);
291 return false;
292 }
295 "setup_flow: '{}' names no field on this volume, supplied as '{}'",
296 name, role);
297 return false;
298 }
299 return true;
300 };
301
302 if (!require(config.velocity, "velocity")
303 || !require(config.divergence, "divergence")
304 || !require(config.pressure, "pressure")) {
305 return stages;
306 }
307
308 if (config.viscosity > 0.0F && !require(config.scratch, "scratch")) {
309 return stages;
310 }
311
312 stages.self_advect = std::make_shared<AdvectProcessor>(
313 config.velocity, config.velocity, "volume_advect_vector.comp.spv");
314 stages.self_advect->set_time_step(config.time_step);
315 chain->add_processor(stages.self_advect, self);
316
317 if (config.buoyancy) {
318 const auto&
b = *config.buoyancy;
319
320 if (!require(
b.temperature,
"buoyancy.temperature")
321 || !require(
b.density,
"buoyancy.density")) {
322 return stages;
323 }
324
325 stages.buoyancy = std::make_shared<BuoyancyProcessor>(
326 b.temperature,
b.density, config.velocity,
327 b.direction,
"volume_buoyancy.comp.spv");
328 stages.buoyancy->set_time_step(config.time_step);
329 stages.buoyancy->set_temperature_gain(
b.temperature_gain);
330 stages.buoyancy->set_density_gain(
b.density_gain);
331 stages.buoyancy->set_ambient(
b.ambient);
332 chain->add_processor(stages.buoyancy, self);
333 }
334
335 if (config.viscosity > 0.0F) {
336 stages.diffuse = std::make_shared<DiffuseProcessor>(
337 config.velocity, config.scratch, "volume_diffuse_vector.comp.spv");
338 stages.diffuse->set_rate(config.viscosity);
339 stages.diffuse->set_time_step(config.time_step);
340 chain->add_processor(stages.diffuse, self);
341 }
342
343 if (config.walls) {
344 stages.wall_advected = std::make_shared<WallProcessor>(
345 config.velocity, "volume_wall.comp.spv");
346 chain->add_processor(stages.wall_advected, self);
347 }
348
349 stages.divergence = std::make_shared<DivergenceProcessor>(
350 config.velocity, config.divergence, "volume_divergence.comp.spv");
351 chain->add_processor(stages.divergence, self);
352
353 stages.pressure = std::make_shared<PressureProcessor>(
354 config.divergence, config.pressure, "volume_pressure_jacobi.comp.spv");
355 stages.pressure->set_iteration_count(config.jacobi_iterations);
356 chain->add_processor(stages.pressure, self);
357
358 stages.solenoidal = std::make_shared<SolenoidalProcessor>(
359 config.pressure, config.velocity, "volume_solenoidal.comp.spv");
360 chain->add_processor(stages.solenoidal, self);
361
362 if (config.walls) {
363 stages.wall_projected = std::make_shared<WallProcessor>(
364 config.velocity, "volume_wall.comp.spv");
365 chain->add_processor(stages.wall_projected, self);
366 }
367
368 for (const auto& carried : config.carried) {
369 if (!require(carried.field, "carried")) {
370 continue;
371 }
372
373 auto advect = std::make_shared<AdvectProcessor>(
374 config.velocity, carried.field, "volume_advect_scalar.comp.spv");
375 advect->set_time_step(config.time_step);
376 advect->set_dissipation(carried.dissipation);
377 chain->add_processor(advect, self);
378
379 stages.carriers.push_back(std::move(advect));
380 }
381
383 "VolumeGridBuffer::setup_flow: {} carried, buoyancy {}, viscosity {}, walls {}",
384 stages.carriers.size(), config.buoyancy ? "on" : "off",
385 config.viscosity, config.walls ? "on" : "off");
386
387 return stages;
388}
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
std::shared_ptr< Buffers::BufferProcessingChain > get_processing_chain() override
Access the buffer's processing chain.
bool has_field(const std::string &name) const
Whether a field of this name was declared.
@ Init
Engine/subsystem initialization.
@ Buffers
Buffers, Managers, processors and processing chains.
Tendency< A, C > chain(const Tendency< A, B > &first, const Tendency< B, C > &second)
Sequential composition: evaluate first, feed result into second.