From 2aa4301c88aac15d81e08b1f5ac24da2a9279243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Mon, 16 Dec 2019 15:41:07 +0100 Subject: [PATCH] Mantaflow [Part 2]: Added fluid wrapper files Files from /intern/mantaflow handle the communication between core Blender code and Mantaflow itself. It's the bridge to communicate with Mantas Python functions. Code from /intern/mantaflow/intern/strings/ is pure Manta code and would likely need less attention in the review. Reviewed By: sergey Maniphest Tasks: T59995 Differential Revision: https://developer.blender.org/D3851 --- intern/mantaflow/CMakeLists.txt | 67 + intern/mantaflow/extern/manta_fluid_API.h | 232 ++ intern/mantaflow/extern/manta_python_API.h | 45 + intern/mantaflow/intern/MANTA_main.cpp | 2679 +++++++++++++++++ intern/mantaflow/intern/MANTA_main.h | 850 ++++++ intern/mantaflow/intern/manta_fluid_API.cpp | 872 ++++++ intern/mantaflow/intern/manta_python_API.cpp | 36 + .../mantaflow/intern/strings/fluid_script.h | 805 +++++ .../mantaflow/intern/strings/liquid_script.h | 462 +++ .../mantaflow/intern/strings/smoke_script.h | 581 ++++ 10 files changed, 6629 insertions(+) create mode 100644 intern/mantaflow/CMakeLists.txt create mode 100644 intern/mantaflow/extern/manta_fluid_API.h create mode 100644 intern/mantaflow/extern/manta_python_API.h create mode 100644 intern/mantaflow/intern/MANTA_main.cpp create mode 100644 intern/mantaflow/intern/MANTA_main.h create mode 100644 intern/mantaflow/intern/manta_fluid_API.cpp create mode 100644 intern/mantaflow/intern/manta_python_API.cpp create mode 100644 intern/mantaflow/intern/strings/fluid_script.h create mode 100644 intern/mantaflow/intern/strings/liquid_script.h create mode 100644 intern/mantaflow/intern/strings/smoke_script.h diff --git a/intern/mantaflow/CMakeLists.txt b/intern/mantaflow/CMakeLists.txt new file mode 100644 index 00000000000..9fdd8b59aca --- /dev/null +++ b/intern/mantaflow/CMakeLists.txt @@ -0,0 +1,67 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2019, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Sebastian Barschkis (sebbas) +# +# ***** END GPL LICENSE BLOCK ***** + +add_definitions(-DWITH_FLUID=1) + +if(WITH_OPENVDB) + add_definitions(-DOPENVDB=1) +endif() + +set(INC + extern + intern/strings + ../../source/blender/makesdna + ../../source/blender/blenlib +) + +# Python is always required +add_definitions(-DWITH_PYTHON) + +set(INC_SYS + ../../extern/mantaflow/helper/util + ../../extern/mantaflow/helper/pwrapper + ../../extern/mantaflow/preprocessed + ${PYTHON_INCLUDE_DIRS} + ${ZLIB_INCLUDE_DIRS} +) + +set(SRC + intern/manta_python_API.cpp + intern/manta_fluid_API.cpp + intern/MANTA_main.cpp + + extern/manta_python_API.h + extern/manta_fluid_API.h + intern/MANTA_main.h + intern/strings/fluid_script.h + intern/strings/smoke_script.h + intern/strings/liquid_script.h +) + +set(LIB + extern_mantaflow +) + +blender_add_lib(bf_intern_mantaflow "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/intern/mantaflow/extern/manta_fluid_API.h b/intern/mantaflow/extern/manta_fluid_API.h new file mode 100644 index 00000000000..9e0bd2d9a3e --- /dev/null +++ b/intern/mantaflow/extern/manta_fluid_API.h @@ -0,0 +1,232 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sebastian Barschkis (sebbas) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file mantaflow/extern/manta_smoke_API.h + * \ingroup mantaflow + */ + +#ifndef MANTA_API_H +#define MANTA_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct MANTA; + +/* Fluid functions */ +struct MANTA *manta_init(int *res, struct FluidModifierData *mmd); +void manta_free(struct MANTA *fluid); +void manta_ensure_obstacle(struct MANTA *fluid, struct FluidModifierData *mmd); +void manta_ensure_guiding(struct MANTA *fluid, struct FluidModifierData *mmd); +void manta_ensure_invelocity(struct MANTA *fluid, struct FluidModifierData *mmd); +void manta_ensure_outflow(struct MANTA *fluid, struct FluidModifierData *mmd); +int manta_write_config(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_write_data(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_read_config(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_read_data(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_read_noise(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_read_mesh(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_read_particles(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_read_guiding(struct MANTA *fluid, + struct FluidModifierData *mmd, + int framenr, + bool sourceDomain); +int manta_update_liquid_structures(struct MANTA *fluid, + struct FluidModifierData *mmd, + int framenr); +int manta_update_mesh_structures(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_update_particle_structures(struct MANTA *fluid, + struct FluidModifierData *mmd, + int framenr); +int manta_bake_data(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_bake_noise(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_bake_mesh(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_bake_particles(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_bake_guiding(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +void manta_update_variables(struct MANTA *fluid, struct FluidModifierData *mmd); +int manta_get_frame(struct MANTA *fluid); +float manta_get_timestep(struct MANTA *fluid); +void manta_adapt_timestep(struct MANTA *fluid); +bool manta_needs_realloc(struct MANTA *fluid, struct FluidModifierData *mmd); + +/* Fluid accessors */ +size_t manta_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */); +size_t manta_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */); +float *manta_get_velocity_x(struct MANTA *fluid); +float *manta_get_velocity_y(struct MANTA *fluid); +float *manta_get_velocity_z(struct MANTA *fluid); +float *manta_get_ob_velocity_x(struct MANTA *fluid); +float *manta_get_ob_velocity_y(struct MANTA *fluid); +float *manta_get_ob_velocity_z(struct MANTA *fluid); +float *manta_get_guide_velocity_x(struct MANTA *fluid); +float *manta_get_guide_velocity_y(struct MANTA *fluid); +float *manta_get_guide_velocity_z(struct MANTA *fluid); +float *manta_get_in_velocity_x(struct MANTA *fluid); +float *manta_get_in_velocity_y(struct MANTA *fluid); +float *manta_get_in_velocity_z(struct MANTA *fluid); +float *manta_get_force_x(struct MANTA *fluid); +float *manta_get_force_y(struct MANTA *fluid); +float *manta_get_force_z(struct MANTA *fluid); +float *manta_get_phiguide_in(struct MANTA *fluid); +int *manta_get_num_obstacle(struct MANTA *fluid); +int *manta_get_num_guide(struct MANTA *fluid); +int manta_get_res_x(struct MANTA *fluid); +int manta_get_res_y(struct MANTA *fluid); +int manta_get_res_z(struct MANTA *fluid); +float *manta_get_phi_in(struct MANTA *fluid); +float *manta_get_phiobs_in(struct MANTA *fluid); +float *manta_get_phiout_in(struct MANTA *fluid); + +/* Smoke functions */ +void manta_smoke_export_script(struct MANTA *smoke, struct FluidModifierData *mmd); +void manta_smoke_export(struct MANTA *smoke, + float *dt, + float *dx, + float **dens, + float **react, + float **flame, + float **fuel, + float **heat, + float **vx, + float **vy, + float **vz, + float **r, + float **g, + float **b, + int **obstacles, + float **shadow); +void manta_smoke_turbulence_export(struct MANTA *smoke, + float **dens, + float **react, + float **flame, + float **fuel, + float **r, + float **g, + float **b, + float **tcu, + float **tcv, + float **tcw, + float **tcu2, + float **tcv2, + float **tcw2); +void manta_smoke_get_rgba(struct MANTA *smoke, float *data, int sequential); +void manta_smoke_turbulence_get_rgba(struct MANTA *smoke, float *data, int sequential); +void manta_smoke_get_rgba_from_density(struct MANTA *smoke, + float color[3], + float *data, + int sequential); +void manta_smoke_turbulence_get_rgba_from_density(struct MANTA *smoke, + float color[3], + float *data, + int sequential); +void manta_smoke_ensure_heat(struct MANTA *smoke, struct FluidModifierData *mmd); +void manta_smoke_ensure_fire(struct MANTA *smoke, struct FluidModifierData *mmd); +void manta_smoke_ensure_colors(struct MANTA *smoke, struct FluidModifierData *mmd); + +/* Smoke accessors */ +float *manta_smoke_get_density(struct MANTA *smoke); +float *manta_smoke_get_fuel(struct MANTA *smoke); +float *manta_smoke_get_react(struct MANTA *smoke); +float *manta_smoke_get_heat(struct MANTA *smoke); +float *manta_smoke_get_flame(struct MANTA *smoke); +float *manta_smoke_get_shadow(struct MANTA *fluid); +float *manta_smoke_get_color_r(struct MANTA *smoke); +float *manta_smoke_get_color_g(struct MANTA *smoke); +float *manta_smoke_get_color_b(struct MANTA *smoke); +int *manta_smoke_get_obstacle(struct MANTA *smoke); +float *manta_smoke_get_density_in(struct MANTA *smoke); +float *manta_smoke_get_heat_in(struct MANTA *smoke); +float *manta_smoke_get_color_r_in(struct MANTA *smoke); +float *manta_smoke_get_color_g_in(struct MANTA *smoke); +float *manta_smoke_get_color_b_in(struct MANTA *smoke); +float *manta_smoke_get_fuel_in(struct MANTA *smoke); +float *manta_smoke_get_react_in(struct MANTA *smoke); +float *manta_smoke_get_emission_in(struct MANTA *smoke); +int manta_smoke_has_heat(struct MANTA *smoke); +int manta_smoke_has_fuel(struct MANTA *smoke); +int manta_smoke_has_colors(struct MANTA *smoke); +float *manta_smoke_turbulence_get_density(struct MANTA *smoke); +float *manta_smoke_turbulence_get_fuel(struct MANTA *smoke); +float *manta_smoke_turbulence_get_react(struct MANTA *smoke); +float *manta_smoke_turbulence_get_color_r(struct MANTA *smoke); +float *manta_smoke_turbulence_get_color_g(struct MANTA *smoke); +float *manta_smoke_turbulence_get_color_b(struct MANTA *smoke); +float *manta_smoke_turbulence_get_flame(struct MANTA *smoke); +int manta_smoke_turbulence_has_fuel(struct MANTA *smoke); +int manta_smoke_turbulence_has_colors(struct MANTA *smoke); +void manta_smoke_turbulence_get_res(struct MANTA *smoke, int *res); +int manta_smoke_turbulence_get_cells(struct MANTA *smoke); + +/* Liquid functions */ +void manta_liquid_export_script(struct MANTA *smoke, struct FluidModifierData *mmd); +void manta_liquid_ensure_sndparts(struct MANTA *fluid, struct FluidModifierData *mmd); + +/* Liquid accessors */ +int manta_liquid_get_particle_res_x(struct MANTA *liquid); +int manta_liquid_get_particle_res_y(struct MANTA *liquid); +int manta_liquid_get_particle_res_z(struct MANTA *liquid); +int manta_liquid_get_mesh_res_x(struct MANTA *liquid); +int manta_liquid_get_mesh_res_y(struct MANTA *liquid); +int manta_liquid_get_mesh_res_z(struct MANTA *liquid); +int manta_liquid_get_particle_upres(struct MANTA *liquid); +int manta_liquid_get_mesh_upres(struct MANTA *liquid); +int manta_liquid_get_num_verts(struct MANTA *liquid); +int manta_liquid_get_num_normals(struct MANTA *liquid); +int manta_liquid_get_num_triangles(struct MANTA *liquid); +float manta_liquid_get_vertex_x_at(struct MANTA *liquid, int i); +float manta_liquid_get_vertex_y_at(struct MANTA *liquid, int i); +float manta_liquid_get_vertex_z_at(struct MANTA *liquid, int i); +float manta_liquid_get_normal_x_at(struct MANTA *liquid, int i); +float manta_liquid_get_normal_y_at(struct MANTA *liquid, int i); +float manta_liquid_get_normal_z_at(struct MANTA *liquid, int i); +int manta_liquid_get_triangle_x_at(struct MANTA *liquid, int i); +int manta_liquid_get_triangle_y_at(struct MANTA *liquid, int i); +int manta_liquid_get_triangle_z_at(struct MANTA *liquid, int i); +float manta_liquid_get_vertvel_x_at(struct MANTA *liquid, int i); +float manta_liquid_get_vertvel_y_at(struct MANTA *liquid, int i); +float manta_liquid_get_vertvel_z_at(struct MANTA *liquid, int i); +int manta_liquid_get_num_flip_particles(struct MANTA *liquid); +int manta_liquid_get_num_snd_particles(struct MANTA *liquid); +int manta_liquid_get_flip_particle_flag_at(struct MANTA *liquid, int i); +int manta_liquid_get_snd_particle_flag_at(struct MANTA *liquid, int i); +float manta_liquid_get_flip_particle_position_x_at(struct MANTA *liquid, int i); +float manta_liquid_get_flip_particle_position_y_at(struct MANTA *liquid, int i); +float manta_liquid_get_flip_particle_position_z_at(struct MANTA *liquid, int i); +float manta_liquid_get_flip_particle_velocity_x_at(struct MANTA *liquid, int i); +float manta_liquid_get_flip_particle_velocity_y_at(struct MANTA *liquid, int i); +float manta_liquid_get_flip_particle_velocity_z_at(struct MANTA *liquid, int i); +float manta_liquid_get_snd_particle_position_x_at(struct MANTA *liquid, int i); +float manta_liquid_get_snd_particle_position_y_at(struct MANTA *liquid, int i); +float manta_liquid_get_snd_particle_position_z_at(struct MANTA *liquid, int i); +float manta_liquid_get_snd_particle_velocity_x_at(struct MANTA *liquid, int i); +float manta_liquid_get_snd_particle_velocity_y_at(struct MANTA *liquid, int i); +float manta_liquid_get_snd_particle_velocity_z_at(struct MANTA *liquid, int i); + +#ifdef __cplusplus +} +#endif + +#endif /* MANTA_API_H_ */ diff --git a/intern/mantaflow/extern/manta_python_API.h b/intern/mantaflow/extern/manta_python_API.h new file mode 100644 index 00000000000..9ed795bedaf --- /dev/null +++ b/intern/mantaflow/extern/manta_python_API.h @@ -0,0 +1,45 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sebastian Barschkis (sebbas) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file mantaflow/extern/manta_python_API.h + * \ingroup mantaflow + */ + +#ifndef MANTA_PYTHON_API_H +#define MANTA_PYTHON_API_H + +#include "Python.h" + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject *Manta_initPython(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp new file mode 100644 index 00000000000..70b6f98d97b --- /dev/null +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -0,0 +1,2679 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sebastian Barschkis (sebbas) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file mantaflow/intern/MANTA.cpp + * \ingroup mantaflow + */ + +#include +#include +#include +#include +#include + +#include "MANTA_main.h" +#include "manta.h" +#include "Python.h" +#include "fluid_script.h" +#include "smoke_script.h" +#include "liquid_script.h" + +#include "BLI_path_util.h" +#include "BLI_utildefines.h" +#include "BLI_fileops.h" + +#include "DNA_scene_types.h" +#include "DNA_modifier_types.h" +#include "DNA_fluid_types.h" + +std::atomic MANTA::mantaInitialized(false); +std::atomic MANTA::solverID(0); +int MANTA::with_debug(0); + +MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) +{ + if (with_debug) + std::cout << "MANTA: " << mCurrentID << " with res(" << res[0] << ", " << res[1] << ", " + << res[2] << ")" << std::endl; + + mmd->domain->fluid = this; + + mUsingLiquid = (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID); + mUsingSmoke = (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS); + mUsingHeat = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) && mUsingSmoke; + mUsingFire = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) && mUsingSmoke; + mUsingColors = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) && mUsingSmoke; + mUsingNoise = (mmd->domain->flags & FLUID_DOMAIN_USE_NOISE) && mUsingSmoke; + mUsingFractions = (mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS) && mUsingLiquid; + mUsingDrops = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && mUsingLiquid; + mUsingBubbles = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) && mUsingLiquid; + mUsingFloats = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) && mUsingLiquid; + mUsingTracers = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) && mUsingLiquid; + mUsingMesh = (mmd->domain->flags & FLUID_DOMAIN_USE_MESH) && mUsingLiquid; + mUsingMVel = (mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) && mUsingLiquid; + mUsingObstacle = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE); + mUsingInvel = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL); + mUsingOutflow = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW); + mUsingGuiding = (mmd->domain->flags & FLUID_DOMAIN_USE_GUIDING); + + // Simulation constants + mTempAmb = 0; // TODO: Maybe use this later for buoyancy calculation + mResX = res[0]; + mResY = res[1]; + mResZ = res[2]; + mMaxRes = MAX3(mResX, mResY, mResZ); + mConstantScaling = 64.0f / mMaxRes; + mConstantScaling = (mConstantScaling < 1.0f) ? 1.0f : mConstantScaling; + mTotalCells = mResX * mResY * mResZ; + mResGuiding = mmd->domain->res; + + // Smoke low res grids + mDensity = NULL; + mShadow = NULL; + mHeat = NULL; + mVelocityX = NULL; + mVelocityY = NULL; + mVelocityZ = NULL; + mForceX = NULL; + mForceY = NULL; + mForceZ = NULL; + mFlame = NULL; + mFuel = NULL; + mReact = NULL; + mColorR = NULL; + mColorG = NULL; + mColorB = NULL; + mObstacle = NULL; + mDensityIn = NULL; + mHeatIn = NULL; + mColorRIn = NULL; + mColorGIn = NULL; + mColorBIn = NULL; + mFuelIn = NULL; + mReactIn = NULL; + mEmissionIn = NULL; + + // Smoke high res grids + mDensityHigh = NULL; + mFlameHigh = NULL; + mFuelHigh = NULL; + mReactHigh = NULL; + mColorRHigh = NULL; + mColorGHigh = NULL; + mColorBHigh = NULL; + mTextureU = NULL; + mTextureV = NULL; + mTextureW = NULL; + mTextureU2 = NULL; + mTextureV2 = NULL; + mTextureW2 = NULL; + + // Fluid low res grids + mPhiIn = NULL; + mPhiOutIn = NULL; + mPhi = NULL; + + // Mesh + mMeshNodes = NULL; + mMeshTriangles = NULL; + mMeshVelocities = NULL; + + // Fluid obstacle + mPhiObsIn = NULL; + mNumObstacle = NULL; + mObVelocityX = NULL; + mObVelocityY = NULL; + mObVelocityZ = NULL; + + // Fluid guiding + mPhiGuideIn = NULL; + mNumGuide = NULL; + mGuideVelocityX = NULL; + mGuideVelocityY = NULL; + mGuideVelocityZ = NULL; + + // Fluid initial velocity + mInVelocityX = NULL; + mInVelocityY = NULL; + mInVelocityZ = NULL; + + // Secondary particles + mFlipParticleData = NULL; + mFlipParticleVelocity = NULL; + mSndParticleData = NULL; + mSndParticleVelocity = NULL; + mSndParticleLife = NULL; + + // Only start Mantaflow once. No need to start whenever new FLUID objected is allocated + if (!mantaInitialized) + initializeMantaflow(); + + // Initialize Mantaflow variables in Python + // Liquid + if (mUsingLiquid) { + initDomain(mmd); + initLiquid(mmd); + if (mUsingObstacle) + initObstacle(mmd); + if (mUsingInvel) + initInVelocity(mmd); + if (mUsingOutflow) + initOutflow(mmd); + + if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) { + mUpresParticle = mmd->domain->particle_scale; + mResXParticle = mUpresParticle * mResX; + mResYParticle = mUpresParticle * mResY; + mResZParticle = mUpresParticle * mResZ; + mTotalCellsParticles = mResXParticle * mResYParticle * mResZParticle; + + initSndParts(mmd); + initLiquidSndParts(mmd); + } + + if (mUsingMesh) { + mUpresMesh = mmd->domain->mesh_scale; + mResXMesh = mUpresMesh * mResX; + mResYMesh = mUpresMesh * mResY; + mResZMesh = mUpresMesh * mResZ; + mTotalCellsMesh = mResXMesh * mResYMesh * mResZMesh; + + // Initialize Mantaflow variables in Python + initMesh(mmd); + initLiquidMesh(mmd); + } + + if (mUsingGuiding) { + mResGuiding = (mmd->domain->guiding_parent) ? mmd->domain->guide_res : mmd->domain->res; + initGuiding(mmd); + } + if (mUsingFractions) { + initFractions(mmd); + } + } + + // Smoke + if (mUsingSmoke) { + initDomain(mmd); + initSmoke(mmd); + if (mUsingHeat) + initHeat(mmd); + if (mUsingFire) + initFire(mmd); + if (mUsingColors) + initColors(mmd); + if (mUsingObstacle) + initObstacle(mmd); + if (mUsingInvel) + initInVelocity(mmd); + if (mUsingOutflow) + initOutflow(mmd); + + if (mUsingGuiding) { + mResGuiding = (mmd->domain->guiding_parent) ? mmd->domain->guide_res : mmd->domain->res; + initGuiding(mmd); + } + + if (mUsingNoise) { + int amplify = mmd->domain->noise_scale; + mResXNoise = amplify * mResX; + mResYNoise = amplify * mResY; + mResZNoise = amplify * mResZ; + mTotalCellsHigh = mResXNoise * mResYNoise * mResZNoise; + + // Initialize Mantaflow variables in Python + initNoise(mmd); + initSmokeNoise(mmd); + if (mUsingFire) + initFireHigh(mmd); + if (mUsingColors) + initColorsHigh(mmd); + } + } + updatePointers(); +} + +void MANTA::initDomain(FluidModifierData *mmd) +{ + // Vector will hold all python commands that are to be executed + std::vector pythonCommands; + + // Set manta debug level first + pythonCommands.push_back(manta_import + manta_debuglevel); + + std::ostringstream ss; + ss << "set_manta_debuglevel(" << with_debug << ")"; + pythonCommands.push_back(ss.str()); + + // Now init basic fluid domain + std::string tmpString = fluid_variables + fluid_solver + fluid_alloc + fluid_cache_helper + + fluid_bake_multiprocessing + fluid_bake_data + fluid_bake_noise + + fluid_bake_mesh + fluid_bake_particles + fluid_bake_guiding + + fluid_file_import + fluid_file_export + fluid_save_data + + fluid_load_data + fluid_pre_step + fluid_post_step + + fluid_adapt_time_step + fluid_time_stepping; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + runPythonString(pythonCommands); +} + +void MANTA::initNoise(FluidModifierData *mmd) +{ + std::vector pythonCommands; + std::string tmpString = fluid_variables_noise + fluid_solver_noise; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); +} + +void MANTA::initSmoke(FluidModifierData *mmd) +{ + std::vector pythonCommands; + std::string tmpString = smoke_variables + smoke_alloc + smoke_adaptive_step + smoke_save_data + + smoke_load_data + smoke_step; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); +} + +void MANTA::initSmokeNoise(FluidModifierData *mmd) +{ + std::vector pythonCommands; + std::string tmpString = smoke_variables_noise + smoke_alloc_noise + smoke_wavelet_noise + + smoke_save_noise + smoke_load_noise + smoke_step_noise; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingNoise = true; +} + +void MANTA::initHeat(FluidModifierData *mmd) +{ + if (!mHeat) { + std::vector pythonCommands; + std::string tmpString = smoke_alloc_heat + smoke_with_heat; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingHeat = true; + } +} + +void MANTA::initFire(FluidModifierData *mmd) +{ + if (!mFuel) { + std::vector pythonCommands; + std::string tmpString = smoke_alloc_fire + smoke_with_fire; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingFire = true; + } +} + +void MANTA::initFireHigh(FluidModifierData *mmd) +{ + if (!mFuelHigh) { + std::vector pythonCommands; + std::string tmpString = smoke_alloc_fire_noise + smoke_with_fire; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingFire = true; + } +} + +void MANTA::initColors(FluidModifierData *mmd) +{ + if (!mColorR) { + std::vector pythonCommands; + std::string tmpString = smoke_alloc_colors + smoke_init_colors + smoke_with_colors; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingColors = true; + } +} + +void MANTA::initColorsHigh(FluidModifierData *mmd) +{ + if (!mColorRHigh) { + std::vector pythonCommands; + std::string tmpString = smoke_alloc_colors_noise + smoke_init_colors_noise + smoke_with_colors; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingColors = true; + } +} + +void MANTA::initLiquid(FluidModifierData *mmd) +{ + if (!mPhiIn) { + std::vector pythonCommands; + std::string tmpString = liquid_variables + liquid_alloc + liquid_init_phi + liquid_save_data + + liquid_save_flip + liquid_load_data + liquid_load_flip + + liquid_adaptive_step + liquid_step; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingLiquid = true; + } +} + +void MANTA::initMesh(FluidModifierData *mmd) +{ + std::vector pythonCommands; + std::string tmpString = fluid_variables_mesh + fluid_solver_mesh + liquid_load_mesh + + liquid_load_meshvel; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingMesh = true; +} + +void MANTA::initLiquidMesh(FluidModifierData *mmd) +{ + std::vector pythonCommands; + std::string tmpString = liquid_alloc_mesh + liquid_step_mesh + liquid_save_mesh + + liquid_save_meshvel; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingMesh = true; +} + +void MANTA::initObstacle(FluidModifierData *mmd) +{ + if (!mPhiObsIn) { + std::vector pythonCommands; + std::string tmpString = fluid_alloc_obstacle + fluid_with_obstacle; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingObstacle = true; + } +} + +void MANTA::initGuiding(FluidModifierData *mmd) +{ + if (!mPhiGuideIn) { + std::vector pythonCommands; + std::string tmpString = fluid_variables_guiding + fluid_solver_guiding + fluid_alloc_guiding + + fluid_save_guiding + fluid_load_vel + fluid_load_guiding; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingGuiding = true; + } +} + +void MANTA::initFractions(FluidModifierData *mmd) +{ + std::vector pythonCommands; + std::string tmpString = fluid_alloc_fractions + fluid_with_fractions; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingFractions = true; +} + +void MANTA::initInVelocity(FluidModifierData *mmd) +{ + if (!mInVelocityX) { + std::vector pythonCommands; + std::string tmpString = fluid_alloc_invel + fluid_with_invel; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingInvel = true; + } +} + +void MANTA::initOutflow(FluidModifierData *mmd) +{ + if (!mPhiOutIn) { + std::vector pythonCommands; + std::string tmpString = fluid_alloc_outflow + fluid_with_outflow; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingOutflow = true; + } +} + +void MANTA::initSndParts(FluidModifierData *mmd) +{ + std::vector pythonCommands; + std::string tmpString = fluid_variables_particles + fluid_solver_particles + + fluid_load_particles + fluid_save_particles; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); +} + +void MANTA::initLiquidSndParts(FluidModifierData *mmd) +{ + if (!mSndParticleData) { + std::vector pythonCommands; + std::string tmpString = fluid_alloc_sndparts + liquid_alloc_particles + + liquid_variables_particles + liquid_step_particles + + fluid_with_sndparts + liquid_load_particles + liquid_save_particles; + std::string finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + } +} + +MANTA::~MANTA() +{ + if (with_debug) + std::cout << "~FLUID: " << mCurrentID << " with res(" << mResX << ", " << mResY << ", " + << mResZ << ")" << std::endl; + + // Destruction string for Python + std::string tmpString = ""; + std::vector pythonCommands; + + tmpString += manta_import; + tmpString += fluid_delete_all; + + // Leave out mmd argument in parseScript since only looking up IDs + std::string finalString = parseScript(tmpString); + pythonCommands.push_back(finalString); + runPythonString(pythonCommands); +} + +void MANTA::runPythonString(std::vector commands) +{ + PyGILState_STATE gilstate = PyGILState_Ensure(); + for (std::vector::iterator it = commands.begin(); it != commands.end(); ++it) { + std::string command = *it; + +#ifdef WIN32 + // special treatment for windows when running python code + size_t cmdLength = command.length(); + char *buffer = new char[cmdLength + 1]; + memcpy(buffer, command.data(), cmdLength); + + buffer[cmdLength] = '\0'; + PyRun_SimpleString(buffer); + delete[] buffer; +#else + PyRun_SimpleString(command.c_str()); +#endif + } + PyGILState_Release(gilstate); +} + +void MANTA::initializeMantaflow() +{ + if (with_debug) + std::cout << "Initializing Mantaflow" << std::endl; + + std::string filename = "manta_scene_" + std::to_string(mCurrentID) + ".py"; + std::vector fill = std::vector(); + + // Initialize extension classes and wrappers + srand(0); + PyGILState_STATE gilstate = PyGILState_Ensure(); + Pb::setup(filename, fill); // Namespace from Mantaflow (registry) + PyGILState_Release(gilstate); + mantaInitialized = true; +} + +void MANTA::terminateMantaflow() +{ + if (with_debug) + std::cout << "Terminating Mantaflow" << std::endl; + + PyGILState_STATE gilstate = PyGILState_Ensure(); + Pb::finalize(); // Namespace from Mantaflow (registry) + PyGILState_Release(gilstate); + mantaInitialized = false; +} + +std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *mmd) +{ + std::ostringstream ss; + bool is2D = false; + int tmpVar; + float tmpFloat; + + if (varName == "ID") { + ss << mCurrentID; + return ss.str(); + } + + if (!mmd) { + if (with_debug) + std::cout << "Invalid modifier data in getRealValue()" << std::endl; + ss << "ERROR - INVALID MODIFIER DATA"; + return ss.str(); + } + + is2D = (mmd->domain->solver_res == 2); + + if (varName == "USING_SMOKE") + ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) ? "True" : "False"); + else if (varName == "USING_LIQUID") + ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) ? "True" : "False"); + else if (varName == "USING_COLORS") + ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS ? "True" : "False"); + else if (varName == "USING_HEAT") + ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT ? "True" : "False"); + else if (varName == "USING_FIRE") + ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE ? "True" : "False"); + else if (varName == "USING_NOISE") + ss << (mmd->domain->flags & FLUID_DOMAIN_USE_NOISE ? "True" : "False"); + else if (varName == "USING_OBSTACLE") + ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE ? "True" : "False"); + else if (varName == "USING_GUIDING") + ss << (mmd->domain->flags & FLUID_DOMAIN_USE_GUIDING ? "True" : "False"); + else if (varName == "USING_INVEL") + ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL ? "True" : "False"); + else if (varName == "USING_OUTFLOW") + ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW ? "True" : "False"); + else if (varName == "USING_LOG_DISSOLVE") + ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG ? "True" : "False"); + else if (varName == "USING_DISSOLVE") + ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE ? "True" : "False"); + else if (varName == "SOLVER_DIM") + ss << mmd->domain->solver_res; + else if (varName == "DO_OPEN") { + tmpVar = (FLUID_DOMAIN_BORDER_BACK | FLUID_DOMAIN_BORDER_FRONT | FLUID_DOMAIN_BORDER_LEFT | + FLUID_DOMAIN_BORDER_RIGHT | FLUID_DOMAIN_BORDER_BOTTOM | FLUID_DOMAIN_BORDER_TOP); + ss << (((mmd->domain->border_collisions & tmpVar) == tmpVar) ? "False" : "True"); + } + else if (varName == "BOUND_CONDITIONS") { + if (mmd->domain->solver_res == 2) { + if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0) + ss << "x"; + if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0) + ss << "X"; + if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0) + ss << "y"; + if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0) + ss << "Y"; + } + if (mmd->domain->solver_res == 3) { + if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0) + ss << "x"; + if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0) + ss << "X"; + if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0) + ss << "y"; + if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0) + ss << "Y"; + if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BOTTOM) == 0) + ss << "z"; + if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_TOP) == 0) + ss << "Z"; + } + } + else if (varName == "BOUNDARY_WIDTH") + ss << mmd->domain->boundary_width; + else if (varName == "RES") + ss << mMaxRes; + else if (varName == "RESX") + ss << mResX; + else if (varName == "RESY") + if (is2D) { + ss << mResZ; + } + else { + ss << mResY; + } + else if (varName == "RESZ") { + if (is2D) { + ss << 1; + } + else { + ss << mResZ; + } + } + else if (varName == "FRAME_LENGTH") + ss << mmd->domain->frame_length; + else if (varName == "CFL") + ss << mmd->domain->cfl_condition; + else if (varName == "DT") + ss << mmd->domain->dt; + else if (varName == "TIMESTEPS_MIN") + ss << mmd->domain->timesteps_minimum; + else if (varName == "TIMESTEPS_MAX") + ss << mmd->domain->timesteps_maximum; + else if (varName == "TIME_TOTAL") + ss << mmd->domain->time_total; + else if (varName == "TIME_PER_FRAME") + ss << mmd->domain->time_per_frame; + else if (varName == "VORTICITY") + ss << mmd->domain->vorticity / mConstantScaling; + else if (varName == "FLAME_VORTICITY") + ss << mmd->domain->flame_vorticity / mConstantScaling; + else if (varName == "NOISE_SCALE") + ss << mmd->domain->noise_scale; + else if (varName == "MESH_SCALE") + ss << mmd->domain->mesh_scale; + else if (varName == "PARTICLE_SCALE") + ss << mmd->domain->particle_scale; + else if (varName == "NOISE_RESX") + ss << mResXNoise; + else if (varName == "NOISE_RESY") { + if (is2D) { + ss << mResZNoise; + } + else { + ss << mResYNoise; + } + } + else if (varName == "NOISE_RESZ") { + if (is2D) { + ss << 1; + } + else { + ss << mResZNoise; + } + } + else if (varName == "MESH_RESX") + ss << mResXMesh; + else if (varName == "MESH_RESY") { + if (is2D) { + ss << mResZMesh; + } + else { + ss << mResYMesh; + } + } + else if (varName == "MESH_RESZ") { + if (is2D) { + ss << 1; + } + else { + ss << mResZMesh; + } + } + else if (varName == "PARTICLE_RESX") + ss << mResXParticle; + else if (varName == "PARTICLE_RESY") { + if (is2D) { + ss << mResZParticle; + } + else { + ss << mResYParticle; + } + } + else if (varName == "PARTICLE_RESZ") { + if (is2D) { + ss << 1; + } + else { + ss << mResZParticle; + } + } + else if (varName == "GUIDING_RESX") + ss << mResGuiding[0]; + else if (varName == "GUIDING_RESY") { + if (is2D) { + ss << mResGuiding[2]; + } + else { + ss << mResGuiding[1]; + } + } + else if (varName == "GUIDING_RESZ") { + if (is2D) { + ss << 1; + } + else { + ss << mResGuiding[2]; + } + } + else if (varName == "MIN_RESX") + ss << mmd->domain->res_min[0]; + else if (varName == "MIN_RESY") + ss << mmd->domain->res_min[1]; + else if (varName == "MIN_RESZ") + ss << mmd->domain->res_min[2]; + else if (varName == "BASE_RESX") + ss << mmd->domain->base_res[0]; + else if (varName == "BASE_RESY") + ss << mmd->domain->base_res[1]; + else if (varName == "BASE_RESZ") + ss << mmd->domain->base_res[2]; + else if (varName == "WLT_STR") + ss << mmd->domain->noise_strength; + else if (varName == "NOISE_POSSCALE") + ss << mmd->domain->noise_pos_scale; + else if (varName == "NOISE_TIMEANIM") + ss << mmd->domain->noise_time_anim; + else if (varName == "COLOR_R") + ss << mmd->domain->active_color[0]; + else if (varName == "COLOR_G") + ss << mmd->domain->active_color[1]; + else if (varName == "COLOR_B") + ss << mmd->domain->active_color[2]; + else if (varName == "BUOYANCY_ALPHA") + ss << mmd->domain->alpha; + else if (varName == "BUOYANCY_BETA") + ss << mmd->domain->beta; + else if (varName == "DISSOLVE_SPEED") + ss << mmd->domain->diss_speed; + else if (varName == "BURNING_RATE") + ss << mmd->domain->burning_rate; + else if (varName == "FLAME_SMOKE") + ss << mmd->domain->flame_smoke; + else if (varName == "IGNITION_TEMP") + ss << mmd->domain->flame_ignition; + else if (varName == "MAX_TEMP") + ss << mmd->domain->flame_max_temp; + else if (varName == "FLAME_SMOKE_COLOR_X") + ss << mmd->domain->flame_smoke_color[0]; + else if (varName == "FLAME_SMOKE_COLOR_Y") + ss << mmd->domain->flame_smoke_color[1]; + else if (varName == "FLAME_SMOKE_COLOR_Z") + ss << mmd->domain->flame_smoke_color[2]; + else if (varName == "CURRENT_FRAME") + ss << mmd->time; + else if (varName == "END_FRAME") + ss << mmd->domain->cache_frame_end; + else if (varName == "SIMULATION_METHOD") { + if (mmd->domain->simulation_method & FLUID_DOMAIN_METHOD_FLIP) { + ss << "'FLIP'"; + } + else if (mmd->domain->simulation_method & FLUID_DOMAIN_METHOD_APIC) { + ss << "'APIC'"; + } + else { + ss << "'NONE'"; + } + } + else if (varName == "FLIP_RATIO") + ss << mmd->domain->flip_ratio; + else if (varName == "PARTICLE_RANDOMNESS") + ss << mmd->domain->particle_randomness; + else if (varName == "PARTICLE_NUMBER") + ss << mmd->domain->particle_number; + else if (varName == "PARTICLE_MINIMUM") + ss << mmd->domain->particle_minimum; + else if (varName == "PARTICLE_MAXIMUM") + ss << mmd->domain->particle_maximum; + else if (varName == "PARTICLE_RADIUS") + ss << mmd->domain->particle_radius; + else if (varName == "FRACTIONS_THRESHOLD") + ss << mmd->domain->fractions_threshold; + else if (varName == "MESH_CONCAVE_UPPER") + ss << mmd->domain->mesh_concave_upper; + else if (varName == "MESH_CONCAVE_LOWER") + ss << mmd->domain->mesh_concave_lower; + else if (varName == "MESH_PARTICLE_RADIUS") + ss << mmd->domain->mesh_particle_radius; + else if (varName == "MESH_SMOOTHEN_POS") + ss << mmd->domain->mesh_smoothen_pos; + else if (varName == "MESH_SMOOTHEN_NEG") + ss << mmd->domain->mesh_smoothen_neg; + else if (varName == "USING_MESH") + ss << (mmd->domain->flags & FLUID_DOMAIN_USE_MESH ? "True" : "False"); + else if (varName == "USING_IMPROVED_MESH") + ss << (mmd->domain->mesh_generator == FLUID_DOMAIN_MESH_IMPROVED ? "True" : "False"); + else if (varName == "PARTICLE_BAND_WIDTH") + ss << mmd->domain->particle_band_width; + else if (varName == "SNDPARTICLE_TAU_MIN_WC") + ss << mmd->domain->sndparticle_tau_min_wc; + else if (varName == "SNDPARTICLE_TAU_MAX_WC") + ss << mmd->domain->sndparticle_tau_max_wc; + else if (varName == "SNDPARTICLE_TAU_MIN_TA") + ss << mmd->domain->sndparticle_tau_min_ta; + else if (varName == "SNDPARTICLE_TAU_MAX_TA") + ss << mmd->domain->sndparticle_tau_max_ta; + else if (varName == "SNDPARTICLE_TAU_MIN_K") + ss << mmd->domain->sndparticle_tau_min_k; + else if (varName == "SNDPARTICLE_TAU_MAX_K") + ss << mmd->domain->sndparticle_tau_max_k; + else if (varName == "SNDPARTICLE_K_WC") + ss << mmd->domain->sndparticle_k_wc; + else if (varName == "SNDPARTICLE_K_TA") + ss << mmd->domain->sndparticle_k_ta; + else if (varName == "SNDPARTICLE_K_B") + ss << mmd->domain->sndparticle_k_b; + else if (varName == "SNDPARTICLE_K_D") + ss << mmd->domain->sndparticle_k_d; + else if (varName == "SNDPARTICLE_L_MIN") + ss << mmd->domain->sndparticle_l_min; + else if (varName == "SNDPARTICLE_L_MAX") + ss << mmd->domain->sndparticle_l_max; + else if (varName == "SNDPARTICLE_BOUNDARY_DELETE") + ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_DELETE); + else if (varName == "SNDPARTICLE_BOUNDARY_PUSHOUT") + ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_PUSHOUT); + else if (varName == "SNDPARTICLE_POTENTIAL_RADIUS") + ss << mmd->domain->sndparticle_potential_radius; + else if (varName == "SNDPARTICLE_UPDATE_RADIUS") + ss << mmd->domain->sndparticle_update_radius; + else if (varName == "LIQUID_SURFACE_TENSION") + ss << mmd->domain->surface_tension; + else if (varName == "FLUID_VISCOSITY") + ss << mmd->domain->viscosity_base * pow(10.0f, -mmd->domain->viscosity_exponent); + else if (varName == "FLUID_DOMAIN_SIZE") { + tmpFloat = MAX3( + mmd->domain->global_size[0], mmd->domain->global_size[1], mmd->domain->global_size[2]); + ss << tmpFloat; + } + else if (varName == "SNDPARTICLE_TYPES") { + if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) { + ss << "PtypeSpray"; + } + if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) { + if (!ss.str().empty()) + ss << "|"; + ss << "PtypeBubble"; + } + if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) { + if (!ss.str().empty()) + ss << "|"; + ss << "PtypeFoam"; + } + if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) { + if (!ss.str().empty()) + ss << "|"; + ss << "PtypeTracer"; + } + if (ss.str().empty()) + ss << "0"; + } + else if (varName == "USING_SNDPARTS") { + tmpVar = (FLUID_DOMAIN_PARTICLE_SPRAY | FLUID_DOMAIN_PARTICLE_BUBBLE | + FLUID_DOMAIN_PARTICLE_FOAM | FLUID_DOMAIN_PARTICLE_TRACER); + ss << (((mmd->domain->particle_type & tmpVar)) ? "True" : "False"); + } + else if (varName == "GUIDING_ALPHA") + ss << mmd->domain->guiding_alpha; + else if (varName == "GUIDING_BETA") + ss << mmd->domain->guiding_beta; + else if (varName == "GUIDING_FACTOR") + ss << mmd->domain->guiding_vel_factor; + else if (varName == "GRAVITY_X") + ss << mmd->domain->gravity[0]; + else if (varName == "GRAVITY_Y") + ss << mmd->domain->gravity[1]; + else if (varName == "GRAVITY_Z") + ss << mmd->domain->gravity[2]; + else if (varName == "CACHE_DIR") + ss << mmd->domain->cache_directory; + else if (varName == "USING_ADAPTIVETIME") + ss << (mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME ? "True" : "False"); + else if (varName == "USING_SPEEDVECTORS") + ss << (mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS ? "True" : "False"); + else if (varName == "USING_FRACTIONS") + ss << (mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS ? "True" : "False"); + else + std::cout << "ERROR: Unknown option: " << varName << std::endl; + return ss.str(); +} + +std::string MANTA::parseLine(const std::string &line, FluidModifierData *mmd) +{ + if (line.size() == 0) + return ""; + std::string res = ""; + int currPos = 0, start_del = 0, end_del = -1; + bool readingVar = false; + const char delimiter = '$'; + while (currPos < line.size()) { + if (line[currPos] == delimiter && !readingVar) { + readingVar = true; + start_del = currPos + 1; + res += line.substr(end_del + 1, currPos - end_del - 1); + } + else if (line[currPos] == delimiter && readingVar) { + readingVar = false; + end_del = currPos; + res += getRealValue(line.substr(start_del, currPos - start_del), mmd); + } + currPos++; + } + res += line.substr(end_del + 1, line.size() - end_del); + return res; +} + +std::string MANTA::parseScript(const std::string &setup_string, FluidModifierData *mmd) +{ + std::istringstream f(setup_string); + std::ostringstream res; + std::string line = ""; + while (getline(f, line)) { + res << parseLine(line, mmd) << "\n"; + } + return res.str(); +} + +static std::string getCacheFileEnding(char cache_format) +{ + if (MANTA::with_debug) + std::cout << "MANTA::getCacheFileEnding()" << std::endl; + + switch (cache_format) { + case FLUID_DOMAIN_FILE_UNI: + return ".uni"; + case FLUID_DOMAIN_FILE_OPENVDB: + return ".vdb"; + case FLUID_DOMAIN_FILE_RAW: + return ".raw"; + case FLUID_DOMAIN_FILE_BIN_OBJECT: + return ".bobj.gz"; + case FLUID_DOMAIN_FILE_OBJECT: + return ".obj"; + default: + if (MANTA::with_debug) + std::cout << "Error: Could not find file extension" << std::endl; + return ".uni"; + } +} + +int MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr) +{ + if (MANTA::with_debug) + std::cout << "MANTA::updateFlipStructures()" << std::endl; + + // Ensure empty data structures at start + if (mFlipParticleData) + mFlipParticleData->clear(); + if (mFlipParticleVelocity) + mFlipParticleVelocity->clear(); + + if (!mUsingLiquid) + return 0; + if (BLI_path_is_rel(mmd->domain->cache_directory)) + return 0; + + std::ostringstream ss; + char cacheDir[FILE_MAX], targetFile[FILE_MAX]; + cacheDir[0] = '\0'; + targetFile[0] = '\0'; + + std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + BLI_path_join( + cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL); + + // TODO (sebbas): Use pp_xl and pVel_xl when using upres simulation? + + ss << "pp_####" << pformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + + if (BLI_exists(targetFile)) { + updateParticlesFromFile(targetFile, false, false); + } + + ss.str(""); + ss << "pVel_####" << pformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + + if (BLI_exists(targetFile)) { + updateParticlesFromFile(targetFile, false, true); + } + return 1; +} + +int MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr) +{ + if (MANTA::with_debug) + std::cout << "MANTA::updateMeshStructures()" << std::endl; + + if (!mUsingMesh) + return 0; + if (BLI_path_is_rel(mmd->domain->cache_directory)) + return 0; + + // Ensure empty data structures at start + if (mMeshNodes) + mMeshNodes->clear(); + if (mMeshTriangles) + mMeshTriangles->clear(); + if (mMeshVelocities) + mMeshVelocities->clear(); + + std::ostringstream ss; + char cacheDir[FILE_MAX], targetFile[FILE_MAX]; + cacheDir[0] = '\0'; + targetFile[0] = '\0'; + + std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format); + std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + BLI_path_join( + cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL); + + ss << "lMesh_####" << mformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + + if (BLI_exists(targetFile)) { + updateMeshFromFile(targetFile); + } + + if (mUsingMVel) { + ss.str(""); + ss << "lVelMesh_####" << dformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + + if (BLI_exists(targetFile)) { + updateMeshFromFile(targetFile); + } + } + return 1; +} + +int MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr) +{ + if (MANTA::with_debug) + std::cout << "MANTA::updateParticleStructures()" << std::endl; + + if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers) + return 0; + if (BLI_path_is_rel(mmd->domain->cache_directory)) + return 0; + + // Ensure empty data structures at start + if (mSndParticleData) + mSndParticleData->clear(); + if (mSndParticleVelocity) + mSndParticleVelocity->clear(); + if (mSndParticleLife) + mSndParticleLife->clear(); + + std::ostringstream ss; + char cacheDir[FILE_MAX], targetFile[FILE_MAX]; + cacheDir[0] = '\0'; + targetFile[0] = '\0'; + + std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + BLI_path_join( + cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL); + + ss << "ppSnd_####" << pformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + + if (BLI_exists(targetFile)) { + updateParticlesFromFile(targetFile, true, false); + } + + ss.str(""); + ss << "pVelSnd_####" << pformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + + if (BLI_exists(targetFile)) { + updateParticlesFromFile(targetFile, true, true); + } + + ss.str(""); + ss << "pLifeSnd_####" << pformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + + if (BLI_exists(targetFile)) { + updateParticlesFromFile(targetFile, true, false); + } + return 1; +} + +/* Dirty hack: Needed to format paths from python code that is run via PyRun_SimpleString */ +static std::string escapeSlashes(std::string const &s) +{ + std::string result = ""; + for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i) { + unsigned char c = *i; + if (c == '\\') + result += "\\\\"; + else + result += c; + } + return result; +} + +int MANTA::writeConfiguration(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::writeConfiguration()" << std::endl; + + FluidDomainSettings *mds = mmd->domain; + std::ostringstream ss; + char cacheDir[FILE_MAX], targetFile[FILE_MAX]; + ; + cacheDir[0] = '\0'; + targetFile[0] = '\0'; + + std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + + BLI_path_join( + cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL); + BLI_path_make_safe(cacheDir); + BLI_dir_create_recursive(cacheDir); /* Create 'config' subdir if it does not exist already */ + + ss.str(""); + ss << "config_####" << dformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + + gzFile gzf = gzopen(targetFile, "wb1"); // do some compression + if (!gzf) + std::cerr << "writeConfiguration: can't open file: " << targetFile << std::endl; + + gzwrite(gzf, &mds->active_fields, sizeof(int)); + gzwrite(gzf, &mds->res, 3 * sizeof(int)); + gzwrite(gzf, &mds->dx, sizeof(float)); + gzwrite(gzf, &mds->dt, sizeof(float)); + gzwrite(gzf, &mds->p0, 3 * sizeof(float)); + gzwrite(gzf, &mds->p1, 3 * sizeof(float)); + gzwrite(gzf, &mds->dp0, 3 * sizeof(float)); + gzwrite(gzf, &mds->shift, 3 * sizeof(int)); + gzwrite(gzf, &mds->obj_shift_f, 3 * sizeof(float)); + gzwrite(gzf, &mds->obmat, 16 * sizeof(float)); + gzwrite(gzf, &mds->base_res, 3 * sizeof(int)); + gzwrite(gzf, &mds->res_min, 3 * sizeof(int)); + gzwrite(gzf, &mds->res_max, 3 * sizeof(int)); + gzwrite(gzf, &mds->active_color, 3 * sizeof(float)); + + gzclose(gzf); + + return 1; +} + +int MANTA::writeData(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::writeData()" << std::endl; + + std::ostringstream ss; + std::vector pythonCommands; + + char cacheDirData[FILE_MAX]; + cacheDirData[0] = '\0'; + + std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + + BLI_path_join(cacheDirData, + sizeof(cacheDirData), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_DATA, + NULL); + BLI_path_make_safe(cacheDirData); + + ss.str(""); + ss << "fluid_save_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', " << framenr + << ", '" << dformat << "')"; + pythonCommands.push_back(ss.str()); + + if (mUsingSmoke) { + ss.str(""); + ss << "smoke_save_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', " + << framenr << ", '" << dformat << "')"; + pythonCommands.push_back(ss.str()); + } + if (mUsingLiquid) { + ss.str(""); + ss << "liquid_save_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', " + << framenr << ", '" << dformat << "')"; + pythonCommands.push_back(ss.str()); + ss.str(""); + ss << "liquid_save_flip_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', " + << framenr << ", '" << pformat << "')"; + pythonCommands.push_back(ss.str()); + } + runPythonString(pythonCommands); + return 1; +} + +int MANTA::readConfiguration(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::readConfiguration()" << std::endl; + + FluidDomainSettings *mds = mmd->domain; + std::ostringstream ss; + char cacheDir[FILE_MAX], targetFile[FILE_MAX]; + cacheDir[0] = '\0'; + targetFile[0] = '\0'; + float dummy; + + std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + + BLI_path_join( + cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL); + BLI_path_make_safe(cacheDir); + + ss.str(""); + ss << "config_####" << dformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + + if (!BLI_exists(targetFile)) + return 0; + + gzFile gzf = gzopen(targetFile, "rb"); // do some compression + if (!gzf) + std::cerr << "readConfiguration: can't open file: " << targetFile << std::endl; + + gzread(gzf, &mds->active_fields, sizeof(int)); + gzread(gzf, &mds->res, 3 * sizeof(int)); + gzread(gzf, &mds->dx, sizeof(float)); + gzread(gzf, &dummy, sizeof(float)); // dt not needed right now + gzread(gzf, &mds->p0, 3 * sizeof(float)); + gzread(gzf, &mds->p1, 3 * sizeof(float)); + gzread(gzf, &mds->dp0, 3 * sizeof(float)); + gzread(gzf, &mds->shift, 3 * sizeof(int)); + gzread(gzf, &mds->obj_shift_f, 3 * sizeof(float)); + gzread(gzf, &mds->obmat, 16 * sizeof(float)); + gzread(gzf, &mds->base_res, 3 * sizeof(int)); + gzread(gzf, &mds->res_min, 3 * sizeof(int)); + gzread(gzf, &mds->res_max, 3 * sizeof(int)); + gzread(gzf, &mds->active_color, 3 * sizeof(float)); + mds->total_cells = mds->res[0] * mds->res[1] * mds->res[2]; + + gzclose(gzf); + return 1; +} + +int MANTA::readData(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::readData()" << std::endl; + + if (!mUsingSmoke && !mUsingLiquid) + return 0; + + std::ostringstream ss; + std::vector pythonCommands; + + char cacheDirData[FILE_MAX], targetFile[FILE_MAX]; + cacheDirData[0] = '\0'; + targetFile[0] = '\0'; + + std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + + BLI_path_join(cacheDirData, + sizeof(cacheDirData), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_DATA, + NULL); + BLI_path_make_safe(cacheDirData); + + if (mUsingSmoke) { + /* Exit early if there is nothing present in the cache for this frame */ + ss.str(""); + ss << "density_####" << dformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirData, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + if (!BLI_exists(targetFile)) + return 0; + + ss.str(""); + ss << "fluid_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', " + << framenr << ", '" << dformat << "')"; + pythonCommands.push_back(ss.str()); + ss.str(""); + ss << "smoke_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', " + << framenr << ", '" << dformat << "')"; + pythonCommands.push_back(ss.str()); + } + if (mUsingLiquid) { + /* Exit early if there is nothing present in the cache for this frame */ + ss.str(""); + ss << "phiIn_####" << dformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirData, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + if (!BLI_exists(targetFile)) + return 0; + + ss.str(""); + ss << "fluid_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', " + << framenr << ", '" << dformat << "')"; + pythonCommands.push_back(ss.str()); + ss.str(""); + ss << "liquid_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', " + << framenr << ", '" << dformat << "')"; + pythonCommands.push_back(ss.str()); + ss.str(""); + ss << "liquid_load_flip_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', " + << framenr << ", '" << pformat << "')"; + pythonCommands.push_back(ss.str()); + } + runPythonString(pythonCommands); + return 1; +} + +int MANTA::readNoise(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::readNoise()" << std::endl; + + if (!mUsingNoise) + return 0; + + std::ostringstream ss; + std::vector pythonCommands; + + char cacheDirNoise[FILE_MAX], targetFile[FILE_MAX]; + cacheDirNoise[0] = '\0'; + targetFile[0] = '\0'; + + std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format); + + BLI_path_join(cacheDirNoise, + sizeof(cacheDirNoise), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_NOISE, + NULL); + BLI_path_make_safe(cacheDirNoise); + + /* Exit early if there is nothing present in the cache for this frame */ + ss.str(""); + ss << "density_noise_####" << nformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirNoise, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + if (!BLI_exists(targetFile)) + return 0; + + if (mUsingSmoke && mUsingNoise) { + ss.str(""); + ss << "smoke_load_noise_" << mCurrentID << "('" << escapeSlashes(cacheDirNoise) << "', " + << framenr << ", '" << nformat << "')"; + pythonCommands.push_back(ss.str()); + } + runPythonString(pythonCommands); + return 1; +} + +int MANTA::readMesh(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::readMesh()" << std::endl; + + if (!mUsingMesh) + return 0; + + std::ostringstream ss; + std::vector pythonCommands; + + char cacheDirMesh[FILE_MAX], targetFile[FILE_MAX]; + cacheDirMesh[0] = '\0'; + targetFile[0] = '\0'; + + std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format); + + BLI_path_join(cacheDirMesh, + sizeof(cacheDirMesh), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_MESH, + NULL); + BLI_path_make_safe(cacheDirMesh); + + if (mUsingLiquid) { + /* Exit early if there is nothing present in the cache for this frame */ + ss.str(""); + ss << "lMesh_####" << mformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirMesh, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + if (!BLI_exists(targetFile)) + return 0; + + ss.str(""); + ss << "liquid_load_mesh_" << mCurrentID << "('" << escapeSlashes(cacheDirMesh) << "', " + << framenr << ", '" << mformat << "')"; + pythonCommands.push_back(ss.str()); + + if (mUsingMVel) { + ss.str(""); + ss << "liquid_load_meshvel_" << mCurrentID << "('" << escapeSlashes(cacheDirMesh) << "', " + << framenr << ", '" << mformat << "')"; + pythonCommands.push_back(ss.str()); + } + } + runPythonString(pythonCommands); + return 1; +} + +int MANTA::readParticles(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::readParticles()" << std::endl; + + if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers) + return 0; + + std::ostringstream ss; + std::vector pythonCommands; + + char cacheDirParticles[FILE_MAX], targetFile[FILE_MAX]; + cacheDirParticles[0] = '\0'; + targetFile[0] = '\0'; + + std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + + BLI_path_join(cacheDirParticles, + sizeof(cacheDirParticles), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_PARTICLES, + NULL); + BLI_path_make_safe(cacheDirParticles); + + /* Exit early if there is nothing present in the cache for this frame */ + ss.str(""); + ss << "ppSnd_####" << pformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirParticles, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + if (!BLI_exists(targetFile)) + return 0; + + if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) { + ss.str(""); + ss << "fluid_load_particles_" << mCurrentID << "('" << escapeSlashes(cacheDirParticles) + << "', " << framenr << ", '" << pformat << "')"; + pythonCommands.push_back(ss.str()); + ss.str(""); + ss << "liquid_load_particles_" << mCurrentID << "('" << escapeSlashes(cacheDirParticles) + << "', " << framenr << ", '" << pformat << "')"; + pythonCommands.push_back(ss.str()); + } + runPythonString(pythonCommands); + return 1; +} + +int MANTA::readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain) +{ + if (with_debug) + std::cout << "MANTA::readGuiding()" << std::endl; + + if (!mUsingGuiding) + return 0; + if (!mmd->domain) + return 0; + + std::ostringstream ss; + std::vector pythonCommands; + + char cacheDirGuiding[FILE_MAX], targetFile[FILE_MAX]; + cacheDirGuiding[0] = '\0'; + targetFile[0] = '\0'; + + std::string gformat = getCacheFileEnding(mmd->domain->cache_data_format); + const char *subdir = (sourceDomain) ? FLUID_DOMAIN_DIR_DATA : FLUID_DOMAIN_DIR_GUIDING; + + BLI_path_join( + cacheDirGuiding, sizeof(cacheDirGuiding), mmd->domain->cache_directory, subdir, NULL); + BLI_path_make_safe(cacheDirGuiding); + + /* Exit early if there is nothing present in the cache for this frame */ + ss.str(""); + ss << "guidevel_####" << gformat; + BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirGuiding, ss.str().c_str()); + BLI_path_frame(targetFile, framenr, 0); + if (!BLI_exists(targetFile)) + return 0; + + if (sourceDomain) { + ss.str(""); + ss << "fluid_load_vel_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', " + << framenr << ", '" << gformat << "')"; + } + else { + ss.str(""); + ss << "fluid_load_guiding_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', " + << framenr << ", '" << gformat << "')"; + } + pythonCommands.push_back(ss.str()); + + runPythonString(pythonCommands); + return 1; +} + +int MANTA::bakeData(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::bakeData()" << std::endl; + + std::string tmpString, finalString; + std::ostringstream ss; + std::vector pythonCommands; + + char cacheDirData[FILE_MAX], cacheDirGuiding[FILE_MAX]; + cacheDirData[0] = '\0'; + cacheDirGuiding[0] = '\0'; + + std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + std::string gformat = dformat; // Use same data format for guiding format + + BLI_path_join(cacheDirData, + sizeof(cacheDirData), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_DATA, + NULL); + BLI_path_join(cacheDirGuiding, + sizeof(cacheDirGuiding), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_GUIDING, + NULL); + BLI_path_make_safe(cacheDirData); + BLI_path_make_safe(cacheDirGuiding); + + ss.str(""); + ss << "bake_fluid_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '" + << escapeSlashes(cacheDirGuiding) << "', " << framenr << ", '" << dformat << "', '" << pformat + << "', '" << gformat << "')"; + pythonCommands.push_back(ss.str()); + + runPythonString(pythonCommands); + return 1; +} + +int MANTA::bakeNoise(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::bakeNoise()" << std::endl; + + std::ostringstream ss; + std::vector pythonCommands; + + char cacheDirData[FILE_MAX], cacheDirNoise[FILE_MAX]; + cacheDirData[0] = '\0'; + cacheDirNoise[0] = '\0'; + + std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format); + + BLI_path_join(cacheDirData, + sizeof(cacheDirData), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_DATA, + NULL); + BLI_path_join(cacheDirNoise, + sizeof(cacheDirNoise), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_NOISE, + NULL); + BLI_path_make_safe(cacheDirData); + BLI_path_make_safe(cacheDirNoise); + + ss.str(""); + ss << "bake_noise_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '" + << escapeSlashes(cacheDirNoise) << "', " << framenr << ", '" << dformat << "', '" << nformat + << "')"; + pythonCommands.push_back(ss.str()); + + runPythonString(pythonCommands); + return 1; +} + +int MANTA::bakeMesh(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::bakeMesh()" << std::endl; + + std::ostringstream ss; + std::vector pythonCommands; + + char cacheDirData[FILE_MAX], cacheDirMesh[FILE_MAX]; + cacheDirData[0] = '\0'; + cacheDirMesh[0] = '\0'; + + std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format); + std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + + BLI_path_join(cacheDirData, + sizeof(cacheDirData), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_DATA, + NULL); + BLI_path_join(cacheDirMesh, + sizeof(cacheDirMesh), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_MESH, + NULL); + BLI_path_make_safe(cacheDirData); + BLI_path_make_safe(cacheDirMesh); + + ss.str(""); + ss << "bake_mesh_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '" + << escapeSlashes(cacheDirMesh) << "', " << framenr << ", '" << dformat << "', '" << mformat + << "', '" << pformat << "')"; + pythonCommands.push_back(ss.str()); + + runPythonString(pythonCommands); + return 1; +} + +int MANTA::bakeParticles(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::bakeParticles()" << std::endl; + + std::ostringstream ss; + std::vector pythonCommands; + + char cacheDirData[FILE_MAX], cacheDirParticles[FILE_MAX]; + cacheDirData[0] = '\0'; + cacheDirParticles[0] = '\0'; + + std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + + BLI_path_join(cacheDirData, + sizeof(cacheDirData), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_DATA, + NULL); + BLI_path_join(cacheDirParticles, + sizeof(cacheDirParticles), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_PARTICLES, + NULL); + BLI_path_make_safe(cacheDirData); + BLI_path_make_safe(cacheDirParticles); + + ss.str(""); + ss << "bake_particles_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '" + << escapeSlashes(cacheDirParticles) << "', " << framenr << ", '" << dformat << "', '" + << pformat << "')"; + pythonCommands.push_back(ss.str()); + + runPythonString(pythonCommands); + return 1; +} + +int MANTA::bakeGuiding(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::bakeGuiding()" << std::endl; + + std::ostringstream ss; + std::vector pythonCommands; + + char cacheDirGuiding[FILE_MAX]; + cacheDirGuiding[0] = '\0'; + + std::string gformat = getCacheFileEnding(mmd->domain->cache_data_format); + + BLI_path_join(cacheDirGuiding, + sizeof(cacheDirGuiding), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_GUIDING, + NULL); + BLI_path_make_safe(cacheDirGuiding); + + ss.str(""); + ss << "bake_guiding_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', " << framenr + << ", '" << gformat << "')"; + pythonCommands.push_back(ss.str()); + + runPythonString(pythonCommands); + return 1; +} + +void MANTA::updateVariables(FluidModifierData *mmd) +{ + std::string tmpString, finalString; + std::vector pythonCommands; + + tmpString += fluid_variables; + if (mUsingSmoke) + tmpString += smoke_variables; + if (mUsingLiquid) + tmpString += liquid_variables; + if (mUsingGuiding) + tmpString += fluid_variables_guiding; + if (mUsingNoise) { + tmpString += fluid_variables_noise; + tmpString += smoke_variables_noise; + tmpString += smoke_wavelet_noise; + } + if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) { + tmpString += fluid_variables_particles; + tmpString += liquid_variables_particles; + } + if (mUsingMesh) + tmpString += fluid_variables_mesh; + + finalString = parseScript(tmpString, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); +} + +void MANTA::exportSmokeScript(FluidModifierData *mmd) +{ + if (with_debug) + std::cout << "MANTA::exportSmokeScript()" << std::endl; + + char cacheDirScript[FILE_MAX]; + cacheDirScript[0] = '\0'; + + BLI_path_join(cacheDirScript, + sizeof(cacheDirScript), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_SCRIPT, + NULL); + BLI_path_make_safe(cacheDirScript); + BLI_dir_create_recursive( + cacheDirScript); /* Create 'script' subdir if it does not exist already */ + BLI_path_join( + cacheDirScript, sizeof(cacheDirScript), cacheDirScript, FLUID_DOMAIN_SMOKE_SCRIPT, NULL); + BLI_path_make_safe(cacheDirScript); + + bool noise = mmd->domain->flags & FLUID_DOMAIN_USE_NOISE; + bool heat = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT; + bool colors = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS; + bool fire = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE; + bool obstacle = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE; + bool guiding = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_GUIDING; + bool invel = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL; + + std::string manta_script; + + // Libraries + manta_script += header_libraries + manta_import; + + // Variables + manta_script += header_variables + fluid_variables + smoke_variables; + if (noise) { + manta_script += fluid_variables_noise + smoke_variables_noise; + } + if (guiding) + manta_script += fluid_variables_guiding; + + // Solvers + manta_script += header_solvers + fluid_solver; + if (noise) + manta_script += fluid_solver_noise; + if (guiding) + manta_script += fluid_solver_guiding; + + // Grids + manta_script += header_grids + fluid_alloc + smoke_alloc; + if (noise) { + manta_script += smoke_alloc_noise; + if (colors) + manta_script += smoke_alloc_colors_noise; + if (fire) + manta_script += smoke_alloc_fire_noise; + } + if (heat) + manta_script += smoke_alloc_heat; + if (colors) + manta_script += smoke_alloc_colors; + if (fire) + manta_script += smoke_alloc_fire; + if (guiding) + manta_script += fluid_alloc_guiding; + if (obstacle) + manta_script += fluid_alloc_obstacle; + if (invel) + manta_script += fluid_alloc_invel; + + // Noise field + if (noise) + manta_script += smoke_wavelet_noise; + + // Time + manta_script += header_time + fluid_time_stepping + fluid_adapt_time_step; + + // Import + manta_script += header_import + fluid_file_import + fluid_cache_helper + fluid_load_data + + smoke_load_data; + if (noise) + manta_script += smoke_load_noise; + if (guiding) + manta_script += fluid_load_guiding; + + // Pre/Post Steps + manta_script += header_prepost + fluid_pre_step + fluid_post_step; + + // Steps + manta_script += header_steps + smoke_adaptive_step + smoke_step; + if (noise) { + manta_script += smoke_step_noise; + } + + // Main + manta_script += header_main + smoke_standalone + fluid_standalone; + + // Fill in missing variables in script + std::string final_script = MANTA::parseScript(manta_script, mmd); + + // Write script + std::ofstream myfile; + myfile.open(cacheDirScript); + myfile << final_script; + myfile.close(); +} + +void MANTA::exportLiquidScript(FluidModifierData *mmd) +{ + if (with_debug) + std::cout << "MANTA::exportLiquidScript()" << std::endl; + + char cacheDirScript[FILE_MAX]; + cacheDirScript[0] = '\0'; + + BLI_path_join(cacheDirScript, + sizeof(cacheDirScript), + mmd->domain->cache_directory, + FLUID_DOMAIN_DIR_SCRIPT, + NULL); + BLI_path_make_safe(cacheDirScript); + BLI_dir_create_recursive( + cacheDirScript); /* Create 'script' subdir if it does not exist already */ + BLI_path_join( + cacheDirScript, sizeof(cacheDirScript), cacheDirScript, FLUID_DOMAIN_LIQUID_SCRIPT, NULL); + BLI_path_make_safe(cacheDirScript); + + bool mesh = mmd->domain->flags & FLUID_DOMAIN_USE_MESH; + bool drops = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY; + bool bubble = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE; + bool floater = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM; + bool tracer = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER; + bool obstacle = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE; + bool guiding = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_GUIDING; + bool invel = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL; + + std::string manta_script; + + // Libraries + manta_script += header_libraries + manta_import; + + // Variables + manta_script += header_variables + fluid_variables + liquid_variables; + if (mesh) + manta_script += fluid_variables_mesh; + if (drops || bubble || floater || tracer) + manta_script += fluid_variables_particles + liquid_variables_particles; + if (guiding) + manta_script += fluid_variables_guiding; + + // Solvers + manta_script += header_solvers + fluid_solver; + if (mesh) + manta_script += fluid_solver_mesh; + if (drops || bubble || floater || tracer) + manta_script += fluid_solver_particles; + if (guiding) + manta_script += fluid_solver_guiding; + + // Grids + manta_script += header_grids + fluid_alloc + liquid_alloc; + if (mesh) + manta_script += liquid_alloc_mesh; + if (drops || bubble || floater || tracer) + manta_script += fluid_alloc_sndparts + liquid_alloc_particles; + if (guiding) + manta_script += fluid_alloc_guiding; + if (obstacle) + manta_script += fluid_alloc_obstacle; + if (invel) + manta_script += fluid_alloc_invel; + + // Domain init + manta_script += header_gridinit + liquid_init_phi; + + // Time + manta_script += header_time + fluid_time_stepping + fluid_adapt_time_step; + + // Import + manta_script += header_import + fluid_file_import + fluid_cache_helper + fluid_load_data + + liquid_load_data + liquid_load_flip; + if (mesh) + manta_script += liquid_load_mesh; + if (drops || bubble || floater || tracer) + manta_script += fluid_load_particles + liquid_load_particles; + if (guiding) + manta_script += fluid_load_guiding; + + // Pre/Post Steps + manta_script += header_prepost + fluid_pre_step + fluid_post_step; + + // Steps + manta_script += header_steps + liquid_adaptive_step + liquid_step; + if (mesh) + manta_script += liquid_step_mesh; + if (drops || bubble || floater || tracer) + manta_script += liquid_step_particles; + + // Main + manta_script += header_main + liquid_standalone + fluid_standalone; + + // Fill in missing variables in script + std::string final_script = MANTA::parseScript(manta_script, mmd); + + // Write script + std::ofstream myfile; + myfile.open(cacheDirScript); + myfile << final_script; + myfile.close(); +} + +/* Call Mantaflow python functions through this function. Use isAttribute for object attributes, + * e.g. s.cfl (here 's' is varname, 'cfl' functionName, and isAttribute true) */ +static PyObject *callPythonFunction(std::string varName, + std::string functionName, + bool isAttribute = false) +{ + if ((varName == "") || (functionName == "")) { + if (MANTA::with_debug) + std::cout << "Missing Python variable name and/or function name -- name is: " << varName + << ", function name is: " << functionName << std::endl; + return NULL; + } + + PyGILState_STATE gilstate = PyGILState_Ensure(); + PyObject *main = NULL, *var = NULL, *func = NULL, *returnedValue = NULL; + + /* Be sure to initialise Python before importing main. */ + Py_Initialize(); + + // Get pyobject that holds result value + main = PyImport_ImportModule("__main__"); + if (!main) + return NULL; + + var = PyObject_GetAttrString(main, varName.c_str()); + if (!var) + return NULL; + + func = PyObject_GetAttrString(var, functionName.c_str()); + + Py_DECREF(var); + if (!func) + return NULL; + + if (!isAttribute) { + returnedValue = PyObject_CallObject(func, NULL); + Py_DECREF(func); + } + + PyGILState_Release(gilstate); + return (!isAttribute) ? returnedValue : func; +} + +static char *pyObjectToString(PyObject *inputObject) +{ + PyObject *encoded = PyUnicode_AsUTF8String(inputObject); + char *result = PyBytes_AsString(encoded); + Py_DECREF(encoded); + Py_DECREF(inputObject); + return result; +} + +static double pyObjectToDouble(PyObject *inputObject) +{ + // Cannot use PyFloat_AsDouble() since its error check crashes - likely because of Real (aka + // float) type in Mantaflow + return PyFloat_AS_DOUBLE(inputObject); +} + +static long pyObjectToLong(PyObject *inputObject) +{ + return PyLong_AsLong(inputObject); +} + +static void *stringToPointer(char *inputString) +{ + std::string str(inputString); + std::istringstream in(str); + void *dataPointer = NULL; + in >> dataPointer; + return dataPointer; +} + +int MANTA::getFrame() +{ + if (with_debug) + std::cout << "MANTA::getFrame()" << std::endl; + + std::string func = "frame"; + std::string id = std::to_string(mCurrentID); + std::string solver = "s" + id; + + return pyObjectToLong(callPythonFunction(solver, func, true)); +} + +float MANTA::getTimestep() +{ + if (with_debug) + std::cout << "MANTA::getTimestep()" << std::endl; + + std::string func = "timestep"; + std::string id = std::to_string(mCurrentID); + std::string solver = "s" + id; + + return pyObjectToDouble(callPythonFunction(solver, func, true)); +} + +bool MANTA::needsRealloc(FluidModifierData *mmd) +{ + FluidDomainSettings *mds = mmd->domain; + return (mds->res[0] != mResX || mds->res[1] != mResY || mds->res[2] != mResZ); +} + +void MANTA::adaptTimestep() +{ + if (with_debug) + std::cout << "MANTA::adaptTimestep()" << std::endl; + + std::vector pythonCommands; + std::ostringstream ss; + + ss << "fluid_adapt_time_step_" << mCurrentID << "()"; + pythonCommands.push_back(ss.str()); + + runPythonString(pythonCommands); +} + +void MANTA::updateMeshFromFile(const char *filename) +{ + std::string fname(filename); + std::string::size_type idx; + + idx = fname.rfind('.'); + if (idx != std::string::npos) { + std::string extension = fname.substr(idx + 1); + + if (extension.compare("gz") == 0) + updateMeshFromBobj(filename); + else if (extension.compare("obj") == 0) + updateMeshFromObj(filename); + else if (extension.compare("uni") == 0) + updateMeshFromUni(filename); + else + std::cerr << "updateMeshFromFile: invalid file extension in file: " << filename << std::endl; + } + else { + std::cerr << "updateMeshFromFile: unable to open file: " << filename << std::endl; + } +} + +void MANTA::updateMeshFromBobj(const char *filename) +{ + if (with_debug) + std::cout << "MANTA::updateMeshFromBobj()" << std::endl; + + gzFile gzf; + float fbuffer[3]; + int ibuffer[3]; + int numBuffer = 0; + + gzf = (gzFile)BLI_gzopen(filename, "rb1"); // do some compression + if (!gzf) + std::cerr << "updateMeshData: unable to open file: " << filename << std::endl; + + // Num vertices + gzread(gzf, &numBuffer, sizeof(int)); + + if (with_debug) + std::cout << "read mesh , num verts: " << numBuffer << " , in file: " << filename << std::endl; + + if (numBuffer) { + // Vertices + mMeshNodes->resize(numBuffer); + for (std::vector::iterator it = mMeshNodes->begin(); it != mMeshNodes->end(); ++it) { + gzread(gzf, fbuffer, sizeof(float) * 3); + it->pos[0] = fbuffer[0]; + it->pos[1] = fbuffer[1]; + it->pos[2] = fbuffer[2]; + } + } + + // Num normals + gzread(gzf, &numBuffer, sizeof(int)); + + if (with_debug) + std::cout << "read mesh , num normals : " << numBuffer << " , in file: " << filename + << std::endl; + + if (numBuffer) { + // Normals + if (!getNumVertices()) + mMeshNodes->resize(numBuffer); + for (std::vector::iterator it = mMeshNodes->begin(); it != mMeshNodes->end(); ++it) { + gzread(gzf, fbuffer, sizeof(float) * 3); + it->normal[0] = fbuffer[0]; + it->normal[1] = fbuffer[1]; + it->normal[2] = fbuffer[2]; + } + } + + // Num triangles + gzread(gzf, &numBuffer, sizeof(int)); + + if (with_debug) + std::cout << "read mesh , num triangles : " << numBuffer << " , in file: " << filename + << std::endl; + + if (numBuffer) { + // Triangles + mMeshTriangles->resize(numBuffer); + MANTA::Triangle *bufferTriangle; + for (std::vector::iterator it = mMeshTriangles->begin(); it != mMeshTriangles->end(); + ++it) { + gzread(gzf, ibuffer, sizeof(int) * 3); + bufferTriangle = (MANTA::Triangle *)ibuffer; + it->c[0] = bufferTriangle->c[0]; + it->c[1] = bufferTriangle->c[1]; + it->c[2] = bufferTriangle->c[2]; + } + } + gzclose(gzf); +} + +void MANTA::updateMeshFromObj(const char *filename) +{ + if (with_debug) + std::cout << "MANTA::updateMeshFromObj()" << std::endl; + + std::ifstream ifs(filename); + float fbuffer[3]; + int ibuffer[3]; + int cntVerts = 0, cntNormals = 0, cntTris = 0; + + if (!ifs.good()) + std::cerr << "updateMeshDataFromObj: unable to open file: " << filename << std::endl; + + while (ifs.good() && !ifs.eof()) { + std::string id; + ifs >> id; + + if (id[0] == '#') { + // comment + getline(ifs, id); + continue; + } + if (id == "vt") { + // tex coord, ignore + } + else if (id == "vn") { + // normals + if (getNumVertices() != cntVerts) + std::cerr << "updateMeshDataFromObj: invalid amount of mesh nodes" << std::endl; + + ifs >> fbuffer[0] >> fbuffer[1] >> fbuffer[2]; + MANTA::Node *node = &mMeshNodes->at(cntNormals); + (*node).normal[0] = fbuffer[0]; + (*node).normal[1] = fbuffer[1]; + (*node).normal[2] = fbuffer[2]; + cntNormals++; + } + else if (id == "v") { + // vertex + ifs >> fbuffer[0] >> fbuffer[1] >> fbuffer[2]; + MANTA::Node node; + node.pos[0] = fbuffer[0]; + node.pos[1] = fbuffer[1]; + node.pos[2] = fbuffer[2]; + mMeshNodes->push_back(node); + cntVerts++; + } + else if (id == "g") { + // group + std::string group; + ifs >> group; + } + else if (id == "f") { + // face + std::string face; + for (int i = 0; i < 3; i++) { + ifs >> face; + if (face.find('/') != std::string::npos) + face = face.substr(0, face.find('/')); // ignore other indices + int idx = atoi(face.c_str()) - 1; + if (idx < 0) + std::cerr << "updateMeshDataFromObj: invalid face encountered" << std::endl; + ibuffer[i] = idx; + } + MANTA::Triangle triangle; + triangle.c[0] = ibuffer[0]; + triangle.c[1] = ibuffer[1]; + triangle.c[2] = ibuffer[2]; + mMeshTriangles->push_back(triangle); + cntTris++; + } + else { + // whatever, ignore + } + // kill rest of line + getline(ifs, id); + } + ifs.close(); +} + +void MANTA::updateMeshFromUni(const char *filename) +{ + if (with_debug) + std::cout << "MANTA::updateMeshFromUni()" << std::endl; + + gzFile gzf; + float fbuffer[4]; + int ibuffer[4]; + + gzf = (gzFile)BLI_gzopen(filename, "rb1"); // do some compression + if (!gzf) + std::cout << "updateMeshFromUni: unable to open file" << std::endl; + + char ID[5] = {0, 0, 0, 0, 0}; + gzread(gzf, ID, 4); + + std::vector *velocityPointer = mMeshVelocities; + + // mdata uni header + const int STR_LEN_PDATA = 256; + int elementType, bytesPerElement, numParticles; + char info[STR_LEN_PDATA]; // mantaflow build information + unsigned long long timestamp; // creation time + + // read mesh header + gzread(gzf, &ibuffer, sizeof(int) * 4); // num particles, dimX, dimY, dimZ + gzread(gzf, &elementType, sizeof(int)); + gzread(gzf, &bytesPerElement, sizeof(int)); + gzread(gzf, &info, sizeof(info)); + gzread(gzf, ×tamp, sizeof(unsigned long long)); + + if (with_debug) + std::cout << "read " << ibuffer[0] << " vertices in file: " << filename << std::endl; + + // Sanity checks + const int meshSize = sizeof(float) * 3 + sizeof(int); + if (!(bytesPerElement == meshSize) && (elementType == 0)) { + std::cout << "particle type doesn't match" << std::endl; + } + if (!ibuffer[0]) { // Any vertices present? + if (with_debug) + std::cout << "no vertices present yet" << std::endl; + return; + } + + // Reading mesh + if (!strcmp(ID, "MB01")) { + // TODO (sebbas): Future update could add uni mesh support + } + // Reading mesh data file v1 with vec3 + else if (!strcmp(ID, "MD01")) { + numParticles = ibuffer[0]; + + velocityPointer->resize(numParticles); + MANTA::pVel *bufferPVel; + for (std::vector::iterator it = velocityPointer->begin(); it != velocityPointer->end(); + ++it) { + gzread(gzf, fbuffer, sizeof(float) * 3); + bufferPVel = (MANTA::pVel *)fbuffer; + it->pos[0] = bufferPVel->pos[0]; + it->pos[1] = bufferPVel->pos[1]; + it->pos[2] = bufferPVel->pos[2]; + } + } + + gzclose(gzf); +} + +void MANTA::updateParticlesFromFile(const char *filename, bool isSecondarySys, bool isVelData) +{ + if (with_debug) + std::cout << "MANTA::updateParticlesFromFile()" << std::endl; + + std::string fname(filename); + std::string::size_type idx; + + idx = fname.rfind('.'); + if (idx != std::string::npos) { + std::string extension = fname.substr(idx + 1); + + if (extension.compare("uni") == 0) + updateParticlesFromUni(filename, isSecondarySys, isVelData); + else + std::cerr << "updateParticlesFromFile: invalid file extension in file: " << filename + << std::endl; + } + else { + std::cerr << "updateParticlesFromFile: unable to open file: " << filename << std::endl; + } +} + +void MANTA::updateParticlesFromUni(const char *filename, bool isSecondarySys, bool isVelData) +{ + if (with_debug) + std::cout << "MANTA::updateParticlesFromUni()" << std::endl; + + gzFile gzf; + float fbuffer[4]; + int ibuffer[4]; + + gzf = (gzFile)BLI_gzopen(filename, "rb1"); // do some compression + if (!gzf) + std::cout << "updateParticlesFromUni: unable to open file" << std::endl; + + char ID[5] = {0, 0, 0, 0, 0}; + gzread(gzf, ID, 4); + + if (!strcmp(ID, "PB01")) { + std::cout << "particle uni file format v01 not supported anymore" << std::endl; + return; + } + + // Pointer to FLIP system or to secondary particle system + std::vector *dataPointer = NULL; + std::vector *velocityPointer = NULL; + std::vector *lifePointer = NULL; + + if (isSecondarySys) { + dataPointer = mSndParticleData; + velocityPointer = mSndParticleVelocity; + lifePointer = mSndParticleLife; + } + else { + dataPointer = mFlipParticleData; + velocityPointer = mFlipParticleVelocity; + } + + // pdata uni header + const int STR_LEN_PDATA = 256; + int elementType, bytesPerElement, numParticles; + char info[STR_LEN_PDATA]; // mantaflow build information + unsigned long long timestamp; // creation time + + // read particle header + gzread(gzf, &ibuffer, sizeof(int) * 4); // num particles, dimX, dimY, dimZ + gzread(gzf, &elementType, sizeof(int)); + gzread(gzf, &bytesPerElement, sizeof(int)); + gzread(gzf, &info, sizeof(info)); + gzread(gzf, ×tamp, sizeof(unsigned long long)); + + if (with_debug) + std::cout << "read " << ibuffer[0] << " particles in file: " << filename << std::endl; + + // Sanity checks + const int partSysSize = sizeof(float) * 3 + sizeof(int); + if (!(bytesPerElement == partSysSize) && (elementType == 0)) { + std::cout << "particle type doesn't match" << std::endl; + } + if (!ibuffer[0]) { // Any particles present? + if (with_debug) + std::cout << "no particles present yet" << std::endl; + return; + } + + numParticles = ibuffer[0]; + + // Reading base particle system file v2 + if (!strcmp(ID, "PB02")) { + dataPointer->resize(numParticles); + MANTA::pData *bufferPData; + for (std::vector::iterator it = dataPointer->begin(); it != dataPointer->end(); ++it) { + gzread(gzf, fbuffer, sizeof(float) * 3 + sizeof(int)); + bufferPData = (MANTA::pData *)fbuffer; + it->pos[0] = bufferPData->pos[0]; + it->pos[1] = bufferPData->pos[1]; + it->pos[2] = bufferPData->pos[2]; + it->flag = bufferPData->flag; + } + } + // Reading particle data file v1 with velocities + else if (!strcmp(ID, "PD01") && isVelData) { + velocityPointer->resize(numParticles); + MANTA::pVel *bufferPVel; + for (std::vector::iterator it = velocityPointer->begin(); it != velocityPointer->end(); + ++it) { + gzread(gzf, fbuffer, sizeof(float) * 3); + bufferPVel = (MANTA::pVel *)fbuffer; + it->pos[0] = bufferPVel->pos[0]; + it->pos[1] = bufferPVel->pos[1]; + it->pos[2] = bufferPVel->pos[2]; + } + } + // Reading particle data file v1 with lifetime + else if (!strcmp(ID, "PD01")) { + lifePointer->resize(numParticles); + float *bufferPLife; + for (std::vector::iterator it = lifePointer->begin(); it != lifePointer->end(); ++it) { + gzread(gzf, fbuffer, sizeof(float)); + bufferPLife = (float *)fbuffer; + *it = *bufferPLife; + } + } + + gzclose(gzf); +} + +template +void MANTA::setPointers(std::vector> objects) +{ + PyObject *mantaObject = NULL; + + for (typename std::vector>::iterator it = + objects.begin(); + it != objects.end(); + ++it) { + if (!std::get<3>(*it)) + continue; + mantaObject = callPythonFunction(std::get<1>(*it), std::get<2>(*it)); + if (mantaObject) { + (*std::get<0>(*it)) = (T *)stringToPointer(pyObjectToString(mantaObject)); + } + else { + (*std::get<0>(*it)) = NULL; + } + } +} + +void MANTA::updatePointers() +{ + if (with_debug) + std::cout << "MANTA::updatePointers()" << std::endl; + + std::string func = "getDataPointer"; + std::string funcNodes = "getNodesDataPointer"; + std::string funcTris = "getTrisDataPointer"; + + std::string id = std::to_string(mCurrentID); + std::string solver = "s" + id; + std::string parts = "pp" + id; + std::string snd = "sp" + id; + std::string mesh = "sm" + id; + std::string mesh2 = "mesh" + id; + std::string noise = "sn" + id; + std::string solver_ext = "_" + solver; + std::string parts_ext = "_" + parts; + std::string snd_ext = "_" + snd; + std::string mesh_ext = "_" + mesh; + std::string mesh_ext2 = "_" + mesh2; + std::string noise_ext = "_" + noise; + + std::vector> mantaIntObjects; + mantaIntObjects.push_back(std::make_tuple(&mObstacle, "flags" + solver_ext, func, true)); + mantaIntObjects.push_back( + std::make_tuple(&mNumObstacle, "numObs" + solver_ext, func, mUsingObstacle)); + mantaIntObjects.push_back( + std::make_tuple(&mNumGuide, "numGuides" + solver_ext, func, mUsingGuiding)); + + std::vector> mantaFloatObjects; + mantaFloatObjects.push_back(std::make_tuple(&mPhiIn, "phiIn" + solver_ext, func, true)); + mantaFloatObjects.push_back(std::make_tuple(&mVelocityX, "x_vel" + solver_ext, func, true)); + mantaFloatObjects.push_back(std::make_tuple(&mVelocityY, "y_vel" + solver_ext, func, true)); + mantaFloatObjects.push_back(std::make_tuple(&mVelocityZ, "z_vel" + solver_ext, func, true)); + mantaFloatObjects.push_back(std::make_tuple(&mForceX, "x_force" + solver_ext, func, true)); + mantaFloatObjects.push_back(std::make_tuple(&mForceY, "y_force" + solver_ext, func, true)); + mantaFloatObjects.push_back(std::make_tuple(&mForceZ, "z_force" + solver_ext, func, true)); + mantaFloatObjects.push_back( + std::make_tuple(&mPhiOutIn, "phiOutIn" + solver_ext, func, mUsingOutflow)); + mantaFloatObjects.push_back( + std::make_tuple(&mPhiObsIn, "phiObsIn" + solver_ext, func, mUsingObstacle)); + mantaFloatObjects.push_back( + std::make_tuple(&mObVelocityX, "x_obvel" + solver_ext, func, mUsingObstacle)); + mantaFloatObjects.push_back( + std::make_tuple(&mObVelocityY, "y_obvel" + solver_ext, func, mUsingObstacle)); + mantaFloatObjects.push_back( + std::make_tuple(&mObVelocityZ, "z_obvel" + solver_ext, func, mUsingObstacle)); + mantaFloatObjects.push_back( + std::make_tuple(&mPhiGuideIn, "phiGuideIn" + solver_ext, func, mUsingGuiding)); + mantaFloatObjects.push_back( + std::make_tuple(&mGuideVelocityX, "x_guidevel" + solver_ext, func, mUsingGuiding)); + mantaFloatObjects.push_back( + std::make_tuple(&mGuideVelocityY, "y_guidevel" + solver_ext, func, mUsingGuiding)); + mantaFloatObjects.push_back( + std::make_tuple(&mGuideVelocityZ, "z_guidevel" + solver_ext, func, mUsingGuiding)); + mantaFloatObjects.push_back( + std::make_tuple(&mInVelocityX, "x_invel" + solver_ext, func, mUsingInvel)); + mantaFloatObjects.push_back( + std::make_tuple(&mInVelocityY, "y_invel" + solver_ext, func, mUsingInvel)); + mantaFloatObjects.push_back( + std::make_tuple(&mInVelocityZ, "z_invel" + solver_ext, func, mUsingInvel)); + + mantaFloatObjects.push_back(std::make_tuple(&mPhi, "phi" + solver_ext, func, mUsingLiquid)); + + mantaFloatObjects.push_back( + std::make_tuple(&mDensity, "density" + solver_ext, func, mUsingSmoke)); + mantaFloatObjects.push_back( + std::make_tuple(&mDensityIn, "densityIn" + solver_ext, func, mUsingSmoke)); + mantaFloatObjects.push_back(std::make_tuple(&mShadow, "shadow" + solver_ext, func, mUsingSmoke)); + mantaFloatObjects.push_back( + std::make_tuple(&mEmissionIn, "emissionIn" + solver_ext, func, mUsingSmoke)); + mantaFloatObjects.push_back( + std::make_tuple(&mHeat, "heat" + solver_ext, func, mUsingSmoke & mUsingHeat)); + mantaFloatObjects.push_back( + std::make_tuple(&mHeatIn, "heatIn" + solver_ext, func, mUsingSmoke & mUsingHeat)); + mantaFloatObjects.push_back( + std::make_tuple(&mFlame, "flame" + solver_ext, func, mUsingSmoke & mUsingFire)); + mantaFloatObjects.push_back( + std::make_tuple(&mFuel, "fuel" + solver_ext, func, mUsingSmoke & mUsingFire)); + mantaFloatObjects.push_back( + std::make_tuple(&mReact, "react" + solver_ext, func, mUsingSmoke & mUsingFire)); + mantaFloatObjects.push_back( + std::make_tuple(&mFuelIn, "fuelIn" + solver_ext, func, mUsingSmoke & mUsingFire)); + mantaFloatObjects.push_back( + std::make_tuple(&mReactIn, "reactIn" + solver_ext, func, mUsingSmoke & mUsingFire)); + mantaFloatObjects.push_back( + std::make_tuple(&mColorR, "color_r" + solver_ext, func, mUsingSmoke & mUsingColors)); + mantaFloatObjects.push_back( + std::make_tuple(&mColorG, "color_g" + solver_ext, func, mUsingSmoke & mUsingColors)); + mantaFloatObjects.push_back( + std::make_tuple(&mColorB, "color_b" + solver_ext, func, mUsingSmoke & mUsingColors)); + mantaFloatObjects.push_back( + std::make_tuple(&mColorRIn, "color_r_in" + solver_ext, func, mUsingSmoke & mUsingColors)); + mantaFloatObjects.push_back( + std::make_tuple(&mColorGIn, "color_g_in" + solver_ext, func, mUsingSmoke & mUsingColors)); + mantaFloatObjects.push_back( + std::make_tuple(&mColorBIn, "color_b_in" + solver_ext, func, mUsingSmoke & mUsingColors)); + + mantaFloatObjects.push_back( + std::make_tuple(&mDensityHigh, "density" + noise_ext, func, mUsingSmoke & mUsingNoise)); + mantaFloatObjects.push_back( + std::make_tuple(&mTextureU, "texture_u" + solver_ext, func, mUsingSmoke & mUsingNoise)); + mantaFloatObjects.push_back( + std::make_tuple(&mTextureV, "texture_v" + solver_ext, func, mUsingSmoke & mUsingNoise)); + mantaFloatObjects.push_back( + std::make_tuple(&mTextureW, "texture_w" + solver_ext, func, mUsingSmoke & mUsingNoise)); + mantaFloatObjects.push_back( + std::make_tuple(&mTextureU2, "texture_u2" + solver_ext, func, mUsingSmoke & mUsingNoise)); + mantaFloatObjects.push_back( + std::make_tuple(&mTextureV2, "texture_v2" + solver_ext, func, mUsingSmoke & mUsingNoise)); + mantaFloatObjects.push_back( + std::make_tuple(&mTextureW2, "texture_w2" + solver_ext, func, mUsingSmoke & mUsingNoise)); + mantaFloatObjects.push_back(std::make_tuple( + &mFlameHigh, "flame" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingFire)); + mantaFloatObjects.push_back(std::make_tuple( + &mFuelHigh, "fuel" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingFire)); + mantaFloatObjects.push_back(std::make_tuple( + &mReactHigh, "react" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingFire)); + mantaFloatObjects.push_back(std::make_tuple( + &mColorRHigh, "color_r" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingColors)); + mantaFloatObjects.push_back(std::make_tuple( + &mColorGHigh, "color_g" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingColors)); + mantaFloatObjects.push_back(std::make_tuple( + &mColorRHigh, "color_b" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingColors)); + + std::vector **, std::string, std::string, bool>> mantaPDataObjects; + mantaPDataObjects.push_back( + std::make_tuple(&mFlipParticleData, "pp" + solver_ext, func, mUsingLiquid)); + mantaPDataObjects.push_back(std::make_tuple( + &mSndParticleData, + "ppSnd" + snd_ext, + func, + mUsingLiquid & (mUsingDrops | mUsingBubbles | mUsingFloats | mUsingTracers))); + + std::vector **, std::string, std::string, bool>> mantaPVelObjects; + mantaPVelObjects.push_back( + std::make_tuple(&mFlipParticleVelocity, "pVel" + parts_ext, func, mUsingLiquid)); + mantaPVelObjects.push_back(std::make_tuple( + &mMeshVelocities, "mVel" + mesh_ext2, func, mUsingLiquid & mUsingMesh & mUsingMVel)); + mantaPVelObjects.push_back(std::make_tuple( + &mSndParticleVelocity, + "pVelSnd" + parts_ext, + func, + mUsingLiquid & (mUsingDrops | mUsingBubbles | mUsingFloats | mUsingTracers))); + + std::vector **, std::string, std::string, bool>> mantaNodeObjects; + mantaNodeObjects.push_back( + std::make_tuple(&mMeshNodes, "mesh" + mesh_ext, funcNodes, mUsingLiquid & mUsingMesh)); + + std::vector **, std::string, std::string, bool>> + mantaTriangleObjects; + mantaTriangleObjects.push_back( + std::make_tuple(&mMeshTriangles, "mesh" + mesh_ext, funcTris, mUsingLiquid & mUsingMesh)); + + std::vector **, std::string, std::string, bool>> + mantaFloatVecObjects; + mantaFloatVecObjects.push_back(std::make_tuple( + &mSndParticleLife, + "pLifeSnd" + parts_ext, + func, + mUsingLiquid & (mUsingDrops | mUsingBubbles | mUsingFloats | mUsingTracers))); + + setPointers(mantaIntObjects); + setPointers(mantaFloatObjects); + setPointers(mantaPDataObjects); + setPointers(mantaPVelObjects); + setPointers(mantaNodeObjects); + setPointers(mantaTriangleObjects); + setPointers(mantaFloatVecObjects); +} diff --git a/intern/mantaflow/intern/MANTA_main.h b/intern/mantaflow/intern/MANTA_main.h new file mode 100644 index 00000000000..276770de07a --- /dev/null +++ b/intern/mantaflow/intern/MANTA_main.h @@ -0,0 +1,850 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sebastian Barschkis (sebbas) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file mantaflow/intern/MANTA.h + * \ingroup mantaflow + */ + +#ifndef MANTA_A_H +#define MANTA_A_H + +#include +#include +#include +#include + +struct MANTA { + public: + MANTA(int *res, struct FluidModifierData *mmd); + MANTA(){}; + virtual ~MANTA(); + + // Mirroring Mantaflow structures for particle data (pVel also used for mesh vert vels) + typedef struct PData { + float pos[3]; + int flag; + } pData; + typedef struct PVel { + float pos[3]; + } pVel; + + // Mirroring Mantaflow structures for meshes + typedef struct Node { + int flags; + float pos[3], normal[3]; + } Node; + typedef struct Triangle { + int c[3]; + int flags; + } Triangle; + + // Manta step, handling everything + void step(struct FluidModifierData *mmd, int startFrame); + + // Grid initialization functions + void initHeat(struct FluidModifierData *mmd); + void initFire(struct FluidModifierData *mmd); + void initColors(struct FluidModifierData *mmd); + void initFireHigh(struct FluidModifierData *mmd); + void initColorsHigh(struct FluidModifierData *mmd); + void initLiquid(FluidModifierData *mmd); + void initLiquidMesh(FluidModifierData *mmd); + void initObstacle(FluidModifierData *mmd); + void initGuiding(FluidModifierData *mmd); + void initFractions(FluidModifierData *mmd); + void initInVelocity(FluidModifierData *mmd); + void initOutflow(FluidModifierData *mmd); + void initSndParts(FluidModifierData *mmd); + void initLiquidSndParts(FluidModifierData *mmd); + + // Pointer transfer: Mantaflow -> Blender + void updatePointers(); + + // Write cache + int writeConfiguration(FluidModifierData *mmd, int framenr); + int writeData(FluidModifierData *mmd, int framenr); + // write call for noise, mesh and particles were left in bake calls for now + + // Read cache (via Manta save/load) + int readConfiguration(FluidModifierData *mmd, int framenr); + int readData(FluidModifierData *mmd, int framenr); + int readNoise(FluidModifierData *mmd, int framenr); + int readMesh(FluidModifierData *mmd, int framenr); + int readParticles(FluidModifierData *mmd, int framenr); + int readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain); + + // Read cache (via file read functions in MANTA - e.g. read .bobj.gz meshes, .uni particles) + int updateMeshStructures(FluidModifierData *mmd, int framenr); + int updateFlipStructures(FluidModifierData *mmd, int framenr); + int updateParticleStructures(FluidModifierData *mmd, int framenr); + void updateVariables(FluidModifierData *mmd); + + // Bake cache + int bakeData(FluidModifierData *mmd, int framenr); + int bakeNoise(FluidModifierData *mmd, int framenr); + int bakeMesh(FluidModifierData *mmd, int framenr); + int bakeParticles(FluidModifierData *mmd, int framenr); + int bakeGuiding(FluidModifierData *mmd, int framenr); + + // IO for Mantaflow scene script + void exportSmokeScript(struct FluidModifierData *mmd); + void exportLiquidScript(struct FluidModifierData *mmd); + + inline size_t getTotalCells() + { + return mTotalCells; + } + inline size_t getTotalCellsHigh() + { + return mTotalCellsHigh; + } + inline bool usingNoise() + { + return mUsingNoise; + } + inline int getResX() + { + return mResX; + } + inline int getResY() + { + return mResY; + } + inline int getResZ() + { + return mResZ; + } + inline int getParticleResX() + { + return mResXParticle; + } + inline int getParticleResY() + { + return mResYParticle; + } + inline int getParticleResZ() + { + return mResZParticle; + } + inline int getMeshResX() + { + return mResXMesh; + } + inline int getMeshResY() + { + return mResYMesh; + } + inline int getMeshResZ() + { + return mResZMesh; + } + inline int getResXHigh() + { + return mResXNoise; + } + inline int getResYHigh() + { + return mResYNoise; + } + inline int getResZHigh() + { + return mResZNoise; + } + inline int getMeshUpres() + { + return mUpresMesh; + } + inline int getParticleUpres() + { + return mUpresParticle; + } + + // Smoke getters + inline float *getDensity() + { + return mDensity; + } + inline float *getHeat() + { + return mHeat; + } + inline float *getVelocityX() + { + return mVelocityX; + } + inline float *getVelocityY() + { + return mVelocityY; + } + inline float *getVelocityZ() + { + return mVelocityZ; + } + inline float *getObVelocityX() + { + return mObVelocityX; + } + inline float *getObVelocityY() + { + return mObVelocityY; + } + inline float *getObVelocityZ() + { + return mObVelocityZ; + } + inline float *getGuideVelocityX() + { + return mGuideVelocityX; + } + inline float *getGuideVelocityY() + { + return mGuideVelocityY; + } + inline float *getGuideVelocityZ() + { + return mGuideVelocityZ; + } + inline float *getInVelocityX() + { + return mInVelocityX; + } + inline float *getInVelocityY() + { + return mInVelocityY; + } + inline float *getInVelocityZ() + { + return mInVelocityZ; + } + inline float *getForceX() + { + return mForceX; + } + inline float *getForceY() + { + return mForceY; + } + inline float *getForceZ() + { + return mForceZ; + } + inline int *getObstacle() + { + return mObstacle; + } + inline int *getNumObstacle() + { + return mNumObstacle; + } + inline int *getNumGuide() + { + return mNumGuide; + } + inline float *getFlame() + { + return mFlame; + } + inline float *getFuel() + { + return mFuel; + } + inline float *getReact() + { + return mReact; + } + inline float *getColorR() + { + return mColorR; + } + inline float *getColorG() + { + return mColorG; + } + inline float *getColorB() + { + return mColorB; + } + inline float *getShadow() + { + return mShadow; + } + inline float *getDensityIn() + { + return mDensityIn; + } + inline float *getHeatIn() + { + return mHeatIn; + } + inline float *getColorRIn() + { + return mColorRIn; + } + inline float *getColorGIn() + { + return mColorGIn; + } + inline float *getColorBIn() + { + return mColorBIn; + } + inline float *getFuelIn() + { + return mFuelIn; + } + inline float *getReactIn() + { + return mReactIn; + } + inline float *getEmissionIn() + { + return mEmissionIn; + } + + inline float *getDensityHigh() + { + return mDensityHigh; + } + inline float *getFlameHigh() + { + return mFlameHigh; + } + inline float *getFuelHigh() + { + return mFuelHigh; + } + inline float *getReactHigh() + { + return mReactHigh; + } + inline float *getColorRHigh() + { + return mColorRHigh; + } + inline float *getColorGHigh() + { + return mColorGHigh; + } + inline float *getColorBHigh() + { + return mColorBHigh; + } + inline float *getTextureU() + { + return mTextureU; + } + inline float *getTextureV() + { + return mTextureV; + } + inline float *getTextureW() + { + return mTextureW; + } + inline float *getTextureU2() + { + return mTextureU2; + } + inline float *getTextureV2() + { + return mTextureV2; + } + inline float *getTextureW2() + { + return mTextureW2; + } + + inline float *getPhiIn() + { + return mPhiIn; + } + inline float *getPhiObsIn() + { + return mPhiObsIn; + } + inline float *getPhiGuideIn() + { + return mPhiGuideIn; + } + inline float *getPhiOutIn() + { + return mPhiOutIn; + } + inline float *getPhi() + { + return mPhi; + } + + static std::atomic mantaInitialized; + static std::atomic solverID; + static int with_debug; // on or off (1 or 0), also sets manta debug level + + // Mesh getters + inline int getNumVertices() + { + return (mMeshNodes && !mMeshNodes->empty()) ? mMeshNodes->size() : 0; + } + inline int getNumNormals() + { + return (mMeshNodes && !mMeshNodes->empty()) ? mMeshNodes->size() : 0; + } + inline int getNumTriangles() + { + return (mMeshTriangles && !mMeshTriangles->empty()) ? mMeshTriangles->size() : 0; + } + + inline float getVertexXAt(int i) + { + assert(i >= 0); + if (mMeshNodes && !mMeshNodes->empty()) { + assert(i < mMeshNodes->size()); + return (*mMeshNodes)[i].pos[0]; + } + return 0.0f; + } + inline float getVertexYAt(int i) + { + assert(i >= 0); + if (mMeshNodes && !mMeshNodes->empty()) { + assert(i < mMeshNodes->size()); + return (*mMeshNodes)[i].pos[1]; + } + return 0.0f; + } + inline float getVertexZAt(int i) + { + assert(i >= 0); + if (mMeshNodes && !mMeshNodes->empty()) { + assert(i < mMeshNodes->size()); + return (*mMeshNodes)[i].pos[2]; + } + return 0.0f; + } + + inline float getNormalXAt(int i) + { + assert(i >= 0); + if (mMeshNodes && !mMeshNodes->empty()) { + assert(i < mMeshNodes->size()); + return (*mMeshNodes)[i].normal[0]; + } + return 0.0f; + } + inline float getNormalYAt(int i) + { + assert(i >= 0); + if (mMeshNodes && !mMeshNodes->empty()) { + assert(i < mMeshNodes->size()); + return (*mMeshNodes)[i].normal[1]; + } + return 0.0f; + } + inline float getNormalZAt(int i) + { + assert(i >= 0); + if (mMeshNodes && !mMeshNodes->empty()) { + assert(i < mMeshNodes->size()); + return (*mMeshNodes)[i].normal[2]; + } + return 0.0f; + } + + inline int getTriangleXAt(int i) + { + assert(i >= 0); + if (mMeshTriangles && !mMeshTriangles->empty()) { + assert(i < mMeshTriangles->size()); + return (*mMeshTriangles)[i].c[0]; + } + return 0; + } + inline int getTriangleYAt(int i) + { + assert(i >= 0); + if (mMeshTriangles && !mMeshTriangles->empty()) { + assert(i < mMeshTriangles->size()); + return (*mMeshTriangles)[i].c[1]; + } + return 0; + } + inline int getTriangleZAt(int i) + { + assert(i >= 0); + if (mMeshTriangles && !mMeshTriangles->empty()) { + assert(i < mMeshTriangles->size()); + return (*mMeshTriangles)[i].c[2]; + } + return 0; + } + + inline float getVertVelXAt(int i) + { + assert(i >= 0); + if (mMeshVelocities && !mMeshVelocities->empty()) { + assert(i < mMeshVelocities->size()); + return (*mMeshVelocities)[i].pos[0]; + } + return 0.0f; + } + inline float getVertVelYAt(int i) + { + assert(i >= 0); + if (mMeshVelocities && !mMeshVelocities->empty()) { + assert(i < mMeshVelocities->size()); + return (*mMeshVelocities)[i].pos[1]; + } + return 0.0f; + } + inline float getVertVelZAt(int i) + { + assert(i >= 0); + if (mMeshVelocities && !mMeshVelocities->empty()) { + assert(i < mMeshVelocities->size()); + return (*mMeshVelocities)[i].pos[2]; + } + return 0.0f; + } + + // Particle getters + inline int getFlipParticleFlagAt(int i) + { + assert(i >= 0); + if (mFlipParticleData && !mFlipParticleData->empty()) { + assert(i < mFlipParticleData->size()); + return (*mFlipParticleData)[i].flag; + } + return 0; + } + inline int getSndParticleFlagAt(int i) + { + assert(i >= 0); + if (mSndParticleData && !mSndParticleData->empty()) { + assert(i < mSndParticleData->size()); + return (*mSndParticleData)[i].flag; + } + return 0; + } + + inline float getFlipParticlePositionXAt(int i) + { + assert(i >= 0); + if (mFlipParticleData && !mFlipParticleData->empty()) { + assert(i < mFlipParticleData->size()); + return (*mFlipParticleData)[i].pos[0]; + } + return 0.0f; + } + inline float getFlipParticlePositionYAt(int i) + { + assert(i >= 0); + if (mFlipParticleData && !mFlipParticleData->empty()) { + assert(i < mFlipParticleData->size()); + return (*mFlipParticleData)[i].pos[1]; + } + return 0.0f; + } + inline float getFlipParticlePositionZAt(int i) + { + assert(i >= 0); + if (mFlipParticleData && !mFlipParticleData->empty()) { + assert(i < mFlipParticleData->size()); + return (*mFlipParticleData)[i].pos[2]; + } + return 0.0f; + } + + inline float getSndParticlePositionXAt(int i) + { + assert(i >= 0); + if (mSndParticleData && !mSndParticleData->empty()) { + assert(i < mSndParticleData->size()); + return (*mSndParticleData)[i].pos[0]; + } + return 0.0f; + } + inline float getSndParticlePositionYAt(int i) + { + assert(i >= 0); + if (mSndParticleData && !mSndParticleData->empty()) { + assert(i < mSndParticleData->size()); + return (*mSndParticleData)[i].pos[1]; + } + return 0.0f; + } + inline float getSndParticlePositionZAt(int i) + { + assert(i >= 0); + if (mSndParticleData && !mSndParticleData->empty()) { + assert(i < mSndParticleData->size()); + return (*mSndParticleData)[i].pos[2]; + } + return 0.0f; + } + + inline float getFlipParticleVelocityXAt(int i) + { + assert(i >= 0); + if (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) { + assert(i < mFlipParticleVelocity->size()); + return (*mFlipParticleVelocity)[i].pos[0]; + } + return 0.0f; + } + inline float getFlipParticleVelocityYAt(int i) + { + assert(i >= 0); + if (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) { + assert(i < mFlipParticleVelocity->size()); + return (*mFlipParticleVelocity)[i].pos[1]; + } + return 0.0f; + } + inline float getFlipParticleVelocityZAt(int i) + { + assert(i >= 0); + if (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) { + assert(i < mFlipParticleVelocity->size()); + return (*mFlipParticleVelocity)[i].pos[2]; + } + return 0.0f; + } + + inline float getSndParticleVelocityXAt(int i) + { + assert(i >= 0); + if (mSndParticleVelocity && !mSndParticleVelocity->empty()) { + assert(i < mSndParticleVelocity->size()); + return (*mSndParticleVelocity)[i].pos[0]; + } + return 0.0f; + } + inline float getSndParticleVelocityYAt(int i) + { + assert(i >= 0); + if (mSndParticleVelocity && !mSndParticleVelocity->empty()) { + assert(i < mSndParticleVelocity->size()); + return (*mSndParticleVelocity)[i].pos[1]; + } + return 0.0f; + } + inline float getSndParticleVelocityZAt(int i) + { + assert(i >= 0); + if (mSndParticleVelocity && !mSndParticleVelocity->empty()) { + assert(i < mSndParticleVelocity->size()); + return (*mSndParticleVelocity)[i].pos[2]; + } + return 0.0f; + } + + inline float *getFlipParticleData() + { + return (mFlipParticleData && !mFlipParticleData->empty()) ? + (float *)&mFlipParticleData->front() : + NULL; + } + inline float *getSndParticleData() + { + return (mSndParticleData && !mSndParticleData->empty()) ? (float *)&mSndParticleData->front() : + NULL; + } + + inline float *getFlipParticleVelocity() + { + return (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) ? + (float *)&mFlipParticleVelocity->front() : + NULL; + } + inline float *getSndParticleVelocity() + { + return (mSndParticleVelocity && !mSndParticleVelocity->empty()) ? + (float *)&mSndParticleVelocity->front() : + NULL; + } + inline float *getSndParticleLife() + { + return (mSndParticleLife && !mSndParticleLife->empty()) ? (float *)&mSndParticleLife->front() : + NULL; + } + + inline int getNumFlipParticles() + { + return (mFlipParticleData && !mFlipParticleData->empty()) ? mFlipParticleData->size() : 0; + } + inline int getNumSndParticles() + { + return (mSndParticleData && !mSndParticleData->empty()) ? mSndParticleData->size() : 0; + } + + // Direct access to solver time attributes + int getFrame(); + float getTimestep(); + void adaptTimestep(); + + bool needsRealloc(FluidModifierData *mmd); + + private: + // simulation constants + size_t mTotalCells; + size_t mTotalCellsHigh; + size_t mTotalCellsMesh; + size_t mTotalCellsParticles; + + int mCurrentID; + + bool mUsingHeat; + bool mUsingColors; + bool mUsingFire; + bool mUsingObstacle; + bool mUsingGuiding; + bool mUsingFractions; + bool mUsingInvel; + bool mUsingOutflow; + bool mUsingNoise; + bool mUsingMesh; + bool mUsingMVel; + bool mUsingLiquid; + bool mUsingSmoke; + bool mUsingDrops; + bool mUsingBubbles; + bool mUsingFloats; + bool mUsingTracers; + + int mResX; + int mResY; + int mResZ; + int mMaxRes; + + int mResXNoise; + int mResYNoise; + int mResZNoise; + int mResXMesh; + int mResYMesh; + int mResZMesh; + int mResXParticle; + int mResYParticle; + int mResZParticle; + int *mResGuiding; + + int mUpresMesh; + int mUpresParticle; + + float mTempAmb; /* ambient temperature */ + float mConstantScaling; + + // Fluid grids + float *mVelocityX; + float *mVelocityY; + float *mVelocityZ; + float *mObVelocityX; + float *mObVelocityY; + float *mObVelocityZ; + float *mGuideVelocityX; + float *mGuideVelocityY; + float *mGuideVelocityZ; + float *mInVelocityX; + float *mInVelocityY; + float *mInVelocityZ; + float *mForceX; + float *mForceY; + float *mForceZ; + int *mObstacle; + int *mNumObstacle; + int *mNumGuide; + + // Smoke grids + float *mDensity; + float *mHeat; + float *mFlame; + float *mFuel; + float *mReact; + float *mColorR; + float *mColorG; + float *mColorB; + float *mShadow; + float *mDensityIn; + float *mHeatIn; + float *mFuelIn; + float *mReactIn; + float *mEmissionIn; + float *mColorRIn; + float *mColorGIn; + float *mColorBIn; + float *mDensityHigh; + float *mFlameHigh; + float *mFuelHigh; + float *mReactHigh; + float *mColorRHigh; + float *mColorGHigh; + float *mColorBHigh; + float *mTextureU; + float *mTextureV; + float *mTextureW; + float *mTextureU2; + float *mTextureV2; + float *mTextureW2; + + // Liquid grids + float *mPhiIn; + float *mPhiObsIn; + float *mPhiGuideIn; + float *mPhiOutIn; + float *mPhi; + + // Mesh fields + std::vector *mMeshNodes; + std::vector *mMeshTriangles; + std::vector *mMeshVelocities; + + // Particle fields + std::vector *mFlipParticleData; + std::vector *mFlipParticleVelocity; + + std::vector *mSndParticleData; + std::vector *mSndParticleVelocity; + std::vector *mSndParticleLife; + + void initDomain(struct FluidModifierData *mmd); + void initNoise(struct FluidModifierData *mmd); + void initMesh(struct FluidModifierData *mmd); + void initSmoke(struct FluidModifierData *mmd); + void initSmokeNoise(struct FluidModifierData *mmd); + void initializeMantaflow(); + void terminateMantaflow(); + void runPythonString(std::vector commands); + std::string getRealValue(const std::string &varName, FluidModifierData *mmd); + std::string parseLine(const std::string &line, FluidModifierData *mmd); + std::string parseScript(const std::string &setup_string, FluidModifierData *mmd = NULL); + void updateMeshFromBobj(const char *filename); + void updateMeshFromObj(const char *filename); + void updateMeshFromUni(const char *filename); + void updateParticlesFromUni(const char *filename, bool isSecondarySys, bool isVelData); + void updateMeshFromFile(const char *filename); + void updateParticlesFromFile(const char *filename, bool isSecondarySys, bool isVelData); + template + void setPointers(std::vector>); +}; + +#endif diff --git a/intern/mantaflow/intern/manta_fluid_API.cpp b/intern/mantaflow/intern/manta_fluid_API.cpp new file mode 100644 index 00000000000..107d7134d87 --- /dev/null +++ b/intern/mantaflow/intern/manta_fluid_API.cpp @@ -0,0 +1,872 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sebastian Barschkis (sebbas) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file mantaflow/intern/manta_smoke_API.cpp + * \ingroup mantaflow + */ + +#include + +#include "MANTA_main.h" +#include "manta_fluid_API.h" + +/* Fluid functions */ +MANTA *manta_init(int *res, struct FluidModifierData *mmd) +{ + return new MANTA(res, mmd); +} +void manta_free(MANTA *fluid) +{ + delete fluid; + fluid = nullptr; +} + +void manta_ensure_obstacle(MANTA *fluid, struct FluidModifierData *mmd) +{ + if (!fluid) + return; + fluid->initObstacle(mmd); + fluid->updatePointers(); +} +void manta_ensure_guiding(MANTA *fluid, struct FluidModifierData *mmd) +{ + if (!fluid) + return; + fluid->initGuiding(mmd); + fluid->updatePointers(); +} +void manta_ensure_invelocity(MANTA *fluid, struct FluidModifierData *mmd) +{ + if (!fluid) + return; + fluid->initInVelocity(mmd); + fluid->updatePointers(); +} +void manta_ensure_outflow(MANTA *fluid, struct FluidModifierData *mmd) +{ + if (!fluid) + return; + fluid->initOutflow(mmd); + fluid->updatePointers(); +} + +int manta_write_config(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->writeConfiguration(mmd, framenr); +} + +int manta_write_data(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->writeData(mmd, framenr); +} + +int manta_read_config(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->readConfiguration(mmd, framenr); +} + +int manta_read_data(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->readData(mmd, framenr); +} + +int manta_read_noise(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->readNoise(mmd, framenr); +} + +int manta_read_mesh(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->readMesh(mmd, framenr); +} + +int manta_read_particles(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->readParticles(mmd, framenr); +} + +int manta_read_guiding(MANTA *fluid, FluidModifierData *mmd, int framenr, bool sourceDomain) +{ + if (!fluid || !mmd) + return 0; + return fluid->readGuiding(mmd, framenr, sourceDomain); +} + +int manta_update_liquid_structures(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->updateFlipStructures(mmd, framenr); +} + +int manta_update_mesh_structures(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->updateMeshStructures(mmd, framenr); +} + +int manta_update_particle_structures(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->updateParticleStructures(mmd, framenr); +} + +int manta_bake_data(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->bakeData(mmd, framenr); +} + +int manta_bake_noise(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->bakeNoise(mmd, framenr); +} + +int manta_bake_mesh(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->bakeMesh(mmd, framenr); +} + +int manta_bake_particles(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->bakeParticles(mmd, framenr); +} + +int manta_bake_guiding(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->bakeGuiding(mmd, framenr); +} + +void manta_update_variables(MANTA *fluid, FluidModifierData *mmd) +{ + if (!fluid) + return; + fluid->updateVariables(mmd); +} + +int manta_get_frame(MANTA *fluid) +{ + if (!fluid) + return 0; + return fluid->getFrame(); +} + +float manta_get_timestep(MANTA *fluid) +{ + if (!fluid) + return 0; + return fluid->getTimestep(); +} + +void manta_adapt_timestep(MANTA *fluid) +{ + if (!fluid) + return; + fluid->adaptTimestep(); +} + +bool manta_needs_realloc(MANTA *fluid, FluidModifierData *mmd) +{ + if (!fluid) + return false; + return fluid->needsRealloc(mmd); +} + +/* Fluid accessors */ +size_t manta_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */) +{ + return x + y * max_x + z * max_x * max_y; +} +size_t manta_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */) +{ + return x + y * max_x; +} +float *manta_get_velocity_x(MANTA *fluid) +{ + return fluid->getVelocityX(); +} +float *manta_get_velocity_y(MANTA *fluid) +{ + return fluid->getVelocityY(); +} +float *manta_get_velocity_z(MANTA *fluid) +{ + return fluid->getVelocityZ(); +} + +float *manta_get_ob_velocity_x(MANTA *fluid) +{ + return fluid->getObVelocityX(); +} +float *manta_get_ob_velocity_y(MANTA *fluid) +{ + return fluid->getObVelocityY(); +} +float *manta_get_ob_velocity_z(MANTA *fluid) +{ + return fluid->getObVelocityZ(); +} + +float *manta_get_guide_velocity_x(MANTA *fluid) +{ + return fluid->getGuideVelocityX(); +} +float *manta_get_guide_velocity_y(MANTA *fluid) +{ + return fluid->getGuideVelocityY(); +} +float *manta_get_guide_velocity_z(MANTA *fluid) +{ + return fluid->getGuideVelocityZ(); +} + +float *manta_get_in_velocity_x(MANTA *fluid) +{ + return fluid->getInVelocityX(); +} +float *manta_get_in_velocity_y(MANTA *fluid) +{ + return fluid->getInVelocityY(); +} +float *manta_get_in_velocity_z(MANTA *fluid) +{ + return fluid->getInVelocityZ(); +} + +float *manta_get_force_x(MANTA *fluid) +{ + return fluid->getForceX(); +} +float *manta_get_force_y(MANTA *fluid) +{ + return fluid->getForceY(); +} +float *manta_get_force_z(MANTA *fluid) +{ + return fluid->getForceZ(); +} + +float *manta_get_phiguide_in(MANTA *fluid) +{ + return fluid->getPhiGuideIn(); +} + +int *manta_get_num_obstacle(MANTA *fluid) +{ + return fluid->getNumObstacle(); +} +int *manta_get_num_guide(MANTA *fluid) +{ + return fluid->getNumGuide(); +} + +int manta_get_res_x(MANTA *fluid) +{ + return fluid->getResX(); +} +int manta_get_res_y(MANTA *fluid) +{ + return fluid->getResY(); +} +int manta_get_res_z(MANTA *fluid) +{ + return fluid->getResZ(); +} + +float *manta_get_phi_in(MANTA *fluid) +{ + return fluid->getPhiIn(); +} +float *manta_get_phiobs_in(MANTA *fluid) +{ + return fluid->getPhiObsIn(); +} +float *manta_get_phiout_in(MANTA *fluid) +{ + return fluid->getPhiOutIn(); +} + +/* Smoke functions */ +void manta_smoke_export_script(MANTA *smoke, FluidModifierData *mmd) +{ + if (!smoke || !mmd) + return; + smoke->exportSmokeScript(mmd); +} + +void manta_smoke_export(MANTA *smoke, + float *dt, + float *dx, + float **dens, + float **react, + float **flame, + float **fuel, + float **heat, + float **vx, + float **vy, + float **vz, + float **r, + float **g, + float **b, + int **obstacle, + float **shadow) +{ + if (dens) + *dens = smoke->getDensity(); + if (fuel) + *fuel = smoke->getFuel(); + if (react) + *react = smoke->getReact(); + if (flame) + *flame = smoke->getFlame(); + if (heat) + *heat = smoke->getHeat(); + *vx = smoke->getVelocityX(); + *vy = smoke->getVelocityY(); + *vz = smoke->getVelocityZ(); + if (r) + *r = smoke->getColorR(); + if (g) + *g = smoke->getColorG(); + if (b) + *b = smoke->getColorB(); + *obstacle = smoke->getObstacle(); + *shadow = smoke->getShadow(); + *dt = 1; // dummy value, not needed for smoke + *dx = 1; // dummy value, not needed for smoke +} + +void manta_smoke_turbulence_export(MANTA *smoke, + float **dens, + float **react, + float **flame, + float **fuel, + float **r, + float **g, + float **b, + float **tcu, + float **tcv, + float **tcw, + float **tcu2, + float **tcv2, + float **tcw2) +{ + if (!smoke && !(smoke->usingNoise())) + return; + + *dens = smoke->getDensityHigh(); + if (fuel) + *fuel = smoke->getFuelHigh(); + if (react) + *react = smoke->getReactHigh(); + if (flame) + *flame = smoke->getFlameHigh(); + if (r) + *r = smoke->getColorRHigh(); + if (g) + *g = smoke->getColorGHigh(); + if (b) + *b = smoke->getColorBHigh(); + *tcu = smoke->getTextureU(); + *tcv = smoke->getTextureV(); + *tcw = smoke->getTextureW(); + + *tcu2 = smoke->getTextureU2(); + *tcv2 = smoke->getTextureV2(); + *tcw2 = smoke->getTextureW2(); +} + +static void get_rgba( + float *r, float *g, float *b, float *a, int total_cells, float *data, int sequential) +{ + int i; + /* Use offsets to map RGB grids to to correct location in data grid. */ + int m = 4, i_g = 1, i_b = 2, i_a = 3; + if (sequential) { + m = 1; + i_g *= total_cells; + i_b *= total_cells; + i_a *= total_cells; + } + + for (i = 0; i < total_cells; i++) { + float alpha = a[i]; + if (alpha) { + data[i * m] = r[i]; + data[i * m + i_g] = g[i]; + data[i * m + i_b] = b[i]; + } + else { + data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f; + } + data[i * m + i_a] = alpha; + } +} + +void manta_smoke_get_rgba(MANTA *smoke, float *data, int sequential) +{ + get_rgba(smoke->getColorR(), + smoke->getColorG(), + smoke->getColorB(), + smoke->getDensity(), + smoke->getTotalCells(), + data, + sequential); +} + +void manta_smoke_turbulence_get_rgba(MANTA *smoke, float *data, int sequential) +{ + get_rgba(smoke->getColorRHigh(), + smoke->getColorGHigh(), + smoke->getColorBHigh(), + smoke->getDensityHigh(), + smoke->getTotalCellsHigh(), + data, + sequential); +} + +static void get_rgba_from_density( + float color[3], float *a, int total_cells, float *data, int sequential) +{ + int i; + int m = 4, i_g = 1, i_b = 2, i_a = 3; + if (sequential) { + m = 1; + i_g *= total_cells; + i_b *= total_cells; + i_a *= total_cells; + } + + for (i = 0; i < total_cells; i++) { + float alpha = a[i]; + if (alpha) { + data[i * m] = color[0] * alpha; + data[i * m + i_g] = color[1] * alpha; + data[i * m + i_b] = color[2] * alpha; + } + else { + data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f; + } + data[i * m + i_a] = alpha; + } +} + +void manta_smoke_get_rgba_from_density(MANTA *smoke, float color[3], float *data, int sequential) +{ + get_rgba_from_density(color, smoke->getDensity(), smoke->getTotalCells(), data, sequential); +} + +void manta_smoke_turbulence_get_rgba_from_density(MANTA *smoke, + float color[3], + float *data, + int sequential) +{ + get_rgba_from_density( + color, smoke->getDensityHigh(), smoke->getTotalCellsHigh(), data, sequential); +} + +void manta_smoke_ensure_heat(MANTA *smoke, struct FluidModifierData *mmd) +{ + if (smoke) { + smoke->initHeat(mmd); + smoke->updatePointers(); + } +} + +void manta_smoke_ensure_fire(MANTA *smoke, struct FluidModifierData *mmd) +{ + if (smoke) { + smoke->initFire(mmd); + if (smoke->usingNoise()) { + smoke->initFireHigh(mmd); + } + smoke->updatePointers(); + } +} + +void manta_smoke_ensure_colors(MANTA *smoke, struct FluidModifierData *mmd) +{ + if (smoke) { + smoke->initColors(mmd); + if (smoke->usingNoise()) { + smoke->initColorsHigh(mmd); + } + smoke->updatePointers(); + } +} + +/* Smoke accessors */ +float *manta_smoke_get_density(MANTA *smoke) +{ + return smoke->getDensity(); +} +float *manta_smoke_get_fuel(MANTA *smoke) +{ + return smoke->getFuel(); +} +float *manta_smoke_get_react(MANTA *smoke) +{ + return smoke->getReact(); +} +float *manta_smoke_get_heat(MANTA *smoke) +{ + return smoke->getHeat(); +} +float *manta_smoke_get_flame(MANTA *smoke) +{ + return smoke->getFlame(); +} +float *manta_smoke_get_shadow(MANTA *fluid) +{ + return fluid->getShadow(); +} + +float *manta_smoke_get_color_r(MANTA *smoke) +{ + return smoke->getColorR(); +} +float *manta_smoke_get_color_g(MANTA *smoke) +{ + return smoke->getColorG(); +} +float *manta_smoke_get_color_b(MANTA *smoke) +{ + return smoke->getColorB(); +} + +int *manta_smoke_get_obstacle(MANTA *smoke) +{ + return smoke->getObstacle(); +} + +float *manta_smoke_get_density_in(MANTA *smoke) +{ + return smoke->getDensityIn(); +} +float *manta_smoke_get_heat_in(MANTA *smoke) +{ + return smoke->getHeatIn(); +} +float *manta_smoke_get_color_r_in(MANTA *smoke) +{ + return smoke->getColorRIn(); +} +float *manta_smoke_get_color_g_in(MANTA *smoke) +{ + return smoke->getColorGIn(); +} +float *manta_smoke_get_color_b_in(MANTA *smoke) +{ + return smoke->getColorBIn(); +} +float *manta_smoke_get_fuel_in(MANTA *smoke) +{ + return smoke->getFuelIn(); +} +float *manta_smoke_get_react_in(MANTA *smoke) +{ + return smoke->getReactIn(); +} +float *manta_smoke_get_emission_in(MANTA *smoke) +{ + return smoke->getEmissionIn(); +} + +int manta_smoke_has_heat(MANTA *smoke) +{ + return (smoke->getHeat()) ? 1 : 0; +} +int manta_smoke_has_fuel(MANTA *smoke) +{ + return (smoke->getFuel()) ? 1 : 0; +} +int manta_smoke_has_colors(MANTA *smoke) +{ + return (smoke->getColorR() && smoke->getColorG() && smoke->getColorB()) ? 1 : 0; +} + +float *manta_smoke_turbulence_get_density(MANTA *smoke) +{ + return (smoke && smoke->usingNoise()) ? smoke->getDensityHigh() : nullptr; +} +float *manta_smoke_turbulence_get_fuel(MANTA *smoke) +{ + return (smoke && smoke->usingNoise()) ? smoke->getFuelHigh() : nullptr; +} +float *manta_smoke_turbulence_get_react(MANTA *smoke) +{ + return (smoke && smoke->usingNoise()) ? smoke->getReactHigh() : nullptr; +} +float *manta_smoke_turbulence_get_color_r(MANTA *smoke) +{ + return (smoke && smoke->usingNoise()) ? smoke->getColorRHigh() : nullptr; +} +float *manta_smoke_turbulence_get_color_g(MANTA *smoke) +{ + return (smoke && smoke->usingNoise()) ? smoke->getColorGHigh() : nullptr; +} +float *manta_smoke_turbulence_get_color_b(MANTA *smoke) +{ + return (smoke && smoke->usingNoise()) ? smoke->getColorBHigh() : nullptr; +} +float *manta_smoke_turbulence_get_flame(MANTA *smoke) +{ + return (smoke && smoke->usingNoise()) ? smoke->getFlameHigh() : nullptr; +} + +int manta_smoke_turbulence_has_fuel(MANTA *smoke) +{ + return (smoke->getFuelHigh()) ? 1 : 0; +} +int manta_smoke_turbulence_has_colors(MANTA *smoke) +{ + return (smoke->getColorRHigh() && smoke->getColorGHigh() && smoke->getColorBHigh()) ? 1 : 0; +} + +void manta_smoke_turbulence_get_res(MANTA *smoke, int *res) +{ + if (smoke && smoke->usingNoise()) { + res[0] = smoke->getResXHigh(); + res[1] = smoke->getResYHigh(); + res[2] = smoke->getResZHigh(); + } +} +int manta_smoke_turbulence_get_cells(MANTA *smoke) +{ + int total_cells_high = smoke->getResXHigh() * smoke->getResYHigh() * smoke->getResZHigh(); + return (smoke && smoke->usingNoise()) ? total_cells_high : 0; +} + +/* Liquid functions */ +void manta_liquid_export_script(MANTA *liquid, FluidModifierData *mmd) +{ + if (!liquid || !mmd) + return; + liquid->exportLiquidScript(mmd); +} + +void manta_liquid_ensure_sndparts(MANTA *liquid, struct FluidModifierData *mmd) +{ + if (liquid) { + liquid->initLiquidSndParts(mmd); + liquid->updatePointers(); + } +} + +/* Liquid accessors */ +int manta_liquid_get_particle_res_x(MANTA *liquid) +{ + return liquid->getParticleResX(); +} +int manta_liquid_get_particle_res_y(MANTA *liquid) +{ + return liquid->getParticleResY(); +} +int manta_liquid_get_particle_res_z(MANTA *liquid) +{ + return liquid->getParticleResZ(); +} + +int manta_liquid_get_mesh_res_x(MANTA *liquid) +{ + return liquid->getMeshResX(); +} +int manta_liquid_get_mesh_res_y(MANTA *liquid) +{ + return liquid->getMeshResY(); +} +int manta_liquid_get_mesh_res_z(MANTA *liquid) +{ + return liquid->getMeshResZ(); +} + +int manta_liquid_get_particle_upres(MANTA *liquid) +{ + return liquid->getParticleUpres(); +} +int manta_liquid_get_mesh_upres(MANTA *liquid) +{ + return liquid->getMeshUpres(); +} + +int manta_liquid_get_num_verts(MANTA *liquid) +{ + return liquid->getNumVertices(); +} +int manta_liquid_get_num_normals(MANTA *liquid) +{ + return liquid->getNumNormals(); +} +int manta_liquid_get_num_triangles(MANTA *liquid) +{ + return liquid->getNumTriangles(); +} + +float manta_liquid_get_vertex_x_at(MANTA *liquid, int i) +{ + return liquid->getVertexXAt(i); +} +float manta_liquid_get_vertex_y_at(MANTA *liquid, int i) +{ + return liquid->getVertexYAt(i); +} +float manta_liquid_get_vertex_z_at(MANTA *liquid, int i) +{ + return liquid->getVertexZAt(i); +} + +float manta_liquid_get_normal_x_at(MANTA *liquid, int i) +{ + return liquid->getNormalXAt(i); +} +float manta_liquid_get_normal_y_at(MANTA *liquid, int i) +{ + return liquid->getNormalYAt(i); +} +float manta_liquid_get_normal_z_at(MANTA *liquid, int i) +{ + return liquid->getNormalZAt(i); +} + +int manta_liquid_get_triangle_x_at(MANTA *liquid, int i) +{ + return liquid->getTriangleXAt(i); +} +int manta_liquid_get_triangle_y_at(MANTA *liquid, int i) +{ + return liquid->getTriangleYAt(i); +} +int manta_liquid_get_triangle_z_at(MANTA *liquid, int i) +{ + return liquid->getTriangleZAt(i); +} + +float manta_liquid_get_vertvel_x_at(MANTA *liquid, int i) +{ + return liquid->getVertVelXAt(i); +} +float manta_liquid_get_vertvel_y_at(MANTA *liquid, int i) +{ + return liquid->getVertVelYAt(i); +} +float manta_liquid_get_vertvel_z_at(MANTA *liquid, int i) +{ + return liquid->getVertVelZAt(i); +} + +int manta_liquid_get_num_flip_particles(MANTA *liquid) +{ + return liquid->getNumFlipParticles(); +} +int manta_liquid_get_num_snd_particles(MANTA *liquid) +{ + return liquid->getNumSndParticles(); +} + +int manta_liquid_get_flip_particle_flag_at(MANTA *liquid, int i) +{ + return liquid->getFlipParticleFlagAt(i); +} +int manta_liquid_get_snd_particle_flag_at(MANTA *liquid, int i) +{ + return liquid->getSndParticleFlagAt(i); +} + +float manta_liquid_get_flip_particle_position_x_at(MANTA *liquid, int i) +{ + return liquid->getFlipParticlePositionXAt(i); +} +float manta_liquid_get_flip_particle_position_y_at(MANTA *liquid, int i) +{ + return liquid->getFlipParticlePositionYAt(i); +} +float manta_liquid_get_flip_particle_position_z_at(MANTA *liquid, int i) +{ + return liquid->getFlipParticlePositionZAt(i); +} + +float manta_liquid_get_flip_particle_velocity_x_at(MANTA *liquid, int i) +{ + return liquid->getFlipParticleVelocityXAt(i); +} +float manta_liquid_get_flip_particle_velocity_y_at(MANTA *liquid, int i) +{ + return liquid->getFlipParticleVelocityYAt(i); +} +float manta_liquid_get_flip_particle_velocity_z_at(MANTA *liquid, int i) +{ + return liquid->getFlipParticleVelocityZAt(i); +} + +float manta_liquid_get_snd_particle_position_x_at(MANTA *liquid, int i) +{ + return liquid->getSndParticlePositionXAt(i); +} +float manta_liquid_get_snd_particle_position_y_at(MANTA *liquid, int i) +{ + return liquid->getSndParticlePositionYAt(i); +} +float manta_liquid_get_snd_particle_position_z_at(MANTA *liquid, int i) +{ + return liquid->getSndParticlePositionZAt(i); +} + +float manta_liquid_get_snd_particle_velocity_x_at(MANTA *liquid, int i) +{ + return liquid->getSndParticleVelocityXAt(i); +} +float manta_liquid_get_snd_particle_velocity_y_at(MANTA *liquid, int i) +{ + return liquid->getSndParticleVelocityYAt(i); +} +float manta_liquid_get_snd_particle_velocity_z_at(MANTA *liquid, int i) +{ + return liquid->getSndParticleVelocityZAt(i); +} diff --git a/intern/mantaflow/intern/manta_python_API.cpp b/intern/mantaflow/intern/manta_python_API.cpp new file mode 100644 index 00000000000..66b4a4082c5 --- /dev/null +++ b/intern/mantaflow/intern/manta_python_API.cpp @@ -0,0 +1,36 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sebastian Barschkis (sebbas) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file mantaflow/intern/manta_python_API.cpp + * \ingroup mantaflow + */ + +#include "manta_python_API.h" +#include "manta.h" + +PyObject *Manta_initPython(void) +{ + return Pb::PyInit_Main(); +} diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h new file mode 100644 index 00000000000..b2a709ac4c1 --- /dev/null +++ b/intern/mantaflow/intern/strings/fluid_script.h @@ -0,0 +1,805 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sebastian Barschkis (sebbas) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file mantaflow/intern/strings/shared_script.h + * \ingroup mantaflow + */ + +#include + +////////////////////////////////////////////////////////////////////// +// LIBRARIES +////////////////////////////////////////////////////////////////////// + +const std::string manta_import = + "\ +from manta import *\n\ +import os.path, shutil, math, sys, gc, multiprocessing, platform, time\n\ +\n\ +withMPBake = False # Bake files asynchronously\n\ +withMPSave = True # Save files asynchronously\n\ +isWindows = platform.system() != 'Darwin' and platform.system() != 'Linux'\n\ +# TODO (sebbas): Use this to simulate Windows multiprocessing (has default mode spawn)\n\ +#try:\n\ +# multiprocessing.set_start_method('spawn')\n\ +#except:\n\ +# pass\n\ +\n\ +bpy = sys.modules.get('bpy')\n\ +if bpy is not None:\n\ + sys.executable = bpy.app.binary_path_python\n"; + +////////////////////////////////////////////////////////////////////// +// DEBUG +////////////////////////////////////////////////////////////////////// + +const std::string manta_debuglevel = + "\n\ +def set_manta_debuglevel(level):\n\ + setDebugLevel(level=level)\n # level 0 = mute all output from manta\n"; + +////////////////////////////////////////////////////////////////////// +// SOLVERS +////////////////////////////////////////////////////////////////////// + +const std::string fluid_solver = + "\n\ +mantaMsg('Solver base')\n\ +s$ID$ = Solver(name='solver_base$ID$', gridSize=gs_s$ID$, dim=dim_s$ID$)\n"; + +const std::string fluid_solver_noise = + "\n\ +mantaMsg('Solver noise')\n\ +sn$ID$ = Solver(name='solver_noise$ID$', gridSize=gs_sn$ID$)\n"; + +const std::string fluid_solver_mesh = + "\n\ +mantaMsg('Solver mesh')\n\ +sm$ID$ = Solver(name='solver_mesh$ID$', gridSize=gs_sm$ID$)\n"; + +const std::string fluid_solver_particles = + "\n\ +mantaMsg('Solver particles')\n\ +sp$ID$ = Solver(name='solver_particles$ID$', gridSize=gs_sp$ID$)\n"; + +const std::string fluid_solver_guiding = + "\n\ +mantaMsg('Solver guiding')\n\ +sg$ID$ = Solver(name='solver_guiding$ID$', gridSize=gs_sg$ID$)\n"; + +////////////////////////////////////////////////////////////////////// +// VARIABLES +////////////////////////////////////////////////////////////////////// + +const std::string fluid_variables = + "\n\ +mantaMsg('Fluid variables')\n\ +dim_s$ID$ = $SOLVER_DIM$\n\ +res_s$ID$ = $RES$\n\ +gravity_s$ID$ = vec3($GRAVITY_X$, $GRAVITY_Y$, $GRAVITY_Z$)\n\ +gs_s$ID$ = vec3($RESX$, $RESY$, $RESZ$)\n\ +maxVel_s$ID$ = 0\n\ +\n\ +doOpen_s$ID$ = $DO_OPEN$\n\ +boundConditions_s$ID$ = '$BOUND_CONDITIONS$'\n\ +boundaryWidth_s$ID$ = $BOUNDARY_WIDTH$\n\ +\n\ +using_smoke_s$ID$ = $USING_SMOKE$\n\ +using_liquid_s$ID$ = $USING_LIQUID$\n\ +using_noise_s$ID$ = $USING_NOISE$\n\ +using_adaptTime_s$ID$ = $USING_ADAPTIVETIME$\n\ +using_obstacle_s$ID$ = $USING_OBSTACLE$\n\ +using_guiding_s$ID$ = $USING_GUIDING$\n\ +using_fractions_s$ID$ = $USING_FRACTIONS$\n\ +using_invel_s$ID$ = $USING_INVEL$\n\ +using_outflow_s$ID$ = $USING_OUTFLOW$\n\ +using_sndparts_s$ID$ = $USING_SNDPARTS$\n\ +using_speedvectors_s$ID$ = $USING_SPEEDVECTORS$\n\ +\n\ +# Fluid time params\n\ +timeTotal_s$ID$ = $TIME_TOTAL$\n\ +timePerFrame_s$ID$ = $TIME_PER_FRAME$\n\ +frameLength_s$ID$ = $FRAME_LENGTH$\n\ +dt0_s$ID$ = $DT$\n\ +cflCond_s$ID$ = $CFL$\n\ +timestepsMin_s$ID$ = $TIMESTEPS_MIN$\n\ +timestepsMax_s$ID$ = $TIMESTEPS_MAX$\n\ +\n\ +# Fluid diffusion / viscosity\n\ +domainSize_s$ID$ = $FLUID_DOMAIN_SIZE$ # longest domain side in meters\n\ +viscosity_s$ID$ = $FLUID_VISCOSITY$ / (domainSize_s$ID$*domainSize_s$ID$) # kinematic viscosity in m^2/s\n\ +\n\ +# Factor to convert blender velocities to manta velocities\n\ +toMantaUnitsFac_s$ID$ = (1.0 / (1.0 / res_s$ID$))\n # = dt/dx * 1/dt "; + +const std::string fluid_variables_noise = + "\n\ +mantaMsg('Fluid variables noise')\n\ +upres_sn$ID$ = $NOISE_SCALE$\n\ +gs_sn$ID$ = vec3(upres_sn$ID$*gs_s$ID$.x, upres_sn$ID$*gs_s$ID$.y, upres_sn$ID$*gs_s$ID$.z)\n"; + +const std::string fluid_variables_mesh = + "\n\ +mantaMsg('Fluid variables mesh')\n\ +upres_sm$ID$ = $MESH_SCALE$\n\ +gs_sm$ID$ = vec3(upres_sm$ID$*gs_s$ID$.x, upres_sm$ID$*gs_s$ID$.y, upres_sm$ID$*gs_s$ID$.z)\n"; + +const std::string fluid_variables_particles = + "\n\ +mantaMsg('Fluid variables particles')\n\ +upres_sp$ID$ = $PARTICLE_SCALE$\n\ +gs_sp$ID$ = vec3(upres_sp$ID$*gs_s$ID$.x, upres_sp$ID$*gs_s$ID$.y, upres_sp$ID$*gs_s$ID$.z)\n"; + +const std::string fluid_variables_guiding = + "\n\ +mantaMsg('Fluid variables guiding')\n\ +gs_sg$ID$ = vec3($GUIDING_RESX$, $GUIDING_RESY$, $GUIDING_RESZ$)\n\ +\n\ +alpha_sg$ID$ = $GUIDING_ALPHA$\n\ +beta_sg$ID$ = $GUIDING_BETA$\n\ +gamma_sg$ID$ = $GUIDING_FACTOR$\n\ +tau_sg$ID$ = 1.0\n\ +sigma_sg$ID$ = 0.99/tau_sg$ID$\n\ +theta_sg$ID$ = 1.0\n"; + +const std::string fluid_with_obstacle = + "\n\ +using_obstacle_s$ID$ = True\n"; + +const std::string fluid_with_guiding = + "\n\ +using_guiding_s$ID$ = True\n"; + +const std::string fluid_with_fractions = + "\n\ +using_fractions_s$ID$ = True\n"; + +const std::string fluid_with_invel = + "\n\ +using_invel_s$ID$ = True\n"; + +const std::string fluid_with_outflow = + "\n\ +using_outflow_s$ID$ = True\n"; + +const std::string fluid_with_sndparts = + "\n\ +using_sndparts_s$ID$ = True\n"; + +////////////////////////////////////////////////////////////////////// +// ADAPTIVE TIME STEPPING +////////////////////////////////////////////////////////////////////// + +const std::string fluid_time_stepping = + "\n\ +mantaMsg('Fluid adaptive time stepping')\n\ +s$ID$.frameLength = frameLength_s$ID$\n\ +s$ID$.timestepMin = s$ID$.frameLength / max(1, timestepsMax_s$ID$)\n\ +s$ID$.timestepMax = s$ID$.frameLength / max(1, timestepsMin_s$ID$)\n\ +s$ID$.cfl = cflCond_s$ID$\n\ +s$ID$.timePerFrame = timePerFrame_s$ID$\n\ +s$ID$.timestep = dt0_s$ID$\n\ +s$ID$.timeTotal = timeTotal_s$ID$\n\ +#mantaMsg('timestep: ' + str(s$ID$.timestep) + ' // timPerFrame: ' + str(s$ID$.timePerFrame) + ' // frameLength: ' + str(s$ID$.frameLength) + ' // timeTotal: ' + str(s$ID$.timeTotal) )\n"; + +const std::string fluid_adapt_time_step = + "\n\ +def fluid_adapt_time_step_$ID$():\n\ + mantaMsg('Fluid adapt time step')\n\ + \n\ + # time params are animatable\n\ + s$ID$.frameLength = frameLength_s$ID$\n\ + s$ID$.cfl = cflCond_s$ID$\n\ + \n\ + # ensure that vel grid is full (remember: adaptive domain can reallocate solver)\n\ + copyRealToVec3(sourceX=x_vel_s$ID$, sourceY=y_vel_s$ID$, sourceZ=z_vel_s$ID$, target=vel_s$ID$)\n\ + maxVel_s$ID$ = vel_s$ID$.getMax() if vel_s$ID$ else 0\n\ + if using_adaptTime_s$ID$:\n\ + mantaMsg('Adapt timestep, maxvel: ' + str(maxVel_s$ID$))\n\ + s$ID$.adaptTimestep(maxVel_s$ID$)\n"; + +////////////////////////////////////////////////////////////////////// +// GRIDS +////////////////////////////////////////////////////////////////////// + +const std::string fluid_alloc = + "\n\ +mantaMsg('Fluid alloc data')\n\ +flags_s$ID$ = s$ID$.create(FlagGrid)\n\ +vel_s$ID$ = s$ID$.create(MACGrid)\n\ +velC_s$ID$ = s$ID$.create(MACGrid)\n\ +x_vel_s$ID$ = s$ID$.create(RealGrid)\n\ +y_vel_s$ID$ = s$ID$.create(RealGrid)\n\ +z_vel_s$ID$ = s$ID$.create(RealGrid)\n\ +pressure_s$ID$ = s$ID$.create(RealGrid)\n\ +phiObs_s$ID$ = s$ID$.create(LevelsetGrid)\n\ +phiIn_s$ID$ = s$ID$.create(LevelsetGrid)\n\ +phiOut_s$ID$ = s$ID$.create(LevelsetGrid)\n\ +forces_s$ID$ = s$ID$.create(Vec3Grid)\n\ +x_force_s$ID$ = s$ID$.create(RealGrid)\n\ +y_force_s$ID$ = s$ID$.create(RealGrid)\n\ +z_force_s$ID$ = s$ID$.create(RealGrid)\n\ +obvel_s$ID$ = None\n\ +\n\ +# Keep track of important objects in dict to load them later on\n\ +fluid_data_dict_s$ID$ = dict(vel=vel_s$ID$, phiObs=phiObs_s$ID$, phiIn=phiIn_s$ID$, phiOut=phiOut_s$ID$, flags=flags_s$ID$)\n"; + +const std::string fluid_alloc_obstacle = + "\n\ +mantaMsg('Allocating obstacle data')\n\ +numObs_s$ID$ = s$ID$.create(IntGrid)\n\ +phiObsIn_s$ID$ = s$ID$.create(LevelsetGrid)\n\ +obvel_s$ID$ = s$ID$.create(MACGrid)\n\ +obvelC_s$ID$ = s$ID$.create(Vec3Grid)\n\ +x_obvel_s$ID$ = s$ID$.create(RealGrid)\n\ +y_obvel_s$ID$ = s$ID$.create(RealGrid)\n\ +z_obvel_s$ID$ = s$ID$.create(RealGrid)\n\ +\n\ +tmpDict_s$ID$ = dict(phiObsIn=phiObsIn_s$ID$)\n\ +fluid_data_dict_s$ID$.update(tmpDict_s$ID$)\n"; + +const std::string fluid_alloc_guiding = + "\n\ +mantaMsg('Allocating guiding data')\n\ +velT_s$ID$ = s$ID$.create(MACGrid)\n\ +weightGuide_s$ID$ = s$ID$.create(RealGrid)\n\ +numGuides_s$ID$ = s$ID$.create(IntGrid)\n\ +phiGuideIn_s$ID$ = s$ID$.create(LevelsetGrid)\n\ +guidevelC_s$ID$ = s$ID$.create(Vec3Grid)\n\ +x_guidevel_s$ID$ = s$ID$.create(RealGrid)\n\ +y_guidevel_s$ID$ = s$ID$.create(RealGrid)\n\ +z_guidevel_s$ID$ = s$ID$.create(RealGrid)\n\ +\n\ +# Final guide vel grid needs to have independent size\n\ +guidevel_sg$ID$ = sg$ID$.create(MACGrid)\n\ +\n\ +# Keep track of important objects in dict to load them later on\n\ +fluid_guiding_dict_s$ID$ = dict(guidevel=guidevel_sg$ID$)\n"; + +const std::string fluid_alloc_fractions = + "\n\ +mantaMsg('Allocating fractions data')\n\ +fractions_s$ID$ = s$ID$.create(MACGrid)\n"; + +const std::string fluid_alloc_invel = + "\n\ +mantaMsg('Allocating initial velocity data')\n\ +invelC_s$ID$ = s$ID$.create(VecGrid)\n\ +invel_s$ID$ = s$ID$.create(MACGrid)\n\ +x_invel_s$ID$ = s$ID$.create(RealGrid)\n\ +y_invel_s$ID$ = s$ID$.create(RealGrid)\n\ +z_invel_s$ID$ = s$ID$.create(RealGrid)\n"; + +const std::string fluid_alloc_outflow = + "\n\ +mantaMsg('Allocating outflow data')\n\ +phiOutIn_s$ID$ = s$ID$.create(LevelsetGrid)\n"; + +const std::string fluid_alloc_sndparts = + "\n\ +mantaMsg('Allocating snd parts low')\n\ +ppSnd_sp$ID$ = sp$ID$.create(BasicParticleSystem)\n\ +pVelSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataVec3)\n\ +pForceSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataVec3)\n\ +pLifeSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataReal)\n\ +vel_sp$ID$ = sp$ID$.create(MACGrid)\n\ +flags_sp$ID$ = sp$ID$.create(FlagGrid)\n\ +phi_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\ +phiIn_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\ +phiObs_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\ +phiObsIn_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\ +\n\ +# Keep track of important objects in dict to load them later on\n\ +fluid_particles_dict_s$ID$ = dict(ppSnd=ppSnd_sp$ID$, pVelSnd=pVelSnd_pp$ID$, pLifeSnd=pLifeSnd_pp$ID$)\n"; + +////////////////////////////////////////////////////////////////////// +// PRE / POST STEP +////////////////////////////////////////////////////////////////////// + +const std::string fluid_pre_step = + "\n\ +def fluid_pre_step_$ID$():\n\ + mantaMsg('Fluid pre step')\n\ + \n\ + phiObs_s$ID$.setConst(9999)\n\ + phiOut_s$ID$.setConst(9999)\n\ + \n\ + # Main vel grid is copied in adapt time step function\n\ + \n\ + # translate obvels (world space) to grid space\n\ + if using_obstacle_s$ID$:\n\ + x_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ + y_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ + z_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ + copyRealToVec3(sourceX=x_obvel_s$ID$, sourceY=y_obvel_s$ID$, sourceZ=z_obvel_s$ID$, target=obvelC_s$ID$)\n\ + \n\ + # translate invels (world space) to grid space\n\ + if using_invel_s$ID$:\n\ + x_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ + y_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ + z_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ + copyRealToVec3(sourceX=x_invel_s$ID$, sourceY=y_invel_s$ID$, sourceZ=z_invel_s$ID$, target=invelC_s$ID$)\n\ + \n\ + if using_guiding_s$ID$:\n\ + weightGuide_s$ID$.multConst(0)\n\ + weightGuide_s$ID$.addConst(alpha_sg$ID$)\n\ + interpolateMACGrid(source=guidevel_sg$ID$, target=velT_s$ID$)\n\ + velT_s$ID$.multConst(vec3(gamma_sg$ID$))\n\ + \n\ + # translate external forces (world space) to grid space\n\ + x_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ + y_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ + z_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ + copyRealToVec3(sourceX=x_force_s$ID$, sourceY=y_force_s$ID$, sourceZ=z_force_s$ID$, target=forces_s$ID$)\n\ + \n\ + # If obstacle has velocity, i.e. is a moving obstacle, switch to dynamic preconditioner\n\ + if using_smoke_s$ID$ and using_obstacle_s$ID$ and obvelC_s$ID$.getMax() > 0:\n\ + mantaMsg('Using dynamic preconditioner')\n\ + preconditioner_s$ID$ = PcMGDynamic\n\ + else:\n\ + mantaMsg('Using static preconditioner')\n\ + preconditioner_s$ID$ = PcMGStatic\n"; + +const std::string fluid_post_step = + "\n\ +def fluid_post_step_$ID$():\n\ + mantaMsg('Fluid post step')\n\ + forces_s$ID$.clear()\n\ + x_force_s$ID$.clear()\n\ + y_force_s$ID$.clear()\n\ + z_force_s$ID$.clear()\n\ + \n\ + if using_guiding_s$ID$:\n\ + weightGuide_s$ID$.clear()\n\ + if using_invel_s$ID$:\n\ + x_invel_s$ID$.clear()\n\ + y_invel_s$ID$.clear()\n\ + z_invel_s$ID$.clear()\n\ + invel_s$ID$.clear()\n\ + invelC_s$ID$.clear()\n\ + \n\ + # Copy vel grid to reals grids (which Blender internal will in turn use for vel access)\n\ + copyVec3ToReal(source=vel_s$ID$, targetX=x_vel_s$ID$, targetY=y_vel_s$ID$, targetZ=z_vel_s$ID$)\n"; + +////////////////////////////////////////////////////////////////////// +// DESTRUCTION +////////////////////////////////////////////////////////////////////// + +const std::string fluid_delete_all = + "\n\ +mantaMsg('Deleting fluid')\n\ +# Clear all helper dictionaries first\n\ +mantaMsg('Clear helper dictionaries')\n\ +if 'liquid_data_dict_s$ID$' in globals(): liquid_data_dict_s$ID$.clear()\n\ +if 'liquid_flip_dict_s$ID$' in globals(): liquid_flip_dict_s$ID$.clear()\n\ +if 'liquid_mesh_dict_s$ID$' in globals(): liquid_mesh_dict_s$ID$.clear()\n\ +if 'liquid_meshvel_dict_s$ID$' in globals(): liquid_meshvel_dict_s$ID$.clear()\n\ +if 'liquid_particles_dict_s$ID$' in globals(): liquid_particles_dict_s$ID$.clear()\n\ +if 'smoke_data_dict_s$ID$' in globals(): smoke_data_dict_s$ID$.clear()\n\ +if 'smoke_noise_dict_s$ID$' in globals(): smoke_noise_dict_s$ID$.clear()\n\ +if 'fluid_particles_dict_s$ID$' in globals(): fluid_particles_dict_s$ID$.clear()\n\ +if 'fluid_guiding_dict_s$ID$' in globals(): fluid_guiding_dict_s$ID$.clear()\n\ +if 'fluid_data_dict_s$ID$' in globals(): fluid_data_dict_s$ID$.clear()\n\ +if 'fluid_vel_dict_s$ID$' in globals(): fluid_vel_dict_s$ID$.clear()\n\ +\n\ +# Delete all childs from objects (e.g. pdata for particles)\n\ +mantaMsg('Release solver childs childs')\n\ +for var in list(globals()):\n\ + if var.endswith('_pp$ID$') or var.endswith('_mesh$ID$'):\n\ + del globals()[var]\n\ +\n\ +# Now delete childs from solver objects\n\ +mantaMsg('Release solver childs')\n\ +for var in list(globals()):\n\ + if var.endswith('_s$ID$') or var.endswith('_sn$ID$') or var.endswith('_sm$ID$') or var.endswith('_sp$ID$') or var.endswith('_sg$ID$'):\n\ + del globals()[var]\n\ +\n\ +# Extra cleanup for multigrid and fluid guiding\n\ +mantaMsg('Release multigrid')\n\ +if 's$ID$' in globals(): releaseMG(s$ID$)\n\ +if 'sn$ID$' in globals(): releaseMG(sn$ID$)\n\ +mantaMsg('Release fluid guiding')\n\ +releaseBlurPrecomp()\n\ +\n\ +# Release unreferenced memory (if there is some left, can in fact happen)\n\ +gc.collect()\n\ +\n\ +# Now it is safe to delete solver objects (always need to be deleted last)\n\ +mantaMsg('Delete base solver')\n\ +if 's$ID$' in globals(): del s$ID$\n\ +mantaMsg('Delete noise solver')\n\ +if 'sn$ID$' in globals(): del sn$ID$\n\ +mantaMsg('Delete mesh solver')\n\ +if 'sm$ID$' in globals(): del sm$ID$\n\ +mantaMsg('Delete particle solver')\n\ +if 'sp$ID$' in globals(): del sp$ID$\n\ +mantaMsg('Delete guiding solver')\n\ +if 'sg$ID$' in globals(): del sg$ID$\n\ +\n\ +# Release unreferenced memory (if there is some left)\n\ +gc.collect()\n"; + +////////////////////////////////////////////////////////////////////// +// BAKE +////////////////////////////////////////////////////////////////////// + +const std::string fluid_cache_helper = + "\n\ +def fluid_cache_get_framenr_formatted_$ID$(framenr):\n\ + return str(framenr).zfill(4) # framenr with leading zeroes\n"; + +const std::string fluid_bake_multiprocessing = + "\n\ +def fluid_cache_multiprocessing_start_$ID$(function, framenr, format_data=None, format_noise=None, format_mesh=None, format_particles=None, format_guiding=None, path_data=None, path_noise=None, path_mesh=None, path_particles=None, path_guiding=None, dict=None, do_join=True):\n\ + mantaMsg('Multiprocessing cache')\n\ + if __name__ == '__main__':\n\ + args = (framenr,)\n\ + if format_data:\n\ + args += (format_data,)\n\ + if format_noise:\n\ + args += (format_noise,)\n\ + if format_mesh:\n\ + args += (format_mesh,)\n\ + if format_particles:\n\ + args += (format_particles,)\n\ + if format_guiding:\n\ + args += (format_guiding,)\n\ + if path_data:\n\ + args += (path_data,)\n\ + if path_noise:\n\ + args += (path_noise,)\n\ + if path_mesh:\n\ + args += (path_mesh,)\n\ + if path_particles:\n\ + args += (path_particles,)\n\ + if path_guiding:\n\ + args += (path_guiding,)\n\ + if dict:\n\ + args += (dict,)\n\ + p$ID$ = multiprocessing.Process(target=function, args=args)\n\ + p$ID$.start()\n\ + if do_join:\n\ + p$ID$.join()\n"; + +const std::string fluid_bake_data = + "\n\ +def bake_fluid_process_data_$ID$(framenr, format_data, format_particles, format_guiding, path_data, path_guiding):\n\ + mantaMsg('Bake fluid data')\n\ + \n\ + s$ID$.frame = framenr\n\ + # Must not set 'timeTotal' here. Remember, this function is called from manta.c while-loop\n\ + \n\ + start_time = time.time()\n\ + if using_smoke_s$ID$:\n\ + smoke_adaptive_step_$ID$(framenr)\n\ + if using_liquid_s$ID$:\n\ + liquid_adaptive_step_$ID$(framenr)\n\ + mantaMsg('--- Step: %s seconds ---' % (time.time() - start_time))\n\ +\n\ +def bake_fluid_data_$ID$(path_data, path_guiding, framenr, format_data, format_particles, format_guiding):\n\ + if not withMPBake or isWindows:\n\ + bake_fluid_process_data_$ID$(framenr, format_data, format_particles, format_guiding, path_data, path_guiding)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=bake_fluid_process_data_$ID$, framenr=framenr, format_data=format_data, format_particles=format_particles, format_guiding=format_guiding, path_data=path_data, path_guiding=path_guiding, do_join=False)\n"; + +const std::string fluid_bake_noise = + "\n\ +def bake_noise_process_$ID$(framenr, format_data, format_noise, path_data, path_noise):\n\ + mantaMsg('Bake fluid noise')\n\ + \n\ + sn$ID$.frame = framenr\n\ + sn$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\ + sn$ID$.timestep = dt0_s$ID$\n\ + mantaMsg('sn$ID$.timeTotal: ' + str(sn$ID$.timeTotal))\n\ + \n\ + smoke_step_noise_$ID$(framenr)\n\ + smoke_save_noise_$ID$(path_noise, framenr, format_noise)\n\ +\n\ +def bake_noise_$ID$(path_data, path_noise, framenr, format_data, format_noise):\n\ + if not withMPBake or isWindows:\n\ + bake_noise_process_$ID$(framenr, format_data, format_noise, path_data, path_noise)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=bake_noise_process_$ID$, framenr=framenr, format_data=format_data, format_noise=format_noise, path_data=path_data, path_noise=path_noise)\n"; + +const std::string fluid_bake_mesh = + "\n\ +def bake_mesh_process_$ID$(framenr, format_data, format_mesh, format_particles, path_data, path_mesh):\n\ + mantaMsg('Bake fluid mesh')\n\ + \n\ + sm$ID$.frame = framenr\n\ + sm$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\ + sm$ID$.timestep = dt0_s$ID$\n\ + \n\ + #if using_smoke_s$ID$:\n\ + # TODO (sebbas): Future update could include smoke mesh (vortex sheets)\n\ + if using_liquid_s$ID$:\n\ + liquid_step_mesh_$ID$()\n\ + liquid_save_mesh_$ID$(path_mesh, framenr, format_mesh)\n\ + if using_speedvectors_s$ID$:\n\ + liquid_save_meshvel_$ID$(path_mesh, framenr, format_data)\n\ +\n\ +def bake_mesh_$ID$(path_data, path_mesh, framenr, format_data, format_mesh, format_particles):\n\ + if not withMPBake or isWindows:\n\ + bake_mesh_process_$ID$(framenr, format_data, format_mesh, format_particles, path_data, path_mesh)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=bake_mesh_process_$ID$, framenr=framenr, format_data=format_data, format_mesh=format_mesh, format_particles=format_particles, path_data=path_data, path_mesh=path_mesh)\n"; + +const std::string fluid_bake_particles = + "\n\ +def bake_particles_process_$ID$(framenr, format_data, format_particles, path_data, path_particles):\n\ + mantaMsg('Bake secondary particles')\n\ + \n\ + sp$ID$.frame = framenr\n\ + sp$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\ + sp$ID$.timestep = dt0_s$ID$\n\ + \n\ + fluid_load_data_$ID$(path_data, framenr, format_data)\n\ + #if using_smoke_s$ID$:\n\ + # TODO (sebbas): Future update could include smoke particles (e.g. fire sparks)\n\ + if using_liquid_s$ID$:\n\ + liquid_load_data_$ID$(path_data, framenr, format_data)\n\ + liquid_step_particles_$ID$()\n\ + fluid_save_particles_$ID$(path_particles, framenr, format_particles)\n\ + liquid_save_particles_$ID$(path_particles, framenr, format_particles)\n\ +\n\ +def bake_particles_$ID$(path_data, path_particles, framenr, format_data, format_particles):\n\ + if not withMPBake or isWindows:\n\ + bake_particles_process_$ID$(framenr, format_data, format_particles, path_data, path_particles)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=bake_particles_process_$ID$, framenr=framenr, format_data=format_data, format_particles=format_particles, path_data=path_data, path_particles=path_particles)\n"; + +const std::string fluid_bake_guiding = + "\n\ +def bake_guiding_process_$ID$(framenr, format_guiding, path_guiding):\n\ + mantaMsg('Bake fluid guiding')\n\ + \n\ + if framenr>1:\n\ + fluid_load_guiding_$ID$(path_guiding, framenr-1, format_guiding)\n\ + \n\ + x_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\ + y_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\ + z_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\ + copyRealToVec3(sourceX=x_guidevel_s$ID$, sourceY=y_guidevel_s$ID$, sourceZ=z_guidevel_s$ID$, target=guidevelC_s$ID$)\n\ + \n\ + mantaMsg('Extrapolating guiding velocity')\n\ + # ensure velocities inside of guiding object, slightly add guiding vels outside of object too\n\ + extrapolateVec3Simple(vel=guidevelC_s$ID$, phi=phiGuideIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\ + extrapolateVec3Simple(vel=guidevelC_s$ID$, phi=phiGuideIn_s$ID$, distance=4, inside=False)\n\ + resampleVec3ToMac(source=guidevelC_s$ID$, target=guidevel_sg$ID$)\n\ + \n\ + fluid_save_guiding_$ID$(path_guiding, framenr, format_guiding)\n\ +\n\ +def bake_guiding_$ID$(path_guiding, framenr, format_guiding):\n\ + if not withMPBake or isWindows:\n\ + bake_guiding_process_$ID$(framenr, format_guiding, path_guiding)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=bake_guiding_process_$ID$, framenr=framenr, format_guiding=format_guiding, path_guiding=path_guiding)\n"; + +////////////////////////////////////////////////////////////////////// +// IMPORT +////////////////////////////////////////////////////////////////////// + +const std::string fluid_file_import = + "\n\ +def fluid_file_import_s$ID$(dict, path, framenr, file_format):\n\ + try:\n\ + framenr = fluid_cache_get_framenr_formatted_$ID$(framenr)\n\ + for name, object in dict.items():\n\ + file = os.path.join(path, name + '_' + framenr + file_format)\n\ + if os.path.isfile(file):\n\ + object.load(file)\n\ + else:\n\ + mantaMsg('Could not load file ' + str(file))\n\ + except:\n\ + mantaMsg('exception found')\n\ + #mantaMsg(str(e))\n\ + pass # Just skip file load errors for now\n"; + +const std::string fluid_load_particles = + "\n\ +def fluid_load_particles_$ID$(path, framenr, file_format):\n\ + mantaMsg('Fluid load particles, frame ' + str(framenr))\n\ + fluid_file_import_s$ID$(dict=fluid_particles_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n"; + +const std::string fluid_load_data = + "\n\ +def fluid_load_data_$ID$(path, framenr, file_format):\n\ + mantaMsg('Fluid load data, frame ' + str(framenr))\n\ + fluid_file_import_s$ID$(dict=fluid_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\ + \n\ + # When adaptive domain bake is resumed we need correct values in xyz vel grids\n\ + copyVec3ToReal(source=vel_s$ID$, targetX=x_vel_s$ID$, targetY=y_vel_s$ID$, targetZ=z_vel_s$ID$)\n"; + +const std::string fluid_load_guiding = + "\n\ +def fluid_load_guiding_$ID$(path, framenr, file_format):\n\ + mantaMsg('Fluid load guiding, frame ' + str(framenr))\n\ + fluid_file_import_s$ID$(dict=fluid_guiding_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n"; + +const std::string fluid_load_vel = + "\n\ +def fluid_load_vel_$ID$(path, framenr, file_format):\n\ + mantaMsg('Fluid load vel, frame ' + str(framenr))\n\ + fluid_vel_dict = dict(vel=guidevel_sg$ID$)\n\ + fluid_file_import_s$ID$(dict=fluid_vel_dict, path=path, framenr=framenr, file_format=file_format)\n"; + +////////////////////////////////////////////////////////////////////// +// EXPORT +////////////////////////////////////////////////////////////////////// + +const std::string fluid_file_export = + "\n\ +def fluid_file_export_s$ID$(framenr, file_format, path, dict, mode_override=True, skip_subframes=True):\n\ + if skip_subframes and ((timePerFrame_s$ID$ + dt0_s$ID$) < frameLength_s$ID$):\n\ + return\n\ + mantaMsg('Fluid file export, frame: ' + str(framenr))\n\ + try:\n\ + framenr = fluid_cache_get_framenr_formatted_$ID$(framenr)\n\ + if not os.path.exists(path):\n\ + os.makedirs(path)\n\ + for name, object in dict.items():\n\ + file = os.path.join(path, name + '_' + framenr + file_format)\n\ + if not os.path.isfile(file) or mode_override: object.save(file)\n\ + except Exception as e:\n\ + mantaMsg(str(e))\n\ + pass # Just skip file save errors for now\n"; + +const std::string fluid_save_particles = + "\n\ +def fluid_save_particles_$ID$(path, framenr, file_format):\n\ + mantaMsg('Liquid save particles, frame ' + str(framenr))\n\ + if not withMPSave or isWindows:\n\ + fluid_file_export_s$ID$(dict=fluid_particles_dict_s$ID$, framenr=framenr, file_format=file_format, path=path)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=fluid_particles_dict_s$ID$, do_join=False)\n"; + +const std::string fluid_save_data = + "\n\ +def fluid_save_data_$ID$(path, framenr, file_format):\n\ + mantaMsg('Fluid save data, frame ' + str(framenr))\n\ + start_time = time.time()\n\ + if not withMPSave or isWindows:\n\ + fluid_file_export_s$ID$(framenr=framenr, file_format=file_format, path=path, dict=fluid_data_dict_s$ID$)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=fluid_data_dict_s$ID$, do_join=False)\n\ + mantaMsg('--- Save: %s seconds ---' % (time.time() - start_time))\n"; + +const std::string fluid_save_guiding = + "\n\ +def fluid_save_guiding_$ID$(path, framenr, file_format):\n\ + mantaMsg('Fluid save guiding, frame ' + str(framenr))\n\ + if not withMPSave or isWindows:\n\ + fluid_file_export_s$ID$(dict=fluid_guiding_dict_s$ID$, framenr=framenr, file_format=file_format, path=path)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=fluid_guiding_dict_s$ID$, do_join=False)\n"; + +////////////////////////////////////////////////////////////////////// +// STANDALONE MODE +////////////////////////////////////////////////////////////////////// + +const std::string fluid_standalone = + "\n\ +gui = None\n\ +if (GUI):\n\ + gui=Gui()\n\ + gui.show()\n\ + gui.pause()\n\ +\n\ +cache_dir = '$CACHE_DIR$'\n\ +file_format_data = '.uni'\n\ +file_format_noise = '.uni'\n\ +file_format_particles = '.uni'\n\ +file_format_mesh = '.bobj.gz'\n\ +\n\ +# Start and stop for simulation\n\ +current_frame = $CURRENT_FRAME$\n\ +end_frame = $END_FRAME$\n\ +\n\ +# How many frame to load from cache\n\ +from_cache_cnt = 100\n\ +\n\ +loop_cnt = 0\n\ +while current_frame <= end_frame:\n\ + \n\ + # Load already simulated data from cache:\n\ + if loop_cnt < from_cache_cnt:\n\ + load(current_frame)\n\ + \n\ + # Otherwise simulate new data\n\ + else:\n\ + while(s$ID$.frame <= current_frame):\n\ + if using_adaptTime_s$ID$:\n\ + fluid_adapt_time_step_$ID$()\n\ + step(current_frame)\n\ + \n\ + current_frame += 1\n\ + loop_cnt += 1\n\ + \n\ + if gui:\n\ + gui.pause()\n"; + +////////////////////////////////////////////////////////////////////// +// SCRIPT SECTION HEADERS +////////////////////////////////////////////////////////////////////// + +const std::string header_libraries = + "\n\ +######################################################################\n\ +## LIBRARIES\n\ +######################################################################\n"; + +const std::string header_main = + "\n\ +######################################################################\n\ +## MAIN\n\ +######################################################################\n"; + +const std::string header_prepost = + "\n\ +######################################################################\n\ +## PRE/POST STEPS\n\ +######################################################################\n"; + +const std::string header_steps = + "\n\ +######################################################################\n\ +## STEPS\n\ +######################################################################\n"; + +const std::string header_import = + "\n\ +######################################################################\n\ +## IMPORT\n\ +######################################################################\n"; + +const std::string header_grids = + "\n\ +######################################################################\n\ +## GRIDS\n\ +######################################################################\n"; + +const std::string header_solvers = + "\n\ +######################################################################\n\ +## SOLVERS\n\ +######################################################################\n"; + +const std::string header_variables = + "\n\ +######################################################################\n\ +## VARIABLES\n\ +######################################################################\n"; + +const std::string header_time = + "\n\ +######################################################################\n\ +## ADAPTIVE TIME\n\ +######################################################################\n"; + +const std::string header_gridinit = + "\n\ +######################################################################\n\ +## DOMAIN INIT\n\ +######################################################################\n"; diff --git a/intern/mantaflow/intern/strings/liquid_script.h b/intern/mantaflow/intern/strings/liquid_script.h new file mode 100644 index 00000000000..0569dfc6810 --- /dev/null +++ b/intern/mantaflow/intern/strings/liquid_script.h @@ -0,0 +1,462 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sebastian Barschkis (sebbas) + * Georg Kohl + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file mantaflow/intern/strings/liquid.h + * \ingroup mantaflow + */ + +#include + +////////////////////////////////////////////////////////////////////// +// VARIABLES +////////////////////////////////////////////////////////////////////// + +const std::string liquid_variables = + "\n\ +mantaMsg('Liquid variables')\n\ +narrowBandWidth_s$ID$ = 3\n\ +combineBandWidth_s$ID$ = narrowBandWidth_s$ID$ - 1\n\ +adjustedNarrowBandWidth_s$ID$ = $PARTICLE_BAND_WIDTH$ # only used in adjustNumber to control band width\n\ +particleNumber_s$ID$ = $PARTICLE_NUMBER$\n\ +minParticles_s$ID$ = $PARTICLE_MINIMUM$\n\ +maxParticles_s$ID$ = $PARTICLE_MAXIMUM$\n\ +radiusFactor_s$ID$ = $PARTICLE_RADIUS$\n\ +using_mesh_s$ID$ = $USING_MESH$\n\ +using_final_mesh_s$ID$ = $USING_IMPROVED_MESH$\n\ +using_fractions_s$ID$ = $USING_FRACTIONS$\n\ +fracThreshold_s$ID$ = $FRACTIONS_THRESHOLD$\n\ +flipRatio_s$ID$ = $FLIP_RATIO$\n\ +concaveUpper_s$ID$ = $MESH_CONCAVE_UPPER$\n\ +concaveLower_s$ID$ = $MESH_CONCAVE_LOWER$\n\ +meshRadiusFactor_s$ID$ = $MESH_PARTICLE_RADIUS$\n\ +smoothenPos_s$ID$ = $MESH_SMOOTHEN_POS$\n\ +smoothenNeg_s$ID$ = $MESH_SMOOTHEN_NEG$\n\ +randomness_s$ID$ = $PARTICLE_RANDOMNESS$\n\ +surfaceTension_s$ID$ = $LIQUID_SURFACE_TENSION$\n"; + +const std::string liquid_variables_particles = + "\n\ +tauMin_wc_sp$ID$ = $SNDPARTICLE_TAU_MIN_WC$\n\ +tauMax_wc_sp$ID$ = $SNDPARTICLE_TAU_MAX_WC$\n\ +tauMin_ta_sp$ID$ = $SNDPARTICLE_TAU_MIN_TA$\n\ +tauMax_ta_sp$ID$ = $SNDPARTICLE_TAU_MAX_TA$\n\ +tauMin_k_sp$ID$ = $SNDPARTICLE_TAU_MIN_K$\n\ +tauMax_k_sp$ID$ = $SNDPARTICLE_TAU_MAX_K$\n\ +k_wc_sp$ID$ = $SNDPARTICLE_K_WC$\n\ +k_ta_sp$ID$ = $SNDPARTICLE_K_TA$\n\ +k_b_sp$ID$ = $SNDPARTICLE_K_B$\n\ +k_d_sp$ID$ = $SNDPARTICLE_K_D$\n\ +lMin_sp$ID$ = $SNDPARTICLE_L_MIN$\n\ +lMax_sp$ID$ = $SNDPARTICLE_L_MAX$\n\ +c_s_sp$ID$ = 0.4 # classification constant for snd parts\n\ +c_b_sp$ID$ = 0.77 # classification constant for snd parts\n\ +pot_radius_sp$ID$ = $SNDPARTICLE_POTENTIAL_RADIUS$\n\ +update_radius_sp$ID$ = $SNDPARTICLE_UPDATE_RADIUS$\n\ +scaleFromManta_sp$ID$ = $FLUID_DOMAIN_SIZE$ / float(res_s$ID$) # resize factor for snd parts\n"; + +////////////////////////////////////////////////////////////////////// +// GRIDS & MESH & PARTICLESYSTEM +////////////////////////////////////////////////////////////////////// + +const std::string liquid_alloc = + "\n\ +mantaMsg('Liquid alloc')\n\ +phiParts_s$ID$ = s$ID$.create(LevelsetGrid)\n\ +phi_s$ID$ = s$ID$.create(LevelsetGrid)\n\ +phiTmp_s$ID$ = s$ID$.create(LevelsetGrid)\n\ +curvature_s$ID$ = s$ID$.create(RealGrid)\n\ +velOld_s$ID$ = s$ID$.create(MACGrid)\n\ +velParts_s$ID$ = s$ID$.create(MACGrid)\n\ +mapWeights_s$ID$ = s$ID$.create(MACGrid)\n\ +fractions_s$ID$ = None # allocated dynamically\n\ +\n\ +pp_s$ID$ = s$ID$.create(BasicParticleSystem)\n\ +pVel_pp$ID$ = pp_s$ID$.create(PdataVec3)\n\ +\n\ +# Acceleration data for particle nbs\n\ +pindex_s$ID$ = s$ID$.create(ParticleIndexSystem)\n\ +gpi_s$ID$ = s$ID$.create(IntGrid)\n\ +\n\ +# Keep track of important objects in dict to load them later on\n\ +liquid_data_dict_s$ID$ = dict(phiParts=phiParts_s$ID$, phi=phi_s$ID$, phiTmp=phiTmp_s$ID$)\n\ +liquid_flip_dict_s$ID$ = dict(pp=pp_s$ID$, pVel=pVel_pp$ID$)\n"; + +const std::string liquid_alloc_mesh = + "\n\ +mantaMsg('Liquid alloc mesh')\n\ +phiParts_sm$ID$ = sm$ID$.create(LevelsetGrid)\n\ +phi_sm$ID$ = sm$ID$.create(LevelsetGrid)\n\ +pp_sm$ID$ = sm$ID$.create(BasicParticleSystem)\n\ +flags_sm$ID$ = sm$ID$.create(FlagGrid)\n\ +mesh_sm$ID$ = sm$ID$.create(Mesh)\n\ +\n\ +if using_speedvectors_s$ID$:\n\ + mVel_mesh$ID$ = mesh_sm$ID$.create(MdataVec3)\n\ + vel_sm$ID$ = sm$ID$.create(MACGrid)\n\ +\n\ +# Acceleration data for particle nbs\n\ +pindex_sm$ID$ = sm$ID$.create(ParticleIndexSystem)\n\ +gpi_sm$ID$ = sm$ID$.create(IntGrid)\n\ +\n\ +# Keep track of important objects in dict to load them later on\n\ +liquid_mesh_dict_s$ID$ = dict(lMesh=mesh_sm$ID$)\n\ +\n\ +if using_speedvectors_s$ID$:\n\ + liquid_meshvel_dict_s$ID$ = dict(lVelMesh=mVel_mesh$ID$)\n"; + +const std::string liquid_alloc_particles = + "\n\ +normal_sp$ID$ = sp$ID$.create(VecGrid)\n\ +neighborRatio_sp$ID$ = sp$ID$.create(RealGrid)\n\ +trappedAir_sp$ID$ = sp$ID$.create(RealGrid)\n\ +waveCrest_sp$ID$ = sp$ID$.create(RealGrid)\n\ +kineticEnergy_sp$ID$ = sp$ID$.create(RealGrid)\n\ +\n\ +# Keep track of important objects in dict to load them later on\n\ +liquid_particles_dict_s$ID$ = dict(trappedAir=trappedAir_sp$ID$, waveCrest=waveCrest_sp$ID$, kineticEnergy=kineticEnergy_sp$ID$)\n"; + +const std::string liquid_init_phi = + "\n\ +# Prepare domain\n\ +phi_s$ID$.initFromFlags(flags_s$ID$)\n\ +phiIn_s$ID$.initFromFlags(flags_s$ID$)\n"; + +////////////////////////////////////////////////////////////////////// +// STEP FUNCTIONS +////////////////////////////////////////////////////////////////////// + +const std::string liquid_adaptive_step = + "\n\ +def liquid_adaptive_step_$ID$(framenr):\n\ + mantaMsg('Manta step, frame ' + str(framenr))\n\ + s$ID$.frame = framenr\n\ + \n\ + fluid_pre_step_$ID$()\n\ + \n\ + flags_s$ID$.initDomain(boundaryWidth=1 if using_fractions_s$ID$ else 0, phiWalls=phiObs_s$ID$, outflow=boundConditions_s$ID$)\n\ + \n\ + if using_obstacle_s$ID$:\n\ + mantaMsg('Initializing obstacle levelset')\n\ + phiObsIn_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\ + extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\ + extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\ + phiObs_s$ID$.join(phiObsIn_s$ID$)\n\ + \n\ + # Using boundaryWidth=2 to not search beginning from walls (just a performance optimization)\n\ + # Additional sanity check: fill holes in phiObs which can result after joining with phiObsIn\n\ + phiObs_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\ + extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\ + extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\ + \n\ + mantaMsg('Initializing fluid levelset')\n\ + extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\ + extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\ + phi_s$ID$.join(phiIn_s$ID$)\n\ + \n\ + if using_obstacle_s$ID$:\n\ + phi_s$ID$.subtract(phiObsIn_s$ID$)\n\ + \n\ + if using_outflow_s$ID$:\n\ + phiOut_s$ID$.join(phiOutIn_s$ID$)\n\ + \n\ + if using_fractions_s$ID$:\n\ + updateFractions(flags=flags_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$, boundaryWidth=boundaryWidth_s$ID$, fracThreshold=fracThreshold_s$ID$)\n\ + setObstacleFlags(flags=flags_s$ID$, phiObs=phiObs_s$ID$, phiOut=phiOut_s$ID$, fractions=fractions_s$ID$, phiIn=phiIn_s$ID$)\n\ + \n\ + # add initial velocity: set invel as source grid to ensure const vels in inflow region, sampling makes use of this\n\ + if using_invel_s$ID$:\n\ + extrapolateVec3Simple(vel=invelC_s$ID$, phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\ + resampleVec3ToMac(source=invelC_s$ID$, target=invel_s$ID$)\n\ + pVel_pp$ID$.setSource(invel_s$ID$, isMAC=True)\n\ + \n\ + sampleLevelsetWithParticles(phi=phiIn_s$ID$, flags=flags_s$ID$, parts=pp_s$ID$, discretization=particleNumber_s$ID$, randomness=randomness_s$ID$)\n\ + flags_s$ID$.updateFromLevelset(phi_s$ID$)\n\ + \n\ + mantaMsg('Liquid step / s$ID$.frame: ' + str(s$ID$.frame))\n\ + liquid_step_$ID$()\n\ + \n\ + s$ID$.step()\n\ + \n\ + fluid_post_step_$ID$()\n"; + +const std::string liquid_step = + "\n\ +def liquid_step_$ID$():\n\ + mantaMsg('Liquid step')\n\ + \n\ + mantaMsg('Advecting particles')\n\ + pp_s$ID$.advectInGrid(flags=flags_s$ID$, vel=vel_s$ID$, integrationMode=IntRK4, deleteInObstacle=False, stopInObstacle=False)\n\ + \n\ + mantaMsg('Pushing particles out of obstacles')\n\ + pushOutofObs(parts=pp_s$ID$, flags=flags_s$ID$, phiObs=phiObs_s$ID$)\n\ + \n\ + mantaMsg('Advecting phi')\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=phi_s$ID$, order=1) # first order is usually enough\n\ + mantaMsg('Advecting velocity')\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=vel_s$ID$, order=2)\n\ + \n\ + phiTmp_s$ID$.copyFrom(phi_s$ID$) # save original phi for later use in mesh creation\n\ + \n\ + # create level set of particles\n\ + gridParticleIndex(parts=pp_s$ID$, flags=flags_s$ID$, indexSys=pindex_s$ID$, index=gpi_s$ID$)\n\ + unionParticleLevelset(parts=pp_s$ID$, indexSys=pindex_s$ID$, flags=flags_s$ID$, index=gpi_s$ID$, phi=phiParts_s$ID$, radiusFactor=radiusFactor_s$ID$)\n\ + \n\ + # combine level set of particles with grid level set\n\ + phi_s$ID$.addConst(1.) # shrink slightly\n\ + phi_s$ID$.join(phiParts_s$ID$)\n\ + extrapolateLsSimple(phi=phi_s$ID$, distance=narrowBandWidth_s$ID$+2, inside=True)\n\ + extrapolateLsSimple(phi=phi_s$ID$, distance=3)\n\ + phi_s$ID$.setBoundNeumann(0) # make sure no particles are placed at outer boundary\n\ + \n\ + if doOpen_s$ID$ or using_outflow_s$ID$:\n\ + resetOutflow(flags=flags_s$ID$, phi=phi_s$ID$, parts=pp_s$ID$, index=gpi_s$ID$, indexSys=pindex_s$ID$)\n\ + flags_s$ID$.updateFromLevelset(phi_s$ID$)\n\ + \n\ + # combine particles velocities with advected grid velocities\n\ + mapPartsToMAC(vel=velParts_s$ID$, flags=flags_s$ID$, velOld=velOld_s$ID$, parts=pp_s$ID$, partVel=pVel_pp$ID$, weight=mapWeights_s$ID$)\n\ + extrapolateMACFromWeight(vel=velParts_s$ID$, distance=2, weight=mapWeights_s$ID$)\n\ + combineGridVel(vel=velParts_s$ID$, weight=mapWeights_s$ID$, combineVel=vel_s$ID$, phi=phi_s$ID$, narrowBand=combineBandWidth_s$ID$, thresh=0)\n\ + velOld_s$ID$.copyFrom(vel_s$ID$)\n\ + \n\ + # forces & pressure solve\n\ + addGravity(flags=flags_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$)\n\ + \n\ + mantaMsg('Adding external forces')\n\ + addForceField(flags=flags_s$ID$, vel=vel_s$ID$, force=forces_s$ID$)\n\ + \n\ + if using_obstacle_s$ID$:\n\ + mantaMsg('Extrapolating object velocity')\n\ + # ensure velocities inside of obs object, slightly add obvels outside of obs object\n\ + extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\ + extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=3, inside=False)\n\ + resampleVec3ToMac(source=obvelC_s$ID$, target=obvel_s$ID$)\n\ + \n\ + extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=2, intoObs=True if using_fractions_s$ID$ else False)\n\ + \n\ + # vel diffusion / viscosity!\n\ + if viscosity_s$ID$ > 0.:\n\ + mantaMsg('Viscosity')\n\ + # diffusion param for solve = const * dt / dx^2\n\ + alphaV = viscosity_s$ID$ * s$ID$.timestep * float(res_s$ID$*res_s$ID$)\n\ + setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\ + cgSolveDiffusion(flags_s$ID$, vel_s$ID$, alphaV)\n\ + \n\ + setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\ + \n\ + mantaMsg('Calculating curvature')\n\ + getLaplacian(laplacian=curvature_s$ID$, grid=phi_s$ID$)\n\ + \n\ + if using_guiding_s$ID$:\n\ + mantaMsg('Guiding and pressure')\n\ + PD_fluid_guiding(vel=vel_s$ID$, velT=velT_s$ID$, flags=flags_s$ID$, phi=phi_s$ID$, curv=curvature_s$ID$, surfTens=surfaceTension_s$ID$, fractions=fractions_s$ID$, weight=weightGuide_s$ID$, blurRadius=beta_sg$ID$, pressure=pressure_s$ID$, tau=tau_sg$ID$, sigma=sigma_sg$ID$, theta=theta_sg$ID$, zeroPressureFixing=not doOpen_s$ID$)\n\ + else:\n\ + mantaMsg('Pressure')\n\ + solvePressure(flags=flags_s$ID$, vel=vel_s$ID$, pressure=pressure_s$ID$, phi=phi_s$ID$, curv=curvature_s$ID$, surfTens=surfaceTension_s$ID$, fractions=fractions_s$ID$, obvel=obvel_s$ID$ if using_fractions_s$ID$ else None)\n\ + \n\ + extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=4, intoObs=True if using_fractions_s$ID$ else False)\n\ + setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\ + \n\ + if not using_fractions_s$ID$:\n\ + extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=(int(maxVel_s$ID$*1.25)))\n\ + \n\ + # set source grids for resampling, used in adjustNumber!\n\ + pVel_pp$ID$.setSource(vel_s$ID$, isMAC=True)\n\ + adjustNumber(parts=pp_s$ID$, vel=vel_s$ID$, flags=flags_s$ID$, minParticles=minParticles_s$ID$, maxParticles=maxParticles_s$ID$, phi=phi_s$ID$, exclude=phiObs_s$ID$, radiusFactor=radiusFactor_s$ID$, narrowBand=adjustedNarrowBandWidth_s$ID$)\n\ + flipVelocityUpdate(vel=vel_s$ID$, velOld=velOld_s$ID$, flags=flags_s$ID$, parts=pp_s$ID$, partVel=pVel_pp$ID$, flipRatio=flipRatio_s$ID$)\n"; + +const std::string liquid_step_mesh = + "\n\ +def liquid_step_mesh_$ID$():\n\ + mantaMsg('Liquid step mesh')\n\ + \n\ + interpolateGrid(target=phi_sm$ID$, source=phiTmp_s$ID$)\n\ + \n\ + # create surface\n\ + pp_sm$ID$.readParticles(pp_s$ID$)\n\ + gridParticleIndex(parts=pp_sm$ID$, flags=flags_sm$ID$, indexSys=pindex_sm$ID$, index=gpi_sm$ID$)\n\ + \n\ + if using_final_mesh_s$ID$:\n\ + mantaMsg('Liquid using improved particle levelset')\n\ + improvedParticleLevelset(pp_sm$ID$, pindex_sm$ID$, flags_sm$ID$, gpi_sm$ID$, phiParts_sm$ID$, meshRadiusFactor_s$ID$, smoothenPos_s$ID$, smoothenNeg_s$ID$, concaveLower_s$ID$, concaveUpper_s$ID$)\n\ + else:\n\ + mantaMsg('Liquid using union particle levelset')\n\ + unionParticleLevelset(pp_sm$ID$, pindex_sm$ID$, flags_sm$ID$, gpi_sm$ID$, phiParts_sm$ID$, meshRadiusFactor_s$ID$)\n\ + \n\ + phi_sm$ID$.addConst(1.) # shrink slightly\n\ + phi_sm$ID$.join(phiParts_sm$ID$)\n\ + extrapolateLsSimple(phi=phi_sm$ID$, distance=narrowBandWidth_s$ID$+2, inside=True)\n\ + extrapolateLsSimple(phi=phi_sm$ID$, distance=3)\n\ + phi_sm$ID$.setBoundNeumann(0) # make sure no particles are placed at outer boundary\n\ + \n\ + # Vert vel vector needs to pull data from vel grid with correct dim\n\ + if using_speedvectors_s$ID$:\n\ + interpolateMACGrid(target=vel_sm$ID$, source=vel_s$ID$)\n\ + mVel_mesh$ID$.setSource(vel_sm$ID$, isMAC=True)\n\ + \n\ + phi_sm$ID$.setBound(0.5,int(((upres_sm$ID$)*2)-2) )\n\ + phi_sm$ID$.createMesh(mesh_sm$ID$)\n"; + +const std::string liquid_step_particles = + "\n\ +def liquid_step_particles_$ID$():\n\ + mantaMsg('Secondary particles step')\n\ + \n\ + # no upres: just use the loaded grids\n\ + if upres_sp$ID$ <= 1:\n\ + flags_sp$ID$.copyFrom(flags_s$ID$)\n\ + vel_sp$ID$.copyFrom(vel_s$ID$)\n\ + phiObs_sp$ID$.copyFrom(phiObs_s$ID$)\n\ + phi_sp$ID$.copyFrom(phi_s$ID$)\n\ + \n\ + # with upres: recreate grids\n\ + else:\n\ + # create highres grids by interpolation\n\ + interpolateMACGrid(target=vel_sp$ID$, source=vel_s$ID$)\n\ + interpolateGrid(target=phi_sp$ID$, source=phi_s$ID$)\n\ + flags_sp$ID$.initDomain(boundaryWidth=boundaryWidth_s$ID$, phiWalls=phiObs_sp$ID$, outflow=boundConditions_s$ID$)\n\ + flags_sp$ID$.updateFromLevelset(levelset=phi_sp$ID$)\n\ + \n\ + # actual secondary simulation\n\ + #extrapolateLsSimple(phi=phi_sp$ID$, distance=radius+1, inside=True)\n\ + flipComputeSecondaryParticlePotentials(potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, normal=normal_sp$ID$, phi=phi_sp$ID$, radius=pot_radius_sp$ID$, tauMinTA=tauMin_ta_sp$ID$, tauMaxTA=tauMax_ta_sp$ID$, tauMinWC=tauMin_wc_sp$ID$, tauMaxWC=tauMax_wc_sp$ID$, tauMinKE=tauMin_k_sp$ID$, tauMaxKE=tauMax_k_sp$ID$, scaleFromManta=scaleFromManta_sp$ID$)\n\ + flipSampleSecondaryParticles(mode='single', flags=flags_sp$ID$, v=vel_sp$ID$, pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, lMin=lMin_sp$ID$, lMax=lMax_sp$ID$, potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, k_ta=k_ta_sp$ID$, k_wc=k_wc_sp$ID$, dt=s$ID$.frameLength)\n\ + flipUpdateSecondaryParticles(mode='linear', pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, f_sec=pForceSnd_pp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, neighborRatio=neighborRatio_sp$ID$, radius=update_radius_sp$ID$, gravity=gravity_s$ID$, k_b=k_b_sp$ID$, k_d=k_d_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, dt=s$ID$.frameLength)\n\ + if $SNDPARTICLE_BOUNDARY_PUSHOUT$:\n\ + pushOutofObs(parts = ppSnd_sp$ID$, flags = flags_sp$ID$, phiObs = phiObs_sp$ID$, shift = 1.0)\n\ + flipDeleteParticlesInObstacle(pts=ppSnd_sp$ID$, flags=flags_sp$ID$)\n\ + #debugGridInfo(flags = flags_sp$ID$, grid = trappedAir_sp$ID$, name = 'Trapped Air')\n\ + #debugGridInfo(flags = flags_sp$ID$, grid = waveCrest_sp$ID$, name = 'Wave Crest')\n\ + #debugGridInfo(flags = flags_sp$ID$, grid = kineticEnergy_sp$ID$, name = 'Kinetic Energy')\n"; + +////////////////////////////////////////////////////////////////////// +// IMPORT +////////////////////////////////////////////////////////////////////// + +const std::string liquid_load_data = + "\n\ +def liquid_load_data_$ID$(path, framenr, file_format):\n\ + mantaMsg('Liquid load data')\n\ + fluid_file_import_s$ID$(dict=liquid_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n"; + +const std::string liquid_load_flip = + "\n\ +def liquid_load_flip_$ID$(path, framenr, file_format):\n\ + mantaMsg('Liquid load flip')\n\ + fluid_file_import_s$ID$(dict=liquid_flip_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n"; + +const std::string liquid_load_mesh = + "\n\ +def liquid_load_mesh_$ID$(path, framenr, file_format):\n\ + mantaMsg('Liquid load mesh')\n\ + fluid_file_import_s$ID$(dict=liquid_mesh_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n"; + +const std::string liquid_load_meshvel = + "\n\ +def liquid_load_meshvel_$ID$(path, framenr, file_format):\n\ + mantaMsg('Liquid load meshvel')\n\ + fluid_file_import_s$ID$(dict=liquid_meshvel_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n"; + +const std::string liquid_load_particles = + "\n\ +def liquid_load_particles_$ID$(path, framenr, file_format):\n\ + mantaMsg('Liquid load particles')\n\ + fluid_file_import_s$ID$(dict=liquid_particles_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n"; + +////////////////////////////////////////////////////////////////////// +// EXPORT +////////////////////////////////////////////////////////////////////// + +const std::string liquid_save_data = + "\n\ +def liquid_save_data_$ID$(path, framenr, file_format):\n\ + mantaMsg('Liquid save data')\n\ + if not withMPSave or isWindows:\n\ + fluid_file_export_s$ID$(dict=liquid_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_data_dict_s$ID$, do_join=False)\n"; + +const std::string liquid_save_flip = + "\n\ +def liquid_save_flip_$ID$(path, framenr, file_format):\n\ + mantaMsg('Liquid save flip')\n\ + if not withMPSave or isWindows:\n\ + fluid_file_export_s$ID$(dict=liquid_flip_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_flip_dict_s$ID$, do_join=False)\n"; + +const std::string liquid_save_mesh = + "\n\ +def liquid_save_mesh_$ID$(path, framenr, file_format):\n\ + mantaMsg('Liquid save mesh')\n\ + if not withMPSave or isWindows:\n\ + fluid_file_export_s$ID$(dict=liquid_mesh_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_mesh_dict_s$ID$, do_join=False)\n"; + +const std::string liquid_save_meshvel = + "\n\ +def liquid_save_meshvel_$ID$(path, framenr, file_format):\n\ + mantaMsg('Liquid save mesh vel')\n\ + if not withMPSave or isWindows:\n\ + fluid_file_export_s$ID$(dict=liquid_meshvel_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_meshvel_dict_s$ID$, do_join=False)\n"; + +const std::string liquid_save_particles = + "\n\ +def liquid_save_particles_$ID$(path, framenr, file_format):\n\ + mantaMsg('Liquid save particles')\n\ + if not withMPSave or isWindows:\n\ + fluid_file_export_s$ID$(dict=liquid_particles_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_particles_dict_s$ID$, do_join=False)\n"; + +////////////////////////////////////////////////////////////////////// +// STANDALONE MODE +////////////////////////////////////////////////////////////////////// + +const std::string liquid_standalone = + "\n\ +# Helper function to call cache load functions\n\ +def load(frame):\n\ + fluid_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\ + liquid_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\ + liquid_load_flip_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_particles)\n\ + if using_sndparts_s$ID$:\n\ + fluid_load_particles_$ID$(os.path.join(cache_dir, 'particles'), frame, file_format_particles)\n\ + liquid_load_particles_$ID$(os.path.join(cache_dir, 'particles'), frame, file_format_particles)\n\ + if using_mesh_s$ID$:\n\ + liquid_load_mesh_$ID$(os.path.join(cache_dir, 'mesh'), frame, file_format_mesh)\n\ + if using_guiding_s$ID$:\n\ + fluid_load_guiding_$ID$(os.path.join(cache_dir, 'guiding'), frame, file_format_data)\n\ +\n\ +# Helper function to call step functions\n\ +def step(frame):\n\ + liquid_adaptive_step_$ID$(frame)\n\ + if using_mesh_s$ID$:\n\ + liquid_step_mesh_$ID$()\n\ + if using_sndparts_s$ID$:\n\ + liquid_step_particles_$ID$()\n"; diff --git a/intern/mantaflow/intern/strings/smoke_script.h b/intern/mantaflow/intern/strings/smoke_script.h new file mode 100644 index 00000000000..ef300fc5c17 --- /dev/null +++ b/intern/mantaflow/intern/strings/smoke_script.h @@ -0,0 +1,581 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sebastian Barschkis (sebbas) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file mantaflow/intern/strings/smoke.h + * \ingroup mantaflow + */ + +#include + +////////////////////////////////////////////////////////////////////// +// VARIABLES +////////////////////////////////////////////////////////////////////// + +const std::string smoke_variables = + "\n\ +mantaMsg('Smoke variables low')\n\ +preconditioner_s$ID$ = PcMGDynamic\n\ +using_colors_s$ID$ = $USING_COLORS$\n\ +using_heat_s$ID$ = $USING_HEAT$\n\ +using_fire_s$ID$ = $USING_FIRE$\n\ +using_noise_s$ID$ = $USING_NOISE$\n\ +vorticity_s$ID$ = $VORTICITY$\n\ +buoyancy_dens_s$ID$ = float($BUOYANCY_ALPHA$) / float($FLUID_DOMAIN_SIZE$)\n\ +buoyancy_heat_s$ID$ = float($BUOYANCY_BETA$) / float($FLUID_DOMAIN_SIZE$)\n\ +dissolveSpeed_s$ID$ = $DISSOLVE_SPEED$\n\ +using_logdissolve_s$ID$ = $USING_LOG_DISSOLVE$\n\ +using_dissolve_s$ID$ = $USING_DISSOLVE$\n\ +flameVorticity_s$ID$ = $FLAME_VORTICITY$\n\ +burningRate_s$ID$ = $BURNING_RATE$\n\ +flameSmoke_s$ID$ = $FLAME_SMOKE$\n\ +ignitionTemp_s$ID$ = $IGNITION_TEMP$\n\ +maxTemp_s$ID$ = $MAX_TEMP$\n\ +flameSmokeColor_s$ID$ = vec3($FLAME_SMOKE_COLOR_X$,$FLAME_SMOKE_COLOR_Y$,$FLAME_SMOKE_COLOR_Z$)\n"; + +const std::string smoke_variables_noise = + "\n\ +mantaMsg('Smoke variables noise')\n\ +wltStrength_s$ID$ = $WLT_STR$\n\ +uvs_s$ID$ = 2\n\ +uvs_offset_s$ID$ = vec3($MIN_RESX$, $MIN_RESY$, $MIN_RESZ$)\n\ +octaves_s$ID$ = int(math.log(upres_sn$ID$) / math.log(2.0) + 0.5) if (upres_sn$ID$ > 1) else 1\n"; + +const std::string smoke_wavelet_noise = + "\n\ +# wavelet noise params\n\ +wltnoise_sn$ID$.posScale = vec3(int($BASE_RESX$), int($BASE_RESY$), int($BASE_RESZ$)) * (1. / $NOISE_POSSCALE$)\n\ +wltnoise_sn$ID$.timeAnim = $NOISE_TIMEANIM$\n"; + +const std::string smoke_with_heat = + "\n\ +using_heat_s$ID$ = True\n"; + +const std::string smoke_with_colors = + "\n\ +using_colors_s$ID$ = True\n"; + +const std::string smoke_with_fire = + "\n\ +using_fire_s$ID$ = True\n"; + +////////////////////////////////////////////////////////////////////// +// GRIDS +////////////////////////////////////////////////////////////////////// + +const std::string smoke_alloc = + "\n\ +mantaMsg('Smoke alloc')\n\ +shadow_s$ID$ = s$ID$.create(RealGrid)\n\ +emissionIn_s$ID$ = s$ID$.create(RealGrid)\n\ +density_s$ID$ = s$ID$.create(RealGrid)\n\ +densityIn_s$ID$ = s$ID$.create(RealGrid)\n\ +heat_s$ID$ = None # allocated dynamically\n\ +heatIn_s$ID$ = None\n\ +flame_s$ID$ = None\n\ +fuel_s$ID$ = None\n\ +react_s$ID$ = None\n\ +fuelIn_s$ID$ = None\n\ +reactIn_s$ID$ = None\n\ +color_r_s$ID$ = None\n\ +color_g_s$ID$ = None\n\ +color_b_s$ID$ = None\n\ +color_r_in_s$ID$ = None\n\ +color_g_in_s$ID$ = None\n\ +color_b_in_s$ID$ = None\n\ +\n\ +# Keep track of important objects in dict to load them later on\n\ +smoke_data_dict_s$ID$ = dict(density=density_s$ID$, shadow=shadow_s$ID$, densityIn=densityIn_s$ID$, emissionIn=emissionIn_s$ID$)\n"; + +const std::string smoke_alloc_noise = + "\n\ +mantaMsg('Smoke alloc noise')\n\ +vel_sn$ID$ = sn$ID$.create(MACGrid)\n\ +density_sn$ID$ = sn$ID$.create(RealGrid)\n\ +phiIn_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\ +phiOut_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\ +phiObs_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\ +flags_sn$ID$ = sn$ID$.create(FlagGrid)\n\ +tmpIn_sn$ID$ = sn$ID$.create(RealGrid)\n\ +emissionIn_sn$ID$ = sn$ID$.create(RealGrid)\n\ +energy_s$ID$ = s$ID$.create(RealGrid)\n\ +tempFlag_s$ID$ = s$ID$.create(FlagGrid)\n\ +texture_u_s$ID$ = s$ID$.create(RealGrid)\n\ +texture_v_s$ID$ = s$ID$.create(RealGrid)\n\ +texture_w_s$ID$ = s$ID$.create(RealGrid)\n\ +texture_u2_s$ID$ = s$ID$.create(RealGrid)\n\ +texture_v2_s$ID$ = s$ID$.create(RealGrid)\n\ +texture_w2_s$ID$ = s$ID$.create(RealGrid)\n\ +flame_sn$ID$ = None\n\ +fuel_sn$ID$ = None\n\ +react_sn$ID$ = None\n\ +color_r_sn$ID$ = None\n\ +color_g_sn$ID$ = None\n\ +color_b_sn$ID$ = None\n\ +wltnoise_sn$ID$ = sn$ID$.create(NoiseField, fixedSeed=265, loadFromFile=True)\n\ +\n\ +mantaMsg('Initializing UV Grids')\n\ +uvGrid0_s$ID$ = s$ID$.create(VecGrid)\n\ +uvGrid1_s$ID$ = s$ID$.create(VecGrid)\n\ +resetUvGrid(target=uvGrid0_s$ID$, offset=uvs_offset_s$ID$)\n\ +resetUvGrid(target=uvGrid1_s$ID$, offset=uvs_offset_s$ID$)\n\ +\n\ +# Sync UV and texture grids\n\ +copyVec3ToReal(source=uvGrid0_s$ID$, targetX=texture_u_s$ID$, targetY=texture_v_s$ID$, targetZ=texture_w_s$ID$)\n\ +copyVec3ToReal(source=uvGrid1_s$ID$, targetX=texture_u2_s$ID$, targetY=texture_v2_s$ID$, targetZ=texture_w2_s$ID$)\n\ +\n\ +# Keep track of important objects in dict to load them later on\n\ +smoke_noise_dict_s$ID$ = dict(density_noise=density_sn$ID$, uv0_noise=uvGrid0_s$ID$, uv1_noise=uvGrid1_s$ID$)\n"; + +////////////////////////////////////////////////////////////////////// +// ADDITIONAL GRIDS +////////////////////////////////////////////////////////////////////// + +const std::string smoke_alloc_colors = + "\n\ +# Sanity check, clear grids first\n\ +if 'color_r_s$ID$' in globals(): del color_r_s$ID$\n\ +if 'color_g_s$ID$' in globals(): del color_g_s$ID$\n\ +if 'color_b_s$ID$' in globals(): del color_b_s$ID$\n\ +\n\ +mantaMsg('Allocating colors')\n\ +color_r_s$ID$ = s$ID$.create(RealGrid)\n\ +color_g_s$ID$ = s$ID$.create(RealGrid)\n\ +color_b_s$ID$ = s$ID$.create(RealGrid)\n\ +color_r_in_s$ID$ = s$ID$.create(RealGrid)\n\ +color_g_in_s$ID$ = s$ID$.create(RealGrid)\n\ +color_b_in_s$ID$ = s$ID$.create(RealGrid)\n\ +\n\ +# Add objects to dict to load them later on\n\ +if 'smoke_data_dict_s$ID$' in globals():\n\ + smoke_data_dict_s$ID$.update(color_r=color_r_s$ID$, color_g=color_g_s$ID$, color_b=color_b_s$ID$)\n\ + smoke_data_dict_s$ID$.update(color_r_in=color_r_in_s$ID$, color_g_in=color_g_in_s$ID$, color_b_in=color_b_in_s$ID$)\n"; + +const std::string smoke_alloc_colors_noise = + "\n\ +# Sanity check, clear grids first\n\ +if 'color_r_sn$ID$' in globals(): del color_r_sn$ID$\n\ +if 'color_g_sn$ID$' in globals(): del color_g_sn$ID$\n\ +if 'color_b_sn$ID$' in globals(): del color_b_sn$ID$\n\ +\n\ +mantaMsg('Allocating colors noise')\n\ +color_r_sn$ID$ = sn$ID$.create(RealGrid)\n\ +color_g_sn$ID$ = sn$ID$.create(RealGrid)\n\ +color_b_sn$ID$ = sn$ID$.create(RealGrid)\n\ +\n\ +# Add objects to dict to load them later on\n\ +if 'smoke_noise_dict_s$ID$' in globals():\n\ + smoke_noise_dict_s$ID$.update(color_r_noise=color_r_sn$ID$, color_g_noise=color_g_sn$ID$, color_b_noise=color_b_sn$ID$)\n"; + +const std::string smoke_init_colors = + "\n\ +mantaMsg('Initializing colors')\n\ +color_r_s$ID$.copyFrom(density_s$ID$) \n\ +color_r_s$ID$.multConst($COLOR_R$) \n\ +color_g_s$ID$.copyFrom(density_s$ID$) \n\ +color_g_s$ID$.multConst($COLOR_G$) \n\ +color_b_s$ID$.copyFrom(density_s$ID$) \n\ +color_b_s$ID$.multConst($COLOR_B$)\n"; + +const std::string smoke_init_colors_noise = + "\n\ +mantaMsg('Initializing colors noise')\n\ +color_r_sn$ID$.copyFrom(density_sn$ID$) \n\ +color_r_sn$ID$.multConst($COLOR_R$) \n\ +color_g_sn$ID$.copyFrom(density_sn$ID$) \n\ +color_g_sn$ID$.multConst($COLOR_G$) \n\ +color_b_sn$ID$.copyFrom(density_sn$ID$) \n\ +color_b_sn$ID$.multConst($COLOR_B$)\n"; + +const std::string smoke_alloc_heat = + "\n\ +# Sanity check, clear grids first\n\ +if 'heat_s$ID$' in globals(): del heat_s$ID$\n\ +if 'heatIn_s$ID$' in globals(): del heatIn_s$ID$\n\ +\n\ +mantaMsg('Allocating heat')\n\ +heat_s$ID$ = s$ID$.create(RealGrid)\n\ +heatIn_s$ID$ = s$ID$.create(RealGrid)\n\ +\n\ +# Add objects to dict to load them later on\n\ +if 'smoke_data_dict_s$ID$' in globals():\n\ + smoke_data_dict_s$ID$.update(heat=heat_s$ID$, heatIn=heatIn_s$ID$)\n"; + +const std::string smoke_alloc_fire = + "\n\ +# Sanity check, clear grids first\n\ +if 'flame_s$ID$' in globals(): del flame_s$ID$\n\ +if 'fuel_s$ID$' in globals(): del fuel_s$ID$\n\ +if 'react_s$ID$' in globals(): del react_s$ID$\n\ +if 'fuelIn_s$ID$' in globals(): del fuelIn_s$ID$\n\ +if 'reactIn_s$ID$' in globals(): del reactIn_s$ID$\n\ +\n\ +mantaMsg('Allocating fire')\n\ +flame_s$ID$ = s$ID$.create(RealGrid)\n\ +fuel_s$ID$ = s$ID$.create(RealGrid)\n\ +react_s$ID$ = s$ID$.create(RealGrid)\n\ +fuelIn_s$ID$ = s$ID$.create(RealGrid)\n\ +reactIn_s$ID$ = s$ID$.create(RealGrid)\n\ +\n\ +# Add objects to dict to load them later on\n\ +if 'smoke_data_dict_s$ID$' in globals():\n\ + smoke_data_dict_s$ID$.update(flame=flame_s$ID$, fuel=fuel_s$ID$, react=react_s$ID$)\n\ + smoke_data_dict_s$ID$.update(fuelIn=fuelIn_s$ID$, reactIn=reactIn_s$ID$)\n"; + +const std::string smoke_alloc_fire_noise = + "\n\ +# Sanity check, clear grids first\n\ +if 'flame_sn$ID$' in globals(): del flame_sn$ID$\n\ +if 'fuel_sn$ID$' in globals(): del fuel_sn$ID$\n\ +if 'react_sn$ID$' in globals(): del react_sn$ID$\n\ +\n\ +mantaMsg('Allocating fire noise')\n\ +flame_sn$ID$ = sn$ID$.create(RealGrid)\n\ +fuel_sn$ID$ = sn$ID$.create(RealGrid)\n\ +react_sn$ID$ = sn$ID$.create(RealGrid)\n\ +\n\ +# Add objects to dict to load them later on\n\ +if 'smoke_noise_dict_s$ID$' in globals():\n\ + smoke_noise_dict_s$ID$.update(flame_noise=flame_sn$ID$, fuel_noise=fuel_sn$ID$, react_noise=react_sn$ID$)\n"; + +////////////////////////////////////////////////////////////////////// +// STEP FUNCTIONS +////////////////////////////////////////////////////////////////////// + +const std::string smoke_adaptive_step = + "\n\ +def smoke_adaptive_step_$ID$(framenr):\n\ + mantaMsg('Manta step, frame ' + str(framenr))\n\ + s$ID$.frame = framenr\n\ + \n\ + fluid_pre_step_$ID$()\n\ + \n\ + flags_s$ID$.initDomain(boundaryWidth=0, phiWalls=phiObs_s$ID$, outflow=boundConditions_s$ID$)\n\ + \n\ + if using_obstacle_s$ID$:\n\ + mantaMsg('Initializing obstacle levelset')\n\ + phiObsIn_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\ + extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\ + extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\ + phiObs_s$ID$.join(phiObsIn_s$ID$)\n\ + \n\ + # Using boundaryWidth=2 to not search beginning from walls (just a performance optimization)\n\ + # Additional sanity check: fill holes in phiObs which can result after joining with phiObsIn\n\ + phiObs_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\ + extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\ + extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\ + \n\ + mantaMsg('Initializing fluid levelset')\n\ + extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\ + extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\ + \n\ + if using_outflow_s$ID$:\n\ + phiOut_s$ID$.join(phiOutIn_s$ID$)\n\ + \n\ + setObstacleFlags(flags=flags_s$ID$, phiObs=phiObs_s$ID$, phiOut=phiOut_s$ID$, phiIn=phiIn_s$ID$)\n\ + flags_s$ID$.fillGrid()\n\ + \n\ + if timePerFrame_s$ID$ == 0: # Only apply inflow once per frame\n\ + mantaMsg('Smoke inflow at frame: ' + str(framenr))\n\ + applyEmission(flags=flags_s$ID$, target=density_s$ID$, source=densityIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\ + if using_heat_s$ID$:\n\ + applyEmission(flags=flags_s$ID$, target=heat_s$ID$, source=heatIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\ + \n\ + if using_colors_s$ID$:\n\ + applyEmission(flags=flags_s$ID$, target=color_r_s$ID$, source=color_r_in_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\ + applyEmission(flags=flags_s$ID$, target=color_g_s$ID$, source=color_g_in_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\ + applyEmission(flags=flags_s$ID$, target=color_b_s$ID$, source=color_b_in_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\ + \n\ + if using_fire_s$ID$:\n\ + applyEmission(flags=flags_s$ID$, target=fuel_s$ID$, source=fuelIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\ + applyEmission(flags=flags_s$ID$, target=react_s$ID$, source=reactIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\ + \n\ + mantaMsg('Smoke step / s$ID$.frame: ' + str(s$ID$.frame))\n\ + if using_fire_s$ID$:\n\ + process_burn_$ID$()\n\ + smoke_step_$ID$()\n\ + if using_fire_s$ID$:\n\ + update_flame_$ID$()\n\ + \n\ + s$ID$.step()\n\ + \n\ + fluid_post_step_$ID$()\n"; + +const std::string smoke_step = + "\n\ +def smoke_step_$ID$():\n\ + mantaMsg('Smoke step low')\n\ + \n\ + if using_dissolve_s$ID$:\n\ + mantaMsg('Dissolving smoke')\n\ + dissolveSmoke(flags=flags_s$ID$, density=density_s$ID$, heat=heat_s$ID$, red=color_r_s$ID$, green=color_g_s$ID$, blue=color_b_s$ID$, speed=dissolveSpeed_s$ID$, logFalloff=using_logdissolve_s$ID$)\n\ + \n\ + mantaMsg('Advecting density')\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=density_s$ID$, order=2)\n\ + \n\ + if using_heat_s$ID$:\n\ + mantaMsg('Advecting heat')\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=heat_s$ID$, order=2)\n\ + \n\ + if using_fire_s$ID$:\n\ + mantaMsg('Advecting fire')\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=fuel_s$ID$, order=2)\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=react_s$ID$, order=2)\n\ + \n\ + if using_colors_s$ID$:\n\ + mantaMsg('Advecting colors')\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=color_r_s$ID$, order=2)\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=color_g_s$ID$, order=2)\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=color_b_s$ID$, order=2)\n\ + \n\ + mantaMsg('Advecting velocity')\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=vel_s$ID$, order=2)\n\ + \n\ + if doOpen_s$ID$ or using_outflow_s$ID$:\n\ + resetOutflow(flags=flags_s$ID$, real=density_s$ID$)\n\ + \n\ + mantaMsg('Vorticity')\n\ + if using_fire_s$ID$:\n\ + flame_s$ID$.copyFrom(fuel_s$ID$) # temporarily misuse flame grid as vorticity storage\n\ + flame_s$ID$.multConst(flameVorticity_s$ID$)\n\ + vorticityConfinement(vel=vel_s$ID$, flags=flags_s$ID$, strengthGlobal=vorticity_s$ID$, strengthCell=flame_s$ID$ if using_fire_s$ID$ else None)\n\ + \n\ + if using_heat_s$ID$:\n\ + mantaMsg('Adding heat buoyancy')\n\ + addBuoyancy(flags=flags_s$ID$, density=heat_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_heat_s$ID$)\n\ + mantaMsg('Adding buoyancy')\n\ + addBuoyancy(flags=flags_s$ID$, density=density_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_dens_s$ID$)\n\ + \n\ + mantaMsg('Adding forces')\n\ + addForceField(flags=flags_s$ID$, vel=vel_s$ID$, force=forces_s$ID$)\n\ + \n\ + if using_obstacle_s$ID$:\n\ + mantaMsg('Extrapolating object velocity')\n\ + # ensure velocities inside of obs object, slightly add obvels outside of obs object\n\ + extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\ + extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=3, inside=False)\n\ + resampleVec3ToMac(source=obvelC_s$ID$, target=obvel_s$ID$)\n\ + \n\ + # add initial velocity\n\ + if using_invel_s$ID$:\n\ + resampleVec3ToMac(source=invelC_s$ID$, target=invel_s$ID$)\n\ + setInitialVelocity(flags=flags_s$ID$, vel=vel_s$ID$, invel=invel_s$ID$)\n\ + \n\ + mantaMsg('Walls')\n\ + setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=obvel_s$ID$ if using_obstacle_s$ID$ else None)\n\ + \n\ + if using_guiding_s$ID$:\n\ + mantaMsg('Guiding and pressure')\n\ + PD_fluid_guiding(vel=vel_s$ID$, velT=velT_s$ID$, flags=flags_s$ID$, weight=weightGuide_s$ID$, blurRadius=beta_sg$ID$, pressure=pressure_s$ID$, tau=tau_sg$ID$, sigma=sigma_sg$ID$, theta=theta_sg$ID$, preconditioner=preconditioner_s$ID$, zeroPressureFixing=not doOpen_s$ID$)\n\ + else:\n\ + mantaMsg('Pressure')\n\ + solvePressure(flags=flags_s$ID$, vel=vel_s$ID$, pressure=pressure_s$ID$, preconditioner=preconditioner_s$ID$, zeroPressureFixing=not doOpen_s$ID$) # closed domains require pressure fixing\n\ +\n\ +def process_burn_$ID$():\n\ + mantaMsg('Process burn')\n\ + processBurn(fuel=fuel_s$ID$, density=density_s$ID$, react=react_s$ID$, red=color_r_s$ID$ if using_colors_s$ID$ else None, green=color_g_s$ID$ if using_colors_s$ID$ else None, blue=color_b_s$ID$ if using_colors_s$ID$ else None, heat=heat_s$ID$ if using_heat_s$ID$ else None, burningRate=burningRate_s$ID$, flameSmoke=flameSmoke_s$ID$, ignitionTemp=ignitionTemp_s$ID$, maxTemp=maxTemp_s$ID$, flameSmokeColor=flameSmokeColor_s$ID$)\n\ +\n\ +def update_flame_$ID$():\n\ + mantaMsg('Update flame')\n\ + updateFlame(react=react_s$ID$, flame=flame_s$ID$)\n"; + +const std::string smoke_step_noise = + "\n\ +def smoke_step_noise_$ID$(framenr):\n\ + mantaMsg('Manta step noise, frame ' + str(framenr))\n\ + sn$ID$.frame = framenr\n\ + \n\ + copyRealToVec3(sourceX=texture_u_s$ID$, sourceY=texture_v_s$ID$, sourceZ=texture_w_s$ID$, target=uvGrid0_s$ID$)\n\ + copyRealToVec3(sourceX=texture_u2_s$ID$, sourceY=texture_v2_s$ID$, sourceZ=texture_w2_s$ID$, target=uvGrid1_s$ID$)\n\ + \n\ + flags_sn$ID$.initDomain(boundaryWidth=0, phiWalls=phiObs_sn$ID$, outflow=boundConditions_s$ID$)\n\ + \n\ + mantaMsg('Interpolating grids')\n\ + # Join big obstacle levelset after initDomain() call as it overwrites everything in phiObs\n\ + if using_obstacle_s$ID$:\n\ + interpolateGrid(target=phiIn_sn$ID$, source=phiObsIn_s$ID$) # mis-use phiIn_sn\n\ + phiObs_sn$ID$.join(phiIn_sn$ID$)\n\ + if using_outflow_s$ID$:\n\ + interpolateGrid(target=phiOut_sn$ID$, source=phiOut_s$ID$)\n\ + interpolateGrid(target=phiIn_sn$ID$, source=phiIn_s$ID$)\n\ + interpolateMACGrid(target=vel_sn$ID$, source=vel_s$ID$)\n\ + \n\ + setObstacleFlags(flags=flags_sn$ID$, phiObs=phiObs_sn$ID$, phiOut=phiOut_sn$ID$, phiIn=phiIn_sn$ID$)\n\ + flags_sn$ID$.fillGrid()\n\ + \n\ + # Interpolate emission grids and apply them to big noise grids\n\ + interpolateGrid(source=densityIn_s$ID$, target=tmpIn_sn$ID$)\n\ + interpolateGrid(source=emissionIn_s$ID$, target=emissionIn_sn$ID$)\n\ + \n\ + # Higher-res noise grid needs scaled emission values\n\ + tmpIn_sn$ID$.multConst(float(upres_sn$ID$))\n\ + applyEmission(flags=flags_sn$ID$, target=density_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ + \n\ + if using_colors_s$ID$:\n\ + interpolateGrid(source=color_r_in_s$ID$, target=tmpIn_sn$ID$)\n\ + applyEmission(flags=flags_sn$ID$, target=color_r_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ + interpolateGrid(source=color_g_in_s$ID$, target=tmpIn_sn$ID$)\n\ + applyEmission(flags=flags_sn$ID$, target=color_g_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ + interpolateGrid(source=color_b_in_s$ID$, target=tmpIn_sn$ID$)\n\ + applyEmission(flags=flags_sn$ID$, target=color_b_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ + \n\ + if using_fire_s$ID$:\n\ + interpolateGrid(source=fuelIn_s$ID$, target=tmpIn_sn$ID$)\n\ + applyEmission(flags=flags_sn$ID$, target=fuel_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ + interpolateGrid(source=reactIn_s$ID$, target=tmpIn_sn$ID$)\n\ + applyEmission(flags=flags_sn$ID$, target=react_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ + \n\ + mantaMsg('Noise step / sn$ID$.frame: ' + str(sn$ID$.frame))\n\ + if using_fire_s$ID$:\n\ + process_burn_noise_$ID$()\n\ + step_noise_$ID$()\n\ + if using_fire_s$ID$:\n\ + update_flame_noise_$ID$()\n\ + \n\ + sn$ID$.step()\n\ + \n\ + copyVec3ToReal(source=uvGrid0_s$ID$, targetX=texture_u_s$ID$, targetY=texture_v_s$ID$, targetZ=texture_w_s$ID$)\n\ + copyVec3ToReal(source=uvGrid1_s$ID$, targetX=texture_u2_s$ID$, targetY=texture_v2_s$ID$, targetZ=texture_w2_s$ID$)\n\ +\n\ +def step_noise_$ID$():\n\ + mantaMsg('Smoke step noise')\n\ + \n\ + if using_dissolve_s$ID$:\n\ + mantaMsg('Dissolving noise')\n\ + dissolveSmoke(flags=flags_sn$ID$, density=density_sn$ID$, heat=None, red=color_r_sn$ID$, green=color_g_sn$ID$, blue=color_b_sn$ID$, speed=dissolveSpeed_s$ID$, logFalloff=using_logdissolve_s$ID$)\n\ + \n\ + mantaMsg('Advecting UVs and updating UV weight')\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=uvGrid0_s$ID$, order=2)\n\ + updateUvWeight(resetTime=sn$ID$.timestep*10.0 , index=0, numUvs=uvs_s$ID$, uv=uvGrid0_s$ID$, offset=uvs_offset_s$ID$)\n\ + advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=uvGrid1_s$ID$, order=2)\n\ + updateUvWeight(resetTime=sn$ID$.timestep*10.0 , index=1, numUvs=uvs_s$ID$, uv=uvGrid1_s$ID$, offset=uvs_offset_s$ID$)\n\ + \n\ + mantaMsg('Energy')\n\ + computeEnergy(flags=flags_s$ID$, vel=vel_s$ID$, energy=energy_s$ID$)\n\ + \n\ + tempFlag_s$ID$.copyFrom(flags_s$ID$)\n\ + extrapolateSimpleFlags(flags=flags_s$ID$, val=tempFlag_s$ID$, distance=2, flagFrom=FlagObstacle, flagTo=FlagFluid)\n\ + extrapolateSimpleFlags(flags=tempFlag_s$ID$, val=energy_s$ID$, distance=6, flagFrom=FlagFluid, flagTo=FlagObstacle)\n\ + computeWaveletCoeffs(energy_s$ID$)\n\ + \n\ + sStr_s$ID$ = 1.0 * wltStrength_s$ID$\n\ + sPos_s$ID$ = 2.0\n\ + \n\ + mantaMsg('Applying noise vec')\n\ + for o in range(octaves_s$ID$):\n\ + uvWeight_s$ID$ = getUvWeight(uvGrid0_s$ID$)\n\ + applyNoiseVec3(flags=flags_sn$ID$, target=vel_sn$ID$, noise=wltnoise_sn$ID$, scale=sStr_s$ID$ * uvWeight_s$ID$, scaleSpatial=sPos_s$ID$ , weight=energy_s$ID$, uv=uvGrid0_s$ID$)\n\ + uvWeight_s$ID$ = getUvWeight(uvGrid1_s$ID$)\n\ + applyNoiseVec3(flags=flags_sn$ID$, target=vel_sn$ID$, noise=wltnoise_sn$ID$, scale=sStr_s$ID$ * uvWeight_s$ID$, scaleSpatial=sPos_s$ID$ , weight=energy_s$ID$, uv=uvGrid1_s$ID$)\n\ + \n\ + sStr_s$ID$ *= 0.06 # magic kolmogorov factor \n\ + sPos_s$ID$ *= 2.0 \n\ + \n\ + for substep in range(int(upres_sn$ID$)):\n\ + if using_colors_s$ID$: \n\ + mantaMsg('Advecting colors noise')\n\ + advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=color_r_sn$ID$, order=2)\n\ + advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=color_g_sn$ID$, order=2)\n\ + advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=color_b_sn$ID$, order=2)\n\ + \n\ + if using_fire_s$ID$: \n\ + mantaMsg('Advecting fire noise')\n\ + advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=fuel_sn$ID$, order=2)\n\ + advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=react_sn$ID$, order=2)\n\ + \n\ + mantaMsg('Advecting density noise')\n\ + advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=density_sn$ID$, order=2)\n\ +\n\ +def process_burn_noise_$ID$():\n\ + mantaMsg('Process burn noise')\n\ + processBurn(fuel=fuel_sn$ID$, density=density_sn$ID$, react=react_sn$ID$, red=color_r_sn$ID$ if using_colors_s$ID$ else None, green=color_g_sn$ID$ if using_colors_s$ID$ else None, blue=color_b_sn$ID$ if using_colors_s$ID$ else None, burningRate=burningRate_s$ID$, flameSmoke=flameSmoke_s$ID$, ignitionTemp=ignitionTemp_s$ID$, maxTemp=maxTemp_s$ID$, flameSmokeColor=flameSmokeColor_s$ID$)\n\ +\n\ +def update_flame_noise_$ID$():\n\ + mantaMsg('Update flame noise')\n\ + updateFlame(react=react_sn$ID$, flame=flame_sn$ID$)\n"; + +////////////////////////////////////////////////////////////////////// +// IMPORT +////////////////////////////////////////////////////////////////////// + +const std::string smoke_load_data = + "\n\ +def smoke_load_data_$ID$(path, framenr, file_format):\n\ + mantaMsg('Smoke load data')\n\ + fluid_file_import_s$ID$(dict=smoke_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n"; + +const std::string smoke_load_noise = + "\n\ +def smoke_load_noise_$ID$(path, framenr, file_format):\n\ + mantaMsg('Smoke load noise')\n\ + fluid_file_import_s$ID$(dict=smoke_noise_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\ + \n\ + # Fill up xyz texture grids, important when resuming a bake\n\ + copyVec3ToReal(source=uvGrid0_s$ID$, targetX=texture_u_s$ID$, targetY=texture_v_s$ID$, targetZ=texture_w_s$ID$)\n\ + copyVec3ToReal(source=uvGrid1_s$ID$, targetX=texture_u2_s$ID$, targetY=texture_v2_s$ID$, targetZ=texture_w2_s$ID$)\n"; + +////////////////////////////////////////////////////////////////////// +// EXPORT +////////////////////////////////////////////////////////////////////// + +const std::string smoke_save_data = + "\n\ +def smoke_save_data_$ID$(path, framenr, file_format):\n\ + mantaMsg('Smoke save data')\n\ + start_time = time.time()\n\ + if not withMPSave or isWindows:\n\ + fluid_file_export_s$ID$(framenr=framenr, file_format=file_format, path=path, dict=smoke_data_dict_s$ID$,)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=smoke_data_dict_s$ID$, do_join=False)\n\ + mantaMsg('--- Save: %s seconds ---' % (time.time() - start_time))\n"; + +const std::string smoke_save_noise = + "\n\ +def smoke_save_noise_$ID$(path, framenr, file_format):\n\ + mantaMsg('Smoke save noise')\n\ + if not withMPSave or isWindows:\n\ + fluid_file_export_s$ID$(dict=smoke_noise_dict_s$ID$, framenr=framenr, file_format=file_format, path=path)\n\ + else:\n\ + fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=smoke_noise_dict_s$ID$, do_join=False)\n"; + +////////////////////////////////////////////////////////////////////// +// STANDALONE MODE +////////////////////////////////////////////////////////////////////// + +const std::string smoke_standalone = + "\n\ +# Helper function to call cache load functions\n\ +def load(frame):\n\ + fluid_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\ + smoke_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\ + if using_noise_s$ID$:\n\ + smoke_load_noise_$ID$(os.path.join(cache_dir, 'noise'), frame, file_format_noise)\n\ + if using_guiding_s$ID$:\n\ + fluid_load_guiding_$ID$(os.path.join(cache_dir, 'guiding'), frame, file_format_data)\n\ +\n\ +# Helper function to call step functions\n\ +def step(frame):\n\ + smoke_adaptive_step_$ID$(frame)\n\ + if using_noise_s$ID$:\n\ + smoke_step_noise_$ID$(frame)\n";