Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt15
-rw-r--r--build_files/cmake/config/blender_full.cmake3
-rw-r--r--build_files/cmake/config/blender_lite.cmake3
-rw-r--r--build_files/cmake/config/blender_release.cmake3
-rw-r--r--build_files/cmake/macros.cmake3
-rw-r--r--build_files/cmake/platform/platform_apple.cmake5
-rw-r--r--build_files/cmake/platform/platform_win32.cmake5
-rw-r--r--doc/doxygen/doxygen.intern.h4
-rw-r--r--intern/CMakeLists.txt12
-rw-r--r--intern/cycles/blender/blender_mesh.cpp29
-rw-r--r--intern/cycles/blender/blender_session.cpp32
-rw-r--r--intern/cycles/blender/blender_util.h29
-rw-r--r--intern/elbeem/CMakeLists.txt122
-rw-r--r--intern/elbeem/COPYING358
-rw-r--r--intern/elbeem/COPYING_trimesh2303
-rw-r--r--intern/elbeem/extern/elbeem.h273
-rw-r--r--intern/elbeem/intern/attributes.cpp362
-rw-r--r--intern/elbeem/intern/attributes.h248
-rw-r--r--intern/elbeem/intern/controlparticles.cpp1465
-rw-r--r--intern/elbeem/intern/controlparticles.h327
-rw-r--r--intern/elbeem/intern/elbeem.cpp430
-rw-r--r--intern/elbeem/intern/elbeem_control.cpp28
-rw-r--r--intern/elbeem/intern/elbeem_control.h65
-rw-r--r--intern/elbeem/intern/globals.h10
-rw-r--r--intern/elbeem/intern/isosurface.cpp1122
-rw-r--r--intern/elbeem/intern/isosurface.h244
-rw-r--r--intern/elbeem/intern/loop_tools.h186
-rw-r--r--intern/elbeem/intern/mcubes_tables.h300
-rw-r--r--intern/elbeem/intern/mvmcoords.cpp205
-rw-r--r--intern/elbeem/intern/mvmcoords.h108
-rw-r--r--intern/elbeem/intern/ntl_blenderdumper.cpp270
-rw-r--r--intern/elbeem/intern/ntl_blenderdumper.h42
-rw-r--r--intern/elbeem/intern/ntl_bsptree.cpp945
-rw-r--r--intern/elbeem/intern/ntl_bsptree.h135
-rw-r--r--intern/elbeem/intern/ntl_geometryclass.h127
-rw-r--r--intern/elbeem/intern/ntl_geometrymodel.cpp477
-rw-r--r--intern/elbeem/intern/ntl_geometrymodel.h104
-rw-r--r--intern/elbeem/intern/ntl_geometryobject.cpp806
-rw-r--r--intern/elbeem/intern/ntl_geometryobject.h255
-rw-r--r--intern/elbeem/intern/ntl_geometryshader.h73
-rw-r--r--intern/elbeem/intern/ntl_lighting.cpp184
-rw-r--r--intern/elbeem/intern/ntl_lighting.h254
-rw-r--r--intern/elbeem/intern/ntl_matrices.h790
-rw-r--r--intern/elbeem/intern/ntl_ray.cpp915
-rw-r--r--intern/elbeem/intern/ntl_ray.h438
-rw-r--r--intern/elbeem/intern/ntl_vector3dim.h1105
-rw-r--r--intern/elbeem/intern/ntl_world.cpp934
-rw-r--r--intern/elbeem/intern/ntl_world.h411
-rw-r--r--intern/elbeem/intern/paraloopend.h45
-rw-r--r--intern/elbeem/intern/parametrizer.cpp597
-rw-r--r--intern/elbeem/intern/parametrizer.h322
-rw-r--r--intern/elbeem/intern/particletracer.cpp470
-rw-r--r--intern/elbeem/intern/particletracer.h296
-rw-r--r--intern/elbeem/intern/simulation_object.cpp471
-rw-r--r--intern/elbeem/intern/simulation_object.h206
-rw-r--r--intern/elbeem/intern/solver_adap.cpp1281
-rw-r--r--intern/elbeem/intern/solver_class.h1036
-rw-r--r--intern/elbeem/intern/solver_control.cpp876
-rw-r--r--intern/elbeem/intern/solver_control.h199
-rw-r--r--intern/elbeem/intern/solver_init.cpp2396
-rw-r--r--intern/elbeem/intern/solver_interface.cpp753
-rw-r--r--intern/elbeem/intern/solver_interface.h639
-rw-r--r--intern/elbeem/intern/solver_main.cpp1723
-rw-r--r--intern/elbeem/intern/solver_relax.h1169
-rw-r--r--intern/elbeem/intern/solver_util.cpp1753
-rw-r--r--intern/elbeem/intern/utilities.cpp498
-rw-r--r--intern/elbeem/intern/utilities.h205
-rw-r--r--intern/mantaflow/CMakeLists.txt241
-rw-r--r--intern/mantaflow/extern/manta_fluid_API.h229
-rw-r--r--intern/mantaflow/extern/manta_python_API.h (renamed from source/blender/modifiers/intern/MOD_fluidsim_util.h)36
-rw-r--r--intern/mantaflow/intern/MANTA_main.cpp2566
-rw-r--r--intern/mantaflow/intern/MANTA_main.h774
-rw-r--r--intern/mantaflow/intern/manta_develop/dependencies/cnpy/LICENSE21
-rw-r--r--intern/mantaflow/intern/manta_develop/dependencies/cnpy/cnpy.cpp341
-rw-r--r--intern/mantaflow/intern/manta_develop/dependencies/cnpy/cnpy.h269
-rw-r--r--intern/mantaflow/intern/manta_develop/dependencies/cnpy/example1.cpp71
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/manta.h31
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/numpyWrap.cpp123
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/numpyWrap.h72
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/pclass.cpp188
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/pclass.h99
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/pconvert.cpp471
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/pconvert.h220
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/pvec3.cpp393
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/pymain.cpp125
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/pythonInclude.h49
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/registry.cpp681
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/pwrapper/registry.h97
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/integrator.h75
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/interpol.h209
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/interpolHigh.h187
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/matrixbase.h256
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/mcubes.h323
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/quaternion.h89
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/randomstream.h374
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/rcmatrix.h921
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/simpleimage.cpp285
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/simpleimage.h183
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/solvana.h176
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/vector4d.cpp35
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/vector4d.h447
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/vectorbase.cpp40
-rw-r--r--intern/mantaflow/intern/manta_develop/helper/util/vectorbase.h619
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h736
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.cpp521
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h293
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.cpp679
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h48
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.cpp807
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h195
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/iogrids.cpp1237
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/iomeshes.cpp459
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/ioparticles.cpp310
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h83
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.cpp296
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h220
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h.reg17
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h.reg.cpp50
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/general.cpp165
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h173
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/gitinfo.h4
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.cpp1634
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h1025
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h.reg72
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h.reg.cpp233
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.cpp1023
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h746
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h.reg39
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h.reg.cpp204
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.cpp64
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h102
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.cpp541
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h118
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h.reg11
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h.reg.cpp36
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.cpp1875
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h767
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h.reg56
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h.reg.cpp233
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.cpp109
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h86
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h.reg7
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h.reg.cpp30
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.cpp1250
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h154
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.cpp312
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h450
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h.reg12
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h.reg.cpp40
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.cpp1060
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h1251
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h.reg70
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h.reg.cpp275
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/advection.cpp802
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/apic.cpp278
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/extforces.cpp855
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/fire.cpp207
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/flip.cpp1444
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/fluidguiding.cpp516
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/initplugins.cpp1265
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/kepsilon.cpp334
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/meshplugins.cpp678
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/pressure.cpp783
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/ptsplugins.cpp226
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/secondaryparticles.cpp1343
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/surfaceturbulence.cpp1500
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/vortexplugins.cpp457
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/waveletturbulence.cpp691
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/waves.cpp314
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py11
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py.reg2
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py.reg.cpp8
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/registration.cpp406
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.cpp694
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h285
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h.reg28
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h.reg.cpp72
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/test.cpp97
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.cpp128
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h96
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h.reg6
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h.reg.cpp28
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.cpp186
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h105
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h.reg9
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h.reg.cpp56
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.cpp152
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h82
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h.reg7
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h.reg.cpp52
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.cpp106
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h132
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h.reg7
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h.reg.cpp30
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h558
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.cpp513
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h275
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.cpp679
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h48
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.cpp747
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h195
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/iogrids.cpp1229
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/iomeshes.cpp459
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/ioparticles.cpp310
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h83
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.cpp296
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h220
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h.reg17
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h.reg.cpp50
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.cpp165
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h173
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/gitinfo.h4
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.cpp1522
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h983
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h.reg72
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h.reg.cpp233
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.cpp947
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h700
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h.reg39
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h.reg.cpp204
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.cpp64
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h102
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.cpp503
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h118
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h.reg11
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h.reg.cpp36
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.cpp1781
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h767
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h.reg56
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h.reg.cpp233
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.cpp109
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h86
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h.reg7
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h.reg.cpp30
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.cpp1196
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h154
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h.reg1
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h.reg.cpp18
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.cpp312
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h450
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h.reg12
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h.reg.cpp40
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.cpp986
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h1241
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h.reg70
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h.reg.cpp275
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/advection.cpp718
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/apic.cpp274
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/extforces.cpp775
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/fire.cpp187
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/flip.cpp1344
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/fluidguiding.cpp486
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/initplugins.cpp1167
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/kepsilon.cpp316
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/meshplugins.cpp678
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/pressure.cpp731
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/ptsplugins.cpp210
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/secondaryparticles.cpp1263
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/surfaceturbulence.cpp1436
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/vortexplugins.cpp453
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/waveletturbulence.cpp631
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/waves.cpp284
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py11
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py.reg2
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py.reg.cpp8
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/registration.cpp406
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.cpp624
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h285
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h.reg28
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h.reg.cpp72
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/test.cpp93
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.cpp128
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h96
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h.reg6
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h.reg.cpp28
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.cpp182
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h105
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h.reg9
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h.reg.cpp56
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.cpp156
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h82
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h.reg7
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h.reg.cpp52
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.cpp106
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h132
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h.reg7
-rw-r--r--intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h.reg.cpp30
-rw-r--r--intern/mantaflow/intern/manta_develop/update_mantaflow.sh54
-rw-r--r--intern/mantaflow/intern/manta_fluid_API.cpp880
-rw-r--r--intern/mantaflow/intern/manta_python_API.cpp (renamed from intern/elbeem/extern/LBM_fluidsim.h)32
-rw-r--r--intern/mantaflow/intern/strings/fluid_script.h788
-rw-r--r--intern/mantaflow/intern/strings/liquid_script.h439
-rw-r--r--intern/mantaflow/intern/strings/smoke_script.h534
-rw-r--r--intern/smoke/CMakeLists.txt99
-rw-r--r--intern/smoke/extern/smoke_API.h111
-rw-r--r--intern/smoke/intern/EIGENVALUE_HELPER.cpp888
-rw-r--r--intern/smoke/intern/EIGENVALUE_HELPER.h77
-rw-r--r--intern/smoke/intern/FFT_NOISE.h183
-rw-r--r--intern/smoke/intern/FLUID_3D.cpp1792
-rw-r--r--intern/smoke/intern/FLUID_3D.h269
-rw-r--r--intern/smoke/intern/FLUID_3D_SOLVERS.cpp328
-rw-r--r--intern/smoke/intern/FLUID_3D_STATIC.cpp646
-rw-r--r--intern/smoke/intern/IMAGE.h289
-rw-r--r--intern/smoke/intern/INTERPOLATE.h230
-rw-r--r--intern/smoke/intern/LICENSE.txt674
-rw-r--r--intern/smoke/intern/LU_HELPER.cpp139
-rw-r--r--intern/smoke/intern/LU_HELPER.h54
-rw-r--r--intern/smoke/intern/MERSENNETWISTER.h432
-rw-r--r--intern/smoke/intern/Makefile.FFT22
-rw-r--r--intern/smoke/intern/Makefile.cygwin23
-rw-r--r--intern/smoke/intern/Makefile.linux23
-rw-r--r--intern/smoke/intern/Makefile.mac35
-rw-r--r--intern/smoke/intern/OBSTACLE.h46
-rw-r--r--intern/smoke/intern/SPHERE.cpp53
-rw-r--r--intern/smoke/intern/SPHERE.h44
-rw-r--r--intern/smoke/intern/VEC3.h991
-rw-r--r--intern/smoke/intern/WAVELET_NOISE.h519
-rw-r--r--intern/smoke/intern/WTURBULENCE.cpp1198
-rw-r--r--intern/smoke/intern/WTURBULENCE.h150
-rw-r--r--intern/smoke/intern/smoke_API.cpp495
-rw-r--r--intern/smoke/intern/tnt/jama_eig.h1053
-rw-r--r--intern/smoke/intern/tnt/jama_lu.h322
-rw-r--r--intern/smoke/intern/tnt/tnt.h67
-rw-r--r--intern/smoke/intern/tnt/tnt_array1d.h281
-rw-r--r--intern/smoke/intern/tnt/tnt_array1d_utils.h233
-rw-r--r--intern/smoke/intern/tnt/tnt_array2d.h318
-rw-r--r--intern/smoke/intern/tnt/tnt_array2d_utils.h290
-rw-r--r--intern/smoke/intern/tnt/tnt_array3d.h299
-rw-r--r--intern/smoke/intern/tnt/tnt_array3d_utils.h239
-rw-r--r--intern/smoke/intern/tnt/tnt_cmat.h583
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array1d.h270
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array1d_utils.h245
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array2d.h228
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array2d_utils.h239
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array3d.h226
-rw-r--r--intern/smoke/intern/tnt/tnt_fortran_array3d_utils.h252
-rw-r--r--intern/smoke/intern/tnt/tnt_i_refvec.h246
-rw-r--r--intern/smoke/intern/tnt/tnt_math_utils.h35
-rw-r--r--intern/smoke/intern/tnt/tnt_sparse_matrix_csr.h106
-rw-r--r--intern/smoke/intern/tnt/tnt_stopwatch.h98
-rw-r--r--intern/smoke/intern/tnt/tnt_subscript.h57
-rw-r--r--intern/smoke/intern/tnt/tnt_vec.h407
-rw-r--r--intern/smoke/intern/tnt/tnt_version.h42
-rw-r--r--release/datafiles/blender_icons16/icon16_mod_manta.dat (renamed from release/datafiles/blender_icons16/icon16_mod_smoke.dat)bin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_mod_manta.dat (renamed from release/datafiles/blender_icons32/icon32_mod_smoke.dat)bin4120 -> 4120 bytes
m---------release/datafiles/locale0
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/presets/fluid/honey.py3
-rw-r--r--release/scripts/presets/fluid/oil.py3
-rw-r--r--release/scripts/presets/fluid/water.py3
-rw-r--r--release/scripts/presets/mantaflow/honey.py3
-rw-r--r--release/scripts/presets/mantaflow/oil.py3
-rw-r--r--release/scripts/presets/mantaflow/water.py3
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py130
-rw-r--r--release/scripts/startup/bl_operators/presets.py19
-rw-r--r--release/scripts/startup/bl_ui/__init__.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py21
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_fluid.py467
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_manta.py1178
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_smoke.py692
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py2
-rw-r--r--source/blender/CMakeLists.txt2
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc13
-rw-r--r--source/blender/blenkernel/BKE_fluidsim.h51
-rw-r--r--source/blender/blenkernel/BKE_manta.h (renamed from source/blender/blenkernel/BKE_smoke.h)38
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h4
-rw-r--r--source/blender/blenkernel/CMakeLists.txt24
-rw-r--r--source/blender/blenkernel/intern/bpath.c10
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c9
-rw-r--r--source/blender/blenkernel/intern/effect.c11
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c90
-rw-r--r--source/blender/blenkernel/intern/manta.c4402
-rw-r--r--source/blender/blenkernel/intern/object.c27
-rw-r--r--source/blender/blenkernel/intern/particle.c14
-rw-r--r--source/blender/blenkernel/intern/particle_system.c502
-rw-r--r--source/blender/blenkernel/intern/pointcache.c499
-rw-r--r--source/blender/blenkernel/intern/smoke.c3658
-rw-r--r--source/blender/blenloader/intern/readfile.c135
-rw-r--r--source/blender/blenloader/intern/versioning_250.c28
-rw-r--r--source/blender/blenloader/intern/versioning_260.c80
-rw-r--r--source/blender/blenloader/intern/versioning_270.c26
-rw-r--r--source/blender/blenloader/intern/writefile.c40
-rw-r--r--source/blender/depsgraph/intern/depsgraph_physics.cc2
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c48
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c4
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c4
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c73
-rw-r--r--source/blender/draw/modes/object_mode.c66
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt3
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/interface/interface_templates.c12
-rw-r--r--source/blender/editors/physics/CMakeLists.txt17
-rw-r--r--source/blender/editors/physics/particle_object.c2
-rw-r--r--source/blender/editors/physics/physics_fluid.c1247
-rw-r--r--source/blender/editors/physics/physics_intern.h14
-rw-r--r--source/blender/editors/physics/physics_manta.c802
-rw-r--r--source/blender/editors/physics/physics_ops.c18
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c19
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c4
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt6
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h2
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpu/CMakeLists.txt6
-rw-r--r--source/blender/gpu/GPU_draw.h12
-rw-r--r--source/blender/gpu/intern/gpu_draw.c248
-rw-r--r--source/blender/makesdna/DNA_manta_types.h501
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h23
-rw-r--r--source/blender/makesdna/DNA_object_types.h3
-rw-r--r--source/blender/makesdna/DNA_particle_types.h23
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h346
-rw-r--r--source/blender/makesdna/intern/makesdna.c4
-rw-r--r--source/blender/makesrna/RNA_access.h9
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt13
-rw-r--r--source/blender/makesrna/intern/makesrna.c3
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c792
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c4
-rw-r--r--source/blender/makesrna/intern/rna_internal.h3
-rw-r--r--source/blender/makesrna/intern/rna_manta.c2476
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c82
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c8
-rw-r--r--source/blender/makesrna/intern/rna_particle.c9
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c1218
-rw-r--r--source/blender/modifiers/CMakeLists.txt10
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h2
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim.c150
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c582
-rw-r--r--source/blender/modifiers/intern/MOD_manta.c (renamed from source/blender/modifiers/intern/MOD_smoke.c)110
-rw-r--r--source/blender/modifiers/intern/MOD_util.c3
-rw-r--r--source/blender/python/intern/CMakeLists.txt9
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c21
-rw-r--r--source/blender/python/intern/bpy_interface.c14
-rw-r--r--source/blender/render/CMakeLists.txt6
-rw-r--r--source/blender/shader_fx/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/WM_api.h1
m---------source/tools0
467 files changed, 92806 insertions, 55909 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4dd165b0185..edfa85de2f5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -229,7 +229,7 @@ mark_as_advanced(BUILDINFO_OVERRIDE_TIME)
option(WITH_IK_ITASC "Enable ITASC IK solver (only disable for development & for incompatible C++ compilers)" ON)
option(WITH_IK_SOLVER "Enable Legacy IK solver (only disable for development)" ON)
-option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke, ocean sim, and audio effects)" ${_init_FFTW3})
+option(WITH_FFTW3 "Enable FFTW3 support (Used for ocean sim and audio effects)" ${_init_FFTW3})
option(WITH_BULLET "Enable Bullet (Physics Engine)" ON)
option(WITH_SYSTEM_BULLET "Use the systems bullet library (currently unsupported due to missing features in upstream!)" )
mark_as_advanced(WITH_SYSTEM_BULLET)
@@ -298,8 +298,8 @@ endif()
# Modifiers
-option(WITH_MOD_FLUID "Enable Elbeem Modifier (Fluid Simulation)" ON)
-option(WITH_MOD_SMOKE "Enable Smoke Modifier (Smoke Simulation)" ON)
+option(WITH_MOD_MANTA "Enable Mantaflow Fluid Simulation Framework" ON)
+option(WITH_MANTA_OMP "Enable Mantaflow OpenMP support (instead of default TBB support)" OFF)
option(WITH_MOD_REMESH "Enable Remesh Modifier" ON)
# option(WITH_MOD_CLOTH_ELTOPO "Enable Experimental cloth solver" OFF) # this is now only available in a branch
# mark_as_advanced(WITH_MOD_CLOTH_ELTOPO)
@@ -1248,6 +1248,13 @@ if(WITH_PYTHON_MODULE)
endif()
#-----------------------------------------------------------------------------
+# Configure mantaflow.
+
+if(WITH_MOD_MANTA)
+ add_definitions(-DWITH_MANTA)
+endif()
+
+#-----------------------------------------------------------------------------
# Configure GLog/GFlags
if(WITH_LIBMV OR WITH_GTESTS OR (WITH_CYCLES AND WITH_CYCLES_LOGGING))
@@ -1812,7 +1819,7 @@ if(FIRST_RUN)
info_cfg_text("Modifiers:")
info_cfg_option(WITH_MOD_REMESH)
- info_cfg_option(WITH_MOD_FLUID)
+ info_cfg_option(WITH_MOD_MANTA)
info_cfg_option(WITH_MOD_OCEANSIM)
info_cfg_text("OpenGL:")
diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake
index 6786cb5ce37..a84f7a9e8dc 100644
--- a/build_files/cmake/config/blender_full.cmake
+++ b/build_files/cmake/config/blender_full.cmake
@@ -32,9 +32,8 @@ set(WITH_INTERNATIONAL ON CACHE BOOL "" FORCE)
set(WITH_JACK ON CACHE BOOL "" FORCE)
set(WITH_LZMA ON CACHE BOOL "" FORCE)
set(WITH_LZO ON CACHE BOOL "" FORCE)
-set(WITH_MOD_FLUID ON CACHE BOOL "" FORCE)
set(WITH_MOD_REMESH ON CACHE BOOL "" FORCE)
-set(WITH_MOD_SMOKE ON CACHE BOOL "" FORCE)
+set(WITH_MOD_MANTA ON CACHE BOOL "" FORCE)
set(WITH_MOD_OCEANSIM ON CACHE BOOL "" FORCE)
set(WITH_AUDASPACE ON CACHE BOOL "" FORCE)
set(WITH_OPENAL ON CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index b85176d37f3..e23e5a35ae2 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -37,9 +37,8 @@ set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE)
set(WITH_JACK OFF CACHE BOOL "" FORCE)
set(WITH_LZMA OFF CACHE BOOL "" FORCE)
set(WITH_LZO OFF CACHE BOOL "" FORCE)
-set(WITH_MOD_FLUID OFF CACHE BOOL "" FORCE)
set(WITH_MOD_REMESH OFF CACHE BOOL "" FORCE)
-set(WITH_MOD_SMOKE OFF CACHE BOOL "" FORCE)
+set(WITH_MOD_MANTA OFF CACHE BOOL "" FORCE)
set(WITH_MOD_OCEANSIM OFF CACHE BOOL "" FORCE)
set(WITH_AUDASPACE OFF CACHE BOOL "" FORCE)
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake
index 24032b6aed6..c7929722193 100644
--- a/build_files/cmake/config/blender_release.cmake
+++ b/build_files/cmake/config/blender_release.cmake
@@ -33,9 +33,8 @@ set(WITH_INTERNATIONAL ON CACHE BOOL "" FORCE)
set(WITH_JACK ON CACHE BOOL "" FORCE)
set(WITH_LZMA ON CACHE BOOL "" FORCE)
set(WITH_LZO ON CACHE BOOL "" FORCE)
-set(WITH_MOD_FLUID ON CACHE BOOL "" FORCE)
set(WITH_MOD_REMESH ON CACHE BOOL "" FORCE)
-set(WITH_MOD_SMOKE ON CACHE BOOL "" FORCE)
+set(WITH_MOD_MANTA ON CACHE BOOL "" FORCE)
set(WITH_MOD_OCEANSIM ON CACHE BOOL "" FORCE)
set(WITH_AUDASPACE ON CACHE BOOL "" FORCE)
set(WITH_OPENAL ON CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index c2f608de921..a094fd26042 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -481,6 +481,9 @@ function(setup_liblinks
if(WITH_ALEMBIC)
target_link_libraries(${target} ${ALEMBIC_LIBRARIES} ${HDF5_LIBRARIES})
endif()
+ if(WITH_MOD_MANTA)
+ target_link_libraries(${target} ${TBB_LIBRARIES})
+ endif()
if(WITH_IMAGE_TIFF)
target_link_libraries(${target} ${TIFF_LIBRARY})
endif()
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index 882f41b3c0d..8a34d0d0adf 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -403,6 +403,11 @@ if(WITH_OPENMP)
endif()
endif()
+if(WITH_MOD_MANTA)
+ set(TBB_INCLUDE_DIRS ${LIBDIR}/tbb/include)
+ set(TBB_LIBRARIES ${LIBDIR}/tbb/lib/libtbb.a)
+endif()
+
set(EXETYPE MACOSX_BUNDLE)
set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index 3fc0d20fb46..10feb0bc48e 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -546,6 +546,11 @@ if(WITH_SYSTEM_AUDASPACE)
set(AUDASPACE_PY_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace-py.lib)
endif()
+if(WITH_MOD_MANTA)
+ set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib)
+ set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include)
+endif()
+
# used in many places so include globally, like OpenGL
blender_include_dirs_sys("${PTHREADS_INCLUDE_DIRS}")
diff --git a/doc/doxygen/doxygen.intern.h b/doc/doxygen/doxygen.intern.h
index 8e51cb01df0..98fb039c90b 100644
--- a/doc/doxygen/doxygen.intern.h
+++ b/doc/doxygen/doxygen.intern.h
@@ -18,10 +18,6 @@
* \ingroup intern
*/
-/** \defgroup elbeem elbeem
- * \ingroup intern
- */
-
/** \defgroup iksolver iksolver
* \ingroup intern
*/
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index b93f2057b47..b01993bf0e8 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -40,14 +40,6 @@ if(WITH_MOD_REMESH)
add_subdirectory(dualcon)
endif()
-if(WITH_MOD_FLUID)
- add_subdirectory(elbeem)
-endif()
-
-if(WITH_MOD_SMOKE)
- add_subdirectory(smoke)
-endif()
-
if(WITH_IK_SOLVER)
add_subdirectory(iksolver)
endif()
@@ -73,6 +65,10 @@ if(WIN32)
add_subdirectory(utfconv)
endif()
+if(WITH_MOD_MANTA)
+ add_subdirectory(mantaflow)
+endif()
+
if(WITH_OPENVDB)
add_subdirectory(openvdb)
endif()
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index c672bc9f3e2..934503c80a4 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -281,7 +281,7 @@ static void mikk_compute_tangents(
static void create_mesh_volume_attribute(
BL::Object &b_ob, Mesh *mesh, ImageManager *image_manager, AttributeStandard std, float frame)
{
- BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
+ BL::MantaDomainSettings b_domain = object_manta_domain_find(b_ob);
if (!b_domain)
return;
@@ -873,18 +873,18 @@ static void create_subd_mesh(Scene *scene,
/* Sync */
-static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
+static void sync_mesh_manta_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
{
if (scene->need_motion() == Scene::MOTION_NONE)
return;
- BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob);
+ BL::MantaDomainSettings b_manta_domain = object_manta_domain_find(b_ob);
- if (!b_fluid_domain)
+ if (!b_manta_domain)
return;
/* If the mesh has modifiers following the fluid domain we can't export motion. */
- if (b_fluid_domain.fluid_mesh_vertices.length() != mesh->verts.size())
+ if (b_manta_domain.mesh_vertices.length() != mesh->verts.size())
return;
/* Find or add attribute */
@@ -901,13 +901,12 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f;
float3 *mP = attr_mP->data_float3() + step * mesh->verts.size();
- BL::DomainFluidSettings::fluid_mesh_vertices_iterator fvi;
+ BL::MantaDomainSettings::mesh_vertices_iterator svi;
int i = 0;
- for (b_fluid_domain.fluid_mesh_vertices.begin(fvi);
- fvi != b_fluid_domain.fluid_mesh_vertices.end();
- ++fvi, ++i) {
- mP[i] = P[i] + get_float3(fvi->velocity()) * relative_time;
+ for (b_manta_domain.mesh_vertices.begin(svi); svi != b_manta_domain.mesh_vertices.end();
+ ++svi, ++i) {
+ mP[i] = P[i] + get_float3(svi->velocity()) * relative_time;
}
}
}
@@ -1044,8 +1043,8 @@ Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph,
}
mesh->geometry_flags = requested_geometry_flags;
- /* fluid motion */
- sync_mesh_fluid_motion(b_ob, scene, mesh);
+ /* mesh fluid motion mantaflow */
+ sync_mesh_manta_motion(b_ob, scene, mesh);
/* tag update */
bool rebuild = (oldtriangles != mesh->triangles) || (oldsubd_faces != mesh->subd_faces) ||
@@ -1092,9 +1091,9 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph &b_depsgraph,
* would need a more extensive check to see which objects are animated */
BL::Mesh b_mesh(PointerRNA_NULL);
- /* fluid motion is exported immediate with mesh, skip here */
- BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob);
- if (b_fluid_domain)
+ /* manta motion is exported immediate with mesh, skip here */
+ BL::MantaDomainSettings b_manta_domain = object_manta_domain_find(b_ob);
+ if (b_manta_domain)
return;
if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index dcbb101b01d..eb681c23e5d 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -1162,7 +1162,7 @@ void BlenderSession::builtin_image_info(const string &builtin_name,
else if (b_id.is_a(&RNA_Object)) {
/* smoke volume data */
BL::Object b_ob(b_id);
- BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
+ BL::MantaDomainSettings b_domain = object_manta_domain_find(b_ob);
metadata.is_float = true;
metadata.depth = 1;
@@ -1184,7 +1184,7 @@ void BlenderSession::builtin_image_info(const string &builtin_name,
return;
int3 resolution = get_int3(b_domain.domain_resolution());
- int amplify = (b_domain.use_high_resolution()) ? b_domain.amplify() + 1 : 1;
+ int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
/* Velocity and heat data is always low-resolution. */
if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
@@ -1341,14 +1341,14 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
else if (b_id.is_a(&RNA_Object)) {
/* smoke volume data */
BL::Object b_ob(b_id);
- BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
+ BL::MantaDomainSettings b_domain = object_manta_domain_find(b_ob);
if (!b_domain) {
return false;
}
int3 resolution = get_int3(b_domain.domain_resolution());
- int length, amplify = (b_domain.use_high_resolution()) ? b_domain.amplify() + 1 : 1;
+ int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
/* Velocity and heat data is always low-resolution. */
if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
@@ -1362,47 +1362,47 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
const size_t num_pixels = ((size_t)width) * height * depth;
if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
- SmokeDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
+ MantaDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels) {
- SmokeDomainSettings_density_grid_get(&b_domain.ptr, pixels);
+ MantaDomainSettings_density_grid_get(&b_domain.ptr, pixels);
return true;
}
}
else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) {
/* this is in range 0..1, and interpreted by the OpenGL smoke viewer
* as 1500..3000 K with the first part faded to zero density */
- SmokeDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
+ MantaDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels) {
- SmokeDomainSettings_flame_grid_get(&b_domain.ptr, pixels);
+ MantaDomainSettings_flame_grid_get(&b_domain.ptr, pixels);
return true;
}
}
else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) {
/* the RGB is "premultiplied" by density for better interpolation results */
- SmokeDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
+ MantaDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels * 4) {
- SmokeDomainSettings_color_grid_get(&b_domain.ptr, pixels);
+ MantaDomainSettings_color_grid_get(&b_domain.ptr, pixels);
return true;
}
}
else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) {
- SmokeDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
+ MantaDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels * 3) {
- SmokeDomainSettings_velocity_grid_get(&b_domain.ptr, pixels);
+ MantaDomainSettings_velocity_grid_get(&b_domain.ptr, pixels);
return true;
}
}
else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
- SmokeDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
+ MantaDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels) {
- SmokeDomainSettings_heat_grid_get(&b_domain.ptr, pixels);
+ MantaDomainSettings_heat_grid_get(&b_domain.ptr, pixels);
return true;
}
}
else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) {
- SmokeDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
+ MantaDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
if (length == num_pixels) {
- SmokeDomainSettings_temperature_grid_get(&b_domain.ptr, pixels);
+ MantaDomainSettings_temperature_grid_get(&b_domain.ptr, pixels);
return true;
}
}
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index c9d1dc67e54..c95c4e1cf6a 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -521,37 +521,20 @@ static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_
return use_deform_motion;
}
-static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object &b_ob)
+static inline BL::MantaDomainSettings object_manta_domain_find(BL::Object &b_ob)
{
BL::Object::modifiers_iterator b_mod;
for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
- if (b_mod->is_a(&RNA_SmokeModifier)) {
- BL::SmokeModifier b_smd(*b_mod);
+ if (b_mod->is_a(&RNA_MantaModifier)) {
+ BL::MantaModifier b_mmd(*b_mod);
- if (b_smd.smoke_type() == BL::SmokeModifier::smoke_type_DOMAIN)
- return b_smd.domain_settings();
+ if (b_mmd.type() == BL::MantaModifier::type_DOMAIN)
+ return b_mmd.domain_settings();
}
}
- return BL::SmokeDomainSettings(PointerRNA_NULL);
-}
-
-static inline BL::DomainFluidSettings object_fluid_domain_find(BL::Object b_ob)
-{
- BL::Object::modifiers_iterator b_mod;
-
- for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
- if (b_mod->is_a(&RNA_FluidSimulationModifier)) {
- BL::FluidSimulationModifier b_fmd(*b_mod);
- BL::FluidSettings fss = b_fmd.settings();
-
- if (fss.type() == BL::FluidSettings::type_DOMAIN)
- return (BL::DomainFluidSettings)b_fmd.settings();
- }
- }
-
- return BL::DomainFluidSettings(PointerRNA_NULL);
+ return BL::MantaDomainSettings(PointerRNA_NULL);
}
static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
diff --git a/intern/elbeem/CMakeLists.txt b/intern/elbeem/CMakeLists.txt
deleted file mode 100644
index 926329be61b..00000000000
--- a/intern/elbeem/CMakeLists.txt
+++ /dev/null
@@ -1,122 +0,0 @@
-# ***** 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) 2006, Blender Foundation
-# All rights reserved.
-# ***** END GPL LICENSE BLOCK *****
-
-set(INC
- extern
- ../guardedalloc
-)
-
-set(INC_SYS
- ${PNG_INCLUDE_DIRS}
- ${ZLIB_INCLUDE_DIRS}
-)
-
-set(SRC
- intern/attributes.cpp
- intern/controlparticles.cpp
- intern/elbeem.cpp
- intern/elbeem_control.cpp
- intern/isosurface.cpp
- intern/mvmcoords.cpp
- intern/ntl_blenderdumper.cpp
- intern/ntl_bsptree.cpp
- intern/ntl_geometrymodel.cpp
- intern/ntl_geometryobject.cpp
- intern/ntl_lighting.cpp
- intern/ntl_ray.cpp
- intern/ntl_world.cpp
- intern/parametrizer.cpp
- intern/particletracer.cpp
- intern/simulation_object.cpp
- intern/solver_adap.cpp
- intern/solver_control.cpp
- intern/solver_init.cpp
- intern/solver_interface.cpp
- intern/solver_main.cpp
- intern/solver_util.cpp
- intern/utilities.cpp
-
- extern/LBM_fluidsim.h
- extern/elbeem.h
- intern/attributes.h
- intern/controlparticles.h
- intern/elbeem_control.h
- intern/isosurface.h
- intern/loop_tools.h
- intern/mcubes_tables.h
- intern/mvmcoords.h
- intern/ntl_blenderdumper.h
- intern/ntl_bsptree.h
- intern/ntl_geometryclass.h
- intern/ntl_geometrymodel.h
- intern/ntl_geometryobject.h
- intern/ntl_geometryshader.h
- intern/ntl_lighting.h
- intern/ntl_matrices.h
- intern/ntl_ray.h
- intern/ntl_vector3dim.h
- intern/ntl_world.h
- intern/paraloopend.h
- intern/parametrizer.h
- intern/particletracer.h
- intern/simulation_object.h
- intern/solver_class.h
- intern/solver_control.h
- intern/solver_interface.h
- intern/solver_relax.h
- intern/utilities.h
- intern/globals.h
-)
-
-set(LIB
-)
-
-# elbeem has some harmless UNUSED warnings
-remove_strict_flags()
-
-add_definitions(
- -DNOGUI
- -DELBEEM_BLENDER=1
-)
-
-# not essential but quiet gcc's -Wundef
-add_definitions(
- -DLBM_PRECISION=1
- -DLBM_INCLUDE_TESTSOLVERS=0
- -DFSGR_STRICT_DEBUG=0
- -DELBEEM_MPI=0
- -DNEWDIRVELMOTEST=0
-)
-
-if(WIN32)
- # We need BLI_gzopen on win32 for unicode paths
- add_definitions(
- -DLBM_GZIP_OVERRIDE_H="${CMAKE_SOURCE_DIR}/source/blender/blenlib/BLI_fileops.h"
- -D LBM_GZIP_OPEN_FN="\(gzFile\)BLI_gzopen"
- )
-endif()
-
-if(WITH_OPENMP)
- add_definitions(-DPARALLEL=1)
-else()
- add_definitions(-DPARALLEL=0)
-endif()
-
-blender_add_lib_nolist(bf_intern_elbeem "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/intern/elbeem/COPYING b/intern/elbeem/COPYING
deleted file mode 100644
index 2600c731161..00000000000
--- a/intern/elbeem/COPYING
+++ /dev/null
@@ -1,358 +0,0 @@
- All code distributed as part of El'Beem is covered by the following
- version of the GNU General Public License.
-
- 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.
-
- Copyright (c) 2003-2005 Nils Thuerey. All rights reserved.
-
-
-
-
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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 St, Fifth Floor, Boston, MA 02110-1301 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/intern/elbeem/COPYING_trimesh2 b/intern/elbeem/COPYING_trimesh2
deleted file mode 100644
index a214195fd60..00000000000
--- a/intern/elbeem/COPYING_trimesh2
+++ /dev/null
@@ -1,303 +0,0 @@
-This distribution includes source to "miniball", "freeGLUT",
-and "GLUI", which are covered under their own licenses.
-
-All other code distributed as part of trimesh2 is covered
-by the following license:
-
-
-Copyright (c) 2004 Szymon Rusinkiewicz.
-All rights reserved.
-
-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.
-
-
-
-
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
diff --git a/intern/elbeem/extern/elbeem.h b/intern/elbeem/extern/elbeem.h
deleted file mode 100644
index 073055cf562..00000000000
--- a/intern/elbeem/extern/elbeem.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * API header
- */
-#ifndef ELBEEM_API_H
-#define ELBEEM_API_H
-
-
-// simulation run callback function type (elbeemSimulationSettings->runsimCallback)
-// best use with FLUIDSIM_CBxxx defines below.
-// >parameters
-// return values: 0=continue, 1=stop, 2=abort
-// data pointer: user data pointer from elbeemSimulationSettings->runsimUserData
-// status integer: 1=running simulation, 2=new frame saved
-// frame integer: if status is 1, contains current frame number
-typedef int (*elbeemRunSimulationCallback)(void *data, int status, int frame);
-#define FLUIDSIM_CBRET_CONTINUE 0
-#define FLUIDSIM_CBRET_STOP 1
-#define FLUIDSIM_CBRET_ABORT 2
-#define FLUIDSIM_CBSTATUS_STEP 1
-#define FLUIDSIM_CBSTATUS_NEWFRAME 2
-
-
-// global settings for the simulation
-typedef struct elbeemSimulationSettings {
- /* version number */
- short version;
- /* id number of simulation domain, needed if more than a
- * single domain should be simulated */
- short domainId; // unused within blender
-
- /* geometrical extent */
- float geoStart[3], geoSize[3];
-
- /* resolutions */
- short resolutionxyz;
- short previewresxyz;
- /* size of the domain in real units (meters along largest resolution x,y,z extent) */
- float realsize;
-
- /* fluid properties */
- double viscosity;
- /* gravity strength */
- float gravity[3];
- /* anim start end time */
- float animStart, aniFrameTime;
- /* no. of frames to simulate & output */
- short noOfFrames;
- /* g star param (LBM compressibility) */
- float gstar;
- /* activate refinement? */
- short maxRefine;
- /* probability for surface particle generation (0.0=off) */
- float generateParticles;
- /* amount of tracer particles to generate (0=off) */
- int numTracerParticles;
-
- /* store output path, and file prefix for baked fluid surface */
- char outputPath[160+80];
-
- /* channel for frame time, visc & gravity animations */
- int channelSizeFrameTime;
- float *channelFrameTime;
- int channelSizeViscosity;
- float *channelViscosity;
- int channelSizeGravity;
- float *channelGravity; // vector
-
- /* boundary types and settings for domain walls */
- short domainobsType;
- float domainobsPartslip;
-
- /* what surfaces to generate */
- int mFsSurfGenSetting;
-
- /* generate speed vectors for vertices (e.g. for image based motion blur)*/
- short generateVertexVectors;
- /* strength of surface smoothing */
- float surfaceSmoothing;
- /* no. of surface subdivisions */
- int surfaceSubdivs;
-
- /* global transformation to apply to fluidsim mesh */
- float surfaceTrafo[4*4];
-
- /* development variables, testing for upcoming releases...*/
- float farFieldSize;
-
- /* callback function to notify calling program of performed simulation steps
- * or newly available frame data, if NULL it is ignored */
- elbeemRunSimulationCallback runsimCallback;
- /* pointer passed to runsimCallback for user data storage */
- void* runsimUserData;
- /* simulation threads used by omp */
- int threads;
-
-} elbeemSimulationSettings;
-
-
-// defines for elbeemMesh->type below
-/* please keep in sync with DNA_object_fluidsim_types.h */
-#define OB_FLUIDSIM_FLUID 4
-#define OB_FLUIDSIM_OBSTACLE 8
-#define OB_FLUIDSIM_INFLOW 16
-#define OB_FLUIDSIM_OUTFLOW 32
-#define OB_FLUIDSIM_PARTICLE 64
-#define OB_FLUIDSIM_CONTROL 128
-
-// defines for elbeemMesh->obstacleType below (low bits) high bits (>=64) are reserved for mFsSurfGenSetting flags which are defined in solver_class.h
-#define FLUIDSIM_OBSTACLE_NOSLIP 1
-#define FLUIDSIM_OBSTACLE_PARTSLIP 2
-#define FLUIDSIM_OBSTACLE_FREESLIP 3
-#define FLUIDSIM_FSSG_NOOBS 64
-
-
-#define OB_VOLUMEINIT_VOLUME 1
-#define OB_VOLUMEINIT_SHELL 2
-#define OB_VOLUMEINIT_BOTH (OB_VOLUMEINIT_SHELL|OB_VOLUMEINIT_VOLUME)
-
-// a single mesh object
-typedef struct elbeemMesh {
- /* obstacle,fluid or inflow or control ... */
- short type;
- /* id of simulation domain it belongs to */
- short parentDomainId;
-
- /* vertices */
- int numVertices;
- float *vertices; // = float[n][3];
- /* animated vertices */
- int channelSizeVertices;
- float *channelVertices; // = float[channelSizeVertices* (n*3+1) ];
-
- /* triangles */
- int numTriangles;
- int *triangles; // = int[][3];
-
- /* animation channels */
- int channelSizeTranslation;
- float *channelTranslation;
- int channelSizeRotation;
- float *channelRotation;
- int channelSizeScale;
- float *channelScale;
-
- /* active channel */
- int channelSizeActive;
- float *channelActive;
- /* initial velocity channel (e.g. for inflow) */
- int channelSizeInitialVel;
- float *channelInitialVel; // vector
- /* use initial velocity in object coordinates? (e.g. for rotation) */
- short localInivelCoords;
- /* boundary types and settings */
- short obstacleType;
- float obstaclePartslip;
- /* amount of force transfer from fluid to obj, 0=off, 1=normal */
- float obstacleImpactFactor;
- /* init volume, shell or both? use OB_VOLUMEINIT_xxx defines above */
- short volumeInitType;
-
- /* name of the mesh, mostly for debugging */
- const char *name;
-
- /* fluid control settings */
- float cpsTimeStart;
- float cpsTimeEnd;
- float cpsQuality;
-
- int channelSizeAttractforceStrength;
- float *channelAttractforceStrength;
- int channelSizeAttractforceRadius;
- float *channelAttractforceRadius;
- int channelSizeVelocityforceStrength;
- float *channelVelocityforceStrength;
- int channelSizeVelocityforceRadius;
- float *channelVelocityforceRadius;
-} elbeemMesh;
-
-// API functions
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-
-// reset elbeemSimulationSettings struct with defaults
-void elbeemResetSettings(struct elbeemSimulationSettings*);
-
-// start fluidsim init (returns !=0 upon failure)
-int elbeemInit(void);
-
-// frees fluidsim
-int elbeemFree(void);
-
-// start fluidsim init (returns !=0 upon failure)
-int elbeemAddDomain(struct elbeemSimulationSettings*);
-
-// get failure message during simulation or init
-// if an error occured (the string is copied into buffer,
-// max. length = 256 chars )
-void elbeemGetErrorString(char *buffer);
-
-// reset elbeemMesh struct with zeroes
-void elbeemResetMesh(struct elbeemMesh*);
-
-// add mesh as fluidsim object
-int elbeemAddMesh(struct elbeemMesh*);
-
-// do the actual simulation
-int elbeemSimulate(void);
-
-// continue a previously stopped simulation
-int elbeemContinueSimulation(void);
-
-
-// helper functions
-
-// simplify animation channels
-// returns if the channel and its size changed
-int elbeemSimplifyChannelFloat(float *channel, int *size);
-int elbeemSimplifyChannelVec3(float *channel, int *size);
-
-// helper functions implemented in utilities.cpp
-
-/* set elbeem debug output level (0=off to 10=full on) */
-void elbeemSetDebugLevel(int level);
-/* elbeem debug output function, prints if debug level >0 */
-void elbeemDebugOut(char *msg);
-
-/* estimate how much memory a given setup will require */
-double elbeemEstimateMemreq(int res,
- float sx, float sy, float sz,
- int refine, char *retstr);
-
-
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-
-
-/******************************************************************************/
-// internal defines, do not use for initializing elbeemMesh
-// structs, for these use OB_xxx defines above
-
-/*! fluid geometry init types */
-// type "int" used, so max is 8
-#define FGI_FLAGSTART 16
-#define FGI_FLUID (1<<(FGI_FLAGSTART+ 0))
-#define FGI_NO_FLUID (1<<(FGI_FLAGSTART+ 1))
-#define FGI_BNDNO (1<<(FGI_FLAGSTART+ 2))
-#define FGI_BNDFREE (1<<(FGI_FLAGSTART+ 3))
-#define FGI_BNDPART (1<<(FGI_FLAGSTART+ 4))
-#define FGI_NO_BND (1<<(FGI_FLAGSTART+ 5))
-#define FGI_MBNDINFLOW (1<<(FGI_FLAGSTART+ 6))
-#define FGI_MBNDOUTFLOW (1<<(FGI_FLAGSTART+ 7))
-#define FGI_CONTROL (1<<(FGI_FLAGSTART+ 8))
-
-// all boundary types at once
-#define FGI_ALLBOUNDS ( FGI_BNDNO | FGI_BNDFREE | FGI_BNDPART | FGI_MBNDINFLOW | FGI_MBNDOUTFLOW )
-
-
-#endif // ELBEEM_API_H
diff --git a/intern/elbeem/intern/attributes.cpp b/intern/elbeem/intern/attributes.cpp
deleted file mode 100644
index beebc459c1a..00000000000
--- a/intern/elbeem/intern/attributes.cpp
+++ /dev/null
@@ -1,362 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * DEPRECATED - replaced by elbeem API, only channels are still used
- *
- *****************************************************************************/
-
-#include "attributes.h"
-#include "ntl_matrices.h"
-#include "elbeem.h"
-
-
-
-/******************************************************************************
- * attribute conversion functions
- *****************************************************************************/
-
-bool Attribute::initChannel(int elemSize) {
- elemSize=0; // remove warning
- return false;
-}
-string Attribute::getAsString(bool debug) {
- debug=false; // remove warning
- return string("");
-}
-int Attribute::getAsInt() {
- return 0;
-}
-bool Attribute::getAsBool() {
- return false;
-}
-double Attribute::getAsFloat() {
- return 0.;
-}
-ntlVec3d Attribute::getAsVec3d() {
- return ntlVec3d(0.);
-}
-void Attribute::getAsMat4Gfx(ntlMat4Gfx *mat) {
- mat=NULL; // remove warning
-}
-string Attribute::getCompleteString() {
- return string("");
-}
-
-
-/******************************************************************************
- * channel returns
- *****************************************************************************/
-
-AnimChannel<double> Attribute::getChannelFloat() {
- return AnimChannel<double>();
-}
-AnimChannel<int> Attribute::getChannelInt() {
- return AnimChannel<int>();
-}
-AnimChannel<ntlVec3d> Attribute::getChannelVec3d() {
- return AnimChannel<ntlVec3d>();
-}
-AnimChannel<ntlSetVec3f>
-Attribute::getChannelSetVec3f() {
- return AnimChannel<ntlSetVec3f>();
-}
-
-/******************************************************************************
- * check if there were unknown params
- *****************************************************************************/
-bool AttributeList::checkUnusedParams() {
- return false;
-}
-void AttributeList::setAllUsed() {
-}
-
-/******************************************************************************
- * Attribute list read functions
- *****************************************************************************/
-int AttributeList::readInt(string name, int defaultValue, string source,string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return defaultValue;
-}
-bool AttributeList::readBool(string name, bool defaultValue, string source,string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return defaultValue;
-}
-double AttributeList::readFloat(string name, double defaultValue, string source,string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return defaultValue;
-}
-string AttributeList::readString(string name, string defaultValue, string source,string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return defaultValue;
-}
-ntlVec3d AttributeList::readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return defaultValue;
-}
-
-void AttributeList::readMat4Gfx(string name, ntlMat4Gfx defaultValue, string source,string target, bool needed, ntlMat4Gfx *mat) {
- *mat = defaultValue;
- name=source=target=string(""); needed=false; mat=NULL; // remove warning
-}
-
-// set that a parameter can be given, and will be ignored...
-bool AttributeList::ignoreParameter(string name, string source) {
- name = source = ("");
- return false;
-}
-
-// read channels
-AnimChannel<int> AttributeList::readChannelInt(string name, int defaultValue, string source, string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<int>(defaultValue);
-}
-AnimChannel<double> AttributeList::readChannelFloat(string name, double defaultValue, string source, string target, bool needed ) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<double>(defaultValue);
-}
-AnimChannel<ntlVec3d> AttributeList::readChannelVec3d(string name, ntlVec3d defaultValue, string source, string target, bool needed ) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<ntlVec3d>(defaultValue);
-}
-AnimChannel<ntlSetVec3f> AttributeList::readChannelSetVec3f(string name, ntlSetVec3f defaultValue, string source, string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<ntlSetVec3f>(defaultValue);
-}
-AnimChannel<float> AttributeList::readChannelSinglePrecFloat(string name, float defaultValue, string source, string target, bool needed ) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<float>(defaultValue);
-}
-AnimChannel<ntlVec3f> AttributeList::readChannelVec3f(string name, ntlVec3f defaultValue, string source, string target, bool needed) {
- name=source=target=string(""); needed=false; // remove warning
- return AnimChannel<ntlVec3f>(defaultValue);
-}
-
-/******************************************************************************
- * destructor
- *****************************************************************************/
-AttributeList::~AttributeList() {
-};
-
-
-/******************************************************************************
- * debugging
- *****************************************************************************/
-
-//! debug function, prints value
-void Attribute::print() {
-}
-
-//! debug function, prints all attribs
-void AttributeList::print() {
-}
-
-
-/******************************************************************************
- * import attributes from other attribute list
- *****************************************************************************/
-void AttributeList::import(AttributeList *oal) {
- oal=NULL; // remove warning
-}
-
-
-/******************************************************************************
- * channel max finding
- *****************************************************************************/
-ntlVec3f channelFindMaxVf (AnimChannel<ntlVec3f> channel) {
- ntlVec3f ret(0.0);
- float maxLen = 0.0;
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- float nlen = normNoSqrt(channel.accessValues()[i]);
- if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
- }
- return ret;
-}
-ntlVec3d channelFindMaxVd (AnimChannel<ntlVec3d> channel) {
- ntlVec3d ret(0.0);
- float maxLen = 0.0;
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- float nlen = normNoSqrt(channel.accessValues()[i]);
- if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
- }
- return ret;
-}
-int channelFindMaxi (AnimChannel<float > channel) {
- int ret = 0;
- float maxLen = 0.0;
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- float nlen = ABS(channel.accessValues()[i]);
- if(nlen>maxLen) { ret= (int)channel.accessValues()[i]; maxLen=nlen; }
- }
- return ret;
-}
-float channelFindMaxf (AnimChannel<float > channel) {
- float ret = 0.0;
- float maxLen = 0.0;
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- float nlen = ABS(channel.accessValues()[i]);
- if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
- }
- return ret;
-}
-double channelFindMaxd (AnimChannel<double > channel) {
- double ret = 0.0;
- float maxLen = 0.0;
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- float nlen = ABS(channel.accessValues()[i]);
- if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
- }
- return ret;
-}
-
-/******************************************************************************
- // unoptimized channel simplification functions, use elbeem.cpp functions
- // warning - currently only with single precision
- *****************************************************************************/
-
-template<class SCALAR>
-static bool channelSimplifyScalarT(AnimChannel<SCALAR> &channel) {
- int size = channel.getSize();
- if(size<=1) return false;
- float *nchannel = new float[2*size];
- // convert to array
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- nchannel[i*2 + 0] = (float)channel.accessValues()[i];
- nchannel[i*2 + 1] = (float)channel.accessTimes()[i];
- }
- bool ret = elbeemSimplifyChannelFloat(nchannel, &size);
- if(ret) {
- vector<SCALAR> vals;
- vector<double> times;
- for(int i=0; i<size; i++) {
- vals.push_back( (SCALAR)(nchannel[i*2 + 0]) );
- times.push_back( (double)(nchannel[i*2 + 1]) );
- }
- channel = AnimChannel<SCALAR>(vals, times);
- }
- delete [] nchannel;
- return ret;
-}
-bool channelSimplifyi (AnimChannel<int > &channel) { return channelSimplifyScalarT<int>(channel); }
-bool channelSimplifyf (AnimChannel<float> &channel) { return channelSimplifyScalarT<float>(channel); }
-bool channelSimplifyd (AnimChannel<double > &channel) { return channelSimplifyScalarT<double>(channel); }
-template<class VEC>
-static bool channelSimplifyVecT(AnimChannel<VEC> &channel) {
- int size = channel.getSize();
- if(size<=1) return false;
- float *nchannel = new float[4*size];
- // convert to array
- for(size_t i=0; i<channel.accessValues().size(); i++) {
- nchannel[i*4 + 0] = (float)channel.accessValues()[i][0];
- nchannel[i*4 + 1] = (float)channel.accessValues()[i][1];
- nchannel[i*4 + 2] = (float)channel.accessValues()[i][2];
- nchannel[i*4 + 3] = (float)channel.accessTimes()[i];
- }
- bool ret = elbeemSimplifyChannelVec3(nchannel, &size);
- if(ret) {
- vector<VEC> vals;
- vector<double> times;
- for(int i=0; i<size; i++) {
- vals.push_back( VEC(nchannel[i*4 + 0], nchannel[i*4 + 1], nchannel[i*4 + 2] ) );
- times.push_back( (double)(nchannel[i*4 + 3]) );
- }
- channel = AnimChannel<VEC>(vals, times);
- }
- delete [] nchannel;
- return ret;
-}
-bool channelSimplifyVf (AnimChannel<ntlVec3f> &channel) {
- return channelSimplifyVecT<ntlVec3f>(channel);
-}
-bool channelSimplifyVd (AnimChannel<ntlVec3d> &channel) {
- return channelSimplifyVecT<ntlVec3d>(channel);
-}
-
-//! debug function, prints channel as string
-template<class Scalar>
-string AnimChannel<Scalar>::printChannel() {
- std::ostringstream ostr;
- ostr << " CHANNEL #"<< mValue.size() <<" = { ";
- for(size_t i=0;i<mValue.size();i++) {
- ostr <<"'"<< mValue[i]<<"' ";
- ostr << "@"<<mTimes[i]<<"; ";
- }
- ostr << " } ";
- return ostr.str();
-} // */
-
-// is now in header file: debugPrintChannel()
-// hack to force instantiation
-void __forceAnimChannelInstantiation() {
- AnimChannel< float > tmp1;
- AnimChannel< double > tmp2;
- AnimChannel< string > tmp3;
- AnimChannel< ntlVector3Dim<float> > tmp4;
- AnimChannel< ntlVector3Dim<double> > tmp5;
- tmp1.debugPrintChannel();
- tmp2.debugPrintChannel();
- tmp3.debugPrintChannel();
- tmp4.debugPrintChannel();
- tmp5.debugPrintChannel();
-}
-
-
-ntlSetVec3f::ntlSetVec3f(double v ) {
- mVerts.clear();
- mVerts.push_back( ntlVec3f(v) );
-}
-const ntlSetVec3f&
-ntlSetVec3f::operator=(double v ) {
- mVerts.clear();
- mVerts.push_back( ntlVec3f(v) );
- return *this;
-}
-
-std::ostream& operator<<( std::ostream& os, const ntlSetVec3f& vs ) {
- os<< "{";
- for(int j=0;j<(int)vs.mVerts.size();j++) os<<vs.mVerts[j];
- os<< "}";
- return os;
-}
-
-ntlSetVec3f&
-ntlSetVec3f::operator+=( double v )
-{
- for(int j=0;j<(int)(mVerts.size()) ;j++) {
- mVerts[j] += v;
- }
- return *this;
-}
-
-ntlSetVec3f&
-ntlSetVec3f::operator+=( const ntlSetVec3f &v )
-{
- for(int j=0;j<(int)MIN(mVerts.size(),v.mVerts.size()) ;j++) {
- mVerts[j] += v.mVerts[j];
- }
- return *this;
-}
-
-ntlSetVec3f&
-ntlSetVec3f::operator*=( double v )
-{
- for(int j=0;j<(int)(mVerts.size()) ;j++) {
- mVerts[j] *= v;
- }
- return *this;
-}
-
-ntlSetVec3f&
-ntlSetVec3f::operator*=( const ntlSetVec3f &v )
-{
- for(int j=0;j<(int)MIN(mVerts.size(),v.mVerts.size()) ;j++) {
- mVerts[j] *= v.mVerts[j];
- }
- return *this;
-}
-
-
diff --git a/intern/elbeem/intern/attributes.h b/intern/elbeem/intern/attributes.h
deleted file mode 100644
index 2d3b85887f5..00000000000
--- a/intern/elbeem/intern/attributes.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * DEPRECATED - replaced by elbeem API, only channels are still used
- *
- *****************************************************************************/
-
-
-#ifndef NTL_ATTRIBUTES_H
-
-#include "utilities.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-template<class T> class ntlMatrix4x4;
-class ntlSetVec3f;
-std::ostream& operator<<( std::ostream& os, const ntlSetVec3f& i );
-
-
-
-//! An animated attribute channel
-template<class Scalar>
-class AnimChannel
-{
- public:
- // default constructor
- AnimChannel() :
- mValue(), mTimes() { mInited = false; debugPrintChannel(); }
-
- // null init constructor
- AnimChannel(Scalar null) :
- mValue(1), mTimes(1) { mValue[0]=null; mTimes[0]=0.0; mInited = true; debugPrintChannel(); }
-
- // proper init
- AnimChannel(vector<Scalar> &v, vector<double> &t) :
- mValue(v), mTimes(t) { mInited = true; debugPrintChannel(); }
-
- // desctructor, nothing to do
- ~AnimChannel() { };
-
- // get interpolated value at time t
- Scalar get(double t) const {
- if(!mInited) { Scalar null; null=(Scalar)(0.0); return null; }
- if(t<=mTimes[0]) { return mValue[0]; }
- if(t>=mTimes[mTimes.size()-1]) { return mValue[mTimes.size()-1]; }
- for(size_t i=0; i<mTimes.size()-1; i++) {
- // find first time thats in between
- if((mTimes[i]<=t)&&(mTimes[i+1]>t)) {
- // interpolate
- double d = mTimes[i+1]-mTimes[i];
- double f = (t-mTimes[i])/d;
- //return (Scalar)(mValue[i] * (1.0-f) + mValue[i+1] * f);
- Scalar ret,tmp;
- ret = mValue[i];
- ret *= 1.-f;
- tmp = mValue[i+1];
- tmp *= f;
- ret += tmp;
- return ret;
- }
- }
- // whats this...?
- return mValue[0];
- };
-
- // get uninterpolated value at time t
- Scalar getConstant(double t) const {
- //errMsg("DEBB","getc"<<t<<" ");
- if(!mInited) { Scalar null; null=(Scalar)0.0; return null; }
- if(t<=mTimes[0]) { return mValue[0]; }
- if(t>=mTimes[mTimes.size()-1]) { return mValue[mTimes.size()-1]; }
- for(size_t i=0; i<mTimes.size()-1; i++) {
- //errMsg("DEBB","getc i"<<i<<" "<<mTimes[i]);
- // find first time thats in between
- if((mTimes[i]<=t)&&(mTimes[i+1]>t)) { return mValue[i]; }
- }
- // whats this...?
- return mValue[0];
- };
-
- // reset to null value
- void reset(Scalar null) {
- mValue.clear();
- mTimes.clear();
- mValue.push_back(null);
- mTimes.push_back(0.0);
- }
-
- //! debug function, prints channel as string
- string printChannel();
- //! debug function, prints to stdout if DEBUG_CHANNELS flag is enabled, used in constructors
- void debugPrintChannel();
- //! valid init?
- bool isInited() const { return mInited; }
-
- //! get number of entries (value and time sizes have to be equal)
- int getSize() const { return mValue.size(); };
- //! raw access of value vector
- vector<Scalar> &accessValues() { return mValue; }
- //! raw access of time vector
- vector<double> &accessTimes() { return mTimes; }
-
- protected:
-
- /*! inited at least once? */
- bool mInited;
- /*! anim channel attribute values */
- vector<Scalar> mValue;
- /*! anim channel attr times */
- vector<double> mTimes;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:AnimChannel")
-#endif
-};
-
-
-// helper class (not templated) for animated meshes
-class ntlSetVec3f {
- public:
- ntlSetVec3f(): mVerts() {};
- ntlSetVec3f(double v);
- ntlSetVec3f(vector<ntlVec3f> &v) { mVerts = v; };
-
- const ntlSetVec3f& operator=(double v );
- ntlSetVec3f& operator+=( double v );
- ntlSetVec3f& operator+=( const ntlSetVec3f &v );
- ntlSetVec3f& operator*=( double v );
- ntlSetVec3f& operator*=( const ntlSetVec3f &v );
-
- vector<ntlVec3f> mVerts;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlSetVec3f")
-#endif
-};
-
-
-// warning: DEPRECATED - replaced by elbeem API
-class Attribute
-{
- public:
- Attribute(string mn, vector<string> &value, int setline,bool channel) {
- mn = string(""); setline=0; channel=false; value.clear(); // remove warnings
- };
- Attribute(Attribute &a) { a.getCompleteString(); };
- ~Attribute() { };
-
- void setUsed(bool set){ set=false; }
- bool getUsed() { return true; }
- void setIsChannel(bool set){ set=false; }
- bool getIsChannel() { return false; }
-
- string getAsString(bool debug=false);
- int getAsInt();
- bool getAsBool();
- double getAsFloat();
- ntlVec3d getAsVec3d();
- void getAsMat4Gfx(ntlMatrix4x4<gfxReal> *mat);
-
- AnimChannel<int> getChannelInt();
- AnimChannel<double> getChannelFloat();
- AnimChannel<ntlVec3d> getChannelVec3d();
- AnimChannel<ntlSetVec3f> getChannelSetVec3f();
-
- string getCompleteString();
- void print();
-
- protected:
-
- bool initChannel(int elemSize);
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:Attribute")
-#endif
-};
-
-
-// warning: DEPRECATED - replaced by elbeem API
-//! The list of configuration attributes
-class AttributeList
-{
- public:
- AttributeList(string name) { name=string(""); };
- ~AttributeList();
- void addAttr(string name, vector<string> &value, int line, bool isChannel) {
- name=string(""); value.clear(); line=0; isChannel=false; // remove warnings
- };
- bool exists(string name) { name=string(""); return false; }
- void setAllUsed();
- bool checkUnusedParams();
- void import(AttributeList *oal);
- int readInt(string name, int defaultValue, string source,string target, bool needed);
- bool readBool(string name, bool defaultValue, string source,string target, bool needed);
- double readFloat(string name, double defaultValue, string source,string target, bool needed);
- string readString(string name, string defaultValue, string source,string target, bool needed);
- ntlVec3d readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed);
- void readMat4Gfx(string name, ntlMatrix4x4<gfxReal> defaultValue, string source,string target, bool needed, ntlMatrix4x4<gfxReal> *mat);
- AnimChannel<int> readChannelInt( string name, int defaultValue=0, string source=string("src"), string target=string("dst"), bool needed=false );
- AnimChannel<double> readChannelFloat( string name, double defaultValue=0, string source=string("src"), string target=string("dst"), bool needed=false );
- AnimChannel<ntlVec3d> readChannelVec3d( string name, ntlVec3d defaultValue=ntlVec3d(0.), string source=string("src"), string target=string("dst"), bool needed=false );
- AnimChannel<ntlSetVec3f> readChannelSetVec3f(string name, ntlSetVec3f defaultValue=ntlSetVec3f(0.), string source=string("src"), string target=string("dst"), bool needed=false );
- AnimChannel<ntlVec3f> readChannelVec3f( string name, ntlVec3f defaultValue=ntlVec3f(0.), string source=string("src"), string target=string("dst"), bool needed=false );
- AnimChannel<float> readChannelSinglePrecFloat( string name, float defaultValue=0., string source=string("src"), string target=string("dst"), bool needed=false );
- bool ignoreParameter(string name, string source);
- void print();
- protected:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:AttributeList")
-#endif
-};
-
-ntlVec3f channelFindMaxVf (AnimChannel<ntlVec3f> channel);
-ntlVec3d channelFindMaxVd (AnimChannel<ntlVec3d> channel);
-int channelFindMaxi (AnimChannel<int > channel);
-float channelFindMaxf (AnimChannel<float > channel);
-double channelFindMaxd (AnimChannel<double > channel);
-
-// unoptimized channel simplification functions, use elbeem.cpp functions
-bool channelSimplifyVf (AnimChannel<ntlVec3f> &channel);
-bool channelSimplifyVd (AnimChannel<ntlVec3d> &channel);
-bool channelSimplifyi (AnimChannel<int > &channel);
-bool channelSimplifyf (AnimChannel<float > &channel);
-bool channelSimplifyd (AnimChannel<double > &channel);
-
-//! output channel values? on=1/off=0
-#define DEBUG_PCHANNELS 0
-
-//! debug function, prints to stdout if DEBUG_PCHANNELS flag is enabled, used in constructors
-template<class Scalar>
-void AnimChannel<Scalar>::debugPrintChannel() { }
-
-
-#define NTL_ATTRIBUTES_H
-#endif
-
diff --git a/intern/elbeem/intern/controlparticles.cpp b/intern/elbeem/intern/controlparticles.cpp
deleted file mode 100644
index efecb354890..00000000000
--- a/intern/elbeem/intern/controlparticles.cpp
+++ /dev/null
@@ -1,1465 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-// --------------------------------------------------------------------------
-//
-// El'Beem - the visual lattice boltzmann freesurface simulator
-// All code distributed as part of El'Beem is covered by the version 2 of the
-// GNU General Public License. See the file COPYING for details.
-//
-// Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede
-//
-// implementation of control particle handling
-//
-// --------------------------------------------------------------------------
-
-// indicator for LBM inclusion
-#include "ntl_geometrymodel.h"
-#include "ntl_world.h"
-#include "solver_class.h"
-#include "controlparticles.h"
-#include "mvmcoords.h"
-#include <zlib.h>
-
-#ifndef sqrtf
-#define sqrtf sqrt
-#endif
-
-// brute force circle test init in initTimeArray
-// replaced by mDebugInit
-//#define CP_FORCECIRCLEINIT 0
-
-
-void ControlParticles::initBlenderTest() {
- mPartSets.clear();
-
- ControlParticleSet cps;
- mPartSets.push_back(cps);
- int setCnt = mPartSets.size()-1;
- ControlParticle p;
-
- // set for time zero
- mPartSets[setCnt].time = 0.;
-
- // add single particle
- p.reset();
- p.pos = LbmVec(0.5, 0.5, -0.5);
- mPartSets[setCnt].particles.push_back(p);
-
- // add second set for animation
- mPartSets.push_back(cps);
- setCnt = mPartSets.size()-1;
- mPartSets[setCnt].time = 0.15;
-
- // insert new position
- p.reset();
- p.pos = LbmVec(-0.5, -0.5, 0.5);
- mPartSets[setCnt].particles.push_back(p);
-
- // applyTrafos();
- initTime(0. , 1.);
-}
-
-// blender control object gets converted to mvm flui control object
-int ControlParticles::initFromObject(ntlGeometryObjModel *model) {
- vector<ntlTriangle> triangles;
- vector<ntlVec3Gfx> vertices;
- vector<ntlVec3Gfx> normals;
-
- /*
- model->loadBobjModel(string(infile));
-
- model->setLoaded(true);
-
- model->setGeoInitId(gid);
-
-
- printf("a animated? %d\n", model->getIsAnimated());
- printf("b animated? %d\n", model->getMeshAnimated());
- */
-
- model->setGeoInitType(FGI_FLUID);
-
- model->getTriangles(mCPSTimeStart, &triangles, &vertices, &normals, 1 );
- // model->applyTransformation(mCPSTimeStart, &vertices, &normals, 0, vertices.size(), true);
-
- // valid mesh?
- if(triangles.size() <= 0) {
- return 0;
- }
-
- ntlRenderGlobals *glob = new ntlRenderGlobals;
- ntlScene *genscene = new ntlScene( glob, false );
- genscene->addGeoClass(model);
- genscene->addGeoObject(model);
- genscene->buildScene(0., false);
- char treeFlag = (1<<(4+model->getGeoInitId()));
-
- ntlTree *tree = new ntlTree(
- 15, 8, // TREEwarning - fixed values for depth & maxtriangles here...
- genscene, treeFlag );
-
- // TODO? use params
- ntlVec3Gfx start,end;
- model->getExtends(start,end);
- /*
- printf("start - x: %f, y: %f, z: %f\n", start[0], start[1], start[2]);
- printf("end - x: %f, y: %f, z: %f\n", end[0], end[1], end[2]);
- printf("mCPSWidth: %f\n");
-*/
- LbmFloat width = mCPSWidth;
- if(width<=LBM_EPSILON) { errMsg("ControlParticles::initFromMVMCMesh","Invalid mCPSWidth! "<<mCPSWidth); width=mCPSWidth=0.1; }
- ntlVec3Gfx org = start+ntlVec3Gfx(width*0.5);
- gfxReal distance = -1.;
- vector<ntlVec3Gfx> inspos;
-
- // printf("distance: %f, width: %f\n", distance, width);
-
- while(org[2]<end[2]) {
- while(org[1]<end[1]) {
- while(org[0]<end[0]) {
- if(checkPointInside(tree, org, distance)) {
- inspos.push_back(org);
- }
- // TODO optimize, use distance
- org[0] += width;
- }
- org[1] += width;
- org[0] = start[0];
- }
- org[2] += width;
- org[1] = start[1];
- }
-
- // printf("inspos.size(): %d\n", inspos.size());
-
- MeanValueMeshCoords mvm;
- mvm.calculateMVMCs(vertices,triangles, inspos, mCPSWeightFac);
- vector<ntlVec3Gfx> ninspos;
- mvm.transfer(vertices, ninspos);
-
- // init first set, check dist
- ControlParticleSet firstcps; //T
- mPartSets.push_back(firstcps);
- mPartSets[mPartSets.size()-1].time = mCPSTimeStart;
- vector<bool> useCP;
-
- for(int i=0; i<(int)inspos.size(); i++) {
- ControlParticle p; p.reset();
- p.pos = vec2L(inspos[i]);
-
- bool usecpv = true;
-
- mPartSets[mPartSets.size()-1].particles.push_back(p);
- useCP.push_back(usecpv);
- }
-
- // init further sets, temporal mesh sampling
- double tsampling = mCPSTimestep;
- // printf("tsampling: %f, ninspos.size(): %d, mCPSTimeEnd: %f\n", tsampling, ninspos.size(), mCPSTimeEnd);
-
- int tcnt=0;
- for(double t=mCPSTimeStart+tsampling; ((t<mCPSTimeEnd) && (ninspos.size()>0.)); t+=tsampling) {
- ControlParticleSet nextcps; //T
- mPartSets.push_back(nextcps);
- mPartSets[mPartSets.size()-1].time = (gfxReal)t;
-
- vertices.clear(); triangles.clear(); normals.clear();
- model->getTriangles(t, &triangles, &vertices, &normals, 1 );
- mvm.transfer(vertices, ninspos);
-
- tcnt++;
- for(size_t i=0; i < ninspos.size(); i++) {
-
- if(useCP[i]) {
- ControlParticle p; p.reset();
- p.pos = vec2L(ninspos[i]);
- mPartSets[mPartSets.size()-1].particles.push_back(p);
- }
- }
- }
-
- model->setGeoInitType(FGI_CONTROL);
-
- delete tree;
- delete genscene;
- delete glob;
-
- // do reverse here
- if(model->getGeoPartSlipValue())
- {
- mirrorTime();
- }
-
- return 1;
-}
-
-
-// init all zero / defaults for a single particle
-void ControlParticle::reset() {
- pos = LbmVec(0.,0.,0.);
- vel = LbmVec(0.,0.,0.);
- influence = 1.;
- size = 1.;
-#ifndef LBMDIM
-#ifdef MAIN_2D
- rotaxis = LbmVec(0.,1.,0.); // SPH xz
-#else // MAIN_2D
- // 3d - roate in xy plane, vortex
- rotaxis = LbmVec(0.,0.,1.);
- // 3d - rotate for wave
- //rotaxis = LbmVec(0.,1.,0.);
-#endif // MAIN_2D
-#else // LBMDIM
- rotaxis = LbmVec(0.,1.,0.); // LBM xy , is swapped afterwards
-#endif // LBMDIM
-
- density = 0.;
- densityWeight = 0.;
- avgVelAcc = avgVel = LbmVec(0.);
- avgVelWeight = 0.;
-}
-
-
-// default preset/empty init
-ControlParticles::ControlParticles() :
- _influenceTangential(0.f),
- _influenceAttraction(0.f),
- _influenceVelocity(0.f),
- _influenceMaxdist(0.f),
- _radiusAtt(1.0f),
- _radiusVel(1.0f),
- _radiusMinMaxd(2.0f),
- _radiusMaxd(3.0f),
- _currTime(-1.0), _currTimestep(1.),
- _initTimeScale(1.),
- _initPartOffset(0.), _initPartScale(1.),
- _initLastPartOffset(0.), _initLastPartScale(1.),
- _initMirror(""),
- _fluidSpacing(1.), _kernelWeight(-1.),
- _charLength(1.), _charLengthInv(1.),
- mvCPSStart(-10000.), mvCPSEnd(10000.),
- mCPSWidth(0.1), mCPSTimestep(0.02), // was 0.05
- mCPSTimeStart(0.), mCPSTimeEnd(0.5), mCPSWeightFac(1.),
- mDebugInit(0)
-{
- _radiusAtt = 0.15f;
- _radiusVel = 0.15f;
- _radiusMinMaxd = 0.16f;
- _radiusMaxd = 0.3;
-
- _influenceAttraction = 0.f;
- _influenceTangential = 0.f;
- _influenceVelocity = 0.f;
- // 3d tests */
-}
-
-
-
-ControlParticles::~ControlParticles() {
- // nothing to do...
-}
-
-LbmFloat ControlParticles::getControlTimStart() {
- if(mPartSets.size()>0) { return mPartSets[0].time; }
- return -1000.;
-}
-LbmFloat ControlParticles::getControlTimEnd() {
- if(mPartSets.size()>0) { return mPartSets[mPartSets.size()-1].time; }
- return -1000.;
-}
-
-// calculate for delta t
-void ControlParticles::setInfluenceVelocity(LbmFloat set, LbmFloat dt) {
- const LbmFloat dtInter = 0.01;
- LbmFloat facFv = 1.-set; //cparts->getInfluenceVelocity();
- // mLevel[mMaxRefine].timestep
- LbmFloat facNv = (LbmFloat)( 1.-pow( (double)facFv, (double)(dt/dtInter)) );
- //errMsg("vwcalc","ts:"<<dt<< " its:"<<(dt/dtInter) <<" fv"<<facFv<<" nv"<<facNv<<" test:"<< pow( (double)(1.-facNv),(double)(dtInter/dt)) );
- _influenceVelocity = facNv;
-}
-
-int ControlParticles::initExampleSet()
-{
- // unused
- return 0;
-}
-
-int ControlParticles::getTotalSize()
-{
- int s=0;
- for(int i=0; i<(int)mPartSets.size(); i++) {
- s+= mPartSets[i].particles.size();
- }
- return s;
-}
-
-// --------------------------------------------------------------------------
-// load positions & timing from text file
-// WARNING - make sure file has unix format, no win/dos linefeeds...
-#define LINE_LEN 100
-int ControlParticles::initFromTextFile(string filename)
-{
- /*
- const bool debugRead = false;
- char line[LINE_LEN];
- line[LINE_LEN-1] = '\0';
- mPartSets.clear();
- if(filename.size()<2) return 0;
-
- // HACK , use "cparts" suffix as old
- // e.g. "cpart2" as new
- if(filename[ filename.size()-1 ]=='s') {
- return initFromTextFileOld(filename);
- }
-
- FILE *infile = fopen(filename.c_str(), "r");
- if(!infile) {
- errMsg("ControlParticles::initFromTextFile","unable to open '"<<filename<<"' " );
- // try to open as gz sequence
- if(initFromBinaryFile(filename)) { return 1; }
- // try mesh MVCM generation
- if(initFromMVCMesh(filename)) { return 1; }
- // failed...
- return 0;
- }
-
- int haveNo = false;
- int haveScale = false;
- int haveTime = false;
- int noParts = -1;
- int partCnt = 0;
- int setCnt = 0;
- //ControlParticle p; p.reset();
- // scale times by constant factor while reading
- LbmFloat timeScale= 1.0;
- int lineCnt = 0;
- bool abortParse = false;
-#define LASTCP mPartSets[setCnt].particles[ mPartSets[setCnt].particles.size()-1 ]
-
- while( (!feof(infile)) && (!abortParse)) {
- lineCnt++;
- fgets(line, LINE_LEN, infile);
-
- //if(debugRead) printf("\nDEBUG%d r '%s'\n",lineCnt, line);
- if(!line) continue;
- size_t len = strlen(line);
-
- // skip empty lines and comments (#,//)
- if(len<1) continue;
- if( (line[0]=='#') || (line[0]=='\n') ) continue;
- if((len>1) && (line[0]=='/' && line[1]=='/')) continue;
-
- // debug remove newline
- if((len>=1)&&(line[len-1]=='\n')) line[len-1]='\0';
-
- switch(line[0]) {
-
- case 'N': { // total number of particles, more for debugging...
- noParts = atoi(line+2);
- if(noParts<=0) {
- errMsg("ControlParticles::initFromTextFile","file '"<<filename<<"' - invalid no of particles "<<noParts);
- mPartSets.clear(); fclose(infile); return 0;
- }
- if(debugRead) printf("CPDEBUG%d no parts '%d'\n",lineCnt, noParts );
- haveNo = true;
- } break;
-
- case 'T': { // global time scale
- timeScale *= (LbmFloat)atof(line+2);
- if(debugRead) printf("ControlParticles::initFromTextFile - line %d , set timescale '%f', org %f\n",lineCnt, timeScale , _initTimeScale);
- if(timeScale==0.) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error: timescale = 0.! reseting to 1 ...\n",lineCnt); timeScale=1.; }
- haveScale = true;
- } break;
-
- case 'I': { // influence settings, overrides others as of now...
- float val = (LbmFloat)atof(line+3);
- const char *setvar = "[invalid]";
- switch(line[1]) {
- //case 'f': { _influenceFalloff = val; setvar = "falloff"; } break;
- case 't': { _influenceTangential = val; setvar = "tangential"; } break;
- case 'a': { _influenceAttraction = val; setvar = "attraction"; } break;
- case 'v': { _influenceVelocity = val; setvar = "velocity"; } break;
- case 'm': { _influenceMaxdist = val; setvar = "maxdist"; } break;
- default:
- fprintf(stdout,"ControlParticles::initFromTextFile (%s) - line %d , invalid influence setting %c, %f\n",filename.c_str() ,lineCnt, line[1], val);
- }
- if(debugRead) printf("CPDEBUG%d set influence '%s'=%f \n",lineCnt, setvar, val);
- } break;
-
- case 'R': { // radius settings, overrides others as of now...
- float val = (LbmFloat)atof(line+3);
- const char *setvar = "[invalid]";
- switch(line[1]) {
- case 'a': { _radiusAtt = val; setvar = "r_attraction"; } break;
- case 'v': { _radiusVel = val; setvar = "r_velocity"; } break;
- case 'm': { _radiusMaxd = val; setvar = "r_maxdist"; } break;
- default:
- fprintf(stdout,"ControlParticles::initFromTextFile (%s) - line %d , invalid influence setting %c, %f\n",filename.c_str() ,lineCnt, line[1], val);
- }
- if(debugRead) printf("CPDEBUG%d set influence '%s'=%f \n",lineCnt, setvar, val);
- } break;
-
- case 'S': { // new particle set at time T
- ControlParticleSet cps;
- mPartSets.push_back(cps);
- setCnt = (int)mPartSets.size()-1;
-
- LbmFloat val = (LbmFloat)atof(line+2);
- mPartSets[setCnt].time = val * timeScale;
- if(debugRead) printf("CPDEBUG%d new set, time '%f', %d\n",lineCnt, mPartSets[setCnt].time, setCnt );
- haveTime = true;
- partCnt = -1;
- } break;
-
- case 'P': // new particle with pos
- case 'n': { // new particle without pos
- if((!haveTime)||(setCnt<0)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error: set missing!\n",lineCnt); abortParse=true; break; }
- partCnt++;
- if(partCnt>=noParts) {
- if(debugRead) printf("CPDEBUG%d partset done \n",lineCnt);
- haveTime = false;
- } else {
- ControlParticle p; p.reset();
- mPartSets[setCnt].particles.push_back(p);
- }
- }
- // only new part, or new with pos?
- if(line[0] == 'n') break;
-
- // particle properties
-
- case 'p': { // new particle set at time T
- if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|p: particle missing!\n",lineCnt); abortParse=true; break; }
- float px=0.,py=0.,pz=0.;
- if( sscanf(line+2,"%f %f %f",&px,&py,&pz) != 3) {
- fprintf(stdout,"CPDEBUG%d, unable to parse position!\n",lineCnt); abortParse=true; break;
- }
- if(!(finite(px)&&finite(py)&&finite(pz))) { px=py=pz=0.; }
- LASTCP.pos[0] = px;
- LASTCP.pos[1] = py;
- LASTCP.pos[2] = pz;
- if(debugRead) printf("CPDEBUG%d part%d,%d: position %f,%f,%f \n",lineCnt,setCnt,partCnt, px,py,pz);
- } break;
-
- case 's': { // particle size
- if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|s: particle missing!\n",lineCnt); abortParse=true; break; }
- float ps=1.;
- if( sscanf(line+2,"%f",&ps) != 1) {
- fprintf(stdout,"CPDEBUG%d, unable to parse size!\n",lineCnt); abortParse=true; break;
- }
- if(!(finite(ps))) { ps=0.; }
- LASTCP.size = ps;
- if(debugRead) printf("CPDEBUG%d part%d,%d: size %f \n",lineCnt,setCnt,partCnt, ps);
- } break;
-
- case 'i': { // particle influence
- if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|i: particle missing!\n",lineCnt); abortParse=true; break; }
- float pinf=1.;
- if( sscanf(line+2,"%f",&pinf) != 1) {
- fprintf(stdout,"CPDEBUG%d, unable to parse size!\n",lineCnt); abortParse=true; break;
- }
- if(!(finite(pinf))) { pinf=0.; }
- LASTCP.influence = pinf;
- if(debugRead) printf("CPDEBUG%d part%d,%d: influence %f \n",lineCnt,setCnt,partCnt, pinf);
- } break;
-
- case 'a': { // rotation axis
- if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|a: particle missing!\n",lineCnt); abortParse=true; break; }
- float px=0.,py=0.,pz=0.;
- if( sscanf(line+2,"%f %f %f",&px,&py,&pz) != 3) {
- fprintf(stdout,"CPDEBUG%d, unable to parse rotaxis!\n",lineCnt); abortParse=true; break;
- }
- if(!(finite(px)&&finite(py)&&finite(pz))) { px=py=pz=0.; }
- LASTCP.rotaxis[0] = px;
- LASTCP.rotaxis[1] = py;
- LASTCP.rotaxis[2] = pz;
- if(debugRead) printf("CPDEBUG%d part%d,%d: rotaxis %f,%f,%f \n",lineCnt,setCnt,partCnt, px,py,pz);
- } break;
-
-
- default:
- if(debugRead) printf("CPDEBUG%d ignored: '%s'\n",lineCnt, line );
- break;
- }
- }
- if(debugRead && abortParse) printf("CPDEBUG aborted parsing after set... %d\n",(int)mPartSets.size() );
-
- // sanity check
- for(int i=0; i<(int)mPartSets.size(); i++) {
- if( (int)mPartSets[i].particles.size()!=noParts) {
- fprintf(stdout,"ControlParticles::initFromTextFile (%s) - invalid no of particles in set %d, is:%d, shouldbe:%d \n",filename.c_str() ,i,(int)mPartSets[i].particles.size(), noParts);
- mPartSets.clear();
- fclose(infile);
- return 0;
- }
- }
-
- // print stats
- printf("ControlParticles::initFromTextFile (%s): Read %d sets, each %d particles\n",filename.c_str() ,
- (int)mPartSets.size(), noParts );
- if(mPartSets.size()>0) {
- printf("ControlParticles::initFromTextFile (%s): Time: %f,%f\n",filename.c_str() ,mPartSets[0].time, mPartSets[mPartSets.size()-1].time );
- }
-
- // done...
- fclose(infile);
- applyTrafos();
- */
- return 1;
-}
-
-
-int ControlParticles::initFromTextFileOld(string filename)
-{
- /*
- const bool debugRead = false;
- char line[LINE_LEN];
- line[LINE_LEN-1] = '\0';
- mPartSets.clear();
- if(filename.size()<1) return 0;
-
- FILE *infile = fopen(filename.c_str(), "r");
- if(!infile) {
- fprintf(stdout,"ControlParticles::initFromTextFileOld - unable to open '%s'\n",filename.c_str() );
- return 0;
- }
-
- int haveNo = false;
- int haveScale = false;
- int haveTime = false;
- int noParts = -1;
- int coordCnt = 0;
- int partCnt = 0;
- int setCnt = 0;
- ControlParticle p; p.reset();
- // scale times by constant factor while reading
- LbmFloat timeScale= 1.0;
- int lineCnt = 0;
-
- while(!feof(infile)) {
- lineCnt++;
- fgets(line, LINE_LEN, infile);
-
- if(debugRead) printf("\nDEBUG%d r '%s'\n",lineCnt, line);
-
- if(!line) continue;
- size_t len = strlen(line);
-
- // skip empty lines and comments (#,//)
- if(len<1) continue;
- if( (line[0]=='#') || (line[0]=='\n') ) continue;
- if((len>1) && (line[0]=='/' && line[1]=='/')) continue;
-
- // debug remove newline
- if((len>=1)&&(line[len-1]=='\n')) line[len-1]='\0';
-
- // first read no. of particles
- if(!haveNo) {
- noParts = atoi(line);
- if(noParts<=0) {
- fprintf(stdout,"ControlParticles::initFromTextFileOld - invalid no of particles %d\n",noParts);
- mPartSets.clear();
- fclose(infile);
- return 0;
- }
- if(debugRead) printf("DEBUG%d noparts '%d'\n",lineCnt, noParts );
- haveNo = true;
- }
-
- // then read time scale
- else if(!haveScale) {
- timeScale *= (LbmFloat)atof(line);
- if(debugRead) printf("DEBUG%d tsc '%f', org %f\n",lineCnt, timeScale , _initTimeScale);
- haveScale = true;
- }
-
- // then get set time
- else if(!haveTime) {
- ControlParticleSet cps;
- mPartSets.push_back(cps);
- setCnt = (int)mPartSets.size()-1;
-
- LbmFloat val = (LbmFloat)atof(line);
- mPartSets[setCnt].time = val * timeScale;
- if(debugRead) printf("DEBUG%d time '%f', %d\n",lineCnt, mPartSets[setCnt].time, setCnt );
- haveTime = true;
- }
-
- // default read all parts
- else {
- LbmFloat val = (LbmFloat)atof(line);
- if(debugRead) printf("DEBUG: l%d s%d,particle%d '%f' %d,%d/%d\n",lineCnt,(int)mPartSets.size(),(int)mPartSets[setCnt].particles.size(), val ,coordCnt,partCnt,noParts);
- p.pos[coordCnt] = val;
- coordCnt++;
- if(coordCnt>=3) {
- mPartSets[setCnt].particles.push_back(p);
- p.reset();
- coordCnt=0;
- partCnt++;
- }
- if(partCnt>=noParts) {
- partCnt = 0;
- haveTime = false;
- }
- //if(debugRead) printf("DEBUG%d par2 %d,%d/%d\n",lineCnt, coordCnt,partCnt,noParts);
- }
- //read pos, vel ...
- }
-
- // sanity check
- for(int i=0; i<(int)mPartSets.size(); i++) {
- if( (int)mPartSets[i].particles.size()!=noParts) {
- fprintf(stdout,"ControlParticles::initFromTextFileOld - invalid no of particles in set %d, is:%d, shouldbe:%d \n",i,(int)mPartSets[i].particles.size(), noParts);
- mPartSets.clear();
- fclose(infile);
- return 0;
- }
- }
- // print stats
- printf("ControlParticles::initFromTextFileOld: Read %d sets, each %d particles\n",
- (int)mPartSets.size(), noParts );
- if(mPartSets.size()>0) {
- printf("ControlParticles::initFromTextFileOld: Time: %f,%f\n",mPartSets[0].time, mPartSets[mPartSets.size()-1].time );
- }
-
- // done...
- fclose(infile);
- applyTrafos();
- */
- return 1;
-}
-
-// load positions & timing from gzipped binary file
-int ControlParticles::initFromBinaryFile(string filename) {
- mPartSets.clear();
- if(filename.size()<1) return 0;
- int fileNotFound=0;
- int fileFound=0;
- char ofile[256];
-
- for(int set=0; ((set<10000)&&(fileNotFound<10)); set++) {
- snprintf(ofile,256,"%s%04d.gz",filename.c_str(),set);
- //errMsg("ControlParticle::initFromBinaryFile","set"<<set<<" notf"<<fileNotFound<<" ff"<<fileFound);
-
- gzFile gzf;
- gzf = gzopen(ofile, "rb");
- if (!gzf) {
- //errMsg("ControlParticles::initFromBinaryFile","Unable to open file for reading '"<<ofile<<"' ");
- fileNotFound++;
- continue;
- }
- fileNotFound=0;
- fileFound++;
-
- ControlParticleSet cps;
- mPartSets.push_back(cps);
- int setCnt = (int)mPartSets.size()-1;
- //LbmFloat val = (LbmFloat)atof(line+2);
- mPartSets[setCnt].time = (gfxReal)set;
-
- int totpart = 0;
- gzread(gzf, &totpart, sizeof(totpart));
-
- for(int a=0; a<totpart; a++) {
- int ptype=0;
- float psize=0.0;
- ntlVec3Gfx ppos,pvel;
- gzread(gzf, &ptype, sizeof(ptype));
- gzread(gzf, &psize, sizeof(float));
-
- for (int j=0; j<3; j++) { gzread(gzf, &ppos[j], sizeof(float)); }
- for (int j=0; j<3; j++) { gzread(gzf, &pvel[j], sizeof(float)); }
-
- ControlParticle p;
- p.reset();
- p.pos = vec2L(ppos);
- mPartSets[setCnt].particles.push_back(p);
- }
-
- gzclose(gzf);
- //errMsg("ControlParticle::initFromBinaryFile","Read set "<<ofile<<", #"<<mPartSets[setCnt].particles.size() ); // DEBUG
- } // sets
-
- if(fileFound==0) return 0;
- applyTrafos();
- return 1;
-}
-
-int globCPIProblems =0;
-bool ControlParticles::checkPointInside(ntlTree *tree, ntlVec3Gfx org, gfxReal &distance) {
- // warning - stripped down version of geoInitCheckPointInside
- const int globGeoInitDebug = 0;
- const int flags = FGI_FLUID;
- org += ntlVec3Gfx(0.0001);
- ntlVec3Gfx dir = ntlVec3Gfx(1.0, 0.0, 0.0);
- int OId = -1;
- ntlRay ray(org, dir, 0, 1.0, NULL);
- bool done = false;
- bool inside = false;
- int mGiObjInside = 0;
- LbmFloat mGiObjDistance = -1.0;
- LbmFloat giObjFirstHistSide = 0;
-
- // if not inside, return distance to first hit
- gfxReal firstHit=-1.0;
- int firstOId = -1;
- if(globGeoInitDebug) errMsg("IIIstart"," isect "<<org);
-
- while(!done) {
- // find first inside intersection
- ntlTriangle *triIns = NULL;
- distance = -1.0;
- ntlVec3Gfx normal(0.0);
- tree->intersectX(ray,distance,normal, triIns, flags, true);
- if(triIns) {
- ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
- LbmFloat orientation = dot(normal, dir);
- OId = triIns->getObjectId();
- if(orientation<=0.0) {
- // outside hit
- normal *= -1.0;
- mGiObjInside++;
- if(giObjFirstHistSide==0) giObjFirstHistSide = 1;
- if(globGeoInitDebug) errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation);
- } else {
- // inside hit
- mGiObjInside++;
- if(mGiObjDistance<0.0) mGiObjDistance = distance;
- if(globGeoInitDebug) errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation);
- if(giObjFirstHistSide==0) giObjFirstHistSide = -1;
- }
- norg += normal * getVecEpsilon();
- ray = ntlRay(norg, dir, 0, 1.0, NULL);
- // remember first hit distance, in case we're not
- // inside anything
- if(firstHit<0.0) {
- firstHit = distance;
- firstOId = OId;
- }
- } else {
- // no more intersections... return false
- done = true;
- }
- }
-
- distance = -1.0;
- if(mGiObjInside>0) {
- bool mess = false;
- if((mGiObjInside%2)==1) {
- if(giObjFirstHistSide != -1) mess=true;
- } else {
- if(giObjFirstHistSide != 1) mess=true;
- }
- if(mess) {
- // ?
- //errMsg("IIIproblem","At "<<org<<" obj inside:"<<mGiObjInside<<" firstside:"<<giObjFirstHistSide );
- globCPIProblems++;
- mGiObjInside++; // believe first hit side...
- }
- }
-
- if(globGeoInitDebug) errMsg("CHIII"," ins="<<mGiObjInside<<" t"<<mGiObjDistance<<" d"<<distance);
- if(((mGiObjInside%2)==1)&&(mGiObjDistance>0.0)) {
- if( (distance<0.0) || // first intersection -> good
- ((distance>0.0)&&(distance>mGiObjDistance)) // more than one intersection -> use closest one
- ) {
- distance = mGiObjDistance;
- OId = 0;
- inside = true;
- }
- }
-
- if(!inside) {
- distance = firstHit;
- OId = firstOId;
- }
- if(globGeoInitDebug) errMsg("CHIII","ins"<<inside<<" fh"<<firstHit<<" fo"<<firstOId<<" - h"<<distance<<" o"<<OId);
-
- return inside;
-}
-int ControlParticles::initFromMVCMesh(string filename) {
- myTime_t mvmstart = getTime();
- ntlGeometryObjModel *model = new ntlGeometryObjModel();
- int gid=1;
- char infile[256];
- vector<ntlTriangle> triangles;
- vector<ntlVec3Gfx> vertices;
- vector<ntlVec3Gfx> normals;
- snprintf(infile,256,"%s.bobj.gz", filename.c_str() );
- model->loadBobjModel(string(infile));
- model->setLoaded(true);
- model->setGeoInitId(gid);
- model->setGeoInitType(FGI_FLUID);
- debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG,"infile:"<<string(infile) ,4);
-
- //getTriangles(double t, vector<ntlTriangle> *triangles, vector<ntlVec3Gfx> *vertices, vector<ntlVec3Gfx> *normals, int objectId );
- model->getTriangles(mCPSTimeStart, &triangles, &vertices, &normals, 1 );
- debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG," tris:"<<triangles.size()<<" verts:"<<vertices.size()<<" norms:"<<normals.size() , 2);
-
- // valid mesh?
- if(triangles.size() <= 0) {
- return 0;
- }
-
- ntlRenderGlobals *glob = new ntlRenderGlobals;
- ntlScene *genscene = new ntlScene( glob, false );
- genscene->addGeoClass(model);
- genscene->addGeoObject(model);
- genscene->buildScene(0., false);
- char treeFlag = (1<<(4+gid));
-
- ntlTree *tree = new ntlTree(
- 15, 8, // TREEwarning - fixed values for depth & maxtriangles here...
- genscene, treeFlag );
-
- // TODO? use params
- ntlVec3Gfx start,end;
- model->getExtends(start,end);
-
- LbmFloat width = mCPSWidth;
- if(width<=LBM_EPSILON) { errMsg("ControlParticles::initFromMVMCMesh","Invalid mCPSWidth! "<<mCPSWidth); width=mCPSWidth=0.1; }
- ntlVec3Gfx org = start+ntlVec3Gfx(width*0.5);
- gfxReal distance = -1.;
- vector<ntlVec3Gfx> inspos;
- int approxmax = (int)( ((end[0]-start[0])/width)*((end[1]-start[1])/width)*((end[2]-start[2])/width) );
-
- debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG,"start"<<start<<" end"<<end<<" w="<<width<<" maxp:"<<approxmax, 5);
- while(org[2]<end[2]) {
- while(org[1]<end[1]) {
- while(org[0]<end[0]) {
- if(checkPointInside(tree, org, distance)) {
- inspos.push_back(org);
- //inspos.push_back(org+ntlVec3Gfx(width));
- //inspos.push_back(start+end*0.5);
- }
- // TODO optimize, use distance
- org[0] += width;
- }
- org[1] += width;
- org[0] = start[0];
- }
- org[2] += width;
- org[1] = start[1];
- }
- debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG,"points: "<<inspos.size()<<" initproblems: "<<globCPIProblems,5 );
-
- MeanValueMeshCoords mvm;
- mvm.calculateMVMCs(vertices,triangles, inspos, mCPSWeightFac);
- vector<ntlVec3Gfx> ninspos;
- mvm.transfer(vertices, ninspos);
-
- // init first set, check dist
- ControlParticleSet firstcps; //T
- mPartSets.push_back(firstcps);
- mPartSets[mPartSets.size()-1].time = (gfxReal)0.;
- vector<bool> useCP;
- bool debugPos=false;
-
- for(int i=0; i<(int)inspos.size(); i++) {
- ControlParticle p; p.reset();
- p.pos = vec2L(inspos[i]);
- //errMsg("COMP "," "<<inspos[i]<<" vs "<<ninspos[i] );
- double cpdist = norm(inspos[i]-ninspos[i]);
- bool usecpv = true;
- if(debugPos) errMsg("COMP "," "<<cpdist<<usecpv);
-
- mPartSets[mPartSets.size()-1].particles.push_back(p);
- useCP.push_back(usecpv);
- }
-
- // init further sets, temporal mesh sampling
- double tsampling = mCPSTimestep;
- int totcnt = (int)( (mCPSTimeEnd-mCPSTimeStart)/tsampling ), tcnt=0;
- for(double t=mCPSTimeStart+tsampling; ((t<mCPSTimeEnd) && (ninspos.size()>0.)); t+=tsampling) {
- ControlParticleSet nextcps; //T
- mPartSets.push_back(nextcps);
- mPartSets[mPartSets.size()-1].time = (gfxReal)t;
-
- vertices.clear(); triangles.clear(); normals.clear();
- model->getTriangles(t, &triangles, &vertices, &normals, 1 );
- mvm.transfer(vertices, ninspos);
- if(tcnt%(totcnt/10)==1) debMsgStd("MeanValueMeshCoords::calculateMVMCs",DM_MSG,"Transferring animation, frame: "<<tcnt<<"/"<<totcnt,5 );
- tcnt++;
- for(int i=0; i<(int)ninspos.size(); i++) {
- if(debugPos) errMsg("COMP "," "<<norm(inspos[i]-ninspos[i]) );
- if(useCP[i]) {
- ControlParticle p; p.reset();
- p.pos = vec2L(ninspos[i]);
- mPartSets[mPartSets.size()-1].particles.push_back(p);
- }
- }
- }
-
- applyTrafos();
-
- myTime_t mvmend = getTime();
- debMsgStd("ControlParticle::initFromMVMCMesh",DM_MSG,"t:"<<getTimeString(mvmend-mvmstart)<<" ",7 );
- delete tree;
- delete genscene;
- delete glob;
-//exit(1); // DEBUG
- return 1;
-}
-
-#define TRISWAP(v,a,b) { LbmFloat tmp = (v)[b]; (v)[b]=(v)[a]; (v)[a]=tmp; }
-#define TRISWAPALL(v,a,b) { \
- TRISWAP( (v).pos ,a,b ); \
- TRISWAP( (v).vel ,a,b ); \
- TRISWAP( (v).rotaxis ,a,b ); }
-
-// helper function for LBM 2D -> swap Y and Z components everywhere
-void ControlParticles::swapCoords(int a, int b) {
- //return;
- for(int i=0; i<(int)mPartSets.size(); i++) {
- for(int j=0; j<(int)mPartSets[i].particles.size(); j++) {
- TRISWAPALL( mPartSets[i].particles[j],a,b );
- }
- }
-}
-
-// helper function for LBM 2D -> mirror time
-void ControlParticles::mirrorTime() {
- LbmFloat maxtime = mPartSets[mPartSets.size()-1].time;
- const bool debugTimeswap = false;
-
- for(int i=0; i<(int)mPartSets.size(); i++) {
- mPartSets[i].time = maxtime - mPartSets[i].time;
- }
-
- for(int i=0; i<(int)mPartSets.size()/2; i++) {
- ControlParticleSet cps = mPartSets[i];
- if(debugTimeswap) errMsg("TIMESWAP", " s"<<i<<","<<mPartSets[i].time<<" and s"<<(mPartSets.size()-1-i)<<","<< mPartSets[mPartSets.size()-1-i].time <<" mt:"<<maxtime );
- mPartSets[i] = mPartSets[mPartSets.size()-1-i];
- mPartSets[mPartSets.size()-1-i] = cps;
- }
-
- for(int i=0; i<(int)mPartSets.size(); i++) {
- if(debugTimeswap) errMsg("TIMESWAP", "done: s"<<i<<","<<mPartSets[i].time<<" "<<mPartSets[i].particles.size() );
- }
-}
-
-// apply init transformations
-void ControlParticles::applyTrafos() {
- // apply trafos
- for(int i=0; i<(int)mPartSets.size(); i++) {
- mPartSets[i].time *= _initTimeScale;
- /*for(int j=0; j<(int)mPartSets[i].particles.size(); j++) {
- for(int k=0; k<3; k++) {
- mPartSets[i].particles[j].pos[k] *= _initPartScale[k];
- mPartSets[i].particles[j].pos[k] += _initPartOffset[k];
- }
- } now done in initarray */
- }
-
- // mirror coords...
- for(int l=0; l<(int)_initMirror.length(); l++) {
- switch(_initMirror[l]) {
- case 'X':
- case 'x':
- //printf("ControlParticles::applyTrafos - mirror x\n");
- swapCoords(1,2);
- break;
- case 'Y':
- case 'y':
- //printf("ControlParticles::applyTrafos - mirror y\n");
- swapCoords(0,2);
- break;
- case 'Z':
- case 'z':
- //printf("ControlParticles::applyTrafos - mirror z\n");
- swapCoords(0,1);
- break;
- case 'T':
- case 't':
- //printf("ControlParticles::applyTrafos - mirror time\n");
- mirrorTime();
- break;
- case ' ':
- case '-':
- case '\n':
- break;
- default:
- //printf("ControlParticles::applyTrafos - mirror unknown %c !?\n", _initMirror[l] );
- break;
- }
- }
-
- // reset 2d positions
-#if (CP_PROJECT2D==1) && ( defined(MAIN_2D) || LBMDIM==2 )
- for(size_t j=0; j<mPartSets.size(); j++)
- for(size_t i=0; i<mPartSets[j].particles.size(); i++) {
- // DEBUG
- mPartSets[j].particles[i].pos[1] = 0.f;
- }
-#endif
-
-#if defined(LBMDIM)
- //? if( (getenv("ELBEEM_CPINFILE")) || (getenv("ELBEEM_CPOUTFILE")) ){
- // gui control test, don swap...
- //? } else {
- //? swapCoords(1,2); // LBM 2D -> swap Y and Z components everywhere
- //? }
-#endif
-
- initTime(0.f, 0.f);
-}
-
-#undef TRISWAP
-
-// --------------------------------------------------------------------------
-// init for a given time
-void ControlParticles::initTime(LbmFloat t, LbmFloat dt)
-{
- //fprintf(stdout, "CPINITTIME init %f\n",t);
- _currTime = t;
- if(mPartSets.size()<1) return;
-
- // init zero velocities
- initTimeArray(t, _particles);
-
- // calculate velocities from prev. timestep?
- if(dt>0.) {
- _currTimestep = dt;
- std::vector<ControlParticle> prevparts;
- initTimeArray(t-dt, prevparts);
- LbmFloat invdt = 1.0/dt;
- for(size_t j=0; j<_particles.size(); j++) {
- ControlParticle &p = _particles[j];
- ControlParticle &prevp = prevparts[j];
- for(int k=0; k<3; k++) {
- p.pos[k] *= _initPartScale[k];
- p.pos[k] += _initPartOffset[k];
- prevp.pos[k] *= _initLastPartScale[k];
- prevp.pos[k] += _initLastPartOffset[k];
- }
- p.vel = (p.pos - prevp.pos)*invdt;
- }
-
- if(0) {
- LbmVec avgvel(0.);
- for(size_t j=0; j<_particles.size(); j++) {
- avgvel += _particles[j].vel;
- }
- avgvel /= (LbmFloat)_particles.size();
- //fprintf(stdout," AVGVEL %f,%f,%f \n",avgvel[0],avgvel[1],avgvel[2]); // DEBUG
- }
- }
-}
-
-// helper, init given array
-void ControlParticles::initTimeArray(LbmFloat t, std::vector<ControlParticle> &parts) {
- if(mPartSets.size()<1) return;
-
- if(parts.size()!=mPartSets[0].particles.size()) {
- //fprintf(stdout,"PRES \n");
- parts.resize(mPartSets[0].particles.size());
- // TODO reset all?
- for(size_t j=0; j<parts.size(); j++) {
- parts[j].reset();
- }
- }
- if(parts.size()<1) return;
-
- // debug inits
- if(mDebugInit==1) {
- // hard coded circle init
- for(size_t j=0; j<mPartSets[0].particles.size(); j++) {
- ControlParticle p = mPartSets[0].particles[j];
- // remember old
- p.density = parts[j].density;
- p.densityWeight = parts[j].densityWeight;
- p.avgVel = parts[j].avgVel;
- p.avgVelAcc = parts[j].avgVelAcc;
- p.avgVelWeight = parts[j].avgVelWeight;
- LbmVec ppos(0.); { // DEBUG
- const float tscale=10.;
- const float tprevo = 0.33;
- const LbmVec toff(50,50,0);
- const LbmVec oscale(30,30,0);
- ppos[0] = cos(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[0] + toff[0];
- ppos[1] = -sin(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[1] + toff[1];
- ppos[2] = toff[2]; } // DEBUG
- p.pos = ppos;
- parts[j] = p;
- //errMsg("ControlParticle::initTimeArray","j:"<<j<<" p:"<<parts[j].pos );
- }
- return;
- }
- else if(mDebugInit==2) {
- // hard coded spiral init
- const float tscale=-10.;
- const float tprevo = 0.33;
- LbmVec toff(50,0,-50);
- const LbmVec oscale(20,20,0);
- toff[2] += 30. * t +30.;
- for(size_t j=0; j<mPartSets[0].particles.size(); j++) {
- ControlParticle p = mPartSets[0].particles[j];
- // remember old
- p.density = parts[j].density;
- p.densityWeight = parts[j].densityWeight;
- p.avgVel = parts[j].avgVel;
- p.avgVelAcc = parts[j].avgVelAcc;
- p.avgVelWeight = parts[j].avgVelWeight;
- LbmVec ppos(0.);
- ppos[1] = toff[2];
- LbmFloat zscal = (ppos[1]+100.)/200.;
- ppos[0] = cos(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[0]*zscal + toff[0];
- ppos[2] = -sin(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[1]*zscal + toff[1];
- p.pos = ppos;
- parts[j] = p;
-
- toff[2] += 0.25;
- }
- return;
- }
-
- // use first set
- if((t<=mPartSets[0].time)||(mPartSets.size()==1)) {
- //fprintf(stdout,"PINI %f \n", t);
- //parts = mPartSets[0].particles;
- const int i=0;
- for(size_t j=0; j<mPartSets[i].particles.size(); j++) {
- ControlParticle p = mPartSets[i].particles[j];
- // remember old
- p.density = parts[j].density;
- p.densityWeight = parts[j].densityWeight;
- p.avgVel = parts[j].avgVel;
- p.avgVelAcc = parts[j].avgVelAcc;
- p.avgVelWeight = parts[j].avgVelWeight;
- parts[j] = p;
- }
- return;
- }
-
- for(int i=0; i<(int)mPartSets.size()-1; i++) {
- if((mPartSets[i].time<=t) && (mPartSets[i+1].time>t)) {
- LbmFloat d = mPartSets[i+1].time-mPartSets[i].time;
- LbmFloat f = (t-mPartSets[i].time)/d;
- LbmFloat omf = 1.0f - f;
-
- for(size_t j=0; j<mPartSets[i].particles.size(); j++) {
- ControlParticle *src1=&mPartSets[i ].particles[j];
- ControlParticle *src2=&mPartSets[i+1].particles[j];
- ControlParticle &p = parts[j];
- // do linear interpolation
- p.pos = src1->pos * omf + src2->pos *f;
- p.vel = LbmVec(0.); // reset, calculated later on src1->vel * omf + src2->vel *f;
- p.rotaxis = src1->rotaxis * omf + src2->rotaxis *f;
- p.influence = src1->influence * omf + src2->influence *f;
- p.size = src1->size * omf + src2->size *f;
- // dont modify: density, densityWeight
- }
- }
- }
-
- // after last?
- if(t>=mPartSets[ mPartSets.size() -1 ].time) {
- //parts = mPartSets[ mPartSets.size() -1 ].particles;
- const int i= (int)mPartSets.size() -1;
- for(size_t j=0; j<mPartSets[i].particles.size(); j++) {
- ControlParticle p = mPartSets[i].particles[j];
- // restore
- p.density = parts[j].density;
- p.densityWeight = parts[j].densityWeight;
- p.avgVel = parts[j].avgVel;
- p.avgVelAcc = parts[j].avgVelAcc;
- p.avgVelWeight = parts[j].avgVelWeight;
- parts[j] = p;
- }
- }
-}
-
-
-
-
-// --------------------------------------------------------------------------
-
-#define DEBUG_MODVEL 0
-
-// recalculate
-void ControlParticles::calculateKernelWeight() {
- const bool debugKernel = true;
-
- // calculate kernel area with respect to particlesize/cellsize
- LbmFloat kernelw = -1.;
- LbmFloat kernelnorm = -1.;
- LbmFloat krad = (_radiusAtt*0.75); // FIXME use real cone approximation...?
- //krad = (_influenceFalloff*1.);
-#if (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2)
- kernelw = CP_PI*krad*krad;
- kernelnorm = 1.0 / (_fluidSpacing * _fluidSpacing);
-#else // 2D
- kernelw = CP_PI*krad*krad*krad* (4./3.);
- kernelnorm = 1.0 / (_fluidSpacing * _fluidSpacing * _fluidSpacing);
-#endif // MAIN_2D
-
- if(debugKernel) debMsgStd("ControlParticles::calculateKernelWeight",DM_MSG,"kw"<<kernelw<<", norm"<<
- kernelnorm<<", w*n="<<(kernelw*kernelnorm)<<", rad"<<krad<<", sp"<<_fluidSpacing<<" ", 7);
- LbmFloat kernelws = kernelw*kernelnorm;
- _kernelWeight = kernelws;
- if(debugKernel) debMsgStd("ControlParticles::calculateKernelWeight",DM_MSG,"influence f="<<_radiusAtt<<" t="<<
- _influenceTangential<<" a="<<_influenceAttraction<<" v="<<_influenceVelocity<<" kweight="<<_kernelWeight, 7);
- if(_kernelWeight<=0.) {
- errMsg("ControlParticles::calculateKernelWeight", "invalid kernel! "<<_kernelWeight<<", resetting");
- _kernelWeight = 1.;
- }
-}
-
-void
-ControlParticles::prepareControl(LbmFloat simtime, LbmFloat dt, ControlParticles *motion) {
- debMsgStd("ControlParticle::prepareControl",DM_MSG," simtime="<<simtime<<" dt="<<dt<<" ", 5);
-
- //fprintf(stdout,"PREPARE \n");
- LbmFloat avgdw = 0.;
- for(size_t i=0; i<_particles.size(); i++) {
- ControlParticle *cp = &_particles[i];
-
- if(this->getInfluenceAttraction()<0.) {
- cp->density=
- cp->densityWeight = 1.0;
- continue;
- }
-
- // normalize by kernel
- //cp->densityWeight = (1.0 - (cp->density / _kernelWeight)); // store last
-#if (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2)
- cp->densityWeight = (1.0 - (cp->density / (_kernelWeight*cp->size*cp->size) )); // store last
-#else // 2D
- cp->densityWeight = (1.0 - (cp->density / (_kernelWeight*cp->size*cp->size*cp->size) )); // store last
-#endif // MAIN_2D
-
- if(i<10) debMsgStd("ControlParticle::prepareControl",DM_MSG,"kernelDebug i="<<i<<" densWei="<<cp->densityWeight<<" 1/kw"<<(1.0/_kernelWeight)<<" cpdensity="<<cp->density, 9 );
- if(cp->densityWeight<0.) cp->densityWeight=0.;
- if(cp->densityWeight>1.) cp->densityWeight=1.;
-
- avgdw += cp->densityWeight;
- // reset for next step
- cp->density = 0.;
-
- if(cp->avgVelWeight>0.) {
- cp->avgVel = cp->avgVelAcc/cp->avgVelWeight;
- cp->avgVelWeight = 0.;
- cp->avgVelAcc = LbmVec(0.,0.,0.);
- }
- }
- //if(debugKernel) for(size_t i=0; i<_particles.size(); i++) { ControlParticle *cp = &_particles[i]; fprintf(stdout,"A %f,%f \n",cp->density,cp->densityWeight); }
- avgdw /= (LbmFloat)(_particles.size());
- //if(motion) { printf("ControlParticle::kernel: avgdw:%f, kw%f, sp%f \n", avgdw, _kernelWeight, _fluidSpacing); }
-
- //if((simtime>=0.) && (simtime != _currTime))
- initTime(simtime, dt);
-
- if((motion) && (motion->getSize()>0)){
- ControlParticle *motionp = motion->getParticle(0);
- //printf("ControlParticle::prepareControl motion: pos[%f,%f,%f] vel[%f,%f,%f] \n", motionp->pos[0], motionp->pos[1], motionp->pos[2], motionp->vel[0], motionp->vel[1], motionp->vel[2] );
- for(size_t i=0; i<_particles.size(); i++) {
- ControlParticle *cp = &_particles[i];
- cp->pos = cp->pos + motionp->pos;
- cp->vel = cp->vel + motionp->vel;
- cp->size = cp->size * motionp->size;
- cp->influence = cp->size * motionp->influence;
- }
- }
-
- // reset to radiusAtt by default
- if(_radiusVel==0.) _radiusVel = _radiusAtt;
- if(_radiusMinMaxd==0.) _radiusMinMaxd = _radiusAtt;
- if(_radiusMaxd==0.) _radiusMaxd = 2.*_radiusAtt;
- // has to be radiusVel<radiusAtt<radiusMinMaxd<radiusMaxd
- if(_radiusVel>_radiusAtt) _radiusVel = _radiusAtt;
- if(_radiusAtt>_radiusMinMaxd) _radiusAtt = _radiusMinMaxd;
- if(_radiusMinMaxd>_radiusMaxd) _radiusMinMaxd = _radiusMaxd;
-
- //printf("ControlParticle::radii vel:%f att:%f min:%f max:%f \n", _radiusVel,_radiusAtt,_radiusMinMaxd,_radiusMaxd);
- // prepareControl done
-}
-
-void ControlParticles::finishControl(std::vector<ControlForces> &forces, LbmFloat iatt, LbmFloat ivel, LbmFloat imaxd) {
-
- //const LbmFloat iatt = this->getInfluenceAttraction() * this->getCurrTimestep();
- //const LbmFloat ivel = this->getInfluenceVelocity();
- //const LbmFloat imaxd = this->getInfluenceMaxdist() * this->getCurrTimestep();
- // prepare for usage
- iatt *= this->getCurrTimestep();
- ivel *= 1.; // not necessary!
- imaxd *= this->getCurrTimestep();
-
- // skip when size=0
- for(int i=0; i<(int)forces.size(); i++) {
- if(DEBUG_MODVEL) fprintf(stdout, "CPFORGF %d , wf:%f,f:%f,%f,%f , v:%f,%f,%f \n",i, forces[i].weightAtt, forces[i].forceAtt[0],forces[i].forceAtt[1],forces[i].forceAtt[2], forces[i].forceVel[0], forces[i].forceVel[1], forces[i].forceVel[2] );
- LbmFloat cfweight = forces[i].weightAtt; // always normalize
- if((cfweight!=0.)&&(iatt!=0.)) {
- // multiple kernels, normalize - note this does not normalize in d>r/2 region
- if(ABS(cfweight)>1.) { cfweight = 1.0/cfweight; }
- // multiply iatt afterwards to allow stronger force
- cfweight *= iatt;
- forces[i].forceAtt *= cfweight;
- } else {
- forces[i].weightAtt = 0.;
- forces[i].forceAtt = LbmVec(0.);
- }
-
- if( (cfweight==0.) && (imaxd>0.) && (forces[i].maxDistance>0.) ) {
- forces[i].forceMaxd *= imaxd;
- } else {
- forces[i].maxDistance= 0.;
- forces[i].forceMaxd = LbmVec(0.);
- }
-
- LbmFloat cvweight = forces[i].weightVel; // always normalize
- if(cvweight>0.) {
- forces[i].forceVel /= cvweight;
- forces[i].compAv /= cvweight;
- // now modify cvweight, and write back
- // important, cut at 1 - otherwise strong vel. influences...
- if(cvweight>1.) { cvweight = 1.; }
- // thus cvweight is in the range of 0..influenceVelocity, currently not normalized by numCParts
- cvweight *= ivel;
- if(cvweight<0.) cvweight=0.;
- if(cvweight>1.) cvweight=1.;
- // LBM, FIXME todo use relaxation factor
- //pvel = (cvel*0.5 * cvweight) + (pvel * (1.0-cvweight));
- forces[i].weightVel = cvweight;
-
- //errMsg("COMPAV","i"<<i<<" compav"<<forces[i].compAv<<" forcevel"<<forces[i].forceVel<<" ");
- } else {
- forces[i].weightVel = 0.;
- if(forces[i].maxDistance==0.) forces[i].forceVel = LbmVec(0.);
- forces[i].compAvWeight = 0.;
- forces[i].compAv = LbmVec(0.);
- }
- if(DEBUG_MODVEL) fprintf(stdout, "CPFINIF %d , wf:%f,f:%f,%f,%f , v:%f,%f,%f \n",i, forces[i].weightAtt, forces[i].forceAtt[0],forces[i].forceAtt[1],forces[i].forceAtt[2], forces[i].forceVel[0],forces[i].forceVel[1],forces[i].forceVel[2] );
- }
-
- // unused...
- if(DEBUG_MODVEL) fprintf(stdout,"MFC iatt:%f,%f ivel:%f,%f ifmd:%f,%f \n", iatt,_radiusAtt, ivel,_radiusVel, imaxd, _radiusMaxd);
- //for(size_t i=0; i<_particles.size(); i++) { ControlParticle *cp = &_particles[i]; fprintf(stdout," %f,%f,%f ",cp->density,cp->densityWeight, (1.0 - (12.0*cp->densityWeight))); }
- //fprintf(stdout,"\n\nCP DONE \n\n\n");
-}
-
-
-// --------------------------------------------------------------------------
-// calculate forces at given position, and modify velocity
-// according to timestep
-void ControlParticles::calculateCpInfluenceOpt(ControlParticle *cp, LbmVec fluidpos, LbmVec fluidvel, ControlForces *force, LbmFloat fillFactor) {
- // dont reset, only add...
- // test distance, simple squared distance reject
- const LbmFloat cpfo = _radiusAtt*cp->size;
-
- LbmVec posDelta;
- if(DEBUG_MODVEL) fprintf(stdout, "CP at %f,%f,%f bef fw:%f, f:%f,%f,%f , vw:%f, v:%f,%f,%f \n",fluidpos[0],fluidpos[1],fluidpos[2], force->weightAtt, force->forceAtt[0], force->forceAtt[1], force->forceAtt[2], force->weightVel, force->forceVel[0], force->forceVel[1], force->forceVel[2]);
- posDelta = cp->pos - fluidpos;
-#if LBMDIM==2 && (CP_PROJECT2D==1)
- posDelta[2] = 0.; // project to xy plane, z-velocity should already be gone...
-#endif
-
- const LbmFloat distsqr = posDelta[0]*posDelta[0]+posDelta[1]*posDelta[1]+posDelta[2]*posDelta[2];
- if(DEBUG_MODVEL) fprintf(stdout, " Pd at %f,%f,%f d%f \n",posDelta[0],posDelta[1],posDelta[2], distsqr);
- // cut at influence=0.5 , scaling not really makes sense
- if(cpfo*cpfo < distsqr) {
- /*if(cp->influence>0.5) {
- if(force->weightAtt == 0.) {
- if(force->maxDistance*force->maxDistance > distsqr) {
- const LbmFloat dis = sqrtf((float)distsqr);
- const LbmFloat sc = dis-cpfo;
- force->maxDistance = dis;
- force->forceMaxd = (posDelta)*(sc/dis);
- }
- } } */
- return;
- }
- force->weightAtt += 1e-6; // for distance
- force->maxDistance = 0.; // necessary for SPH?
-
- const LbmFloat pdistance = MAGNITUDE(posDelta);
- LbmFloat pdistinv = 0.;
- if(ABS(pdistance)>0.) pdistinv = 1./pdistance;
- posDelta *= pdistinv;
-
- LbmFloat falloffAtt = 0.; //CPKernel::kernel(cpfo * 1.0, pdistance);
- const LbmFloat qac = pdistance / cpfo ;
- if (qac < 1.0){ // return 0.;
- if(qac < 0.5) falloffAtt = 1.0f;
- else falloffAtt = (1.0f - qac) * 2.0f;
- }
-
- // vorticity force:
- // - //LbmVec forceVort;
- // - //CROSS(forceVort, posDelta, cp->rotaxis);
- // - //NORMALIZE(forceVort);
- // - if(falloffAtt>1.0) falloffAtt=1.0;
-
-#if (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2)
- // fillFactor *= 2.0 *0.75 * pdistance; // 2d>3d sampling
-#endif // (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2)
-
- LbmFloat signum = getInfluenceAttraction() > 0.0 ? 1.0 : -1.0;
- cp->density += falloffAtt * fillFactor;
- force->forceAtt += posDelta *cp->densityWeight *cp->influence *signum;
- force->weightAtt += falloffAtt*cp->densityWeight *cp->influence;
-
- LbmFloat falloffVel = 0.; //CPKernel::kernel(cpfo * 1.0, pdistance);
- const LbmFloat cpfv = _radiusVel*cp->size;
- if(cpfv*cpfv < distsqr) { return; }
- const LbmFloat qvc = pdistance / cpfo ;
- //if (qvc < 1.0){
- //if(qvc < 0.5) falloffVel = 1.0f;
- //else falloffVel = (1.0f - qvc) * 2.0f;
- //}
- falloffVel = 1.-qvc;
-
- LbmFloat pvWeight; // = (1.0-cp->densityWeight) * _currTimestep * falloffVel;
- pvWeight = falloffVel *cp->influence; // std, without density influence
- //pvWeight *= (1.0-cp->densityWeight); // use inverse density weight
- //pvWeight *= cp->densityWeight; // test, use density weight
- LbmVec modvel(0.);
- modvel += cp->vel * pvWeight;
- //pvWeight = 1.; modvel = partVel; // DEBUG!?
-
- if(pvWeight>0.) {
- force->forceVel += modvel;
- force->weightVel += pvWeight;
-
- cp->avgVelWeight += falloffVel;
- cp->avgVel += fluidvel;
- }
- if(DEBUG_MODVEL) fprintf(stdout, "CP at %f,%f,%f aft fw:%f, f:%f,%f,%f , vw:%f, v:%f,%f,%f \n",fluidpos[0],fluidpos[1],fluidpos[2], force->weightAtt, force->forceAtt[0], force->forceAtt[1], force->forceAtt[2], force->weightVel, force->forceVel[0], force->forceVel[1], force->forceVel[2]);
- return;
-}
-
-void ControlParticles::calculateMaxdForce(ControlParticle *cp, LbmVec fluidpos, ControlForces *force) {
- if(force->weightAtt != 0.) return; // maxd force off
- if(cp->influence <= 0.5) return; // ignore
-
- LbmVec posDelta;
- //if(DEBUG_MODVEL) fprintf(stdout, "CP at %f,%f,%f bef fw:%f, f:%f,%f,%f , vw:%f, v:%f,%f,%f \n",fluidpos[0],fluidpos[1],fluidpos[2], force->weightAtt, force->forceAtt[0], force->forceAtt[1], force->forceAtt[2], force->weightVel, force->forceVel[0], force->forceVel[1], force->forceVel[2]);
- posDelta = cp->pos - fluidpos;
-#if LBMDIM==2 && (CP_PROJECT2D==1)
- posDelta[2] = 0.; // project to xy plane, z-velocity should already be gone...
-#endif
-
- // dont reset, only add...
- // test distance, simple squared distance reject
- const LbmFloat distsqr = posDelta[0]*posDelta[0]+posDelta[1]*posDelta[1]+posDelta[2]*posDelta[2];
-
- // closer cp found
- if(force->maxDistance*force->maxDistance < distsqr) return;
-
- const LbmFloat dmin = _radiusMinMaxd*cp->size;
- if(distsqr<dmin*dmin) return; // inside min
- const LbmFloat dmax = _radiusMaxd*cp->size;
- if(distsqr>dmax*dmax) return; // outside
-
-
- if(DEBUG_MODVEL) fprintf(stdout, " Pd at %f,%f,%f d%f \n",posDelta[0],posDelta[1],posDelta[2], distsqr);
- // cut at influence=0.5 , scaling not really makes sense
- const LbmFloat dis = sqrtf((float)distsqr);
- //const LbmFloat sc = dis - dmin;
- const LbmFloat sc = (dis-dmin)/(dmax-dmin); // scale from 0-1
- force->maxDistance = dis;
- force->forceMaxd = (posDelta/dis) * sc;
- //debug errMsg("calculateMaxdForce","pos"<<fluidpos<<" dis"<<dis<<" sc"<<sc<<" dmin"<<dmin<<" maxd"<< force->maxDistance <<" fmd"<<force->forceMaxd );
- return;
-}
-
diff --git a/intern/elbeem/intern/controlparticles.h b/intern/elbeem/intern/controlparticles.h
deleted file mode 100644
index 37b694f7cf2..00000000000
--- a/intern/elbeem/intern/controlparticles.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-// --------------------------------------------------------------------------
-//
-// El'Beem - the visual lattice boltzmann freesurface simulator
-// All code distributed as part of El'Beem is covered by the version 2 of the
-// GNU General Public License. See the file COPYING for details.
-//
-// Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede
-//
-// control particle classes
-//
-// --------------------------------------------------------------------------
-
-#ifndef CONTROLPARTICLES_H
-#define CONTROLPARTICLES_H
-
-#include "ntl_geometrymodel.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-// indicator for LBM inclusion
-//#ifndef LBMDIM
-
-//#include <NxFoundation.h>
-//#include <vector>
-//class MultisphGUI;
-//#define NORMALIZE(a) a.normalize()
-//#define MAGNITUDE(a) a.magnitude()
-//#define CROSS(a,b,c) a.cross(b,c)
-//#define ABS(a) (a>0. ? (a) : -(a))
-//#include "cpdefines.h"
-
-//#else // LBMDIM
-
-// use compatibility defines
-//#define NORMALIZE(a) normalize(a)
-//#define MAGNITUDE(a) norm(a)
-//#define CROSS(a,b,c) a=cross(b,c)
-
-//#endif // LBMDIM
-
-#define MAGNITUDE(a) norm(a)
-
-// math.h compatibility
-#define CP_PI ((LbmFloat)3.14159265358979323846)
-
-// project 2d test cases onto plane?
-// if not, 3d distance is used for 2d sim as well
-#define CP_PROJECT2D 1
-
-
-// default init for mincpdist, ControlForces::maxDistance
-#define CPF_MAXDINIT 10000.
-
-// storage of influence for a fluid cell/particle in lbm/sph
-class ControlForces
-{
-public:
- ControlForces() { };
- ~ControlForces() {};
-
- // attraction force
- LbmFloat weightAtt;
- LbmVec forceAtt;
- // velocity influence
- LbmFloat weightVel;
- LbmVec forceVel;
- // maximal distance influence,
- // first is max. distance to first control particle
- // second attraction strength
- LbmFloat maxDistance;
- LbmVec forceMaxd;
-
- LbmFloat compAvWeight;
- LbmVec compAv;
-
- void resetForces() {
- weightAtt = weightVel = 0.;
- maxDistance = CPF_MAXDINIT;
- forceAtt = forceVel = forceMaxd = LbmVec(0.,0.,0.);
- compAvWeight=0.; compAv=LbmVec(0.);
- };
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ControlForces")
-#endif
-};
-
-
-// single control particle
-class ControlParticle
-{
-public:
- ControlParticle() { reset(); };
- ~ControlParticle() {};
-
- // control parameters
-
- // position
- LbmVec pos;
- // size (influences influence radius)
- LbmFloat size;
- // overall strength of influence
- LbmFloat influence;
- // rotation axis
- LbmVec rotaxis;
-
- // computed values
-
- // velocity
- LbmVec vel;
- // computed density
- LbmFloat density;
- LbmFloat densityWeight;
-
- LbmVec avgVel;
- LbmVec avgVelAcc;
- LbmFloat avgVelWeight;
-
- // init all zero / defaults
- void reset();
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ControlParticle")
-#endif
-};
-
-
-// container for a particle configuration at time t
-class ControlParticleSet
-{
-public:
-
- // time of particle set
- LbmFloat time;
- // particle positions
- std::vector<ControlParticle> particles;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ControlParticleSet")
-#endif
-};
-
-
-// container & management of control particles
-class ControlParticles
-{
-public:
- ControlParticles();
- ~ControlParticles();
-
- // reset datastructures for next influence step
- // if motion object is given, particle 1 of second system is used for overall
- // position and speed offset
- void prepareControl(LbmFloat simtime, LbmFloat dt, ControlParticles *motion);
- // post control operations
- void finishControl(std::vector<ControlForces> &forces, LbmFloat iatt, LbmFloat ivel, LbmFloat imaxd);
- // recalculate
- void calculateKernelWeight();
-
- // calculate forces at given position, and modify velocity
- // according to timestep (from initControl)
- void calculateCpInfluenceOpt (ControlParticle *cp, LbmVec fluidpos, LbmVec fluidvel, ControlForces *force, LbmFloat fillFactor);
- void calculateMaxdForce (ControlParticle *cp, LbmVec fluidpos, ControlForces *force);
-
- // no. of particles
- inline int getSize() { return (int)_particles.size(); }
- int getTotalSize();
- // get particle [i]
- inline ControlParticle* getParticle(int i){ return &_particles[i]; }
-
- // set influence parameters
- void setInfluenceTangential(LbmFloat set) { _influenceTangential=set; }
- void setInfluenceAttraction(LbmFloat set) { _influenceAttraction=set; }
- void setInfluenceMaxdist(LbmFloat set) { _influenceMaxdist=set; }
- // calculate for delta t
- void setInfluenceVelocity(LbmFloat set, LbmFloat dt);
- // get influence parameters
- inline LbmFloat getInfluenceAttraction() { return _influenceAttraction; }
- inline LbmFloat getInfluenceTangential() { return _influenceTangential; }
- inline LbmFloat getInfluenceVelocity() { return _influenceVelocity; }
- inline LbmFloat getInfluenceMaxdist() { return _influenceMaxdist; }
- inline LbmFloat getCurrTimestep() { return _currTimestep; }
-
- void setRadiusAtt(LbmFloat set) { _radiusAtt=set; }
- inline LbmFloat getRadiusAtt() { return _radiusAtt; }
- void setRadiusVel(LbmFloat set) { _radiusVel=set; }
- inline LbmFloat getRadiusVel() { return _radiusVel; }
- void setRadiusMaxd(LbmFloat set) { _radiusMaxd=set; }
- inline LbmFloat getRadiusMaxd() { return _radiusMaxd; }
- void setRadiusMinMaxd(LbmFloat set) { _radiusMinMaxd=set; }
- inline LbmFloat getRadiusMinMaxd() { return _radiusMinMaxd; }
-
- LbmFloat getControlTimStart();
- LbmFloat getControlTimEnd();
-
- // set/get characteristic length (and inverse)
- void setCharLength(LbmFloat set) { _charLength=set; _charLengthInv=1./_charLength; }
- inline LbmFloat getCharLength() { return _charLength;}
- inline LbmFloat getCharLengthInv() { return _charLengthInv;}
-
- // set init parameters
- void setInitTimeScale(LbmFloat set) { _initTimeScale = set; };
- void setInitMirror(string set) { _initMirror = set; };
- string getInitMirror() { return _initMirror; };
-
- void setLastOffset(LbmVec set) { _initLastPartOffset = set; };
- void setLastScale(LbmVec set) { _initLastPartScale = set; };
- void setOffset(LbmVec set) { _initPartOffset = set; };
- void setScale(LbmVec set) { _initPartScale = set; };
-
- // set/get cps params
- void setCPSWith(LbmFloat set) { mCPSWidth = set; };
- void setCPSTimestep(LbmFloat set) { mCPSTimestep = set; };
- void setCPSTimeStart(LbmFloat set) { mCPSTimeStart = set; };
- void setCPSTimeEnd(LbmFloat set) { mCPSTimeEnd = set; };
- void setCPSMvmWeightFac(LbmFloat set) { mCPSWeightFac = set; };
-
- LbmFloat getCPSWith() { return mCPSWidth; };
- LbmFloat getCPSTimestep() { return mCPSTimestep; };
- LbmFloat getCPSTimeStart() { return mCPSTimeStart; };
- LbmFloat getCPSTimeEnd() { return mCPSTimeEnd; };
- LbmFloat getCPSMvmWeightFac() { return mCPSWeightFac; };
-
- void setDebugInit(int set) { mDebugInit = set; };
-
- // set init parameters
- void setFluidSpacing(LbmFloat set) { _fluidSpacing = set; };
-
- // load positions & timing from text file
- int initFromTextFile(string filename);
- int initFromTextFileOld(string filename);
- // load positions & timing from gzipped binary file
- int initFromBinaryFile(string filename);
- int initFromMVCMesh(string filename);
- // init an example test case
- int initExampleSet();
-
- // init for a given time
- void initTime(LbmFloat t, LbmFloat dt);
-
- // blender test init
- void initBlenderTest();
-
- int initFromObject(ntlGeometryObjModel *model);
-
-protected:
- // sets influence params
- friend class MultisphGUI;
-
- // tangential and attraction influence
- LbmFloat _influenceTangential, _influenceAttraction;
- // direct velocity influence
- LbmFloat _influenceVelocity;
- // maximal distance influence
- LbmFloat _influenceMaxdist;
-
- // influence radii
- LbmFloat _radiusAtt, _radiusVel, _radiusMinMaxd, _radiusMaxd;
-
- // currently valid time & timestep
- LbmFloat _currTime, _currTimestep;
- // all particles
- std::vector<ControlParticle> _particles;
-
- // particle sets
- std::vector<ControlParticleSet> mPartSets;
-
- // additional parameters for initing particles
- LbmFloat _initTimeScale;
- LbmVec _initPartOffset;
- LbmVec _initPartScale;
- LbmVec _initLastPartOffset;
- LbmVec _initLastPartScale;
- // mirror particles for loading?
- string _initMirror;
-
- // row spacing paramter, e.g. use for approximation of kernel area/volume
- LbmFloat _fluidSpacing;
- // save current kernel weight
- LbmFloat _kernelWeight;
- // charateristic length in world coordinates for normalizatioon of forces
- LbmFloat _charLength, _charLengthInv;
-
-
- /*! do ani mesh CPS */
- void calculateCPS(string filename);
- //! ani mesh cps params
- ntlVec3Gfx mvCPSStart, mvCPSEnd;
- gfxReal mCPSWidth, mCPSTimestep;
- gfxReal mCPSTimeStart, mCPSTimeEnd;
- gfxReal mCPSWeightFac;
-
- int mDebugInit;
-
-
-protected:
- // apply init transformations
- void applyTrafos();
-
- // helper function for init -> swap components everywhere
- void swapCoords(int a,int b);
- // helper function for init -> mirror time
- void mirrorTime();
-
- // helper, init given array
- void initTimeArray(LbmFloat t, std::vector<ControlParticle> &parts);
-
- bool checkPointInside(ntlTree *tree, ntlVec3Gfx org, gfxReal &distance);
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ControlParticles")
-#endif
-};
-
-
-
-#endif
-
diff --git a/intern/elbeem/intern/elbeem.cpp b/intern/elbeem/intern/elbeem.cpp
deleted file mode 100644
index 01e4801fed2..00000000000
--- a/intern/elbeem/intern/elbeem.cpp
+++ /dev/null
@@ -1,430 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Main program functions
- */
-
-#include "elbeem.h"
-#include "ntl_blenderdumper.h"
-extern "C" void elbeemCheckDebugEnv(void);
-
-#include "ntl_world.h"
-#include "ntl_geometrymodel.h"
-
-/*****************************************************************************/
-// region of interest global vars
-// currently used by e.g. fsgr solver
-double guiRoiSX = 0.0;
-double guiRoiSY = 0.0;
-double guiRoiSZ = 0.0;
-double guiRoiEX = 1.0;
-double guiRoiEY = 1.0;
-double guiRoiEZ = 1.0;
-int guiRoiMaxLev=6, guiRoiMinLev=0;
-
-//! global raytracer pointer (=world)
-ntlWorld *gpWorld = NULL;
-
-
-
-// API
-
-// reset elbeemSimulationSettings struct with defaults
-extern "C"
-void elbeemResetSettings(elbeemSimulationSettings *set) {
- if(!set) return;
- set->version = 3;
- set->domainId = 0;
- for(int i=0 ; i<3; i++) set->geoStart[i] = 0.0;
- for(int i=0 ; i<3; i++) set->geoSize[i] = 1.0;
- set->resolutionxyz = 64;
- set->previewresxyz = 24;
- set->realsize = 1.0;
- set->viscosity = 0.000001;
-
- for(int i=0 ; i<2; i++) set->gravity[i] = 0.0;
- set->gravity[2] = -9.81;
-
- set->animStart = 0;
- set->aniFrameTime = 0.01;
- set->noOfFrames = 10;
- set->gstar = 0.005;
- set->maxRefine = -1;
- set->generateParticles = 0.0;
- set->numTracerParticles = 0;
- strcpy(set->outputPath,"./elbeemdata_");
-
- set->channelSizeFrameTime=0;
- set->channelFrameTime=NULL;
- set->channelSizeViscosity=0;
- set->channelViscosity=NULL;
- set->channelSizeGravity=0;
- set->channelGravity=NULL;
-
- set->domainobsType= FLUIDSIM_OBSTACLE_NOSLIP;
- set->domainobsPartslip= 0.;
- set->generateVertexVectors = 0;
- set->surfaceSmoothing = 1.;
- set->surfaceSubdivs = 1;
-
- set->farFieldSize = 0.;
- set->runsimCallback = NULL;
- set->runsimUserData = NULL;
-
- // init identity
- for(int i=0; i<16; i++) set->surfaceTrafo[i] = 0.0;
- for(int i=0; i<4; i++) set->surfaceTrafo[i*4+i] = 1.0;
-}
-
-// start fluidsim init
-extern "C"
-int elbeemInit() {
- setElbeemState( SIMWORLD_INITIALIZING );
- setElbeemErrorString("[none]");
- resetGlobalColorSetting();
-
- elbeemCheckDebugEnv();
- debMsgStd("performElbeemSimulation",DM_NOTIFY,"El'Beem Simulation Init Start as Plugin, debugLevel:"<<gDebugLevel<<" ...\n", 2);
-
- // create world object with initial settings
- ntlBlenderDumper *elbeem = new ntlBlenderDumper();
- gpWorld = elbeem;
- return 0;
-}
-
-// fluidsim end
-extern "C"
-int elbeemFree() {
-
- return 0;
-}
-
-// start fluidsim init
-extern "C"
-int elbeemAddDomain(elbeemSimulationSettings *settings) {
- // has to be inited...
- if((getElbeemState() == SIMWORLD_INVALID) && (!gpWorld)) { elbeemInit(); }
- if(getElbeemState() != SIMWORLD_INITIALIZING) { errFatal("elbeemAddDomain","Unable to init simulation world",SIMWORLD_INITERROR); }
- // create domain with given settings
- gpWorld->addDomain(settings);
- return 0;
-}
-
-// error message access
-extern "C"
-void elbeemGetErrorString(char *buffer) {
- if(!buffer) return;
- strncpy(buffer,getElbeemErrorString(),256);
-}
-
-// reset elbeemMesh struct with zeroes
-extern "C"
-void elbeemResetMesh(elbeemMesh *mesh) {
- if(!mesh) return;
- // init typedef struct elbeemMesh
- mesh->type = 0;
-
- mesh->parentDomainId = 0;
-
- /* vertices */
- mesh->numVertices = 0;
- mesh->vertices = NULL;
-
- mesh->channelSizeVertices = 0;
- mesh->channelVertices = NULL;
-
- /* triangles */
- mesh->numTriangles = 0;
- mesh->triangles = NULL;
-
- /* animation channels */
- mesh->channelSizeTranslation = 0;
- mesh->channelTranslation = NULL;
- mesh->channelSizeRotation = 0;
- mesh->channelRotation = NULL;
- mesh->channelSizeScale = 0;
- mesh->channelScale = NULL;
-
- /* active channel */
- mesh->channelSizeActive = 0;
- mesh->channelActive = NULL;
-
- mesh->channelSizeInitialVel = 0;
- mesh->channelInitialVel = NULL;
-
- mesh->localInivelCoords = 0;
-
- mesh->obstacleType= FLUIDSIM_OBSTACLE_NOSLIP;
- mesh->obstaclePartslip= 0.;
- mesh->obstacleImpactFactor= 1.;
-
- mesh->volumeInitType= OB_VOLUMEINIT_VOLUME;
-
- /* name of the mesh, mostly for debugging */
- mesh->name = "[unnamed]";
-
- /* fluid control settings */
- mesh->cpsTimeStart = 0;
- mesh->cpsTimeEnd = 0;
- mesh->cpsQuality = 0;
-
- mesh->channelSizeAttractforceStrength = 0;
- mesh->channelAttractforceStrength = NULL;
- mesh->channelSizeAttractforceRadius = 0;
- mesh->channelAttractforceRadius = NULL;
- mesh->channelSizeVelocityforceStrength = 0;
- mesh->channelVelocityforceStrength = NULL;
- mesh->channelSizeVelocityforceRadius = 0;
- mesh->channelVelocityforceRadius = NULL;
-}
-
-int globalMeshCounter = 1;
-// add mesh as fluidsim object
-extern "C"
-int elbeemAddMesh(elbeemMesh *mesh) {
- int initType;
- if(getElbeemState() != SIMWORLD_INITIALIZING) { errFatal("elbeemAddMesh","World and domain not initialized, call elbeemInit and elbeemAddDomain before...", SIMWORLD_INITERROR); }
-
- switch(mesh->type) {
- case OB_FLUIDSIM_OBSTACLE:
- if (mesh->obstacleType==FLUIDSIM_OBSTACLE_PARTSLIP) initType = FGI_BNDPART;
- else if(mesh->obstacleType==FLUIDSIM_OBSTACLE_FREESLIP) initType = FGI_BNDFREE;
- else /*if(mesh->obstacleType==FLUIDSIM_OBSTACLE_NOSLIP)*/ initType = FGI_BNDNO;
- break;
- case OB_FLUIDSIM_FLUID: initType = FGI_FLUID; break;
- case OB_FLUIDSIM_INFLOW: initType = FGI_MBNDINFLOW; break;
- case OB_FLUIDSIM_OUTFLOW: initType = FGI_MBNDOUTFLOW; break;
- case OB_FLUIDSIM_CONTROL: initType = FGI_CONTROL; break;
- default: return 1; // invalid type
- }
-
- ntlGeometryObjModel *obj = new ntlGeometryObjModel( );
- gpWorld->getRenderGlobals()->getSimScene()->addGeoClass( obj );
- gpWorld->getRenderGlobals()->getRenderScene()->addGeoClass(obj);
- obj->initModel(
- mesh->numVertices, mesh->vertices, mesh->numTriangles, mesh->triangles,
- mesh->channelSizeVertices, mesh->channelVertices );
- if(mesh->name) obj->setName(string(mesh->name));
- else {
- char meshname[100];
- snprintf(meshname,100,"mesh%04d",globalMeshCounter);
- obj->setName(string(meshname));
- }
- globalMeshCounter++;
- obj->setGeoInitId( mesh->parentDomainId+1 );
- obj->setGeoInitIntersect(true);
- obj->setGeoInitType(initType);
-
- // abuse partslip value for control fluid: reverse control keys or not
- if(initType == FGI_CONTROL)
- obj->setGeoPartSlipValue(mesh->obstacleType);
- else
- obj->setGeoPartSlipValue(mesh->obstaclePartslip);
-
- obj->setGeoImpactFactor(mesh->obstacleImpactFactor);
-
- /* fluid control features */
- obj->setCpsTimeStart(mesh->cpsTimeStart);
- obj->setCpsTimeEnd(mesh->cpsTimeEnd);
- obj->setCpsQuality(mesh->cpsQuality);
-
- if((mesh->volumeInitType<VOLUMEINIT_VOLUME)||(mesh->volumeInitType>VOLUMEINIT_BOTH)) mesh->volumeInitType = VOLUMEINIT_VOLUME;
- obj->setVolumeInit(mesh->volumeInitType);
- // use channel instead, obj->setInitialVelocity( ntlVec3Gfx(mesh->iniVelocity[0], mesh->iniVelocity[1], mesh->iniVelocity[2]) );
-
- obj->initChannels(
- mesh->channelSizeTranslation, mesh->channelTranslation,
- mesh->channelSizeRotation, mesh->channelRotation,
- mesh->channelSizeScale, mesh->channelScale,
- mesh->channelSizeActive, mesh->channelActive,
- mesh->channelSizeInitialVel, mesh->channelInitialVel,
- mesh->channelSizeAttractforceStrength, mesh->channelAttractforceStrength,
- mesh->channelSizeAttractforceRadius, mesh->channelAttractforceRadius,
- mesh->channelSizeVelocityforceStrength, mesh->channelVelocityforceStrength,
- mesh->channelSizeVelocityforceRadius, mesh->channelVelocityforceRadius
- );
- obj->setLocalCoordInivel( mesh->localInivelCoords );
-
- debMsgStd("elbeemAddMesh",DM_MSG,"Added elbeem mesh: "<<obj->getName()<<" type="<<initType<<" "<<obj->getIsAnimated(), 9 );
- return 0;
-}
-
-// do the actual simulation
-extern "C"
-int elbeemSimulate(void) {
- if(!gpWorld) return 1;
-
- gpWorld->finishWorldInit();
- if( isSimworldOk() ) {
- myTime_t timestart = getTime();
- gpWorld->renderAnimation();
- myTime_t timeend = getTime();
-
- if(getElbeemState() != SIMWORLD_STOP) {
- // ok, we're done...
- delete gpWorld;
-
- gpWorld = NULL;
- debMsgStd("elbeemSimulate",DM_NOTIFY, "El'Beem simulation done, time: "<<getTimeString(timeend-timestart)<<".\n", 2 );
- } else {
- debMsgStd("elbeemSimulate",DM_NOTIFY, "El'Beem simulation stopped, time so far: "<<getTimeString(timeend-timestart)<<".", 2 );
- }
- return 0;
- }
-
- // failure...
- return 1;
-}
-
-
-// continue a previously stopped simulation
-extern "C"
-int elbeemContinueSimulation(void) {
-
- if(getElbeemState() != SIMWORLD_STOP) {
- errMsg("elbeemContinueSimulation","No running simulation found! Aborting...");
- if(gpWorld) delete gpWorld;
- return 1;
- }
-
- myTime_t timestart = getTime();
- gpWorld->renderAnimation();
- myTime_t timeend = getTime();
-
- if(getElbeemState() != SIMWORLD_STOP) {
- // ok, we're done...
- delete gpWorld;
- gpWorld = NULL;
- debMsgStd("elbeemContinueSimulation",DM_NOTIFY, "El'Beem simulation done, time: "<<getTimeString(timeend-timestart)<<".\n", 2 );
- } else {
- debMsgStd("elbeemContinueSimulation",DM_NOTIFY, "El'Beem simulation stopped, time so far: "<<getTimeString(timeend-timestart)<<".", 2 );
- }
- return 0;
-}
-
-
-// global vector to flag values to remove
-vector<int> gKeepVal;
-
-#define SIMPLIFY_FLOAT_EPSILON (1e-6f)
-#define SIMPLIFY_DOUBLE_EPSILON (1e-12f)
-#define SFLOATEQ(x,y) (ABS((x)-(y)) < SIMPLIFY_FLOAT_EPSILON)
-#define SDOUBLEEQ(x,y) (ABS((x)-(y)) < SIMPLIFY_DOUBLE_EPSILON)
-#define SVECFLOATEQ(x,y) ( \
- (ABS((x)[0]-(y)[0]) < SIMPLIFY_FLOAT_EPSILON) && \
- (ABS((x)[1]-(y)[1]) < SIMPLIFY_FLOAT_EPSILON) && \
- (ABS((x)[2]-(y)[2]) < SIMPLIFY_FLOAT_EPSILON) )
-
-// helper function - simplify animation channels
-extern "C"
-int elbeemSimplifyChannelFloat(float *channel, int* size) {
- bool changed = false;
- int nsize = *size;
- int orgsize = *size;
- if(orgsize<1) return false;
- gKeepVal.resize( orgsize );
- for(int i=0; i<orgsize; i++) { gKeepVal[i] = true; }
- const bool debugSF = false;
-
- float last = channel[0 + 0];
- for(int i=1; i<orgsize; i++) {
- float curr = channel[2*i + 0];
- bool remove = false;
- if(SFLOATEQ(curr,last)) remove = true;
- // dont remove if next value is different
- if((remove)&&(i<orgsize-1)) {
- float next = channel[2*(i+1)+0];
- if(!SFLOATEQ(next,curr)) remove = false;
- }
- if(remove) {
- changed = true;
- gKeepVal[i] = false;
- nsize--;
- }
- if(debugSF) errMsg("elbeemSimplifyChannelFloat","i"<<i<<"/"<<orgsize<<" v"<<channel[ (i*2) + 0 ]<<" t"<<channel[ (i*2) + 1 ]<<" nsize="<<nsize<<" r"<<remove );
- last = curr;
- }
-
- if(changed) {
- nsize = 1;
- for(int i=1; i<orgsize; i++) {
- if(gKeepVal[i]) {
- channel[ (nsize*2) + 0 ] = channel[ (i*2) + 0 ];
- channel[ (nsize*2) + 1 ] = channel[ (i*2) + 1 ];
- nsize++;
- }
- }
- *size = nsize;
- }
-
- if(debugSF) for(int i=1; i<nsize; i++) {
- errMsg("elbeemSimplifyChannelFloat","n i"<<i<<"/"<<nsize<<" v"<<channel[ (i*2) + 0 ]<<" t"<<channel[ (i*2) + 1 ] );
- }
-
- return changed;
-}
-
-extern "C"
-int elbeemSimplifyChannelVec3(float *channel, int* size) {
- bool changed = false;
- int nsize = *size;
- int orgsize = *size;
- if(orgsize<1) return false;
- gKeepVal.resize( orgsize );
- for(int i=0; i<orgsize; i++) { gKeepVal[i] = true; }
- const bool debugVF = false;
-
- ntlVec3f last( channel[0 + 0], channel[0 + 1], channel[0 + 2] );
- for(int i=1; i<orgsize; i++) {
- ntlVec3f curr( channel[4*i + 0], channel[4*i + 1], channel[4*i + 2]);
- bool remove = false;
- if(SVECFLOATEQ(curr,last)) remove = true;
- // dont remove if next value is different
- if((remove)&&(i<orgsize-1)) {
- ntlVec3f next( channel[4*(i+1)+0], channel[4*(i+1)+1], channel[4*(i+1)+2]);
- if(!SVECFLOATEQ(next,curr)) remove = false;
- }
- if(remove) {
- changed = true;
- gKeepVal[i] = false;
- nsize--;
- }
- if(debugVF) errMsg("elbeemSimplifyChannelVec3","i"<<i<<"/"<<orgsize<<" v"<<
- channel[ (i*4) + 0 ]<<","<< channel[ (i*4) + 1 ]<<","<< channel[ (i*4) + 2 ]<<
- " t"<<channel[ (i*4) + 3 ]<<" nsize="<<nsize<<" r"<<remove );
- last = curr;
- }
-
- if(changed) {
- nsize = 1;
- for(int i=1; i<orgsize; i++) {
- if(gKeepVal[i]) {
- for(int j=0; j<4; j++){ channel[ (nsize*4) + j ] = channel[ (i*4) + j ]; }
- nsize++;
- }
- }
- *size = nsize;
- }
-
- if(debugVF) for(int i=1; i<nsize; i++) {
- errMsg("elbeemSimplifyChannelVec3","n i"<<i<<"/"<<nsize<<" v"<<
- channel[ (i*4) + 0 ]<<","<< channel[ (i*4) + 1 ]<<","<< channel[ (i*4) + 2 ]<<
- " t"<<channel[ (i*4) + 3 ] );
- }
-
- return changed;
-}
-
-
-#undef SIMPLIFY_FLOAT_EPSILON
-#undef SIMPLIFY_DOUBLE_EPSILON
-#undef SFLOATEQ
-#undef SDOUBLEEQ
-
diff --git a/intern/elbeem/intern/elbeem_control.cpp b/intern/elbeem/intern/elbeem_control.cpp
deleted file mode 100644
index d033f535979..00000000000
--- a/intern/elbeem/intern/elbeem_control.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Control API header
- */
-
-#include "elbeem.h"
-#include "elbeem_control.h"
-
-// add mesh as fluidsim object
-int elbeemControlAddSet(struct elbeemControl*) {
-
- return 0;
-}
-
-int elbeemControlComputeMesh(struct elbeemMesh*) {
-
-
- return 0;
-}
-
diff --git a/intern/elbeem/intern/elbeem_control.h b/intern/elbeem/intern/elbeem_control.h
deleted file mode 100644
index f8bb9798fc5..00000000000
--- a/intern/elbeem/intern/elbeem_control.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Control API header
- */
-#ifndef ELBEEMCONTROL_API_H
-#define ELBEEMCONTROL_API_H
-
-// a single control particle set
-typedef struct elbeemControl {
- /* influence forces */
- float influenceAttraction;
- float *channelInfluenceAttraction;
- float channelSizeInfluenceAttraction;
-
- float influenceVelocity;
- float *channelInfluenceVelocity;
- float channelSizeInfluenceVelocity;
-
- float influenceMaxdist;
- float *channelInfluenceMaxdist;
- float channelSizeInfluenceMaxdist;
-
- /* influence force radii */
- float radiusAttraction;
- float *channelRadiusAttraction;
- float channelSizeRadiusAttraction;
-
- float radiusVelocity;
- float *channelRadiusVelocity;
- float channelSizeRadiusVelocity;
-
- float radiusMindist;
- float *channelRadiusMindist;
- float channelSizeRadiusMindist;
- float radiusMaxdist;
- float *channelRadiusMaxdist;
- float channelSizeRadiusMaxdist;
-
- /* control particle positions/scale */
- float offset[3];
- float *channelOffset;
- float channelSizeOffset;
-
- float scale[3];
- float *channelScale;
- float channelSizeScale;
-
-} elbeemControl;
-
-
-// add mesh as fluidsim object
-int elbeemControlAddSet(struct elbeemControl*);
-
-// sample & track mesh control particles, TODO add return type...
-int elbeemControlComputeMesh(struct elbeemMesh*);
-
-#endif // ELBEEMCONTROL_API_H
diff --git a/intern/elbeem/intern/globals.h b/intern/elbeem/intern/globals.h
deleted file mode 100644
index 3e8e2691942..00000000000
--- a/intern/elbeem/intern/globals.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-
-// required globals
-
-extern bool glob_mpactive;
-
-extern int glob_mpnum;
-extern int glob_mpindex;
diff --git a/intern/elbeem/intern/isosurface.cpp b/intern/elbeem/intern/isosurface.cpp
deleted file mode 100644
index b270073a362..00000000000
--- a/intern/elbeem/intern/isosurface.cpp
+++ /dev/null
@@ -1,1122 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Marching Cubes surface mesh generation
- *
- *****************************************************************************/
-
-#include "isosurface.h"
-#include "mcubes_tables.h"
-#include "particletracer.h"
-#include <algorithm>
-#include <stdio.h>
-#include <cmath>
-
-#ifdef sun
-#include "ieeefp.h"
-#endif
-
-// just use default rounding for platforms where its not available
-#ifndef round
-#define round(x) (x)
-#endif
-
-using std::isfinite;
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-IsoSurface::IsoSurface(double iso) :
- ntlGeometryObject(),
- mSizex(-1), mSizey(-1), mSizez(-1),
- mpData(NULL),
- mIsoValue( iso ),
- mPoints(),
- mUseFullEdgeArrays(false),
- mpEdgeVerticesX(NULL), mpEdgeVerticesY(NULL), mpEdgeVerticesZ(NULL),
- mEdgeArSize(-1),
- mIndices(),
-
- mStart(0.0), mEnd(0.0), mDomainExtent(0.0),
- mInitDone(false),
- mSmoothSurface(0.0), mSmoothNormals(0.0),
- mAcrossEdge(), mAdjacentFaces(),
- mCutoff(-1), mCutArray(NULL), // off by default
- mpIsoParts(NULL), mPartSize(0.), mSubdivs(0),
- mFlagCnt(1),
- mSCrad1(0.), mSCrad2(0.), mSCcenter(0.)
-{
-}
-
-
-/******************************************************************************
- * The real init...
- *****************************************************************************/
-void IsoSurface::initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent)
-{
- // range 1-10 (max due to subd array in triangulate)
- if(mSubdivs<1) mSubdivs=1;
- if(mSubdivs>10) mSubdivs=10;
-
- // init solver and size
- mSizex = setx;
- mSizey = sety;
- if(setz == 1) {// 2D, create thin 2D surface
- setz = 5;
- }
- mSizez = setz;
- mDomainExtent = extent;
-
- /* check triangulation size (for raytraing) */
- if( ( mStart[0] >= mEnd[0] ) && ( mStart[1] >= mEnd[1] ) && ( mStart[2] >= mEnd[2] ) ){
- // extent was not set, use normalized one from parametrizer
- mStart = ntlVec3Gfx(0.0) - extent*0.5;
- mEnd = ntlVec3Gfx(0.0) + extent*0.5;
- }
-
- // init
- mIndices.clear();
- mPoints.clear();
-
- int nodes = mSizez*mSizey*mSizex;
- mpData = new float[nodes];
- for(int i=0;i<nodes;i++) { mpData[i] = 0.0; }
-
- // allocate edge arrays (last slices are never used...)
- int initsize = -1;
- if(mUseFullEdgeArrays) {
- mEdgeArSize = nodes;
- mpEdgeVerticesX = new int[nodes];
- mpEdgeVerticesY = new int[nodes];
- mpEdgeVerticesZ = new int[nodes];
- initsize = 3*nodes;
- } else {
- int sliceNodes = 2*mSizex*mSizey*mSubdivs*mSubdivs;
- mEdgeArSize = sliceNodes;
- mpEdgeVerticesX = new int[sliceNodes];
- mpEdgeVerticesY = new int[sliceNodes];
- mpEdgeVerticesZ = new int[sliceNodes];
- initsize = 3*sliceNodes;
- }
- for(int i=0;i<mEdgeArSize;i++) { mpEdgeVerticesX[i] = mpEdgeVerticesY[i] = mpEdgeVerticesZ[i] = -1; }
- // WARNING - make sure this is consistent with calculateMemreqEstimate
-
- // marching cubes are ready
- mInitDone = true;
- debMsgStd("IsoSurface::initializeIsosurface",DM_MSG,"Inited, edgenodes:"<<initsize<<" subdivs:"<<mSubdivs<<" fulledg:"<<mUseFullEdgeArrays , 10);
-}
-
-
-
-/*! Reset all values */
-void IsoSurface::resetAll(gfxReal val) {
- int nodes = mSizez*mSizey*mSizex;
- for(int i=0;i<nodes;i++) { mpData[i] = val; }
-}
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-IsoSurface::~IsoSurface( void )
-{
- if(mpData) delete [] mpData;
- if(mpEdgeVerticesX) delete [] mpEdgeVerticesX;
- if(mpEdgeVerticesY) delete [] mpEdgeVerticesY;
- if(mpEdgeVerticesZ) delete [] mpEdgeVerticesZ;
-}
-
-
-
-
-
-/******************************************************************************
- * triangulate the scalar field given by pointer
- *****************************************************************************/
-void IsoSurface::triangulate( void )
-{
- double gsx,gsy,gsz; // grid spacing in x,y,z direction
- double px,py,pz; // current position in grid in x,y,z direction
- IsoLevelCube cubie; // struct for a small subcube
- myTime_t tritimestart = getTime();
-
- if(!mpData) {
- errFatal("IsoSurface::triangulate","no LBM object, and no scalar field...!",SIMWORLD_INITERROR);
- return;
- }
-
- // get grid spacing (-2 to have same spacing as sim)
- gsx = (mEnd[0]-mStart[0])/(double)(mSizex-2.0);
- gsy = (mEnd[1]-mStart[1])/(double)(mSizey-2.0);
- gsz = (mEnd[2]-mStart[2])/(double)(mSizez-2.0);
-
- // clean up previous frame
- mIndices.clear();
- mPoints.clear();
-
- // reset edge vertices
- for(int i=0;i<mEdgeArSize;i++) {
- mpEdgeVerticesX[i] = -1;
- mpEdgeVerticesY[i] = -1;
- mpEdgeVerticesZ[i] = -1;
- }
-
- ntlVec3Gfx pos[8];
- float value[8];
- int cubeIndex; // index entry of the cube
- int triIndices[12]; // vertex indices
- int *eVert[12];
- IsoLevelVertex ilv;
-
- // edges between which points?
- const int mcEdges[24] = {
- 0,1, 1,2, 2,3, 3,0,
- 4,5, 5,6, 6,7, 7,4,
- 0,4, 1,5, 2,6, 3,7 };
-
- const int cubieOffsetX[8] = {
- 0,1,1,0, 0,1,1,0 };
- const int cubieOffsetY[8] = {
- 0,0,1,1, 0,0,1,1 };
- const int cubieOffsetZ[8] = {
- 0,0,0,0, 1,1,1,1 };
-
- const int coAdd=2;
- // let the cubes march
- if(mSubdivs<=1) {
-
- pz = mStart[2]-gsz*0.5;
- for(int k=1;k<(mSizez-2);k++) {
- pz += gsz;
- py = mStart[1]-gsy*0.5;
- for(int j=1;j<(mSizey-2);j++) {
- py += gsy;
- px = mStart[0]-gsx*0.5;
- for(int i=1;i<(mSizex-2);i++) {
- px += gsx;
-
- value[0] = *getData(i ,j ,k );
- value[1] = *getData(i+1,j ,k );
- value[2] = *getData(i+1,j+1,k );
- value[3] = *getData(i ,j+1,k );
- value[4] = *getData(i ,j ,k+1);
- value[5] = *getData(i+1,j ,k+1);
- value[6] = *getData(i+1,j+1,k+1);
- value[7] = *getData(i ,j+1,k+1);
-
- // check intersections of isosurface with edges, and calculate cubie index
- cubeIndex = 0;
- if (value[0] < mIsoValue) cubeIndex |= 1;
- if (value[1] < mIsoValue) cubeIndex |= 2;
- if (value[2] < mIsoValue) cubeIndex |= 4;
- if (value[3] < mIsoValue) cubeIndex |= 8;
- if (value[4] < mIsoValue) cubeIndex |= 16;
- if (value[5] < mIsoValue) cubeIndex |= 32;
- if (value[6] < mIsoValue) cubeIndex |= 64;
- if (value[7] < mIsoValue) cubeIndex |= 128;
-
- // No triangles to generate?
- if (mcEdgeTable[cubeIndex] == 0) {
- continue;
- }
-
- // where to look up if this point already exists
- int edgek = 0;
- if(mUseFullEdgeArrays) edgek=k;
- const int baseIn = ISOLEVEL_INDEX( i+0, j+0, edgek+0);
- eVert[ 0] = &mpEdgeVerticesX[ baseIn ];
- eVert[ 1] = &mpEdgeVerticesY[ baseIn + 1 ];
- eVert[ 2] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+1, edgek+0) ];
- eVert[ 3] = &mpEdgeVerticesY[ baseIn ];
-
- eVert[ 4] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+0, edgek+1) ];
- eVert[ 5] = &mpEdgeVerticesY[ ISOLEVEL_INDEX( i+1, j+0, edgek+1) ];
- eVert[ 6] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+1, edgek+1) ];
- eVert[ 7] = &mpEdgeVerticesY[ ISOLEVEL_INDEX( i+0, j+0, edgek+1) ];
-
- eVert[ 8] = &mpEdgeVerticesZ[ baseIn ];
- eVert[ 9] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+1, j+0, edgek+0) ];
- eVert[10] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+1, j+1, edgek+0) ];
- eVert[11] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+0, j+1, edgek+0) ];
-
- // grid positions
- pos[0] = ntlVec3Gfx(px ,py ,pz);
- pos[1] = ntlVec3Gfx(px+gsx,py ,pz);
- pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz);
- pos[3] = ntlVec3Gfx(px ,py+gsy,pz);
- pos[4] = ntlVec3Gfx(px ,py ,pz+gsz);
- pos[5] = ntlVec3Gfx(px+gsx,py ,pz+gsz);
- pos[6] = ntlVec3Gfx(px+gsx,py+gsy,pz+gsz);
- pos[7] = ntlVec3Gfx(px ,py+gsy,pz+gsz);
-
- // check all edges
- for(int e=0;e<12;e++) {
- if (mcEdgeTable[cubeIndex] & (1<<e)) {
- // is the vertex already calculated?
- if(*eVert[ e ] < 0) {
- // interpolate edge
- const int e1 = mcEdges[e*2 ];
- const int e2 = mcEdges[e*2+1];
- const ntlVec3Gfx p1 = pos[ e1 ]; // scalar field pos 1
- const ntlVec3Gfx p2 = pos[ e2 ]; // scalar field pos 2
- const float valp1 = value[ e1 ]; // scalar field val 1
- const float valp2 = value[ e2 ]; // scalar field val 2
- const float mu = (mIsoValue - valp1) / (valp2 - valp1);
-
- // init isolevel vertex
- ilv.v = p1 + (p2-p1)*mu;
- ilv.n = getNormal( i+cubieOffsetX[e1], j+cubieOffsetY[e1], k+cubieOffsetZ[e1]) * (1.0-mu) +
- getNormal( i+cubieOffsetX[e2], j+cubieOffsetY[e2], k+cubieOffsetZ[e2]) * ( mu) ;
- mPoints.push_back( ilv );
-
- triIndices[e] = (mPoints.size()-1);
- // store vertex
- *eVert[ e ] = triIndices[e];
- } else {
- // retrieve from vert array
- triIndices[e] = *eVert[ e ];
- }
- } // along all edges
- }
-
- if( (i<coAdd+mCutoff) || (j<coAdd+mCutoff) ||
- ((mCutoff>0) && (k<coAdd)) ||// bottom layer
- (i>mSizex-2-coAdd-mCutoff) ||
- (j>mSizey-2-coAdd-mCutoff) ) {
- if(mCutArray) {
- if(k < mCutArray[j*this->mSizex+i]) continue;
- } else { continue; }
- }
-
- // Create the triangles...
- for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) {
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] );
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] );
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] );
- }
-
- }//i
- }// j
-
- // copy edge arrays
- if(!mUseFullEdgeArrays) {
- for(int j=0;j<(mSizey-0);j++)
- for(int i=0;i<(mSizex-0);i++) {
- //int edgek = 0;
- const int dst = ISOLEVEL_INDEX( i+0, j+0, 0);
- const int src = ISOLEVEL_INDEX( i+0, j+0, 1);
- mpEdgeVerticesX[ dst ] = mpEdgeVerticesX[ src ];
- mpEdgeVerticesY[ dst ] = mpEdgeVerticesY[ src ];
- mpEdgeVerticesZ[ dst ] = mpEdgeVerticesZ[ src ];
- mpEdgeVerticesX[ src ]=-1;
- mpEdgeVerticesY[ src ]=-1;
- mpEdgeVerticesZ[ src ]=-1;
- }
- } // */
-
- } // k
-
- // precalculate normals using an approximation of the scalar field gradient
- for(int ni=0;ni<(int)mPoints.size();ni++) { normalize( mPoints[ni].n ); }
-
- } else { // subdivs
-
-#define EDGEAR_INDEX(Ai,Aj,Ak, Bi,Bj) ((mSizex*mSizey*mSubdivs*mSubdivs*(Ak))+\
- (mSizex*mSubdivs*((Aj)*mSubdivs+(Bj)))+((Ai)*mSubdivs)+(Bi))
-
-#define ISOTRILININT(fi,fj,fk) ( \
- (1.-(fi))*(1.-(fj))*(1.-(fk))*orgval[0] + \
- ( (fi))*(1.-(fj))*(1.-(fk))*orgval[1] + \
- ( (fi))*( (fj))*(1.-(fk))*orgval[2] + \
- (1.-(fi))*( (fj))*(1.-(fk))*orgval[3] + \
- (1.-(fi))*(1.-(fj))*( (fk))*orgval[4] + \
- ( (fi))*(1.-(fj))*( (fk))*orgval[5] + \
- ( (fi))*( (fj))*( (fk))*orgval[6] + \
- (1.-(fi))*( (fj))*( (fk))*orgval[7] )
-
- // use subdivisions
- gfxReal subdfac = 1./(gfxReal)(mSubdivs);
- gfxReal orgGsx = gsx;
- gfxReal orgGsy = gsy;
- gfxReal orgGsz = gsz;
- gsx *= subdfac;
- gsy *= subdfac;
- gsz *= subdfac;
- if(mUseFullEdgeArrays) {
- errMsg("IsoSurface::triangulate","Disabling mUseFullEdgeArrays!");
- }
-
- // subdiv local arrays
- gfxReal orgval[8];
- gfxReal subdAr[2][11][11]; // max 10 subdivs!
- ParticleObject* *arppnt = new ParticleObject*[mSizez*mSizey*mSizex];
-
- // construct pointers
- // part test
- int pInUse = 0;
- int pUsedTest = 0;
- // reset particles
- // reset list array
- for(int k=0;k<(mSizez);k++)
- for(int j=0;j<(mSizey);j++)
- for(int i=0;i<(mSizex);i++) {
- arppnt[ISOLEVEL_INDEX(i,j,k)] = NULL;
- }
- if(mpIsoParts) {
- for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
- pit!= mpIsoParts->getParticlesEnd(); pit++) {
- if( (*pit).getActive()==false ) continue;
- if( (*pit).getType()!=PART_DROP) continue;
- (*pit).setNext(NULL);
- }
- // build per node lists
- for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
- pit!= mpIsoParts->getParticlesEnd(); pit++) {
- if( (*pit).getActive()==false ) continue;
- if( (*pit).getType()!=PART_DROP) continue;
- // check lifetime ignored here
- ParticleObject *p = &(*pit);
- const ntlVec3Gfx ppos = p->getPos();
- const int pi= (int)round(ppos[0])+0;
- const int pj= (int)round(ppos[1])+0;
- int pk= (int)round(ppos[2])+0;// no offset necessary
- // 2d should be handled by solver. if(LBMDIM==2) { pk = 0; }
-
- if(pi<0) continue;
- if(pj<0) continue;
- if(pk<0) continue;
- if(pi>mSizex-1) continue;
- if(pj>mSizey-1) continue;
- if(pk>mSizez-1) continue;
- ParticleObject* &pnt = arppnt[ISOLEVEL_INDEX(pi,pj,pk)];
- if(pnt) {
- // append
- ParticleObject* listpnt = pnt;
- while(listpnt) {
- if(!listpnt->getNext()) {
- listpnt->setNext(p); listpnt = NULL;
- } else {
- listpnt = listpnt->getNext();
- }
- }
- } else {
- // start new list
- pnt = p;
- }
- pInUse++;
- }
- } // mpIsoParts
-
- debMsgStd("IsoSurface::triangulate",DM_MSG,"Starting. Parts in use:"<<pInUse<<", Subdivs:"<<mSubdivs, 9);
- pz = mStart[2]-(double)(0.*gsz)-0.5*orgGsz;
- for(int ok=1;ok<(mSizez-2)*mSubdivs;ok++) {
- pz += gsz;
- const int k = ok/mSubdivs;
- if(k<=0) continue; // skip zero plane
- for(int j=1;j<(mSizey-2);j++) {
- for(int i=1;i<(mSizex-2);i++) {
-
- orgval[0] = *getData(i ,j ,k );
- orgval[1] = *getData(i+1,j ,k );
- orgval[2] = *getData(i+1,j+1,k ); // with subdivs
- orgval[3] = *getData(i ,j+1,k );
- orgval[4] = *getData(i ,j ,k+1);
- orgval[5] = *getData(i+1,j ,k+1);
- orgval[6] = *getData(i+1,j+1,k+1); // with subdivs
- orgval[7] = *getData(i ,j+1,k+1);
-
- // prebuild subsampled array slice
- const int sdkOffset = ok-k*mSubdivs;
- for(int sdk=0; sdk<2; sdk++)
- for(int sdj=0; sdj<mSubdivs+1; sdj++)
- for(int sdi=0; sdi<mSubdivs+1; sdi++) {
- subdAr[sdk][sdj][sdi] = ISOTRILININT(sdi*subdfac, sdj*subdfac, (sdkOffset+sdk)*subdfac);
- }
-
- const int poDistOffset=2;
- for(int pok=-poDistOffset; pok<1+poDistOffset; pok++) {
- if(k+pok<0) continue;
- if(k+pok>=mSizez-1) continue;
- for(int poj=-poDistOffset; poj<1+poDistOffset; poj++) {
- if(j+poj<0) continue;
- if(j+poj>=mSizey-1) continue;
- for(int poi=-poDistOffset; poi<1+poDistOffset; poi++) {
- if(i+poi<0) continue;
- if(i+poi>=mSizex-1) continue;
- ParticleObject *p;
- p = arppnt[ISOLEVEL_INDEX(i+poi,j+poj,k+pok)];
- while(p) { // */
- /*
- for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
- pit!= mpIsoParts->getParticlesEnd(); pit++) { { { {
- // debug test! , full list slow!
- if(( (*pit).getActive()==false ) || ( (*pit).getType()!=PART_DROP)) continue;
- ParticleObject *p;
- p = &(*pit); // */
-
- pUsedTest++;
- ntlVec3Gfx ppos = p->getPos();
- const int spi= (int)round( (ppos[0]+1.-(gfxReal)i) *(gfxReal)mSubdivs-1.5);
- const int spj= (int)round( (ppos[1]+1.-(gfxReal)j) *(gfxReal)mSubdivs-1.5);
- const int spk= (int)round( (ppos[2]+1.-(gfxReal)k) *(gfxReal)mSubdivs-1.5)-sdkOffset; // why -2?
- // 2d should be handled by solver. if(LBMDIM==2) { spk = 0; }
-
- gfxReal pfLen = p->getSize()*1.5*mPartSize; // test, was 1.1
- const gfxReal minPfLen = subdfac*0.8;
- if(pfLen<minPfLen) pfLen = minPfLen;
- //errMsg("ISOPPP"," at "<<PRINT_IJK<<" pp"<<ppos<<" sp"<<PRINT_VEC(spi,spj,spk)<<" pflen"<<pfLen );
- //errMsg("ISOPPP"," subdfac="<<subdfac<<" size"<<p->getSize()<<" ps"<<mPartSize );
- const int icellpsize = (int)(1.*pfLen*(gfxReal)mSubdivs)+1;
- for(int swk=-icellpsize; swk<=icellpsize; swk++) {
- if(spk+swk< 0) { continue; }
- if(spk+swk> 1) { continue; } // */
- for(int swj=-icellpsize; swj<=icellpsize; swj++) {
- if(spj+swj< 0) { continue; }
- if(spj+swj>mSubdivs+0) { continue; } // */
- for(int swi=-icellpsize; swi<=icellpsize; swi++) {
- if(spi+swi< 0) { continue; }
- if(spi+swi>mSubdivs+0) { continue; } // */
- ntlVec3Gfx cellp = ntlVec3Gfx(
- (1.5+(gfxReal)(spi+swi)) *subdfac + (gfxReal)(i-1),
- (1.5+(gfxReal)(spj+swj)) *subdfac + (gfxReal)(j-1),
- (1.5+(gfxReal)(spk+swk)+sdkOffset) *subdfac + (gfxReal)(k-1)
- );
- //if(swi==0 && swj==0 && swk==0) subdAr[spk][spj][spi] = 1.; // DEBUG
- // clip domain boundaries again
- if(cellp[0]<1.) { continue; }
- if(cellp[1]<1.) { continue; }
- if(cellp[2]<1.) { continue; }
- if(cellp[0]>(gfxReal)mSizex-3.) { continue; }
- if(cellp[1]>(gfxReal)mSizey-3.) { continue; }
- if(cellp[2]>(gfxReal)mSizez-3.) { continue; }
- gfxReal len = norm(cellp-ppos);
- gfxReal isoadd = 0.;
- const gfxReal baseIsoVal = mIsoValue*1.1;
- if(len<pfLen) {
- isoadd = baseIsoVal*1.;
- } else {
- // falloff linear with pfLen (kernel size=2pfLen
- isoadd = baseIsoVal*(1. - (len-pfLen)/(pfLen));
- }
- if(isoadd<0.) { continue; }
- //errMsg("ISOPPP"," at "<<PRINT_IJK<<" sp"<<PRINT_VEC(spi+swi,spj+swj,spk+swk)<<" cellp"<<cellp<<" pp"<<ppos << " l"<< len<< " add"<< isoadd);
- const gfxReal arval = subdAr[spk+swk][spj+swj][spi+swi];
- if(arval>1.) { continue; }
- subdAr[spk+swk][spj+swj][spi+swi] = arval + isoadd;
- } } }
-
- p = p->getNext();
- }
- } } } // poDist loops */
-
- py = mStart[1]+(((double)j-0.5)*orgGsy)-gsy;
- for(int sj=0;sj<mSubdivs;sj++) {
- py += gsy;
- px = mStart[0]+(((double)i-0.5)*orgGsx)-gsx;
- for(int si=0;si<mSubdivs;si++) {
- px += gsx;
- value[0] = subdAr[0+0][sj+0][si+0];
- value[1] = subdAr[0+0][sj+0][si+1];
- value[2] = subdAr[0+0][sj+1][si+1];
- value[3] = subdAr[0+0][sj+1][si+0];
- value[4] = subdAr[0+1][sj+0][si+0];
- value[5] = subdAr[0+1][sj+0][si+1];
- value[6] = subdAr[0+1][sj+1][si+1];
- value[7] = subdAr[0+1][sj+1][si+0];
-
- // check intersections of isosurface with edges, and calculate cubie index
- cubeIndex = 0;
- if (value[0] < mIsoValue) cubeIndex |= 1;
- if (value[1] < mIsoValue) cubeIndex |= 2; // with subdivs
- if (value[2] < mIsoValue) cubeIndex |= 4;
- if (value[3] < mIsoValue) cubeIndex |= 8;
- if (value[4] < mIsoValue) cubeIndex |= 16;
- if (value[5] < mIsoValue) cubeIndex |= 32; // with subdivs
- if (value[6] < mIsoValue) cubeIndex |= 64;
- if (value[7] < mIsoValue) cubeIndex |= 128;
-
- if (mcEdgeTable[cubeIndex] > 0) {
-
- // where to look up if this point already exists
- const int edgek = 0;
- const int baseIn = EDGEAR_INDEX( i+0, j+0, edgek+0, si,sj);
- eVert[ 0] = &mpEdgeVerticesX[ baseIn ];
- eVert[ 1] = &mpEdgeVerticesY[ baseIn + 1 ];
- eVert[ 2] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ];
- eVert[ 3] = &mpEdgeVerticesY[ baseIn ];
-
- eVert[ 4] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ];
- eVert[ 5] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+1,sj+0) ]; // with subdivs
- eVert[ 6] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+1) ];
- eVert[ 7] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ];
-
- eVert[ 8] = &mpEdgeVerticesZ[ baseIn ];
- eVert[ 9] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+0) ]; // with subdivs
- eVert[10] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+1) ];
- eVert[11] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ];
-
- // grid positions
- pos[0] = ntlVec3Gfx(px ,py ,pz);
- pos[1] = ntlVec3Gfx(px+gsx,py ,pz);
- pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz); // with subdivs
- pos[3] = ntlVec3Gfx(px ,py+gsy,pz);
- pos[4] = ntlVec3Gfx(px ,py ,pz+gsz);
- pos[5] = ntlVec3Gfx(px+gsx,py ,pz+gsz);
- pos[6] = ntlVec3Gfx(px+gsx,py+gsy,pz+gsz); // with subdivs
- pos[7] = ntlVec3Gfx(px ,py+gsy,pz+gsz);
-
- // check all edges
- for(int e=0;e<12;e++) {
- if (mcEdgeTable[cubeIndex] & (1<<e)) {
- // is the vertex already calculated?
- if(*eVert[ e ] < 0) {
- // interpolate edge
- const int e1 = mcEdges[e*2 ];
- const int e2 = mcEdges[e*2+1];
- const ntlVec3Gfx p1 = pos[ e1 ]; // scalar field pos 1
- const ntlVec3Gfx p2 = pos[ e2 ]; // scalar field pos 2
- const float valp1 = value[ e1 ]; // scalar field val 1
- const float valp2 = value[ e2 ]; // scalar field val 2
- const float mu = (mIsoValue - valp1) / (valp2 - valp1);
-
- // init isolevel vertex
- ilv.v = p1 + (p2-p1)*mu; // with subdivs
- mPoints.push_back( ilv );
- triIndices[e] = (mPoints.size()-1);
- // store vertex
- *eVert[ e ] = triIndices[e];
- } else {
- // retrieve from vert array
- triIndices[e] = *eVert[ e ];
- }
- } // along all edges
- }
- // removed cutoff treatment...
-
- // Create the triangles...
- for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) {
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] );
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] ); // with subdivs
- mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] );
- //errMsg("TTT"," i1"<<mIndices[mIndices.size()-3]<<" "<< " i2"<<mIndices[mIndices.size()-2]<<" "<< " i3"<<mIndices[mIndices.size()-1]<<" "<< mIndices.size() );
- }
-
- } // triangles in edge table?
-
- }//si
- }// sj
-
- }//i
- }// j
-
- // copy edge arrays
- for(int j=0;j<(mSizey-0)*mSubdivs;j++)
- for(int i=0;i<(mSizex-0)*mSubdivs;i++) {
- //int edgek = 0;
- const int dst = EDGEAR_INDEX( 0, 0, 0, i,j);
- const int src = EDGEAR_INDEX( 0, 0, 1, i,j);
- mpEdgeVerticesX[ dst ] = mpEdgeVerticesX[ src ];
- mpEdgeVerticesY[ dst ] = mpEdgeVerticesY[ src ]; // with subdivs
- mpEdgeVerticesZ[ dst ] = mpEdgeVerticesZ[ src ];
- mpEdgeVerticesX[ src ]=-1;
- mpEdgeVerticesY[ src ]=-1; // with subdivs
- mpEdgeVerticesZ[ src ]=-1;
- }
- // */
-
- } // ok, k subdiv loop
-
- //delete [] subdAr;
- delete [] arppnt;
- computeNormals();
- } // with subdivs
-
- // perform smoothing
- float smoSubdfac = 1.;
- if(mSubdivs>0) {
- //smoSubdfac = 1./(float)(mSubdivs);
- smoSubdfac = pow(0.55,(double)mSubdivs); // slightly stronger
- }
- if(mSmoothSurface>0. || mSmoothNormals>0.) debMsgStd("IsoSurface::triangulate",DM_MSG,"Smoothing...",10);
- if(mSmoothSurface>0.0) {
- smoothSurface(mSmoothSurface*smoSubdfac, (mSmoothNormals<=0.0) );
- }
- if(mSmoothNormals>0.0) {
- smoothNormals(mSmoothNormals*smoSubdfac);
- }
-
- myTime_t tritimeend = getTime();
- debMsgStd("IsoSurface::triangulate",DM_MSG,"took "<< getTimeString(tritimeend-tritimestart)<<", S("<<mSmoothSurface<<","<<mSmoothNormals<<"),"<<
- " verts:"<<mPoints.size()<<" tris:"<<(mIndices.size()/3)<<" subdivs:"<<mSubdivs
- , 10 );
- if(mpIsoParts) debMsgStd("IsoSurface::triangulate",DM_MSG,"parts:"<<mpIsoParts->getNumParticles(), 10);
-}
-
-
-
-
-
-/******************************************************************************
- * Get triangles for rendering
- *****************************************************************************/
-void IsoSurface::getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId )
-{
- if(!mInitDone) {
- debugOut("IsoSurface::getTriangles warning: Not initialized! ", 10);
- return;
- }
- t = 0.;
- //return; // DEBUG
-
- /* triangulate field */
- triangulate();
- //errMsg("TRIS"," "<<mIndices.size() );
-
- // new output with vertice reuse
- int iniVertIndex = (*vertices).size();
- int iniNormIndex = (*normals).size();
- if(iniVertIndex != iniNormIndex) {
- errFatal("getTriangles Error","For '"<<mName<<"': Vertices and normal array sizes to not match!!!",SIMWORLD_GENERICERROR);
- return;
- }
- //errMsg("NM"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
- //errMsg("NM"," ovs"<<mVertices.size()<<" ons"<<mVertNormals.size()<<" ots"<<mIndices.size() );
-
- for(int i=0;i<(int)mPoints.size();i++) {
- vertices->push_back( mPoints[i].v );
- }
- for(int i=0;i<(int)mPoints.size();i++) {
- normals->push_back( mPoints[i].n );
- }
-
- //errMsg("N2"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
- //errMsg("N2"," ovs"<<mVertices.size()<<" ons"<<mVertNormals.size()<<" ots"<<mIndices.size() );
-
- for(int i=0;i<(int)mIndices.size();i+=3) {
- const int smooth = 1;
- int t1 = mIndices[i];
- int t2 = mIndices[i+1];
- int t3 = mIndices[i+2];
- //errMsg("NM"," tri"<<t1<<" "<<t2<<" "<<t3 );
-
- ntlTriangle tri;
-
- tri.getPoints()[0] = t1+iniVertIndex;
- tri.getPoints()[1] = t2+iniVertIndex;
- tri.getPoints()[2] = t3+iniVertIndex;
-
- /* init flags */
- int flag = 0;
- if(getVisible()){ flag |= TRI_GEOMETRY; }
- if(getCastShadows() ) {
- flag |= TRI_CASTSHADOWS; }
-
- /* init geo init id */
- int geoiId = getGeoInitId();
- if(geoiId > 0) {
- flag |= (1<< (geoiId+4));
- flag |= mGeoInitType;
- }
-
- tri.setFlags( flag );
-
- /* triangle normal missing */
- tri.setNormal( ntlVec3Gfx(0.0) );
- tri.setSmoothNormals( smooth );
- tri.setObjectId( objectId );
- triangles->push_back( tri );
- }
- //errMsg("N3"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
- return;
-}
-
-
-
-inline ntlVec3Gfx IsoSurface::getNormal(int i, int j,int k) {
- // WARNING - this requires a security boundary layer...
- ntlVec3Gfx ret(0.0);
- ret[0] = *getData(i-1,j ,k ) -
- *getData(i+1,j ,k );
- ret[1] = *getData(i ,j-1,k ) -
- *getData(i ,j+1,k );
- ret[2] = *getData(i ,j ,k-1 ) -
- *getData(i ,j ,k+1 );
- return ret;
-}
-
-
-
-
-/******************************************************************************
- *
- * Surface improvement, inspired by trimesh2 library
- * (http://www.cs.princeton.edu/gfx/proj/trimesh2/)
- *
- *****************************************************************************/
-
-void IsoSurface::setSmoothRad(float radi1, float radi2, ntlVec3Gfx mscc) {
- mSCrad1 = radi1*radi1;
- mSCrad2 = radi2*radi2;
- mSCcenter = mscc;
-}
-
-// compute normals for all generated triangles
-void IsoSurface::computeNormals() {
- for(int i=0;i<(int)mPoints.size();i++) {
- mPoints[i].n = ntlVec3Gfx(0.);
- }
-
- for(int i=0;i<(int)mIndices.size();i+=3) {
- const int t1 = mIndices[i];
- const int t2 = mIndices[i+1];
- const int t3 = mIndices[i+2];
- const ntlVec3Gfx p1 = mPoints[t1].v;
- const ntlVec3Gfx p2 = mPoints[t2].v;
- const ntlVec3Gfx p3 = mPoints[t3].v;
- const ntlVec3Gfx n1=p1-p2;
- const ntlVec3Gfx n2=p2-p3;
- const ntlVec3Gfx n3=p3-p1;
- const gfxReal len1 = normNoSqrt(n1);
- const gfxReal len2 = normNoSqrt(n2);
- const gfxReal len3 = normNoSqrt(n3);
- const ntlVec3Gfx norm = cross(n1,n2);
- mPoints[t1].n += norm * (1./(len1*len3));
- mPoints[t2].n += norm * (1./(len1*len2));
- mPoints[t3].n += norm * (1./(len2*len3));
- }
-
- for(int i=0;i<(int)mPoints.size();i++) {
- normalize(mPoints[i].n);
- }
-}
-
-// Diffuse a vector field at 1 vertex, weighted by
-// a gaussian of width 1/sqrt(invsigma2)
-bool IsoSurface::diffuseVertexField(ntlVec3Gfx *field, const int pointerScale, int src, float invsigma2, ntlVec3Gfx &target)
-{
- if((neighbors[src].size()<1) || (pointareas[src]<=0.0)) return 0;
- const ntlVec3Gfx srcp = mPoints[src].v;
- const ntlVec3Gfx srcn = mPoints[src].n;
- if(mSCrad1>0.0 && mSCrad2>0.0) {
- ntlVec3Gfx dp = mSCcenter-srcp; dp[2] = 0.0; // only xy-plane
- float rd = normNoSqrt(dp);
- if(rd > mSCrad2) {
- return 0;
- } else if(rd > mSCrad1) {
- // optimize?
- float org = 1.0/sqrt(invsigma2);
- org *= (1.0- (rd-mSCrad1) / (mSCrad2-mSCrad1));
- invsigma2 = 1.0/(org*org);
- //errMsg("TRi","p"<<srcp<<" rd:"<<rd<<" r1:"<<mSCrad1<<" r2:"<<mSCrad2<<" org:"<<org<<" is:"<<invsigma2);
- } else {
- }
- }
- target = ntlVec3Gfx(0.0);
- target += *(field+pointerScale*src) *pointareas[src];
- float smstrSum = pointareas[src];
-
- int flag = mFlagCnt;
- mFlagCnt++;
- flags[src] = flag;
- mDboundary = neighbors[src];
- while (!mDboundary.empty()) {
- const int bbn = mDboundary.back();
- mDboundary.pop_back();
- if(flags[bbn]==flag) continue;
- flags[bbn] = flag;
-
- // normal check
- const float nvdot = dot(srcn, mPoints[bbn].n); // faster than before d2 calc?
- if(nvdot <= 0.0f) continue;
-
- // gaussian weight of width 1/sqrt(invsigma2)
- const float d2 = invsigma2 * normNoSqrt(mPoints[bbn].v - srcp);
- if(d2 >= 9.0f) continue;
-
- // aggressive smoothing factor
- float smstr = nvdot * pointareas[bbn];
- // Accumulate weight times field at neighbor
- target += *(field+pointerScale*bbn)*smstr;
- smstrSum += smstr;
-
- for(int i = 0; i < (int)neighbors[bbn].size(); i++) {
- const int nn = neighbors[bbn][i];
- if (flags[nn] == flag) continue;
- mDboundary.push_back(nn);
- }
- }
- target /= smstrSum;
- return 1;
-}
-
-
-// perform smoothing of the surface (and possible normals)
-void IsoSurface::smoothSurface(float sigma, bool normSmooth)
-{
- int nv = mPoints.size();
- if ((int)flags.size() != nv) flags.resize(nv);
- int nf = mIndices.size()/3;
-
- { // need neighbors
- vector<int> numneighbors(mPoints.size());
- int i;
- for (i = 0; i < (int)mIndices.size()/3; i++) {
- numneighbors[mIndices[i*3+0]]++;
- numneighbors[mIndices[i*3+1]]++;
- numneighbors[mIndices[i*3+2]]++;
- }
-
- neighbors.clear();
- neighbors.resize(mPoints.size());
- for (i = 0; i < (int)mPoints.size(); i++) {
- neighbors[i].clear();
- neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries
- }
-
- for (i = 0; i < (int)mIndices.size()/3; i++) {
- for (int j = 0; j < 3; j++) {
- vector<int> &me = neighbors[ mIndices[i*3+j]];
- int n1 = mIndices[i*3+((j+1)%3)];
- int n2 = mIndices[i*3+((j+2)%3)];
- if (std::find(me.begin(), me.end(), n1) == me.end())
- me.push_back(n1);
- if (std::find(me.begin(), me.end(), n2) == me.end())
- me.push_back(n2);
- }
- }
- } // need neighbor
-
- { // need pointarea
- pointareas.clear();
- pointareas.resize(nv);
- cornerareas.clear();
- cornerareas.resize(nf);
-
- for (int i = 0; i < nf; i++) {
- // Edges
- ntlVec3Gfx e[3] = {
- mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v,
- mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v,
- mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v };
-
- // Compute corner weights
- float area = 0.5f * norm( cross(e[0], e[1]));
- float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) };
- float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]),
- l2[1] * (l2[2] + l2[0] - l2[1]),
- l2[2] * (l2[0] + l2[1] - l2[2]) };
- if (ew[0] <= 0.0f) {
- cornerareas[i][1] = -0.25f * l2[2] * area /
- dot(e[0] , e[2]);
- cornerareas[i][2] = -0.25f * l2[1] * area /
- dot(e[0] , e[1]);
- cornerareas[i][0] = area - cornerareas[i][1] -
- cornerareas[i][2];
- } else if (ew[1] <= 0.0f) {
- cornerareas[i][2] = -0.25f * l2[0] * area /
- dot(e[1] , e[0]);
- cornerareas[i][0] = -0.25f * l2[2] * area /
- dot(e[1] , e[2]);
- cornerareas[i][1] = area - cornerareas[i][2] -
- cornerareas[i][0];
- } else if (ew[2] <= 0.0f) {
- cornerareas[i][0] = -0.25f * l2[1] * area /
- dot(e[2] , e[1]);
- cornerareas[i][1] = -0.25f * l2[0] * area /
- dot(e[2] , e[0]);
- cornerareas[i][2] = area - cornerareas[i][0] -
- cornerareas[i][1];
- } else {
- float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]);
- for (int j = 0; j < 3; j++)
- cornerareas[i][j] = ewscale * (ew[(j+1)%3] +
- ew[(j+2)%3]);
- }
-
- // FIX T50887: ensure pointareas are finite
- if (!isfinite(cornerareas[i][0])) cornerareas[i][0] = 1e-6;
- if (!isfinite(cornerareas[i][1])) cornerareas[i][1] = 1e-6;
- if (!isfinite(cornerareas[i][2])) cornerareas[i][2] = 1e-6;
-
- pointareas[mIndices[i*3+0]] += cornerareas[i][0];
- pointareas[mIndices[i*3+1]] += cornerareas[i][1];
- pointareas[mIndices[i*3+2]] += cornerareas[i][2];
- }
-
- } // need pointarea
- // */
-
- float invsigma2 = 1.0f / (sigma*sigma);
-
- vector<ntlVec3Gfx> dflt(nv);
- for (int i = 0; i < nv; i++) {
- if(diffuseVertexField( &mPoints[0].v, 2,
- i, invsigma2, dflt[i])) {
- // Just keep the displacement
- dflt[i] -= mPoints[i].v;
- } else { dflt[i] = 0.0; } //?mPoints[i].v; }
- }
-
- // Slightly better small-neighborhood approximation
- for (int i = 0; i < nf; i++) {
- ntlVec3Gfx c = mPoints[mIndices[i*3+0]].v +
- mPoints[mIndices[i*3+1]].v +
- mPoints[mIndices[i*3+2]].v;
- c /= 3.0f;
- for (int j = 0; j < 3; j++) {
- int v = mIndices[i*3+j];
- ntlVec3Gfx d =(c - mPoints[v].v) * 0.5f;
- dflt[v] += d * (cornerareas[i][j] /
- pointareas[mIndices[i*3+j]] *
- exp(-0.5f * invsigma2 * normNoSqrt(d)) );
- }
- }
-
- // Filter displacement field
- vector<ntlVec3Gfx> dflt2(nv);
- for (int i = 0; i < nv; i++) {
- if(diffuseVertexField( &dflt[0], 1,
- i, invsigma2, dflt2[i])) { }
- else { /*mPoints[i].v=0.0;*/ dflt2[i] = 0.0; }//dflt2[i]; }
- }
-
- // Update vertex positions
- for (int i = 0; i < nv; i++) {
- mPoints[i].v += dflt[i] - dflt2[i]; // second Laplacian
- }
-
- // when normals smoothing off, this cleans up quite well
- // costs ca. 50% additional time though
- float nsFac = 1.5f;
- if(normSmooth) { float ninvsigma2 = 1.0f / (nsFac*nsFac*sigma*sigma);
- for (int i = 0; i < nv; i++) {
- if( diffuseVertexField( &mPoints[0].n, 2, i, ninvsigma2, dflt[i]) ) {
- normalize(dflt[i]);
- } else {
- dflt[i] = mPoints[i].n;
- }
- }
- for (int i = 0; i < nv; i++) {
- mPoints[i].n = dflt[i];
- }
- } // smoothNormals copy */
-
- //errMsg("SMSURF","done v:"<<sigma); // DEBUG
-}
-
-// only smoothen the normals
-void IsoSurface::smoothNormals(float sigma) {
- // reuse from smoothSurface
- if(neighbors.size() != mPoints.size()) {
- // need neighbor
- vector<int> numneighbors(mPoints.size());
- int i;
- for (i = 0; i < (int)mIndices.size()/3; i++) {
- numneighbors[mIndices[i*3+0]]++;
- numneighbors[mIndices[i*3+1]]++;
- numneighbors[mIndices[i*3+2]]++;
- }
-
- neighbors.clear();
- neighbors.resize(mPoints.size());
- for (i = 0; i < (int)mPoints.size(); i++) {
- neighbors[i].clear();
- neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries
- }
-
- for (i = 0; i < (int)mIndices.size()/3; i++) {
- for (int j = 0; j < 3; j++) {
- vector<int> &me = neighbors[ mIndices[i*3+j]];
- int n1 = mIndices[i*3+((j+1)%3)];
- int n2 = mIndices[i*3+((j+2)%3)];
- if (std::find(me.begin(), me.end(), n1) == me.end())
- me.push_back(n1);
- if (std::find(me.begin(), me.end(), n2) == me.end())
- me.push_back(n2);
- }
- }
- } // need neighbor
-
- { // need pointarea
- int nf = mIndices.size()/3, nv = mPoints.size();
- pointareas.clear();
- pointareas.resize(nv);
- cornerareas.clear();
- cornerareas.resize(nf);
-
- for (int i = 0; i < nf; i++) {
- // Edges
- ntlVec3Gfx e[3] = {
- mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v,
- mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v,
- mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v };
-
- // Compute corner weights
- float area = 0.5f * norm( cross(e[0], e[1]));
- float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) };
- float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]),
- l2[1] * (l2[2] + l2[0] - l2[1]),
- l2[2] * (l2[0] + l2[1] - l2[2]) };
- if (ew[0] <= 0.0f) {
- cornerareas[i][1] = -0.25f * l2[2] * area /
- dot(e[0] , e[2]);
- cornerareas[i][2] = -0.25f * l2[1] * area /
- dot(e[0] , e[1]);
- cornerareas[i][0] = area - cornerareas[i][1] -
- cornerareas[i][2];
- } else if (ew[1] <= 0.0f) {
- cornerareas[i][2] = -0.25f * l2[0] * area /
- dot(e[1] , e[0]);
- cornerareas[i][0] = -0.25f * l2[2] * area /
- dot(e[1] , e[2]);
- cornerareas[i][1] = area - cornerareas[i][2] -
- cornerareas[i][0];
- } else if (ew[2] <= 0.0f) {
- cornerareas[i][0] = -0.25f * l2[1] * area /
- dot(e[2] , e[1]);
- cornerareas[i][1] = -0.25f * l2[0] * area /
- dot(e[2] , e[0]);
- cornerareas[i][2] = area - cornerareas[i][0] -
- cornerareas[i][1];
- } else {
- float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]);
- for (int j = 0; j < 3; j++)
- cornerareas[i][j] = ewscale * (ew[(j+1)%3] +
- ew[(j+2)%3]);
- }
-
- // FIX T50887: ensure pointareas are finite
- if (!isfinite(cornerareas[i][0])) cornerareas[i][0] = 1e-6;
- if (!isfinite(cornerareas[i][1])) cornerareas[i][1] = 1e-6;
- if (!isfinite(cornerareas[i][2])) cornerareas[i][2] = 1e-6;
-
- pointareas[mIndices[i*3+0]] += cornerareas[i][0];
- pointareas[mIndices[i*3+1]] += cornerareas[i][1];
- pointareas[mIndices[i*3+2]] += cornerareas[i][2];
- }
-
- } // need pointarea
-
- int nv = mPoints.size();
- if ((int)flags.size() != nv) flags.resize(nv);
- float invsigma2 = 1.0f / (sigma*sigma);
-
- vector<ntlVec3Gfx> nflt(nv);
- for (int i = 0; i < nv; i++) {
- if(diffuseVertexField( &mPoints[0].n, 2, i, invsigma2, nflt[i])) {
- normalize(nflt[i]);
- } else { nflt[i]=mPoints[i].n; }
- }
-
- // copy results
- for (int i = 0; i < nv; i++) { mPoints[i].n = nflt[i]; }
-}
-
-
diff --git a/intern/elbeem/intern/isosurface.h b/intern/elbeem/intern/isosurface.h
deleted file mode 100644
index 10da57ae75e..00000000000
--- a/intern/elbeem/intern/isosurface.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Marching Cubes "displayer"
- *
- *****************************************************************************/
-
-#ifndef ISOSURFACE_H
-
-#include "ntl_geometryobject.h"
-#include "ntl_bsptree.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-#define ISO_STRICT_DEBUG 0
-#define ISOSTRICT_EXIT *((int *)0)=0;
-
-/* access some 3d array */
-#define ISOLEVEL_INDEX(ii,ij,ik) ((mSizex*mSizey*(ik))+(mSizex*(ij))+((ii)))
-
-class ParticleTracer;
-
-/* struct for a small cube in the scalar field */
-typedef struct {
- ntlVec3Gfx pos[8];
- double value[8];
- int i,j,k;
-} IsoLevelCube;
-
-
-typedef struct {
- ntlVec3Gfx v; // vertex
- ntlVec3Gfx n; // vertex normal
-} IsoLevelVertex;
-
-//! class to triangulate a scalar field, e.g. for
-// the fluid surface, templated by scalar field access object
-class IsoSurface :
- public ntlGeometryObject //, public S
-{
-
- public:
-
- /*! Constructor */
- IsoSurface(double iso);
- /*! Destructor */
- virtual ~IsoSurface();
-
- /*! Init ararys etc. */
- virtual void initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent);
-
- /*! Reset all values */
- void resetAll(gfxReal val);
-
- /*! triangulate the scalar field given by pointer*/
- void triangulate( void );
-
- /*! set particle pointer */
- void setParticles(ParticleTracer *pnt,float psize){ mpIsoParts = pnt; mPartSize=psize; };
- /*! set # of subdivisions, this has to be done before init! */
- void setSubdivs(int s) {
- if(mInitDone) errFatal("IsoSurface::setSubdivs","Changing subdivs after init!", SIMWORLD_INITERROR);
- if(s<1) s=1;
- if(s>10) s=10;
- mSubdivs = s;
- }
- int getSubdivs() { return mSubdivs;}
- /*! set full edge settings, this has to be done before init! */
- void setUseFulledgeArrays(bool set) {
- if(mInitDone) errFatal("IsoSurface::setUseFulledgeArrays","Changing usefulledge after init!", SIMWORLD_INITERROR);
- mUseFullEdgeArrays = set;}
-
- protected:
-
- /* variables ... */
-
- //! size
- int mSizex, mSizey, mSizez;
-
- //! data pointer
- float *mpData;
-
- //! Level of the iso surface
- double mIsoValue;
-
- //! Store all the triangles vertices
- vector<IsoLevelVertex> mPoints;
-
- //! use full arrays? (not for farfield)
- bool mUseFullEdgeArrays;
- //! Store indices of calculated points along the cubie edges
- int *mpEdgeVerticesX;
- int *mpEdgeVerticesY;
- int *mpEdgeVerticesZ;
- int mEdgeArSize;
-
-
- //! vector for all the triangles (stored as 3 indices)
- vector<unsigned int> mIndices;
-
- //! start and end vectors for the triangulation region to create triangles in
- ntlVec3Gfx mStart, mEnd;
-
- //! normalized domain extent from parametrizer/visualizer
- ntlVec3Gfx mDomainExtent;
-
- //! initialized?
- bool mInitDone;
-
- //! amount of surface smoothing
- float mSmoothSurface;
- //! amount of normal smoothing
- float mSmoothNormals;
-
- //! grid data
- vector<int> mAcrossEdge;
- vector< vector<int> > mAdjacentFaces;
-
- //! cutoff border area
- int mCutoff;
- //! cutoff heigh values
- int *mCutArray;
- //! particle pointer
- ParticleTracer *mpIsoParts;
- //! particle size
- float mPartSize;
- //! no of subdivisions
- int mSubdivs;
-
- //! trimesh vars
- vector<int> flags;
- int mFlagCnt;
- vector<ntlVec3Gfx> cornerareas;
- vector<float> pointareas;
- vector< vector<int> > neighbors;
-
- public:
- // miscelleanous access functions
-
- //! set geometry start (for renderer)
- void setStart(ntlVec3Gfx set) { mStart = set; };
- ntlVec3Gfx getStart() { return mStart; };
- //! set geometry end (for renderer)
- void setEnd(ntlVec3Gfx set) { mEnd = set; };
- ntlVec3Gfx getEnd() { return mEnd; };
- //! set iso level value for surface reconstruction
- inline void setIsolevel(double set) { mIsoValue = set; };
- //! set loop subdiv num
- inline void setSmoothSurface(float set) { mSmoothSurface = set; };
- inline void setSmoothNormals(float set) { mSmoothNormals = set; };
- inline float getSmoothSurface() { return mSmoothSurface; }
- inline float getSmoothNormals() { return mSmoothNormals; }
-
- // geometry object functions
- virtual void getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId );
-
- //! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB
- virtual inline ntlVec3Gfx *getBBStart() { return &mStart; }
- virtual inline ntlVec3Gfx *getBBEnd() { return &mEnd; }
-
- //! access data array
- inline float* getData(){ return mpData; }
- inline float* getData(int ii, int jj, int kk){
-#if ISO_STRICT_DEBUG==1
- if(ii<0){ errMsg("IsoStrict"," invX- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(jj<0){ errMsg("IsoStrict"," invY- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(kk<0){ errMsg("IsoStrict"," invZ- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(ii>mSizex-1){ errMsg("IsoStrict"," invX+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(jj>mSizey-1){ errMsg("IsoStrict"," invY+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(kk>mSizez-1){ errMsg("IsoStrict"," invZ+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- return mpData + ISOLEVEL_INDEX(ii, jj, kk);
-#else //ISO_STRICT_DEBUG==1
- return mpData + ISOLEVEL_INDEX(ii, jj, kk);
-#endif
- }
- inline float* lbmGetData(int ii, int jj, int kk){
-#if ISO_STRICT_DEBUG==1
- ii++; jj++; kk++;
- if(ii<0){ errMsg("IsoStrict"," invX- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(jj<0){ errMsg("IsoStrict"," invY- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(kk<0){ errMsg("IsoStrict"," invZ- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(ii>mSizex-1){ errMsg("IsoStrict"," invX+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(jj>mSizey-1){ errMsg("IsoStrict"," invY+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- if(kk>mSizez-1){ errMsg("IsoStrict"," invZ+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
- return mpData + ISOLEVEL_INDEX(ii, jj, kk);
-#else //ISO_STRICT_DEBUG==1
- return mpData + ISOLEVEL_INDEX(ii+1,jj+1,kk+1);
-#endif
- }
- //! set cut off border
- inline void setCutoff(int set) { mCutoff = set; };
- //! set cut off border
- inline void setCutArray(int *set) { mCutArray = set; };
-
- //! OpenGL viz "interface"
- unsigned int getIsoVertexCount() {
- return mPoints.size();
- }
- unsigned int getIsoIndexCount() {
- return mIndices.size();
- }
- char* getIsoVertexArray() {
- return (char *) &(mPoints[0]);
- }
- unsigned int *getIsoIndexArray() {
- return &(mIndices[0]);
- }
-
- // surface smoothing functions
- void setSmoothRad(float radi1, float radi2, ntlVec3Gfx mscc);
- void smoothSurface(float val, bool smoothNorm);
- void smoothNormals(float val);
- void computeNormals();
-
- protected:
-
- //! compute normal
- inline ntlVec3Gfx getNormal(int i, int j,int k);
- //! smoothing helper function
- bool diffuseVertexField(ntlVec3Gfx *field, int pointerScale, int v, float invsigma2, ntlVec3Gfx &flt);
- vector<int> mDboundary;
- float mSCrad1, mSCrad2;
- ntlVec3Gfx mSCcenter;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:IsoSurface")
-#endif
-};
-
-
-#define ISOSURFACE_H
-#endif
-
-
diff --git a/intern/elbeem/intern/loop_tools.h b/intern/elbeem/intern/loop_tools.h
deleted file mode 100644
index d1ef03d6667..00000000000
--- a/intern/elbeem/intern/loop_tools.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-
-// advance pointer in main loop
-#define ADVANCE_POINTERS(p) \
- ccel += (QCELLSTEP*(p)); \
- tcel += (QCELLSTEP*(p)); \
- pFlagSrc+= (p); \
- pFlagDst+= (p); \
- i+= (p);
-
-#define MAX_CALC_ARR 4
-
-// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-// init region vars
-#define GRID_REGION_INIT() \
- const int istart = -1+gridLoopBound; \
- const int iend = mLevel[mMaxRefine].lSizex-1-gridLoopBound; \
- LbmFloat calcCurrentMass=0; \
- LbmFloat calcCurrentVolume=0; \
- int calcCellsFilled=0; \
- int calcCellsEmptied=0; \
- int calcNumUsedCells=0; \
- /* This is a generic macro, and now all it's users are using all variables. */ \
- (void)calcCurrentMass; \
- (void)calcCellsFilled \
-
-
-
-
-// -----------------------------------------------------------------------------------
-// serial stuff
-#if PARALLEL!=1
-
-#define PERFORM_USQRMAXCHECK USQRMAXCHECK(usqr,ux,uy,uz, mMaxVlen, mMxvx,mMxvy,mMxvz);
-#define LIST_EMPTY(x) mListEmpty.push_back( x );
-#define LIST_FULL(x) mListFull.push_back( x );
-#define FSGR_ADDPART(x) mpParticles->addFullParticle( x );
-
-// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-#define GRID_REGION_START() \
- { /* main_region */ \
- int kstart=getForZMinBnd(), kend=getForZMaxBnd(mMaxRefine); \
- if(gridLoopBound>0){ kstart=getForZMin1(), kend=getForZMax1(mMaxRefine); } \
- int kdir = 1; \
- int jstart = gridLoopBound; \
- int jend = mLevel[mMaxRefine].lSizey-gridLoopBound; \
- const int id=0; \
- LbmFloat *ccel = NULL, *tcel = NULL; \
- CellFlagType *pFlagSrc=NULL, *pFlagDst=NULL; \
- if(mLevel[mMaxRefine].setCurr==1) { \
- kdir = -1; \
- int temp = kend; \
- kend = kstart-1; \
- kstart = temp-1; \
- temp = id; /* dummy remove warning */ \
- } \
-
-
-
-
-
-// -----------------------------------------------------------------------------------
-#else // PARALLEL==1
-
-//#include "paraloop.h"
-#define PERFORM_USQRMAXCHECK USQRMAXCHECK(usqr,ux,uy,uz, calcMaxVlen, calcMxvx,calcMxvy,calcMxvz);
-#define LIST_EMPTY(x) calcListEmpty.push_back( x );
-#define LIST_FULL(x) calcListFull.push_back( x );
-#define FSGR_ADDPART(x) calcListParts.push_back( x );
-
-
-// parallel region
-//was: # pragma omp parallel default(shared)
-#if COMPRESSGRIDS!=1
- // requires compressed grids...!
- ERROR!
-#endif
-
-// loop start
-#define GRID_REGION_START() \
- { \
- \
- \
- if(mSizez<2) { \
- mPanic = 1; \
- errFatal("ParaLoop::2D","Not valid...!", SIMWORLD_GENERICERROR); \
- } \
- \
- \
- vector<LbmPoint> calcListFull; \
- vector<LbmPoint> calcListEmpty; \
- vector<ParticleObject> calcListParts; \
- LbmFloat calcMxvx, calcMxvy, calcMxvz, calcMaxVlen; \
- calcMxvx = calcMxvy = calcMxvz = calcMaxVlen = 0.0; \
- calcListEmpty.reserve(mListEmpty.capacity() / omp_get_num_threads() ); \
- calcListFull.reserve( mListFull.capacity() / omp_get_num_threads() ); \
- calcListParts.reserve(mSizex); \
- \
- \
- const int id = omp_get_thread_num(); \
- const int Nthrds = omp_get_num_threads(); \
- \
- \
- \
- \
- \
- int kdir = 1; \
- \
- int kstart=getForZMinBnd(), kend=getForZMaxBnd(mMaxRefine); \
- if(gridLoopBound>0){ kstart=getForZMin1(); kend=getForZMax1(mMaxRefine); } \
- LbmFloat *ccel = NULL, *tcel = NULL; \
- CellFlagType *pFlagSrc=NULL, *pFlagDst=NULL; \
- \
- \
- if(mLevel[mMaxRefine].setCurr==1) { \
- kdir = -1; \
- int temp = kend; \
- kend = kstart-1; \
- kstart = temp-1; \
- } \
- \
- const int Nj = mLevel[mMaxRefine].lSizey; \
- int jstart = 0+( (id * Nj ) / Nthrds ); \
- int jend = 0+(((id+1) * Nj ) / Nthrds ); \
- if( ((Nj/Nthrds) *Nthrds) != Nj) { \
- errMsg("LbmFsgrSolver","Invalid domain size Nj="<<Nj<<" Nthrds="<<Nthrds); \
- } \
- \
- if(jstart<gridLoopBound) jstart = gridLoopBound; \
- if(jend>mLevel[mMaxRefine].lSizey-gridLoopBound) jend = mLevel[mMaxRefine].lSizey-gridLoopBound; \
- \
- debMsgStd("ParaLoop::OMP",DM_MSG,"Thread:"<<id<<" i:"<<istart<<"-"<<iend<<" j:"<<jstart<<"-"<<jend<<", k:"<<kstart<<"-"<<kend<<" ", 1); \
- \
-
-
-
-
-// para GRID LOOP END is parainc3
-
-#endif // PARALLEL==1
-
-
-// -----------------------------------------------------------------------------------
-
-// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-#define GRID_LOOP_START() \
- for(int k=kstart;k!=kend;k+=kdir) { \
- pFlagSrc = &RFLAG(lev, istart, jstart, k, SRCS(lev)); \
- pFlagDst = &RFLAG(lev, istart, jstart, k, TSET(lev)); \
- ccel = RACPNT(lev, istart, jstart, k, SRCS(lev)); \
- tcel = RACPNT(lev, istart, jstart, k, TSET(lev)); \
- for(int j=jstart;j!=jend;++j) { \
- /* for(int i=0;i<mLevel[lev].lSizex-2; ) { */ \
- for(int i=istart;i!=iend; ) { \
- ADVANCE_POINTERS(1); \
-
-
-
-
-// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-#define GRID_LOOPREG_END() \
- \
- } /* i */ \
- int i=0; \
- ADVANCE_POINTERS(2*gridLoopBound); \
- } /* j */ \
- /* COMPRESSGRIDS!=1 */ \
- /* int i=0; */ \
- /* ADVANCE_POINTERS(mLevel[lev].lSizex*2); */ \
- } /* all cell loop k,j,i */ \
- if(doReduce) { } /* dummy remove warning */ \
- } /* main_region */ \
- \
-
-
-
-
-// old loop for COMPRESSGRIDS==0
-#define old__GRID_LOOP_START() \
- for(int k=kstart;k<kend;++k) { \
- for(int j=1;j<mLevel[lev].lSizey-1;++j) { \
- for(int i=0;i<mLevel[lev].lSizex-2; ) {
-
-
diff --git a/intern/elbeem/intern/mcubes_tables.h b/intern/elbeem/intern/mcubes_tables.h
deleted file mode 100644
index df83578d176..00000000000
--- a/intern/elbeem/intern/mcubes_tables.h
+++ /dev/null
@@ -1,300 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-
-/* which edges are needed ? */
-/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
-static const short mcEdgeTable[256]={
- 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
- 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
- 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
- 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
- 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
- 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
- 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
- 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
- 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
- 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
- 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
- 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
- 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
- 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
- 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
- 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
- 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
- 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
- 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
- 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
- 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
- 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
- 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
- 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
- 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
- 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
- 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
- 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
- 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
- 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
- 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
- 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };
-
-/* triangles for the 256 intersection possibilities */
-/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
-static const short mcTriTable[256][16] = {
- {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
- {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
- {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
- {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
- {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
- {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
- {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
- {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
- {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
- {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
- {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
- {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
- {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
- {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
- {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
- {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
- {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
- {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
- {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
- {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
- {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
- {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
- {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
- {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
- {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
- {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
- {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
- {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
- {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
- {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
- {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
- {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
- {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
- {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
- {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
- {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
- {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
- {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
- {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
- {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
- {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
- {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
- {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
- {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
- {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
- {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
- {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
- {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
- {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
- {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
- {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
- {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
- {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
- {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
- {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
- {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
- {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
- {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
- {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
- {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
- {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
- {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
- {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
- {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
- {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
- {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
- {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
- {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
- {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
- {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
- {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
- {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
- {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
- {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
- {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
- {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
- {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
- {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
- {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
- {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
- {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
- {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
- {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
- {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
- {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
- {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
- {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
- {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
- {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
- {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
- {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
- {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
- {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
- {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
- {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
- {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
- {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
- {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
- {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
- {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
- {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
- {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
- {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
- {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
- {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
- {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
- {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
- {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
- {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
- {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
- {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
- {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
- {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
- {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
- {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
- {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
- {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
- {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
- {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
- {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
- {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
- {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
- {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
- {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
- {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
- {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
- {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
- {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
- {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
- {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
- {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
- {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
- {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
- {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
- {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
- {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
- {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
- {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
- {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
- {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
- {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
- {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
- {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
- {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
- {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
- {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
- {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
- {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
- {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
- {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
- {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
- {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
- {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
- {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
- {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
- {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
- {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
- {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
- {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
- {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
- {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
- {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
- {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
- {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
- {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
- {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
- {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
- {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
- {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
- {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
- {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
- {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
- {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
- {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
- {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
- {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
- {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
- {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
- {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
- {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
- {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
-};
diff --git a/intern/elbeem/intern/mvmcoords.cpp b/intern/elbeem/intern/mvmcoords.cpp
deleted file mode 100644
index 407a1b426f3..00000000000
--- a/intern/elbeem/intern/mvmcoords.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
-// El'Beem - the visual lattice boltzmann freesurface simulator
-// All code distributed as part of El'Beem is covered by the version 2 of the
-// GNU General Public License. See the file COPYING for details.
-//
-// Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede
-//
- *
- * Mean Value Mesh Coords class
- *
- *****************************************************************************/
-
-#include "mvmcoords.h"
-#include <algorithm>
-#include <cmath>
-
-#if defined(_MSC_VER) && _MSC_VER > 1600
-// std::greater
-#include <functional>
-#endif
-
-
-using std::vector;
-using std::isfinite;
-
-void MeanValueMeshCoords::clear()
-{
- mVertices.resize(0);
- mNumVerts = 0;
-}
-
-void MeanValueMeshCoords::calculateMVMCs(vector<ntlVec3Gfx> &reference_vertices, vector<ntlTriangle> &tris,
- vector<ntlVec3Gfx> &points, gfxReal numweights)
-{
- clear();
- mvmTransferPoint tds;
- int mem = 0;
- int i = 0;
-
- mNumVerts = (int)reference_vertices.size();
-
- for (vector<ntlVec3Gfx>::iterator iter = points.begin(); iter != points.end(); ++iter, ++i) {
- /*
- if(i%(points.size()/10)==1) debMsgStd("MeanValueMeshCoords::calculateMVMCs",DM_MSG,"Computing weights, points: "<<i<<"/"<<points.size(),5 );
- */
- tds.lastpos = *iter;
- tds.weights.resize(0); // clear
- computeWeights(reference_vertices, tris, tds, numweights);
- mem += (int)tds.weights.size();
- mVertices.push_back(tds);
- }
- int mbmem = mem * sizeof(mvmFloat) / (1024*1024);
- debMsgStd("MeanValueMeshCoords::calculateMVMCs",DM_MSG,"vertices:"<<mNumVerts<<" points:"<<points.size()<<" weights:"<<mem<<", wmem:"<<mbmem<<"MB ",7 );
-}
-
-// from: mean value coordinates for closed triangular meshes
-// attention: fails if a point is exactly (or very close) to a vertex
-void MeanValueMeshCoords::computeWeights(vector<ntlVec3Gfx> &reference_vertices, vector<ntlTriangle>& tris,
- mvmTransferPoint& tds, gfxReal numweights)
-{
- const bool mvmFullDebug=false;
- //const ntlVec3Gfx cEPS = 1.0e-6;
- const mvmFloat cEPS = 1.0e-14;
-
- //mvmFloat d[3], s[3], phi[3],c[3];
- ntlVec3d u[3],c,d,s,phi;
- int indices[3];
-
- for (int i = 0; i < (int)reference_vertices.size(); ++i) {
- tds.weights.push_back(mvmIndexWeight(i, 0.0));
- }
-
- // for each triangle
- //for (vector<ntlTriangle>::iterator iter = tris.begin(); iter != tris.end();) {
- for(int t=0; t<(int)tris.size(); t++) {
-
- for (int i = 0; i < 3; ++i) { //, ++iter) {
- indices[i] = tris[t].getPoints()[i];
- u[i] = vec2D(reference_vertices[ indices[i] ]-tds.lastpos);
- d[i] = normalize(u[i]); //.normalize();
- //assert(d[i] != 0.);
- if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","t"<<t<<" i"<<indices[i] //<<" lp"<<tds.lastpos
- <<" v"<<reference_vertices[indices[i]]<<" u"<<u[i]<<" ");
- // on vertex!
- //? if(d[i]<=0.) continue;
- }
- //for (int i = 0; i < 3; ++i) { errMsg("III"," "<<i <<" i"<<indices[i]<<reference_vertices[ indices[i] ] ); }
-
- // arcsin is not needed, see paper
- phi[0] = 2.*asin( (mvmFloat)(0.5* norm(u[1]-u[2]) ) );
- phi[1] = 2.*asin( (mvmFloat)(0.5* norm(u[0]-u[2]) ) );
- phi[2] = 2.*asin( (mvmFloat)(0.5* norm(u[0]-u[1]) ) );
- mvmFloat h = (phi[0] + phi[1] + phi[2])*0.5;
- if (M_PI-h < cEPS) {
- if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","point on triangle");
- tds.weights.resize(0);
- tds.weights.push_back( mvmIndexWeight(indices[0], sin(phi[0])*d[1]*d[2]));
- tds.weights.push_back( mvmIndexWeight(indices[1], sin(phi[1])*d[0]*d[2]));
- tds.weights.push_back( mvmIndexWeight(indices[2], sin(phi[2])*d[1]*d[0]));
- break;
- }
- mvmFloat sinh = 2.*sin(h);
- c[0] = (sinh*sin(h-phi[0]))/(sin(phi[1])*sin(phi[2]))-1.;
- c[1] = (sinh*sin(h-phi[1]))/(sin(phi[0])*sin(phi[2]))-1.;
- c[2] = (sinh*sin(h-phi[2]))/(sin(phi[0])*sin(phi[1]))-1.;
- if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","c="<<c<<" phi="<<phi<<" d="<<d);
- //if (c[0] > 1. || c[0] < 0. || c[1] > 1. || c[1] < 0. || c[2] > 1. || c[2] < 0.) continue;
-
- s[0] = sqrt((float)(1.-c[0]*c[0]));
- s[1] = sqrt((float)(1.-c[1]*c[1]));
- s[2] = sqrt((float)(1.-c[2]*c[2]));
-
- if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","s");
- if (s[0] <= cEPS || s[1] <= cEPS || s[2] <= cEPS) {
- //MSG("position lies outside the triangle on the same plane -> ignore it");
- continue;
- }
- const mvmFloat u0x = u[0][0];
- const mvmFloat u0y = u[0][1];
- const mvmFloat u0z = u[0][2];
- const mvmFloat u1x = u[1][0];
- const mvmFloat u1y = u[1][1];
- const mvmFloat u1z = u[1][2];
- const mvmFloat u2x = u[2][0];
- const mvmFloat u2y = u[2][1];
- const mvmFloat u2z = u[2][2];
- mvmFloat det = u0x*u1y*u2z - u0x*u1z*u2y + u0y*u1z*u2x - u0y*u1x*u2z + u0z*u1x*u2y - u0z*u1y*u2x;
- //assert(det != 0.);
- if (det < 0.) {
- s[0] = -s[0];
- s[1] = -s[1];
- s[2] = -s[2];
- }
-
- tds.weights[indices[0]].weight += (phi[0]-c[1]*phi[2]-c[2]*phi[1])/(d[0]*sin(phi[1])*s[2]);
- tds.weights[indices[1]].weight += (phi[1]-c[2]*phi[0]-c[0]*phi[2])/(d[1]*sin(phi[2])*s[0]);
- tds.weights[indices[2]].weight += (phi[2]-c[0]*phi[1]-c[1]*phi[0])/(d[2]*sin(phi[0])*s[1]);
- if(mvmFullDebug) { errMsg("MeanValueMeshCoords::computeWeights","i"<<indices[0]<<" o"<<tds.weights[indices[0]].weight);
- errMsg("MeanValueMeshCoords::computeWeights","i"<<indices[1]<<" o"<<tds.weights[indices[1]].weight);
- errMsg("MeanValueMeshCoords::computeWeights","i"<<indices[2]<<" o"<<tds.weights[indices[2]].weight);
- errMsg("MeanValueMeshCoords::computeWeights","\n\n\n"); }
- }
-
- //sort weights
- if((numweights>0.)&& (numweights<1.) ) {
- //if( ((int)tds.weights.size() > maxNumWeights) && (maxNumWeights > 0) ) {
- int maxNumWeights = (int)(tds.weights.size()*numweights);
- if(maxNumWeights<=0) maxNumWeights = 1;
- std::sort(tds.weights.begin(), tds.weights.end(), std::greater<mvmIndexWeight>());
- // only use maxNumWeights-th largest weights
- tds.weights.resize(maxNumWeights);
- }
-
- // normalize weights
- mvmFloat totalWeight = 0.;
- for (vector<mvmIndexWeight>::const_iterator witer = tds.weights.begin();
- witer != tds.weights.end(); ++witer) {
- totalWeight += witer->weight;
- }
- mvmFloat invTotalWeight;
- if (totalWeight == 0.) {
- if(mvmFullDebug) errMsg("MeanValueMeshCoords::computeWeights","totalWeight == 0");
- invTotalWeight = 0.0;
- } else {
- invTotalWeight = 1.0/totalWeight;
- }
-
- for (vector<mvmIndexWeight>::iterator viter = tds.weights.begin();
- viter != tds.weights.end(); ++viter) {
- viter->weight *= invTotalWeight;
- //assert(isfinite(viter->weight) != 0);
- if(!isfinite(viter->weight)) viter->weight=0.;
- }
-}
-
-void MeanValueMeshCoords::transfer(vector<ntlVec3Gfx> &vertices, vector<ntlVec3Gfx>& displacements)
-{
- displacements.resize(0);
-
- //debMsgStd("MeanValueMeshCoords::transfer",DM_MSG,"vertices:"<<mNumVerts<<" curr_verts:"<<vertices.size()<<" ",7 );
- if((int)vertices.size() != mNumVerts) {
- errMsg("MeanValueMeshCoords::transfer","Different no of verts: "<<vertices.size()<<" vs "<<mNumVerts);
- return;
- }
-
- for (vector<mvmTransferPoint>::iterator titer = mVertices.begin(); titer != mVertices.end(); ++titer) {
- mvmTransferPoint &tds = *titer;
- ntlVec3Gfx newpos(0.0);
-
- for (vector<mvmIndexWeight>::iterator witer = tds.weights.begin();
- witer != tds.weights.end(); ++witer) {
- newpos += vertices[witer->index] * witer->weight;
- //errMsg("transfer","np"<<newpos<<" v"<<vertices[witer->index]<<" w"<< witer->weight);
- }
-
- displacements.push_back(newpos);
- //displacements.push_back(newpos - tds.lastpos);
- //tds.lastpos = newpos;
- }
-}
-
diff --git a/intern/elbeem/intern/mvmcoords.h b/intern/elbeem/intern/mvmcoords.h
deleted file mode 100644
index d00215ebd0e..00000000000
--- a/intern/elbeem/intern/mvmcoords.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
-// El'Beem - the visual lattice boltzmann freesurface simulator
-// All code distributed as part of El'Beem is covered by the version 2 of the
-// GNU General Public License. See the file COPYING for details.
-//
-// Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede
-//
- *
- * Mean Value Mesh Coords class
- *
- *****************************************************************************/
-
-#ifndef MVMCOORDS_H
-#define MVMCOORDS_H
-
-#include "utilities.h"
-#include "ntl_ray.h"
-#include <vector>
-#define mvmFloat double
-
-#ifdef WIN32
-#include "float.h"
-#define isnan(n) _isnan(n)
-#define finite _finite
-#endif
-
-#ifdef sun
-#include "ieeefp.h"
-#endif
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-// weight and triangle index
-class mvmIndexWeight {
- public:
-
- mvmIndexWeight() : weight(0.0) {}
-
- mvmIndexWeight(int const& i, mvmFloat const& w) :
- weight(w), index(i) {}
-
- // for sorting
- bool operator> (mvmIndexWeight const& w) const { return this->weight > w.weight; }
- bool operator< (mvmIndexWeight const& w) const { return this->weight < w.weight; }
-
- mvmFloat weight;
- int index;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:mvmIndexWeight")
-#endif
-};
-
-// transfer point with weights
-class mvmTransferPoint {
- public:
- //! position of transfer point
- ntlVec3Gfx lastpos;
- //! triangle weights
- std::vector<mvmIndexWeight> weights;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:mvmTransferPoint")
-#endif
-};
-
-
-//! compute mvmcs
-class MeanValueMeshCoords {
-
- public:
-
- MeanValueMeshCoords() {}
- ~MeanValueMeshCoords() {
- clear();
- }
-
- void clear();
-
- void calculateMVMCs(std::vector<ntlVec3Gfx> &reference_vertices,
- std::vector<ntlTriangle> &tris, std::vector<ntlVec3Gfx> &points, gfxReal numweights);
-
- void transfer(std::vector<ntlVec3Gfx> &vertices, std::vector<ntlVec3Gfx>& displacements);
-
- protected:
-
- void computeWeights(std::vector<ntlVec3Gfx> &reference_vertices,
- std::vector<ntlTriangle> &tris, mvmTransferPoint& tds, gfxReal numweights);
-
- std::vector<mvmTransferPoint> mVertices;
- int mNumVerts;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:MeanValueMeshCoords")
-#endif
-};
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_blenderdumper.cpp b/intern/elbeem/intern/ntl_blenderdumper.cpp
deleted file mode 100644
index eca184ae717..00000000000
--- a/intern/elbeem/intern/ntl_blenderdumper.cpp
+++ /dev/null
@@ -1,270 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Replaces std. raytracer, and only dumps time dep. objects to disc
- *
- *****************************************************************************/
-
-#include <fstream>
-#include <sys/types.h>
-
-#include "utilities.h"
-#include "ntl_matrices.h"
-#include "ntl_blenderdumper.h"
-#include "ntl_world.h"
-#include "solver_interface.h"
-#include "globals.h"
-
-#include <zlib.h>
-
-#ifdef LBM_GZIP_OVERRIDE_H
-# include LBM_GZIP_OVERRIDE_H
-#else
-# define LBM_GZIP_OPEN_FN(a, b) gzopen(a, b)
-#endif
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-ntlBlenderDumper::ntlBlenderDumper() : ntlWorld()
-{
- // same as normal constructor here
-}
-ntlBlenderDumper::ntlBlenderDumper(string filename, bool commandlineMode) :
- ntlWorld(filename,commandlineMode)
-{
- // init world
-}
-
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlBlenderDumper::~ntlBlenderDumper()
-{
- debMsgStd("ntlBlenderDumper",DM_NOTIFY, "ntlBlenderDumper done", 10);
-}
-
-/******************************************************************************
- * Only dump time dep. objects to file
- *****************************************************************************/
-int ntlBlenderDumper::renderScene( void )
-{
- char nrStr[5]; /* nr conversion */
- ntlRenderGlobals *glob = mpGlob;
- ntlScene *scene = mpGlob->getSimScene();
- bool debugOut = false;
- bool debugRender = false;
-#if ELBEEM_PLUGIN==1
- debugOut = false;
-#endif // ELBEEM_PLUGIN==1
-
- vector<string> gmName; // gm names
- vector<string> gmMat; // materials for gm
- int numGMs = 0; // no. of .obj models created
-
- if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Dumping geometry data", 1);
- long startTime = getTime();
- snprintf(nrStr, 5, "%04d", glob->getAniCount() );
-
- // local scene vars
- vector<ntlTriangle> Triangles;
- vector<ntlVec3Gfx> Vertices;
- vector<ntlVec3Gfx> VertNormals;
-
- // check geo objects
- int idCnt = 0; // give IDs to objects
- for (vector<ntlGeometryClass*>::iterator iter = scene->getGeoClasses()->begin();
- iter != scene->getGeoClasses()->end(); iter++) {
- if(!(*iter)->getVisible()) continue;
- int tid = (*iter)->getTypeId();
-
- if(tid & GEOCLASSTID_OBJECT) {
- // normal geom. objects -> ignore
- }
- if(tid & GEOCLASSTID_SHADER) {
- ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter); //dynamic_cast<ntlGeometryShader*>(*iter);
- string outname = geoshad->getOutFilename();
- if(outname.length()<1) outname = mpGlob->getOutFilename();
- geoshad->notifyShaderOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname);
-
- for (vector<ntlGeometryObject*>::iterator siter = geoshad->getObjectsBegin();
- siter != geoshad->getObjectsEnd();
- siter++) {
- if(debugOut) debMsgStd("ntlBlenderDumper::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName(), 8);
-
- (*siter)->notifyOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname, this->mSimulationTime);
- bool doDump = false;
- bool isPreview = false;
- // only dump final&preview surface meshes
- if( (*siter)->getName().find( "final" ) != string::npos) {
- doDump = true;
- } else if( (*siter)->getName().find( "preview" ) != string::npos) {
- doDump = true;
- isPreview = true;
- }
- if(!doDump) continue;
-
- // dont quit, some objects need notifyOfDump call
- if((glob_mpactive) && (glob_mpindex>0)) {
- continue; //return 0;
- }
-
- // only dump geo shader objects
- Triangles.clear();
- Vertices.clear();
- VertNormals.clear();
- (*siter)->initialize( mpGlob );
- (*siter)->getTriangles(this->mSimulationTime, &Triangles, &Vertices, &VertNormals, idCnt);
- idCnt ++;
-
- // WARNING - this is dirty, but simobjs are the only geoshaders right now
- SimulationObject *sim = (SimulationObject *)geoshad;
- LbmSolverInterface *lbm = sim->getSolver();
-
-
- // always dump mesh, even empty ones...
-
- // dump to binary file
- std::ostringstream boutfilename("");
- //boutfilename << ecrpath.str() << outname <<"_"<< (*siter)->getName() <<"_" << nrStr << ".obj";
- boutfilename << outname <<"_"<< (*siter)->getName() <<"_" << nrStr;
- if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"B-Dumping: "<< (*siter)->getName()
- <<", triangles:"<<Triangles.size()<<", vertices:"<<Vertices.size()<<
- " to "<<boutfilename.str() , 7);
- gzFile gzf;
-
- // output velocities if desired
- if((!isPreview) && (lbm->getDumpVelocities())) {
- std::ostringstream bvelfilename;
- bvelfilename << boutfilename.str();
- bvelfilename << ".bvel.gz";
- /* wraps gzopen */
- gzf = LBM_GZIP_OPEN_FN(bvelfilename.str().c_str(), "wb9");
- if(gzf) {
- int numVerts;
- if(sizeof(numVerts)!=4) { errMsg("ntlBlenderDumper::renderScene","Invalid int size"); return 1; }
- numVerts = Vertices.size();
- gzwrite(gzf, &numVerts, sizeof(numVerts));
- for(size_t i=0; i<Vertices.size(); i++) {
- // returns smoothed velocity, scaled by frame time
- ntlVec3Gfx v = lbm->getVelocityAt( Vertices[i][0], Vertices[i][1], Vertices[i][2] );
- // translation not necessary, test rotation & scaling?
- for(int j=0; j<3; j++) {
- float vertp = v[j];
- //if(i<20) errMsg("ntlBlenderDumper","DUMP_VEL final "<<i<<" = "<<v);
- gzwrite(gzf, &vertp, sizeof(vertp)); }
- }
- gzclose( gzf );
- }
- }
-
- // compress all bobj's
- boutfilename << ".bobj.gz";
- /* wraps gzopen */
- gzf = LBM_GZIP_OPEN_FN(boutfilename.str().c_str(), "wb1"); // wb9 is slow for large meshes!
- if (!gzf) {
- errMsg("ntlBlenderDumper::renderScene","Unable to open output '" + boutfilename.str() + "' ");
- return 1; }
-
- // dont transform velocity output, this is handled in blender
- // current transform matrix
- ntlMatrix4x4<gfxReal> *trafo;
- trafo = lbm->getDomainTrafo();
- if(trafo) {
- // transform into source space
- for(size_t i=0; i<Vertices.size(); i++) {
- Vertices[i] = (*trafo) * Vertices[i];
- }
- }
- // rotate vertnormals
- ntlMatrix4x4<gfxReal> rottrafo;
- rottrafo.initId();
- if(lbm->getDomainTrafo()) {
- // dont modifiy original!
- rottrafo = *lbm->getDomainTrafo();
- ntlVec3Gfx rTrans,rScale,rRot,rShear;
- rottrafo.decompose(rTrans,rScale,rRot,rShear);
- rottrafo.initRotationXYZ(rRot[0],rRot[1],rRot[2]);
- // only rotate here...
- for(size_t i=0; i<Vertices.size(); i++) {
- VertNormals[i] = rottrafo * VertNormals[i];
- normalize(VertNormals[i]); // remove scaling etc.
- }
- }
-
-
- // write to file
- int numVerts;
- if(sizeof(numVerts)!=4) { errMsg("ntlBlenderDumper::renderScene","Invalid int size"); return 1; }
- numVerts = Vertices.size();
- gzwrite(gzf, &numVerts, sizeof(numVerts));
- for(size_t i=0; i<Vertices.size(); i++) {
- for(int j=0; j<3; j++) {
- float vertp = Vertices[i][j];
- gzwrite(gzf, &vertp, sizeof(vertp)); }
- }
-
- // should be the same as Vertices.size
- if(VertNormals.size() != (size_t)numVerts) {
- errMsg("ntlBlenderDumper::renderScene","Normals have to have same size as vertices!");
- VertNormals.resize( Vertices.size() );
- }
- gzwrite(gzf, &numVerts, sizeof(numVerts));
- for(size_t i=0; i<VertNormals.size(); i++) {
- for(int j=0; j<3; j++) {
- float normp = VertNormals[i][j];
- gzwrite(gzf, &normp, sizeof(normp)); }
- }
-
- int numTris = Triangles.size();
- gzwrite(gzf, &numTris, sizeof(numTris));
- for(size_t i=0; i<Triangles.size(); i++) {
- for(int j=0; j<3; j++) {
- int triIndex = Triangles[i].getPoints()[j];
- gzwrite(gzf, &triIndex, sizeof(triIndex)); }
- }
- gzclose( gzf );
- debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY," Wrote: '"<<boutfilename.str()<<"' ", 2);
- numGMs++;
- }
- }
-
- }
-
- // output ecr config file
- if(numGMs>0) {
- if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Objects dumped: "<<numGMs, 10);
- } else {
- if((glob_mpactive) && (glob_mpindex>0)) {
- // ok, nothing to do anyway...
- } else {
- errFatal("ntlBlenderDumper::renderScene","No objects to dump! Aborting...",SIMWORLD_INITERROR);
- return 1;
- }
- }
-
- // debug timing
- long stopTime = getTime();
- debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Scene #"<<nrStr<<" dump time: "<< getTimeString(stopTime-startTime) <<" ", 10);
-
- // still render for preview...
- if(debugRender) {
- debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Performing preliminary render", 1);
- ntlWorld::renderScene(); }
- else {
- // next frame
- glob->setAniCount( glob->getAniCount() +1 );
- }
-
- return 0;
-}
-
-
-
diff --git a/intern/elbeem/intern/ntl_blenderdumper.h b/intern/elbeem/intern/ntl_blenderdumper.h
deleted file mode 100644
index e3c0e3df12b..00000000000
--- a/intern/elbeem/intern/ntl_blenderdumper.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Replaces std. raytracer, and only dumps time dep. objects to disc, header
- *
- *****************************************************************************/
-#ifndef NTL_BLENDERDUMPER_H
-#include "ntl_world.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlBlenderDumper :
- public ntlWorld
-{
-public:
- /*! Constructor */
- ntlBlenderDumper();
- ntlBlenderDumper(string filename, bool commandlineMode);
- /*! Destructor */
- virtual ~ntlBlenderDumper( void );
-
- /*! render scene (a single pictures) */
- virtual int renderScene( void );
-
-protected:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlBlenderDumper")
-#endif
-};
-
-#define NTL_BLENDERDUMPER_H
-#endif
-
diff --git a/intern/elbeem/intern/ntl_bsptree.cpp b/intern/elbeem/intern/ntl_bsptree.cpp
deleted file mode 100644
index 8d589e50cb4..00000000000
--- a/intern/elbeem/intern/ntl_bsptree.cpp
+++ /dev/null
@@ -1,945 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Tree container for fast triangle intersects
- *
- *****************************************************************************/
-
-
-#include "ntl_bsptree.h"
-#include "utilities.h"
-
-#include <algorithm>
-
-/*! Static global variable for sorting direction */
-int globalSortingAxis;
-/*! Access to points array for sorting */
-vector<ntlVec3Gfx> *globalSortingPoints;
-
-#define TREE_DOUBLEI 300
-
-/* try axis selection? */
-bool chooseAxis = 0;
-/* do median search? */
-int doSort = 0;
-
-
-//! struct for a single node in the bsp tree
-class BSPNode {
- public:
- BSPNode() {};
-
- ntlVec3Gfx min,max; /* AABB for node */
- vector<ntlTriangle *> *members; /* stored triangles */
- BSPNode *child[2]; /* pointer to children nodes */
- char axis; /* division axis */
- char cloneVec; /* is this vector a clone? */
-
- //! check if node is a leaf
- inline bool isLeaf() const {
- return (child[0] == NULL);
- }
-};
-
-
-//! an element node stack
-class BSPStackElement {
- public:
- //! tree node
- BSPNode *node;
- //! min and maximum distance along axis
- gfxReal mindist, maxdist;
-};
-
-//! bsp tree stack
-class BSPStack {
- public:
- //! current stack element
- int stackPtr;
- //! stack storage
- BSPStackElement elem[ BSP_STACK_SIZE ];
-};
-
-//! triangle bounding box for quick tree subdivision
-class TriangleBBox {
- public:
- //! start and end of triangle bounding box
- ntlVec3Gfx start, end;
-};
-
-
-/******************************************************************************
- * calculate tree statistics
- *****************************************************************************/
-void calcStats(BSPNode *node, int depth, int &noLeafs, gfxReal &avgDepth, gfxReal &triPerLeaf,int &totalTris)
-{
- if(node->members != NULL) {
- totalTris += node->members->size();
- }
- //depth = 15; // DBEUG!
-
- if( (node->child[0]==NULL) && (node->child[1]==NULL) ) {
- // leaf
- noLeafs++;
- avgDepth += depth;
- triPerLeaf += node->members->size();
- } else {
- for(int i=0;i<2;i++)
- calcStats(node->child[i], depth+1, noLeafs, avgDepth, triPerLeaf, totalTris);
- }
-}
-
-
-
-/******************************************************************************
- * triangle comparison function for median search
- *****************************************************************************/
-bool lessTriangleAverage(const ntlTriangle *x, const ntlTriangle *y)
-{
- return x->getAverage(globalSortingAxis) < y->getAverage(globalSortingAxis);
-}
-
-
-/******************************************************************************
- * triangle AABB intersection
- *****************************************************************************/
-bool ntlTree::checkAABBTriangle(ntlVec3Gfx &min, ntlVec3Gfx &max, ntlTriangle *tri)
-{
- // test only BB of triangle
- TriangleBBox *bbox = &mpTBB[ tri->getBBoxId() ];
- if( bbox->end[0] < min[0] ) return false;
- if( bbox->start[0] > max[0] ) return false;
- if( bbox->end[1] < min[1] ) return false;
- if( bbox->start[1] > max[1] ) return false;
- if( bbox->end[2] < min[2] ) return false;
- if( bbox->start[2] > max[2] ) return false;
- return true;
-}
-
-
-
-
-
-
-
-/******************************************************************************
- * Default constructor
- *****************************************************************************/
-ntlTree::ntlTree() :
- mStart(0.0), mEnd(0.0), mMaxDepth( 5 ), mMaxListLength( 5 ), mpRoot( NULL) ,
- mpNodeStack( NULL), mpVertices( NULL ), mpVertNormals( NULL ), mpTriangles( NULL ),
- mCurrentDepth(0), mCurrentNodes(0), mTriDoubles(0)
-{
- errFatal( "ntlTree","Uninitialized BSP Tree!\n",SIMWORLD_INITERROR );
- return;
-}
-
-
-/******************************************************************************
- * Constructor with init
- *****************************************************************************/
-//ntlTree::ntlTree(int depth, int objnum, vector<ntlVec3Gfx> *vertices, vector<ntlVec3Gfx> *normals, vector<ntlTriangle> *trilist) :
-ntlTree::ntlTree(int depth, int objnum, ntlScene *scene, int triFlagMask) :
- mStart(0.0), mEnd(0.0), mMaxDepth( depth ), mMaxListLength( objnum ), mpRoot( NULL) ,
- mpNodeStack( NULL), mpTBB( NULL ),
- mTriangleMask( 0xFFFF ),
- mCurrentDepth(0), mCurrentNodes(0), mTriDoubles(0)
-{
- // init scene data pointers
- mpVertices = scene->getVertexPointer();
- mpVertNormals = scene->getVertexNormalPointer();
- mpTriangles = scene->getTrianglePointer();
- mTriangleMask = triFlagMask;
-
- if(mpTriangles == NULL) {
- errFatal( "ntlTree Cons","no triangle list!\n",SIMWORLD_INITERROR);
- return;
- }
- if(mpTriangles->size() == 0) {
- warnMsg( "ntlTree::ntlTree","No triangles ("<< mpTriangles->size() <<")!\n");
- mStart = mEnd = ntlVec3Gfx(0,0,0);
- return;
- }
- if(depth>=BSP_STACK_SIZE) {
- errFatal( "ntlTree::ntlTree","Depth to high ("<< mMaxDepth <<")!\n", SIMWORLD_INITERROR );
- return;
- }
-
- /* check triangles (a bit inefficient, but we dont know which vertices belong
- to this tree), and generate bounding boxes */
- mppTriangles = new vector<ntlTriangle *>;
- int noOfTriangles = mpTriangles->size();
- mpTBB = new TriangleBBox[ noOfTriangles ];
- int bbCount = 0;
- mStart = mEnd = (*mpVertices)[ mpTriangles->front().getPoints()[0] ];
- //errMsg("TreeDebug","Start");
- for (vector<ntlTriangle>::iterator iter = mpTriangles->begin();
- iter != mpTriangles->end();
- iter++ ) {
- //errorOut(" d "<< convertFlags2String((int)(*iter).getFlags()) <<" "<< convertFlags2String( (int)mTriangleMask)<<" add? "<<( ((int)(*iter).getFlags() & (int)mTriangleMask) != 0 ) );
- // discard triangles that dont match mask
- if( ((int)(*iter).getFlags() & (int)mTriangleMask) == 0 ) {
- continue;
- }
-
- // test? TODO
- ntlVec3Gfx tnormal = (*mpVertNormals)[ (*iter).getPoints()[0] ]+
- (*mpVertNormals)[ (*iter).getPoints()[1] ]+
- (*mpVertNormals)[ (*iter).getPoints()[2] ];
- ntlVec3Gfx triangleNormal = (*iter).getNormal();
- if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) continue;
- if( equal( tnormal, ntlVec3Gfx(0.0)) ) continue;
- // */
-
- ntlVec3Gfx bbs, bbe;
- //errMsg("TreeDebug","Triangle");
- for(int i=0;i<3;i++) {
- int index = (*iter).getPoints()[i];
- ntlVec3Gfx tp = (*mpVertices)[ index ];
- //errMsg("TreeDebug"," Point "<<i<<" = "<<tp<<" ");
- if(tp[0] < mStart[0]) mStart[0]= tp[0];
- if(tp[0] > mEnd[0]) mEnd[0]= tp[0];
- if(tp[1] < mStart[1]) mStart[1]= tp[1];
- if(tp[1] > mEnd[1]) mEnd[1]= tp[1];
- if(tp[2] < mStart[2]) mStart[2]= tp[2];
- if(tp[2] > mEnd[2]) mEnd[2]= tp[2];
- if(i==0) {
- bbs = bbe = tp;
- } else {
- if( tp[0] < bbs[0] ) bbs[0] = tp[0];
- if( tp[0] > bbe[0] ) bbe[0] = tp[0];
- if( tp[1] < bbs[1] ) bbs[1] = tp[1];
- if( tp[1] > bbe[1] ) bbe[1] = tp[1];
- if( tp[2] < bbs[2] ) bbs[2] = tp[2];
- if( tp[2] > bbe[2] ) bbe[2] = tp[2];
- }
- }
- mppTriangles->push_back( &(*iter) );
- //errMsg("TreeDebug","Triangle "<<(*mpVertices)[(*iter).getPoints()[0]]<<" "<<(*mpVertices)[(*iter).getPoints()[1]]<<" "<<(*mpVertices)[(*iter).getPoints()[2]]<<" ");
-
- // add BB
- mpTBB[ bbCount ].start = bbs;
- mpTBB[ bbCount ].end = bbe;
- (*iter).setBBoxId( bbCount );
- bbCount++;
- }
-
-
-
- /* slighlty enlarge bounding tolerance for tree
- to avoid problems with triangles paralell to slabs */
- mStart -= ntlVec3Gfx( getVecEpsilon() );
- mEnd += ntlVec3Gfx( getVecEpsilon() );
-
- /* init root node and stack */
- mpNodeStack = new BSPStack;
- mpRoot = new BSPNode;
- mpRoot->min = mStart;
- mpRoot->max = mEnd;
- mpRoot->axis = AXIS_X;
- mpRoot->members = mppTriangles;
- mpRoot->child[0] = mpRoot->child[1] = NULL;
- mpRoot->cloneVec = 0;
- globalSortingPoints = mpVertices;
- mpTriDist = new char[ mppTriangles->size() ];
- mNumNodes = 1;
- mAbortSubdiv = 0;
-
- /* create tree */
- debugOutInter( "Generating BSP Tree... (Nodes "<< mCurrentNodes <<
- ", Depth "<<mCurrentDepth<< ") ", 2, 2000 );
- subdivide(mpRoot, 0, AXIS_X);
- debMsgStd("ntlTree::ntlTree",DM_MSG,"Generated Tree: Nodes "<< mCurrentNodes <<
- ", Depth "<<mCurrentDepth<< " with "<<noOfTriangles<<" triangles", 2 );
-
- delete [] mpTriDist;
- delete [] mpTBB;
- mpTriDist = NULL;
- mpTBB = NULL;
-
- /* calculate some stats about tree */
- int noLeafs = 0;
- gfxReal avgDepth = 0.0;
- gfxReal triPerLeaf = 0.0;
- int totalTris = 0;
-
- calcStats(mpRoot,0, noLeafs, avgDepth, triPerLeaf, totalTris);
- avgDepth /= (gfxReal)noLeafs;
- triPerLeaf /= (gfxReal)noLeafs;
- debMsgStd("ntlTree::ntlTree",DM_MSG,"Tree ("<<doSort<<","<<chooseAxis<<") Stats: Leafs:"<<noLeafs<<", avgDepth:"<<avgDepth<<
- ", triPerLeaf:"<<triPerLeaf<<", triDoubles:"<<mTriDoubles<<", totalTris:"<<totalTris
- <<" nodes:"<<mNumNodes
- //<<" T"<< (totalTris%3) // 0=ich, 1=f, 2=a
- , 2 );
-
- if(mAbortSubdiv) {
- errMsg("ntlTree::ntlTree","Aborted... "<<mNumNodes);
- deleteNode(mpRoot);
- mpRoot = NULL;
- }
-}
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlTree::~ntlTree()
-{
- /* delete tree, and all members except for the root node */
- deleteNode(mpRoot);
- if(mpNodeStack) delete mpNodeStack;
-}
-
-
-/******************************************************************************
- * subdivide tree
- *****************************************************************************/
-void ntlTree::subdivide(BSPNode *node, int depth, int axis)
-{
- int nextAxis=0; /* next axis to partition */
- int allTriDistSet = (1<<0)|(1<<1); // all mpTriDist flags set?
- //errorOut(" "<<node<<" depth:"<<depth<<" m:"<<node->members->size() <<" "<<node->min<<" - "<<node->max );
-
- if(depth>mCurrentDepth) mCurrentDepth = depth;
- node->child[0] = node->child[1] = NULL;
- if( ( (int)node->members->size() > mMaxListLength) &&
- (depth < mMaxDepth )
- && (node->cloneVec<10)
- && (!mAbortSubdiv)
- ) {
-
- gfxReal planeDiv = 0.499999; // position of plane division
-
- // determine next subdivision axis
- int newaxis = 0;
- gfxReal extX = node->max[0]-node->min[0];
- gfxReal extY = node->max[1]-node->min[1];
- gfxReal extZ = node->max[2]-node->min[2];
-
- if( extY>extX ) {
- if( extZ>extY ) {
- newaxis = 2;
- } else {
- newaxis = 1;
- }
- } else {
- if( extZ>extX ) {
- newaxis = 2;
- } else {
- newaxis = 0;
- }
- }
- axis = node->axis = newaxis;
-
- // init child nodes
- for( int i=0; i<2; i++) {
- /* status output */
- mCurrentNodes++;
- if(mCurrentNodes % 13973 ==0) {
- debugOutInter( "NTL Generating BSP Tree ("<<doSort<<","<<chooseAxis<<") ... (Nodes "<< mCurrentNodes <<
- ", Depth "<<mCurrentDepth<< ") " , 2, 2000);
- }
-
- /* create new node */
- node->child[i] = new BSPNode;
- node->child[i]->min = node->min;
- node->child[i]->max = node->max;
- node->child[i]->max = node->max;
- node->child[i]->child[0] = NULL;
- node->child[i]->child[1] = NULL;
- node->child[i]->members = NULL;
- nextAxis = (axis+1)%3;
- node->child[i]->axis = nextAxis;
- mNumNodes++;
- // abort when using 256MB only for tree...
- if(mNumNodes*sizeof(BSPNode)> 1024*1024*512) mAbortSubdiv = 1;
-
- /* current division plane */
- if(!i) {
- node->child[i]->min[axis] = node->min[axis];
- node->child[i]->max[axis] = node->min[axis] + planeDiv*
- (node->max[axis]-node->min[axis]);
- } else {
- node->child[i]->min[axis] = node->min[axis] + planeDiv*
- (node->max[axis]-node->min[axis]);
- node->child[i]->max[axis] = node->max[axis];
- }
- }
-
-
- /* process the two children */
- int thisTrisFor[2] = {0,0};
- int thisTriDoubles[2] = {0,0};
- for(int t=0;t<(int)node->members->size();t++) mpTriDist[t] = 0;
- for( int i=0; i<2; i++) {
- /* distribute triangles */
- int t = 0;
- for (vector<ntlTriangle *>::iterator iter = node->members->begin();
- iter != node->members->end(); iter++ ) {
-
- /* add triangle, check bounding box axis */
- TriangleBBox *bbox = &mpTBB[ (*iter)->getBBoxId() ];
- bool isintersect = true;
- if( bbox->end[axis] < node->child[i]->min[axis] ) isintersect = false;
- else if( bbox->start[axis] > node->child[i]->max[axis] ) isintersect = false;
- if(isintersect) {
- // add flag to vector
- mpTriDist[t] |= (1<<i);
- // count no. of triangles for vector init
- thisTrisFor[i]++;
- }
-
- if(mpTriDist[t] == allTriDistSet) {
- thisTriDoubles[i]++;
- mTriDoubles++; // TODO check for small geo tree??
- }
- t++;
- } /* end of loop over all triangles */
- } // i
-
- /* distribute triangles */
- bool haveCloneVec[2] = {false, false};
- for( int i=0; i<2; i++) {
- node->child[i]->members = new vector<ntlTriangle *>( thisTrisFor[i] );
- node->child[i]->cloneVec = 0;
- }
-
- int tind0 = 0;
- int tind1 = 0;
- if( (!haveCloneVec[0]) || (!haveCloneVec[1]) ){
- int t = 0; // triangle index counter
- for (vector<ntlTriangle *>::iterator iter = node->members->begin();
- iter != node->members->end(); iter++ ) {
- if(!haveCloneVec[0]) {
- if( (mpTriDist[t] & 1) == 1) {
- (*node->child[0]->members)[tind0] = (*iter); // dont use push_back for preinited size!
- tind0++;
- }
- }
- if(!haveCloneVec[1]) {
- if( (mpTriDist[t] & 2) == 2) {
- (*node->child[1]->members)[tind1] = (*iter); // dont use push_back for preinited size!
- tind1++;
- }
- }
- t++;
- } /* end of loop over all triangles */
- }
-
- // subdivide children
- for( int i=0; i<2; i++) {
- /* recurse */
- subdivide( node->child[i], depth+1, nextAxis );
- }
-
- /* if we are here, this are childs, so we dont need the members any more... */
- /* delete unecessary members */
- if( (!haveCloneVec[0]) && (!haveCloneVec[1]) && (node->cloneVec == 0) ){
- delete node->members;
- }
- node->members = NULL;
-
- } /* subdivision necessary */
-}
-
-/******************************************************************
- * triangle intersection with triangle pointer,
- * returns t,u,v by references
- */
-#if GFX_PRECISION==1
-// float values
-//! the minimal triangle determinant length
-#define RAY_TRIANGLE_EPSILON (1e-07)
-
-#else
-// double values
-//! the minimal triangle determinant length
-#define RAY_TRIANGLE_EPSILON (1e-15)
-
-#endif
-
-
-/******************************************************************************
- * intersect ray with BSPtree
- *****************************************************************************/
-inline void ntlRay::intersectTriangle(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const
-{
- /* (cf. moeller&haines, page 305) */
- t = GFX_REAL_MAX;
- ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ];
- ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0;
- ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0;
- ntlVec3Gfx p = cross( mDirection, e2 );
- gfxReal divisor = dot(e1, p);
- if((divisor > -RAY_TRIANGLE_EPSILON)&&(divisor < RAY_TRIANGLE_EPSILON)) return;
-
- gfxReal invDivisor = 1/divisor;
- ntlVec3Gfx s = mOrigin - e0;
- u = invDivisor * dot(s, p);
- if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- ntlVec3Gfx q = cross( s,e1 );
- v = invDivisor * dot(mDirection, q);
- if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- t = invDivisor * dot(e2, q);
-}
-void ntlTree::intersect(const ntlRay &ray, gfxReal &distance,
- ntlVec3Gfx &normal,
- ntlTriangle *&tri,
- int flags, bool forceNonsmooth) const
-{
- gfxReal mint = GFX_REAL_MAX; /* current minimal t */
- ntlVec3Gfx retnormal; /* intersection (interpolated) normal */
- gfxReal mintu=0.0, mintv=0.0; /* u,v for min t intersection */
-
- BSPNode *curr, *nearChild, *farChild; /* current node and children */
- gfxReal planedist, mindist, maxdist;
- ntlVec3Gfx pos;
-
- ntlTriangle *hit = NULL;
- tri = NULL;
-
- ray.intersectCompleteAABB(mStart,mEnd,mindist,maxdist);
-
- if((maxdist < 0.0) ||
- (!mpRoot) ||
- (mindist == GFX_REAL_MAX) ||
- (maxdist == GFX_REAL_MAX) ) {
- distance = -1.0;
- return;
- }
- mindist -= getVecEpsilon();
- maxdist += getVecEpsilon();
-
- /* stack init */
- mpNodeStack->elem[0].node = NULL;
- mpNodeStack->stackPtr = 1;
-
- curr = mpRoot;
- mint = GFX_REAL_MAX;
- while(curr != NULL) {
-
- while( !curr->isLeaf() ) {
- planedist = distanceToPlane(curr, curr->child[0]->max, ray );
- getChildren(curr, ray.getOrigin(), nearChild, farChild );
-
- // check ray direction for small plane distances
- if( (planedist>-getVecEpsilon() )&&(planedist< getVecEpsilon() ) ) {
- // ray origin on intersection plane
- planedist = 0.0;
- if(ray.getDirection()[curr->axis]>getVecEpsilon() ) {
- // larger coords
- curr = curr->child[1];
- } else if(ray.getDirection()[curr->axis]<-getVecEpsilon() ) {
- // smaller coords
- curr = curr->child[0];
- } else {
- // paralell, order doesnt really matter are min/max/plane ok?
- mpNodeStack->elem[ mpNodeStack->stackPtr ].node = curr->child[0];
- mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
- (mpNodeStack->stackPtr)++;
- curr = curr->child[1];
- maxdist = planedist;
- }
- } else {
- // normal ray
- if( (planedist>maxdist) || (planedist<0.0-getVecEpsilon() ) ) {
- curr = nearChild;
- } else if(planedist < mindist) {
- curr = farChild;
- } else {
- mpNodeStack->elem[ mpNodeStack->stackPtr ].node = farChild;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
- (mpNodeStack->stackPtr)++;
-
- curr = nearChild;
- maxdist = planedist;
- }
- }
- }
-
-
- /* intersect with current node */
- for (vector<ntlTriangle *>::iterator iter = curr->members->begin();
- iter != curr->members->end(); iter++ ) {
-
- /* check for triangle flags before intersecting */
- if((!flags) || ( ((*iter)->getFlags() & flags) > 0 )) {
-
- if( ((*iter)->getLastRay() == ray.getID() )&&((*iter)->getLastRay()>0) ) {
- // was already intersected...
- } else {
- // we still need to intersect this triangle
- gfxReal u=0.0,v=0.0, t=-1.0;
- ray.intersectTriangle( mpVertices, (*iter), t,u,v);
- (*iter)->setLastRay( ray.getID() );
-
- if( (t > 0.0) && (t<mint) ) {
- mint = t;
- hit = (*iter);
- mintu = u; mintv = v;
- }
- }
-
- } // flags check
- }
-
- /* check if intersection is valid */
- if( (mint>0.0) && (mint < GFX_REAL_MAX) ) {
- pos = ray.getOrigin() + ray.getDirection()*mint;
-
- if( (pos[0] >= curr->min[0]) && (pos[0] <= curr->max[0]) &&
- (pos[1] >= curr->min[1]) && (pos[1] <= curr->max[1]) &&
- (pos[2] >= curr->min[2]) && (pos[2] <= curr->max[2]) )
- {
-
- if(forceNonsmooth) {
- // calculate triangle normal
- ntlVec3Gfx e0,e1,e2;
- e0 = (*mpVertices)[ hit->getPoints()[0] ];
- e1 = (*mpVertices)[ hit->getPoints()[1] ];
- e2 = (*mpVertices)[ hit->getPoints()[2] ];
- retnormal = cross( -(e2-e0), (e1-e0) );
- } else {
- // calculate interpolated normal
- retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
- (*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
- (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
- }
- normalize(retnormal);
- normal = retnormal;
- distance = mint;
- tri = hit;
- return;
- }
- }
-
- (mpNodeStack->stackPtr)--;
- curr = mpNodeStack->elem[ mpNodeStack->stackPtr ].node;
- mindist = mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist;
- maxdist = mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist;
- } /* traverse tree */
-
- if(mint == GFX_REAL_MAX) {
- distance = -1.0;
- } else {
- // intersection outside the BSP bounding volumes might occur due to roundoff...
- //retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
- if(forceNonsmooth) {
- // calculate triangle normal
- ntlVec3Gfx e0,e1,e2;
- e0 = (*mpVertices)[ hit->getPoints()[0] ];
- e1 = (*mpVertices)[ hit->getPoints()[1] ];
- e2 = (*mpVertices)[ hit->getPoints()[2] ];
- retnormal = cross( -(e2-e0), (e1-e0) );
- } else {
- // calculate interpolated normal
- retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
- (*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
- (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
- }
-
- normalize(retnormal);
- normal = retnormal;
- distance = mint;
- tri = hit;
- }
- return;
-}
-
-inline void ntlRay::intersectTriangleX(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const
-{
- /* (cf. moeller&haines, page 305) */
- t = GFX_REAL_MAX;
- ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ];
- ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0;
- ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0;
-
- //ntlVec3Gfx p = cross( mDirection, e2 );
- //ntlVector3Dim<Scalar> cp( (-), (- (1.0 *v[2])), ((1.0 *v[1]) -) );
- ntlVec3Gfx p(0.0, -e2[2], e2[1]);
-
- gfxReal divisor = dot(e1, p);
- if((divisor > -RAY_TRIANGLE_EPSILON)&&(divisor < RAY_TRIANGLE_EPSILON)) return;
-
- gfxReal invDivisor = 1/divisor;
- ntlVec3Gfx s = mOrigin - e0;
- u = invDivisor * dot(s, p);
- if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- ntlVec3Gfx q = cross( s,e1 );
- //v = invDivisor * dot(mDirection, q);
- v = invDivisor * q[0];
- if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- t = invDivisor * dot(e2, q);
-}
-void ntlTree::intersectX(const ntlRay &ray, gfxReal &distance,
- ntlVec3Gfx &normal,
- ntlTriangle *&tri,
- int flags, bool forceNonsmooth) const
-{
- gfxReal mint = GFX_REAL_MAX; /* current minimal t */
- ntlVec3Gfx retnormal; /* intersection (interpolated) normal */
- gfxReal mintu=0.0, mintv=0.0; /* u,v for min t intersection */
-
- BSPNode *curr, *nearChild, *farChild; /* current node and children */
- gfxReal planedist, mindist, maxdist;
- ntlVec3Gfx pos;
-
- ntlTriangle *hit = NULL;
- tri = NULL;
-
- ray.intersectCompleteAABB(mStart,mEnd,mindist,maxdist); // +X
-
- if((maxdist < 0.0) ||
- (!mpRoot) ||
- (mindist == GFX_REAL_MAX) ||
- (maxdist == GFX_REAL_MAX) ) {
- distance = -1.0;
- return;
- }
- mindist -= getVecEpsilon();
- maxdist += getVecEpsilon();
-
- /* stack init */
- mpNodeStack->elem[0].node = NULL;
- mpNodeStack->stackPtr = 1;
-
- curr = mpRoot;
- mint = GFX_REAL_MAX;
- while(curr != NULL) { // +X
-
- while( !curr->isLeaf() ) {
- planedist = distanceToPlane(curr, curr->child[0]->max, ray );
- getChildren(curr, ray.getOrigin(), nearChild, farChild );
-
- // check ray direction for small plane distances
- if( (planedist>-getVecEpsilon() )&&(planedist< getVecEpsilon() ) ) {
- // ray origin on intersection plane
- planedist = 0.0;
- if(ray.getDirection()[curr->axis]>getVecEpsilon() ) {
- // larger coords
- curr = curr->child[1];
- } else if(ray.getDirection()[curr->axis]<-getVecEpsilon() ) {
- // smaller coords
- curr = curr->child[0];
- } else {
- // paralell, order doesnt really matter are min/max/plane ok?
- mpNodeStack->elem[ mpNodeStack->stackPtr ].node = curr->child[0];
- mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
- (mpNodeStack->stackPtr)++;
- curr = curr->child[1];
- maxdist = planedist;
- }
- } else {
- // normal ray
- if( (planedist>maxdist) || (planedist<0.0-getVecEpsilon() ) ) {
- curr = nearChild;
- } else if(planedist < mindist) {
- curr = farChild;
- } else {
- mpNodeStack->elem[ mpNodeStack->stackPtr ].node = farChild;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist;
- mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist;
- (mpNodeStack->stackPtr)++;
-
- curr = nearChild;
- maxdist = planedist;
- }
- }
- } // +X
-
-
- /* intersect with current node */
- for (vector<ntlTriangle *>::iterator iter = curr->members->begin();
- iter != curr->members->end(); iter++ ) {
-
- /* check for triangle flags before intersecting */
- if((!flags) || ( ((*iter)->getFlags() & flags) > 0 )) {
-
- if( ((*iter)->getLastRay() == ray.getID() )&&((*iter)->getLastRay()>0) ) {
- // was already intersected...
- } else {
- // we still need to intersect this triangle
- gfxReal u=0.0,v=0.0, t=-1.0;
- ray.intersectTriangleX( mpVertices, (*iter), t,u,v);
- (*iter)->setLastRay( ray.getID() );
-
- if( (t > 0.0) && (t<mint) ) {
- mint = t;
- hit = (*iter);
- mintu = u; mintv = v;
- }
- }
-
- } // flags check
- } // +X
-
- /* check if intersection is valid */
- if( (mint>0.0) && (mint < GFX_REAL_MAX) ) {
- pos = ray.getOrigin() + ray.getDirection()*mint;
-
- if( (pos[0] >= curr->min[0]) && (pos[0] <= curr->max[0]) &&
- (pos[1] >= curr->min[1]) && (pos[1] <= curr->max[1]) &&
- (pos[2] >= curr->min[2]) && (pos[2] <= curr->max[2]) )
- {
-
- if(forceNonsmooth) {
- // calculate triangle normal
- ntlVec3Gfx e0,e1,e2;
- e0 = (*mpVertices)[ hit->getPoints()[0] ];
- e1 = (*mpVertices)[ hit->getPoints()[1] ];
- e2 = (*mpVertices)[ hit->getPoints()[2] ];
- retnormal = cross( -(e2-e0), (e1-e0) );
- } else {
- // calculate interpolated normal
- retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
- (*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
- (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
- }
- normalize(retnormal);
- normal = retnormal;
- distance = mint;
- tri = hit;
- return;
- }
- } // +X
-
- (mpNodeStack->stackPtr)--;
- curr = mpNodeStack->elem[ mpNodeStack->stackPtr ].node;
- mindist = mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist;
- maxdist = mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist;
- } /* traverse tree */
-
- if(mint == GFX_REAL_MAX) {
- distance = -1.0;
- } else {
-
- // intersection outside the BSP bounding volumes might occur due to roundoff...
- if(forceNonsmooth) {
- // calculate triangle normal
- ntlVec3Gfx e0,e1,e2;
- e0 = (*mpVertices)[ hit->getPoints()[0] ];
- e1 = (*mpVertices)[ hit->getPoints()[1] ];
- e2 = (*mpVertices)[ hit->getPoints()[2] ];
- retnormal = cross( -(e2-e0), (e1-e0) );
- } else {
- // calculate interpolated normal
- retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+
- (*mpVertNormals)[ hit->getPoints()[1] ]*mintu +
- (*mpVertNormals)[ hit->getPoints()[2] ]*mintv;
- }
-
- normalize(retnormal);
- normal = retnormal;
- distance = mint;
- tri = hit;
- } // +X
- return;
-}
-
-
-
-/******************************************************************************
- * distance to plane function for nodes
- *****************************************************************************/
-gfxReal ntlTree::distanceToPlane(BSPNode *curr, ntlVec3Gfx plane, ntlRay ray) const
-{
- return ( (plane[curr->axis]-ray.getOrigin()[curr->axis]) / ray.getDirection()[curr->axis] );
-}
-
-
-/******************************************************************************
- * return ordering of children nodes relatice to origin point
- *****************************************************************************/
-void ntlTree::getChildren(BSPNode *curr, ntlVec3Gfx origin, BSPNode *&node_near, BSPNode *&node_far) const
-{
- if(curr->child[0]->max[ curr->axis ] >= origin[ curr->axis ]) {
- node_near = curr->child[0];
- node_far = curr->child[1];
- } else {
- node_near = curr->child[1];
- node_far = curr->child[0];
- }
-}
-
-
-/******************************************************************************
- * delete a node of the tree with all sub nodes
- * dont delete root members
- *****************************************************************************/
-void ntlTree::deleteNode(BSPNode *curr)
-{
- if(!curr) return;
-
- if(curr->child[0] != NULL)
- deleteNode(curr->child[0]);
- if(curr->child[1] != NULL)
- deleteNode(curr->child[1]);
-
- if(curr->members != NULL) delete curr->members;
- delete curr;
-}
-
-
-
-/******************************************************************
- * intersect only front or backsides
- * currently unused
- */
-inline void ntlRay::intersectTriangleFront(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const
-{
- t = GFX_REAL_MAX;
- ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ];
- ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0;
- ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0;
- ntlVec3Gfx p = cross( mDirection, e2 );
- gfxReal a = dot(e1, p);
- //if((a > -RAY_TRIANGLE_EPSILON)&&(a < RAY_TRIANGLE_EPSILON)) return;
- if(a < RAY_TRIANGLE_EPSILON) return; // cull backsides
-
- gfxReal f = 1/a;
- ntlVec3Gfx s = mOrigin - e0;
- u = f * dot(s, p);
- if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- ntlVec3Gfx q = cross( s,e1 );
- v = f * dot(mDirection, q);
- if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- t = f * dot(e2, q);
-}
-inline void ntlRay::intersectTriangleBack(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const
-{
- t = GFX_REAL_MAX;
- ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ];
- ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0;
- ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0;
- ntlVec3Gfx p = cross( mDirection, e2 );
- gfxReal a = dot(e1, p);
- //if((a > -RAY_TRIANGLE_EPSILON)&&(a < RAY_TRIANGLE_EPSILON)) return;
- if(a > -RAY_TRIANGLE_EPSILON) return; // cull frontsides
-
- gfxReal f = 1/a;
- ntlVec3Gfx s = mOrigin - e0;
- u = f * dot(s, p);
- if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- ntlVec3Gfx q = cross( s,e1 );
- v = f * dot(mDirection, q);
- if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return;
-
- t = f * dot(e2, q);
-}
-
-
-
diff --git a/intern/elbeem/intern/ntl_bsptree.h b/intern/elbeem/intern/ntl_bsptree.h
deleted file mode 100644
index f6eaee069a9..00000000000
--- a/intern/elbeem/intern/ntl_bsptree.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Tree container for fast triangle intersects
- *
- *****************************************************************************/
-#ifndef NTL_TREE_H
-#define NTL_TREE_H
-
-#include "ntl_vector3dim.h"
-#include "ntl_ray.h"
-
-
-#define AXIS_X 0
-#define AXIS_Y 1
-#define AXIS_Z 2
-
-#define BSP_STACK_SIZE 50
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-//! bsp tree stack classes, defined in ntl_bsptree.cpp,
-// detailed definition unnecesseary here
-class BSPNode;
-class BSPStackElement;
-class BSPStack;
-class TriangleBBox;
-class ntlScene;
-class ntlTriangle;
-
-
-//! Class for a bsp tree for triangles
-class ntlTree
-{
- public:
-
- //! Default constructor
- ntlTree();
- //! Constructor with init
- ntlTree(int depth, int objnum, ntlScene *scene, int triFlagMask);
- //! Destructor
- ~ntlTree();
-
- //! subdivide tree
- void subdivide(BSPNode *node, int depth, int axis);
-
- //! intersect ray with BSPtree
- void intersect(const ntlRay &ray, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags, bool forceNonsmooth) const;
- //! intersect along +X ray
- void intersectX(const ntlRay &ray, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags, bool forceNonsmooth) const;
-
- //! Returns number of nodes
- int getCurrentNodes( void ) { return mCurrentNodes; }
-
- protected:
-
- // check if a triangle is in a node
- bool checkAABBTriangle(ntlVec3Gfx &min, ntlVec3Gfx &max, ntlTriangle *tri);
-
-
- // VARs
-
- //! distance to plane function for nodes
- gfxReal distanceToPlane(BSPNode *curr, ntlVec3Gfx plane, ntlRay ray) const;
-
- //! return ordering of children nodes relatice to origin point
- void getChildren(BSPNode *curr, ntlVec3Gfx origin, BSPNode *&node_near, BSPNode *&node_far) const;
-
- //! delete a node of the tree with all sub nodes, dont delete root members
- void deleteNode(BSPNode *curr);
-
- //inline bool isLeaf(BSPNode *node) const { return (node->child[0] == NULL); }
-
-
- //! AABB for tree
- ntlVec3Gfx mStart,mEnd;
-
- //! maximum depth of tree
- int mMaxDepth;
-
- //! maximum number of objects in one node
- int mMaxListLength;
-
- //! root node pointer
- BSPNode *mpRoot;
- //! count no. of node
- int mNumNodes;
- int mAbortSubdiv;
-
- //! stack for the node pointers
- BSPStack *mpNodeStack;
- //stack<BSPNode *> nodestack;
-
- //! pointer to vertex array
- vector<ntlVec3Gfx> *mpVertices;
-
- //! pointer to vertex array
- vector<ntlVec3Gfx> *mpVertNormals;
-
- //! vector for all the triangles
- vector<ntlTriangle> *mpTriangles;
- vector<ntlTriangle *> *mppTriangles;
-
- //! temporary array for triangle distribution to nodes
- char *mpTriDist;
-
- //! temporary array for triangle bounding boxes
- TriangleBBox *mpTBB;
-
- //! triangle mask - include only triangles that match mask
- int mTriangleMask;
-
- //! Status vars (max depth, # of current nodes)
- int mCurrentDepth, mCurrentNodes;
-
- //! duplicated triangles, inited during subdivide
- int mTriDoubles;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlTree")
-#endif
-};
-
-
-#endif
-
-
diff --git a/intern/elbeem/intern/ntl_geometryclass.h b/intern/elbeem/intern/ntl_geometryclass.h
deleted file mode 100644
index a5d44ad477a..00000000000
--- a/intern/elbeem/intern/ntl_geometryclass.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Base class for geometry shaders and objects
- *
- *****************************************************************************/
-
-
-#ifndef NTL_GEOMETRYCLASS_H
-#define NTL_GEOMETRYCLASS_H
-
-#include "attributes.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-//! geometry class type ids
-#define GEOCLASSTID_OBJECT 1
-#define GEOCLASSTID_SHADER 2
-#define GEOCLASSTID_BOX (GEOCLASSTID_OBJECT| 4)
-#define GEOCLASSTID_OBJMODEL (GEOCLASSTID_OBJECT| 8)
-#define GEOCLASSTID_SPHERE (GEOCLASSTID_OBJECT| 16)
-
-class ntlGeometryClass
-{
-
- public:
-
- //! Default constructor
- inline ntlGeometryClass() :
- mVisible( 1 ), mName( "[ObjNameUndef]" ),
- mObjectId(-1), mpAttrs( NULL ), mGeoInitId(-1)
- {
- mpAttrs = new AttributeList("objAttrs");
- mpSwsAttrs = new AttributeList("swsAttrs");
- };
-
- //! Default destructor
- virtual ~ntlGeometryClass() {
- delete mpAttrs;
- delete mpSwsAttrs;
- };
-
- //! Return type id
- virtual int getTypeId() = 0;
-
- /*! Set the object name */
- inline void setName(string set) { mName = set; }
- /*! Get the object name */
- inline string getName( void ) { return mName; }
-
- /*! Sets the visibility attribute
- * visibility can be determined at shader _and_ object level , hiding a shader
- * means comepletely decativating it */
- inline void setVisible(int set) { mVisible=set; }
- /*! Returns the visibility attribute */
- inline int getVisible() const { return mVisible; }
-
- /*! Sets the attribute list pointer */
- inline void setAttributeList(AttributeList *set) { mpAttrs=set; }
- /*! Returns the attribute list pointer */
- inline AttributeList *getAttributeList() { return mpAttrs; }
-
- /*! Get/Sets the attribute list pointer */
- inline void setSwsAttributeList(AttributeList *set) { mpSwsAttrs=set; }
- inline AttributeList *getSwsAttributeList() { return mpSwsAttrs; }
-
- /*! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB */
- virtual inline ntlVec3Gfx *getBBStart() { return NULL; }
- virtual inline ntlVec3Gfx *getBBEnd() { return NULL; }
-
- /*! Set/get the object id*/
- inline void setObjectId(int set) { mObjectId=set; }
- inline int getObjectId() const { return mObjectId; }
-
- /*! GUI - this function is called for selected objects to display debugging information with OpenGL */
- virtual void drawDebugDisplay() { /* do nothing by default */ }
- /*! GUI - this function is called for selected objects to display interactive information with OpenGL */
- virtual void drawInteractiveDisplay() { /* do nothing by default */ }
- /*! GUI - handle mouse movement for selection */
- virtual void setMousePos(int ,int , ntlVec3Gfx , ntlVec3Gfx ) { /* do nothing by default */ }
- /*! GUI - notify object that mouse was clicked at last pos */
- virtual void setMouseClick() { /* do nothing by default */ }
-
- /*! Returns the geo init id */
- inline void setGeoInitId(int set) { mGeoInitId=set; }
- /*! Returns the geo init id */
- inline int getGeoInitId() const { return mGeoInitId; }
-
- protected:
-
- /*! Object visible on/off */
- int mVisible;
-
- /*! Name of this object */
- string mName;
-
- /*! global scene object id */
- int mObjectId;
-
- /*! configuration attributes */
- AttributeList *mpAttrs;
- /*! sws configuration attributes */
- AttributeList *mpSwsAttrs;
-
- /* fluid init data */
- /*! id of fluid init (is used in solver initialization), additional data stored only for objects */
- int mGeoInitId;
-
- private:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlGeometryClass")
-#endif
-};
-
-
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_geometrymodel.cpp b/intern/elbeem/intern/ntl_geometrymodel.cpp
deleted file mode 100644
index 989fcac599b..00000000000
--- a/intern/elbeem/intern/ntl_geometrymodel.cpp
+++ /dev/null
@@ -1,477 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * A simple box object
- *
- *****************************************************************************/
-
-#include "ntl_geometrymodel.h"
-#include "ntl_ray.h"
-#include "ntl_world.h"
-#include "zlib.h"
-
-#ifdef WIN32
-#ifndef strncasecmp
-#define strncasecmp(a,b,c) strcmp(a,b)
-#endif
-#endif // WIN32
-
-
-/******************************************************************************
- * Default Constructor
- *****************************************************************************/
-ntlGeometryObjModel::ntlGeometryObjModel( void ) :
- ntlGeometryObject(),
- mvStart( 0.0 ), mvEnd( 1.0 ),
- mLoaded( false ),
- mTriangles(), mVertices(), mNormals(),
- mcAniVerts(), mcAniNorms(),
- mcAniTimes(), mAniTimeScale(1.), mAniTimeOffset(0.)
-{
-}
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlGeometryObjModel::~ntlGeometryObjModel()
-{
- if(!mLoaded) {
- errMsg("ntlGeometryObjModel","delete obj...");
- }
-}
-
-
-/*! is the mesh animated? */
-bool ntlGeometryObjModel::getMeshAnimated() {
- const bool ret = (mcAniVerts.getSize()>1);
- //errMsg("getMeshAnimated","ret="<<ret<<", size="<<mcAniVerts.getSize() );
- return ret;
-}
-
-/*! calculate max extends of (ani) mesh */
-void ntlGeometryObjModel::getExtends(ntlVec3Gfx &sstart, ntlVec3Gfx &send) {
- bool ini=false;
- ntlVec3Gfx start(0.),end(0.);
- for(int s=0; s<=(int)mcAniVerts.accessValues().size(); s++) {
- vector<ntlVec3f> *sverts;
- if(mcAniVerts.accessValues().size()>0) {
- if(s==(int)mcAniVerts.accessValues().size()) continue;
- sverts = &(mcAniVerts.accessValues()[s].mVerts);
- } else sverts = &mVertices;
-
- for(int i=0; i<(int)sverts->size(); i++) {
-
- if(!ini) {
- start=(*sverts)[i];
- end=(*sverts)[i];
- //errMsg("getExtends","ini "<<s<<","<<i<<" "<<start<<","<<end);
- ini=true;
- } else {
- for(int j=0; j<3; j++) {
- if(start[j] > (*sverts)[i][j]) { start[j]= (*sverts)[i][j]; }
- if(end[j] < (*sverts)[i][j]) { end[j] = (*sverts)[i][j]; }
- }
- //errMsg("getExtends","check "<<s<<","<<i<<" "<<start<<","<<end<<" "<< (*sverts)[i]);
- }
-
- }
- }
- sstart=start;
- send=end;
-}
-
-
-/*****************************************************************************/
-/* Init attributes etc. of this object */
-/*****************************************************************************/
-void ntlGeometryObjModel::initialize(ntlRenderGlobals *glob)
-{
- // perhaps the model is already inited from initModel below?
- if(mLoaded==1) {
- // init default material
- searchMaterial( glob->getMaterials() );
- return;
- }
-
- ntlGeometryObject::initialize(glob);
- mFilename = mpAttrs->readString("filename", mFilename,"ntlGeometryObjModel", "mFilename", true);
-
- if(mFilename == "") {
- errMsg("ntlGeometryObjModel::initialize","Filename not given!");
- return;
- }
-
- const char *suffix = strrchr(mFilename.c_str(), '.');
- if (suffix) {
- if (!strncasecmp(suffix, ".obj", 4)) {
- errMsg("ntlGeometryObjModel::initialize",".obj files not supported!");
- return;
- } else if (!strncasecmp(suffix, ".gz", 3)) {
- //mType = 1; // assume its .bobj.gz
- } else if (!strncasecmp(suffix, ".bobj", 5)) {
- //mType = 1;
- }
- }
-
- if(getAttributeList()->exists("ani_times") || (!mcAniTimes.isInited()) ) {
- mcAniTimes = mpAttrs->readChannelFloat("ani_times");
- }
- mAniTimeScale = mpAttrs->readFloat("ani_timescale", mAniTimeScale,"ntlGeometryObjModel", "mAniTimeScale", false);
- mAniTimeOffset = mpAttrs->readFloat("ani_timeoffset", mAniTimeOffset,"ntlGeometryObjModel", "mAniTimeOffset", false);
-
- // continue with standard obj
- if(loadBobjModel(mFilename)==0) mLoaded=1;
- if(!mLoaded) {
- debMsgStd("ntlGeometryObjModel",DM_WARNING,"Unable to load object file '"<<mFilename<<"' !", 0);
- }
- if(getMeshAnimated()) {
- this->mIsAnimated = true;
- }
-}
-
-/******************************************************************************
- * init model from given vertex and triangle arrays
- *****************************************************************************/
-
-int ntlGeometryObjModel::initModel(int numVertices, float *vertices, int numTriangles, int *triangles,
- int channelSize, float *channelVertices)
-{
- mVertices.clear();
- mVertices.resize( numVertices );
- mNormals.resize( numVertices );
- for(int i=0; i<numVertices; i++) {
- mVertices[i] = ntlVec3Gfx(vertices[i*3+0],vertices[i*3+1],vertices[i*3+2]);
- mNormals[i] = ntlVec3Gfx(1.0); // unused, set to !=0.0
- }
-
- mTriangles.clear();
- mTriangles.resize( 3*numTriangles );
- int triangleErrs=0;
- for(int i=0; i<numTriangles; i++) {
- for(int j=0;j<3;j++) {
- mTriangles[3*i+j] = triangles[i*3+j];
- if(mTriangles[3*i+j]<0) { mTriangles[3*i+j]=0; triangleErrs++; }
- if(mTriangles[3*i+j]>=numVertices) { mTriangles[3*i+j]=0; triangleErrs++; }
- }
- }
- if(triangleErrs>0) {
- errMsg("ntlGeometryObjModel::initModel","Triangle errors occurred ("<<triangleErrs<<")!");
- }
-
- //fprintf(stderr,"initModel DEBUG %d \n",channelSize);
- debMsgStd("ntlGeometryObjModel::initModel",DM_MSG, "Csize:"<<channelSize<<", Cvert:"<<(size_t)(channelVertices) ,10);
- if(channelVertices && (channelSize>0)) {
- vector<ntlSetVec3f> aniverts;
- vector<ntlSetVec3f> aninorms;
- vector<double> anitimes;
- aniverts.clear();
- aninorms.clear();
- anitimes.clear();
- for(int frame=0; frame<channelSize; frame++) {
- ntlSetVec3f averts; averts.mVerts.clear();
- ntlSetVec3f anorms; anorms.mVerts.clear();
- int setsize = (3*numVertices+1);
-
- ntlVec3Gfx p(0.),n(1.);
- for(int i=0; i<numVertices; i++) {
- for(int j=0; j<3; j++) p[j] = channelVertices[frame*setsize+ 3*i +j];
- averts.mVerts.push_back(p);
- anorms.mVerts.push_back(p);
- //debMsgStd("ntlGeometryObjModel::initModel",DM_MSG, "Frame:"<<frame<<",i:"<<i<<" "<<p,10);
- }
- if( ((int)averts.mVerts.size()==numVertices) &&
- ((int)anorms.mVerts.size()==numVertices) ) {
- aniverts.push_back(averts);
- aninorms.push_back(anorms);
- double time = (double)channelVertices[frame*setsize+ setsize-1];
- anitimes.push_back(time);
- } else {
- errMsg("ntlGeometryObjModel::initModel","Invalid mesh, obj="<<this->getName()<<" frame="<<frame<<" verts="<<averts.mVerts.size()<<"/"<<numVertices<<". Skipping...");
- }
- //debMsgStd("ntlGeometryObjModel::initModel",DM_MSG, "Frame:"<<frame<<" at t="<<time,10);
- }
-
- mcAniVerts = AnimChannel<ntlSetVec3f>(aniverts,anitimes);
- mcAniNorms = AnimChannel<ntlSetVec3f>(aninorms,anitimes);
- debMsgStd("ntlGeometryObjModel::initModel",DM_MSG, "Ani sets inited: "<< mcAniVerts.accessValues().size() <<","<<mcAniNorms.accessValues().size() <<" ", 1 );
- }
- if(getMeshAnimated()) {
- this->mIsAnimated = true;
- }
-
- // inited, no need to parse attribs etc.
- mLoaded = 1;
- return 0;
-}
-
-/*! init triangle divisions */
-void ntlGeometryObjModel::calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntlTriangle> &tris, gfxReal fsTri) {
- // warning - copied from geomobj calc!
- errMsg("ntlGeometryObjModel","calcTriangleDivs special!");
- mTriangleDivs1.resize( tris.size() );
- mTriangleDivs2.resize( tris.size() );
- for(size_t i=0; i<tris.size(); i++) {
- ntlVec3Gfx p0 = verts[ tris[i].getPoints()[0] ];
- ntlVec3Gfx p1 = verts[ tris[i].getPoints()[1] ];
- ntlVec3Gfx p2 = verts[ tris[i].getPoints()[2] ];
- ntlVec3Gfx side1 = p1 - p0;
- ntlVec3Gfx side2 = p2 - p0;
- ntlVec3Gfx side3 = p1 - p2;
- int divs1=0, divs2=0;
- if(normNoSqrt(side1) > fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); }
- if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); }
-
- // special handling
- // warning, requires objmodel triangle treatment (no verts dups)
- if(getMeshAnimated()) {
- vector<ntlSetVec3f> &sverts = mcAniVerts.accessValues();
- for(int s=0; s<(int)sverts.size(); s++) {
- p0 = sverts[s].mVerts[ tris[i].getPoints()[0] ];
- p1 = sverts[s].mVerts[ tris[i].getPoints()[1] ];
- p2 = sverts[s].mVerts[ tris[i].getPoints()[2] ];
- side1 = p1 - p0; side2 = p2 - p0; side3 = p1 - p2;
- int tdivs1=0, tdivs2=0;
- if(normNoSqrt(side1) > fsTri*fsTri) { tdivs1 = (int)(norm(side1)/fsTri); }
- if(normNoSqrt(side2) > fsTri*fsTri) { tdivs2 = (int)(norm(side2)/fsTri); }
- if(tdivs1>divs1) divs1=tdivs1;
- if(tdivs2>divs2) divs2=tdivs2;
- }
- } // */
- mTriangleDivs1[i] = divs1;
- mTriangleDivs2[i] = divs2;
- }
-}
-
-
-/******************************************************************************
- * load model from .obj file
- *****************************************************************************/
-
-int ntlGeometryObjModel::loadBobjModel(string filename)
-{
- bool haveAniSets=false;
- vector<ntlSetVec3f> aniverts;
- vector<ntlSetVec3f> aninorms;
- vector<double> anitimes;
-
- const bool debugPrint=false;
- const bool debugPrintFull=false;
- gzFile gzf;
- gzf = gzopen(filename.c_str(), "rb");
- if (!gzf) {
- errFatal("ntlGeometryObjModel::loadBobjModel","Reading GZ_BOBJ, Unable to open '"<< filename <<"'...\n", SIMWORLD_INITERROR );
- return 1;
- }
-
- int numVerts;
- if(sizeof(numVerts)!=4) { // paranoia check
- errMsg("Reading GZ_BOBJ"," Invalid int size, check compiler settings: int has to be 4 byte long");
- goto gzreaderror;
- }
- gzread(gzf, &numVerts, sizeof(numVerts) );
- if(numVerts<0 || numVerts>1e9) {
- errMsg("Reading GZ_BOBJ"," invalid num vertices "<< numVerts);
- goto gzreaderror;
- }
- mVertices.clear();
- mVertices.resize( numVerts );
- for(int i=0; i<numVerts; i++) {
- float x[3];
- for(int j=0; j<3; j++) {
- gzread(gzf, &(x[j]), sizeof( (x[j]) ) );
- }
- mVertices[i] = ntlVec3Gfx(x[0],x[1],x[2]);
- if(debugPrintFull) errMsg("FULLV"," "<<i<<" "<< mVertices[i] );
- }
- if(debugPrint) errMsg("NV"," "<<numVerts<<" "<< mVertices.size() );
-
- // should be the same as Vertices.size
- gzread(gzf, &numVerts, sizeof(numVerts) );
- if(numVerts<0 || numVerts>1e9) {
- errMsg("Reading GZ_BOBJ","invalid num normals "<< numVerts);
- goto gzreaderror;
- }
- mNormals.clear();
- mNormals.resize( numVerts );
- for(int i=0; i<numVerts; i++) {
- float n[3];
- for(int j=0; j<3; j++) {
- gzread(gzf, &(n[j]), sizeof( (n[j]) ) );
- }
- mNormals[i] = ntlVec3Gfx(n[0],n[1],n[2]);
- if(debugPrintFull) errMsg("FULLN"," "<<i<<" "<< mNormals[i] );
- }
- if(debugPrint) errMsg("NN"," "<<numVerts<<" "<< mNormals.size() );
-
- int numTris;
- gzread(gzf, &numTris, sizeof(numTris) );
- if(numTris<0 || numTris>1e9) {
- errMsg("Reading GZ_BOBJ","invalid num normals "<< numTris);
- goto gzreaderror;
- }
- mTriangles.resize( 3*numTris );
- for(int i=0; i<numTris; i++) {
- int tri[3];
- for(int j=0; j<3; j++) {
- gzread(gzf, &(tri[j]), sizeof( (tri[j]) ) );
- }
- mTriangles[3*i+0] = tri[0];
- mTriangles[3*i+1] = tri[1];
- mTriangles[3*i+2] = tri[2];
- }
- if(debugPrint) errMsg("NT"," "<<numTris<<" "<< mTriangles.size() );
-
- debMsgStd("ntlGeometryObjModel::loadBobjModel",DM_MSG, "File '"<<filename<<"' loaded, #Vertices: "<<mVertices.size()<<", #Normals: "<<mNormals.size()<<", #Triangles: "<<(mTriangles.size()/3)<<" ", 1 );
-
- // try to load animated mesh
- aniverts.clear();
- aninorms.clear();
- anitimes.clear();
- while(1) {
- //ntlVec3Gfx check;
- float x[3];
- float frameTime=0.;
- int bytesRead = 0;
- int numNorms2=-1, numVerts2=-1;
- //for(int j=0; j<3; j++) {
- //x[j] = 0.;
- //bytesRead += gzread(gzf, &(x[j]), sizeof(float) );
- //}
- //check = ntlVec3Gfx(x[0],x[1],x[2]);
- //if(debugPrint) errMsg("ANI_NV1"," "<<check<<" "<<" bytes:"<<bytesRead );
- bytesRead += gzread(gzf, &frameTime, sizeof(frameTime) );
- //if(bytesRead!=3*sizeof(float)) {
- if(bytesRead!=sizeof(float)) {
- debMsgStd("ntlGeometryObjModel::loadBobjModel",DM_MSG, "File '"<<filename<<"' end of gzfile. ", 10 );
- if(anitimes.size()>0) {
- // finally init channels and stop reading file
- mcAniVerts = AnimChannel<ntlSetVec3f>(aniverts,anitimes);
- mcAniNorms = AnimChannel<ntlSetVec3f>(aninorms,anitimes);
- }
- goto gzreaddone;
- }
- bytesRead += gzread(gzf, &numVerts2, sizeof(numVerts2) );
- haveAniSets=true;
- // continue to read new set
- vector<ntlVec3Gfx> vertset;
- vector<ntlVec3Gfx> normset;
- vertset.resize(numVerts);
- normset.resize(numVerts);
- //vertset[0] = check;
- if(debugPrintFull) errMsg("FUL1V"," "<<0<<" "<< vertset[0] );
-
- for(int i=0; i<numVerts; i++) { // start at one!
- for(int j=0; j<3; j++) {
- bytesRead += gzread(gzf, &(x[j]), sizeof( (x[j]) ) );
- }
- vertset[i] = ntlVec3Gfx(x[0],x[1],x[2]);
- if(debugPrintFull) errMsg("FUL2V"," "<<i<<" "<< vertset[i] );
- }
- if(debugPrint) errMsg("ANI_VV"," "<<numVerts<<" "<< vertset.size()<<" bytes:"<<bytesRead );
-
- bytesRead += gzread(gzf, &numNorms2, sizeof(numNorms2) );
- for(int i=0; i<numVerts; i++) {
- for(int j=0; j<3; j++) {
- bytesRead += gzread(gzf, &(x[j]), sizeof( (x[j]) ) );
- }
- normset[i] = ntlVec3Gfx(x[0],x[1],x[2]);
- if(debugPrintFull) errMsg("FUL2N"," "<<i<<" "<< normset[i] );
- }
- if(debugPrint) errMsg("ANI_NV"," "<<numVerts<<","<<numVerts2<<","<<numNorms2<<","<< normset.size()<<" bytes:"<<bytesRead );
-
- // set ok
- if(bytesRead== (int)( (numVerts*2*3+1) *sizeof(float)+2*sizeof(int) ) ) {
- if(aniverts.size()==0) {
- // TODO, ignore first mesh?
- double anitime = (double)(frameTime-1.); // start offset!? anitimes.size();
- // get for current frame entry
- if(mcAniTimes.getSize()>1) anitime = mcAniTimes.get(anitime);
- anitime = anitime*mAniTimeScale+mAniTimeOffset;
-
- anitimes.push_back( anitime );
- aniverts.push_back( ntlSetVec3f(mVertices) );
- aninorms.push_back( ntlSetVec3f(mNormals) );
- if(debugPrint) errMsg("ANI_NV","new set "<<mVertices.size()<<","<< mNormals.size()<<" time:"<<anitime );
- }
- double anitime = (double)(frameTime); //anitimes.size();
- // get for current frame entry
- if(mcAniTimes.getSize()>1) anitime = mcAniTimes.get(anitime);
- anitime = anitime*mAniTimeScale+mAniTimeOffset;
-
- anitimes.push_back( anitime );
- aniverts.push_back( ntlSetVec3f(vertset) );
- aninorms.push_back( ntlSetVec3f(normset) );
- if(debugPrint) errMsg("ANI_NV","new set "<<vertset.size()<<","<< normset.size()<<" time:"<<anitime );
- } else {
- errMsg("ntlGeometryObjModel::loadBobjModel","Malformed ani set! Aborting... ("<<bytesRead<<") ");
- goto gzreaddone;
- }
- } // anim sets */
-
-gzreaddone:
-
- if(haveAniSets) {
- debMsgStd("ntlGeometryObjModel::loadBobjModel",DM_MSG, "File '"<<filename<<"' ani sets loaded: "<< mcAniVerts.accessValues().size() <<","<<mcAniNorms.accessValues().size() <<" ", 1 );
- }
- gzclose( gzf );
- return 0;
-
-gzreaderror:
- mTriangles.clear();
- mVertices.clear();
- mNormals.clear();
- gzclose( gzf );
- errFatal("ntlGeometryObjModel::loadBobjModel","Reading GZ_BOBJ, Unable to load '"<< filename <<"', exiting...\n", SIMWORLD_INITERROR );
- return 1;
-}
-
-
-/******************************************************************************
- *
- *****************************************************************************/
-void
-ntlGeometryObjModel::getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId )
-{
- if(!mLoaded) { // invalid type...
- return;
- }
- if(mcAniVerts.getSize()>1) { mVertices = mcAniVerts.get(t).mVerts; }
- if(mcAniNorms.getSize()>1) { mNormals = mcAniNorms.get(t).mVerts; }
-
- int startvert = vertices->size();
- vertices->resize( vertices->size() + mVertices.size() );
- normals->resize( normals->size() + mVertices.size() );
- for(int i=0; i<(int)mVertices.size(); i++) {
- (*vertices)[startvert+i] = mVertices[i];
- (*normals)[startvert+i] = mNormals[i];
- }
-
- triangles->reserve(triangles->size() + mTriangles.size()/3 );
- for(int i=0; i<(int)mTriangles.size(); i+=3) {
- int trip[3];
- trip[0] = startvert+mTriangles[i+0];
- trip[1] = startvert+mTriangles[i+1];
- trip[2] = startvert+mTriangles[i+2];
-
- //sceneAddTriangle(
- //mVertices[trip[0]], mVertices[trip[1]], mVertices[trip[2]],
- //mNormals[trip[0]], mNormals[trip[1]], mNormals[trip[2]],
- //ntlVec3Gfx(0.0), 1 , triangles,vertices,normals ); /* normal unused */
- sceneAddTriangleNoVert( trip, ntlVec3Gfx(0.0), 1 , triangles ); /* normal unused */
- }
- objectId = -1; // remove warning
- // bobj
- return;
-}
-
-
-
-
-
diff --git a/intern/elbeem/intern/ntl_geometrymodel.h b/intern/elbeem/intern/ntl_geometrymodel.h
deleted file mode 100644
index a5f26ba17b8..00000000000
--- a/intern/elbeem/intern/ntl_geometrymodel.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * A model laoded from Wavefront .obj file
- *
- *****************************************************************************/
-#ifndef NTL_GEOMODEL_H
-#define NTL_GEOMODEL_H
-
-#include "ntl_geometryobject.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-/*! A simple box object generatedd by 12 triangles */
-class ntlGeometryObjModel : public ntlGeometryObject
-{
- public:
- /* Init constructor */
- ntlGeometryObjModel( void );
- /* Init constructor */
- //ntlGeometryObjModel( ntlVec3Gfx start, ntlVec3Gfx end );
- /* Destructor */
- virtual ~ntlGeometryObjModel( void );
-
- //! Return type id
- virtual int getTypeId() { return GEOCLASSTID_OBJMODEL; }
-
- /*! Filename setting etc. */
- virtual void initialize(ntlRenderGlobals *glob);
-
- /*! is the mesh animated? */
- virtual bool getMeshAnimated();
-
- /* create triangles from obj */
- virtual void getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId );
-
- /*! load model from .bobj file, returns !=0 upon error */
- int loadBobjModel(string filename);
- /*! init model from given vertex and triangle arrays */
- int initModel(int numVertices, float *vertices, int numTriangles, int *triangles,
- int channelSize, float *channelVertices);
- /*! init triangle divisions */
- virtual void calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntlTriangle> &tris, gfxReal fsTri);
-
- /*! calculate max extends of (ani) mesh */
- void getExtends(ntlVec3Gfx &start, ntlVec3Gfx &end);
-
- private:
-
- /*! Start and end points of box */
- ntlVec3Gfx mvStart, mvEnd;
-
- /*! was the model loaded? */
- bool mLoaded;
-
- /*! filename of the obj file */
- string mFilename;
-
- /*! for bobj models */
- vector<int> mTriangles;
- vector<ntlVec3Gfx> mVertices;
- vector<ntlVec3Gfx> mNormals;
-
- /*! animated channels for vertices, if given will override getris by default */
- AnimChannel<ntlSetVec3f> mcAniVerts;
- AnimChannel<ntlSetVec3f> mcAniNorms;
- /*! map entrie of anim mesh to sim times */
- AnimChannel<double> mcAniTimes;
- /*! timing mapping & offset for config files */
- double mAniTimeScale, mAniTimeOffset;
-
- public:
-
- /* Access methods */
- /*! Access start vector */
- inline ntlVec3Gfx getStart( void ){ return mvStart; }
- inline void setStart( const ntlVec3Gfx &set ){ mvStart = set; }
- /*! Access end vector */
- inline ntlVec3Gfx getEnd( void ){ return mvEnd; }
- inline void setEnd( const ntlVec3Gfx &set ){ mvEnd = set; }
-
- inline bool getLoaded( void ){ return mLoaded; }
- inline void setLoaded( bool set ){ mLoaded = set; }
-
- /*! set data file name */
- inline void setFilename(string set) { mFilename = set; }
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlGeometryObjModel")
-#endif
-};
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_geometryobject.cpp b/intern/elbeem/intern/ntl_geometryobject.cpp
deleted file mode 100644
index 7eb2df4ad3f..00000000000
--- a/intern/elbeem/intern/ntl_geometryobject.cpp
+++ /dev/null
@@ -1,806 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * a geometry object
- * all other geometry objects are derived from this one
- *
- *****************************************************************************/
-
-
-#include "ntl_geometryobject.h"
-#include "ntl_world.h"
-#include "ntl_matrices.h"
-
-// for FGI
-#include "elbeem.h"
-
-#define TRI_UVOFFSET (1./4.)
-//#define TRI_UVOFFSET (1./3.)
-
-
-/*****************************************************************************/
-/* Default constructor */
-/*****************************************************************************/
-ntlGeometryObject::ntlGeometryObject() :
- mIsInitialized(false), mpMaterial( NULL ),
- mMaterialName( "default" ),
- mCastShadows( 1 ), mReceiveShadows( 1 ),
- mGeoInitType( 0 ),
- mInitialVelocity(0.0), mcInitialVelocity(0.0), mLocalCoordInivel(false),
- mGeoInitIntersect(false),
- mGeoPartSlipValue(0.0),
- mcGeoImpactFactor(1.),
- mVolumeInit(VOLUMEINIT_VOLUME),
- mInitialPos(0.),
- mcTrans(0.), mcRot(0.), mcScale(1.),
- mIsAnimated(false),
- mMovPoints(), mMovNormals(),
- mHaveCachedMov(false),
- mCachedMovPoints(), mCachedMovNormals(),
- mTriangleDivs1(), mTriangleDivs2(),
- mMovPntsInited(-100.0), mMaxMovPnt(-1),
- mcGeoActive(1.),
- mCpsTimeStart(0.), mCpsTimeEnd(1.0), mCpsQuality(10.),
- mcAttrFStr(0.),mcAttrFRad(0.), mcVelFStr(0.), mcVelFRad(0.)
-{
-};
-
-
-/*****************************************************************************/
-/* Default destructor */
-/*****************************************************************************/
-ntlGeometryObject::~ntlGeometryObject()
-{
-}
-
-/*! is the mesh animated? */
-bool ntlGeometryObject::getMeshAnimated() {
- // off by default, on for e.g. ntlGeometryObjModel
- return false;
-}
-
-/*! init object anim flag */
-bool ntlGeometryObject::checkIsAnimated() {
- if( (mcTrans.accessValues().size()>1) // VALIDATE
- || (mcRot.accessValues().size()>1)
- || (mcScale.accessValues().size()>1)
- || (mcGeoActive.accessValues().size()>1)
- // mcGeoImpactFactor only needed when moving
- || (mcInitialVelocity.accessValues().size()>1)
- ) {
- mIsAnimated = true;
- }
-
- // fluid objects always have static init!
- if(mGeoInitType==FGI_FLUID) {
- mIsAnimated=false;
- }
- //errMsg("ntlGeometryObject::checkIsAnimated","obj="<<getName()<<" debug: trans:"<<mcTrans.accessValues().size()<<" rot:"<<mcRot.accessValues().size()<<" scale:"<<mcScale.accessValues().size()<<" active:"<<mcGeoActive.accessValues().size()<<" inivel:"<<mcInitialVelocity.accessValues().size()<<". isani?"<<mIsAnimated ); // DEBUG
- return mIsAnimated;
-}
-
-/*****************************************************************************/
-/* Init attributes etc. of this object */
-/*****************************************************************************/
-#define GEOINIT_STRINGS 10
-static const char *initStringStrs[GEOINIT_STRINGS] = {
- "fluid",
- "bnd_no","bnd_noslip",
- "bnd_free","bnd_freeslip",
- "bnd_part","bnd_partslip",
- "inflow", "outflow", "control",
-};
-static int initStringTypes[GEOINIT_STRINGS] = {
- FGI_FLUID,
- FGI_BNDNO, FGI_BNDNO,
- FGI_BNDFREE, FGI_BNDFREE,
- FGI_BNDPART, FGI_BNDPART,
- FGI_MBNDINFLOW, FGI_MBNDOUTFLOW,
- FGI_CONTROL
-};
-void ntlGeometryObject::initialize(ntlRenderGlobals *glob)
-{
- //debugOut("ntlGeometryObject::initialize: '"<<getName()<<"' ", 10);
- // initialize only once...
- if(mIsInitialized) return;
-
- // init material, always necessary
- searchMaterial( glob->getMaterials() );
-
- this->mGeoInitId = mpAttrs->readInt("geoinitid", this->mGeoInitId,"ntlGeometryObject", "mGeoInitId", false);
- mGeoInitIntersect = mpAttrs->readInt("geoinit_intersect", mGeoInitIntersect,"ntlGeometryObject", "mGeoInitIntersect", false);
- string ginitStr = mpAttrs->readString("geoinittype", "", "ntlGeometryObject", "mGeoInitType", false);
- if(this->mGeoInitId>=0) {
- bool gotit = false;
- for(int i=0; i<GEOINIT_STRINGS; i++) {
- if(ginitStr== initStringStrs[i]) {
- gotit = true;
- mGeoInitType = initStringTypes[i];
- }
- }
-
- if(!gotit) {
- errFatal("ntlGeometryObject::initialize","Obj '"<<mName<<"', Unknown 'geoinittype' value: '"<< ginitStr <<"' ", SIMWORLD_INITERROR);
- return;
- }
- }
-
- int geoActive = mpAttrs->readInt("geoinitactive", 1,"ntlGeometryObject", "geoActive", false);
- if(!geoActive) {
- // disable geo init again...
- this->mGeoInitId = -1;
- }
- mInitialVelocity = vec2G( mpAttrs->readVec3d("initial_velocity", vec2D(mInitialVelocity),"ntlGeometryObject", "mInitialVelocity", false));
- if(getAttributeList()->exists("initial_velocity") || (!mcInitialVelocity.isInited()) ) {
- mcInitialVelocity = mpAttrs->readChannelVec3f("initial_velocity");
- }
- // always use channel
- if(!mcInitialVelocity.isInited()) { mcInitialVelocity = AnimChannel<ntlVec3Gfx>(mInitialVelocity); }
- mLocalCoordInivel = mpAttrs->readBool("geoinit_localinivel", mLocalCoordInivel,"ntlGeometryObject", "mLocalCoordInivel", false);
-
- mGeoPartSlipValue = mpAttrs->readFloat("geoinit_partslip", mGeoPartSlipValue,"ntlGeometryObject", "mGeoPartSlipValue", false);
- bool mOnlyThinInit = false; // deprecated!
- mOnlyThinInit = mpAttrs->readBool("geoinit_onlythin", mOnlyThinInit,"ntlGeometryObject", "mOnlyThinInit", false);
- if(mOnlyThinInit) mVolumeInit = VOLUMEINIT_SHELL;
- mVolumeInit = mpAttrs->readInt("geoinit_volumeinit", mVolumeInit,"ntlGeometryObject", "mVolumeInit", false);
- if((mVolumeInit<VOLUMEINIT_VOLUME)||(mVolumeInit>VOLUMEINIT_BOTH)) mVolumeInit = VOLUMEINIT_VOLUME;
-
- // moving obs correction factor
- float impactfactor=1.;
- impactfactor = (float)mpAttrs->readFloat("impactfactor", impactfactor,"ntlGeometryObject", "impactfactor", false);
- if(getAttributeList()->exists("impactfactor") || (!mcGeoImpactFactor.isInited()) ) {
- mcGeoImpactFactor = mpAttrs->readChannelSinglePrecFloat("impactfactor");
- }
-
- // override cfg types
- mVisible = mpAttrs->readBool("visible", mVisible,"ntlGeometryObject", "mVisible", false);
- mReceiveShadows = mpAttrs->readBool("recv_shad", mReceiveShadows,"ntlGeometryObject", "mReceiveShadows", false);
- mCastShadows = mpAttrs->readBool("cast_shad", mCastShadows,"ntlGeometryObject", "mCastShadows", false);
-
- // read mesh animation channels
- ntlVec3d translation(0.0);
- translation = mpAttrs->readVec3d("translation", translation,"ntlGeometryObject", "translation", false);
- if(getAttributeList()->exists("translation") || (!mcTrans.isInited()) ) {
- mcTrans = mpAttrs->readChannelVec3f("translation");
- }
- ntlVec3d rotation(0.0);
- rotation = mpAttrs->readVec3d("rotation", rotation,"ntlGeometryObject", "rotation", false);
- if(getAttributeList()->exists("rotation") || (!mcRot.isInited()) ) {
- mcRot = mpAttrs->readChannelVec3f("rotation");
- }
- ntlVec3d scale(1.0);
- scale = mpAttrs->readVec3d("scale", scale,"ntlGeometryObject", "scale", false);
- if(getAttributeList()->exists("scale") || (!mcScale.isInited()) ) {
- mcScale = mpAttrs->readChannelVec3f("scale");
- }
-
- float geoactive=1.;
- geoactive = (float)mpAttrs->readFloat("geoactive", geoactive,"ntlGeometryObject", "geoactive", false);
- if(getAttributeList()->exists("geoactive") || (!mcGeoActive.isInited()) ) {
- mcGeoActive = mpAttrs->readChannelSinglePrecFloat("geoactive");
- }
- // always use channel
- if(!mcGeoActive.isInited()) { mcGeoActive = AnimChannel<float>(geoactive); }
-
- checkIsAnimated();
-
- mIsInitialized = true;
- debMsgStd("ntlGeometryObject::initialize",DM_MSG,"GeoObj '"<<this->getName()<<"': visible="<<this->mVisible<<" gid="<<this->mGeoInitId<<" gtype="<<mGeoInitType<<","<<ginitStr<<
- " gvel="<<mInitialVelocity<<" gisect="<<mGeoInitIntersect, 10); // debug
-}
-
-/*! notify object that dump is in progress (e.g. for particles) */
-// default action - do nothing...
-void ntlGeometryObject::notifyOfDump(int dumtp, int frameNr,char *frameNrStr,string outfilename, double simtime) {
- bool debugOut=false;
- if(debugOut) debMsgStd("ntlGeometryObject::notifyOfDump",DM_MSG," dt:"<<dumtp<<" obj:"<<this->getName()<<" frame:"<<frameNrStr<<","<<frameNr<<",t"<<simtime<<" to "<<outfilename, 10); // DEBUG
-}
-
-/*****************************************************************************/
-/* Search the material for this object from the material list */
-/*****************************************************************************/
-void ntlGeometryObject::searchMaterial(vector<ntlMaterial *> *mat)
-{
- /* search the list... */
- int i=0;
- for (vector<ntlMaterial*>::iterator iter = mat->begin();
- iter != mat->end(); iter++) {
- if( mMaterialName == (*iter)->getName() ) {
- //warnMsg("ntlGeometryObject::searchMaterial","for obj '"<<getName()<<"' found - '"<<(*iter)->getName()<<"' "<<i); // DEBUG
- mpMaterial = (*iter);
- return;
- }
- i++;
- }
- errFatal("ntlGeometryObject::searchMaterial","Unknown material '"<<mMaterialName<<"' ! ", SIMWORLD_INITERROR);
- mpMaterial = new ntlMaterial();
- return;
-}
-
-/******************************************************************************
- * static add triangle function
- *****************************************************************************/
-void ntlGeometryObject::sceneAddTriangle(
- ntlVec3Gfx p1,ntlVec3Gfx p2,ntlVec3Gfx p3,
- ntlVec3Gfx pn1,ntlVec3Gfx pn2,ntlVec3Gfx pn3,
- ntlVec3Gfx trin, bool smooth,
- vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals) {
- ntlTriangle tri;
- int tempVert;
-
- if(normals->size() != vertices->size()) {
- errFatal("ntlGeometryObject::sceneAddTriangle","For '"<<this->mName<<"': Vertices and normals sizes to not match!!!",SIMWORLD_GENERICERROR);
-
- } else {
-
- vertices->push_back( p1 );
- normals->push_back( pn1 );
- tempVert = normals->size()-1;
- tri.getPoints()[0] = tempVert;
-
- vertices->push_back( p2 );
- normals->push_back( pn2 );
- tempVert = normals->size()-1;
- tri.getPoints()[1] = tempVert;
-
- vertices->push_back( p3 );
- normals->push_back( pn3 );
- tempVert = normals->size()-1;
- tri.getPoints()[2] = tempVert;
-
-
- /* init flags from ntl_ray.h */
- int flag = 0;
- if(getVisible()){ flag |= TRI_GEOMETRY; }
- if(getCastShadows() ) {
- flag |= TRI_CASTSHADOWS; }
-
- /* init geo init id */
- int geoiId = getGeoInitId();
- //if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME) && (!mIsAnimated)) {
- if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME)) {
- flag |= (1<< (geoiId+4));
- flag |= mGeoInitType;
- }
- /*errMsg("ntlScene::addTriangle","DEBUG flag="<<convertFlags2String(flag) ); */
- tri.setFlags( flag );
-
- /* triangle normal missing */
- tri.setNormal( trin );
- tri.setSmoothNormals( smooth );
- tri.setObjectId( this->mObjectId );
- triangles->push_back( tri );
- } /* normals check*/
-}
-
-void ntlGeometryObject::sceneAddTriangleNoVert(int *trips,
- ntlVec3Gfx trin, bool smooth,
- vector<ntlTriangle> *triangles) {
- ntlTriangle tri;
-
- tri.getPoints()[0] = trips[0];
- tri.getPoints()[1] = trips[1];
- tri.getPoints()[2] = trips[2];
-
- // same as normal sceneAddTriangle
-
- /* init flags from ntl_ray.h */
- int flag = 0;
- if(getVisible()){ flag |= TRI_GEOMETRY; }
- if(getCastShadows() ) {
- flag |= TRI_CASTSHADOWS; }
-
- /* init geo init id */
- int geoiId = getGeoInitId();
- if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME)) {
- flag |= (1<< (geoiId+4));
- flag |= mGeoInitType;
- }
- /*errMsg("ntlScene::addTriangle","DEBUG flag="<<convertFlags2String(flag) ); */
- tri.setFlags( flag );
-
- /* triangle normal missing */
- tri.setNormal( trin );
- tri.setSmoothNormals( smooth );
- tri.setObjectId( this->mObjectId );
- triangles->push_back( tri );
-}
-
-
-/******************************************************************************/
-/* Init channels from float arrays (for elbeem API) */
-/******************************************************************************/
-
-#define ADD_CHANNEL_VEC(dst,nvals,val) \
- vals.clear(); time.clear(); elbeemSimplifyChannelVec3(val,&nvals); \
- for(int i=0; i<(nvals); i++) { \
- vals.push_back(ntlVec3Gfx((val)[i*4+0], (val)[i*4+1],(val)[i*4+2] )); \
- time.push_back( (val)[i*4+3] ); \
- } \
- (dst) = AnimChannel< ntlVec3Gfx >(vals,time);
-
-#define ADD_CHANNEL_FLOAT(dst,nvals,val) \
- valsfloat.clear(); time.clear(); elbeemSimplifyChannelFloat(val,&nvals); \
- for(int i=0; i<(nvals); i++) { \
- valsfloat.push_back( (val)[i*2+0] ); \
- time.push_back( (val)[i*2+1] ); \
- } \
- (dst) = AnimChannel< float >(valsfloat,time);
-
-void ntlGeometryObject::initChannels(
- int nTrans, float *trans, int nRot, float *rot, int nScale, float *scale,
- int nAct, float *act, int nIvel, float *ivel,
- int nAttrFStr, float *attrFStr,
- int nAttrFRad, float *attrFRad,
- int nVelFStr, float *velFStr,
- int nVelFRad, float *velFRad
- ) {
- const bool debugInitc=true;
- if(debugInitc) { debMsgStd("ntlGeometryObject::initChannels",DM_MSG,"nt:"<<nTrans<<" nr:"<<nRot<<" ns:"<<nScale, 10);
- debMsgStd("ntlGeometryObject::initChannels",DM_MSG,"na:"<<nAct<<" niv:"<<nIvel<<" ", 10); }
- vector<ntlVec3Gfx> vals;
- vector<float> valsfloat;
- vector<double> time;
- if((trans)&&(nTrans>0)) { ADD_CHANNEL_VEC(mcTrans, nTrans, trans); }
- if((rot)&&(nRot>0)) { ADD_CHANNEL_VEC(mcRot, nRot, rot); }
- if((scale)&&(nScale>0)) { ADD_CHANNEL_VEC(mcScale, nScale, scale); }
- if((act)&&(nAct>0)) { ADD_CHANNEL_FLOAT(mcGeoActive, nAct, act); }
- if((ivel)&&(nIvel>0)) { ADD_CHANNEL_VEC(mcInitialVelocity, nIvel, ivel); }
-
- /* fluid control channels */
- if((attrFStr)&&(nAttrFStr>0)) { ADD_CHANNEL_FLOAT(mcAttrFStr, nAttrFStr, attrFStr); }
- if((attrFRad)&&(nAttrFRad>0)) { ADD_CHANNEL_FLOAT(mcAttrFRad, nAttrFRad, attrFRad); }
- if((velFStr)&&(nVelFStr>0)) { ADD_CHANNEL_FLOAT(mcVelFStr, nAct, velFStr); }
- if((velFRad)&&(nVelFRad>0)) { ADD_CHANNEL_FLOAT(mcVelFRad, nVelFRad, velFRad); }
-
- checkIsAnimated();
-
- if(debugInitc) {
- debMsgStd("ntlGeometryObject::initChannels",DM_MSG,getName()<<
- " nt:"<<mcTrans.accessValues().size()<<" nr:"<<mcRot.accessValues().size()<<
- " ns:"<<mcScale.accessValues().size()<<" isAnim:"<<mIsAnimated, 10); }
-
- if(debugInitc) {
- std::ostringstream ostr;
- ostr << "trans: ";
- for(size_t i=0; i<mcTrans.accessValues().size(); i++) {
- ostr<<" "<<mcTrans.accessValues()[i]<<"@"<<mcTrans.accessTimes()[i]<<" ";
- } ostr<<"; ";
- ostr<<"rot: ";
- for(size_t i=0; i<mcRot.accessValues().size(); i++) {
- ostr<<" "<<mcRot.accessValues()[i]<<"@"<<mcRot.accessTimes()[i]<<" ";
- } ostr<<"; ";
- ostr<<"scale: ";
- for(size_t i=0; i<mcScale.accessValues().size(); i++) {
- ostr<<" "<<mcScale.accessValues()[i]<<"@"<<mcScale.accessTimes()[i]<<" ";
- } ostr<<"; ";
- ostr<<"act: ";
- for(size_t i=0; i<mcGeoActive.accessValues().size(); i++) {
- ostr<<" "<<mcGeoActive.accessValues()[i]<<"@"<<mcGeoActive.accessTimes()[i]<<" ";
- } ostr<<"; ";
- ostr<<"ivel: ";
- for(size_t i=0; i<mcInitialVelocity.accessValues().size(); i++) {
- ostr<<" "<<mcInitialVelocity.accessValues()[i]<<"@"<<mcInitialVelocity.accessTimes()[i]<<" ";
- } ostr<<"; ";
- debMsgStd("ntlGeometryObject::initChannels",DM_MSG,"Inited "<<ostr.str(),10);
- }
-}
-#undef ADD_CHANNEL
-
-
-/*****************************************************************************/
-/* apply object translation at time t*/
-/*****************************************************************************/
-void ntlGeometryObject::applyTransformation(double t, vector<ntlVec3Gfx> *verts, vector<ntlVec3Gfx> *norms, int vstart, int vend, int forceTrafo) {
- if( (mcTrans.accessValues().size()>1) // VALIDATE
- || (mcRot.accessValues().size()>1)
- || (mcScale.accessValues().size()>1)
- || (forceTrafo)
- || (!mHaveCachedMov)
- ) {
- // transformation is animated, continue
- ntlVec3Gfx pos = getTranslation(t);
- ntlVec3Gfx scale = mcScale.get(t);
- ntlVec3Gfx rot = mcRot.get(t);
- ntlMat4Gfx rotMat;
- rotMat.initRotationXYZ(rot[0],rot[1],rot[2]);
- pos += mInitialPos;
- errMsg("ntlGeometryObject::applyTransformation","obj="<<getName()<<" t"<<pos<<" r"<<rot<<" s"<<scale);
- for(int i=vstart; i<vend; i++) {
- (*verts)[i] *= scale;
- (*verts)[i] = rotMat * (*verts)[i];
- (*verts)[i] += pos;
- //if(i<10) errMsg("ntlGeometryObject::applyTransformation"," v"<<i<<"/"<<vend<<"="<<(*verts)[i]);
- }
- if(norms) {
- for(int i=vstart; i<vend; i++) {
- (*norms)[i] = rotMat * (*norms)[i];
- }
- }
- } else {
- // not animated, cached points were already returned
- errMsg ("ntlGeometryObject::applyTransformation","Object "<<getName()<<" used cached points ");
- }
-}
-
-/*! init triangle divisions */
-void ntlGeometryObject::calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntlTriangle> &tris, gfxReal fsTri) {
- mTriangleDivs1.resize( tris.size() );
- mTriangleDivs2.resize( tris.size() );
-
- //fsTri *= 2.; // DEBUG! , wrong init!
-
- for(size_t i=0; i<tris.size(); i++) {
- const ntlVec3Gfx p0 = verts[ tris[i].getPoints()[0] ];
- const ntlVec3Gfx p1 = verts[ tris[i].getPoints()[1] ];
- const ntlVec3Gfx p2 = verts[ tris[i].getPoints()[2] ];
- const ntlVec3Gfx side1 = p1 - p0;
- const ntlVec3Gfx side2 = p2 - p0;
- int divs1=0, divs2=0;
- if(normNoSqrt(side1) > fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); }
- if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); }
-
- mTriangleDivs1[i] = divs1;
- mTriangleDivs2[i] = divs2;
- }
-}
-
-/*! Prepare points for moving objects */
-void ntlGeometryObject::initMovingPoints(double time, gfxReal featureSize) {
- if((mMovPntsInited==featureSize)&&(!getMeshAnimated())) return;
- const bool debugMoinit=false;
-
- vector<ntlTriangle> triangles;
- vector<ntlVec3Gfx> vertices;
- vector<ntlVec3Gfx> vnormals;
- int objectId = 1;
- this->getTriangles(time, &triangles,&vertices,&vnormals,objectId);
-
- mMovPoints.clear();
- mMovNormals.clear();
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","Object "<<getName()<<" has v:"<<vertices.size()<<" t:"<<triangles.size() );
- // no points?
- if(vertices.size()<1) {
- mMaxMovPnt=-1;
- return;
- }
- ntlVec3f maxscale = channelFindMaxVf(mcScale);
- float maxpart = ABS(maxscale[0]);
- if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
- if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
- float scaleFac = 1.0/(maxpart);
- // TODO - better reinit from time to time?
- const gfxReal fsTri = featureSize*0.5 *scaleFac;
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","maxscale:"<<maxpart<<" featureSize:"<<featureSize<<" fsTri:"<<fsTri );
-
- if(mTriangleDivs1.size()!=triangles.size()) {
- calcTriangleDivs(vertices,triangles,fsTri);
- }
-
- // debug: count points to init
- /*if(debugMoinit) {
- errMsg("ntlGeometryObject::initMovingPoints","Object "<<getName()<<" estimating...");
- int countp=vertices.size()*2;
- for(size_t i=0; i<triangles.size(); i++) {
- ntlVec3Gfx p0 = vertices[ triangles[i].getPoints()[0] ];
- ntlVec3Gfx side1 = vertices[ triangles[i].getPoints()[1] ] - p0;
- ntlVec3Gfx side2 = vertices[ triangles[i].getPoints()[2] ] - p0;
- int divs1=0, divs2=0;
- if(normNoSqrt(side1) > fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); }
- if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); }
- errMsg("ntlGeometryObject::initMovingPoints","tri:"<<i<<" p:"<<p0<<" s1:"<<side1<<" s2:"<<side2<<" -> "<<divs1<<","<<divs2 );
- if(divs1+divs2 > 0) {
- for(int u=0; u<=divs1; u++) {
- for(int v=0; v<=divs2; v++) {
- const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0);
- const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0);
- if(uf+vf>1.0) continue;
- countp+=2;
- }
- }
- }
- }
- errMsg("ntlGeometryObject::initMovingPoints","Object "<<getName()<<" requires:"<<countp*2);
- } // */
-
- bool discardInflowBack = false;
- if( (mGeoInitType==FGI_MBNDINFLOW) && (mcInitialVelocity.accessValues().size()<1) ) discardInflowBack = true;
- discardInflowBack = false; // DEBUG disable for now
-
-
- // init std points
- for(size_t i=0; i<vertices.size(); i++) {
- ntlVec3Gfx p = vertices[ i ];
- ntlVec3Gfx n = vnormals[ i ];
- // discard inflow backsides
- //if( (mGeoInitType==FGI_MBNDINFLOW) && (!mIsAnimated)) {
- if(discardInflowBack) { //if( (mGeoInitType==FGI_MBNDINFLOW) && (!mIsAnimated)) {
- if(dot(mInitialVelocity,n)<0.0) continue;
- }
- mMovPoints.push_back(p);
- mMovNormals.push_back(n);
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","std"<<i<<" p"<<p<<" n"<<n<<" ");
- }
- // init points & refine...
- for(size_t i=0; i<triangles.size(); i++) {
- int *trips = triangles[i].getPoints();
- const ntlVec3Gfx p0 = vertices[ trips[0] ];
- const ntlVec3Gfx side1 = vertices[ trips[1] ] - p0;
- const ntlVec3Gfx side2 = vertices[ trips[2] ] - p0;
- int divs1=mTriangleDivs1[i], divs2=mTriangleDivs2[i];
-
- const ntlVec3Gfx trinormOrg = getNormalized(cross(side1,side2));
- const ntlVec3Gfx trinorm = trinormOrg*0.25*featureSize;
- if(discardInflowBack) {
- if(dot(mInitialVelocity,trinorm)<0.0) continue;
- }
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","Tri1 "<<vertices[trips[0]]<<","<<vertices[trips[1]]<<","<<vertices[trips[2]]<<" "<<divs1<<","<<divs2 );
- if(divs1+divs2 > 0) {
- for(int u=0; u<=divs1; u++) {
- for(int v=0; v<=divs2; v++) {
- const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0);
- const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0);
- if(uf+vf>1.0) continue;
- ntlVec3Gfx p =
- vertices[ trips[0] ] * (1.0-uf-vf)+
- vertices[ trips[1] ] * uf +
- vertices[ trips[2] ] * vf;
- //ntlVec3Gfx n = vnormals[
- //trips[0] ] * (1.0-uf-vf)+
- //vnormals[ trips[1] ]*uf +
- //vnormals[ trips[2] ]*vf;
- //normalize(n);
- // discard inflow backsides
-
- mMovPoints.push_back(p + trinorm); // NEW!?
- mMovPoints.push_back(p - trinorm);
- mMovNormals.push_back(trinormOrg);
- mMovNormals.push_back(trinormOrg);
- //errMsg("TRINORM","p"<<p<<" n"<<n<<" trin"<<trinorm);
- }
- }
- }
- }
-
- // find max point
- mMaxMovPnt = 0;
- gfxReal dist = normNoSqrt(mMovPoints[0]);
- for(size_t i=0; i<mMovPoints.size(); i++) {
- if(normNoSqrt(mMovPoints[i])>dist) {
- mMaxMovPnt = i;
- dist = normNoSqrt(mMovPoints[0]);
- }
- }
-
- if( (this->getMeshAnimated())
- || (mcTrans.accessValues().size()>1) // VALIDATE
- || (mcRot.accessValues().size()>1)
- || (mcScale.accessValues().size()>1)
- ) {
- // also do trafo...
- } else {
- mCachedMovPoints = mMovPoints;
- mCachedMovNormals = mMovNormals;
- //applyTransformation(time, &mCachedMovPoints, &mCachedMovNormals, 0, mCachedMovPoints.size(), true);
- applyTransformation(time, &mCachedMovPoints, NULL, 0, mCachedMovPoints.size(), true);
- mHaveCachedMov = true;
- debMsgStd("ntlGeometryObject::initMovingPoints",DM_MSG,"Object "<<getName()<<" cached points ", 7);
- }
-
- mMovPntsInited = featureSize;
- debMsgStd("ntlGeometryObject::initMovingPoints",DM_MSG,"Object "<<getName()<<" inited v:"<<vertices.size()<<"->"<<mMovPoints.size() , 5);
-}
-/*! Prepare points for animated objects,
- * init both sets, never used cached points
- * discardInflowBack ignore */
-void ntlGeometryObject::initMovingPointsAnim(
- double srctime, vector<ntlVec3Gfx> &srcmovPoints,
- double dsttime, vector<ntlVec3Gfx> &dstmovPoints,
- vector<ntlVec3Gfx> *dstmovNormals,
- gfxReal featureSize,
- ntlVec3Gfx geostart, ntlVec3Gfx geoend
- ) {
- const bool debugMoinit=false;
-
- vector<ntlTriangle> srctriangles;
- vector<ntlVec3Gfx> srcvertices;
- vector<ntlVec3Gfx> unused_normals;
- vector<ntlTriangle> dsttriangles;
- vector<ntlVec3Gfx> dstvertices;
- vector<ntlVec3Gfx> dstnormals;
- int objectId = 1;
- // TODO optimize? , get rid of normals?
- unused_normals.clear();
- this->getTriangles(srctime, &srctriangles,&srcvertices,&unused_normals,objectId);
- unused_normals.clear();
- this->getTriangles(dsttime, &dsttriangles,&dstvertices,&dstnormals,objectId);
-
- srcmovPoints.clear();
- dstmovPoints.clear();
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","Object "<<getName()<<" has srcv:"<<srcvertices.size()<<" srct:"<<srctriangles.size() );
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","Object "<<getName()<<" has dstv:"<<dstvertices.size()<<" dstt:"<<dsttriangles.size() );
- // no points?
- if(srcvertices.size()<1) {
- mMaxMovPnt=-1;
- return;
- }
- if((srctriangles.size() != dsttriangles.size()) ||
- (srcvertices.size() != dstvertices.size()) ) {
- errMsg("ntlGeometryObject::initMovingPointsAnim","Invalid triangle numbers! Aborting...");
- return;
- }
- ntlVec3f maxscale = channelFindMaxVf(mcScale);
- float maxpart = ABS(maxscale[0]);
- if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
- if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
- float scaleFac = 1.0/(maxpart);
- // TODO - better reinit from time to time?
- const gfxReal fsTri = featureSize*0.5 *scaleFac;
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","maxscale:"<<maxpart<<" featureSize:"<<featureSize<<" fsTri:"<<fsTri );
-
- if(mTriangleDivs1.size()!=srctriangles.size()) {
- calcTriangleDivs(srcvertices,srctriangles,fsTri);
- }
-
-
- // init std points
- for(size_t i=0; i<srcvertices.size(); i++) {
- srcmovPoints.push_back(srcvertices[i]);
- //srcmovNormals.push_back(srcnormals[i]);
- }
- for(size_t i=0; i<dstvertices.size(); i++) {
- dstmovPoints.push_back(dstvertices[i]);
- if(dstmovNormals) (*dstmovNormals).push_back(dstnormals[i]);
- }
- if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","stats src:"<<srcmovPoints.size()<<" dst:"<<dstmovPoints.size()<<" " );
- // init points & refine...
- for(size_t i=0; i<srctriangles.size(); i++) {
- const int divs1=mTriangleDivs1[i];
- const int divs2=mTriangleDivs2[i];
- if(divs1+divs2 > 0) {
- int *srctrips = srctriangles[i].getPoints();
- int *dsttrips = dsttriangles[i].getPoints();
- const ntlVec3Gfx srcp0 = srcvertices[ srctrips[0] ];
- const ntlVec3Gfx srcside1 = srcvertices[ srctrips[1] ] - srcp0;
- const ntlVec3Gfx srcside2 = srcvertices[ srctrips[2] ] - srcp0;
- const ntlVec3Gfx dstp0 = dstvertices[ dsttrips[0] ];
- const ntlVec3Gfx dstside1 = dstvertices[ dsttrips[1] ] - dstp0;
- const ntlVec3Gfx dstside2 = dstvertices[ dsttrips[2] ] - dstp0;
- const ntlVec3Gfx src_trinorm = getNormalized(cross(srcside1,srcside2))*0.25*featureSize;
- const ntlVec3Gfx dst_trinormOrg = getNormalized(cross(dstside1,dstside2));
- const ntlVec3Gfx dst_trinorm = dst_trinormOrg *0.25*featureSize;
- //errMsg("ntlGeometryObject::initMovingPointsAnim","Tri1 "<<srcvertices[srctrips[0]]<<","<<srcvertices[srctrips[1]]<<","<<srcvertices[srctrips[2]]<<" "<<divs1<<","<<divs2 );
- for(int u=0; u<=divs1; u++) {
- for(int v=0; v<=divs2; v++) {
- const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0);
- const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0);
- if(uf+vf>1.0) continue;
- ntlVec3Gfx srcp =
- srcvertices[ srctrips[0] ] * (1.0-uf-vf)+
- srcvertices[ srctrips[1] ] * uf +
- srcvertices[ srctrips[2] ] * vf;
- ntlVec3Gfx dstp =
- dstvertices[ dsttrips[0] ] * (1.0-uf-vf)+
- dstvertices[ dsttrips[1] ] * uf +
- dstvertices[ dsttrips[2] ] * vf;
-
- // cutoffDomain
- if((srcp[0]<geostart[0]) && (dstp[0]<geostart[0])) continue;
- if((srcp[1]<geostart[1]) && (dstp[1]<geostart[1])) continue;
- if((srcp[2]<geostart[2]) && (dstp[2]<geostart[2])) continue;
- if((srcp[0]>geoend[0] ) && (dstp[0]>geoend[0] )) continue;
- if((srcp[1]>geoend[1] ) && (dstp[1]>geoend[1] )) continue;
- if((srcp[2]>geoend[2] ) && (dstp[2]>geoend[2] )) continue;
-
- srcmovPoints.push_back(srcp+src_trinorm); // SURFENHTEST
- srcmovPoints.push_back(srcp-src_trinorm);
-
- dstmovPoints.push_back(dstp+dst_trinorm); // SURFENHTEST
- dstmovPoints.push_back(dstp-dst_trinorm);
- if(dstmovNormals) {
- (*dstmovNormals).push_back(dst_trinormOrg);
- (*dstmovNormals).push_back(dst_trinormOrg); }
- }
- }
- }
- }
-
- // find max point not necessary
- debMsgStd("ntlGeometryObject::initMovingPointsAnim",DM_MSG,"Object "<<getName()<<" inited v:"<<srcvertices.size()<<"->"<<srcmovPoints.size()<<","<<dstmovPoints.size() , 5);
-}
-
-/*! Prepare points for moving objects */
-void ntlGeometryObject::getMovingPoints(vector<ntlVec3Gfx> &ret, vector<ntlVec3Gfx> *norms) {
- if(mHaveCachedMov) {
- ret = mCachedMovPoints;
- if(norms) {
- *norms = mCachedMovNormals;
- //errMsg("ntlGeometryObject","getMovingPoints - Normals currently unused!");
- }
- //errMsg ("ntlGeometryObject::getMovingPoints","Object "<<getName()<<" used cached points "); // DEBUG
- return;
- }
-
- ret = mMovPoints;
- if(norms) {
- //errMsg("ntlGeometryObject","getMovingPoints - Normals currently unused!");
- *norms = mMovNormals;
- }
-}
-
-
-/*! Calculate max. velocity on object from t1 to t2 */
-ntlVec3Gfx ntlGeometryObject::calculateMaxVel(double t1, double t2) {
- ntlVec3Gfx vel(0.);
- if(mMaxMovPnt<0) return vel;
-
- vector<ntlVec3Gfx> verts1,verts2;
- verts1.push_back(mMovPoints[mMaxMovPnt]);
- verts2 = verts1;
- applyTransformation(t1,&verts1,NULL, 0,verts1.size(), true);
- applyTransformation(t2,&verts2,NULL, 0,verts2.size(), true);
-
- vel = (verts2[0]-verts1[0]); // /(t2-t1);
- //errMsg("ntlGeometryObject::calculateMaxVel","t1="<<t1<<" t2="<<t2<<" p1="<<verts1[0]<<" p2="<<verts2[0]<<" v="<<vel);
- return vel;
-}
-
-/*! get translation at time t*/
-ntlVec3Gfx ntlGeometryObject::getTranslation(double t) {
- ntlVec3Gfx pos = mcTrans.get(t);
- // DEBUG CP_FORCECIRCLEINIT 1
- /*if(
- (mName.compare(string("0__ts1"))==0) ||
- (mName.compare(string("1__ts1"))==0) ||
- (mName.compare(string("2__ts1"))==0) ||
- (mName.compare(string("3__ts1"))==0) ||
- (mName.compare(string("4__ts1"))==0) ||
- (mName.compare(string("5__ts1"))==0) ||
- (mName.compare(string("6__ts1"))==0) ||
- (mName.compare(string("7__ts1"))==0) ||
- (mName.compare(string("8__ts1"))==0) ||
- (mName.compare(string("9__ts1"))==0)
- ) { int j=mName[0]-'0';
- ntlVec3Gfx ppos(0.); { // DEBUG
- const float tscale=10.;
- const float tprevo = 0.33;
- const ntlVec3Gfx toff(50,50,0);
- const ntlVec3Gfx oscale(30,30,0);
- ppos[0] = cos(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[0] + toff[0];
- ppos[1] = -sin(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[1] + toff[1];
- ppos[2] = toff[2]; } // DEBUG
- pos = ppos;
- pos[2] = 0.15;
- }
- // DEBUG CP_FORCECIRCLEINIT 1 */
- return pos;
-}
-/*! get active flag time t*/
-float ntlGeometryObject::getGeoActive(double t) {
- float act = (mcGeoActive.get(t) >= 1.) ? 1.0 : 0.0;
- return act;
-}
-
-void ntlGeometryObject::setInitialVelocity(ntlVec3Gfx set) {
- mInitialVelocity=set;
- mcInitialVelocity = AnimChannel<ntlVec3Gfx>(set);
-}
-ntlVec3Gfx ntlGeometryObject::getInitialVelocity(double t) {
- ntlVec3Gfx v = mcInitialVelocity.get(t); //return mInitialVelocity;
- if(!mLocalCoordInivel) return v;
-
- ntlVec3Gfx rot = mcRot.get(t);
- ntlMat4Gfx rotMat;
- rotMat.initRotationXYZ(rot[0],rot[1],rot[2]);
- v = rotMat * v;
- return v;
-}
-
-
diff --git a/intern/elbeem/intern/ntl_geometryobject.h b/intern/elbeem/intern/ntl_geometryobject.h
deleted file mode 100644
index 7e5e90d6493..00000000000
--- a/intern/elbeem/intern/ntl_geometryobject.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * a geometry object
- * all other geometry objects are derived from this one
- *
- *****************************************************************************/
-#ifndef NTL_GEOMETRYOBJECT_H
-#define NTL_GEOMETRYOBJECT_H
-
-#include "ntl_geometryclass.h"
-#include "ntl_lighting.h"
-#include "ntl_ray.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlRenderGlobals;
-class ntlTriangle;
-
-#define DUMP_FULLGEOMETRY 1
-#define DUMP_PARTIAL 2
-
-#define VOLUMEINIT_VOLUME 1
-#define VOLUMEINIT_SHELL 2
-#define VOLUMEINIT_BOTH (VOLUMEINIT_SHELL|VOLUMEINIT_VOLUME)
-
-class ntlGeometryObject : public ntlGeometryClass
-{
-
- public:
- //! Default constructor
- ntlGeometryObject();
- //! Default destructor
- virtual ~ntlGeometryObject();
-
- //! Return type id
- virtual int getTypeId() { return GEOCLASSTID_OBJECT; }
-
- /*! Init attributes etc. of this object */
- virtual void initialize(ntlRenderGlobals *glob);
-
- /*! Get the triangles from this object */
- virtual void getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId ) = 0;
-
- /*! notify object that dump is in progress (e.g. for particles) */
- virtual void notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename, double simtime);
-
- /*! Search the material for this object from the material list */
- void searchMaterial(vector<ntlMaterial *> *mat);
-
- /* Acces methods */
- /*! Set the property of this object */
- inline void setMaterial(ntlMaterial *p) { mpMaterial = p; }
- /*! Get the surface property of this object */
- inline ntlMaterial *getMaterial( void ) { return mpMaterial; }
- /*! Set the object property name */
- inline void setMaterialName(string set) { mMaterialName = set; }
- /*! Get the object property name */
- inline string getMaterialName( void ) { return mMaterialName; }
-
- /*! Sets the receive shadows attribute */
- inline void setReceiveShadows(int set) { mReceiveShadows=set; }
- /*! Returns the receive shadows attribute */
- inline int getReceiveShadows() const { return mReceiveShadows; }
-
- /*! Sets the cast shadows attribute */
- inline void setCastShadows(int set) { mCastShadows=set; }
- /*! Returns the cast shadows attribute */
- inline int getCastShadows() const { return mCastShadows; }
-
- /*! Returns the geo init typ */
- inline void setGeoInitType(int set) { mGeoInitType=set; }
- /*! Returns the geo init typ */
- inline int getGeoInitType() const { return mGeoInitType; }
-
- /*! Set/get the intersect init flag */
- inline bool getGeoInitIntersect() const { return mGeoInitIntersect; }
- inline void setGeoInitIntersect(bool set) { mGeoInitIntersect=set; }
-
- /*! Set/get the part slip value*/
- inline float getGeoPartSlipValue() const { return mGeoPartSlipValue; }
- inline void setGeoPartSlipValue(float set) { mGeoPartSlipValue=set; }
-
- /*! Set/get the impact corr factor channel */
- inline float getGeoImpactFactor(double t) { return mcGeoImpactFactor.get(t); }
- inline void setGeoImpactFactor(float set) { mcGeoImpactFactor = AnimChannel<float>(set); }
-
- /*! Set/get the part slip value*/
- inline int getVolumeInit() const { return mVolumeInit; }
- inline void setVolumeInit(int set) { mVolumeInit=set; }
-
- /*! Set/get the cast initial veocity attribute */
- void setInitialVelocity(ntlVec3Gfx set);
- ntlVec3Gfx getInitialVelocity(double t);
-
- /*! Set/get the local inivel coords flag */
- inline bool getLocalCoordInivel() const { return mLocalCoordInivel; }
- inline void setLocalCoordInivel(bool set) { mLocalCoordInivel=set; }
-
- /****************************************/
- /* fluid control features */
- /****************************************/
- /*! Set/get the particle control set attract force strength */
- inline float getCpsTimeStart() const { return mCpsTimeStart; }
- inline void setCpsTimeStart(float set) { mCpsTimeStart=set; }
-
- /*! Set/get the particle control set attract force strength */
- inline float getCpsTimeEnd() const { return mCpsTimeEnd; }
- inline void setCpsTimeEnd(float set) { mCpsTimeEnd=set; }
-
- /*! Set/get the particle control set quality */
- inline float getCpsQuality() const { return mCpsQuality; }
- inline void setCpsQuality(float set) { mCpsQuality=set; }
-
- inline AnimChannel<float> getCpsAttrFStr() const { return mcAttrFStr; }
- inline AnimChannel<float> getCpsAttrFRad() const { return mcAttrFRad; }
- inline AnimChannel<float> getCpsVelFStr() const { return mcVelFStr; }
- inline AnimChannel<float> getCpsVelFRad() const { return mcVelFRad; }
-
- /****************************************/
-
- /*! Init channels from float arrays (for elbeem API) */
- void initChannels(
- int nTrans, float *trans, int nRot, float *rot, int nScale, float *scale,
- int nAct, float *act, int nIvel, float *ivel,
- int nAttrFStr, float *attrFStr,
- int nAttrFRad, float *attrFRad,
- int nVelFStr, float *velFStr,
- int nVelFRad, float *velFRad
- );
-
- /*! is the object animated? */
- inline bool getIsAnimated() const { return mIsAnimated; }
- /*! init object anim flag */
- bool checkIsAnimated();
- /*! is the mesh animated? */
- virtual bool getMeshAnimated();
- /*! init triangle divisions */
- virtual void calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntlTriangle> &tris, gfxReal fsTri);
-
- /*! apply object translation at time t*/
- void applyTransformation(double t, vector<ntlVec3Gfx> *verts, vector<ntlVec3Gfx> *norms, int vstart, int vend, int forceTrafo);
-
- /*! Prepare points for moving objects */
- void initMovingPoints(double time, gfxReal featureSize);
- /*! Prepare points for animated objects */
- void initMovingPointsAnim(
- double srctime, vector<ntlVec3Gfx> &srcpoints,
- double dsttime, vector<ntlVec3Gfx> &dstpoints,
- vector<ntlVec3Gfx> *dstnormals,
- gfxReal featureSize, ntlVec3Gfx geostart, ntlVec3Gfx geoend );
- /*! Prepare points for moving objects (copy into ret) */
- void getMovingPoints(vector<ntlVec3Gfx> &ret, vector<ntlVec3Gfx> *norms = NULL);
- /*! Calculate max. velocity on object from t1 to t2 */
- ntlVec3Gfx calculateMaxVel(double t1, double t2);
- /*! get translation at time t*/
- ntlVec3Gfx getTranslation(double t);
- /*! get active flag time t*/
- float getGeoActive(double t);
-
- /*! add triangle to scene and init flags */
- // helper function for getTriangles
- void sceneAddTriangle(
- ntlVec3Gfx p1,ntlVec3Gfx p2,ntlVec3Gfx p3,
- ntlVec3Gfx pn1,ntlVec3Gfx pn2,ntlVec3Gfx pn3,
- ntlVec3Gfx trin, bool smooth,
- vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *vertNormals);
- void sceneAddTriangleNoVert(int *trips,
- ntlVec3Gfx trin, bool smooth,
- vector<ntlTriangle> *triangles);
-
- protected:
-
- /* initialized for scene? */
- bool mIsInitialized;
-
- /*! Point to a property object describing the surface of this object */
- ntlMaterial *mpMaterial;
-
- /*! Name of the surcace property */
- string mMaterialName;
-
- /*! Cast shadows on/off */
- int mCastShadows;
- /*! REceive shadows on/off */
- int mReceiveShadows;
-
- /* fluid init data */
- /*! fluid object type (fluid, obstacle, accelerator etc.) */
- int mGeoInitType;
- /*! initial velocity for fluid objects */
- ntlVec3Gfx mInitialVelocity;
- AnimChannel<ntlVec3Gfx> mcInitialVelocity;
- /*! use object local inflow? */
- bool mLocalCoordInivel;
- /*! perform more accurate intersecting geo init for this object? */
- bool mGeoInitIntersect;
- /*! part slip bc value */
- float mGeoPartSlipValue;
- /*! obstacle impact correction factor */
- AnimChannel<float> mcGeoImpactFactor;
- /*! only init as thin object, dont fill? */
- int mVolumeInit;
-
- /*! initial offset for rot/scale */
- ntlVec3Gfx mInitialPos;
- /*! animated channels for postition, rotation and scale */
- AnimChannel<ntlVec3Gfx> mcTrans, mcRot, mcScale;
- /*! easy check for animation */
- bool mIsAnimated;
-
- /*! moving point/normal storage */
- vector<ntlVec3Gfx> mMovPoints;
- vector<ntlVec3Gfx> mMovNormals;
- /*! cached points for non moving objects/timeslots */
- bool mHaveCachedMov;
- vector<ntlVec3Gfx> mCachedMovPoints;
- vector<ntlVec3Gfx> mCachedMovNormals;
- /*! precomputed triangle divisions */
- vector<int> mTriangleDivs1,mTriangleDivs2;
- /*! inited? */
- float mMovPntsInited;
- /*! point with max. distance from center */
- int mMaxMovPnt;
-
- /*! animated channels for in/outflow on/off */
- AnimChannel<float> mcGeoActive;
-
- /* fluid control settings */
- float mCpsTimeStart;
- float mCpsTimeEnd;
- float mCpsQuality;
- AnimChannel<float> mcAttrFStr, mcAttrFRad, mcVelFStr, mcVelFRad;
-
- public:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlGeometryObject")
-#endif
-};
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_geometryshader.h b/intern/elbeem/intern/ntl_geometryshader.h
deleted file mode 100644
index 5400e05a27a..00000000000
--- a/intern/elbeem/intern/ntl_geometryshader.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Interface for a geometry shader
- *
- *****************************************************************************/
-#ifndef NTL_GEOMETRYSHADER_H
-#define NTL_GEOMETRYSHADER_H
-
-#include "ntl_geometryclass.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlGeometryObject;
-class ntlRenderGlobals;
-
-class ntlGeometryShader :
- public ntlGeometryClass
-{
-
- public:
-
- //! Default constructor
- inline ntlGeometryShader() :
- ntlGeometryClass(), mOutFilename("")
- {};
- //! Default destructor
- virtual ~ntlGeometryShader() {};
-
- //! Return type id
- virtual int getTypeId() { return GEOCLASSTID_SHADER; }
-
- /*! Initialize object, should return !=0 upon error */
- virtual int initializeShader() = 0;
-
- /*! Do further object initialization after all geometry has been constructed, should return !=0 upon error */
- virtual int postGeoConstrInit(ntlRenderGlobals *glob) { glob=NULL; /*unused*/ return 0; };
-
- /*! Get start iterator for all objects */
- virtual vector<ntlGeometryObject *>::iterator getObjectsBegin() { return mObjects.begin(); }
- /*! Get end iterator for all objects */
- virtual vector<ntlGeometryObject *>::iterator getObjectsEnd() { return mObjects.end(); }
-
- /*! notify object that dump is in progress (e.g. for field dump) */
- virtual void notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) = 0;
-
- /*! get output filename, returns global render outfile if empty */
- string getOutFilename( void ) { return mOutFilename; }
-
- protected:
-
- //! vector for the objects
- vector<ntlGeometryObject *> mObjects;
-
-
- /*! surface output name for this simulation */
- string mOutFilename;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlGeometryShader")
-#endif
-};
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_lighting.cpp b/intern/elbeem/intern/ntl_lighting.cpp
deleted file mode 100644
index aef06f8f490..00000000000
--- a/intern/elbeem/intern/ntl_lighting.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * a light object
- *
- *****************************************************************************/
-
-
-#include "ntl_lighting.h"
-#include "ntl_ray.h"
-#include "ntl_world.h"
-
-
-/******************************************************************************
- * Default Constructor
- *****************************************************************************/
-ntlLightObject::ntlLightObject(ntlRenderGlobals *glob) :
- mpGlob( glob ),
- mActive( 1 ),
- mCastShadows( 1 ),
- mcColor( ntlColor(1.0) ),
- mvPosition( ntlVec3Gfx(0.0) )
-{
- // nothing to do...
-}
-
-
-/******************************************************************************
- * Constructor with parameters
- *****************************************************************************/
-ntlLightObject::ntlLightObject(ntlRenderGlobals *glob, const ntlColor& col) :
- mpGlob( glob ),
- mActive( 1 ),
- mCastShadows( 1 ),
- mcColor( col )
-{
- // nothing to do...
-}
-
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlLightObject::~ntlLightObject()
-{
- // nothing to do...
-}
-
-
-
-/******************************************************************************
- * Determine color contribution of a lightsource (Phong model)
- * Specular part is returned in seperate parameter and added later
- *****************************************************************************/
-const ntlColor
-ntlLightObject::getShadedColor(const ntlRay &reflectedRay, const ntlVec3Gfx lightDir,
- ntlMaterial *surf, ntlColor &highlight) const
-{
- gfxReal ldot = dot(lightDir, reflectedRay.getNormal()); /* equals cos( angle(L,N) ) */
- ntlColor reflected_color = ntlColor(0.0); /* adds up to total reflected color */
- if(mpGlob->getDebugOut() > 5) errorOut("Lighting dir:"<<lightDir<<" norm:"<<reflectedRay.getNormal()<<" "<<ldot );
-
- /* lambertian reflection model */
- if (ldot > 0.0) {
- //ldot *= -1.0;
- reflected_color += surf->getDiffuseRefl() * (getColor() * ldot );
-
- /* specular part */
- /* specular reflection only makes sense, when the light is facing the surface,
- as the highlight is supposed to be a reflection of the lightsource, it cannot
- be reflected on surfaces with ldot<=0, as this means the arc between light
- and normal is more than 90 degrees. If this isn't done, ugly moiree patterns appear
- in the highlights, and refractions have strange patterns due to highlights on the
- inside of the surface */
- gfxReal spec = dot(reflectedRay.getDirection(), lightDir); // equals cos( angle(R,L) )
- if((spec > 0.0) && (surf->getSpecular()>0)) {
- spec = pow( spec, surf->getSpecExponent() ); /* phong exponent */
- highlight += getColor() * surf->getSpecular() * spec;
- //errorOut( " "<< surf->getName() <<" S "<<highlight<<" "<<spec<<" "<<surf->getSpecular()<<" "<<surf->getSpecExponent() );
- }
-
- }
-
- return ntlColor(reflected_color);
-}
-
-
-// omni light implementation
-
-
-/******************************************************************************
- *! prepare shadow maps if necessary
- *****************************************************************************/
-void ntlLightObject::prepare( bool doCaustics )
-{
- doCaustics = false; // unused
- if(!mActive) { return; }
-}
-
-
-/******************************************************************************
- * Illuminate the given point on an object
- *****************************************************************************/
-ntlColor ntlLightObject::illuminatePoint(ntlRay &reflectedRay, ntlGeometryObject *closest,
- ntlColor &highlight )
-{
- /* is this light active? */
- if(!mActive) { return ntlColor(0.0); }
-
- gfxReal visibility = 1.0; // how much of light is visible
- ntlVec3Gfx intersectionPos = reflectedRay.getOrigin();
- ntlColor current_color = ntlColor(0.0);
- ntlMaterial *clossurf = closest->getMaterial();
-
- ntlVec3Gfx lightDir = (mvPosition - intersectionPos);
- gfxReal lightDirNorm = normalize(lightDir);
-
- // where is the lightsource ?
- ntlRay rayOfLight(intersectionPos, lightDir, 0, 1.0, mpGlob );
-
- if( (1) && (mCastShadows)&&(closest->getReceiveShadows()) ) {
- ntlTriangle *tri;
- ntlVec3Gfx triNormal;
- gfxReal trit;
- mpGlob->getRenderScene()->intersectScene(rayOfLight, trit, triNormal, tri, TRI_CASTSHADOWS);
- if(( trit>0 )&&( trit<lightDirNorm )) visibility = 0.0;
- if(mpGlob->getDebugOut() > 5) errorOut("Omni lighting with "<<visibility );
- }
-
- /* is light partly visible ? */
-//? visibility=1.;
- if (visibility>0.0) {
- ntlColor highTemp(0.0); // temporary highlight color to multiply highTemp with offFac
- current_color = getShadedColor(reflectedRay, lightDir, clossurf, highTemp) * visibility;
- highlight += highTemp * visibility;
- if(mpGlob->getDebugOut() > 5) errorOut("Omni lighting color "<<current_color );
- }
- return current_color;
-}
-
-
-
-/******************************************************************************
- * Default constructor
- *****************************************************************************/
-ntlMaterial::ntlMaterial( void ) :
- mName( "default" ),
- mDiffuseRefl(0.5,0.5,0.5), mAmbientRefl(0.0,0.0,0.0),
- mSpecular(0.0), mSpecExponent(0.0), mMirror(0.0),
- mTransparence(0.0), mRefracIndex(1.05), mTransAdditive(0.0), mTransAttCol(0.0),
- mFresnel( 0 ) {
- // just do default init...
-}
-
-
-
-/******************************************************************************
- * Init constructor
- *****************************************************************************/
-ntlMaterial::ntlMaterial( string name,
- const ntlColor& Ref, const ntlColor& Amb,
- gfxReal Spec, gfxReal SpecEx, gfxReal Mirr,
- gfxReal Trans, gfxReal Refrac, gfxReal TAdd,
- const ntlColor& Att, int fres)
-{
- mName = name;
- mDiffuseRefl = Ref;
- mAmbientRefl = Amb;
- mSpecular = Spec;
- mSpecExponent = SpecEx;
- mMirror = Mirr;
- mTransparence = Trans;
- mRefracIndex = Refrac;
- mTransAdditive = TAdd;
- mTransAttCol = Att;
- mFresnel = fres;
-}
-
diff --git a/intern/elbeem/intern/ntl_lighting.h b/intern/elbeem/intern/ntl_lighting.h
deleted file mode 100644
index b046ccfae57..00000000000
--- a/intern/elbeem/intern/ntl_lighting.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * a light object
- * default omni light implementation
- *
- *****************************************************************************/
-#ifndef NTL_LIGHTING_H
-#define NTL_LIGHTING_H
-
-#include "ntl_vector3dim.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlMaterial;
-class ntlRay;
-class ntlRenderGlobals;
-class ntlGeometryObject;
-
-
-
-/* shadow map directions */
-#define LSM_RIGHT 0
-#define LSM_LEFT 1
-#define LSM_UP 2
-#define LSM_DOWN 3
-#define LSM_FRONT 4
-#define LSM_BACK 5
-
-/*! Basic object for lights, all other light are derived from this one */
-class ntlLightObject
-{
-public:
- /* CONSTRUCTORS */
- /*! Default constructor */
- ntlLightObject(ntlRenderGlobals *glob);
- /*! Constructor with parameters */
- ntlLightObject(ntlRenderGlobals *glob, const ntlColor& col);
- /*! Destructor */
- virtual ~ntlLightObject();
-
- /*! prepare light for rendering (for example shadow maps) */
- virtual void prepare( bool );
-
- /*! do the illumination... */
- virtual ntlColor illuminatePoint(ntlRay &reflectedRay,
- ntlGeometryObject *closest,
- ntlColor &highlight);
- /*! shade the point */
- const ntlColor
- getShadedColor(const ntlRay &reflectedray, ntlVec3Gfx lightDir,
- ntlMaterial *surf, ntlColor &highlight) const;
-
-
- /* access methods */
- /*! Access the active flag */
- inline void setActive(bool set) { mActive = set; }
- inline bool getActive() const { return mActive; }
- /*! Access the shadow flag */
- inline void setCastShadows(bool set) { mCastShadows = set; }
- inline bool getCastShadows() const { return mCastShadows; }
- /*! Access the light color */
- inline void setColor(ntlColor set) { mcColor = set; }
- inline ntlColor getColor() const { return mcColor; }
-
- /*! Access the omni light position */
- void setPosition(ntlVec3Gfx set) { mvPosition = set; }
- ntlVec3Gfx getPosition() const { return mvPosition; }
-
-
-protected:
- /*! render globals */
- ntlRenderGlobals *mpGlob;
-
- /*! is this light acitve? */
- bool mActive;
-
- /*! does it cast shadows? */
- bool mCastShadows;
-
- /*! color of this light */
- ntlColor mcColor;
-
- /*! light position */
- ntlVec3Gfx mvPosition;
-
-private:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlLightObject")
-#endif
-};
-
-
-//! Properties of an geo object, describing the reflection properties of the surface
-class ntlMaterial
-{
-public:
- // CONSTRUCTORS
- //! Default constructor
- ntlMaterial( void );
- //! Constructor with parameters
- /*! Sets reflectance, ambient reflection, specular intensity
- * specular exponent, mirror intensity
- * transparency, refraction index */
- ntlMaterial( string name,
- const ntlColor& Ref, const ntlColor& Amb,
- gfxReal Spec, gfxReal Exp, gfxReal Mirror,
- gfxReal Trans, gfxReal Refrac, gfxReal TAdd,
- const ntlColor& Att, int fres);
- //! Desctructor
- ~ntlMaterial() {};
-
- //! Calculate reflectance and refratance from Fresnel's law
- inline void calculateFresnel(const ntlVec3Gfx &dir, const ntlVec3Gfx &normal, gfxReal refIndex,
- gfxReal &refl, gfxReal &trans );
-
-protected:
-
- /* name of the material */
- string mName;
-
- //! Vector for reflectance of each color component (used in shade() of ray object)
- ntlColor mDiffuseRefl;
- //! Ambient reflectance
- ntlColor mAmbientRefl;
- //! Specular reflection intensity
- gfxReal mSpecular;
- //! Specular phong exponent
- gfxReal mSpecExponent;
- //! Mirror intensity
- gfxReal mMirror;
-
- //! Transparence
- gfxReal mTransparence;
- //! Refraction index, nu(Air) is assumed 1
- gfxReal mRefracIndex;
- //! Should transparence be additive?
- gfxReal mTransAdditive;
- //! Color dependent transparency attentuation factors (negative logarithm stored)
- ntlColor mTransAttCol;
- //! Should the transparence and reflectivity be determined by fresnel?
- int mFresnel;
-
-
-public:
- // access methods
-
- //! Returns the material name
- inline string getName() { return mName; }
- //! Returns the reflectance
- inline ntlColor getDiffuseRefl() const { return ntlColor(mDiffuseRefl); }
- //! Returns the ambience
- inline ntlColor getAmbientRefl() const { return ntlColor(mAmbientRefl); }
- //! Returns the specular component
- inline gfxReal getSpecular() const { return mSpecular; }
- //! Returns the specular exponent component
- inline gfxReal getSpecExponent() const { return mSpecExponent; }
- //! Returns the mirror component
- inline gfxReal getMirror() const { return mMirror; }
- //! Returns the transparence component
- inline gfxReal getTransparence() const { return mTransparence; }
- //! Returns the refraction index component
- inline gfxReal getRefracIndex() const { return mRefracIndex; }
- //! Returns the transparency additive factor component
- inline gfxReal getTransAdditive() const { return mTransAdditive; }
- //! Returns the transparency attentuation
- inline ntlColor getTransAttCol() const { return mTransAttCol; }
- //! Get Fresnel flag
- inline int getFresnel( void ) { return mFresnel; }
-
-
-
- //! Returns the mat name
- inline void setName(string set) { mName = set; }
- //! Returns the reflectance
- inline void setDiffuseRefl(ntlColor set) { mDiffuseRefl=set; }
- //! Returns the ambience
- inline void setAmbientRefl(ntlColor set) { mAmbientRefl=set; }
- //! Returns the specular component
- inline void setSpecular(gfxReal set) { mSpecular=set; }
- //! Returns the specular exponent component
- inline void setSpecExponent(gfxReal set) { mSpecExponent=set; }
- //! Returns the mirror component
- inline void setMirror(gfxReal set) { mMirror=set; }
- //! Returns the transparence component
- inline void setTransparence(gfxReal set) { mTransparence=set; }
- //! Returns the refraction index component
- inline void setRefracIndex(gfxReal set) { mRefracIndex=set; }
- //! Returns the transparency additive factor component
- inline void setTransAdditive(gfxReal set) { mTransAdditive=set; }
- //! Returns the transparency attentuation
- inline void setTransAttCol(ntlColor set) {
- ntlColor setlog = ntlColor( -log(set[0]), -log(set[1]), -log(set[2]) );
- mTransAttCol=setlog; }
- //! Set Fresnel on/off
- inline void setFresnel(int set) { mFresnel = set; }
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlMaterial")
-#endif
-};
-
-
-/******************************************************************************
- * Macro to define the default surface properties for a newly created object
- *****************************************************************************/
-#define GET_GLOBAL_DEFAULT_MATERIAL new ntlMaterial( "default",\
- ntlColor( 0.5 ), ntlColor(0.0), \
- 1.0, 5.0, 0.0, \
- /*0.0 test:*/ 0.5 , 1.0, 0.0, \
- ntlColor( 0.0 ), 0 );
-
-
-
-/******************************************************************************
- * Calculate reflectance and refratance from Fresnel's law
- * cf. Glassner p. 46
- *****************************************************************************/
-inline void
-ntlMaterial::calculateFresnel(const ntlVec3Gfx &dir, const ntlVec3Gfx &normal, gfxReal refIndex,
- gfxReal &refl, gfxReal &trans)
-{
- gfxReal c = -dot(dir, normal);
- if(c<0) {
- refl = 0.0; trans = 0.0; return;
- //c = 0.0;
- }
-
- gfxReal r0 = ((refIndex-1.0)*(refIndex-1.0)) /
- ((refIndex+1.0)*(refIndex+1.0));
- gfxReal omc = (1.0-c);
- gfxReal r =r0 + (1.0 - r0) * omc*omc*omc*omc*omc;
-
- //mMirror = r;
- //mTransparence = (1.0 - r);
- refl = r;
- trans = (1.0 - r);
- //errorOut(" fres ");
-}
-
-
-#endif
-
-
diff --git a/intern/elbeem/intern/ntl_matrices.h b/intern/elbeem/intern/ntl_matrices.h
deleted file mode 100644
index d3551f1a682..00000000000
--- a/intern/elbeem/intern/ntl_matrices.h
+++ /dev/null
@@ -1,790 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Basic matrix utility include file
- *
- *****************************************************************************/
-#ifndef NTL_MATRICES_H
-
-#include "ntl_vector3dim.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-// The basic vector class
-template<class Scalar>
-class ntlMatrix4x4
-{
-public:
- // Constructor
- inline ntlMatrix4x4(void );
- // Copy-Constructor
- inline ntlMatrix4x4(const ntlMatrix4x4<Scalar> &v );
- // construct a vector from one Scalar
- inline ntlMatrix4x4(Scalar);
- // construct a vector from three Scalars
- inline ntlMatrix4x4(Scalar, Scalar, Scalar);
-
- // Assignment operator
- inline const ntlMatrix4x4<Scalar>& operator= (const ntlMatrix4x4<Scalar>& v);
- // Assignment operator
- inline const ntlMatrix4x4<Scalar>& operator= (Scalar s);
- // Assign and add operator
- inline const ntlMatrix4x4<Scalar>& operator+= (const ntlMatrix4x4<Scalar>& v);
- // Assign and add operator
- inline const ntlMatrix4x4<Scalar>& operator+= (Scalar s);
- // Assign and sub operator
- inline const ntlMatrix4x4<Scalar>& operator-= (const ntlMatrix4x4<Scalar>& v);
- // Assign and sub operator
- inline const ntlMatrix4x4<Scalar>& operator-= (Scalar s);
- // Assign and mult operator
- inline const ntlMatrix4x4<Scalar>& operator*= (const ntlMatrix4x4<Scalar>& v);
- // Assign and mult operator
- inline const ntlMatrix4x4<Scalar>& operator*= (Scalar s);
- // Assign and div operator
- inline const ntlMatrix4x4<Scalar>& operator/= (const ntlMatrix4x4<Scalar>& v);
- // Assign and div operator
- inline const ntlMatrix4x4<Scalar>& operator/= (Scalar s);
-
-
- // unary operator
- inline ntlMatrix4x4<Scalar> operator- () const;
-
- // binary operator add
- inline ntlMatrix4x4<Scalar> operator+ (const ntlMatrix4x4<Scalar>&) const;
- // binary operator add
- inline ntlMatrix4x4<Scalar> operator+ (Scalar) const;
- // binary operator sub
- inline ntlMatrix4x4<Scalar> operator- (const ntlMatrix4x4<Scalar>&) const;
- // binary operator sub
- inline ntlMatrix4x4<Scalar> operator- (Scalar) const;
- // binary operator mult
- inline ntlMatrix4x4<Scalar> operator* (const ntlMatrix4x4<Scalar>&) const;
- // binary operator mult
- inline ntlVector3Dim<Scalar> operator* (const ntlVector3Dim<Scalar>&) const;
- // binary operator mult
- inline ntlMatrix4x4<Scalar> operator* (Scalar) const;
- // binary operator div
- inline ntlMatrix4x4<Scalar> operator/ (Scalar) const;
-
- // init function
- //! init identity matrix
- inline void initId();
- //! init rotation matrix
- inline void initTranslation(Scalar x, Scalar y, Scalar z);
- //! init rotation matrix
- inline void initRotationX(Scalar rot);
- inline void initRotationY(Scalar rot);
- inline void initRotationZ(Scalar rot);
- inline void initRotationXYZ(Scalar rotx,Scalar roty, Scalar rotz);
- //! init scaling matrix
- inline void initScaling(Scalar scale);
- inline void initScaling(Scalar x, Scalar y, Scalar z);
- //! from 16 value array (init id if all 0)
- inline void initArrayCheck(Scalar *array);
-
- //! decompose matrix
- void decompose(ntlVector3Dim<Scalar> &trans,ntlVector3Dim<Scalar> &scale,ntlVector3Dim<Scalar> &rot,ntlVector3Dim<Scalar> &shear);
-
- //! public to avoid [][] operators
- Scalar value[4][4]; //< Storage of vector values
-
-
-protected:
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlMatrix4x4")
-#endif
-};
-
-
-
-//------------------------------------------------------------------------------
-// TYPEDEFS
-//------------------------------------------------------------------------------
-
-// a 3D vector for graphics output, typically float?
-//typedef ntlMatrix4x4<float> ntlVec3Gfx;
-
-//typedef ntlMatrix4x4<double> ntlMat4d;
-typedef ntlMatrix4x4<double> ntlMat4d;
-
-// a 3D vector with single precision
-typedef ntlMatrix4x4<float> ntlMat4f;
-
-// a 3D vector with grafix precision
-typedef ntlMatrix4x4<gfxReal> ntlMat4Gfx;
-
-// a 3D integer vector
-typedef ntlMatrix4x4<int> ntlMat4i;
-
-
-
-
-
-//------------------------------------------------------------------------------
-// STREAM FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Outputs the object in human readable form using the format
- [x,y,z]
- */
-template<class Scalar>
-std::ostream&
-operator<<( std::ostream& os, const ntlMatrix4x4<Scalar>& m )
-{
- for(int i=0; i<4; i++) {
- os << '|' << m.value[i][0] << ", " << m.value[i][1] << ", " << m.value[i][2] << ", " << m.value[i][3] << '|';
- }
- return os;
-}
-
-
-
-/*************************************************************************
- Reads the contents of the object from a stream using the same format
- as the output operator.
- */
-template<class Scalar>
-std::istream&
-operator>>( std::istream& is, ntlMatrix4x4<Scalar>& m )
-{
- char c;
- char dummy[3];
-
- for(int i=0; i<4; i++) {
- is >> c >> m.value[i][0] >> dummy >> m.value[i][1] >> dummy >> m.value[i][2] >> dummy >> m.value[i][3] >> c;
- }
- return is;
-}
-
-
-//------------------------------------------------------------------------------
-// VECTOR inline FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Constructor.
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>::ntlMatrix4x4( void )
-{
-#ifdef MATRIX_INIT_ZERO
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] = 0.0;
- }
- }
-#endif
-}
-
-
-
-/*************************************************************************
- Copy-Constructor.
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>::ntlMatrix4x4( const ntlMatrix4x4<Scalar> &v )
-{
- value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3];
- value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3];
- value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3];
- value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3];
-}
-
-
-
-/*************************************************************************
- Constructor for a vector from a single Scalar. All components of
- the vector get the same value.
- \param s The value to set
- \return The new vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>::ntlMatrix4x4(Scalar s )
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] = s;
- }
- }
-}
-
-
-
-/*************************************************************************
- Copy a ntlMatrix4x4 componentwise.
- \param v vector with values to be copied
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator=( const ntlMatrix4x4<Scalar> &v )
-{
- value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3];
- value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3];
- value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3];
- value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3];
- return *this;
-}
-
-
-/*************************************************************************
- Copy a Scalar to each component.
- \param s The value to copy
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator=(Scalar s)
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] = s;
- }
- }
- return *this;
-}
-
-
-/*************************************************************************
- Add another ntlMatrix4x4 componentwise.
- \param v vector with values to be added
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator+=( const ntlMatrix4x4<Scalar> &v )
-{
- value[0][0] += v.value[0][0]; value[0][1] += v.value[0][1]; value[0][2] += v.value[0][2]; value[0][3] += v.value[0][3];
- value[1][0] += v.value[1][0]; value[1][1] += v.value[1][1]; value[1][2] += v.value[1][2]; value[1][3] += v.value[1][3];
- value[2][0] += v.value[2][0]; value[2][1] += v.value[2][1]; value[2][2] += v.value[2][2]; value[2][3] += v.value[2][3];
- value[3][0] += v.value[3][0]; value[3][1] += v.value[3][1]; value[3][2] += v.value[3][2]; value[3][3] += v.value[3][3];
- return *this;
-}
-
-
-/*************************************************************************
- Add a Scalar value to each component.
- \param s Value to add
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator+=(Scalar s)
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] += s;
- }
- }
- return *this;
-}
-
-
-/*************************************************************************
- Subtract another vector componentwise.
- \param v vector of values to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator-=( const ntlMatrix4x4<Scalar> &v )
-{
- value[0][0] -= v.value[0][0]; value[0][1] -= v.value[0][1]; value[0][2] -= v.value[0][2]; value[0][3] -= v.value[0][3];
- value[1][0] -= v.value[1][0]; value[1][1] -= v.value[1][1]; value[1][2] -= v.value[1][2]; value[1][3] -= v.value[1][3];
- value[2][0] -= v.value[2][0]; value[2][1] -= v.value[2][1]; value[2][2] -= v.value[2][2]; value[2][3] -= v.value[2][3];
- value[3][0] -= v.value[3][0]; value[3][1] -= v.value[3][1]; value[3][2] -= v.value[3][2]; value[3][3] -= v.value[3][3];
- return *this;
-}
-
-
-/*************************************************************************
- Subtract a Scalar value from each component.
- \param s Value to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator-=(Scalar s)
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] -= s;
- }
- }
- return *this;
-}
-
-
-/*************************************************************************
- Multiply with another vector componentwise.
- \param v vector of values to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator*=( const ntlMatrix4x4<Scalar> &v )
-{
- ntlMatrix4x4<Scalar> nv(0.0);
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
-
- for(int k=0;k<4;k++)
- nv.value[i][j] += (value[i][k] * v.value[k][j]);
- }
- }
- *this = nv;
- return *this;
-}
-
-
-/*************************************************************************
- Multiply each component with a Scalar value.
- \param s Value to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator*=(Scalar s)
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] *= s;
- }
- }
- return *this;
-}
-
-
-
-/*************************************************************************
- Divide each component by a Scalar value.
- \param s Value to divide by
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlMatrix4x4<Scalar>&
-ntlMatrix4x4<Scalar>::operator/=(Scalar s)
-{
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] /= s;
- }
- }
- return *this;
-}
-
-
-//------------------------------------------------------------------------------
-// unary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build componentwise the negative this vector.
- \return The new (negative) vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator-() const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = -value[i][j];
- }
- }
- return nv;
-}
-
-
-
-//------------------------------------------------------------------------------
-// binary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build a vector with another vector added componentwise.
- \param v The second vector to add
- \return The sum vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator+( const ntlMatrix4x4<Scalar> &v ) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] + v.value[i][j];
- }
- }
- return nv;
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value added to each component.
- \param s The Scalar value to add
- \return The sum vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator+(Scalar s) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] + s;
- }
- }
- return nv;
-}
-
-
-/*************************************************************************
- Build a vector with another vector subtracted componentwise.
- \param v The second vector to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator-( const ntlMatrix4x4<Scalar> &v ) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] - v.value[i][j];
- }
- }
- return nv;
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value subtracted componentwise.
- \param s The Scalar value to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator-(Scalar s ) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] - s;
- }
- }
- return nv;
-}
-
-
-
-/*************************************************************************
- Build a ntlMatrix4x4 with a Scalar value multiplied to each component.
- \param s The Scalar value to multiply with
- \return The product vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator*(Scalar s) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] * s;
- }
- }
- return nv;
-}
-
-
-
-
-/*************************************************************************
- Build a vector divided componentwise by a Scalar value.
- \param s The Scalar value to divide by
- \return The ratio vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator/(Scalar s) const
-{
- ntlMatrix4x4<Scalar> nv;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- nv[i][j] = value[i][j] / s;
- }
- }
- return nv;
-}
-
-
-
-
-
-/*************************************************************************
- Build a vector with another vector multiplied by componentwise.
- \param v The second vector to muliply with
- \return The product vector
- */
-template<class Scalar>
-inline ntlMatrix4x4<Scalar>
-ntlMatrix4x4<Scalar>::operator*( const ntlMatrix4x4<Scalar>& v) const
-{
- ntlMatrix4x4<Scalar> nv(0.0);
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
-
- for(int k=0;k<4;k++)
- nv.value[i][j] += (value[i][k] * v.value[k][j]);
- }
- }
- return nv;
-}
-
-
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlMatrix4x4<Scalar>::operator*( const ntlVector3Dim<Scalar>& v) const
-{
- ntlVector3Dim<Scalar> nvec(0.0);
- for(int i=0; i<3; i++) {
- for(int j=0; j<3; j++) {
- nvec[i] += (v[j] * value[i][j]);
- }
- }
- // assume normalized w coord
- for(int i=0; i<3; i++) {
- nvec[i] += (1.0 * value[i][3]);
- }
- return nvec;
-}
-
-
-
-//------------------------------------------------------------------------------
-// Other helper functions
-//------------------------------------------------------------------------------
-
-//! init identity matrix
-template<class Scalar>
-inline void ntlMatrix4x4<Scalar>::initId()
-{
- (*this) = (Scalar)(0.0);
- value[0][0] =
- value[1][1] =
- value[2][2] =
- value[3][3] = (Scalar)(1.0);
-}
-
-//! init rotation matrix
-template<class Scalar>
-inline void ntlMatrix4x4<Scalar>::initTranslation(Scalar x, Scalar y, Scalar z)
-{
- //(*this) = (Scalar)(0.0);
- this->initId();
- value[0][3] = x;
- value[1][3] = y;
- value[2][3] = z;
-}
-
-//! init rotation matrix
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initRotationX(Scalar rot)
-{
- double drot = (double)(rot/360.0*2.0*M_PI);
- //? while(drot < 0.0) drot += (M_PI*2.0);
-
- this->initId();
- value[1][1] = (Scalar) cos(drot);
- value[1][2] = (Scalar) sin(drot);
- value[2][1] = (Scalar)(-sin(drot));
- value[2][2] = (Scalar) cos(drot);
-}
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initRotationY(Scalar rot)
-{
- double drot = (double)(rot/360.0*2.0*M_PI);
- //? while(drot < 0.0) drot += (M_PI*2.0);
-
- this->initId();
- value[0][0] = (Scalar) cos(drot);
- value[0][2] = (Scalar)(-sin(drot));
- value[2][0] = (Scalar) sin(drot);
- value[2][2] = (Scalar) cos(drot);
-}
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initRotationZ(Scalar rot)
-{
- double drot = (double)(rot/360.0*2.0*M_PI);
- //? while(drot < 0.0) drot += (M_PI*2.0);
-
- this->initId();
- value[0][0] = (Scalar) cos(drot);
- value[0][1] = (Scalar) sin(drot);
- value[1][0] = (Scalar)(-sin(drot));
- value[1][1] = (Scalar) cos(drot);
-}
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initRotationXYZ( Scalar rotx, Scalar roty, Scalar rotz)
-{
- ntlMatrix4x4<Scalar> val;
- ntlMatrix4x4<Scalar> rot;
- this->initId();
-
- // org
- /*rot.initRotationX(rotx);
- (*this) *= rot;
- rot.initRotationY(roty);
- (*this) *= rot;
- rot.initRotationZ(rotz);
- (*this) *= rot;
- // org */
-
- // blender
- rot.initRotationZ(rotz);
- (*this) *= rot;
- rot.initRotationY(roty);
- (*this) *= rot;
- rot.initRotationX(rotx);
- (*this) *= rot;
- // blender */
-}
-
-//! init scaling matrix
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initScaling(Scalar scale)
-{
- this->initId();
- value[0][0] = scale;
- value[1][1] = scale;
- value[2][2] = scale;
-}
-//! init scaling matrix
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initScaling(Scalar x, Scalar y, Scalar z)
-{
- this->initId();
- value[0][0] = x;
- value[1][1] = y;
- value[2][2] = z;
-}
-
-
-//! from 16 value array (init id if all 0)
-template<class Scalar>
-inline void
-ntlMatrix4x4<Scalar>::initArrayCheck(Scalar *array)
-{
- bool allZero = true;
- for(int i=0; i<4; i++) {
- for(int j=0; j<4; j++) {
- value[i][j] = array[i*4+j];
- if(array[i*4+j]!=0.0) allZero=false;
- }
- }
- if(allZero) this->initId();
-}
-
-//! decompose matrix
-template<class Scalar>
-void
-ntlMatrix4x4<Scalar>::decompose(ntlVector3Dim<Scalar> &trans,ntlVector3Dim<Scalar> &scale,ntlVector3Dim<Scalar> &rot,ntlVector3Dim<Scalar> &shear) {
- ntlVec3Gfx row[3],temp;
-
- for(int i = 0; i < 3; i++) {
- trans[i] = this->value[3][i];
- }
-
- for(int i = 0; i < 3; i++) {
- row[i][0] = this->value[i][0];
- row[i][1] = this->value[i][1];
- row[i][2] = this->value[i][2];
- }
-
- scale[0] = norm(row[0]);
- normalize (row[0]);
-
- shear[0] = dot(row[0], row[1]);
- row[1][0] = row[1][0] - shear[0]*row[0][0];
- row[1][1] = row[1][1] - shear[0]*row[0][1];
- row[1][2] = row[1][2] - shear[0]*row[0][2];
-
- scale[1] = norm(row[1]);
- normalize (row[1]);
-
- if(scale[1] != 0.0)
- shear[0] /= scale[1];
-
- shear[1] = dot(row[0], row[2]);
- row[2][0] = row[2][0] - shear[1]*row[0][0];
- row[2][1] = row[2][1] - shear[1]*row[0][1];
- row[2][2] = row[2][2] - shear[1]*row[0][2];
-
- shear[2] = dot(row[1], row[2]);
- row[2][0] = row[2][0] - shear[2]*row[1][0];
- row[2][1] = row[2][1] - shear[2]*row[1][1];
- row[2][2] = row[2][2] - shear[2]*row[1][2];
-
- scale[2] = norm(row[2]);
- normalize (row[2]);
-
- if(scale[2] != 0.0) {
- shear[1] /= scale[2];
- shear[2] /= scale[2];
- }
-
- temp = cross(row[1], row[2]);
- if(dot(row[0], temp) < 0.0) {
- for(int i = 0; i < 3; i++) {
- scale[i] *= -1.0;
- row[i][0] *= -1.0;
- row[i][1] *= -1.0;
- row[i][2] *= -1.0;
- }
- }
-
- if(row[0][2] < -1.0) row[0][2] = -1.0;
- if(row[0][2] > +1.0) row[0][2] = +1.0;
-
- rot[1] = asin(-row[0][2]);
-
- if(fabs(cos(rot[1])) > VECTOR_EPSILON) {
- rot[0] = atan2 (row[1][2], row[2][2]);
- rot[2] = atan2 (row[0][1], row[0][0]);
- }
- else {
- rot[0] = atan2 (row[1][0], row[1][1]);
- rot[2] = 0.0;
- }
-
- rot[0] = (180.0/M_PI)*rot[0];
- rot[1] = (180.0/M_PI)*rot[1];
- rot[2] = (180.0/M_PI)*rot[2];
-}
-
-#define NTL_MATRICES_H
-#endif
-
diff --git a/intern/elbeem/intern/ntl_ray.cpp b/intern/elbeem/intern/ntl_ray.cpp
deleted file mode 100644
index 1acc8cdca12..00000000000
--- a/intern/elbeem/intern/ntl_ray.cpp
+++ /dev/null
@@ -1,915 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * main renderer class
- *
- *****************************************************************************/
-
-
-#include "utilities.h"
-#include "ntl_ray.h"
-#include "ntl_world.h"
-#include "ntl_geometryobject.h"
-#include "ntl_geometryshader.h"
-
-
-/* Minimum value for refl/refr to be traced */
-#define RAY_THRESHOLD 0.001
-
-#if GFX_PRECISION==1
-// float values
-//! Minimal contribution for rays to be traced on
-#define RAY_MINCONTRIB (1e-04)
-
-#else
-// double values
-//! Minimal contribution for rays to be traced on
-#define RAY_MINCONTRIB (1e-05)
-
-#endif
-
-
-
-
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-ntlRay::ntlRay( void )
- : mOrigin(0.0)
- , mDirection(0.0)
- , mvNormal(0.0)
- , mDepth(0)
- , mpGlob(NULL)
- , mIsRefracted(0)
-{
- errFatal("ntlRay::ntlRay()","Don't use uninitialized rays !", SIMWORLD_GENERICERROR);
- return;
-}
-
-
-/******************************************************************************
- * Copy - Constructor
- *****************************************************************************/
-ntlRay::ntlRay( const ntlRay &r )
-{
- // copy it! initialization is not enough!
- mOrigin = r.mOrigin;
- mDirection = r.mDirection;
- mvNormal = r.mvNormal;
- mDepth = r.mDepth;
- mIsRefracted = r.mIsRefracted;
- mIsReflected = r.mIsReflected;
- mContribution = r.mContribution;
- mpGlob = r.mpGlob;
-
- // get new ID
- if(mpGlob) {
- mID = mpGlob->getCounterRays()+1;
- mpGlob->setCounterRays( mpGlob->getCounterRays()+1 );
- } else {
- mID = 0;
- }
-}
-
-
-/******************************************************************************
- * Constructor with explicit parameters and global render object
- *****************************************************************************/
-ntlRay::ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob)
- : mOrigin( o )
- , mDirection( d )
- , mvNormal(0.0)
- , mDepth( i )
- , mContribution( contrib )
- , mpGlob( glob )
- , mIsRefracted( 0 )
- , mIsReflected( 0 )
-{
- // get new ID
- if(mpGlob) {
- mID = mpGlob->getCounterRays()+1;
- mpGlob->setCounterRays( mpGlob->getCounterRays()+1 );
- } else {
- mID = 0;
- }
-}
-
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlRay::~ntlRay()
-{
- /* nothing to do... */
-}
-
-
-
-/******************************************************************************
- * AABB
- *****************************************************************************/
-/* for AABB intersect */
-#define NUMDIM 3
-#define RIGHT 0
-#define LEFT 1
-#define MIDDLE 2
-
-//! intersect ray with AABB
-#ifndef ELBEEM_PLUGIN
-void ntlRay::intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const
-{
- char inside = true; /* inside box? */
- char hit = false; /* ray hits box? */
- int whichPlane; /* intersection plane */
- gfxReal candPlane[NUMDIM]; /* candidate plane */
- gfxReal quadrant[NUMDIM]; /* quadrants */
- gfxReal maxT[NUMDIM]; /* max intersection T for planes */
- ntlVec3Gfx coord; /* intersection point */
- ntlVec3Gfx dir = mDirection;
- ntlVec3Gfx origin = mOrigin;
- ntlVec3Gfx normal(0.0, 0.0, 0.0);
-
- t = GFX_REAL_MAX;
-
- /* check intersection planes for AABB */
- for(int i=0;i<NUMDIM;i++) {
- if(origin[i] < mStart[i]) {
- quadrant[i] = LEFT;
- candPlane [i] = mStart[i];
- inside = false;
- } else if(origin[i] > mEnd[i]) {
- quadrant[i] = RIGHT;
- candPlane[i] = mEnd[i];
- inside = false;
- } else {
- quadrant[i] = MIDDLE;
- }
- }
-
- /* inside AABB? */
- if(!inside) {
- /* get t distances to planes */
- /* treat too small direction components as paralell */
- for(int i=0;i<NUMDIM;i++) {
- if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
- maxT[i] = (candPlane[i] - origin[i]) / dir[i];
- } else {
- maxT[i] = -1;
- }
- }
-
- /* largest max t */
- whichPlane = 0;
- for(int i=1;i<NUMDIM;i++) {
- if(maxT[whichPlane] < maxT[i]) whichPlane = i;
- }
-
- /* check final candidate */
- hit = true;
- if(maxT[whichPlane] >= 0.0) {
-
- for(int i=0;i<NUMDIM;i++) {
- if(whichPlane != i) {
- coord[i] = origin[i] + maxT[whichPlane] * dir[i];
- if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
- (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
- /* no hit... */
- hit = false;
- }
- }
- else {
- coord[i] = candPlane[i];
- }
- }
-
- /* AABB hit... */
- if( hit ) {
- t = maxT[whichPlane];
- if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0;
- else normal[whichPlane] = -1.0;
- }
- }
-
-
- } else {
- /* inside AABB... */
- t = 0.0;
- coord = origin;
- return;
- }
-
- if(t == GFX_REAL_MAX) t = -1.0;
- retnormal = normal;
- retcoord = coord;
-}
-
-//! intersect ray with AABB
-void ntlRay::intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const
-{
- char hit = false; /* ray hits box? */
- int whichPlane; /* intersection plane */
- gfxReal candPlane[NUMDIM]; /* candidate plane */
- gfxReal quadrant[NUMDIM]; /* quadrants */
- gfxReal maxT[NUMDIM]; /* max intersection T for planes */
- ntlVec3Gfx coord; /* intersection point */
- ntlVec3Gfx dir = mDirection;
- ntlVec3Gfx origin = mOrigin;
- ntlVec3Gfx normal(0.0, 0.0, 0.0);
-
- t = GFX_REAL_MAX;
- for(int i=0;i<NUMDIM;i++) {
- if(origin[i] < mStart[i]) {
- quadrant[i] = LEFT;
- candPlane [i] = mEnd[i];
- } else if(origin[i] > mEnd[i]) {
- quadrant[i] = RIGHT;
- candPlane[i] = mStart[i];
- } else {
- if(dir[i] > 0) {
- quadrant[i] = LEFT;
- candPlane [i] = mEnd[i];
- } else
- if(dir[i] < 0) {
- quadrant[i] = RIGHT;
- candPlane[i] = mStart[i];
- } else {
- quadrant[i] = MIDDLE;
- }
- }
- }
-
-
- /* get t distances to planes */
- /* treat too small direction components as paralell */
- for(int i=0;i<NUMDIM;i++) {
- if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
- maxT[i] = (candPlane[i] - origin[i]) / dir[i];
- } else {
- maxT[i] = GFX_REAL_MAX;
- }
- }
-
- /* largest max t */
- whichPlane = 0;
- for(int i=1;i<NUMDIM;i++) {
- if(maxT[whichPlane] > maxT[i]) whichPlane = i;
- }
-
- /* check final candidate */
- hit = true;
- if(maxT[whichPlane] != GFX_REAL_MAX) {
-
- for(int i=0;i<NUMDIM;i++) {
- if(whichPlane != i) {
- coord[i] = origin[i] + maxT[whichPlane] * dir[i];
- if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
- (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
- /* no hit... */
- hit = false;
- }
- }
- else {
- coord[i] = candPlane[i];
- }
- }
-
- /* AABB hit... */
- if( hit ) {
- t = maxT[whichPlane];
-
- if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0;
- else normal[whichPlane] = -1.0;
- }
- }
-
-
- if(t == GFX_REAL_MAX) t = -1.0;
- retnormal = normal;
- retcoord = coord;
-}
-#endif // ELBEEM_PLUGIN
-
-//! intersect ray with AABB
-void ntlRay::intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const
-{
- // char inside = true; /* inside box? */ /* UNUSED */
- char hit = false; /* ray hits box? */
- int whichPlane; /* intersection plane */
- gfxReal candPlane[NUMDIM]; /* candidate plane */
- gfxReal quadrant[NUMDIM]; /* quadrants */
- gfxReal maxT[NUMDIM]; /* max intersection T for planes */
- ntlVec3Gfx coord; /* intersection point */
- ntlVec3Gfx dir = mDirection;
- ntlVec3Gfx origin = mOrigin;
- gfxReal t = GFX_REAL_MAX;
-
- /* check intersection planes for AABB */
- for(int i=0;i<NUMDIM;i++) {
- if(origin[i] < mStart[i]) {
- quadrant[i] = LEFT;
- candPlane [i] = mStart[i];
- // inside = false;
- } else if(origin[i] > mEnd[i]) {
- quadrant[i] = RIGHT;
- candPlane[i] = mEnd[i];
- // inside = false;
- } else {
- /* intersect with backside */
- if(dir[i] > 0) {
- quadrant[i] = LEFT;
- candPlane [i] = mStart[i];
- } else
- if(dir[i] < 0) {
- quadrant[i] = RIGHT;
- candPlane[i] = mEnd[i];
- } else {
- quadrant[i] = MIDDLE;
- }
- }
- }
-
- /* get t distances to planes */
- for(int i=0;i<NUMDIM;i++) {
- if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
- maxT[i] = (candPlane[i] - origin[i]) / dir[i];
- } else {
- maxT[i] = GFX_REAL_MAX;
- }
- }
-
- /* largest max t */
- whichPlane = 0;
- for(int i=1;i<NUMDIM;i++) {
- if( ((maxT[whichPlane] < maxT[i])&&(maxT[i]!=GFX_REAL_MAX)) ||
- (maxT[whichPlane]==GFX_REAL_MAX) )
- whichPlane = i;
- }
-
- /* check final candidate */
- hit = true;
- if(maxT[whichPlane]<GFX_REAL_MAX) {
- for(int i=0;i<NUMDIM;i++) {
- if(whichPlane != i) {
- coord[i] = origin[i] + maxT[whichPlane] * dir[i];
- if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
- (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
- /* no hit... */
- hit = false;
- }
- }
- else { coord[i] = candPlane[i]; }
- }
-
- /* AABB hit... */
- if( hit ) {
- t = maxT[whichPlane];
- }
- }
- tmin = t;
-
- /* now the backside */
- t = GFX_REAL_MAX;
- for(int i=0;i<NUMDIM;i++) {
- if(origin[i] < mStart[i]) {
- quadrant[i] = LEFT;
- candPlane [i] = mEnd[i];
- } else if(origin[i] > mEnd[i]) {
- quadrant[i] = RIGHT;
- candPlane[i] = mStart[i];
- } else {
- if(dir[i] > 0) {
- quadrant[i] = LEFT;
- candPlane [i] = mEnd[i];
- } else
- if(dir[i] < 0) {
- quadrant[i] = RIGHT;
- candPlane[i] = mStart[i];
- } else {
- quadrant[i] = MIDDLE;
- }
- }
- }
-
-
- /* get t distances to planes */
- for(int i=0;i<NUMDIM;i++) {
- if((quadrant[i] != MIDDLE) && (fabs(dir[i]) > getVecEpsilon()) ) {
- maxT[i] = (candPlane[i] - origin[i]) / dir[i];
- } else {
- maxT[i] = GFX_REAL_MAX;
- }
- }
-
- /* smallest max t */
- whichPlane = 0;
- for(int i=1;i<NUMDIM;i++) {
- if(maxT[whichPlane] > maxT[i]) whichPlane = i;
- }
-
- /* check final candidate */
- hit = true;
- if(maxT[whichPlane] != GFX_REAL_MAX) {
-
- for(int i=0;i<NUMDIM;i++) {
- if(whichPlane != i) {
- coord[i] = origin[i] + maxT[whichPlane] * dir[i];
- if( (coord[i] < mStart[i]-getVecEpsilon() ) ||
- (coord[i] > mEnd[i] +getVecEpsilon() ) ) {
- /* no hit... */
- hit = false;
- }
- }
- else {
- coord[i] = candPlane[i];
- }
- }
-
- /* AABB hit... */
- if( hit ) {
- t = maxT[whichPlane];
- }
- }
-
- tmax = t;
-}
-
-
-
-/******************************************************************************
- * Determine color of this ray by tracing through the scene
- *****************************************************************************/
-const ntlColor ntlRay::shade() //const
-{
-#ifndef ELBEEM_PLUGIN
- ntlGeometryObject *closest = NULL;
- gfxReal minT = GFX_REAL_MAX;
- vector<ntlLightObject*> *lightlist = mpGlob->getLightList();
- mpGlob->setCounterShades( mpGlob->getCounterShades()+1 );
- bool intersectionInside = 0;
- if(mpGlob->getDebugOut() > 5) errorOut(std::endl<<"New Ray: depth "<<mDepth<<", org "<<mOrigin<<", dir "<<mDirection );
-
- /* check if this ray contributes enough */
- if(mContribution <= RAY_MINCONTRIB) {
- //return ntlColor(0.0);
- }
-
- /* find closes object that intersects */
- ntlTriangle *tri = NULL;
- ntlVec3Gfx normal;
- mpGlob->getRenderScene()->intersectScene(*this, minT, normal, tri, 0);
- if(minT>0) {
- closest = mpGlob->getRenderScene()->getObject( tri->getObjectId() );
- }
-
- /* object hit... */
- if (closest != NULL) {
-
- ntlVec3Gfx triangleNormal = tri->getNormal();
- if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) errorOut("ntlRay warning: trinagle normal= 0 "); // DEBUG
- /* intersection on inside faces? if yes invert normal afterwards */
- gfxReal valDN; // = mDirection | normal;
- valDN = dot(mDirection, triangleNormal);
- if( valDN > 0.0) {
- intersectionInside = 1;
- normal = normal * -1.0;
- triangleNormal = triangleNormal * -1.0;
- }
-
- /* ... -> do reflection */
- ntlVec3Gfx intersectionPosition(mOrigin + (mDirection * (minT)) );
- ntlMaterial *clossurf = closest->getMaterial();
- /*if(mpGlob->getDebugOut() > 5) {
- errorOut("Ray hit: at "<<intersectionPosition<<" n:"<<normal<<" dn:"<<valDN<<" ins:"<<intersectionInside<<" cl:"<<((unsigned int)closest) );
- errorOut(" t1:"<<mpGlob->getRenderScene()->getVertex(tri->getPoints()[0])<<" t2:"<<mpGlob->getRenderScene()->getVertex(tri->getPoints()[1])<<" t3:"<<mpGlob->getScene()->getVertex(tri->getPoints()[2]) );
- errorOut(" trin:"<<tri->getNormal() );
- } // debug */
-
- /* current transparence and reflectivity */
- gfxReal currTrans = clossurf->getTransparence();
- gfxReal currRefl = clossurf->getMirror();
-
- /* correct intersectopm position */
- intersectionPosition += ( triangleNormal*getVecEpsilon() );
- /* reflection at normal */
- ntlVec3Gfx reflectedDir = getNormalized( reflectVector(mDirection, normal) );
- int badRefl = 0;
- if(dot(reflectedDir, triangleNormal)<0.0 ) {
- badRefl = 1;
- if(mpGlob->getDebugOut() > 5) { errorOut("Ray Bad reflection...!"); }
- }
-
- /* refraction direction, depending on in/outside hit */
- ntlVec3Gfx refractedDir;
- int refRefl = 0;
- /* refraction at normal is handled by inverting normal before */
- gfxReal myRefIndex = 1.0;
- if((currTrans>RAY_THRESHOLD)||(clossurf->getFresnel())) {
- if(intersectionInside) {
- myRefIndex = 1.0/clossurf->getRefracIndex();
- } else {
- myRefIndex = clossurf->getRefracIndex();
- }
-
- refractedDir = refractVector(mDirection, normal, myRefIndex , (gfxReal)(1.0) /* global ref index */, refRefl);
- }
-
- /* calculate fresnel? */
- if(clossurf->getFresnel()) {
- // for total reflection, just set trans to 0
- if(refRefl) {
- currRefl = 1.0; currTrans = 0.0;
- } else {
- // calculate fresnel coefficients
- clossurf->calculateFresnel( mDirection, normal, myRefIndex, currRefl,currTrans );
- }
- }
-
- ntlRay reflectedRay(intersectionPosition, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
- reflectedRay.setNormal( normal );
- ntlColor currentColor(0.0);
- ntlColor highlightColor(0.0);
-
- /* first add reflected ambient color */
- currentColor += (clossurf->getAmbientRefl() * mpGlob->getAmbientLight() );
-
- /* calculate lighting, not on the insides of objects... */
- if(!intersectionInside) {
- for (vector<ntlLightObject*>::iterator iter = lightlist->begin();
- iter != lightlist->end();
- iter++) {
-
- /* let light illuminate point */
- currentColor += (*iter)->illuminatePoint( reflectedRay, closest, highlightColor );
-
- } // for all lights
- }
-
- // recurse ?
- if ((mDepth < mpGlob->getRayMaxDepth() )&&(currRefl>RAY_THRESHOLD)) {
-
- if(badRefl) {
- ntlVec3Gfx intersectionPosition2;
- ntlGeometryObject *closest2 = NULL;
- gfxReal minT2 = GFX_REAL_MAX;
- ntlTriangle *tri2 = NULL;
- ntlVec3Gfx normal2;
-
- ntlVec3Gfx refractionPosition2(mOrigin + (mDirection * minT) );
- refractionPosition2 -= (triangleNormal*getVecEpsilon() );
-
- ntlRay reflectedRay2 = ntlRay(refractionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
- mpGlob->getRenderScene()->intersectScene(reflectedRay2, minT2, normal2, tri2, 0);
- if(minT2>0) {
- closest2 = mpGlob->getRenderScene()->getObject( tri2->getObjectId() );
- }
-
- /* object hit... */
- if (closest2 != NULL) {
- ntlVec3Gfx triangleNormal2 = tri2->getNormal();
- gfxReal valDN2;
- valDN2 = dot(reflectedDir, triangleNormal2);
- if( valDN2 > 0.0) {
- triangleNormal2 = triangleNormal2 * -1.0;
- intersectionPosition2 = ntlVec3Gfx(intersectionPosition + (reflectedDir * (minT2)) );
- /* correct intersection position and create new reflected ray */
- intersectionPosition2 += ( triangleNormal2*getVecEpsilon() );
- reflectedRay = ntlRay(intersectionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob);
- } else {
- // ray seems to work, continue normally ?
- }
-
- }
-
- }
-
- // add mirror color multiplied by mirror factor of surface
- if(mpGlob->getDebugOut() > 5) errorOut("Reflected ray from depth "<<mDepth<<", dir "<<reflectedDir );
- ntlColor reflectedColor = reflectedRay.shade() * currRefl;
- currentColor += reflectedColor;
- }
-
- /* Trace another ray on for transparent objects */
- if(currTrans > RAY_THRESHOLD) {
- /* position at the other side of the surface, along ray */
- ntlVec3Gfx refraction_position(mOrigin + (mDirection * minT) );
- refraction_position += (mDirection * getVecEpsilon());
- refraction_position -= (triangleNormal*getVecEpsilon() );
- ntlColor refracCol(0.0); /* refracted color */
-
- /* trace refracted ray */
- ntlRay transRay(refraction_position, refractedDir, mDepth+1, mContribution*currTrans, mpGlob);
- transRay.setRefracted(1);
- transRay.setNormal( normal );
- if(mDepth < mpGlob->getRayMaxDepth() ) {
- // full reflection should make sure refracindex&fresnel are on...
- if((0)||(!refRefl)) {
- if(mpGlob->getDebugOut() > 5) errorOut("Refracted ray from depth "<<mDepth<<", dir "<<refractedDir );
- refracCol = transRay.shade();
- } else {
- //we shouldnt reach this!
- if(mpGlob->getDebugOut() > 5) errorOut("Fully reflected ray from depth "<<mDepth<<", dir "<<reflectedDir );
- refracCol = reflectedRay.shade();
- }
- }
- //errMsg("REFMIR","t"<<currTrans<<" thres"<<RAY_THRESHOLD<<" mirr"<<currRefl<<" refRefl"<<refRefl<<" md"<<mDepth);
-
- /* calculate color */
- // use transadditive setting!?
- /* additive transparency "light amplification" */
- //? ntlColor add_col = currentColor + refracCol * currTrans;
- /* mix additive and subtractive */
- //? add_col += sub_col;
- //? currentColor += (refracCol * currTrans);
-
- /* subtractive transparency, more realistic */
- ntlColor sub_col = (refracCol * currTrans) + ( currentColor * (1.0-currTrans) );
- currentColor = sub_col;
-
- }
-
- /* add highlights (should not be affected by transparence as the diffuse reflections */
- currentColor += highlightColor;
-
- /* attentuate as a last step*/
- /* check if we're on the inside or outside */
- if(intersectionInside) {
- gfxReal kr,kg,kb; /* attentuation */
- /* calculate attentuation */
- ntlColor attCol = clossurf->getTransAttCol();
- kr = exp( attCol[0] * minT );
- kg = exp( attCol[1] * minT );
- kb = exp( attCol[2] * minT );
- currentColor = currentColor * ntlColor(kr,kg,kb);
- }
-
- /* done... */
- if(mpGlob->getDebugOut() > 5) { errorOut("Ray "<<mDepth<<" color "<<currentColor ); }
- return ntlColor(currentColor);
- }
-
-#endif // ELBEEM_PLUGIN
- /* no object hit -> ray goes to infinity */
- return mpGlob->getBackgroundCol();
-}
-
-
-
-/******************************************************************************
- ******************************************************************************
- ******************************************************************************
- * scene implementation
- ******************************************************************************
- ******************************************************************************
- *****************************************************************************/
-
-
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-ntlScene::ntlScene( ntlRenderGlobals *glob, bool del ) :
- mpGlob( glob ), mSceneDel(del),
- mpTree( NULL ),
- mSceneBuilt( false ), mFirstInitDone( false )
-{
-}
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlScene::~ntlScene()
-{
- if(mpTree != NULL) delete mpTree;
-
- // cleanup lists, only if this is the rendering cleanup scene
- if(mSceneDel)
- {
- for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
- iter != mGeos.end(); iter++) {
- //errMsg("ntlScene::~ntlScene","Deleting obj "<<(*iter)->getName() );
- delete (*iter);
- }
- for (vector<ntlLightObject*>::iterator iter = mpGlob->getLightList()->begin();
- iter != mpGlob->getLightList()->end(); iter++) {
- delete (*iter);
- }
- for (vector<ntlMaterial*>::iterator iter = mpGlob->getMaterials()->begin();
- iter != mpGlob->getMaterials()->end(); iter++) {
- delete (*iter);
- }
- }
- errMsg("ntlScene::~ntlScene","Deleted, ObjFree:"<<mSceneDel);
-}
-
-
-/******************************************************************************
- * Build the scene arrays (obj, tris etc.)
- *****************************************************************************/
-void ntlScene::buildScene(double time,bool firstInit)
-{
- const bool buildInfo=true;
-
- if(firstInit) {
- mObjects.clear();
- /* init geometry array, first all standard objects */
- for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
- iter != mGeos.end(); iter++) {
- bool geoinit = false;
- int tid = (*iter)->getTypeId();
- if(tid & GEOCLASSTID_OBJECT) {
- ntlGeometryObject *geoobj = (ntlGeometryObject*)(*iter);
- geoinit = true;
- mObjects.push_back( geoobj );
- if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added GeoObj "<<geoobj->getName()<<" Id:"<<geoobj->getObjectId(), 5 );
- }
- //if(geoshad) {
- if(tid & GEOCLASSTID_SHADER) {
- ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter);
- geoinit = true;
- if(!mFirstInitDone) {
- // only on first init
- geoshad->initializeShader();
- }
- for (vector<ntlGeometryObject*>::iterator siter = geoshad->getObjectsBegin();
- siter != geoshad->getObjectsEnd();
- siter++) {
- if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName()<<" Id:"<<(*siter)->getObjectId(), 5 );
- mObjects.push_back( (*siter) );
- }
- }
-
- if(!geoinit) {
- errFatal("ntlScene::BuildScene","Invalid geometry class!", SIMWORLD_INITERROR);
- return;
- }
- }
- }
-
- // collect triangles
- mTriangles.clear();
- mVertices.clear();
- mVertNormals.clear();
-
- /* for test mode deactivate transparencies etc. */
- if( mpGlob->getTestMode() ) {
- debugOut("ntlScene::buildScene : Test Mode activated!", 2);
- // assign random colors to dark materials
- int matCounter = 0;
- ntlColor stdCols[] = { ntlColor(0,0,1.0), ntlColor(0,1.0,0), ntlColor(1.0,0.7,0) , ntlColor(0.7,0,0.6) };
- int stdColNum = 4;
- for (vector<ntlMaterial*>::iterator iter = mpGlob->getMaterials()->begin();
- iter != mpGlob->getMaterials()->end(); iter++) {
- (*iter)->setTransparence(0.0);
- (*iter)->setMirror(0.0);
- (*iter)->setFresnel(false);
- // too dark?
- if( norm((*iter)->getDiffuseRefl()) <0.01) {
- (*iter)->setDiffuseRefl( stdCols[matCounter] );
- matCounter ++;
- matCounter = matCounter%stdColNum;
- }
- }
-
- // restrict output file size to 400
- float downscale = 1.0;
- if(mpGlob->getResX() > 400){ downscale = 400.0/(float)mpGlob->getResX(); }
- if(mpGlob->getResY() > 400){
- float downscale2 = 400.0/(float)mpGlob->getResY();
- if(downscale2<downscale) downscale=downscale2;
- }
- mpGlob->setResX( (int)(mpGlob->getResX() * downscale) );
- mpGlob->setResY( (int)(mpGlob->getResY() * downscale) );
-
- }
-
- /* collect triangles from objects */
- int idCnt = 0; // give IDs to objects
- bool debugTriCollect = false;
- if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Start...",5);
- for (vector<ntlGeometryObject*>::iterator iter = mObjects.begin();
- iter != mObjects.end();
- iter++) {
- /* only add visible objects */
- if(firstInit) {
- if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collect init of "<<(*iter)->getName()<<" idCnt:"<<idCnt, 4 );
- (*iter)->initialize( mpGlob ); }
- if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collecting tris from "<<(*iter)->getName(), 4 );
-
- int vstart = mVertNormals.size();
- (*iter)->setObjectId(idCnt);
- (*iter)->getTriangles(time, &mTriangles, &mVertices, &mVertNormals, idCnt);
- (*iter)->applyTransformation(time, &mVertices, &mVertNormals, vstart, mVertices.size(), false );
-
- if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Done with "<<(*iter)->getName()<<" totTris:"<<mTriangles.size()<<" totVerts:"<<mVertices.size()<<" totNorms:"<<mVertNormals.size(), 4 );
- idCnt ++;
- }
- if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"End",5);
-
-
- /* calculate triangle normals, and initialize flags */
- for (vector<ntlTriangle>::iterator iter = mTriangles.begin();
- iter != mTriangles.end();
- iter++) {
-
- // calculate normal from triangle points
- ntlVec3Gfx normal =
- cross( (ntlVec3Gfx)( (mVertices[(*iter).getPoints()[2]] - mVertices[(*iter).getPoints()[0]]) *-1.0), // BLITZ minus sign right??
- (ntlVec3Gfx)(mVertices[(*iter).getPoints()[1]] - mVertices[(*iter).getPoints()[0]]) );
- normalize(normal);
- (*iter).setNormal( normal );
- }
-
-
-
- // scene geometry built
- mSceneBuilt = true;
-
- // init shaders that require complete geometry
- if(!mFirstInitDone) {
- // only on first init
- for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin();
- iter != mGeos.end(); iter++) {
- if( (*iter)->getTypeId() & GEOCLASSTID_SHADER ) {
- ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter);
- if(geoshad->postGeoConstrInit( mpGlob )) {
- errFatal("ntlScene::buildScene","Init failed for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
- return;
- }
- }
- }
- mFirstInitDone = true;
- }
-
- // check unused attributes (for classes and objects!)
- for (vector<ntlGeometryObject*>::iterator iter = mObjects.begin(); iter != mObjects.end(); iter++) {
- if((*iter)->getAttributeList()->checkUnusedParams()) {
- (*iter)->getAttributeList()->print(); // DEBUG
- errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
- return;
- }
- }
- for (vector<ntlGeometryClass*>::iterator iter = mGeos.begin(); iter != mGeos.end(); iter++) {
- if((*iter)->getAttributeList()->checkUnusedParams()) {
- (*iter)->getAttributeList()->print(); // DEBUG
- errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR );
- return;
- }
- }
-
-}
-
-/******************************************************************************
- * Prepare the scene triangles and maps for raytracing
- *****************************************************************************/
-void ntlScene::prepareScene(double time)
-{
- /* init triangles... */
- buildScene(time, false);
- // what for currently not used ???
- if(mpTree != NULL) delete mpTree;
- mpTree = new ntlTree(
-# if FSGR_STRICT_DEBUG!=1
- mpGlob->getTreeMaxDepth(), mpGlob->getTreeMaxTriangles(),
-# else
- mpGlob->getTreeMaxDepth()/3*2, mpGlob->getTreeMaxTriangles()*2,
-# endif
- this, TRI_GEOMETRY );
-
- //debMsgStd("ntlScene::prepareScene",DM_MSG,"Stats - tris:"<< (int)mTriangles.size()<<" verts:"<<mVertices.size()<<" vnorms:"<<mVertNormals.size(), 5 );
-}
-/******************************************************************************
- * Do some memory cleaning, when frame is finished
- *****************************************************************************/
-void ntlScene::cleanupScene( void )
-{
- mTriangles.clear();
- mVertices.clear();
- mVertNormals.clear();
-
- if(mpTree != NULL) delete mpTree;
- mpTree = NULL;
-}
-
-
-/******************************************************************************
- * Intersect a ray with the scene triangles
- *****************************************************************************/
-void ntlScene::intersectScene(const ntlRay &r, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri,int flags) const
-{
- distance = -1.0;
- mpGlob->setCounterSceneInter( mpGlob->getCounterSceneInter()+1 );
- mpTree->intersect(r, distance, normal, tri, flags, false);
-}
-
-
-
-
-
diff --git a/intern/elbeem/intern/ntl_ray.h b/intern/elbeem/intern/ntl_ray.h
deleted file mode 100644
index 064fce27059..00000000000
--- a/intern/elbeem/intern/ntl_ray.h
+++ /dev/null
@@ -1,438 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * ray class
- *
- *****************************************************************************/
-#ifndef NTL_RAY_H
-#define NTL_RAY_H
-
-#include <sstream>
-#include "ntl_vector3dim.h"
-#include "ntl_lighting.h"
-#include "ntl_geometryobject.h"
-#include "ntl_bsptree.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlTriangle;
-class ntlRay;
-class ntlTree;
-class ntlScene;
-class ntlRenderGlobals;
-class ntlGeometryObject;
-
-//! store data for an intersection of a ray and a triangle
-// NOT YET USED
-class ntlIntersection {
- public:
-
- ntlIntersection() :
- distance(-1.0), normal(0.0),
- ray(NULL), tri(NULL), flags(0) { };
-
- gfxReal distance;
- ntlVec3Gfx normal;
- ntlRay *ray;
- ntlTriangle *tri;
- char flags;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlIntersection")
-#endif
-};
-
-//! the main ray class
-class ntlRay
-{
-public:
- // CONSTRUCTORS
- //! Initialize ray memebers, prints error message
- ntlRay();
- //! Copy constructor, copy all members
- ntlRay(const ntlRay &r);
- //! Explicitly init member variables with global render object
- ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob);
- //! Destructor
- ~ntlRay();
-
- //! Set the refraction flag for refracted rays
- inline void setRefracted(unsigned char set) { mIsRefracted = set; }
- inline void setReflected(unsigned char set) { mIsReflected = set; }
-
- //! main ray recursion function
- /*!
- * First get closest object intersection, return background color if nothing
- * was hit, else calculate shading and reflection components
- * and return mixed color */
- const ntlColor shade() /*const*/;
-
- /*! Trace a photon through the scene */
- void tracePhoton(ntlColor) const;
-
- //! intersect ray with AABB
- void intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &normal, ntlVec3Gfx &retcoord) const;
- void intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &normal, ntlVec3Gfx &retcoord) const;
- void intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const;
- // intersection routines in bsptree.cpp
- //! optimized intersect ray with triangle
- inline void intersectTriangle(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const;
- //! optimized intersect ray with triangle along +X axis dir
- inline void intersectTriangleX(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const;
- //! intersect only with front side
- inline void intersectTriangleFront(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const;
- //! intersect ray only with backsides
- inline void intersectTriangleBack(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const;
-
- // access methods
- //! Returns the ray origin
- inline ntlVec3Gfx getOrigin() const { return ntlVec3Gfx(mOrigin); }
- //! Returns the ray direction
- inline ntlVec3Gfx getDirection() const { return ntlVec3Gfx(mDirection); }
- /*! Returns the ray relfection normal */
- inline ntlVec3Gfx getNormal() const { return ntlVec3Gfx(mvNormal); }
- //! Is this ray refracted?
- inline unsigned char getRefracted() const { return mIsRefracted; }
- inline unsigned char getReflected() const { return mIsReflected; }
- /*! Get position along ray */
- inline ntlVec3Gfx getPositionAt(gfxReal t) const { return (mOrigin+(mDirection*t)); }
- /*! Get render globals pointer of this ray */
- inline ntlRenderGlobals *getRenderglobals( void ) const { return mpGlob; }
- /*! get this ray's ID */
- inline int getID( void ) const { return mID; }
-
- /*! Set origin of this ray */
- inline void setOrigin(ntlVec3Gfx set) { mOrigin = set; }
- /*! Set direction of this ray */
- inline void setDirection(ntlVec3Gfx set) { mDirection = set; }
- /*! Set normal of this ray */
- inline void setNormal(ntlVec3Gfx set) { mvNormal = set; }
-
-protected:
- /* Calulates the Lambertian and Specular color for
- * the given reflection and returns it */
- const ntlColor getShadedColor(ntlLightObject *light, const ntlRay &reflectedray,
- const ntlVec3Gfx &normal, ntlMaterial *surf) const;
-
-private:
- /*! Origin of ray */
- ntlVec3Gfx mOrigin;
- /*! Normalized direction vector of ray */
- ntlVec3Gfx mDirection;
- /*! For reflected/refracted rays, the normal is stored here */
- ntlVec3Gfx mvNormal;
- /*! recursion depth */
- unsigned int mDepth;
- /*! How much does this ray contribute to the surface color? abort if too small */
- gfxReal mContribution;
-
- /*! Global rendering settings */
- ntlRenderGlobals *mpGlob;
-
- /*! If this ray is a refracted one, this flag has to be set
- * This is necessary to for example also give the background color
- * to refracted rays. Otherwise things may look strange...
- */
- unsigned char mIsRefracted;
- unsigned char mIsReflected;
-
- /*! ID of this ray (from renderglobals */
- int mID;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlRay")
-#endif
-};
-
-
-/******************************************************************************
- *
- * a single triangle
- *
- *****************************************************************************/
-
-// triangle intersection code in bsptree.cpp
-// intersectTriangle(vector<ntlVec3Gfx> *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v);
-
-/*! Triangle flag defines */
-#define TRI_GEOMETRY (1<<0)
-#define TRI_CASTSHADOWS (1<<1)
-
-
-class ntlTriangle
-{
-public:
- /* CONSTRUCTORS */
- /*! Default constructor */
- inline ntlTriangle( void );
- /*! Constructor with parameters */
- inline ntlTriangle(int *p, bool smooth, int obj, ntlVec3Gfx norm, int setflags);
- /*! Copy - Constructor */
- inline ntlTriangle(const ntlTriangle &tri);
- /*! Destructor */
- inline ~ntlTriangle() {}
-
- /* Access methods */
-
- /*! Acces to points of triangle */
- inline int *getPoints( void ) { return mPoints; }
- /*! Acces normal smoothing */
- inline bool getSmoothNormals( void ) const { return mSmoothNormals; }
- inline void setSmoothNormals( bool set){ mSmoothNormals = set; }
- /*! Access object */
- inline int getObjectId( void ) const { return mObjectId; }
- inline void setObjectId( int set) { mObjectId = set; }
- /*! Acces normal index */
- inline ntlVec3Gfx getNormal( void ) const { return mNormal; }
- inline void setNormal( ntlVec3Gfx set ) { mNormal = set; }
- /*! Acces flags */
- inline int getFlags( void ) const { return mFlags; }
- inline void setFlags( int set ) { mFlags = set; }
- /*! Access last intersection ray ID */
- inline int getLastRay( void ) const { return mLastRay; }
- inline void setLastRay( int set ) { mLastRay = set; }
- /*! Acces bbox id */
- inline int getBBoxId( void ) const { return mBBoxId; }
- inline void setBBoxId( int set ) { mBBoxId = set; }
-
- /*! Get average of the three points for this axis */
- inline gfxReal getAverage( int axis ) const;
-
- /*! operator < for sorting, uses global sorting axis */
- inline friend bool operator<(const ntlTriangle &lhs, const ntlTriangle &rhs);
- /*! operator > for sorting, uses global sorting axis */
- inline friend bool operator>(const ntlTriangle &lhs, const ntlTriangle &rhs);
-
-protected:
-
-private:
-
- /*! indices to the three points of the triangle */
- int mPoints[3];
-
- /*! bounding box id (for tree generation), -1 if invalid */
- int mBBoxId;
-
- /*! Should the normals of this triangle get smoothed? */
- bool mSmoothNormals;
-
- /*! Id of parent object */
- int mObjectId;
-
- /*! Index to normal (for not smooth triangles) */
- //int mNormalIndex; ??
- ntlVec3Gfx mNormal;
-
- /*! Flags for object attributes cast shadows */
- int mFlags;
-
- /*! ID of last ray that an intersection was calculated for */
- int mLastRay;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlTriangle")
-#endif
-};
-
-
-
-
-/******************************************************************************
- * Default Constructor
- *****************************************************************************/
-ntlTriangle::ntlTriangle( void ) :
- mBBoxId(-1),
- mLastRay( 0 )
-{
- mPoints[0] = mPoints[1] = mPoints[2] = 0;
- mSmoothNormals = 0;
- mObjectId = 0;
- mNormal = ntlVec3Gfx(0.0);
- mFlags = 0;
-}
-
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-ntlTriangle::ntlTriangle(int *p, bool smooth, int obj, ntlVec3Gfx norm, int setflags) :
- mBBoxId(-1),
- mLastRay( 0 )
-{
- mPoints[0] = p[0];
- mPoints[1] = p[1];
- mPoints[2] = p[2];
- mSmoothNormals = smooth;
- mObjectId = obj;
- mNormal = norm;
- mFlags = setflags;
-}
-
-
-/******************************************************************************
- * Copy Constructor
- *****************************************************************************/
-ntlTriangle::ntlTriangle(const ntlTriangle &tri) :
- mBBoxId(-1),
- mLastRay( 0 )
-{
- mPoints[0] = tri.mPoints[0];
- mPoints[1] = tri.mPoints[1];
- mPoints[2] = tri.mPoints[2];
- mSmoothNormals = tri.mSmoothNormals;
- mObjectId = tri.mObjectId;
- mNormal = tri.mNormal;
- mFlags = tri.mFlags;
-}
-
-
-
-
-/******************************************************************************
- * Triangle sorting functions
- *****************************************************************************/
-
-/* variables imported from ntl_bsptree.cc, necessary for using the stl sort funtion */
-/* Static global variable for sorting direction */
-extern int globalSortingAxis;
-/* Access to points array for sorting */
-extern vector<ntlVec3Gfx> *globalSortingPoints;
-
-
-gfxReal ntlTriangle::getAverage( int axis ) const
-{
- return ( ( (*globalSortingPoints)[ mPoints[0] ][axis] +
- (*globalSortingPoints)[ mPoints[1] ][axis] +
- (*globalSortingPoints)[ mPoints[2] ][axis] )/3.0);
-}
-
-bool operator<(const ntlTriangle &lhs,const ntlTriangle &rhs)
-{
- return ( lhs.getAverage(globalSortingAxis) <
- rhs.getAverage(globalSortingAxis) );
-}
-
-bool operator>(const ntlTriangle &lhs,const ntlTriangle &rhs)
-{
- return ( lhs.getAverage(globalSortingAxis) >
- rhs.getAverage(globalSortingAxis) );
-}
-
-
-
-/******************************************************************************
- *
- * Scene object, that contains and manages all geometry objects
- *
- *****************************************************************************/
-
-
-
-class ntlScene
-{
-public:
- /* CONSTRUCTORS */
- /*! Default constructor */
- ntlScene( ntlRenderGlobals *glob, bool del=true );
- /*! Default destructor */
- ~ntlScene();
-
- /*! Add an object to the scene */
- inline void addGeoClass(ntlGeometryClass *geo) {
- mGeos.push_back( geo );
- geo->setObjectId(mGeos.size());
- }
- /*! Add a geo object to the scene, warning - only needed for hand init */
- inline void addGeoObject(ntlGeometryObject *geo) { mObjects.push_back( geo ); }
-
- /*! Acces a certain object */
- inline ntlGeometryObject *getObject(int id) {
- if(!mSceneBuilt) { errFatal("ntlScene::getObject","Scene not inited!", SIMWORLD_INITERROR); }
- return mObjects[id]; }
-
- /*! Acces object array */
- inline vector<ntlGeometryObject*> *getObjects() {
- if(!mSceneBuilt) { errFatal("ntlScene::getObjects[]","Scene not inited!", SIMWORLD_INITERROR); }
- return &mObjects; }
-
- /*! Acces geo class array */
- inline vector<ntlGeometryClass*> *getGeoClasses() {
- if(!mSceneBuilt) { errFatal("ntlScene::getGeoClasses[]","Scene not inited!", SIMWORLD_INITERROR); }
- return &mGeos; }
-
- /*! draw scene with opengl */
- //void draw();
-
- /*! Build/first init the scene arrays */
- void buildScene(double time, bool firstInit);
-
- //! Prepare the scene triangles and maps for raytracing
- void prepareScene(double time);
- //! Do some memory cleaning, when frame is finished
- void cleanupScene( void );
-
- /*! Intersect a ray with the scene triangles */
- void intersectScene(const ntlRay &r, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags) const;
-
- /*! return a vertex */
- ntlVec3Gfx getVertex(int index) { return mVertices[index]; }
-
- // for tree generation
- /*! return pointer to vertices vector */
- vector<ntlVec3Gfx> *getVertexPointer( void ) { return &mVertices; }
- /*! return pointer to vertices vector */
- vector<ntlVec3Gfx> *getVertexNormalPointer( void ) { return &mVertNormals; }
- /*! return pointer to vertices vector */
- vector<ntlTriangle> *getTrianglePointer( void ) { return &mTriangles; }
-
-private:
-
- /*! Global settings */
- ntlRenderGlobals *mpGlob;
-
- /*! free objects? (only necessary for render scene, which contains all) */
- bool mSceneDel;
-
- /*! List of geometry classes */
- vector<ntlGeometryClass *> mGeos;
-
- /*! List of geometry objects */
- vector<ntlGeometryObject *> mObjects;
-
- /*! List of triangles */
- vector<ntlTriangle> mTriangles;
- /*! List of vertices */
- vector<ntlVec3Gfx> mVertices;
- /*! List of normals */
- vector<ntlVec3Gfx> mVertNormals;
- /*! List of triangle normals */
- vector<ntlVec3Gfx> mTriangleNormals;
-
- /*! Tree to store quickly intersect triangles */
- ntlTree *mpTree;
-
- /*! was the scene successfully built? only then getObject(i) requests are valid */
- bool mSceneBuilt;
-
- /*! shader/obj initializations are only done on first init */
- bool mFirstInitDone;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlScene")
-#endif
-};
-
-
-#endif
-
diff --git a/intern/elbeem/intern/ntl_vector3dim.h b/intern/elbeem/intern/ntl_vector3dim.h
deleted file mode 100644
index 89360342864..00000000000
--- a/intern/elbeem/intern/ntl_vector3dim.h
+++ /dev/null
@@ -1,1105 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Basic vector class used everywhere, either blitz or inlined GRAPA class
- *
- *****************************************************************************/
-#ifndef NTL_VECTOR3DIM_H
-#define NTL_VECTOR3DIM_H
-
-// this serves as the main include file
-// for all kinds of stuff that might be required
-// under windos there seem to be strange
-// errors when including the STL header too
-// late...
-
-#ifdef _MSC_VER
-#define _USE_MATH_DEFINES 1
-#endif
-
-#include <iostream>
-#include <map>
-#include <vector>
-#include <string>
-#include <sstream>
-#include <math.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-/* absolute value */
-template < class T >
-inline T
-ABS( T a )
-{ return (0 < a) ? a : -a ; }
-
-// hack for MSVC6.0 compiler
-#ifdef _MSC_VER
-#if _MSC_VER < 1300
-#define for if(false); else for
-#define map std::map
-#define vector std::vector
-#define string std::string
-// use this define for MSVC6 stuff hereafter
-#define USE_MSVC6FIXES
-#else // _MSC_VER < 1300 , 7.0 or higher
-using std::map;
-using std::vector;
-using std::string;
-#endif
-#else // not MSVC6
-// for proper compilers...
-using std::map;
-using std::vector;
-using std::string;
-#endif // MSVC6
-
-#ifdef __APPLE_CC__
-// apple
-#else
-#ifdef WIN32
-
-// windows values missing, see below
-#ifndef snprintf
-#define snprintf _snprintf
-#endif
-
-#ifdef _MSC_VER
-#if _MSC_VER >= 1300
-#include <float.h>
-#endif
-#endif
-
-#else // WIN32
-
-// floating point limits for linux,*bsd etc...
-#include <float.h>
-
-#endif // WIN32
-#endif // __APPLE_CC__
-
-// windos, hardcoded limits for now...
-// for e.g. MSVC compiler...
-// some of these defines can be needed
-// for linux systems as well (e.g. FLT_MAX)
-#ifndef __FLT_MAX__
-# ifdef FLT_MAX // try to use it instead
-# define __FLT_MAX__ FLT_MAX
-# else // FLT_MAX
-# define __FLT_MAX__ 3.402823466e+38f
-# endif // FLT_MAX
-#endif // __FLT_MAX__
-#ifndef __DBL_MAX__
-# ifdef DBL_MAX // try to use it instead
-# define __DBL_MAX__ DBL_MAX
-# else // DBL_MAX
-# define __DBL_MAX__ 1.7976931348623158e+308
-# endif // DBL_MAX
-#endif // __DBL_MAX__
-
-#ifndef M_PI
-#define M_PI 3.1415926536
-#endif
-
-#ifndef M_E
-#define M_E 2.7182818284
-#endif
-
-// make sure elbeem plugin def is valid
-#if ELBEEM_BLENDER==1
-#ifndef ELBEEM_PLUGIN
-#define ELBEEM_PLUGIN 1
-#endif // !ELBEEM_PLUGIN
-#endif // ELBEEM_BLENDER==1
-
-// make sure GUI support is disabled for plugin use
-#if ELBEEM_PLUGIN==1
-#ifndef NOGUI
-#define NOGUI 1
-#endif // !NOGUI
-#endif // ELBEEM_PLUGIN==1
-
-
-// basic inlined vector class
-template<class Scalar>
-class ntlVector3Dim
-{
-public:
- // Constructor
- inline ntlVector3Dim(void );
- // Copy-Constructor
- inline ntlVector3Dim(const ntlVector3Dim<Scalar> &v );
- inline ntlVector3Dim(const float *);
- inline ntlVector3Dim(const double *);
- // construct a vector from one Scalar
- inline ntlVector3Dim(Scalar);
- // construct a vector from three Scalars
- inline ntlVector3Dim(Scalar, Scalar, Scalar);
-
- // get address of array for OpenGL
- Scalar *getAddress() { return value; }
-
- // Assignment operator
- inline const ntlVector3Dim<Scalar>& operator= (const ntlVector3Dim<Scalar>& v);
- // Assignment operator
- inline const ntlVector3Dim<Scalar>& operator= (Scalar s);
- // Assign and add operator
- inline const ntlVector3Dim<Scalar>& operator+= (const ntlVector3Dim<Scalar>& v);
- // Assign and add operator
- inline const ntlVector3Dim<Scalar>& operator+= (Scalar s);
- // Assign and sub operator
- inline const ntlVector3Dim<Scalar>& operator-= (const ntlVector3Dim<Scalar>& v);
- // Assign and sub operator
- inline const ntlVector3Dim<Scalar>& operator-= (Scalar s);
- // Assign and mult operator
- inline const ntlVector3Dim<Scalar>& operator*= (const ntlVector3Dim<Scalar>& v);
- // Assign and mult operator
- inline const ntlVector3Dim<Scalar>& operator*= (Scalar s);
- // Assign and div operator
- inline const ntlVector3Dim<Scalar>& operator/= (const ntlVector3Dim<Scalar>& v);
- // Assign and div operator
- inline const ntlVector3Dim<Scalar>& operator/= (Scalar s);
-
-
- // unary operator
- inline ntlVector3Dim<Scalar> operator- () const;
-
- // binary operator add
- inline ntlVector3Dim<Scalar> operator+ (const ntlVector3Dim<Scalar>&) const;
- // binary operator add
- inline ntlVector3Dim<Scalar> operator+ (Scalar) const;
- // binary operator sub
- inline ntlVector3Dim<Scalar> operator- (const ntlVector3Dim<Scalar>&) const;
- // binary operator sub
- inline ntlVector3Dim<Scalar> operator- (Scalar) const;
- // binary operator mult
- inline ntlVector3Dim<Scalar> operator* (const ntlVector3Dim<Scalar>&) const;
- // binary operator mult
- inline ntlVector3Dim<Scalar> operator* (Scalar) const;
- // binary operator div
- inline ntlVector3Dim<Scalar> operator/ (const ntlVector3Dim<Scalar>&) const;
- // binary operator div
- inline ntlVector3Dim<Scalar> operator/ (Scalar) const;
-
- // Projection normal to a vector
- inline ntlVector3Dim<Scalar> getOrthogonalntlVector3Dim() const;
- // Project into a plane
- inline const ntlVector3Dim<Scalar>& projectNormalTo(const ntlVector3Dim<Scalar> &v);
-
- // minimize
- inline const ntlVector3Dim<Scalar> &minimize(const ntlVector3Dim<Scalar> &);
- // maximize
- inline const ntlVector3Dim<Scalar> &maximize(const ntlVector3Dim<Scalar> &);
-
- // access operator
- inline Scalar& operator[](unsigned int i);
- // access operator
- inline const Scalar& operator[](unsigned int i) const;
-
-protected:
-
-private:
- Scalar value[3]; //< Storage of vector values
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlVector3Dim")
-#endif
-};
-
-
-
-
-//------------------------------------------------------------------------------
-// STREAM FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-//! global string for formatting vector output in utilities.cpp
-extern const char *globVecFormatStr;
-
-/*************************************************************************
- Outputs the object in human readable form using the format
- [x,y,z]
- */
-template<class Scalar>
-std::ostream&
-operator<<( std::ostream& os, const ntlVector3Dim<Scalar>& i )
-{
- char buf[256];
- snprintf(buf,256,globVecFormatStr,i[0],i[1],i[2]);
- os << string(buf);
- //os << '[' << i[0] << ", " << i[1] << ", " << i[2] << ']';
- return os;
-}
-
-
-
-/*************************************************************************
- Reads the contents of the object from a stream using the same format
- as the output operator.
- */
-template<class Scalar>
-std::istream&
-operator>>( std::istream& is, ntlVector3Dim<Scalar>& i )
-{
- char c;
- char dummy[3];
- is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c;
- return is;
-}
-
-
-//------------------------------------------------------------------------------
-// VECTOR inline FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Constructor.
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim( void )
-{
- value[0] = value[1] = value[2] = 0;
-}
-
-
-
-/*************************************************************************
- Copy-Constructor.
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim( const ntlVector3Dim<Scalar> &v )
-{
- value[0] = v.value[0];
- value[1] = v.value[1];
- value[2] = v.value[2];
-}
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim( const float *fvalue)
-{
- value[0] = (Scalar)fvalue[0];
- value[1] = (Scalar)fvalue[1];
- value[2] = (Scalar)fvalue[2];
-}
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim( const double *fvalue)
-{
- value[0] = (Scalar)fvalue[0];
- value[1] = (Scalar)fvalue[1];
- value[2] = (Scalar)fvalue[2];
-}
-
-
-
-/*************************************************************************
- Constructor for a vector from a single Scalar. All components of
- the vector get the same value.
- \param s The value to set
- \return The new vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim(Scalar s )
-{
- value[0]= s;
- value[1]= s;
- value[2]= s;
-}
-
-
-/*************************************************************************
- Constructor for a vector from three Scalars.
- \param s1 The value for the first vector component
- \param s2 The value for the second vector component
- \param s3 The value for the third vector component
- \return The new vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>::ntlVector3Dim(Scalar s1, Scalar s2, Scalar s3)
-{
- value[0]= s1;
- value[1]= s2;
- value[2]= s3;
-}
-
-
-/*************************************************************************
- Compute the vector product of two 3D vectors
- \param v Second vector to compute the product with
- \return A new vector with the product values
- */
-/*template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator^( const ntlVector3Dim<Scalar> &v ) const
-{
- return ntlVector3Dim<Scalar>(value[1]*v.value[2] - value[2]*v.value[1],
- value[2]*v.value[0] - value[0]*v.value[2],
- value[0]*v.value[1] - value[1]*v.value[0]);
-}*/
-
-
-/*************************************************************************
- Copy a ntlVector3Dim componentwise.
- \param v vector with values to be copied
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator=( const ntlVector3Dim<Scalar> &v )
-{
- value[0] = v.value[0];
- value[1] = v.value[1];
- value[2] = v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Copy a Scalar to each component.
- \param s The value to copy
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator=(Scalar s)
-{
- value[0] = s;
- value[1] = s;
- value[2] = s;
- return *this;
-}
-
-
-/*************************************************************************
- Add another ntlVector3Dim componentwise.
- \param v vector with values to be added
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator+=( const ntlVector3Dim<Scalar> &v )
-{
- value[0] += v.value[0];
- value[1] += v.value[1];
- value[2] += v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Add a Scalar value to each component.
- \param s Value to add
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator+=(Scalar s)
-{
- value[0] += s;
- value[1] += s;
- value[2] += s;
- return *this;
-}
-
-
-/*************************************************************************
- Subtract another vector componentwise.
- \param v vector of values to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator-=( const ntlVector3Dim<Scalar> &v )
-{
- value[0] -= v.value[0];
- value[1] -= v.value[1];
- value[2] -= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Subtract a Scalar value from each component.
- \param s Value to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator-=(Scalar s)
-{
- value[0]-= s;
- value[1]-= s;
- value[2]-= s;
- return *this;
-}
-
-
-/*************************************************************************
- Multiply with another vector componentwise.
- \param v vector of values to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator*=( const ntlVector3Dim<Scalar> &v )
-{
- value[0] *= v.value[0];
- value[1] *= v.value[1];
- value[2] *= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Multiply each component with a Scalar value.
- \param s Value to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator*=(Scalar s)
-{
- value[0] *= s;
- value[1] *= s;
- value[2] *= s;
- return *this;
-}
-
-
-/*************************************************************************
- Divide by another ntlVector3Dim componentwise.
- \param v vector of values to divide by
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator/=( const ntlVector3Dim<Scalar> &v )
-{
- value[0] /= v.value[0];
- value[1] /= v.value[1];
- value[2] /= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Divide each component by a Scalar value.
- \param s Value to divide by
- \return Reference to self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::operator/=(Scalar s)
-{
- value[0] /= s;
- value[1] /= s;
- value[2] /= s;
- return *this;
-}
-
-
-//------------------------------------------------------------------------------
-// unary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build componentwise the negative this vector.
- \return The new (negative) vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator-() const
-{
- return ntlVector3Dim<Scalar>(-value[0], -value[1], -value[2]);
-}
-
-
-
-//------------------------------------------------------------------------------
-// binary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build a vector with another vector added componentwise.
- \param v The second vector to add
- \return The sum vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator+( const ntlVector3Dim<Scalar> &v ) const
-{
- return ntlVector3Dim<Scalar>(value[0]+v.value[0],
- value[1]+v.value[1],
- value[2]+v.value[2]);
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value added to each component.
- \param s The Scalar value to add
- \return The sum vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator+(Scalar s) const
-{
- return ntlVector3Dim<Scalar>(value[0]+s,
- value[1]+s,
- value[2]+s);
-}
-
-
-/*************************************************************************
- Build a vector with another vector subtracted componentwise.
- \param v The second vector to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator-( const ntlVector3Dim<Scalar> &v ) const
-{
- return ntlVector3Dim<Scalar>(value[0]-v.value[0],
- value[1]-v.value[1],
- value[2]-v.value[2]);
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value subtracted componentwise.
- \param s The Scalar value to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator-(Scalar s ) const
-{
- return ntlVector3Dim<Scalar>(value[0]-s,
- value[1]-s,
- value[2]-s);
-}
-
-
-
-/*************************************************************************
- Build a vector with another vector multiplied by componentwise.
- \param v The second vector to muliply with
- \return The product vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator*( const ntlVector3Dim<Scalar>& v) const
-{
- return ntlVector3Dim<Scalar>(value[0]*v.value[0],
- value[1]*v.value[1],
- value[2]*v.value[2]);
-}
-
-
-/*************************************************************************
- Build a ntlVector3Dim with a Scalar value multiplied to each component.
- \param s The Scalar value to multiply with
- \return The product vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator*(Scalar s) const
-{
- return ntlVector3Dim<Scalar>(value[0]*s, value[1]*s, value[2]*s);
-}
-
-
-/*************************************************************************
- Build a vector divided componentwise by another vector.
- \param v The second vector to divide by
- \return The ratio vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator/(const ntlVector3Dim<Scalar>& v) const
-{
- return ntlVector3Dim<Scalar>(value[0]/v.value[0],
- value[1]/v.value[1],
- value[2]/v.value[2]);
-}
-
-
-
-/*************************************************************************
- Build a vector divided componentwise by a Scalar value.
- \param s The Scalar value to divide by
- \return The ratio vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::operator/(Scalar s) const
-{
- return ntlVector3Dim<Scalar>(value[0]/s,
- value[1]/s,
- value[2]/s);
-}
-
-
-
-
-
-/*************************************************************************
- Get a particular component of the vector.
- \param i Number of Scalar to get
- \return Reference to the component
- */
-template<class Scalar>
-inline Scalar&
-ntlVector3Dim<Scalar>::operator[]( unsigned int i )
-{
- return value[i];
-}
-
-
-/*************************************************************************
- Get a particular component of a constant vector.
- \param i Number of Scalar to get
- \return Reference to the component
- */
-template<class Scalar>
-inline const Scalar&
-ntlVector3Dim<Scalar>::operator[]( unsigned int i ) const
-{
- return value[i];
-}
-
-
-
-//------------------------------------------------------------------------------
-// BLITZ compatibility functions
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Compute the scalar product with another vector.
- \param v The second vector to work with
- \return The value of the scalar product
- */
-template<class Scalar>
-inline Scalar dot(const ntlVector3Dim<Scalar> &t, const ntlVector3Dim<Scalar> &v )
-{
- //return t.value[0]*v.value[0] + t.value[1]*v.value[1] + t.value[2]*v.value[2];
- return ((t[0]*v[0]) + (t[1]*v[1]) + (t[2]*v[2]));
-}
-
-
-/*************************************************************************
- Calculate the cross product of this and another vector
- */
-template<class Scalar>
-inline ntlVector3Dim<Scalar> cross(const ntlVector3Dim<Scalar> &t, const ntlVector3Dim<Scalar> &v)
-{
- ntlVector3Dim<Scalar> cp(
- ((t[1]*v[2]) - (t[2]*v[1])),
- ((t[2]*v[0]) - (t[0]*v[2])),
- ((t[0]*v[1]) - (t[1]*v[0])) );
- return cp;
-}
-
-
-
-
-/*************************************************************************
- Compute a vector that is orthonormal to self. Nothing else can be assumed
- for the direction of the new vector.
- \return The orthonormal vector
- */
-template<class Scalar>
-ntlVector3Dim<Scalar>
-ntlVector3Dim<Scalar>::getOrthogonalntlVector3Dim() const
-{
- // Determine the component with max. absolute value
- int max= (fabs(value[0]) > fabs(value[1])) ? 0 : 1;
- max= (fabs(value[max]) > fabs(value[2])) ? max : 2;
-
- /*************************************************************************
- Choose another axis than the one with max. component and project
- orthogonal to self
- */
- ntlVector3Dim<Scalar> vec(0.0);
- vec[(max+1)%3]= 1;
- vec.normalize();
- vec.projectNormalTo(this->getNormalized());
- return vec;
-}
-
-
-/*************************************************************************
- Projects the vector into a plane normal to the given vector, which must
- have unit length. Self is modified.
- \param v The plane normal
- \return The projected vector
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar>&
-ntlVector3Dim<Scalar>::projectNormalTo(const ntlVector3Dim<Scalar> &v)
-{
- Scalar sprod = dot(*this,v);
- value[0]= value[0] - v.value[0] * sprod;
- value[1]= value[1] - v.value[1] * sprod;
- value[2]= value[2] - v.value[2] * sprod;
- return *this;
-}
-
-
-
-//------------------------------------------------------------------------------
-// Other helper functions
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Minimize the vector, i.e. set each entry of the vector to the minimum
- of both values.
- \param pnt The second vector to compare with
- \return Reference to the modified self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar> &
-ntlVector3Dim<Scalar>::minimize(const ntlVector3Dim<Scalar> &pnt)
-{
- for (unsigned int i = 0; i < 3; i++)
- value[i] = MIN(value[i],pnt[i]);
- return *this;
-}
-
-
-
-/*************************************************************************
- Maximize the vector, i.e. set each entry of the vector to the maximum
- of both values.
- \param pnt The second vector to compare with
- \return Reference to the modified self
- */
-template<class Scalar>
-inline const ntlVector3Dim<Scalar> &
-ntlVector3Dim<Scalar>::maximize(const ntlVector3Dim<Scalar> &pnt)
-{
- for (unsigned int i = 0; i < 3; i++)
- value[i] = MAX(value[i],pnt[i]);
- return *this;
-}
-
-
-
-
-// ----
-
-// a 3D vector with double precision
-typedef ntlVector3Dim<double> ntlVec3d;
-
-// a 3D vector with single precision
-typedef ntlVector3Dim<float> ntlVec3f;
-
-// a 3D integer vector
-typedef ntlVector3Dim<int> ntlVec3i;
-
-// Color uses single precision fp values
-typedef ntlVec3f ntlColor;
-
-/* convert a float to double vector */
-template<class T> inline ntlVec3d vec2D(T v) { return ntlVec3d(v[0],v[1],v[2]); }
-template<class T> inline ntlVec3f vec2F(T v) { return ntlVec3f(v[0],v[1],v[2]); }
-template<class T> inline ntlColor vec2Col(T v) { return ntlColor(v[0],v[1],v[2]); }
-
-
-
-/************************************************************************/
-// graphics vector typing
-
-
-// use which fp-precision for raytracing? 1=float, 2=double
-
-/* VECTOR_EPSILON is the minimal vector length
- In order to be able to discriminate floating point values near zero, and
- to be sure not to fail a comparison because of roundoff errors, use this
- value as a threshold. */
-
-// use which fp-precision for graphics? 1=float, 2=double
-#ifdef PRECISION_GFX_SINGLE
-#define GFX_PRECISION 1
-#else
-#ifdef PRECISION_GFX_DOUBLE
-#define GFX_PRECISION 2
-#else
-// standard precision for graphics
-#ifndef GFX_PRECISION
-#define GFX_PRECISION 1
-#endif
-#endif
-#endif
-
-#if GFX_PRECISION==1
-typedef float gfxReal;
-#define GFX_REAL_MAX __FLT_MAX__
-//#define vecF2Gfx(x) (x)
-//#define vecGfx2F(x) (x)
-//#define vecD2Gfx(x) vecD2F(x)
-//#define vecGfx2D(x) vecF2D(x)
-#define VECTOR_EPSILON (1e-5f)
-#else
-typedef double gfxReal;
-#define GFX_REAL_MAX __DBL_MAX__
-//#define vecF2Gfx(x) vecD2F(x)
-//#define vecGfx2F(x) vecF2D(x)
-//#define vecD2Gfx(x) (x)
-//#define vecGfx2D(x) (x)
-#define VECTOR_EPSILON (1e-10)
-#endif
-
-/* fixed double prec. type, for epxlicitly double values */
-typedef double gfxDouble;
-
-// a 3D vector for graphics output, typically float?
-typedef ntlVector3Dim<gfxReal> ntlVec3Gfx;
-
-template<class T> inline ntlVec3Gfx vec2G(T v) { return ntlVec3Gfx(v[0],v[1],v[2]); }
-
-/* get minimal vector length value that can be discriminated. */
-//inline double getVecEpsilon() { return (double)VECTOR_EPSILON; }
-inline gfxReal getVecEpsilon() { return (gfxReal)VECTOR_EPSILON; }
-
-#define HAVE_GFXTYPES
-
-
-
-
-/************************************************************************/
-// HELPER FUNCTIONS, independent of implementation
-/************************************************************************/
-
-#define VECTOR_TYPE ntlVector3Dim<Scalar>
-
-
-/*************************************************************************
- Compute the length (norm) of the vector.
- \return The value of the norm
- */
-template<class Scalar>
-inline Scalar norm( const VECTOR_TYPE &v)
-{
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- return (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) ? 1. : sqrt(l);
-}
-
-
-/*************************************************************************
- Same as getNorm but doesnt sqrt
- */
-template<class Scalar>
-inline Scalar normNoSqrt( const VECTOR_TYPE &v)
-{
- return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
-}
-
-
-/*************************************************************************
- Compute a normalized vector based on this vector.
- \return The new normalized vector
- */
-template<class Scalar>
-inline VECTOR_TYPE getNormalized( const VECTOR_TYPE &v)
-{
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON)
- return v; /* normalized "enough"... */
- else if (l > VECTOR_EPSILON*VECTOR_EPSILON)
- {
- Scalar fac = 1./sqrt(l);
- return VECTOR_TYPE(v[0]*fac, v[1]*fac, v[2]*fac);
- }
- else
- return VECTOR_TYPE((Scalar)0);
-}
-
-
-/*************************************************************************
- Compute the norm of the vector and normalize it.
- \return The value of the norm
- */
-template<class Scalar>
-inline Scalar normalize( VECTOR_TYPE &v)
-{
- Scalar norm;
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) {
- norm = 1.;
- } else if (l > VECTOR_EPSILON*VECTOR_EPSILON) {
- norm = sqrt(l);
- Scalar fac = 1./norm;
- v[0] *= fac;
- v[1] *= fac;
- v[2] *= fac;
- } else {
- v[0]= v[1]= v[2]= 0;
- norm = 0.;
- }
- return (Scalar)norm;
-}
-
-
-/*************************************************************************
- Compute a vector, that is self (as an incoming
- vector) reflected at a surface with a distinct normal vector. Note
- that the normal is reversed, if the scalar product with it is positive.
- \param n The surface normal
- \return The new reflected vector
- */
-template<class Scalar>
-inline VECTOR_TYPE reflectVector(const VECTOR_TYPE &t, const VECTOR_TYPE &n)
-{
- VECTOR_TYPE nn= (dot(t, n) > 0.0) ? (n*-1.0) : n;
- return ( t - nn * (2.0 * dot(nn, t)) );
-}
-
-
-
-/*************************************************************************
- * My own refraction calculation
- * Taken from Glassner's book, section 5.2 (Heckberts method)
- */
-template<class Scalar>
-inline VECTOR_TYPE refractVector(const VECTOR_TYPE &t, const VECTOR_TYPE &normal, Scalar nt, Scalar nair, int &refRefl)
-{
- Scalar eta = nair / nt;
- Scalar n = -dot(t, normal);
- Scalar tt = 1.0 + eta*eta* (n*n-1.0);
- if(tt<0.0) {
- // we have total reflection!
- refRefl = 1;
- } else {
- // normal reflection
- tt = eta*n - sqrt(tt);
- return( t*eta + normal*tt );
- }
- return t;
-}
- /*double eta = nair / nt;
- double n = -((*this) | normal);
- double t = 1.0 + eta*eta* (n*n-1.0);
- if(t<0.0) {
- // we have total reflection!
- refRefl = 1;
- } else {
- // normal reflection
- t = eta*n - sqrt(t);
- return( (*this)*eta + normal*t );
- }
- return (*this);*/
-
-
-/*************************************************************************
- Test two ntlVector3Dims for equality based on the equality of their
- values within a small threshold.
- \param c The second vector to compare
- \return TRUE if both are equal
- \sa getEpsilon()
- */
-template<class Scalar>
-inline bool equal(const VECTOR_TYPE &v, const VECTOR_TYPE &c)
-{
- return (ABS(v[0]-c[0]) +
- ABS(v[1]-c[1]) +
- ABS(v[2]-c[2]) < VECTOR_EPSILON);
-}
-
-
-/*************************************************************************
- * Assume this vector is an RGB color, and convert it to HSV
- */
-template<class Scalar>
-inline void rgbToHsv( VECTOR_TYPE &V )
-{
- Scalar h=0,s=0,v=0;
- Scalar maxrgb, minrgb, delta;
- // convert to hsv...
- maxrgb = V[0];
- int maxindex = 1;
- if(V[2] > maxrgb){ maxrgb = V[2]; maxindex = 2; }
- if(V[1] > maxrgb){ maxrgb = V[1]; maxindex = 3; }
- minrgb = V[0];
- if(V[2] < minrgb) minrgb = V[2];
- if(V[1] < minrgb) minrgb = V[1];
-
- v = maxrgb;
- delta = maxrgb-minrgb;
-
- if(maxrgb > 0) s = delta/maxrgb;
- else s = 0;
-
- h = 0;
- if(s > 0) {
- if(maxindex == 1) {
- h = ((V[1]-V[2])/delta) + 0.0; }
- if(maxindex == 2) {
- h = ((V[2]-V[0])/delta) + 2.0; }
- if(maxindex == 3) {
- h = ((V[0]-V[1])/delta) + 4.0; }
- h *= 60.0;
- if(h < 0.0) h += 360.0;
- }
-
- V[0] = h;
- V[1] = s;
- V[2] = v;
-}
-
-/*************************************************************************
- * Assume this vector is HSV and convert to RGB
- */
-template<class Scalar>
-inline void hsvToRgb( VECTOR_TYPE &V )
-{
- Scalar h = V[0], s = V[1], v = V[2];
- Scalar r=0,g=0,b=0;
- Scalar p,q,t, fracth;
- int floorh;
- // ...and back to rgb
- if(s == 0) {
- r = g = b = v; }
- else {
- h /= 60.0;
- floorh = (int)h;
- fracth = h - floorh;
- p = v * (1.0 - s);
- q = v * (1.0 - (s * fracth));
- t = v * (1.0 - (s * (1.0 - fracth)));
- switch (floorh) {
- case 0: r = v; g = t; b = p; break;
- case 1: r = q; g = v; b = p; break;
- case 2: r = p; g = v; b = t; break;
- case 3: r = p; g = q; b = v; break;
- case 4: r = t; g = p; b = v; break;
- case 5: r = v; g = p; b = q; break;
- }
- }
-
- V[0] = r;
- V[1] = g;
- V[2] = b;
-}
-
-
-
-
-#endif /* NTL_VECTOR3DIM_HH */
diff --git a/intern/elbeem/intern/ntl_world.cpp b/intern/elbeem/intern/ntl_world.cpp
deleted file mode 100644
index 5f3d6e36b3b..00000000000
--- a/intern/elbeem/intern/ntl_world.cpp
+++ /dev/null
@@ -1,934 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Main renderer class
- *
- *****************************************************************************/
-
-
-#include <sys/stat.h>
-#include <sstream>
-#include "utilities.h"
-#include "ntl_world.h"
-#include "parametrizer.h"
-
-// for non-threaded renderViz
-#ifndef NOGUI
-#include "../gui/ntl_openglrenderer.h"
-#include "../gui/guifuncs.h"
-#include "../gui/frame.h"
-#endif
-
-
-/* external parser functions from cfgparser.cxx */
-#ifndef ELBEEM_PLUGIN
-/* parse given file as config file */
-void parseFile(string filename);
-/* set pointers for parsing */
-void setPointers( ntlRenderGlobals *setglob);
-#endif // ELBEEM_PLUGIN
-
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-
-ntlWorld::ntlWorld() {
- initDefaults();
-}
-
-ntlWorld::ntlWorld(string filename, bool commandlineMode)
-{
-#ifndef ELBEEM_PLUGIN
-
- initDefaults();
-# ifdef NOGUI
- commandlineMode = true; // remove warning...
-# endif // NOGUI
-
- // load config
- setPointers( getRenderGlobals() );
- parseFile( filename.c_str() );
-# ifndef NOGUI
- // setup opengl display, save first animation step for start time
- // init after parsing file...
- if(!commandlineMode) {
- mpOpenGLRenderer = new ntlOpenGLRenderer( mpGlob );
- }
-# endif // NOGUI
- finishWorldInit();
-
-#else // ELBEEM_PLUGIN
- errFatal("ntlWorld::init","Cfg file parsing not supported for API version! "<<filename<<" "<<commandlineMode, SIMWORLD_INITERROR);
-#endif // ELBEEM_PLUGIN
-}
-
-
-int globalDomainCounter = 1;
-int ntlWorld::addDomain(elbeemSimulationSettings *settings)
-{
- // create domain obj
- SimulationObject *sim = new SimulationObject();
- char simname[100];
- snprintf(simname,100,"domain%04d",globalDomainCounter);
- globalDomainCounter++;
- sim->setName(string(simname));
- mpGlob->getSims()->push_back( sim );
-
- // important - add to both, only render scene objects are free'd
- mpGlob->getRenderScene()->addGeoClass( sim );
- mpGlob->getSimScene()->addGeoClass( sim );
- sim->setGeoStart(ntlVec3Gfx(settings->geoStart[0],settings->geoStart[1],settings->geoStart[2]));
- sim->setGeoEnd(ntlVec3Gfx(
- settings->geoStart[0]+settings->geoSize[0],
- settings->geoStart[1]+settings->geoSize[1],
- settings->geoStart[2]+settings->geoSize[2] ));
- // further init in postGeoConstrInit/initializeLbmSimulation of SimulationObject
- sim->copyElbeemSettings(settings);
-
- Parametrizer *param = sim->getParametrizer();
- param->setSize( settings->resolutionxyz );
- param->setDomainSize( settings->realsize );
- param->setAniStart( settings->animStart );
- param->setNormalizedGStar( settings->gstar );
-
- // init domain channels
- vector<ParamFloat> valf;
- vector<ParamVec> valv;
- vector<double> time;
-
-#define INIT_CHANNEL_FLOAT(channel,size) \
- valf.clear(); time.clear(); elbeemSimplifyChannelFloat(channel,&size); \
- for(int i=0; i<size; i++) { valf.push_back( channel[2*i+0] ); time.push_back( channel[2*i+1] ); }
-#define INIT_CHANNEL_VEC(channel,size) \
- valv.clear(); time.clear(); elbeemSimplifyChannelVec3(channel,&size); \
- for(int i=0; i<size; i++) { valv.push_back( ParamVec(channel[4*i+0],channel[4*i+1],channel[4*i+2]) ); time.push_back( channel[4*i+3] ); }
-
- param->setViscosity( settings->viscosity );
- if((settings->channelViscosity)&&(settings->channelSizeViscosity>0)) {
- INIT_CHANNEL_FLOAT(settings->channelViscosity, settings->channelSizeViscosity);
- param->initViscosityChannel(valf,time); }
-
- param->setGravity( ParamVec(settings->gravity[0], settings->gravity[1], settings->gravity[2]) );
- if((settings->channelGravity)&&(settings->channelSizeGravity>0)) {
- INIT_CHANNEL_VEC(settings->channelGravity, settings->channelSizeGravity);
- param->initGravityChannel(valv,time); }
-
- param->setAniFrameTimeChannel( settings->aniFrameTime );
- if((settings->channelFrameTime)&&(settings->channelSizeFrameTime>0)) {
- INIT_CHANNEL_FLOAT(settings->channelFrameTime, settings->channelSizeFrameTime);
- param->initAniFrameTimeChannel(valf,time); }
-
-#undef INIT_CHANNEL_FLOAT
-#undef INIT_CHANNEL_VEC
-
- // might be set by previous domain
- if(mpGlob->getAniFrames() < settings->noOfFrames) mpGlob->setAniFrames( settings->noOfFrames );
- // set additionally to SimulationObject->mOutFilename
- mpGlob->setOutFilename( settings->outputPath );
-
- return 0;
-}
-
-void ntlWorld::initDefaults()
-{
- mStopRenderVisualization = false;
- mThreadRunning = false;
- mSimulationTime = 0.0;
- mFirstSim = 1;
- mSingleStepDebug = false;
- mFrameCnt = 0;
- mSimFrameCnt = 0;
- mpOpenGLRenderer = NULL;
-
- /* create scene storage */
- mpGlob = new ntlRenderGlobals();
- mpLightList = new vector<ntlLightObject*>;
- mpPropList = new vector<ntlMaterial*>;
- mpSims = new vector<SimulationObject*>;
-
- mpGlob->setLightList(mpLightList);
- mpGlob->setMaterials(mpPropList);
- mpGlob->setSims(mpSims);
-
- /* init default material */
- ntlMaterial *def = GET_GLOBAL_DEFAULT_MATERIAL;
- mpPropList->push_back( def );
-
- /* init the scene object */
- ntlScene *renderscene = new ntlScene( mpGlob, true );
- mpGlob->setRenderScene( renderscene );
- // sim scene shouldnt delete objs, may only contain subset
- ntlScene *simscene = new ntlScene( mpGlob, false );
- mpGlob->setSimScene( simscene );
-}
-
-void ntlWorld::finishWorldInit()
-{
- if(! isSimworldOk() ) return;
-
- // init the scene for the first time
- long sstartTime = getTime();
-
- // first init sim scene for geo setup
- mpGlob->getSimScene()->buildScene(0.0, true);
- if(! isSimworldOk() ) return;
- mpGlob->getRenderScene()->buildScene(0.0, true);
- if(! isSimworldOk() ) return;
- long sstopTime = getTime();
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Scene build time: "<< getTimeString(sstopTime-sstartTime) <<" ", 10);
-
- // TODO check simulations, run first steps
- mFirstSim = -1;
- if(mpSims->size() > 0) {
-
- // use values from first simulation as master time scale
- long startTime = getTime();
-
- // remember first active sim
- for(size_t i=0;i<mpSims->size();i++) {
- if(!(*mpSims)[i]->getVisible()) continue;
- if((*mpSims)[i]->getPanic()) continue;
-
- // check largest timestep
- if(mFirstSim>=0) {
- if( (*mpSims)[i]->getTimestep() > (*mpSims)[mFirstSim]->getTimestep() ) {
- mFirstSim = i;
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"First Sim changed: "<<i ,10);
- }
- }
- // check any valid sim
- if(mFirstSim<0) {
- mFirstSim = i;
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"First Sim: "<<i ,10);
- }
- }
-
- if(mFirstSim>=0) {
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime() ,10);
- while(mSimulationTime < (*mpSims)[mFirstSim]->getStartTime() ) {
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime()<<" simtime:"<<mSimulationTime ,10);
- advanceSims(-1);
- }
- long stopTime = getTime();
-
- debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Time for start-sims:"<< getTimeString(stopTime-startTime) , 1);
-#ifndef NOGUI
- guiResetSimulationTimeRange( mSimulationTime );
-#endif
- } else {
- if(!mpGlob->getSingleFrameMode()) debMsgStd("ntlWorld::ntlWorld",DM_WARNING,"No active simulations!", 1);
- }
- }
-
- if(! isSimworldOk() ) return;
- setElbeemState( SIMWORLD_INITED );
-}
-
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-ntlWorld::~ntlWorld()
-{
- delete mpGlob->getRenderScene();
- delete mpGlob->getSimScene();
-
- delete mpGlob;
-
-
- // these get assigned to mpGlob but not freed there
- delete mpLightList;
- delete mpPropList; // materials
- delete mpSims;
-
-#ifndef NOGUI
- if(mpOpenGLRenderer) delete mpOpenGLRenderer;
-#endif // NOGUI
- debMsgStd("ntlWorld",DM_NOTIFY, "ntlWorld done", 10);
-}
-
-/******************************************************************************/
-/*! set single frame rendering to filename */
-void ntlWorld::setSingleFrameOut(string singleframeFilename) {
- mpGlob->setSingleFrameMode(true);
- mpGlob->setSingleFrameFilename(singleframeFilename);
-}
-
-/******************************************************************************
- * render a whole animation (command line mode)
- *****************************************************************************/
-
-int ntlWorld::renderAnimation( void )
-{
- // only single pic currently
- //debMsgStd("ntlWorld::renderAnimation : Warning only simulating...",1);
- if(mpGlob->getAniFrames() < 0) {
- debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No frames to render... ",1);
- return 1;
- }
-
- if(mFirstSim<0) {
- debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No reference animation found...",1);
- return 1;
- }
-
- mThreadRunning = true; // not threaded, but still use the same flags
- if(getElbeemState() == SIMWORLD_INITED) {
- renderScene();
- } else if(getElbeemState() == SIMWORLD_STOP) {
- // dont render now, just continue
- setElbeemState( SIMWORLD_INITED );
- mFrameCnt--; // counted one too many from last abort...
- } else {
- debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"Not properly inited, stopping...",1);
- return 1;
- }
-
- if(mpSims->size() <= 0) {
- debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No simulations found, stopping...",1);
- return 1;
- }
-
- bool simok = true;
- for( ; ((mFrameCnt<mpGlob->getAniFrames()) && (!getStopRenderVisualization() ) && (simok)); mFrameCnt++) {
- if(!advanceSims(mFrameCnt)) {
- renderScene();
- } // else means sim panicked, so dont render...
- else { simok=false; }
- }
- mThreadRunning = false;
- return 0;
-}
-
-/******************************************************************************
- * render a whole animation (visualization mode)
- * this function is run in another thread, and communicates
- * with the parent thread via a mutex
- *****************************************************************************/
-int ntlWorld::renderVisualization( bool multiThreaded )
-{
-#ifndef NOGUI
- if(getElbeemState() != SIMWORLD_INITED) { return 0; }
-
- if(multiThreaded) mThreadRunning = true;
- // TODO, check global state?
- while(!getStopRenderVisualization()) {
-
- if(mpSims->size() <= 0) {
- debMsgStd("ntlWorld::renderVisualization",DM_NOTIFY,"No simulations found, stopping...",1);
- stopSimulationThread();
- break;
- }
-
- // determine stepsize
- if(!mSingleStepDebug) {
- long startTime = getTime();
- advanceSims(mFrameCnt);
- mFrameCnt++;
- long stopTime = getTime();
- debMsgStd("ntlWorld::renderVisualization",DM_MSG,"Time for t="<<mSimulationTime<<": "<< getTimeString(stopTime-startTime) <<" ", 10);
- } else {
- double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
- singleStepSims(targetTime);
-
- // check paniced sims (normally done by advanceSims
- bool allPanic = true;
- for(size_t i=0;i<mpSims->size();i++) {
- if(!(*mpSims)[i]->getPanic()) allPanic = false;
- }
- if(allPanic) {
- warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" );
- setStopRenderVisualization( true );
- }
- if(! isSimworldOk() ) {
- warnMsg("ntlWorld::advanceSims","World state error... stopping" );
- setStopRenderVisualization( true );
- }
- }
-
- // save frame
- if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
-
- // for non-threaded check events
- if(!multiThreaded) {
- Fl::check();
- gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
- }
-
- }
- mThreadRunning = false;
- stopSimulationRestoreGui();
-#else
- multiThreaded = false; // remove warning
-#endif
- return 0;
-}
-/*! render a single step for viz mode */
-int ntlWorld::singleStepVisualization( void )
-{
- mThreadRunning = true;
- double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
- singleStepSims(targetTime);
- mSimulationTime = (*mpSims)[0]->getCurrentTime();
-
-#ifndef NOGUI
- if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
- Fl::check();
- gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
- mThreadRunning = false;
- stopSimulationRestoreGui();
-#else
- mThreadRunning = false;
-#endif // NOGUI
- return 0;
-}
-
-// dont use LBM_EPSILON here, time is always double-precision!
-#define LBM_TIME_EPSILON 1e-10
-
-/******************************************************************************
- * advance simulations by time t
- *****************************************************************************/
-int ntlWorld::advanceSims(int framenum)
-{
- bool done = false;
- bool allPanic = true;
-
- // stop/quit (abort), dont display/render
- if(!isSimworldOk()) {
- return 1;
- }
-
- for(size_t i=0;i<mpSims->size();i++) { (*mpSims)[i]->setFrameNum(framenum); }
-
- // time stopped? nothing else to do...
- if( (*mpSims)[mFirstSim]->getFrameTime(framenum) <= 0.0 ){
- done=true; allPanic=false;
-
- /* DG: Need to check for user cancel here (fix for [#30298]) */
- (*mpSims)[mFirstSim]->checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0);
- }
-
- // Prevent bug [#29186] Object contribute to fluid sim animation start earlier than keyframe
- // Was: double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getFrameTime(framenum); - DG
- double totalTime = 0.0, targetTime = 0.0;
- for(size_t i = 0; i < mSimFrameCnt; i++)
- {
- /* We need an intermediate array "mSimFrameValue" because
- otherwise if we don't start with starttime = 0,
- the sim gets out of sync - DG */
- totalTime += (*mpSims)[mFirstSim]->getFrameTime(mSimFrameValue[i]);
- }
- targetTime = totalTime + (*mpSims)[mFirstSim]->getFrameTime(framenum);
-
- int gstate = 0;
- myTime_t advsstart = getTime();
-
- // step all the sims, and check for panic
- debMsgStd("ntlWorld::advanceSims",DM_MSG, " sims "<<mpSims->size()<<" t"<<targetTime<<" done:"<<done<<" panic:"<<allPanic<<" gstate:"<<gstate, 10); // debug // timedebug
- while(!done) {
- double nextTargetTime = (*mpSims)[mFirstSim]->getCurrentTime() + (*mpSims)[mFirstSim]->getTimestep();
- singleStepSims(nextTargetTime);
-
- // check target times
- done = true;
- allPanic = false;
-
- if((*mpSims)[mFirstSim]->getTimestep() <1e-9 ) {
- // safety check, avoid timesteps that are too small
- errMsg("ntlWorld::advanceSims","Invalid time step, causing panic! curr:"<<(*mpSims)[mFirstSim]->getCurrentTime()<<" next:"<<nextTargetTime<<", stept:"<< (*mpSims)[mFirstSim]->getTimestep() );
- allPanic = true;
- } else {
- for(size_t i=0;i<mpSims->size();i++) {
- if(!(*mpSims)[i]->getVisible()) continue;
- if((*mpSims)[i]->getPanic()) allPanic = true; // do any panic now!?
- debMsgStd("ntlWorld::advanceSims",DM_MSG, "Sim "<<i<<", currt:"<<(*mpSims)[i]->getCurrentTime()<<", nt:"<<nextTargetTime<<", panic:"<<(*mpSims)[i]->getPanic()<<", targett:"<<targetTime, 10); // debug // timedebug
- }
- }
- if( (targetTime - (*mpSims)[mFirstSim]->getCurrentTime()) > LBM_TIME_EPSILON) done=false;
- if(allPanic) done = true;
- }
-
- if(allPanic) {
- warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" );
- setStopRenderVisualization( true );
- return 1;
- }
-
- myTime_t advsend = getTime();
- debMsgStd("ntlWorld::advanceSims",DM_MSG,"Overall steps so far took:"<< getTimeString(advsend-advsstart)<<" for sim time "<<targetTime, 4);
-
- // finish step
- for(size_t i=0;i<mpSims->size();i++) {
- SimulationObject *sim = (*mpSims)[i];
- if(!sim->getVisible()) continue;
- if(sim->getPanic()) continue;
- sim->prepareVisualization();
- }
-
- mSimFrameValue.push_back(framenum);
- mSimFrameCnt++;
-
- return 0;
-}
-
-/* advance simulations by a single step */
-/* dont check target time, if *targetTime==NULL */
-void ntlWorld::singleStepSims(double targetTime) {
- const bool debugTime = false;
- //double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
- if(debugTime) errMsg("ntlWorld::singleStepSims","Target time: "<<targetTime);
-
- for(size_t i=0;i<mpSims->size();i++) {
- SimulationObject *sim = (*mpSims)[i];
- if(!sim->getVisible()) continue;
- if(sim->getPanic()) continue;
- bool done = false;
- while(!done) {
- // try to prevent round off errs
- if(debugTime) errMsg("ntlWorld::singleStepSims","Test sim "<<i<<" curt:"<< sim->getCurrentTime()<<" target:"<<targetTime<<" delta:"<<(targetTime - sim->getCurrentTime())<<" stept:"<<sim->getTimestep()<<" leps:"<<LBM_TIME_EPSILON ); // timedebug
- if( (targetTime - sim->getCurrentTime()) > LBM_TIME_EPSILON) {
- if(debugTime) errMsg("ntlWorld::singleStepSims","Stepping sim "<<i<<" t:"<< sim->getCurrentTime()); // timedebug
- sim->step();
- } else {
- done = true;
- }
- }
- }
-
- mSimulationTime = (*mpSims)[mFirstSim]->getCurrentTime();
-#ifndef NOGUI
- if(mpOpenGLRenderer) mpOpenGLRenderer->notifyOfNextStep(mSimulationTime);
-#endif // NOGUI
-}
-
-
-
-/******************************************************************************
- * Render the current scene
- * uses the global variables from the parser
- *****************************************************************************/
-int ntlWorld::renderScene( void )
-{
-#ifndef ELBEEM_PLUGIN
- char nrStr[5]; // nr conversion
- std::ostringstream outfn_conv(""); // converted ppm with other suffix
- ntlRenderGlobals *glob; // storage for global rendering parameters
- myTime_t timeStart,totalStart,timeEnd; // measure user running time
- myTime_t rendStart,rendEnd; // measure user rendering time
- glob = mpGlob;
-
- // deactivate for all with index!=0
- if((glob_mpactive)&&(glob_mpindex>0)) return(0);
-
- /* check if picture already exists... */
- if(!glob->getSingleFrameMode() ) {
- snprintf(nrStr, 5, "%04d", glob->getAniCount() );
-
- if(glob_mpactive) {
- outfn_conv << glob->getOutFilename() <<"_"<<glob_mpindex<<"_" << nrStr << ".png"; /// DEBUG!
- } else {
- // ORG
- outfn_conv << glob->getOutFilename() <<"_" << nrStr << ".png";
- }
-
- //if((mpGlob->getDisplayMode() == DM_RAY)&&(mpGlob->getFrameSkip())) {
- if(mpGlob->getFrameSkip()) {
- struct stat statBuf;
- if(stat(outfn_conv.str().c_str(),&statBuf) == 0) {
- errorOut("ntlWorld::renderscene Warning: file "<<outfn_conv.str()<<" already exists - skipping frame...");
- glob->setAniCount( glob->getAniCount() +1 );
- return(2);
- }
- } // RAY mode
- } else {
- // single frame rendering, overwrite if necessary...
- outfn_conv << glob->getSingleFrameFilename();
- }
-
- /* start program */
- timeStart = getTime();
-
- /* build scene geometry, calls buildScene(t,false) */
- glob->getRenderScene()->prepareScene(mSimulationTime);
-
- /* start program */
- totalStart = getTime();
-
-
- /* view parameters are currently not animated */
- /* calculate rays through projection plane */
- ntlVec3Gfx direction = glob->getLookat() - glob->getEye();
- /* calculate width of screen using perpendicular triangle diven by
- * viewing direction and screen plane */
- gfxReal screenWidth = norm(direction)*tan( (glob->getFovy()*0.5/180.0)*M_PI );
-
- /* calculate vector orthogonal to up and viewing direction */
- ntlVec3Gfx upVec = glob->getUpVec();
- ntlVec3Gfx rightVec( cross(upVec,direction) );
- normalize(rightVec);
-
- /* calculate screen plane up vector, perpendicular to viewdir and right vec */
- upVec = ntlVec3Gfx( cross(rightVec,direction) );
- normalize(upVec);
-
- /* check if vectors are valid */
- if( (equal(upVec,ntlVec3Gfx(0.0))) || (equal(rightVec,ntlVec3Gfx(0.0))) ) {
- errMsg("ntlWorld::renderScene","Invalid viewpoint vectors! up="<<upVec<<" right="<<rightVec);
- return(1);
- }
-
- /* length from center to border of screen plane */
- rightVec *= (screenWidth*glob->getAspect() * -1.0);
- upVec *= (screenWidth * -1.0);
-
- /* screen traversal variables */
- ntlVec3Gfx screenPos; /* current position on virtual screen */
- int Xres = glob->getResX(); /* X resolution */
- int Yres = glob->getResY(); /* Y resolution */
- ntlVec3Gfx rightStep = (rightVec/(Xres/2.0)); /* one step right for a pixel */
- ntlVec3Gfx upStep = (upVec/(Yres/2.0)); /* one step up for a pixel */
-
-
- /* anti alias init */
- char showAAPic = 0;
- int aaDepth = glob->getAADepth();
- int aaLength;
- if(aaDepth>=0) aaLength = (2<<aaDepth);
- else aaLength = 0;
- float aaSensRed = 0.1;
- float aaSensGreen = 0.1;
- float aaSensBlue = 0.1;
- int aaArrayX = aaLength*Xres+1;
- int aaArrayY = ( aaLength+1 );
- ntlColor *aaCol = new ntlColor[ aaArrayX*aaArrayY ];
- char *aaUse = new char[ aaArrayX*aaArrayY ];
-
- /* picture storage */
- int picX = Xres;
- int picY = Yres;
- if(showAAPic) {
- picX = Xres *aaLength+1;
- picY = Yres *aaLength+1;
- }
- ntlColor *finalPic = new ntlColor[picX * picY];
-
-
- /* reset picture vars */
- for(int j=0;j<aaArrayY;j++) {
- for(int i=0;i<aaArrayX;i++) {
- aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
- aaUse[j*aaArrayX+i] = 0;
- }
- }
- for(int j=0;j<picY;j++) {
- for(int i=0;i<picX;i++) {
- finalPic[j*picX+i] = ntlColor(0.0, 0.0, 0.0);
- }
- }
-
- /* loop over all y lines in screen, from bottom to top because
- * ppm format wants 0,0 top left */
- rendStart = getTime();
- glob->setCounterShades(0);
- glob->setCounterSceneInter(0);
- for (int scanline=Yres ; scanline > 0 ; --scanline) {
-
- debugOutInter( "ntlWorld::renderScene: Line "<<scanline<<
- " ("<< ((Yres-scanline)*100/Yres) <<"%) ", 2, 2000 );
- screenPos = glob->getLookat() + upVec*((2.0*scanline-Yres)/Yres)
- - rightVec;
-
- /* loop over all pixels in line */
- for (int sx=0 ; sx < Xres ; ++sx) {
-
- if((sx==glob->getDebugPixelX())&&(scanline==(Yres-glob->getDebugPixelY()) )) {
- // DEBUG!!!
- glob->setDebugOut(10);
- } else glob->setDebugOut(0);
-
- /* compute ray from eye through current pixel into scene... */
- ntlColor col;
- if(aaDepth<0) {
- ntlVec3Gfx dir(screenPos - glob->getEye());
- ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
-
- /* ...and trace it */
- col = the_ray.shade();
- } else {
- /* anti alias */
- int ai,aj; /* position in grid */
- int aOrg = sx*aaLength; /* grid offset x */
- int currStep = aaLength; /* step size */
- char colDiff = 1; /* do colors still differ too much? */
- ntlColor minCol,maxCol; /* minimum and maximum Color Values */
- minCol = ntlColor(1.0,1.0,1.0);
- maxCol = ntlColor(0.0,0.0,0.0);
-
- while((colDiff) && (currStep>0)) {
- colDiff = 0;
-
- for(aj = 0;aj<=aaLength;aj+= currStep) {
- for(ai = 0;ai<=aaLength;ai+= currStep) {
-
- /* shade pixel if not done */
- if(aaUse[aj*aaArrayX +ai +aOrg] == 0) {
- aaUse[aj*aaArrayX +ai +aOrg] = 1;
- ntlVec3Gfx aaPos( screenPos +
- (rightStep * (ai- aaLength/2)/(gfxReal)aaLength ) +
- (upStep * (aj- aaLength/2)/(gfxReal)aaLength ) );
-
- ntlVec3Gfx dir(aaPos - glob->getEye());
- ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
-
- /* ...and trace it */
- ntlColor newCol= the_ray.shade();
- aaCol[aj*aaArrayX +ai +aOrg]= newCol;
- } /* not used? */
-
- }
- }
-
- /* check color differences */
- for(aj = 0;aj<aaLength;aj+= currStep) {
- for(ai = 0;ai<aaLength;ai+= currStep) {
-
- char thisColDiff = 0;
- if(
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] -
- aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] -
- aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] -
- aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
- thisColDiff = 1;
- } else
- if(
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] -
- aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][0])> aaSensRed ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] -
- aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][1])> aaSensGreen ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] -
- aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][2])> aaSensBlue ) ) {
- thisColDiff = 1;
- } else
- if(
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] -
- aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] -
- aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
- (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] -
- aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
- thisColDiff = 1;
- }
-
- //colDiff =1;
- if(thisColDiff) {
- /* set diff flag */
- colDiff = thisColDiff;
- for(int bj=aj;bj<=aj+currStep;bj++) {
- for(int bi=ai;bi<=ai+currStep;bi++) {
- if(aaUse[bj*aaArrayX +bi +aOrg]==2) {
- //if(showAAPic)
- aaUse[bj*aaArrayX +bi +aOrg] = 0;
- }
- }
- }
- } else {
- /* set all values */
- ntlColor avgCol = (
- aaCol[(aj+0 )*aaArrayX +(ai+0 ) +aOrg] +
- aaCol[(aj+0 )*aaArrayX +(ai+currStep) +aOrg] +
- aaCol[(aj+currStep)*aaArrayX +(ai+0 ) +aOrg] +
- aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg] ) *0.25;
- for(int bj=aj;bj<=aj+currStep;bj++) {
- for(int bi=ai;bi<=ai+currStep;bi++) {
- if(aaUse[bj*aaArrayX +bi +aOrg]==0) {
- aaCol[bj*aaArrayX +bi +aOrg] = avgCol;
- aaUse[bj*aaArrayX +bi +aOrg] = 2;
- }
- }
- }
- } /* smaller values set */
-
- }
- }
-
- /* half step size */
- currStep /= 2;
-
- } /* repeat until diff not too big */
-
- /* get average color */
- gfxReal colNum = 0.0;
- col = ntlColor(0.0, 0.0, 0.0);
- for(aj = 0;aj<=aaLength;aj++) {
- for(ai = 0;ai<=aaLength;ai++) {
- col += aaCol[aj*aaArrayX +ai +aOrg];
- colNum += 1.0;
- }
- }
- col /= colNum;
-
- }
-
- /* mark pixels with debugging */
- if( glob->getDebugOut() > 0) col = ntlColor(0,1,0);
-
- /* store pixel */
- if(!showAAPic) {
- finalPic[(scanline-1)*picX+sx] = col;
- }
- screenPos += rightStep;
-
- } /* foreach x */
-
- /* init aa array */
- if(showAAPic) {
- for(int j=0;j<=aaArrayY-1;j++) {
- for(int i=0;i<=aaArrayX-1;i++) {
- if(aaUse[j*aaArrayX +i]==1) finalPic[((scanline-1)*aaLength +j)*picX+i][0] = 1.0;
- }
- }
- }
-
- for(int i=0;i<aaArrayX;i++) {
- aaCol[(aaArrayY-1)*aaArrayX+i] = aaCol[0*aaArrayX+i];
- aaUse[(aaArrayY-1)*aaArrayX+i] = aaUse[0*aaArrayX+i];
- }
- for(int j=0;j<aaArrayY-1;j++) {
- for(int i=0;i<aaArrayX;i++) {
- aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
- aaUse[j*aaArrayX+i] = 0;
- }
- }
-
- } /* foreach y */
- rendEnd = getTime();
-
-
- /* write png file */
- {
- int w = picX;
- int h = picY;
-
- unsigned rowbytes = w*4;
- unsigned char *screenbuf, **rows;
- screenbuf = (unsigned char*)malloc( h*rowbytes );
- rows = (unsigned char**)malloc( h*sizeof(unsigned char*) );
- unsigned char *filler = screenbuf;
-
- // cutoff color values 0..1
- for(int j=0;j<h;j++) {
- for(int i=0;i<w;i++) {
- ntlColor col = finalPic[j*w+i];
- for (unsigned int cc=0; cc<3; cc++) {
- if(col[cc] <= 0.0) col[cc] = 0.0;
- if(col[cc] >= 1.0) col[cc] = 1.0;
- }
- *filler = (unsigned char)( col[0]*255.0 );
- filler++;
- *filler = (unsigned char)( col[1]*255.0 );
- filler++;
- *filler = (unsigned char)( col[2]*255.0 );
- filler++;
- *filler = (unsigned char)( 255.0 );
- filler++; // alpha channel
- }
- }
-
- for(int i = 0; i < h; i++) rows[i] = &screenbuf[ (h - i - 1)*rowbytes ];
- writePng(outfn_conv.str().c_str(), rows, w, h);
- }
-
-
- // next frame
- glob->setAniCount( glob->getAniCount() +1 );
-
- // done
- timeEnd = getTime();
-
- char resout[1024];
- snprintf(resout,1024, "NTL Done %s, frame %d/%d (took %s scene, %s raytracing, %s total, %d shades, %d i.s.'s)!\n",
- outfn_conv.str().c_str(), (glob->getAniCount()), (glob->getAniFrames()+1),
- getTimeString(totalStart-timeStart).c_str(), getTimeString(rendEnd-rendStart).c_str(), getTimeString(timeEnd-timeStart).c_str(),
- glob->getCounterShades(),
- glob->getCounterSceneInter() );
- debMsgStd("ntlWorld::renderScene",DM_MSG, resout, 1 );
-
- /* clean stuff up */
- delete [] aaCol;
- delete [] aaUse;
- delete [] finalPic;
- glob->getRenderScene()->cleanupScene();
-
- if(mpGlob->getSingleFrameMode() ) {
- debMsgStd("ntlWorld::renderScene",DM_NOTIFY, "Single frame mode done...", 1 );
- return 1;
- }
-#endif // ELBEEM_PLUGIN
- return 0;
-}
-
-
-/******************************************************************************
- * renderglobals
- *****************************************************************************/
-
-
-/*****************************************************************************/
-/* Constructor with standard value init */
-ntlRenderGlobals::ntlRenderGlobals() :
- mpRenderScene(NULL), mpSimScene(NULL),
- mpLightList( NULL ), mpMaterials( NULL ), mpSims( NULL ),
- mResX(320), mResY(200), mAADepth(-1), mMaxColVal(255),
- mRayMaxDepth( 5 ),
- mvEye(0.0,0.0,5.0), mvLookat(0.0,0.0,0.0), mvUpvec(0.0,1.0,0.0),
- mAspect(320.0/200.0),
- mFovy(45), mcBackgr(0.0,0.0,0.0), mcAmbientLight(0.0,0.0,0.0),
- mDebugOut( 0 ),
- mAniStart(0), mAniFrames( -1 ), mAniCount( 0 ),
- mFrameSkip( 0 ),
- mCounterRays( 0 ), mCounterShades( 0 ), mCounterSceneInter( 0 ),
- mOutFilename( "pic" ),
- mTreeMaxDepth( 30 ), mTreeMaxTriangles( 30 ),
- mpOpenGlAttr(NULL),
- mpBlenderAttr(NULL),
- mTestSphereEnabled( false ),
- mDebugPixelX( -1 ), mDebugPixelY( -1 ), mTestMode(false),
- mSingleFrameMode(false), mSingleFrameFilename("")
- //,mpRndDirections( NULL ), mpRndRoulette( NULL )
-{
- // create internal attribute list for opengl renderer
- mpOpenGlAttr = new AttributeList("__ntlOpenGLRenderer");
- mpBlenderAttr = new AttributeList("__ntlBlenderAttr");
-};
-
-
-/*****************************************************************************/
-/* Destructor */
-ntlRenderGlobals::~ntlRenderGlobals() {
- if(mpOpenGlAttr) delete mpOpenGlAttr;
- if(mpBlenderAttr) delete mpBlenderAttr;
-
-
-}
-
-
-/*****************************************************************************/
-//! get the next random photon direction
-//ntlVec3Gfx ntlRenderGlobals::getRandomDirection( void ) {
- //return ntlVec3Gfx(
- //(mpRndDirections->getGfxReal()-0.5),
- //(mpRndDirections->getGfxReal()-0.5),
- //(mpRndDirections->getGfxReal()-0.5) );
-//}
-
-
diff --git a/intern/elbeem/intern/ntl_world.h b/intern/elbeem/intern/ntl_world.h
deleted file mode 100644
index 7851b783225..00000000000
--- a/intern/elbeem/intern/ntl_world.h
+++ /dev/null
@@ -1,411 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Main renderer class
- *
- *****************************************************************************/
-#ifndef NTL_RAYTRACER_HH
-#define NTL_RAYTRACER_HH
-
-#include "ntl_vector3dim.h"
-#include "ntl_ray.h"
-#include "ntl_lighting.h"
-#include "ntl_geometryobject.h"
-#include "simulation_object.h"
-#include "elbeem.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ntlOpenGLRenderer;
-class ntlScene;
-class SimulationObject;
-class ntlRandomStream;
-
-class ntlWorld
-{
- public:
- /*! Constructor for API init */
- ntlWorld();
- /*! Constructor */
- ntlWorld(string filename, bool commandlineMode);
- /*! Destructor */
- virtual ~ntlWorld( void );
- /*! default init for all contructors */
- void initDefaults();
- /*! common world contruction stuff once the scene is set up */
- void finishWorldInit();
- /*! add domain for API init */
- int addDomain(elbeemSimulationSettings *simSettings);
-
- /*! render a whole animation (command line mode) */
- int renderAnimation( void );
- /*! render a whole animation (visualization mode) */
- int renderVisualization( bool );
- /*! render a single step for viz mode */
- int singleStepVisualization( void );
- /*! advance simulations by time frame time */
- int advanceSims(int framenum);
- /*! advance simulations by a single step */
- void singleStepSims(double targetTime);
-
- /*! set stop rend viz flag */
- void setStopRenderVisualization(bool set) { mStopRenderVisualization = set; }
- /*! should the rendering viz thread be stopped? */
- bool getStopRenderVisualization() { return mStopRenderVisualization; }
-
- /*! render scene (a single pictures) */
- virtual int renderScene( void );
-
- /*! set single frame rendering to filename */
- void setSingleFrameOut( string singleframeFilename );
-
- /* access functions */
-
- /*! set&get render globals */
- inline void setRenderGlobals( ntlRenderGlobals *set) { mpGlob = set; }
- inline ntlRenderGlobals *getRenderGlobals( void ) { return mpGlob; }
-
- /*! set&get render globals */
- inline void setSimulationTime( double set) { mSimulationTime = set; }
- inline double getSimulationTime( void ) { return mSimulationTime; }
-
- /*! set&get single step debug mode */
- inline void setSingleStepDebug( bool set) { mSingleStepDebug = set; }
- inline bool getSingleStepDebug( void ) { return mSingleStepDebug; }
-
- /*! &get simulation object vector (debugging) */
- inline vector<SimulationObject*> *getSimulations( void ) { return mpSims; }
-
- /*! get opengl renderer */
- inline ntlOpenGLRenderer *getOpenGLRenderer() { return mpOpenGLRenderer; }
-
- private:
-
- protected:
-
- /*! global render settings needed almost everywhere */
- ntlRenderGlobals *mpGlob;
-
- /*! a list of lights in the scene (geometry is store in ntl_scene) */
- vector<ntlLightObject*> *mpLightList;
- /*! surface materials */
- vector<ntlMaterial*> *mpPropList;
- /*! sims list */
- vector<SimulationObject*> *mpSims;
-
- /*! opengl display */
- ntlOpenGLRenderer *mpOpenGLRenderer;
-
- /*! stop rend viz? */
- bool mStopRenderVisualization;
-
- /*! rend viz thread currently running? */
- bool mThreadRunning;
-
- /*! remember the current simulation time */
- double mSimulationTime;
-
- /*! first simulation that is valid */
- int mFirstSim;
-
- /*! single step mode for debugging */
- bool mSingleStepDebug;
-
- /*! count no. of frame for viz render */
- int mFrameCnt;
-
- /*! count no. of frame for correct sim time */
- int mSimFrameCnt;
- vector<int> mSimFrameValue;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlWorld")
-#endif
-};
-
-
-//! Class that handles global rendering parameters
-class ntlRenderGlobals
-{
- public:
- //! Standard constructor
- ntlRenderGlobals();
- //! Destructor
- ~ntlRenderGlobals();
-
- //! Returns the renderscene manager (scene changes for each frame)
- inline ntlScene *getRenderScene(void) { return mpRenderScene; }
- //! Set the renderscene manager
- inline void setRenderScene(ntlScene *set) { mpRenderScene = set;}
-
- //! Returns the simulation scene manager (static scene with sim objects)
- inline ntlScene *getSimScene(void) { return mpSimScene; }
- //! Set the simulation scene manager
- inline void setSimScene(ntlScene *set) { mpSimScene = set;}
-
- //! Returns the light object list
- inline vector<ntlLightObject*> *getLightList(void) { return mpLightList; }
- //! Set the light list
- inline void setLightList(vector<ntlLightObject*> *set) { mpLightList = set;}
-
- //! Returns the property object list
- inline vector<ntlMaterial*> *getMaterials(void) { return mpMaterials; }
- //! Set the property list
- inline void setMaterials(vector<ntlMaterial*> *set) { mpMaterials = set;}
-
- //! Returns the list of simulations
- inline vector<SimulationObject*> *getSims(void) { return mpSims; }
- //! Set the pointer to the list of simulations
- inline void setSims(vector<SimulationObject*> *set) { mpSims = set;}
-
- //! Set the x resolution
- inline void setResX(unsigned int set) { mResX = set; }
- //! Set the y resolution
- inline void setResY(unsigned int set) { mResY = set; }
- //! Set the anti-aliasing depth
- inline void setAADepth(int set) { mAADepth = set; }
- //! Set the max color value
- inline void setMaxColVal(unsigned int set) { mMaxColVal = set; }
- //! Set the maximum ray recursion
- inline void setRayMaxDepth(unsigned int set) { mRayMaxDepth = set; }
- //! Set the eye point
- inline void setEye(ntlVec3Gfx set) { mvEye = set; }
- //! Set the look at vector
- inline void setLookat(ntlVec3Gfx set) { mvLookat = set; }
- //! Set the up vector
- inline void setUpVec(ntlVec3Gfx set) { mvUpvec = set; }
- //! Set the image aspect
- inline void setAspect(float set) { mAspect = set; }
- //! Set the field of view
- inline void setFovy(float set) { mFovy = set; }
- //! Set the background color
- inline void setBackgroundCol(ntlColor set) { mcBackgr = set; }
- //! Set the ambient lighting color
- inline void setAmbientLight(ntlColor set) { mcAmbientLight = set; }
- //! Set the debug output var
- inline void setDebugOut(int set) { mDebugOut = set; }
-
- //! Set the animation start time
- inline void setAniStart(int set) { mAniStart = set; }
- //! Set the animation number of frames
- inline void setAniFrames(int set) { mAniFrames = set; }
- //! Set the animation
- inline void setAniCount(int set) { mAniCount = set; }
- //! Set the ray counter
- inline void setCounterRays(int set) { mCounterRays = set; }
- //! Set the ray shades counter
- inline void setCounterShades(int set) { mCounterShades = set; }
- //! Set the scenen intersection counter
- inline void setCounterSceneInter(int set) { mCounterSceneInter = set; }
- //! Set if existing frames should be skipped
- inline void setFrameSkip(int set) { mFrameSkip = set; }
-
- //! Set the outfilename
- inline void setOutFilename(string set) { mOutFilename = set; }
-
- //! get Maximum depth for BSP tree
- inline void setTreeMaxDepth( int set ) { mTreeMaxDepth = set; }
- //! get Maxmimum nr of triangles per BSP tree node
- inline void setTreeMaxTriangles( int set ) { mTreeMaxTriangles = set; }
-
- //! set the enable flag of the test sphere
- inline void setTestSphereEnabled( bool set ) { mTestSphereEnabled = set; }
- //! set the center of the test sphere
- inline void setTestSphereCenter( ntlVec3Gfx set ) { mTestSphereCenter = set; }
- //! set the radius of the test sphere
- inline void setTestSphereRadius( gfxReal set ) { mTestSphereRadius = set; }
- //! set the material name of the test sphere
- inline void setTestSphereMaterialName( char* set ) { mTestSphereMaterialName = set; }
- //! set debugging pixel coordinates
- inline void setDebugPixel( int setx, int sety ) { mDebugPixelX = setx; mDebugPixelY = sety; }
- //! set test mode flag
- inline void setTestMode( bool set ) { mTestMode = set; }
- //! set single frame mode flag
- inline void setSingleFrameMode(bool set) {mSingleFrameMode = set; };
- //! set single frame mode filename
- inline void setSingleFrameFilename(string set) {mSingleFrameFilename = set; };
-
-
- //! Return the x resolution
- inline unsigned int getResX(void) { return mResX; }
- //! Return the y resolution
- inline unsigned int getResY(void) { return mResY; }
- //! Return the anti-aliasing depth
- inline int getAADepth(void) { return mAADepth; }
- //! Return the max color value for ppm
- inline unsigned int getMaxColVal(void) { return mMaxColVal; }
- //! Return the maximum ray recursion
- inline unsigned int getRayMaxDepth(void) { return mRayMaxDepth; }
- //! Return the eye point
- inline ntlVec3Gfx getEye(void) { return mvEye; }
- //! Return the look at vector
- inline ntlVec3Gfx getLookat(void) { return mvLookat; }
- //! Return the up vector
- inline ntlVec3Gfx getUpVec(void) { return mvUpvec; }
- //! Return the image aspect
- inline float getAspect(void) { return mAspect; }
- //! Return the field of view
- inline float getFovy(void) { return mFovy; }
- //! Return the background color
- inline ntlColor getBackgroundCol(void) { return mcBackgr; }
- //! Return the ambient color
- inline ntlColor getAmbientLight(void) { return mcAmbientLight; }
- //! Return the debug mode setting
- inline int getDebugOut(void) { return mDebugOut; }
-
- //! Return the animation start time
- inline int getAniStart(void) { return mAniStart; }
- //! Return the animation frame number
- inline int getAniFrames(void) { return mAniFrames; }
- //! Return the animation counter
- inline int getAniCount(void) { return mAniCount; }
- //! Return the ray counter
- inline int getCounterRays(void) { return mCounterRays; }
- //! Return the ray shades counter
- inline int getCounterShades(void) { return mCounterShades; }
- //! Return the scene intersection counter
- inline int getCounterSceneInter(void) { return mCounterSceneInter; }
- //! Check if existing frames should be skipped
- inline int getFrameSkip( void ) { return mFrameSkip; }
-
-
- //! Return the outfilename
- inline string getOutFilename(void) { return mOutFilename; }
-
- //! get Maximum depth for BSP tree
- inline int getTreeMaxDepth( void ) { return mTreeMaxDepth; }
- //! get Maxmimum nr of triangles per BSP tree node
- inline int getTreeMaxTriangles( void ) { return mTreeMaxTriangles; }
-
- //! get open gl attribute list
- inline AttributeList* getOpenGlAttributes( void ) { return mpOpenGlAttr; }
- //! get blender output attribute list
- inline AttributeList* getBlenderAttributes( void ) { return mpBlenderAttr; }
-
- //! is the test sphere enabled?
- inline bool getTestSphereEnabled( void ) { return mTestSphereEnabled; }
- //! get the center of the test sphere
- inline ntlVec3Gfx getTestSphereCenter( void ) { return mTestSphereCenter; }
- //! get the radius of the test sphere
- inline gfxReal getTestSphereRadius( void) { return mTestSphereRadius; }
- //! get the materialname of the test sphere
- inline char *getTestSphereMaterialName( void) { return mTestSphereMaterialName; }
- //! get the debug pixel coordinate
- inline int getDebugPixelX( void ) { return mDebugPixelX; }
- //! get the debug pixel coordinate
- inline int getDebugPixelY( void ) { return mDebugPixelY; }
- //! get test mode flag
- inline bool getTestMode( void ) { return mTestMode; }
- //! set single frame mode flag
- inline bool getSingleFrameMode() { return mSingleFrameMode; };
- //! set single frame mode filename
- inline string getSingleFrameFilename() { return mSingleFrameFilename; };
-
-
-private:
-
- /*! Scene storage (dynamic rendering scene) */
- ntlScene *mpRenderScene;
- /*! Scene storage (static sim scene, inited only once) */
- ntlScene *mpSimScene;
-
- //! List of light objects
- vector<ntlLightObject*> *mpLightList;
- //! List of surface properties
- vector<ntlMaterial*> *mpMaterials;
- /*! storage for simulations */
- vector<SimulationObject*> *mpSims;
-
- //! resolution of the picture
- unsigned int mResX, mResY;
- //! Anti-Aliasing depth
- int mAADepth;
- //! max color value for ppm
- unsigned int mMaxColVal;
- /* Maximal ray recursion depth */
- int mRayMaxDepth;
- //! The eye point
- ntlVec3Gfx mvEye;
- //! The look at point
- ntlVec3Gfx mvLookat;
- //! The up vector
- ntlVec3Gfx mvUpvec;
- //! The image aspect = Xres/Yres
- float mAspect;
- //! The horizontal field of view
- float mFovy;
- //! The background color
- ntlColor mcBackgr;
- //! The ambient color
- ntlColor mcAmbientLight;
- //! how much debug output is needed? off by default
- char mDebugOut;
-
-
- //! animation properties, start time
- int mAniStart;
- //! animation properties, number of frames to render
- int mAniFrames;
- //! animation status, current frame number
- int mAniCount;
- /*! Should existing picture frames be skipped? */
- int mFrameSkip;
-
-
- //! count the total number of rays created (also used for ray ID's)
- int mCounterRays;
- //! count the total number of rays shaded
- int mCounterShades;
- //! count the total number of scene intersections
- int mCounterSceneInter;
-
- /*! filename of output pictures (without suffix or numbers) */
- string mOutFilename;
-
- //! get Maximum depth for BSP tree
- int mTreeMaxDepth;
- //! get Maxmimum nr of triangles per BSP tree node
- int mTreeMaxTriangles;
-
- //! attribute list for opengl renderer
- AttributeList *mpOpenGlAttr;
- //! attribute list for blender output
- AttributeList *mpBlenderAttr;
-
-
- //! Enable test sphere?
- bool mTestSphereEnabled;
- //! Center of the test sphere
- ntlVec3Gfx mTestSphereCenter;
- //! Radius of the test sphere
- gfxReal mTestSphereRadius;
- //! Materialname of the test sphere
- char *mTestSphereMaterialName;
- //! coordinates of the debugging pixel
- int mDebugPixelX, mDebugPixelY;
-
- //! test mode for quick rendering activated?, inited in ntl_scene::buildScene
- bool mTestMode;
-
- //! single frame flag
- bool mSingleFrameMode;
- //! filename for single frame mode
- string mSingleFrameFilename;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ntlRenderGlobals")
-#endif
-};
-
-
-
-#endif
diff --git a/intern/elbeem/intern/paraloopend.h b/intern/elbeem/intern/paraloopend.h
deleted file mode 100644
index 6f321cd68b1..00000000000
--- a/intern/elbeem/intern/paraloopend.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-
-// same as grid loop_end + barrier
-
- } // i
- int i=0; //dummy
- ADVANCE_POINTERS(2*gridLoopBound);
- } // j
-
-# if COMPRESSGRIDS==1
-# if PARALLEL==1
- //frintf(stderr," (id=%d k=%d) ",id,k);
-#pragma omp barrier
-# endif // PARALLEL==1
-# else // COMPRESSGRIDS==1
- int i=0; //dummy
- ADVANCE_POINTERS(mLevel[lev].lSizex*2);
-# endif // COMPRESSGRIDS==1
-
-} // all cell loop k,j,i
-
-#pragma omp critical
-{
- if(doReduce) {
- // synchronize global vars
- for(size_t j=0; j<calcListFull.size() ; j++) mListFull.push_back( calcListFull[j] );
- for(size_t j=0; j<calcListEmpty.size(); j++) mListEmpty.push_back( calcListEmpty[j] );
- for(size_t j=0; j<calcListParts.size(); j++) mpParticles->addFullParticle( calcListParts[j] );
- if(calcMaxVlen>mMaxVlen) {
- mMxvx = calcMxvx;
- mMxvy = calcMxvy;
- mMxvz = calcMxvz;
- mMaxVlen = calcMaxVlen;
- }
- if(0) {debMsgStd("OMP_CRIT",DM_MSG, "reduce id"<<id<<" curr: "<<mMaxVlen<<"|"<<mMxvx<<","<<mMxvy<<","<<mMxvz<<
- " calc[ "<<calcMaxVlen<<"|"<<calcMxvx<<","<<calcMxvy<<","<<calcMxvz<<"] " ,4 ); }
- }
-} // critical
-
-
-} /* main_region */
- //?lobOutstrForce = true;
-
diff --git a/intern/elbeem/intern/parametrizer.cpp b/intern/elbeem/intern/parametrizer.cpp
deleted file mode 100644
index 889b8b85c4d..00000000000
--- a/intern/elbeem/intern/parametrizer.cpp
+++ /dev/null
@@ -1,597 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Parameter calculator for the LBM Solver class
- *
- *****************************************************************************/
-
-#include <sstream>
-#include "parametrizer.h"
-
-// debug output flag, has to be off for win32 for some reason...
-#define DEBUG_PARAMCHANNELS 0
-
-/*! param seen debug string array */
-const char *ParamStrings[] = {
- "RelaxTime",
- "Reynolds",
- "Viscosity",
- "SoundSpeed",
- "DomainSize",
- "GravityForce",
- "TimeLength",
- "Timestep",
- "Size",
- "TimeFactor",
- "AniFrames",
- "AniFrameTime",
- "AniStart",
- "SurfaceTension",
- "Density",
- "CellSize",
- "GStar",
- "MaxSpeed",
- "SimMaxSpeed",
- "FluidVolHeight",
- "NormalizedGStar",
- "PSERR", "PSERR", "PSERR", "PSERR"
-};
-
-
-
-/******************************************************************************
- * Default constructor
- *****************************************************************************/
-Parametrizer::Parametrizer( void ) :
- mcViscosity( 8.94e-7 ),
- mSoundSpeed( 1500 ),
- mDomainSize( 0.1 ), mCellSize( 0.01 ),
- mcGravity( ParamVec(0.0) ),
- mTimestep(0.0001), mDesiredTimestep(-1.0),
- mMaxTimestep(-1.0),
- mMinTimestep(-1.0),
- mSizex(50), mSizey(50), mSizez(50),
- mTimeFactor( 1.0 ),
- mcAniFrameTime(0.0001),
- mTimeStepScale(1.0),
- mAniStart(0.0),
- //mExtent(1.0, 1.0, 1.0), //mSurfaceTension( 0.0 ),
- mDensity(1000.0), mGStar(0.0001), mFluidVolumeHeight(0.0),
- mSimulationMaxSpeed(0.0),
- mTadapMaxOmega(2.0), mTadapMaxSpeed(0.1), mTadapLevels(1),
- mFrameNum(0),
- mSeenValues( 0 ), mCalculatedValues( 0 )
-{
-}
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-Parametrizer::~Parametrizer()
-{
- /* not much to do... */
-}
-
-/******************************************************************************
- * Init from attr list
- *****************************************************************************/
-void Parametrizer::parseAttrList()
-{
- if(!mpAttrs) {
- errFatal("Parametrizer::parseAttrList", "mpAttrs pointer not initialized!", SIMWORLD_INITERROR);
- return;
- }
-
- // unused
- string mSetupType = "";
- mSetupType = mpAttrs->readString("p_setup",mSetupType, "Parametrizer","mSetupType", false);
-
- // real params
- if(getAttributeList()->exists("p_viscosity")) {
- mcViscosity = mpAttrs->readChannelFloat("p_viscosity"); seenThis( PARAM_VISCOSITY ); }
-
- mSoundSpeed = mpAttrs->readFloat("p_soundspeed",mSoundSpeed, "Parametrizer","mSoundSpeed", false);
- if(getAttributeList()->exists("p_soundspeed")) seenThis( PARAM_SOUNDSPEED );
-
- mDomainSize = mpAttrs->readFloat("p_domainsize",mDomainSize, "Parametrizer","mDomainSize", false);
- if(getAttributeList()->exists("p_domainsize")) seenThis( PARAM_DOMAINSIZE );
- if(mDomainSize<=0.0) {
- errMsg("Parametrizer::parseAttrList","Invalid real world domain size:"<<mDomainSize<<", resetting to 0.1");
- mDomainSize = 0.1;
- }
-
- if(getAttributeList()->exists("p_gravity")) { // || (!mcGravity.isInited()) ) {
- mcGravity = mpAttrs->readChannelVec3d("p_gravity"); seenThis( PARAM_GRAVITY );
- }
-
- mTimestep = mpAttrs->readFloat("p_steptime",mTimestep, "Parametrizer","mTimestep", false);
- if(getAttributeList()->exists("p_steptime")) seenThis( PARAM_STEPTIME );
-
- mTimeFactor = mpAttrs->readFloat("p_timefactor",mTimeFactor, "Parametrizer","mTimeFactor", false);
- if(getAttributeList()->exists("p_timefactor")) seenThis( PARAM_TIMEFACTOR );
-
- if(getAttributeList()->exists("p_aniframetime")) { //|| (!mcAniFrameTime.isInited()) ) {
- mcAniFrameTime = mpAttrs->readChannelFloat("p_aniframetime");seenThis( PARAM_ANIFRAMETIME );
- }
- mTimeStepScale = mpAttrs->readFloat("p_timestepscale",mTimeStepScale, "Parametrizer","mTimeStepScale", false);
-
- mAniStart = mpAttrs->readFloat("p_anistart",mAniStart, "Parametrizer","mAniStart", false);
- if(getAttributeList()->exists("p_anistart")) seenThis( PARAM_ANISTART );
- if(mAniStart<0.0) {
- errMsg("Parametrizer::parseAttrList","Invalid start time:"<<mAniStart<<", resetting to 0.0");
- mAniStart = 0.0;
- }
-
- //mSurfaceTension = mpAttrs->readFloat("p_surfacetension",mSurfaceTension, "Parametrizer","mSurfaceTension", false);
- //if(getAttributeList()->exists("p_surfacetension")) seenThis( PARAM_SURFACETENSION );
-
- mDensity = mpAttrs->readFloat("p_density",mDensity, "Parametrizer","mDensity", false);
- if(getAttributeList()->exists("p_density")) seenThis( PARAM_DENSITY );
-
- ParamFloat cellSize = 0.0; // unused, deprecated
- cellSize = mpAttrs->readFloat("p_cellsize",cellSize, "Parametrizer","cellSize", false);
-
- mGStar = mpAttrs->readFloat("p_gstar",mGStar, "Parametrizer","mGStar", false);
- if(getAttributeList()->exists("p_gstar")) seenThis( PARAM_GSTAR );
-
- mNormalizedGStar = mpAttrs->readFloat("p_normgstar",mNormalizedGStar, "Parametrizer","mNormalizedGStar", false);
- if(getAttributeList()->exists("p_normgstar")) seenThis( PARAM_NORMALIZEDGSTAR );
-
- mTadapMaxOmega = mpAttrs->readFloat("p_tadapmaxomega",mTadapMaxOmega, "Parametrizer","mTadapMaxOmega", false);
- mTadapMaxSpeed = mpAttrs->readFloat("p_tadapmaxspeed",mTadapMaxSpeed, "Parametrizer","mTadapMaxSpeed", false);
-}
-
-/******************************************************************************
- *! advance to next render/output frame
- *****************************************************************************/
-void Parametrizer::setFrameNum(int frame) {
- mFrameNum = frame;
-#if DEBUG_PARAMCHANNELS>0
- errMsg("DEBUG_PARAMCHANNELS","setFrameNum frame-num="<<mFrameNum);
-#endif // DEBUG_PARAMCHANNELS>0
-}
-/*! get time of an animation frame (renderer) */
-// also used by: mpParam->getCurrentAniFrameTime() , e.g. for velocity dump
-ParamFloat Parametrizer::getAniFrameTime( int frame ) {
- double frametime = (double)frame;
- ParamFloat anift = mcAniFrameTime.get(frametime);
- if(anift<0.0) {
- ParamFloat resetv = 0.;
- errMsg("Parametrizer::setFrameNum","Invalid frame time:"<<anift<<" at frame "<<frame<<", resetting to "<<resetv);
- anift = resetv;
- }
-#if DEBUG_PARAMCHANNELS>0
- if((0)|| (DEBUG_PARAMCHANNELS)) errMsg("DEBUG_PARAMCHANNELS","getAniFrameTime frame="<<frame<<", frametime="<<anift<<" ");
-#endif // DEBUG_PARAMCHANNELS>0
- return anift;
-}
-
-/******************************************************************************
- * scale a given speed vector in m/s to lattice values
- *****************************************************************************/
-ParamVec Parametrizer::calculateAddForce(ParamVec vec, string usage)
-{
- ParamVec ret = vec * (mTimestep*mTimestep) /mCellSize;
- debMsgStd("Parametrizer::calculateVector", DM_MSG, "scaled vector = "<<ret<<" for '"<<usage<<"', org = "<<vec<<" dt="<<mTimestep ,10);
- return ret;
-}
-
-
-/******************************************************************************
- * calculate size of a single cell
- *****************************************************************************/
-ParamFloat Parametrizer::calculateCellSize(void)
-{
- int maxsize = mSizex; // get max size
- if(mSizey>maxsize) maxsize = mSizey;
- if(mSizez>maxsize) maxsize = mSizez;
- maxsize = mSizez; // take along gravity dir for now!
- ParamFloat cellSize = 1.0 / (ParamFloat)maxsize;
- return cellSize;
-}
-
-
-/*****************************************************************************/
-/* simple calulation functions */
-/*****************************************************************************/
-
-/*! get omega for LBM from channel */
-ParamFloat Parametrizer::calculateOmega( double time ) {
- ParamFloat viscStar = calculateLatticeViscosity(time);
- ParamFloat relaxTime = (6.0 * viscStar + 1) * 0.5;
-#if DEBUG_PARAMCHANNELS>0
- errMsg("DEBUG_PARAMCHANNELS","calculateOmega viscStar="<<viscStar<<" relaxtime="<<relaxTime);
-#endif // DEBUG_PARAMCHANNELS>0
- return (1.0/relaxTime);
-}
-
-/*! get external force x component */
-ParamVec Parametrizer::calculateGravity( double time ) {
- ParamVec grav = mcGravity.get(time);
- ParamFloat forceFactor = (mTimestep *mTimestep)/mCellSize;
- ParamVec latticeGravity = grav * forceFactor;
-#if DEBUG_PARAMCHANNELS>0
- errMsg("DEBUG_PARAMCHANNELS","calculateGravity grav="<<grav<<" ff"<<forceFactor<<" lattGrav="<<latticeGravity);
-#endif // DEBUG_PARAMCHANNELS>0
- return latticeGravity;
-}
-
-/*! calculate the lattice viscosity */
-ParamFloat Parametrizer::calculateLatticeViscosity( double time ) {
- // check seen values
- int reqValues = PARAM_VISCOSITY | PARAM_STEPTIME;
- if(!checkSeenValues( reqValues ) ){
- errMsg("Parametrizer::calculateLatticeViscosity"," Missing arguments!");
- }
- ParamFloat viscStar = mcViscosity.get(time) * mTimestep / (mCellSize*mCellSize);
-#if DEBUG_PARAMCHANNELS>0
- errMsg("DEBUG_PARAMCHANNELS","calculateLatticeViscosity viscStar="<<viscStar);
-#endif // DEBUG_PARAMCHANNELS>0
- return viscStar;
-}
-
-/*! get no of steps for the given length in seconds */
-int Parametrizer::calculateStepsForSecs( ParamFloat s ) {
- return (int)(s/mTimestep);
-}
-
-/*! get start time of animation */
-int Parametrizer::calculateAniStart( void ) {
- return (int)(mAniStart/mTimestep);
-}
-
-/*! get no of steps for a single animation frame */
-int Parametrizer::calculateAniStepsPerFrame(int frame) {
- if(!checkSeenValues(PARAM_ANIFRAMETIME)) {
- errFatal("Parametrizer::calculateAniStepsPerFrame", "Missing ani frame time argument!", SIMWORLD_INITERROR);
- return 1;
- }
- int value = (int)(getAniFrameTime(frame)/mTimestep);
- if((value<0) || (value>1000000)) {
- errFatal("Parametrizer::calculateAniStepsPerFrame", "Invalid step-time (="<<value<<") <> ani-frame-time ("<<mTimestep<<") settings, aborting...", SIMWORLD_INITERROR);
- return 1;
- }
- return value;
-}
-
-/*! get no. of timesteps for LBM */
-int Parametrizer::calculateNoOfSteps( ParamFloat timelen ) {
- return (int)(timelen/mTimestep);
-}
-
-/*! get extent of the domain = (1,1,1) if parametrizer not used, (x,y,z) [m] otherwise */
-//ParamVec Parametrizer::calculateExtent( void ) {
- //return mExtent;
-//}
-
-/*! get (scaled) surface tension */
-//ParamFloat Parametrizer::calculateSurfaceTension( void ) { return mSurfaceTension; }
-
-/*! get the length of a single time step */
-// explicity scaled by time factor for refinement
-ParamFloat Parametrizer::getTimestep( void ) {
- return mTimestep;
-}
-
-/*! calculate lattice velocity from real world value [m/s] */
-ParamVec Parametrizer::calculateLattVelocityFromRw( ParamVec ivel ) {
- ParamVec velvec = ivel;
- velvec /= mCellSize;
- velvec *= mTimestep;
- return velvec;
-}
-/*! calculate real world [m/s] velocity from lattice value */
-ParamVec Parametrizer::calculateRwVelocityFromLatt( ParamVec ivel ) {
- ParamVec velvec = ivel;
- velvec *= mCellSize;
- velvec /= mTimestep;
- return velvec;
-}
-
-
-/*! get g star value with fhvol calculations */
-ParamFloat Parametrizer::getCurrentGStar( void ) {
- ParamFloat gStar = mGStar; // check? TODO get from mNormalizedGStar?
- if(mFluidVolumeHeight>0.0) { gStar = mGStar/mFluidVolumeHeight; }
- return gStar;
-}
-
-/******************************************************************************
- * function that tries to calculate all the missing values from the given ones
- * prints errors and returns false if thats not possible
- *****************************************************************************/
-bool Parametrizer::calculateAllMissingValues( double time, bool silent )
-{
- bool init = false; // did we init correctly?
- int valuesChecked = 0;
- int reqValues;
-
- // we always need the sizes
- reqValues = PARAM_SIZE;
- valuesChecked |= reqValues;
- if(!checkSeenValues(reqValues)) {
- errMsg("Parametrizer::calculateAllMissingValues"," Missing size argument!");
- return false;
- }
-
- if(!checkSeenValues(PARAM_DOMAINSIZE)) {
- errMsg("Parametrizer::calculateAllMissingValues"," Missing domain size argument!");
- return false;
- }
- int maxsize = mSizex; // get max size
- if(mSizey>maxsize) maxsize = mSizey;
- if(mSizez>maxsize) maxsize = mSizez;
- maxsize = mSizez; // take along gravity dir for now!
- mCellSize = ( mDomainSize * calculateCellSize() ); // sets mCellSize
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," max domain resolution="<<(maxsize)<<" cells , cellsize="<<mCellSize ,10);
-
-
- /* Carolin init , see DA for details */
- ParamFloat maxDeltaT = 0.0;
-
- /* normalized gstar init */
- reqValues = PARAM_NORMALIZEDGSTAR;
- valuesChecked |= reqValues;
- if(checkSeenValues( reqValues ) ){
- //if(checkSeenValues( PARAM_GSTAR ) ){ if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_WARNING," g star value override by normalizedGStar!",1); }
- const ParamFloat normgstarReset = 0.005;
- if(mNormalizedGStar<=1e-6) {
- errMsg("Parametrizer::calculateAllMissingValues","Invalid NormGstar: "<<mNormalizedGStar<<"... resetting to "<<normgstarReset);
- mNormalizedGStar = normgstarReset;
- }
-
- mGStar = mNormalizedGStar/maxsize;
-
-// TODO FIXME add use testdata check!
-mGStar = mNormalizedGStar/mSizez;
-errMsg("Warning","Used z-dir for gstar!");
-
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," g star set to "<<mGStar<<" from normalizedGStar="<<mNormalizedGStar ,1);
- seenThis(PARAM_GSTAR);
- }
-
- reqValues = PARAM_GSTAR | PARAM_VISCOSITY;
- if((checkSeenValues(PARAM_SURFACETENSION))) reqValues |= PARAM_DENSITY; // surface tension optional now...
- valuesChecked |= reqValues;
- if(checkSeenValues( reqValues ) ){
- const ParamFloat gstarReset = 0.0005;
- if(getCurrentGStar()<=1e-6) {
- errMsg("Parametrizer::calculateAllMissingValues","Invalid Gstar: "<<getCurrentGStar()<<" (set to "<<mGStar<<") ... resetting to "<<gstarReset);
- mGStar = gstarReset;
- }
-
- ParamFloat gStar = getCurrentGStar(); // mGStar
- if(mFluidVolumeHeight>0.0) {
- debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," height"<<mFluidVolumeHeight<<" resGStar = "<<gStar, 10);
- }
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," g star = "<<gStar, 10);
-
- ParamFloat forceStrength = 0.0;
- //if(checkSeenValues(PARAM_GRAVITY)) { forceStrength = norm( calculateGravity(time) ); }
- if(checkSeenValues(PARAM_GRAVITY)) { forceStrength = norm( mcGravity.get(time) ); }
-
- // determine max. delta density per timestep trough gravity force
- if(forceStrength>0.0) {
- maxDeltaT = sqrt( gStar*mCellSize *mTimeStepScale /forceStrength );
- } else {
- // use 1 lbm setp = 1 anim step as max
- maxDeltaT = getAniFrameTime(0);
- }
-
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," targeted step time = "<<maxDeltaT, 10);
-
- //ParamFloat viscStarFac = mViscosity/(mCellSize*mCellSize);
- //if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," viscStarFac = "<<viscStarFac<<" viscosity:"<<mViscosity, 10);
-
- // time step adaptivty, only for caro with max sim speed
- ParamFloat setDeltaT = maxDeltaT;
- if(mDesiredTimestep>0.0) {
- // explicitly set step time according to max velocity in sim
- setDeltaT = mDesiredTimestep;
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," desired step time = "<<setDeltaT, 10);
- mDesiredTimestep = -1.0;
- } else {
- // just use max delta t as current
- }
-
- // and once for init determine minimal delta t by omega max.
- if((mMinTimestep<0.0) || (mMaxTimestep<0.0)) {
- ParamFloat minDeltaT;
- ParamFloat maxOmega = mTadapMaxOmega;
- ParamFloat minRelaxTime = 1.0/maxOmega;
- for(int lev=1; lev<mTadapLevels; lev++) {
- // make minRelaxTime larger for each level that exists...
- minRelaxTime = 2.0 * (minRelaxTime-0.5) + 0.5;
- }
- maxOmega = 1.0/minRelaxTime;
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," maxOmega="<<maxOmega<<" minRelaxTime="<<minRelaxTime<<" levels="<<mTadapLevels, 1);
- // visc-star for min relax time to calculate min delta ta
- if(mcViscosity.get(time)>0.0) {
- minDeltaT = ((2.0*minRelaxTime-1.0)/6.0) * mCellSize * mCellSize / mcViscosity.get(time);
- } else {
- // visc=0, this is not physical, but might happen
- minDeltaT = 0.0;
- }
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," min delta t = "<<minDeltaT<<" , range = " << (maxDeltaT/minDeltaT) ,1);
-
- // sim speed + accel shouldnt exceed 0.1?
- mMaxTimestep = maxDeltaT;
- mMinTimestep = minDeltaT;
- // only use once...
- }
-
- setTimestep( setDeltaT ); // set mTimestep to new value
- init = true;
- }
-
- // finish init
- if(init) {
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," omega = "<<calculateOmega(0.0)<<", delt="<<mTimestep,1);
-
- if(checkSeenValues(PARAM_GRAVITY)) {
- ParamFloat forceFactor = (mTimestep *mTimestep)/mCellSize; // only used for printing...
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," gravity force = "<<PRINT_NTLVEC(mcGravity.get(time))<<", scaled with "<<forceFactor<<" to "<<calculateGravity(time),1);
- }
-
- //mExtent = ParamVec( mCellSize*mSizex, mCellSize*mSizey, mCellSize*mSizez );
- //if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," domain extent = "<<PRINT_NTLVEC(mExtent)<<"m , gs:"<<PRINT_VEC(mSizex,mSizey,mSizez)<<" cs:"<<mCellSize,1);
-
- if(!checkSeenValues(PARAM_ANIFRAMETIME)) {
- errFatal("Parametrizer::calculateAllMissingValues"," Warning no ani frame time given!", SIMWORLD_INITERROR);
- setAniFrameTimeChannel( mTimestep );
- }
-
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," ani frame steps = "<<calculateAniStepsPerFrame(mFrameNum)<<" for frame "<<mFrameNum, 1);
-
- if((checkSeenValues(PARAM_ANISTART))&&(calculateAniStart()>0)) {
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," ani start steps = "<<calculateAniStart()<<" ",1);
- }
-
- if(! isSimworldOk() ) return false;
- // everything ok
- return true;
- }
-
- // init failed ... failure:
- errMsg("Parametrizer::calculateAllMissingValues "," invalid configuration!");
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues ",DM_WARNING, " values seen:", 1);
- for(int i=0;i<PARAM_NUMIDS;i++) {
- if(checkSeenValues( 1<<i )) {
- if(!silent) debMsgStd(" ",DM_NOTIFY, ParamStrings[i], 1);
- }
- }
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues ",DM_WARNING, "values checked but missing:", 1);
- for(int i=0;i<PARAM_NUMIDS;i++) {
- if((!checkSeenValues( 1<<i ))&&
- ( (valuesChecked&(1<<i))==(1<<i)) ) {
- debMsgStd(" ",DM_IMPORTANT, ParamStrings[i], 1);
- }
- }
-
- // print values?
- return false;
-}
-
-
-/******************************************************************************
- * init debug functions
- *****************************************************************************/
-
-
-/*! set kinematic viscosity */
-void Parametrizer::setViscosity(ParamFloat set) {
- mcViscosity = AnimChannel<ParamFloat>(set);
- seenThis( PARAM_VISCOSITY );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcViscosity set = "<< mcViscosity.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-void Parametrizer::initViscosityChannel(vector<ParamFloat> val, vector<double> time) {
- mcViscosity = AnimChannel<ParamFloat>(val,time);
- seenThis( PARAM_VISCOSITY );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcViscosity initc = "<< mcViscosity.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-
-/*! set the external force */
-void Parametrizer::setGravity(ParamFloat setx, ParamFloat sety, ParamFloat setz) {
- mcGravity = AnimChannel<ParamVec>(ParamVec(setx,sety,setz));
- seenThis( PARAM_GRAVITY );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcGravity set = "<< mcGravity.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-void Parametrizer::setGravity(ParamVec set) {
- mcGravity = AnimChannel<ParamVec>(set);
- seenThis( PARAM_GRAVITY );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcGravity set = "<< mcGravity.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-void Parametrizer::initGravityChannel(vector<ParamVec> val, vector<double> time) {
- mcGravity = AnimChannel<ParamVec>(val,time);
- seenThis( PARAM_GRAVITY );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcGravity initc = "<< mcGravity.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-
-/*! set time of an animation frame (renderer) */
-void Parametrizer::setAniFrameTimeChannel(ParamFloat set) {
- mcAniFrameTime = AnimChannel<ParamFloat>(set);
- seenThis( PARAM_ANIFRAMETIME );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcAniFrameTime set = "<< mcAniFrameTime.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-void Parametrizer::initAniFrameTimeChannel(vector<ParamFloat> val, vector<double> time) {
- mcAniFrameTime = AnimChannel<ParamFloat>(val,time);
- seenThis( PARAM_ANIFRAMETIME );
-#if DEBUG_PARAMCHANNELS>0
- { errMsg("DebugChannels","Parametrizer::mcAniFrameTime initc = "<< mcAniFrameTime.printChannel() ); }
-#endif // DEBUG_PARAMCHANNELS>0
-}
-
-// OLD interface stuff
-// reactivate at some point?
-
- /*! surface tension, [kg/s^2] */
- //ParamFloat mSurfaceTension;
- /*! set starting time of the animation (renderer) */
- //void setSurfaceTension(ParamFloat set) { mSurfaceTension = set; seenThis( PARAM_SURFACETENSION ); }
- /*! get starting time of the animation (renderer) */
- //ParamFloat getSurfaceTension( void ) { return mSurfaceTension; }
- /*if((checkSeenValues(PARAM_SURFACETENSION))&&(mSurfaceTension>0.0)) {
- ParamFloat massDelta = 1.0;
- ParamFloat densityStar = 1.0;
- massDelta = mDensity / densityStar *mCellSize*mCellSize*mCellSize;
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," massDelta = "<<massDelta, 10);
-
- mSurfaceTension = mSurfaceTension*mTimestep*mTimestep/massDelta;
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," surface tension = "<<mSurfaceTension<<" ",1);
- } // */
-
-// probably just delete:
-
- /*! reynolds number (calculated from domain length and max. speed [dimensionless] */
- //ParamFloat mReynolds;
-
- /*! set relaxation time */
- //void setRelaxTime(ParamFloat set) { mRelaxTime = set; seenThis( PARAM_RELAXTIME ); }
- /*! get relaxation time */
- //ParamFloat getRelaxTime( void ) { return mRelaxTime; }
- /*! set reynolds number */
- //void setReynolds(ParamFloat set) { mReynolds = set; seenThis( PARAM_REYNOLDS ); }
- /*! get reynolds number */
- //ParamFloat getReynolds( void ) { return mReynolds; }
-
- // calculate reynolds number
- /*if(mViscosity>0.0) {
- ParamFloat maxSpeed = 1.0/6.0; // for rough reynolds approx
- ParamFloat reynoldsApprox = -1.0;
- ParamFloat gridSpeed = (maxSpeed*mCellSize/mTimestep);
- reynoldsApprox = (mDomainSize*gridSpeed) / mViscosity;
- if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," reynolds number (D="<<mDomainSize<<", assuming V="<<gridSpeed<<")= "<<reynoldsApprox<<" ", 1);
- } // */
-
- //? mRelaxTime = mpAttrs->readFloat("p_relaxtime",mRelaxTime, "Parametrizer","mRelaxTime", false);
- //if(getAttributeList()->exists("p_relaxtime")) seenThis( PARAM_RELAXTIME );
- //? mReynolds = mpAttrs->readFloat("p_reynolds",mReynolds, "Parametrizer","mReynolds", false);
- //if(getAttributeList()->exists("p_reynolds")) seenThis( PARAM_REYNOLDS );
-
- //mViscosity = mpAttrs->readFloat("p_viscosity",mViscosity, "Parametrizer","mViscosity", false);
- //if(getAttributeList()->exists("p_viscosity") || (!mcViscosity.isInited()) ) { }
- //if(getAttributeList()->exists("p_viscosity"))
-
-
- //ParamFloat viscStar = calculateLatticeViscosity(time);
- //RelaxTime = (6.0 * viscStar + 1) * 0.5;
-
-
diff --git a/intern/elbeem/intern/parametrizer.h b/intern/elbeem/intern/parametrizer.h
deleted file mode 100644
index bd7377b9fbd..00000000000
--- a/intern/elbeem/intern/parametrizer.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Parameter calculator for the LBM Solver class
- *
- *****************************************************************************/
-#ifndef MFFSLBM_PARAMETRIZER
-#define MFFSLBM_PARAMETRIZER
-
-
-/* LBM Files */
-#include "utilities.h"
-#include "attributes.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-/* parametrizer accuracy */
-typedef double ParamFloat;
-typedef ntlVec3d ParamVec;
-
-/*! flags to check which values are known */
-#define PARAM_RELAXTIME (1<< 0)
-#define PARAM_REYNOLDS (1<< 1)
-#define PARAM_VISCOSITY (1<< 2)
-#define PARAM_SOUNDSPEED (1<< 3)
-#define PARAM_DOMAINSIZE (1<< 4)
-#define PARAM_GRAVITY (1<< 5)
-#define PARAM_STEPTIME (1<< 7)
-#define PARAM_SIZE (1<< 8)
-#define PARAM_TIMEFACTOR (1<< 9)
-#define PARAM_ANIFRAMETIME (1<<11)
-#define PARAM_ANISTART (1<<12)
-#define PARAM_SURFACETENSION (1<<13)
-#define PARAM_DENSITY (1<<14)
-#define PARAM_GSTAR (1<<16)
-#define PARAM_SIMMAXSPEED (1<<18)
-#define PARAM_FLUIDVOLHEIGHT (1<<19)
-#define PARAM_NORMALIZEDGSTAR (1<<20)
-#define PARAM_NUMIDS 21
-
-//! output parameter debug message?
-//#define PARAM_DEBUG 1
-
-
-
-/*! Parameter calculator for the LBM Solver class */
-class Parametrizer {
-
- public:
- /*! default contructor */
- Parametrizer();
-
- /*! destructor */
- ~Parametrizer();
-
- /*! Initilize variables fom attribute list */
- void parseAttrList( void );
-
- /*! function that tries to calculate all the missing values from the given ones
- * prints errors and returns false if thats not possible
- * currently needs time value as well */
- bool calculateAllMissingValues( double time, bool silent );
- /*! is the parametrizer used at all? */
- bool isUsed() { return true; }
-
- /*! add this flag to the seen values */
- void seenThis(int seen) { mSeenValues = (mSeenValues | seen);
-#ifdef PARAM_DEBUG
- errorOut(" seen "<<seen<<endl);
-#endif
- }
-
- /*! set the flags integer */
- void setSeenValues(int set) { mSeenValues = set; }
- /*! check if the flags are set in the values int */
- bool checkSeenValues(int check) { /*errorOut( " b"<<((mSeenValues&check)==check) );*/ return ((mSeenValues&check)==check); }
-
- /*! add this flag to the calculated values */
- void calculatedThis(int cac) { mCalculatedValues = (mCalculatedValues | cac); /*errorOut(" a "<<seen);*/ }
- /*! set the calculated flags integer */
- void setCalculatedValues(int set) { mCalculatedValues = set; }
- /*! check if the calculated flags are set in the values int */
- bool checkCalculatedValues(int check) { /*errorOut( " b"<<((mSeenValues&check)==check) );*/ return ((mCalculatedValues&check)==check); }
- /*! advance to next render/output frame */
- void setFrameNum(int frame);
- ParamFloat getAniFrameTime(int frame);
- ParamFloat getCurrentAniFrameTime(){ return getAniFrameTime(mFrameNum); };
-
- /*! scale a given speed vector in m/s to lattice values
- * usage string is only needed for debugging */
- ParamVec calculateAddForce(ParamVec vec, string usage);
-
- /* simple calulation functions */
- /*! get omega for LBM */
- ParamFloat calculateOmega( double time );
- /*! get no. of timesteps for LBM */
- int calculateNoOfSteps( ParamFloat timelen );
- /*! get external force x component */
- ParamVec calculateGravity( double time );
- /*! get no of steps for the given length in seconds */
- int calculateStepsForSecs( ParamFloat s );
- /*! get no of steps for a singel animation frame */
- int calculateAniStepsPerFrame(int frame);
- /*! get start time of animation */
- int calculateAniStart( void );
- /*! get extent of the domain = (1,1,1) if parametrizer not used, (x,y,z) [m] otherwise */
- //ParamVec calculateExtent( void );
- /*! get (scaled) surface tension */
- ParamFloat calculateSurfaceTension( void );
- /*! get time step size for lbm (equals mTimeFactor) */
- // unused ParamFloat calculateTimestep( void );
- /*! calculate size of a single cell */
- ParamFloat calculateCellSize(void);
- /*! calculate the lattice viscosity */
- ParamFloat calculateLatticeViscosity( double time );
-
- /*! calculate lattice velocity from real world value [m/s] */
- ParamVec calculateLattVelocityFromRw( ParamVec ivel );
- /*! calculate real world [m/s] velocity from lattice value */
- ParamVec calculateRwVelocityFromLatt( ParamVec ivel );
-
- /*! set speed of sound */
- void setSoundSpeed(ParamFloat set) { mSoundSpeed = set; seenThis( PARAM_SOUNDSPEED ); }
- /*! get speed of sound */
- ParamFloat getSoundSpeed( void ) { return mSoundSpeed; }
-
- /*! set kinematic viscosity */
- void setViscosity(ParamFloat set);
- void initViscosityChannel(vector<ParamFloat> val, vector<double> time);
-
- /*! set the external force */
- void setGravity(ParamFloat setx, ParamFloat sety, ParamFloat setz);
- void setGravity(ParamVec set);
- void initGravityChannel(vector<ParamVec> val, vector<double> time);
- ParamVec getGravity(double time) { return mcGravity.get( time ); }
-
- /*! set time of an animation frame (renderer) */
- void setAniFrameTimeChannel(ParamFloat set);
- void initAniFrameTimeChannel(vector<ParamFloat> val, vector<double> time);
-
- /*! set the length of a single time step */
- void setTimestep(ParamFloat set) { mTimestep = set; seenThis( PARAM_STEPTIME ); }
- /*! get the length of a single time step */
- ParamFloat getTimestep( void);
- /*! set a desired step time for rescaling/adaptive timestepping */
- void setDesiredTimestep(ParamFloat set) { mDesiredTimestep = set; }
- /*! get the length of a single time step */
- ParamFloat getMaxTimestep( void ) { return mMaxTimestep; }
- /*! get the length of a single time step */
- ParamFloat getMinTimestep( void ) { return mMinTimestep; }
-
- /*! set the time scaling factor */
- void setTimeFactor(ParamFloat set) { mTimeFactor = set; seenThis( PARAM_TIMEFACTOR ); }
- /*! get the time scaling factor */
- ParamFloat getTimeFactor( void ) { return mTimeFactor; }
-
- /*! init domain resoultion */
- void setSize(int ijk) { mSizex = ijk; mSizey = ijk; mSizez = ijk; seenThis( PARAM_SIZE ); }
- void setSize(int i,int j, int k) { mSizex = i; mSizey = j; mSizez = k; seenThis( PARAM_SIZE ); }
-
- /*! set starting time of the animation (renderer) */
- void setAniStart(ParamFloat set) { mAniStart = set; seenThis( PARAM_ANISTART ); }
- /*! get starting time of the animation (renderer) */
- ParamFloat getAniStart( void ) { return mAniStart; }
-
- /*! set fluid density */
- void setDensity(ParamFloat set) { mDensity = set; seenThis( PARAM_DENSITY ); }
- /*! get fluid density */
- ParamFloat getDensity( void ) { return mDensity; }
-
- /*! set g star value */
- void setGStar(ParamFloat set) { mGStar = set; seenThis( PARAM_GSTAR ); }
- /*! get g star value */
- ParamFloat getGStar( void ) { return mGStar; }
- /*! get g star value with fhvol calculations */
- ParamFloat getCurrentGStar( void );
- /*! set normalized g star value */
- void setNormalizedGStar(ParamFloat set) { mNormalizedGStar = set; seenThis( PARAM_NORMALIZEDGSTAR ); }
- /*! get normalized g star value */
- ParamFloat getNormalizedGStar( void ) { return mNormalizedGStar; }
-
- /*! set g star value */
- void setFluidVolumeHeight(ParamFloat set) { mFluidVolumeHeight = set; seenThis( PARAM_FLUIDVOLHEIGHT ); }
- /*! get g star value */
- ParamFloat getFluidVolumeHeight( void ) { return mFluidVolumeHeight; }
-
- /*! set the size of a single lbm cell */
- void setDomainSize(ParamFloat set) { mDomainSize = set; seenThis( PARAM_DOMAINSIZE ); }
- /*! get the size of a single lbm cell */
- ParamFloat getDomainSize( void ) { return mDomainSize; }
-
- /*! set the size of a single lbm cell (dont use, normally set by domainsize and resolution) */
- void setCellSize(ParamFloat set) { mCellSize = set; }
- /*! get the size of a single lbm cell */
- ParamFloat getCellSize( void ) { return mCellSize; }
-
- /*! set active flag for parametrizer */
- //void setActive(bool set) { mActive = set; }
-
- /*! set attr list pointer */
- void setAttrList(AttributeList *set) { mpAttrs = set; }
- /*! Returns the attribute list pointer */
- inline AttributeList *getAttributeList() { return mpAttrs; }
-
- /*! set maximum allowed speed for maxspeed setup */
- void setSimulationMaxSpeed(ParamFloat set) { mSimulationMaxSpeed = set; seenThis( PARAM_SIMMAXSPEED ); }
- /*! get maximum allowed speed for maxspeed setup */
- ParamFloat getSimulationMaxSpeed( void ) { return mSimulationMaxSpeed; }
-
- /*! set maximum allowed omega for time adaptivity */
- void setTadapMaxOmega(ParamFloat set) { mTadapMaxOmega = set; }
- /*! get maximum allowed omega for time adaptivity */
- ParamFloat getTadapMaxOmega( void ) { return mTadapMaxOmega; }
-
- /*! set maximum allowed speed for time adaptivity */
- void setTadapMaxSpeed(ParamFloat set) { mTadapMaxSpeed = set; }
- /*! get maximum allowed speed for time adaptivity */
- ParamFloat getTadapMaxSpeed( void ) { return mTadapMaxSpeed; }
-
- /*! set maximum allowed omega for time adaptivity */
- void setTadapLevels(int set) { mTadapLevels = set; }
- /*! get maximum allowed omega for time adaptivity */
- int getTadapLevels( void ) { return mTadapLevels; }
-
- /*! set */
- // void set(ParamFloat set) { m = set; seenThis( PARAM_ ); }
- /*! get */
- // ParamFloat get( void ) { return m; }
-
-
-
- private:
-
- /*! kinematic viscosity of the fluid [m^2/s] */
- AnimChannel<ParamFloat> mcViscosity;
-
- /*! speed of sound of the fluid [m/s] */
- ParamFloat mSoundSpeed;
-
- /*! size of the domain [m] */
- ParamFloat mDomainSize;
-
- /*! size of a single cell in the grid [m] */
- ParamFloat mCellSize;
-
- /*! time step length [s] */
- ParamFloat mTimeStep;
-
- /*! external force as acceleration [m/s^2] */
- AnimChannel<ParamVec> mcGravity;
-
- /*! length of one time step in the simulation */
- ParamFloat mTimestep;
- /*! desired step time for rescaling/adaptive timestepping, only regarded if >0.0, reset after usage */
- ParamFloat mDesiredTimestep;
- /*! minimal and maximal step times for current setup */
- ParamFloat mMaxTimestep, mMinTimestep;
-
- /*! domain resoultion, the same values as in lbmsolver */
- int mSizex, mSizey, mSizez;
-
- /*! time scaling factor (auto calc from accel, or set), equals the delta t in LBM */
- ParamFloat mTimeFactor;
-
- /*! for renderer - length of an animation step [s] */
- AnimChannel<ParamFloat> mcAniFrameTime;
- /*! time step scaling factor for testing/debugging */
- ParamFloat mTimeStepScale;
-
- /*! for renderer - start time of the animation [s] */
- ParamFloat mAniStart;
-
- /*! extent of the domain in meters */
- //ParamVec mExtent;
-
- /*! fluid density [kg/m^3], default 1.0 g/cm^3 */
- ParamFloat mDensity;
-
- /*! max difference due to gravity (for caro setup) */
- ParamFloat mGStar;
- /*! set gstar normalized! */
- ParamFloat mNormalizedGStar;
- /*! fluid volume/height multiplier for GStar */
- ParamFloat mFluidVolumeHeight;
-
- /*! current max speed of the simulation (for adaptive time steps) */
- ParamFloat mSimulationMaxSpeed;
- /*! maximum omega (for adaptive time steps) */
- ParamFloat mTadapMaxOmega;
- /*! maximum allowed speed in lattice units e.g. 0.1 (for adaptive time steps, not directly used in parametrizer) */
- ParamFloat mTadapMaxSpeed;
- /*! no. of levels for max omega (set by fsgr, not in cfg file) */
- int mTadapLevels;
-
- /*! remember current frame number */
- int mFrameNum;
-
- /*! values that are seen for this simulation */
- int mSeenValues;
-
- /*! values that are calculated from the seen ones for this simulation */
- int mCalculatedValues;
-
- /*! pointer to the attribute list */
- AttributeList *mpAttrs;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:Parametrizer")
-#endif
-};
-
-
-#endif
-
diff --git a/intern/elbeem/intern/particletracer.cpp b/intern/elbeem/intern/particletracer.cpp
deleted file mode 100644
index 7a0005f67ce..00000000000
--- a/intern/elbeem/intern/particletracer.cpp
+++ /dev/null
@@ -1,470 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Particle Viewer/Tracer
- *
- *****************************************************************************/
-
-#include <stdio.h>
-//#include "../libs/my_gl.h"
-//#include "../libs/my_glu.h"
-
-/* own lib's */
-#include "particletracer.h"
-#include "ntl_matrices.h"
-#include "ntl_ray.h"
-#include "ntl_matrices.h"
-#include "globals.h"
-
-#include <zlib.h>
-
-
-// particle object id counter
-int ParticleObjectIdCnt = 1;
-
-/******************************************************************************
- * Standard constructor
- *****************************************************************************/
-ParticleTracer::ParticleTracer() :
- ntlGeometryObject(),
- mParts(),
- //mTrailLength(1), mTrailInterval(1),mTrailIntervalCounter(0),
- mPartSize(0.01),
- mStart(-1.0), mEnd(1.0),
- mSimStart(-1.0), mSimEnd(1.0),
- mPartScale(0.1) , mPartHeadDist( 0.1 ), mPartTailDist( -0.1 ), mPartSegments( 4 ),
- mValueScale(0),
- mValueCutoffTop(0.0), mValueCutoffBottom(0.0),
- mDumpParts(0), //mDumpText(0),
- mDumpTextFile(""),
- mDumpTextInterval(0.), mDumpTextLastTime(0.), mDumpTextCount(0),
- mShowOnly(0),
- mNumInitialParts(0), mpTrafo(NULL),
- mInitStart(-1.), mInitEnd(-1.),
- mPrevs(), mTrailTimeLast(0.), mTrailInterval(-1.), mTrailLength(0)
-{
- debMsgStd("ParticleTracer::ParticleTracer",DM_MSG,"inited",10);
-};
-
-ParticleTracer::~ParticleTracer() {
- debMsgStd("ParticleTracer::~ParticleTracer",DM_MSG,"destroyed",10);
- if(mpTrafo) delete mpTrafo;
-}
-
-/*****************************************************************************/
-//! parse settings from attributes (dont use own list!)
-/*****************************************************************************/
-void ParticleTracer::parseAttrList(AttributeList *att)
-{
- AttributeList *tempAtt = mpAttrs;
- mpAttrs = att;
-
- mNumInitialParts = mpAttrs->readInt("particles",mNumInitialParts, "ParticleTracer","mNumInitialParts", false);
- //errMsg(" NUMP"," "<<mNumInitialParts);
- mPartScale = mpAttrs->readFloat("part_scale",mPartScale, "ParticleTracer","mPartScale", false);
- mPartHeadDist = mpAttrs->readFloat("part_headdist",mPartHeadDist, "ParticleTracer","mPartHeadDist", false);
- mPartTailDist = mpAttrs->readFloat("part_taildist",mPartTailDist, "ParticleTracer","mPartTailDist", false);
- mPartSegments = mpAttrs->readInt ("part_segments",mPartSegments, "ParticleTracer","mPartSegments", false);
- mValueScale = mpAttrs->readInt ("part_valscale",mValueScale, "ParticleTracer","mValueScale", false);
- mValueCutoffTop = mpAttrs->readFloat("part_valcutofftop",mValueCutoffTop, "ParticleTracer","mValueCutoffTop", false);
- mValueCutoffBottom = mpAttrs->readFloat("part_valcutoffbottom",mValueCutoffBottom, "ParticleTracer","mValueCutoffBottom", false);
-
- mDumpParts = mpAttrs->readInt ("part_dump",mDumpParts, "ParticleTracer","mDumpParts", false);
- // mDumpText deprecatd, use mDumpTextInterval>0. instead
- mShowOnly = mpAttrs->readInt ("part_showonly",mShowOnly, "ParticleTracer","mShowOnly", false);
- mDumpTextFile= mpAttrs->readString("part_textdumpfile",mDumpTextFile, "ParticleTracer","mDumpTextFile", false);
- mDumpTextInterval= mpAttrs->readFloat("part_textdumpinterval",mDumpTextInterval, "ParticleTracer","mDumpTextInterval", false);
-
- string matPart;
- matPart = mpAttrs->readString("material_part", "default", "ParticleTracer","material", false);
- setMaterialName( matPart );
-
- mInitStart = mpAttrs->readFloat("part_initstart",mInitStart, "ParticleTracer","mInitStart", false);
- mInitEnd = mpAttrs->readFloat("part_initend", mInitEnd, "ParticleTracer","mInitEnd", false);
-
- // unused...
- //int mTrailLength = 0; // UNUSED
- //int mTrailInterval= 0; // UNUSED
- mTrailLength = mpAttrs->readInt("traillength",mTrailLength, "ParticleTracer","mTrailLength", false);
- mTrailInterval= mpAttrs->readFloat("trailinterval",mTrailInterval, "ParticleTracer","mTrailInterval", false);
-
- // restore old list
- mpAttrs = tempAtt;
-}
-
-/******************************************************************************
- * draw the particle array
- *****************************************************************************/
-void ParticleTracer::draw()
-{
-}
-
-/******************************************************************************
- * init trafo matrix
- *****************************************************************************/
-void ParticleTracer::initTrafoMatrix() {
- ntlVec3Gfx scale = ntlVec3Gfx(
- (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]),
- (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]),
- (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2])
- );
- ntlVec3Gfx trans = mStart;
- if(!mpTrafo) mpTrafo = new ntlMat4Gfx(0.0);
- mpTrafo->initId();
- for(int i=0; i<3; i++) { mpTrafo->value[i][i] = scale[i]; }
- for(int i=0; i<3; i++) { mpTrafo->value[i][3] = trans[i]; }
-}
-
-/******************************************************************************
- * adapt time step by rescaling velocities
- *****************************************************************************/
-void ParticleTracer::adaptPartTimestep(float factor) {
- for(size_t i=0; i<mParts.size(); i++) {
- mParts[i].setVel( mParts[i].getVel() * factor );
- }
-}
-
-
-/******************************************************************************
- * add a particle at this position
- *****************************************************************************/
-void ParticleTracer::addParticle(float x, float y, float z) {
- ntlVec3Gfx p(x,y,z);
- ParticleObject part( p );
- mParts.push_back( part );
-}
-void ParticleTracer::addFullParticle(ParticleObject &np) {
- mParts.push_back( np );
-}
-
-
-void ParticleTracer::cleanup() {
- // cleanup
- int last = (int)mParts.size()-1;
- if(mDumpTextInterval>0.) { errMsg("ParticleTracer::cleanup","Skipping cleanup due to text dump..."); return; }
-
- for(int i=0; i<=last; i++) {
- if( mParts[i].getActive()==false ) {
- ParticleObject *p = &mParts[i];
- ParticleObject *p2 = &mParts[last];
- *p = *p2; last--; mParts.pop_back();
- }
- }
-}
-
-/******************************************************************************
- *! dump particles if desired
- *****************************************************************************/
-void ParticleTracer::notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename, double simtime) {
- debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"obj:"<<this->getName()<<" frame:"<<frameNrStr<<" dumpp"<<mDumpParts<<" t"<<simtime, 10); // DEBUG
-
- if(
- (dumptype==DUMP_FULLGEOMETRY)&&
- (mDumpParts>0)) {
- // dump to binary file
- std::ostringstream boutfilename("");
- boutfilename << outfilename <<"_particles_" << frameNrStr;
- if(glob_mpactive) {
- if(glob_mpindex>0) { boutfilename << "mp"<<glob_mpindex; }
- }
- boutfilename << ".gz";
- debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"B-Dumping: "<< this->getName() <<", particles:"<<mParts.size()<<" "<< " to "<<boutfilename.str()<<" #"<<frameNr , 7);
- //debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"B-Dumping: partgeodeb sim:"<<mSimStart<<","<<mSimEnd<<" geosize:"<<mStart<<","<<mEnd,2 );
-
- // output to zipped file
- gzFile gzf;
- gzf = gzopen(boutfilename.str().c_str(), "wb1");
- if(gzf) {
- int numParts;
- if(sizeof(numParts)!=4) { errMsg("ParticleTracer::notifyOfDump","Invalid int size"); return; }
- // only dump active particles
- numParts = 0;
- for(size_t i=0; i<mParts.size(); i++) {
- if(!mParts[i].getActive()) continue;
- numParts++;
- }
- gzwrite(gzf, &numParts, sizeof(numParts));
- for(size_t i=0; i<mParts.size(); i++) {
- if(!mParts[i].getActive()) { continue; }
- ParticleObject *p = &mParts[i];
- //int type = p->getType(); // export whole type info
- int type = p->getFlags(); // debug export whole type & status info
- ntlVec3Gfx pos = p->getPos();
- float size = p->getSize();
-
- if(type&PART_FLOAT) { // WARNING same handling for dump!
- // add one gridcell offset
- //pos[2] += 1.0;
- }
- // display as drop for now externally
- //else if(type&PART_TRACER) { type |= PART_DROP; }
-
- pos = (*mpTrafo) * pos;
-
- ntlVec3Gfx v = p->getVel();
- v[0] *= mpTrafo->value[0][0];
- v[1] *= mpTrafo->value[1][1];
- v[2] *= mpTrafo->value[2][2];
- // FIXME check: pos = (*mpTrafo) * pos;
- gzwrite(gzf, &type, sizeof(type));
- gzwrite(gzf, &size, sizeof(size));
- for(int j=0; j<3; j++) { gzwrite(gzf, &pos[j], sizeof(float)); }
- for(int j=0; j<3; j++) { gzwrite(gzf, &v[j], sizeof(float)); }
- }
- gzclose( gzf );
- }
- } // dump?
-}
-
-void ParticleTracer::checkDumpTextPositions(double simtime) {
- // dfor partial & full dump
- if(mDumpTextInterval>0.) {
- debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"t="<<simtime<<" last:"<<mDumpTextLastTime<<" inter:"<<mDumpTextInterval,7);
- }
-
- if((mDumpTextInterval>0.) && (simtime>mDumpTextLastTime+mDumpTextInterval)) {
- // dump to binary file
- std::ostringstream boutfilename("");
- if(mDumpTextFile.length()>1) {
- boutfilename << mDumpTextFile << ".cpart2";
- } else {
- boutfilename << "_particles" << ".cpart2";
- }
- debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"T-Dumping: "<< this->getName() <<", particles:"<<mParts.size()<<" "<< " to "<<boutfilename.str()<<" " , 7);
-
- int numParts = 0;
- // only dump bubble particles
- for(size_t i=0; i<mParts.size(); i++) {
- //if(!mParts[i].getActive()) continue;
- //if(!(mParts[i].getType()&PART_BUBBLE)) continue;
- numParts++;
- }
-
- // output to text file
- //gzFile gzf;
- FILE *stf;
- if(mDumpTextCount==0) {
- //gzf = gzopen(boutfilename.str().c_str(), "w0");
- stf = fopen(boutfilename.str().c_str(), "w");
-
- fprintf( stf, "\n\n# cparts generated by elbeem \n# no. of parts \nN %d \n\n",numParts);
- // fixed time scale for now
- fprintf( stf, "T %f \n\n", 1.0);
- } else {
- //gzf = gzopen(boutfilename.str().c_str(), "a+0");
- stf = fopen(boutfilename.str().c_str(), "a+");
- }
-
- // add current set
- if(stf) {
- fprintf( stf, "\n\n# new set at frame %d,t%f,p%d --------------------------------- \n\n", mDumpTextCount, simtime, numParts );
- fprintf( stf, "S %f \n\n", simtime );
-
- for(size_t i=0; i<mParts.size(); i++) {
- ParticleObject *p = &mParts[i];
- ntlVec3Gfx pos = p->getPos();
- float size = p->getSize();
- float infl = 1.;
- //if(!mParts[i].getActive()) { size=0.; } // switch "off"
- if(!mParts[i].getActive()) { infl=0.; } // switch "off"
- if(!mParts[i].getInFluid()) { infl=0.; } // switch "off"
- if(mParts[i].getLifeTime()<0.) { infl=0.; } // not yet active...
-
- pos = (*mpTrafo) * pos;
- ntlVec3Gfx v = p->getVel();
- v[0] *= mpTrafo->value[0][0];
- v[1] *= mpTrafo->value[1][1];
- v[2] *= mpTrafo->value[2][2];
-
- fprintf( stf, "P %f %f %f \n", pos[0],pos[1],pos[2] );
- if(size!=1.0) fprintf( stf, "s %f \n", size );
- if(infl!=1.0) fprintf( stf, "i %f \n", infl );
- fprintf( stf, "\n" );
- }
-
- fprintf( stf, "# %d end ", mDumpTextCount );
- //gzclose( gzf );
- fclose( stf );
-
- mDumpTextCount++;
- }
-
- mDumpTextLastTime += mDumpTextInterval;
- }
-
-}
-
-
-void ParticleTracer::checkTrails(double time) {
- if(mTrailLength<1) return;
- if(time-mTrailTimeLast > mTrailInterval) {
-
- if( (int)mPrevs.size() < mTrailLength) mPrevs.resize( mTrailLength );
- for(int i=mPrevs.size()-1; i>0; i--) {
- mPrevs[i] = mPrevs[i-1];
- //errMsg("TRAIL"," from "<<i<<" to "<<(i-1) );
- }
- mPrevs[0] = mParts;
-
- mTrailTimeLast += mTrailInterval;
- }
-}
-
-
-/******************************************************************************
- * Get triangles for rendering
- *****************************************************************************/
-void ParticleTracer::getTriangles(double time, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId )
-{
-#ifdef ELBEEM_PLUGIN
- // suppress warnings...
- vertices = NULL; triangles = NULL;
- normals = NULL; objectId = 0;
- time = 0.;
-#else // ELBEEM_PLUGIN
- int pcnt = 0;
- // currently not used in blender
- objectId = 0; // remove, deprecated
- if(mDumpParts>1) {
- return; // only dump, no tri-gen
- }
-
- const bool debugParts = false;
- int tris = 0;
- int segments = mPartSegments;
- ntlVec3Gfx scale = ntlVec3Gfx( (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]), (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]), (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2]));
- ntlVec3Gfx trans = mStart;
- time = 0.; // doesnt matter
-
- for(size_t t=0; t<mPrevs.size()+1; t++) {
- vector<ParticleObject> *dparts;
- if(t==0) {
- dparts = &mParts;
- } else {
- dparts = &mPrevs[t-1];
- }
- //errMsg("TRAILT","prevs"<<t<<"/"<<mPrevs.size()<<" parts:"<<dparts->size() );
-
- gfxReal partscale = mPartScale;
- if(t>1) {
- partscale *= (gfxReal)(mPrevs.size()+1-t) / (gfxReal)(mPrevs.size()+1);
- }
- gfxReal partNormSize = 0.01 * partscale;
- //for(size_t i=0; i<mParts.size(); i++) {
- for(size_t i=0; i<dparts->size(); i++) {
- ParticleObject *p = &( (*dparts)[i] ); // mParts[i];
-
- if(mShowOnly!=10) {
- // 10=show only deleted
- if( p->getActive()==false ) continue;
- } else {
- if( p->getActive()==true ) continue;
- }
- int type = p->getType();
- if(mShowOnly>0) {
- switch(mShowOnly) {
- case 1: if(!(type&PART_BUBBLE)) continue; break;
- case 2: if(!(type&PART_DROP)) continue; break;
- case 3: if(!(type&PART_INTER)) continue; break;
- case 4: if(!(type&PART_FLOAT)) continue; break;
- case 5: if(!(type&PART_TRACER)) continue; break;
- }
- } else {
- // by default dont display inter
- if(type&PART_INTER) continue;
- }
-
- pcnt++;
- ntlVec3Gfx pnew = p->getPos();
- if(type&PART_FLOAT) { // WARNING same handling for dump!
- if(p->getStatus()&PART_IN) { pnew[2] += 0.8; } // offset for display
- // add one gridcell offset
- //pnew[2] += 1.0;
- }
-#if LBMDIM==2
- pnew[2] += 0.001; // DEBUG
- pnew[2] += 0.009; // DEBUG
-#endif
-
- ntlVec3Gfx pdir = p->getVel();
- gfxReal plen = normalize( pdir );
- if( plen < 1e-05) pdir = ntlVec3Gfx(-1.0 ,0.0 ,0.0);
- ntlVec3Gfx pos = (*mpTrafo) * pnew;
- gfxReal partsize = 0.0;
- if(debugParts) errMsg("DebugParts"," i"<<i<<" new"<<pnew<<" vel"<<pdir<<" pos="<<pos );
- //if(i==0 &&(debugParts)) errMsg("DebugParts"," i"<<i<<" new"<<pnew[0]<<" pos="<<pos[0]<<" scale="<<scale[0]<<" t="<<trans[0] );
-
- // value length scaling?
- if(mValueScale==1) {
- partsize = partscale * plen;
- } else if(mValueScale==2) {
- // cut off scaling
- if(plen > mValueCutoffTop) continue;
- if(plen < mValueCutoffBottom) continue;
- partsize = partscale * plen;
- } else {
- partsize = partscale; // no length scaling
- }
- //if(type&(PART_DROP|PART_BUBBLE))
- partsize *= p->getSize()/5.0;
-
- ntlVec3Gfx pstart( mPartHeadDist *partsize, 0.0, 0.0 );
- ntlVec3Gfx pend ( mPartTailDist *partsize, 0.0, 0.0 );
- gfxReal phi = 0.0;
- gfxReal phiD = 2.0*M_PI / (gfxReal)segments;
-
- ntlMat4Gfx cvmat;
- cvmat.initId();
- pdir *= -1.0;
- ntlVec3Gfx cv1 = pdir;
- ntlVec3Gfx cv2 = ntlVec3Gfx(pdir[1], -pdir[0], 0.0);
- ntlVec3Gfx cv3 = cross( cv1, cv2);
- //? for(int l=0; l<3; l++) { cvmat.value[l][0] = cv1[l]; cvmat.value[l][1] = cv2[l]; cvmat.value[l][2] = cv3[l]; }
- pstart = (cvmat * pstart);
- pend = (cvmat * pend);
-
- for(int s=0; s<segments; s++) {
- ntlVec3Gfx p1( 0.0 );
- ntlVec3Gfx p2( 0.0 );
-
- gfxReal radscale = partNormSize;
- radscale = (partsize+partNormSize)*0.5;
- p1[1] += cos(phi) * radscale;
- p1[2] += sin(phi) * radscale;
- p2[1] += cos(phi + phiD) * radscale;
- p2[2] += sin(phi + phiD) * radscale;
- ntlVec3Gfx n1 = ntlVec3Gfx( 0.0, cos(phi), sin(phi) );
- ntlVec3Gfx n2 = ntlVec3Gfx( 0.0, cos(phi + phiD), sin(phi + phiD) );
- ntlVec3Gfx ns = n1*0.5 + n2*0.5;
-
- p1 = (cvmat * p1);
- p2 = (cvmat * p2);
-
- sceneAddTriangle( pos+pstart, pos+p1, pos+p2,
- ns,n1,n2, ntlVec3Gfx(0.0), 1, triangles,vertices,normals );
- sceneAddTriangle( pos+pend , pos+p2, pos+p1,
- ns,n2,n1, ntlVec3Gfx(0.0), 1, triangles,vertices,normals );
-
- phi += phiD;
- tris += 2;
- }
- }
-
- } // t
-
- debMsgStd("ParticleTracer::getTriangles",DM_MSG,"Dumped "<<pcnt<<"/"<<mParts.size()<<" parts, tris:"<<tris<<", showonly:"<<mShowOnly,10);
- return; // DEBUG
-
-#endif // ELBEEM_PLUGIN
-}
-
-
-
-
diff --git a/intern/elbeem/intern/particletracer.h b/intern/elbeem/intern/particletracer.h
deleted file mode 100644
index 10b37406f8c..00000000000
--- a/intern/elbeem/intern/particletracer.h
+++ /dev/null
@@ -1,296 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Particle Viewer/Tracer
- *
- *****************************************************************************/
-#ifndef NTL_PARTICLETRACER_H
-
-#include "ntl_geometryobject.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-template<class Scalar> class ntlMatrix4x4;
-
-// particle types
-#define PART_BUBBLE (1<< 1)
-#define PART_DROP (1<< 2)
-#define PART_INTER (1<< 3)
-#define PART_FLOAT (1<< 4)
-#define PART_TRACER (1<< 5)
-
-// particle state
-#define PART_IN (1<< 8)
-#define PART_OUT (1<< 9)
-#define PART_INACTIVE (1<<10)
-#define PART_OUTFLUID (1<<11)
-
-// defines for particle movement
-#define MOVE_FLOATS 1
-#define FLOAT_JITTER 0.03
-//#define FLOAT_JITTER 0.0
-
-extern int ParticleObjectIdCnt;
-
-//! A single particle
-class ParticleObject
-{
- public:
- //! Standard constructor
- inline ParticleObject(ntlVec3Gfx mp) :
- mPos(mp),mVel(0.0), mSize(1.0), mStatus(0),mLifeTime(0),mpNext(NULL)
- { mId = ParticleObjectIdCnt++; };
- //! Copy constructor
- inline ParticleObject(const ParticleObject &a) :
- mPos(a.mPos), mVel(a.mVel), mSize(a.mSize),
- mStatus(a.mStatus),
- mLifeTime(a.mLifeTime), mpNext(NULL)
- { mId = ParticleObjectIdCnt++; };
- //! Destructor
- inline ~ParticleObject() { /* empty */ };
-
- //! add vector to position
- inline void advance(float vx, float vy, float vz) {
- mPos[0] += vx; mPos[1] += vy; mPos[2] += vz; }
- inline void advanceVec(ntlVec3Gfx v) {
- mPos[0] += v[0]; mPos[1] += v[1]; mPos[2] += v[2]; }
- //! advance with own velocity
- inline void advanceVel() { mPos += mVel; }
- //! add acceleration to velocity
- inline void addToVel(ntlVec3Gfx acc) { mVel += acc; }
-
- //! get/set vector to position
- inline ntlVec3Gfx getPos() { return mPos; }
- inline void setPos(ntlVec3Gfx set) { mPos=set; }
- //! set velocity
- inline void setVel(ntlVec3Gfx set) { mVel = set; }
- //! set velocity
- inline void setVel(gfxReal x, gfxReal y, gfxReal z) { mVel = ntlVec3Gfx(x,y,z); }
- //! get velocity
- inline ntlVec3Gfx getVel() { return mVel; }
-
- //! get/set size value
- inline gfxReal getSize() { return mSize; }
- inline void setSize(gfxReal set) { mSize=set; }
-
- //! get/set next pointer
- inline ParticleObject* getNext() { return mpNext; }
- inline void setNext(ParticleObject* set) { mpNext=set; }
-
- //! get whole flags
- inline int getFlags() const { return mStatus; }
- //! get status (higher byte)
- inline int getStatus() const { return (mStatus&0xFF00); }
- //! set status (higher byte)
- inline void setStatus(int set) { mStatus = set|(mStatus&0x00FF); }
- //! get type (lower byte)
- inline int getType() const { return (mStatus&0x00FF); }
- //! set type (lower byte)
- inline void setType(int set) { mStatus = set|(mStatus&0xFF00); }
- //! get active flag
- inline bool getActive() const { return ((mStatus&PART_INACTIVE)==0); }
- //! set active flag
- inline void setActive(bool set) {
- if(set) mStatus &= (~PART_INACTIVE);
- else mStatus |= PART_INACTIVE;
- }
- //! get influid flag
- inline bool getInFluid() const { return ((mStatus&PART_OUTFLUID)==0); }
- //! set influid flag
- inline void setInFluid(bool set) {
- if(set) mStatus &= (~PART_OUTFLUID);
- else mStatus |= PART_OUTFLUID;
- }
- //! get/set lifetime
- inline float getLifeTime() const { return mLifeTime; }
- //! set type (lower byte)
- inline void setLifeTime(float set) { mLifeTime = set; }
-
- inline int getId() const { return mId; }
-
- static inline float getMass(float size) {
- return 4.0/3.0 * M_PI* (size)*(size)*(size); // mass: 4/3 pi r^3 rho
- }
-
- protected:
-
- /*! only for debugging */
- int mId;
- /*! the particle position */
- ntlVec3Gfx mPos;
- /*! the particle velocity */
- ntlVec3Gfx mVel;
- /*! size / mass of particle */
- gfxReal mSize;
- /*! particle status */
- int mStatus;
- /*! count survived time steps */
- float mLifeTime;
-
- /* for list constructions */
- ParticleObject *mpNext;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ParticleObject")
-#endif
-};
-
-
-//! A whole particle array
-class ParticleTracer :
- public ntlGeometryObject
-{
- public:
- //! Standard constructor
- ParticleTracer();
- //! Destructor
- ~ParticleTracer();
-
- //! add a particle at this position
- void addParticle(float x, float y, float z);
- //! add/copy a particle from inited struct
- void addFullParticle(ParticleObject &np);
-
- //! draw the particle array
- void draw();
-
- //! parse settings from attributes (dont use own list!)
- void parseAttrList( AttributeList *att );
-
- //! adapt time step by rescaling velocities
- void adaptPartTimestep(float factor);
-
- // access funcs
-
- //! get the number of particles
- inline int getNumParticles() { return mParts.size(); }
- //! set/get the number of particles
- inline void setNumInitialParticles(int set) { mNumInitialParts=set; }
- inline int getNumInitialParticles() { return mNumInitialParts; }
-
- //! iterate over all newest particles (for advancing positions)
- inline vector<ParticleObject>::iterator getParticlesBegin() { return mParts.begin(); }
- //! end iterator for newest particles
- inline vector<ParticleObject>::iterator getParticlesEnd() { return mParts.end(); }
- //! end iterator for newest particles
- inline ParticleObject* getLast() { return &(mParts[ mParts.size()-1 ]); }
-
- /*! set geometry start (for renderer) */
- inline void setStart(ntlVec3Gfx set) { mStart = set; initTrafoMatrix(); }
- /*! set geometry end (for renderer) */
- inline void setEnd(ntlVec3Gfx set) { mEnd = set; initTrafoMatrix(); }
- /*! get values */
- inline ntlVec3Gfx getStart() { return mStart; }
- /*! set geometry end (for renderer) */
- inline ntlVec3Gfx getEnd() { return mEnd; }
-
- /*! set simulation domain start */
- inline void setSimStart(ntlVec3Gfx set) { mSimStart = set; initTrafoMatrix(); }
- /*! set simulation domain end */
- inline void setSimEnd(ntlVec3Gfx set) { mSimEnd = set; initTrafoMatrix(); }
-
- /*! set/get dump flag */
- inline void setDumpParts(bool set) { mDumpParts = set; }
- inline bool getDumpParts() { return mDumpParts; }
- /*! set/get dump text file */
- inline void setDumpTextFile(string set) { mDumpTextFile = set; }
- inline string getDumpTextFile() { return mDumpTextFile; }
- /*! set/get dump text interval */
- inline void setDumpTextInterval(float set) { mDumpTextInterval = set; }
- inline float getDumpTextInterval() { return mDumpTextInterval; }
- /*! set/get init times */
- inline void setInitStart(float set) { mInitStart = set; }
- inline float getInitStart() { return mInitStart; }
- inline void setInitEnd(float set) { mInitEnd = set; }
- inline float getInitEnd() { return mInitEnd; }
-
- //! set the particle scaling factor
- inline void setPartScale(float set) { mPartScale = set; }
-
- //! called after each frame to check if positions should be dumped
- void checkDumpTextPositions(double simtime);
-
- // NTL geometry implementation
- /*! Get the triangles from this object */
- virtual void getTriangles(double t, vector<ntlTriangle> *triangles,
- vector<ntlVec3Gfx> *vertices,
- vector<ntlVec3Gfx> *normals, int objectId );
-
- virtual void notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename,double simtime);
-
- // notify of next step for trails
- void checkTrails(double time);
- // free deleted particles
- void cleanup();
-
- protected:
-
- /*! the particle array (for multiple timesteps) */
- vector<ParticleObject> mParts;
-
- /*! size of the particles to display */
- float mPartSize;
-
- /*! start and end vectors for the triangulation region to create particles in */
- ntlVec3Gfx mStart, mEnd;
-
- /*! start and end vectors of the simulation domain */
- ntlVec3Gfx mSimStart, mSimEnd;
-
- /*! scaling param for particles */
- float mPartScale;
- /*! head and tail distance for particle shapes */
- float mPartHeadDist, mPartTailDist;
- /*! no of segments for particle cone */
- int mPartSegments;
- /*! use length/absval of values to scale particles? */
- int mValueScale;
- /*! value length maximal cutoff value, for mValueScale==2 */
- float mValueCutoffTop;
- /*! value length minimal cutoff value, for mValueScale==2 */
- float mValueCutoffBottom;
-
- /*! dump particles (or certain types of) to disk? */
- int mDumpParts;
- /*! text dump output file */
- string mDumpTextFile;
- /*! text dump interval, start at t=0, dumping active if >0 */
- float mDumpTextInterval;
- float mDumpTextLastTime;
- int mDumpTextCount;
- /*! show only a certain type (debugging) */
- int mShowOnly;
- /*! no. of particles to init */
- int mNumInitialParts;
-
- //! transform matrix
- ntlMatrix4x4<gfxReal> *mpTrafo;
- /*! init sim/pos transformation */
- void initTrafoMatrix();
-
- //! init time distribution start/end
- float mInitStart, mInitEnd;
-
- /*! the particle array (for multiple timesteps) */
- vector< vector<ParticleObject> > mPrevs;
- /* prev pos save interval */
- float mTrailTimeLast, mTrailInterval;
- int mTrailLength;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:ParticleTracer")
-#endif
-};
-
-#define NTL_PARTICLETRACER_H
-#endif
-
diff --git a/intern/elbeem/intern/simulation_object.cpp b/intern/elbeem/intern/simulation_object.cpp
deleted file mode 100644
index bba202300e9..00000000000
--- a/intern/elbeem/intern/simulation_object.cpp
+++ /dev/null
@@ -1,471 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Basic interface for all simulation modules
- *
- *****************************************************************************/
-
-#include "simulation_object.h"
-#include "solver_interface.h"
-#include "ntl_bsptree.h"
-#include "ntl_ray.h"
-#include "ntl_world.h"
-#include "solver_interface.h"
-#include "particletracer.h"
-#include "elbeem.h"
-
-#if PARALLEL==1
-#include <omp.h>
-#endif
-
-#ifdef _WIN32
-#else
-#include <sys/time.h>
-#endif
-
-
-//! lbm factory functions
-LbmSolverInterface* createSolver();
-
-/******************************************************************************
- * Constructor
- *****************************************************************************/
-SimulationObject::SimulationObject() :
- ntlGeometryShader(),
- mGeoStart(-100.0), mGeoEnd(100.0),
- mpGiTree(NULL), mpGiObjects(NULL),
- mpGlob(NULL),
- mPanic( false ),
- mDebugType( 1 /* =FLUIDDISPNothing*/ ),
- mpLbm(NULL), mpParam( NULL ),
- mShowSurface(true), mShowParticles(false),
- mSelectedCid( NULL ),
- mpElbeemSettings( NULL )
-
-{
- mpParam = new Parametrizer();
- //for(int i=0; i<MAX_DEBDISPSET; i++) { mDebDispSet[i].type = (i); mDebDispSet[i].on = false; mDebDispSet[i].scale = 1.0; }
-
- // reset time
- mTime = 0.0;
-}
-
-
-/******************************************************************************
- * Destructor
- *****************************************************************************/
-SimulationObject::~SimulationObject()
-{
- if(mpGiTree) delete mpGiTree;
- if(mpElbeemSettings) delete mpElbeemSettings;
- if(mpLbm) delete mpLbm;
- if(mpParam) delete mpParam;
- if(mpParts) delete mpParts;
- debMsgStd("SimulationObject",DM_MSG,"El'Beem Done!\n",10);
-}
-
-
-
-/*****************************************************************************/
-/*! init tree for certain geometry init */
-/*****************************************************************************/
-void SimulationObject::initGeoTree() {
- // unused!! overriden by solver interface
- if(mpGlob == NULL) {
- errFatal("SimulationObject::initGeoTree error","Requires globals!", SIMWORLD_INITERROR);
- return;
- }
- ntlScene *scene = mpGlob->getSimScene();
- mpGiObjects = scene->getObjects();
-
- if(mpGiTree != NULL) delete mpGiTree;
- char treeFlag = (1<<(mGeoInitId+4));
- mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here...
- scene, treeFlag );
- // unused!! overriden by solver interface
-}
-
-/*****************************************************************************/
-/*! destroy tree etc. when geometry init done */
-/*****************************************************************************/
-void SimulationObject::freeGeoTree() {
- if(mpGiTree != NULL) delete mpGiTree;
-}
-
-
-
-// copy & remember settings for later use
-void SimulationObject::copyElbeemSettings(elbeemSimulationSettings *settings) {
- mpElbeemSettings = new elbeemSimulationSettings;
- *mpElbeemSettings = *settings;
-
- mGeoInitId = settings->domainId+1;
- debMsgStd("SimulationObject",DM_MSG,"mGeoInitId="<<mGeoInitId<<", domainId="<<settings->domainId, 8);
-}
-
-/******************************************************************************
- * simluation interface: initialize simulation using the given configuration file
- *****************************************************************************/
-extern int glob_mpnum;
-int SimulationObject::initializeLbmSimulation(ntlRenderGlobals *glob)
-{
- if(! isSimworldOk() ) return 1;
-
- // already inited?
- if(mpLbm) return 0;
-
- mpGlob = glob;
- if(!getVisible()) {
- mpAttrs->setAllUsed();
- return 0;
- }
-
-
- mGeoInitId = mpAttrs->readInt("geoinitid", mGeoInitId,"LbmSolverInterface", "mGeoInitId", false);
- //mDimension, mSolverType are deprecated
- string mSolverType("");
- mSolverType = mpAttrs->readString("solver", mSolverType, "SimulationObject","mSolverType", false );
-
- mpLbm = createSolver();
- /* check lbm pointer */
- if(mpLbm == NULL) {
- errFatal("SimulationObject::initializeLbmSimulation","Unable to init LBM solver! ", SIMWORLD_INITERROR);
- return 2;
- }
- debMsgStd("SimulationObject::initialized",DM_MSG,"IdStr:"<<mpLbm->getIdString() <<" LBM solver! ", 2);
-
- mpParts = new ParticleTracer();
-
- // for non-param simulations
- mpLbm->setParametrizer( mpParam );
- mpParam->setAttrList( getAttributeList() );
- // not needed.. done in solver_init: mpParam->setSize ... in solver_interface
- mpParam->parseAttrList();
-
- mpLbm->setAttrList( getAttributeList() );
- mpLbm->setSwsAttrList( getSwsAttributeList() );
- mpLbm->parseAttrList();
- mpParts->parseAttrList( getAttributeList() );
-
- if(! isSimworldOk() ) return 3;
- mpParts->setName( getName() + "_part" );
- mpParts->initialize( glob );
- if(! isSimworldOk() ) return 4;
-
- // init material settings
- string matMc("default");
- matMc = mpAttrs->readString("material_surf", matMc, "SimulationObject","matMc", false );
- mShowSurface = mpAttrs->readInt("showsurface", mShowSurface, "SimulationObject","mShowSurface", false );
- mShowParticles = mpAttrs->readInt("showparticles", mShowParticles, "SimulationObject","mShowParticles", false );
-
- checkBoundingBox( mGeoStart, mGeoEnd, "SimulationObject::initializeSimulation" );
- mpLbm->setLbmInitId( mGeoInitId );
- mpLbm->setGeoStart( mGeoStart );
- mpLbm->setGeoEnd( mGeoEnd );
- mpLbm->setRenderGlobals( mpGlob );
- mpLbm->setName( getName() + "_lbm" );
- mpLbm->setParticleTracer( mpParts );
- if(mpElbeemSettings) {
- // set further settings from API struct init
- this->mOutFilename = string(mpElbeemSettings->outputPath);
- mpLbm->initDomainTrafo( mpElbeemSettings->surfaceTrafo );
- mpLbm->setSmoothing(1.0 * mpElbeemSettings->surfaceSmoothing, 1.0 * mpElbeemSettings->surfaceSmoothing);
- mpLbm->setIsoSubdivs(mpElbeemSettings->surfaceSubdivs);
-#if PARALLEL==1
- mpLbm->setNumOMPThreads(mpElbeemSettings->threads);
-#endif
- mpLbm->setSizeX(mpElbeemSettings->resolutionxyz);
- mpLbm->setSizeY(mpElbeemSettings->resolutionxyz);
- mpLbm->setSizeZ(mpElbeemSettings->resolutionxyz);
- mpLbm->setPreviewSize(mpElbeemSettings->previewresxyz);
- mpLbm->setRefinementDesired(mpElbeemSettings->maxRefine);
- mpLbm->setGenerateParticles(mpElbeemSettings->generateParticles);
- // set initial particles
- mpParts->setNumInitialParticles(mpElbeemSettings->numTracerParticles);
-
- // surface generation flag
- mpLbm->setSurfGenSettings(mpElbeemSettings->mFsSurfGenSetting);
-
- string dinitType = string("no");
- if (mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_PARTSLIP) dinitType = string("part");
- else if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_FREESLIP) dinitType = string("free");
- else /*if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_NOSLIP)*/ dinitType = string("no");
- mpLbm->setDomainBound(dinitType);
- mpLbm->setDomainPartSlip(mpElbeemSettings->domainobsPartslip);
- mpLbm->setDumpVelocities(mpElbeemSettings->generateVertexVectors);
- mpLbm->setFarFieldSize(mpElbeemSettings->farFieldSize);
- debMsgStd("SimulationObject::initialize",DM_MSG,"Added domain bound: "<<dinitType<<" ps="<<mpElbeemSettings->domainobsPartslip<<" vv"<<mpElbeemSettings->generateVertexVectors<<","<<mpLbm->getDumpVelocities(), 9 );
-
- debMsgStd("SimulationObject::initialize",DM_MSG,"Set ElbeemSettings values "<<mpLbm->getGenerateParticles(),10);
- }
-
- if(! mpLbm->initializeSolverMemory() ) { errMsg("SimulationObject::initialize","initializeSolverMemory failed"); mPanic=true; return 10; }
- if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverMemory status"); mPanic=true; return 11; }
- if(! mpLbm->initializeSolverGrids() ) { errMsg("SimulationObject::initialize","initializeSolverGrids failed"); mPanic=true; return 12; }
- if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverGrids status"); mPanic=true; return 13; }
- if(! mpLbm->initializeSolverPostinit() ) { errMsg("SimulationObject::initialize","initializeSolverPostin failed"); mPanic=true; return 14; }
- if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverPostin status"); mPanic=true; return 15; }
-
- // print cell type stats
- bool printStats = true;
- if(glob_mpnum>0) printStats=false; // skip in this case
- if(printStats) {
- const int jmax = sizeof(CellFlagType)*8;
- int totalCells = 0;
- int flagCount[jmax];
- for(int j=0; j<jmax ; j++) flagCount[j] = 0;
- int diffInits = 0;
- LbmSolverInterface::CellIdentifier cid = mpLbm->getFirstCell();
- for(; mpLbm->noEndCell( cid );
- mpLbm->advanceCell( cid ) ) {
- int flag = mpLbm->getCellFlag(cid,0);
- int flag2 = mpLbm->getCellFlag(cid,1);
- if(flag != flag2) {
- diffInits++;
- }
- for(int j=0; j<jmax ; j++) {
- if( flag&(1<<j) ) flagCount[j]++;
- }
- totalCells++;
- }
- mpLbm->deleteCellIterator( &cid );
-
- char charNl = '\n';
- debugOutNnl("SimulationObject::initializeLbmSimulation celltype stats: " <<charNl, 5);
- debugOutNnl("no. of cells = "<<totalCells<<", "<<charNl ,5);
- for(int j=0; j<jmax ; j++) {
- std::ostringstream out;
- if(flagCount[j]>0) {
- out<<"\t" << flagCount[j] <<" x "<< convertCellFlagType2String( (CellFlagType)(1<<j) ) <<", " << charNl;
- debugOutNnl(out.str(), 5);
- }
- }
- // compute dist. of empty/bnd - fluid - if
- // cfEmpty = (1<<0), cfBnd = (1<< 2), cfFluid = (1<<10), cfInter = (1<<11),
- if(1){
- std::ostringstream out;
- out.precision(2); out.width(4);
- int totNum = flagCount[1]+flagCount[2]+flagCount[7]+flagCount[8];
- double ebFrac = (double)(flagCount[1]+flagCount[2]) / totNum;
- double flFrac = (double)(flagCount[7]) / totNum;
- double ifFrac = (double)(flagCount[8]) / totNum;
- //???
- out<<"\tFractions: [empty/bnd - fluid - interface - ext. if] = [" << ebFrac<<" - " << flFrac<<" - " << ifFrac<<"] "<< charNl;
-
- if(diffInits > 0) {
- debMsgStd("SimulationObject::initializeLbmSimulation",DM_MSG,"celltype Warning: Diffinits="<<diffInits<<"!" , 5);
- }
- debugOutNnl(out.str(), 5);
- }
- } // cellstats
-
- // might be modified by mpLbm
- //mpParts->setStart( mGeoStart );? mpParts->setEnd( mGeoEnd );?
- mpParts->setStart( mpLbm->getGeoStart() );
- mpParts->setEnd( mpLbm->getGeoEnd() );
- mpParts->setCastShadows( false );
- mpParts->setReceiveShadows( false );
- mpParts->searchMaterial( glob->getMaterials() );
-
- // this has to be inited here - before, the values might be unknown
- IsoSurface *surf = mpLbm->getSurfaceGeoObj();
- if(surf) {
- surf->setName( "final" ); // final surface mesh
- // warning - this might cause overwriting effects for multiple sims and geom dump...
- surf->setCastShadows( true );
- surf->setReceiveShadows( false );
- surf->searchMaterial( glob->getMaterials() );
- if(mShowSurface) mObjects.push_back( surf );
- }
-
-#ifdef ELBEEM_PLUGIN
- mShowParticles=1; // for e.g. dumping
-#endif // ELBEEM_PLUGIN
- if((mpLbm->getGenerateParticles()>0.0)||(mpParts->getNumInitialParticles()>0)) {
- mShowParticles=1;
- mpParts->setDumpParts(true);
- }
- //debMsgStd("SimulationObject::init",DM_NOTIFY,"Using envvar ELBEEM_DUMPPARTICLE to set mShowParticles, DEBUG!",1);
- //} // DEBUG ENABLE!!!!!!!!!!
- if(mShowParticles) {
- mObjects.push_back(mpParts);
- }
-
- // add objects to display for debugging (e.g. levelset particles)
- vector<ntlGeometryObject *> debugObjs = mpLbm->getDebugObjects();
- for(size_t i=0;i<debugObjs.size(); i++) {
- debugObjs[i]->setCastShadows( false );
- debugObjs[i]->setReceiveShadows( false );
- debugObjs[i]->searchMaterial( glob->getMaterials() );
- mObjects.push_back( debugObjs[i] );
- debMsgStd("SimulationObject::init",DM_NOTIFY,"Added debug obj "<<debugObjs[i]->getName(), 10 );
- }
- return 0;
-}
-
-/*! set current frame */
-void SimulationObject::setFrameNum(int num) {
- // advance parametrizer
- mpParam->setFrameNum(num);
-}
-
-/******************************************************************************
- * simluation interface: advance simulation another step (whatever delta time that might be)
- *****************************************************************************/
-void SimulationObject::step( void )
-{
- if(mpParam->getCurrentAniFrameTime()>0.0) {
- // dont advance for stopped time
- mpLbm->step();
- mTime += mpParam->getTimestep();
- //if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); xit(1); } // PROFILE DEBUG TEST!
- }
- if(mpLbm->getPanic()) mPanic = true;
-
- checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0);
- //if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) {
- //int ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, FLUIDSIM_CBSTATUS_STEP, 0);
- //errMsg("runSimulationCallback cbtest1"," "<<this->getName()<<" ret="<<ret);
- //}
- //debMsgStd("SimulationObject::step",DM_MSG," Sim '"<<mName<<"' stepped to "<<mTime<<" (stept="<<(mpParam->getTimestep())<<", framet="<<getFrameTime()<<") ", 10);
-}
-/*! prepare visualization of simulation for e.g. raytracing */
-void SimulationObject::prepareVisualization( void ) {
- if(mPanic) return;
- mpLbm->prepareVisualization();
-}
-
-
-/******************************************************************************/
-/* get current start simulation time */
-double SimulationObject::getStartTime( void ) {
- //return mpParam->calculateAniStart();
- return mpParam->getAniStart();
-}
-/* get time for a single animation frame */
-double SimulationObject::getFrameTime( int frame ) {
- return mpParam->getAniFrameTime(frame);
-}
-/* get time for a single time step */
-double SimulationObject::getTimestep( void ) {
- return mpParam->getTimestep();
-}
-
-
-/******************************************************************************
- * return a pointer to the geometry object of this simulation
- *****************************************************************************/
-//ntlGeometryObject *SimulationObject::getGeometry() { return mpMC; }
-vector<ntlGeometryObject *>::iterator
-SimulationObject::getObjectsBegin()
-{
- return mObjects.begin();
-}
-vector<ntlGeometryObject *>::iterator
-SimulationObject::getObjectsEnd()
-{
- return mObjects.end();
-}
-
-
-
-
-
-/******************************************************************************
- * GUI - display debug info
- *****************************************************************************/
-
-void SimulationObject::drawDebugDisplay() {
-#ifndef NOGUI
- if(!getVisible()) return;
-
- //if( mDebugType > (MAX_DEBDISPSET-1) ){ errFatal("SimulationObject::drawDebugDisplay","Invalid debug type!", SIMWORLD_GENERICERROR); return; }
- //mDebDispSet[ mDebugType ].on = true;
- //errorOut( mDebugType <<"//"<< mDebDispSet[mDebugType].type );
- mpLbm->debugDisplay( mDebugType );
-
- //::lbmMarkedCellDisplay<>( mpLbm );
- mpLbm->lbmMarkedCellDisplay();
-#endif
-}
-
-/* GUI - display interactive info */
-void SimulationObject::drawInteractiveDisplay()
-{
-#ifndef NOGUI
- if(!getVisible()) return;
- if(mSelectedCid) {
- // in debugDisplayNode if dispset is on is ignored...
- mpLbm->debugDisplayNode( FLUIDDISPGrid, mSelectedCid );
- }
-#endif
-}
-
-
-/*******************************************************************************/
-// GUI - handle mouse movement for selection
-/*******************************************************************************/
-void SimulationObject::setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir)
-{
- normalize( dir );
- // assume 2D sim is in XY plane...
-
- double zplane = (mGeoEnd[2]-mGeoStart[2])*0.5;
- double zt = (zplane-org[2]) / dir[2];
- ntlVec3Gfx pos(
- org[0]+ dir[0] * zt,
- org[1]+ dir[1] * zt, 0.0);
-
- mSelectedCid = mpLbm->getCellAt( pos );
- //errMsg("SMP ", mName<< x<<" "<<y<<" - "<<dir );
- x = y = 0; // remove warning
-}
-
-
-void SimulationObject::setMouseClick()
-{
- if(mSelectedCid) {
- //::debugPrintNodeInfo<>( mpLbm, mSelectedCid, mpLbm->getNodeInfoString() );
- mpLbm->debugPrintNodeInfo( mSelectedCid );
- }
-}
-
-/*! notify object that dump is in progress (e.g. for field dump) */
-void SimulationObject::notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) {
- if(!mpLbm) return;
-
- mpLbm->notifySolverOfDump(dumptype, frameNr,frameNrStr,outfilename);
- checkCallerStatus(FLUIDSIM_CBSTATUS_NEWFRAME, frameNr);
-}
-
-/*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */
-int SimulationObject::checkCallerStatus(int status, int frame) {
- //return 0; // DEBUG
- int ret = 0;
- if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) {
- ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, status,frame);
- if(ret!=FLUIDSIM_CBRET_CONTINUE) {
- if(ret==FLUIDSIM_CBRET_STOP) {
- debMsgStd("SimulationObject::notifySolverOfDump",DM_NOTIFY,"Got stop signal from caller",1);
- setElbeemState( SIMWORLD_STOP );
- }
- else if(ret==FLUIDSIM_CBRET_ABORT) {
- errFatal("SimulationObject::notifySolverOfDump","Got abort signal from caller, aborting...", SIMWORLD_GENERICERROR );
- mPanic = 1;
- }
- else {
- errMsg("SimulationObject::notifySolverOfDump","Invalid callback return value: "<<ret<<", ignoring... ");
- }
- }
- }
-
- //debMsgStd("SimulationObject::checkCallerStatus",DM_MSG, "s="<<status<<",f="<<frame<<" "<<this->getName()<<" ret="<<ret);
- if(isSimworldOk()) return 0;
- return 1;
-}
-
diff --git a/intern/elbeem/intern/simulation_object.h b/intern/elbeem/intern/simulation_object.h
deleted file mode 100644
index b35482f2098..00000000000
--- a/intern/elbeem/intern/simulation_object.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Basic interface for all simulation modules
- *
- *****************************************************************************/
-
-#ifndef SIMULATION_OBJECT_H
-#define SIMULATION_OBJECT_H
-
-
-#define USE_GLUTILITIES
-#include "ntl_geometryshader.h"
-#include "parametrizer.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class LbmSolverInterface;
-class CellIdentifierInterface;
-class ntlTree;
-class ntlRenderGlobals;
-class ntlRenderGlobals;
-class ParticleTracer;
-struct elbeemSimulationSettings;
-
-
-//! type fluid geometry init
-// warning : should match typeslbm.h values!
-const int cFgiFlagstart = 16;
-typedef enum {
- fgiFluid = (1<<(cFgiFlagstart+0)),
- fgiNoFluid = (1<<(cFgiFlagstart+1)),
- fgiSlipNo = (1<<(cFgiFlagstart+2)),
- fgiSlipFree = (1<<(cFgiFlagstart+3)),
- fgiNoBnd = (1<<(cFgiFlagstart+4)),
- fgiAcc = (1<<(cFgiFlagstart+5)),
- fgiNoAcc = (1<<(cFgiFlagstart+6)),
-
- fgiBndAll = (fgiSlipNo | fgiSlipFree)
-} FgiFlagType;
-
-
-/*! interface for different simluation models to visualize */
-class SimulationObject :
- public ntlGeometryShader {
-
- public:
-
- /*! Constructor */
- SimulationObject();
- /*! Destructor */
- virtual ~SimulationObject();
- /*! for init from API */
- void copyElbeemSettings(elbeemSimulationSettings *settings);
-
-
- /*! init tree for certain geometry init */
- void initGeoTree();
- /*! destroy tree etc. when geometry init done */
- void freeGeoTree();
- /*! get fluid init type at certain position */
- int geoInitGetPointType(ntlVec3Gfx org, int &OId);
- /*! check for a certain flag type at position org */
- bool geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId);
-
- // access functions
-
- /*! get current (max) simulation time */
- double getCurrentTime( void ) { return mTime; }
- /*! set geometry generation start point */
- virtual void setGeoStart(ntlVec3Gfx set) { mGeoStart = set; }
- /*! set geometry generation end point */
- virtual void setGeoEnd(ntlVec3Gfx set) { mGeoEnd = set; }
-
- /*! set sim panic flag */
- void setPanic(bool set) { mPanic = set; }
- /*! get sim panic flag */
- bool getPanic( void ) { return mPanic; }
-
- /*! simluation interface: initialize simulation */
- int initializeLbmSimulation(ntlRenderGlobals *glob);
-
- /*! set current frame */
- void setFrameNum(int num);
-
- /*! Do geo etc. init */
- virtual int postGeoConstrInit(ntlRenderGlobals *glob) { return initializeLbmSimulation(glob); };
- virtual int initializeShader() { /* ... */ return true; };
- /*! notify object that dump is in progress (e.g. for field dump) */
- virtual void notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename);
- /*! simluation interface: draw the simulation with OpenGL */
- virtual void draw( void ) {};
- virtual vector<ntlGeometryObject *>::iterator getObjectsBegin();
- virtual vector<ntlGeometryObject *>::iterator getObjectsEnd();
-
-
- /*! simluation interface: advance simulation another step (whatever delta time that might be) */
- virtual void step( void );
- /*! prepare visualization of simulation for e.g. raytracing */
- virtual void prepareVisualization( void );
-
- /*! GUI - display debug info */
- virtual void drawDebugDisplay();
- /*! GUI - display interactive info */
- virtual void drawInteractiveDisplay();
- /*! GUI - handle mouse movement for selection */
- virtual void setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir);
- virtual void setMouseClick();
-
- /*! get current start simulation time */
- double getStartTime( void );
- /*! get time for a single animation frame */
- double getFrameTime( int frame );
- /*! get time for a single time step in the simulation */
- double getTimestep( void );
-
- //! access solver
- LbmSolverInterface *getSolver(){ return mpLbm; }
-
- protected:
-
- /*! current time in the simulation */
- double mTime;
-
- /*! for display - start and end vectors for geometry */
- ntlVec3Gfx mGeoStart, mGeoEnd;
-
- /*! geometry init id */
- //? int mGeoInitId;
- /*! tree object for geomerty initialization */
- ntlTree *mpGiTree;
- /*! object vector for geo init */
- vector<ntlGeometryObject*> *mpGiObjects;
- /*! remember globals */
- ntlRenderGlobals *mpGlob;
-
- /*! simulation panic on/off */
- bool mPanic;
-
- /*! debug info to display */
- int mDebugType;
-
- /*! pointer to the lbm solver */
- LbmSolverInterface *mpLbm;
-
- /*! parametrizer for lbm solver */
- Parametrizer *mpParam;
-
- /*! particle tracing object */
- ParticleTracer *mpParts;
-
- /*! show parts of the simulation toggles */
- bool mShowSurface;
- bool mShowParticles;
-
- /*! debug display settings */
- int mDebDispSetting;
-
- /*! pointer to identifier of selected node */
- CellIdentifierInterface *mSelectedCid;
-
- /*! storage of API settings */
- elbeemSimulationSettings *mpElbeemSettings;
-
- public:
-
- // debug display setting funtions
-
- /*! set type of info to display */
- inline void setDebugDisplay(int disp) { mDebugType = disp; }
- inline int getDebugDisplay() { return mDebugType; }
-
- /* miscelleanous access functions */
-
- /*! init parametrizer for anim step length */
- void initParametrizer(Parametrizer *set) { mpParam = set; }
- /*! init parametrizer for anim step length */
- Parametrizer *getParametrizer() { return mpParam; }
-
- /*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */
- // parameters same as elbeem runsimCallback
- int checkCallerStatus(int status, int frame);
-
- /*! get bounding box of fluid for GUI */
- virtual inline ntlVec3Gfx *getBBStart() { return &mGeoStart; }
- virtual inline ntlVec3Gfx *getBBEnd() { return &mGeoEnd; }
-
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:SimulationObject")
-#endif
-};
-
-
-#endif
-
-
-
diff --git a/intern/elbeem/intern/solver_adap.cpp b/intern/elbeem/intern/solver_adap.cpp
deleted file mode 100644
index 9e5619ca4a5..00000000000
--- a/intern/elbeem/intern/solver_adap.cpp
+++ /dev/null
@@ -1,1281 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Adaptivity functions
- *
- *****************************************************************************/
-
-#include "solver_class.h"
-#include "solver_relax.h"
-#include "particletracer.h"
-
-#include <cmath>
-
-using std::isfinite;
-
-/*****************************************************************************/
-//! coarse step functions
-/*****************************************************************************/
-
-
-
-void LbmFsgrSolver::coarseCalculateFluxareas(int lev)
-{
- FSGR_FORIJK_BOUNDS(lev) {
- if( RFLAG(lev, i,j,k,mLevel[lev].setCurr) & CFFluid) {
- if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & CFGrFromCoarse) {
- LbmFloat totArea = mFsgrCellArea[0]; // for l=0
- for(int l=1; l<this->cDirNum; l++) {
- int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l];
- if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)&
- (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
- ) {
- totArea += mFsgrCellArea[l];
- }
- } // l
- QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = totArea;
- //continue;
- } else
- if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & (CFEmpty|CFUnused)) {
- QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 1.0;
- //continue;
- } else {
- QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 0.0;
- }
- //errMsg("DFINI"," at l"<<lev<<" "<<PRINT_IJK<<" v:"<<QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) );
- }
- } // } TEST DEBUG
- if(!this->mSilent){ debMsgStd("coarseCalculateFluxareas",DM_MSG,"level "<<lev<<" calculated", 7); }
-}
-
-void LbmFsgrSolver::coarseAdvance(int lev)
-{
- LbmFloat calcCurrentMass = 0.0;
- LbmFloat calcCurrentVolume = 0.0;
-
- LbmFloat *ccel = NULL;
- LbmFloat *tcel = NULL;
- LbmFloat m[LBM_DFNUM];
- LbmFloat rho, ux, uy, uz, tmp, usqr, lcsmqo;
-#if OPT3D==1
- LbmFloat lcsmqadd, lcsmeq[LBM_DFNUM], lcsmomega;
-#endif // OPT3D==true
- m[0] = tmp = usqr = 0.0;
-
- coarseCalculateFluxareas(lev);
- // copied from fineAdv.
- CellFlagType *pFlagSrc = &RFLAG(lev, 1,1,getForZMin1(),SRCS(lev));
- CellFlagType *pFlagDst = &RFLAG(lev, 1,1,getForZMin1(),TSET(lev));
- pFlagSrc -= 1;
- pFlagDst -= 1;
- ccel = RACPNT(lev, 1,1,getForZMin1() ,SRCS(lev)); // QTEST
- ccel -= QCELLSTEP;
- tcel = RACPNT(lev, 1,1,getForZMin1() ,TSET(lev)); // QTEST
- tcel -= QCELLSTEP;
- //if(strstr(this->getName().c_str(),"Debug")){ errMsg("DEBUG","DEBUG!!!!!!!!!!!!!!!!!!!!!!!"); }
-
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
-#if FSGR_STRICT_DEBUG==1
- rho = ux = uy = uz = tmp = usqr = -100.0; // DEBUG
-#endif
- pFlagSrc++;
- pFlagDst++;
- ccel += QCELLSTEP;
- tcel += QCELLSTEP;
-
- // from coarse cells without unused nbs are not necessary...! -> remove
- if( ((*pFlagSrc) & (CFGrFromCoarse)) ) {
- bool invNb = false;
- FORDF1 { if(RFLAG_NB(lev, i, j, k, SRCS(lev), l) & CFUnused) { invNb = true; } }
- if(!invNb) {
- // WARNING - this modifies source flag array...
- *pFlagSrc = CFFluid|CFGrNorm;
-#if ELBEEM_PLUGIN!=1
- errMsg("coarseAdvance","FC2NRM_CHECK Converted CFGrFromCoarse to Norm at "<<lev<<" "<<PRINT_IJK);
-#endif // ELBEEM_PLUGIN!=1
- // move to perform coarsening?
- }
- } // */
-
-#if FSGR_STRICT_DEBUG==1
- *pFlagDst = *pFlagSrc; // always set other set...
-#else
- *pFlagDst = (*pFlagSrc & (~CFGrCoarseInited)); // always set other set... , remove coarse inited flag
-#endif
-
- // old INTCFCOARSETEST==1
- if((*pFlagSrc) & CFGrFromCoarse) { // interpolateFineFromCoarse test!
- if(( this->mStepCnt & (1<<(mMaxRefine-lev)) ) ==1) {
- FORDF0 { RAC(tcel,l) = RAC(ccel,l); }
- } else {
- interpolateCellFromCoarse( lev, i,j,k, TSET(lev), 0.0, CFFluid|CFGrFromCoarse, false);
- this->mNumUsedCells++;
- }
- continue; // interpolateFineFromCoarse test!
- } // interpolateFineFromCoarse test! old INTCFCOARSETEST==1
-
- if( ((*pFlagSrc) & (CFFluid)) ) {
- ccel = RACPNT(lev, i,j,k ,SRCS(lev));
- tcel = RACPNT(lev, i,j,k ,TSET(lev));
-
- if( ((*pFlagSrc) & (CFGrFromFine)) ) {
- FORDF0 { RAC(tcel,l) = RAC(ccel,l); } // always copy...?
- continue; // comes from fine grid
- }
- // also ignore CFGrFromCoarse
- else if( ((*pFlagSrc) & (CFGrFromCoarse)) ) {
- FORDF0 { RAC(tcel,l) = RAC(ccel,l); } // always copy...?
- continue;
- }
-
- OPTIMIZED_STREAMCOLLIDE;
- *pFlagDst |= CFNoBndFluid; // test?
- calcCurrentVolume += RAC(ccel,dFlux);
- calcCurrentMass += RAC(ccel,dFlux)*rho;
- //ebugMarkCell(lev+1, 2*i+1,2*j+1,2*k );
-#if FSGR_STRICT_DEBUG==1
- if(rho<-1.0){ debugMarkCell(lev, i,j,k );
- errMsg("INVRHOCELL_CHECK"," l"<<lev<<" "<< PRINT_IJK<<" rho:"<<rho );
- CAUSE_PANIC;
- }
-#endif // FSGR_STRICT_DEBUG==1
- this->mNumUsedCells++;
-
- }
- }
- pFlagSrc+=2; // after x
- pFlagDst+=2; // after x
- ccel += (QCELLSTEP*2);
- tcel += (QCELLSTEP*2);
- }
- pFlagSrc+= mLevel[lev].lSizex*2; // after y
- pFlagDst+= mLevel[lev].lSizex*2; // after y
- ccel += (QCELLSTEP*mLevel[lev].lSizex*2);
- tcel += (QCELLSTEP*mLevel[lev].lSizex*2);
- } // all cell loop k,j,i
-
-
- //errMsg("coarseAdvance","level "<<lev<<" stepped from "<<mLevel[lev].setCurr<<" to "<<mLevel[lev].setOther);
- if(!this->mSilent){ errMsg("coarseAdvance","level "<<lev<<" stepped from "<<SRCS(lev)<<" to "<<TSET(lev)); }
- // */
-
- // update other set
- mLevel[lev].setOther = mLevel[lev].setCurr;
- mLevel[lev].setCurr ^= 1;
- mLevel[lev].lsteps++;
- mLevel[lev].lmass = calcCurrentMass * mLevel[lev].lcellfactor;
- mLevel[lev].lvolume = calcCurrentVolume * mLevel[lev].lcellfactor;
-#if ELBEEM_PLUGIN!=1
- debMsgStd("LbmFsgrSolver::coarseAdvance",DM_NOTIFY, "mass: lev="<<lev<<" m="<<mLevel[lev].lmass<<" c="<<calcCurrentMass<<" lcf="<< mLevel[lev].lcellfactor, 8 );
- debMsgStd("LbmFsgrSolver::coarseAdvance",DM_NOTIFY, "volume: lev="<<lev<<" v="<<mLevel[lev].lvolume<<" c="<<calcCurrentVolume<<" lcf="<< mLevel[lev].lcellfactor, 8 );
-#endif // ELBEEM_PLUGIN
-}
-
-/*****************************************************************************/
-//! multi level functions
-/*****************************************************************************/
-
-
-// get dfs from level (lev+1) to (lev) coarse border nodes
-void LbmFsgrSolver::coarseRestrictFromFine(int lev)
-{
- if((lev<0) || ((lev+1)>mMaxRefine)) return;
-#if FSGR_STRICT_DEBUG==1
- // reset all unused cell values to invalid
- int unuCnt = 0;
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
- CellFlagType *pFlagSrc = &RFLAG(lev, i,j,k,mLevel[lev].setCurr);
- if( ((*pFlagSrc) & (CFFluid|CFGrFromFine)) == (CFFluid|CFGrFromFine) ) {
- FORDF0{ QCELL(lev, i,j,k,mLevel[lev].setCurr, l) = -10000.0; }
- unuCnt++;
- // set here
- } else if( ((*pFlagSrc) & (CFFluid|CFGrNorm)) == (CFFluid|CFGrNorm) ) {
- // simulated...
- } else {
- // reset in interpolation
- //errMsg("coarseRestrictFromFine"," reset l"<<lev<<" "<<PRINT_IJK);
- }
- if( ((*pFlagSrc) & (CFEmpty|CFUnused)) ) { // test, also reset?
- FORDF0{ QCELL(lev, i,j,k,mLevel[lev].setCurr, l) = -10000.0; }
- } // test
- } } }
- errMsg("coarseRestrictFromFine"," reset l"<<lev<<" fluid|coarseBorder cells: "<<unuCnt);
-#endif // FSGR_STRICT_DEBUG==1
- const int srcSet = mLevel[lev+1].setCurr;
- const int dstSet = mLevel[lev].setCurr;
-
- //restrict
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
- CellFlagType *pFlagSrc = &RFLAG(lev, i,j,k,dstSet);
- if((*pFlagSrc) & (CFFluid)) {
- if( ((*pFlagSrc) & (CFFluid|CFGrFromFine)) == (CFFluid|CFGrFromFine) ) {
- // do resctriction
- mNumInterdCells++;
- coarseRestrictCell(lev, i,j,k,srcSet,dstSet);
-
- this->mNumUsedCells++;
- } // from fine & fluid
- else {
- if(RFLAG(lev+1, 2*i,2*j,2*k,srcSet) & CFGrFromCoarse) {
- RFLAG(lev, i,j,k,dstSet) |= CFGrToFine;
- } else {
- RFLAG(lev, i,j,k,dstSet) &= (~CFGrToFine);
- }
- }
- } // & fluid
- }}}
- if(!this->mSilent){ errMsg("coarseRestrictFromFine"," from l"<<(lev+1)<<",s"<<mLevel[lev+1].setCurr<<" to l"<<lev<<",s"<<mLevel[lev].setCurr); }
-}
-
-bool LbmFsgrSolver::adaptGrid(int lev) {
- if((lev<0) || ((lev+1)>mMaxRefine)) return false;
- bool change = false;
- { // refinement, PASS 1-3
-
- //bool nbsok;
- // FIXME remove TIMEINTORDER ?
- LbmFloat interTime = 0.0;
- // update curr from other, as streaming afterwards works on curr
- // thus read only from srcSet, modify other
- const int srcSet = mLevel[lev].setOther;
- const int dstSet = mLevel[lev].setCurr;
- const int srcFineSet = mLevel[lev+1].setCurr;
- const bool debugRefinement = false;
-
- // use //template functions for 2D/3D
- /*if(strstr(this->getName().c_str(),"Debug"))
- if(lev+1==mMaxRefine) { // mixborder
- for(int l=0;((l<this->cDirNum) && (!removeFromFine)); l++) { // FARBORD
- int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l];
- if(RFLAG(lev+1, ni,nj,nk, srcFineSet)&CFBnd) { // NEWREFT
- removeFromFine=true;
- }
- }
- } // FARBORD */
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
-
- if(RFLAG(lev, i,j,k, srcSet) & CFGrFromFine) {
- bool removeFromFine = false;
- const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine);
- CellFlagType reqType = CFGrNorm;
- if(lev+1==mMaxRefine) reqType = CFNoBndFluid;
-
- if( (RFLAG(lev+1, (2*i),(2*j),(2*k), srcFineSet) & reqType) &&
- (!(RFLAG(lev+1, (2*i),(2*j),(2*k), srcFineSet) & (notAllowed)) ) ){ // ok
- } else {
- removeFromFine=true;
- }
-
- if(removeFromFine) {
- // dont turn CFGrFromFine above interface cells into CFGrNorm
- //errMsg("performRefinement","Removing CFGrFromFine on lev"<<lev<<" " <<PRINT_IJK<<" srcflag:"<<convertCellFlagType2String(RFLAG(lev+1, (2*i),(2*j),(2*k), srcFineSet)) <<" set:"<<dstSet );
- RFLAG(lev, i,j,k, dstSet) = CFEmpty;
-#if FSGR_STRICT_DEBUG==1
- // for interpolation later on during fine grid fixing
- // these cells are still correctly inited
- RFLAG(lev, i,j,k, dstSet) |= CFGrCoarseInited; // remove later on? FIXME?
-#endif // FSGR_STRICT_DEBUG==1
- //RFLAG(lev, i,j,k, mLevel[lev].setOther) = CFEmpty; // FLAGTEST
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,i,j,k);
- change=true;
- mNumFsgrChanges++;
- for(int l=1; l<this->cDirNum; l++) {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- //errMsg("performRefinement","On lev:"<<lev<<" check: "<<PRINT_VEC(ni,nj,nk)<<" set:"<<dstSet<<" = "<<convertCellFlagType2String(RFLAG(lev, ni,nj,nk, srcSet)) );
- if( ( RFLAG(lev, ni,nj,nk, srcSet)&CFFluid ) &&
- (!(RFLAG(lev, ni,nj,nk, srcSet)&CFGrFromFine)) ) { // dont change status of nb. from fine cells
- // tag as inited for debugging, cell contains fluid DFs anyway
- RFLAG(lev, ni,nj,nk, dstSet) = CFFluid|CFGrFromFine|CFGrCoarseInited;
- //errMsg("performRefinement","On lev:"<<lev<<" set to from fine: "<<PRINT_VEC(ni,nj,nk)<<" set:"<<dstSet);
- //if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,ni,nj,nk);
- }
- } // l
-
- // FIXME fix fine level?
- }
-
- // recheck from fine flag
- }
- }}} // TEST
- // PASS 1 */
-
-
- /*if( ((*pFlagSrc) & (CFGrFromCoarse)) ) {
- bool invNb = false;
- FORDF1 {
- if(RFLAG_NB(lev, i, j, k, SRCS(lev), l) & CFUnused) { invNb = true; }
- }
- if(!invNb) {
- *pFlagSrc = CFFluid|CFGrNorm;
- errMsg("coarseAdvance","FC2NRM_CHECK Converted CFGrFromCoarse to Norm at "<<lev<<" "<<PRINT_IJK);
- }
- } // */
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { // TEST
- for(int j=1;j<mLevel[lev].lSizey-1;++j) { // TEST
- for(int i=1;i<mLevel[lev].lSizex-1;++i) { // TEST
-
- // test from coarseAdvance
- // from coarse cells without unused nbs are not necessary...! -> remove
-
- if(RFLAG(lev, i,j,k, srcSet) & CFGrFromCoarse) {
-
- // from coarse cells without unused nbs are not necessary...! -> remove
- bool invNb = false;
- bool fluidNb = false;
- for(int l=1; l<this->cDirNum; l++) {
- if(RFLAG_NB(lev, i, j, k, srcSet, l) & CFUnused) { invNb = true; }
- if(RFLAG_NB(lev, i, j, k, srcSet, l) & (CFGrNorm)) { fluidNb = true; }
- }
- if(!invNb) {
- // no unused cells around -> calculate normally from now on
- RFLAG(lev, i,j,k, dstSet) = CFFluid|CFGrNorm;
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k);
- change=true;
- mNumFsgrChanges++;
- } // from advance
- if(!fluidNb) {
- // no fluid cells near -> no transfer necessary
- RFLAG(lev, i,j,k, dstSet) = CFUnused;
- //RFLAG(lev, i,j,k, mLevel[lev].setOther) = CFUnused; // FLAGTEST
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k);
- change=true;
- mNumFsgrChanges++;
- } // from advance
-
-
- // dont allow double transfer
- // this might require fixing the neighborhood
- if(RFLAG(lev+1, 2*i,2*j,2*k, srcFineSet)&(CFGrFromCoarse)) {
- // dont turn CFGrFromFine above interface cells into CFGrNorm
- //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<<lev<<" " <<PRINT_IJK<<" due to finer from coarse cell " );
- RFLAG(lev, i,j,k, dstSet) = CFFluid|CFGrNorm;
- if(lev>0) RFLAG(lev-1, i/2,j/2,k/2, mLevel[lev-1].setCurr) &= (~CFGrToFine); // TODO add more of these?
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k);
- change=true;
- mNumFsgrChanges++;
- for(int l=1; l<this->cDirNum; l++) {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if(RFLAG(lev, ni,nj,nk, srcSet)&(CFGrNorm)) { //ok
- for(int m=1; m<this->cDirNum; m++) {
- int mi= ni +this->dfVecX[m], mj= nj +this->dfVecY[m], mk= nk +this->dfVecZ[m];
- if(RFLAG(lev, mi, mj, mk, srcSet)&CFUnused) {
- // norm cells in neighborhood with unused nbs have to be new border...
- RFLAG(lev, ni,nj,nk, dstSet) = CFFluid|CFGrFromCoarse;
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,ni,nj,nk);
- }
- }
- // these alreay have valid values...
- }
- else if(RFLAG(lev, ni,nj,nk, srcSet)&(CFUnused)) { //ok
- // this should work because we have a valid neighborhood here for now
- interpolateCellFromCoarse(lev, ni, nj, nk, dstSet, interTime, CFFluid|CFGrFromCoarse, false);
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,ni,nj,nk);
- mNumFsgrChanges++;
- }
- } // l
- } // double transer
-
- } // from coarse
-
- } } }
- // PASS 2 */
-
-
- // fix dstSet from fine cells here
- // warning - checks CFGrFromFine on dstset changed before!
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { // TEST
- for(int j=1;j<mLevel[lev].lSizey-1;++j) { // TEST
- for(int i=1;i<mLevel[lev].lSizex-1;++i) { // TEST
-
- //if(RFLAG(lev, i,j,k, srcSet) & CFGrFromFine) {
- if(RFLAG(lev, i,j,k, dstSet) & CFGrFromFine) {
- // modify finer level border
- if((RFLAG(lev+1, 2*i,2*j,2*k, srcFineSet)&(CFGrFromCoarse))) {
- //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<<(lev+1)<<" from l"<<lev<<" " <<PRINT_IJK );
- CellFlagType setf = CFFluid;
- if(lev+1 < mMaxRefine) setf = CFFluid|CFGrNorm;
- RFLAG(lev+1, 2*i,2*j,2*k, srcFineSet)=setf;
- change=true;
- mNumFsgrChanges++;
- for(int l=1; l<this->cDirNum; l++) {
- int bi=(2*i)+this->dfVecX[l], bj=(2*j)+this->dfVecY[l], bk=(2*k)+this->dfVecZ[l];
- if(RFLAG(lev+1, bi, bj, bk, srcFineSet)&(CFGrFromCoarse)) {
- //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<<(lev+1)<<" "<<PRINT_VEC(bi,bj,bk) );
- RFLAG(lev+1, bi, bj, bk, srcFineSet) = setf;
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev+1,bi,bj,bk);
- }
- else if(RFLAG(lev+1, bi, bj, bk, srcFineSet)&(CFUnused )) {
- //errMsg("performRefinement","Removing CFUnused on lev"<<(lev+1)<<" "<<PRINT_VEC(bi,bj,bk) );
- interpolateCellFromCoarse(lev+1, bi, bj, bk, srcFineSet, interTime, setf, false);
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev+1,bi,bj,bk);
- mNumFsgrChanges++;
- }
- }
- for(int l=1; l<this->cDirNum; l++) {
- int bi=(2*i)+this->dfVecX[l], bj=(2*j)+this->dfVecY[l], bk=(2*k)+this->dfVecZ[l];
- if( (RFLAG(lev+1, bi, bj, bk, srcFineSet)&CFFluid ) &&
- (!(RFLAG(lev+1, bi, bj, bk, srcFineSet)&CFGrFromCoarse)) ) {
- // all unused nbs now of coarse have to be from coarse
- for(int m=1; m<this->cDirNum; m++) {
- int mi= bi +this->dfVecX[m], mj= bj +this->dfVecY[m], mk= bk +this->dfVecZ[m];
- if(RFLAG(lev+1, mi, mj, mk, srcFineSet)&CFUnused) {
- //errMsg("performRefinement","Changing CFUnused on lev"<<(lev+1)<<" "<<PRINT_VEC(mi,mj,mk) );
- interpolateCellFromCoarse(lev+1, mi, mj, mk, srcFineSet, interTime, CFFluid|CFGrFromCoarse, false);
- if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev+1,mi,mj,mk);
- mNumFsgrChanges++;
- }
- }
- // nbs prepared...
- }
- }
- }
-
- } // convert regions of from fine
- }}} // TEST
- // PASS 3 */
-
- if(!this->mSilent){ errMsg("performRefinement"," for l"<<lev<<" done ("<<change<<") " ); }
- } // PASS 1-3
- // refinement done
-
- //LbmFsgrSolver::performCoarsening(int lev) {
- { // PASS 4,5
- bool nbsok;
- // WARNING
- // now work on modified curr set
- const int srcSet = mLevel[lev].setCurr;
- const int dstlev = lev+1;
- const int dstFineSet = mLevel[dstlev].setCurr;
- const bool debugCoarsening = false;
-
- // PASS 5 test DEBUG
- /*if(this->mInitDone) {
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
- if(RFLAG(lev, i,j,k, srcSet) & CFEmpty) {
- // check empty -> from fine conversion
- bool changeToFromFine = false;
- const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine);
- CellFlagType reqType = CFGrNorm;
- if(lev+1==mMaxRefine) reqType = CFNoBndFluid;
- if( (RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & reqType) &&
- (!(RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & (notAllowed)) ) ){
- changeToFromFine=true; }
- if(changeToFromFine) {
- change = true;
- mNumFsgrChanges++;
- RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrFromFine;
- if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(lev,i,j,k);
- // same as restr from fine func! not necessary ?!
- // coarseRestrictFromFine part
- coarseRestrictCell(lev, i,j,k,srcSet, dstFineSet);
- }
- } // only check empty cells
- }}} // TEST!
- } // PASS 5 */
-
- // use //template functions for 2D/3D
- /*if(strstr(this->getName().c_str(),"Debug"))
- if((nbsok)&&(lev+1==mMaxRefine)) { // mixborder
- for(int l=0;((l<this->cDirNum) && (nbsok)); l++) { // FARBORD
- int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l];
- if(RFLAG(lev+1, ni,nj,nk, dstFineSet)&CFBnd) { // NEWREFT
- nbsok=false;
- }
- }
- } // FARBORD */
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
-
- // from coarse cells without unused nbs are not necessary...! -> remove
- // perform check from coarseAdvance here?
- if(RFLAG(lev, i,j,k, srcSet) & CFGrFromFine) {
- // remove from fine cells now that are completely in fluid
- // FIXME? check that new from fine in performRefinement never get deleted here afterwards?
- // or more general, one cell never changed more than once?
- const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine);
- //const CellFlagType notNbAllowed = (CFInter|CFBnd|CFGrFromFine); unused
- CellFlagType reqType = CFGrNorm;
- if(lev+1==mMaxRefine) reqType = CFNoBndFluid;
-
- nbsok = true;
- for(int l=0; l<this->cDirNum && nbsok; l++) {
- int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l];
- if( (RFLAG(lev+1, ni,nj,nk, dstFineSet) & reqType) &&
- (!(RFLAG(lev+1, ni,nj,nk, dstFineSet) & (notAllowed)) ) ){
- // ok
- } else {
- nbsok=false;
- }
- // FARBORD
- }
- // dont turn CFGrFromFine above interface cells into CFGrNorm
- // now check nbs on same level
- for(int l=1; l<this->cDirNum && nbsok; l++) {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if(RFLAG(lev, ni,nj,nk, srcSet)&(CFFluid)) { //ok
- } else {
- nbsok = false;
- }
- } // l
-
- if(nbsok) {
- // conversion to coarse fluid cell
- change = true;
- mNumFsgrChanges++;
- RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrNorm;
- // dfs are already ok...
- //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine changed to CFGrNorm at lev"<<lev<<" " <<PRINT_IJK );
- if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(lev,i,j,k);
-
- // only check complete cubes
- for(int dx=-1;dx<=1;dx+=2) {
- for(int dy=-1;dy<=1;dy+=2) {
- for(int dz=-1*(LBMDIM&1);dz<=1*(LBMDIM&1);dz+=2) { // 2d/3d
- // check for norm and from coarse, as the coarse level might just have been refined...
- if(
- // we now the flag of the current cell! ( RFLAG(lev, i , j , k , srcSet)&(CFGrNorm)) &&
- ( RFLAG(lev, i+dx, j , k , srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
- ( RFLAG(lev, i , j+dy, k , srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
- ( RFLAG(lev, i , j , k+dz, srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
-
- ( RFLAG(lev, i+dx, j+dy, k , srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
- ( RFLAG(lev, i+dx, j , k+dz, srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
- ( RFLAG(lev, i , j+dy, k+dz, srcSet)&(CFGrNorm|CFGrFromCoarse)) &&
- ( RFLAG(lev, i+dx, j+dy, k+dz, srcSet)&(CFGrNorm|CFGrFromCoarse))
- ) {
- // middle source node on higher level
- int dstx = (2*i)+dx;
- int dsty = (2*j)+dy;
- int dstz = (2*k)+dz;
-
- mNumFsgrChanges++;
- RFLAG(dstlev, dstx,dsty,dstz, dstFineSet) = CFUnused;
- RFLAG(dstlev, dstx,dsty,dstz, mLevel[dstlev].setOther) = CFUnused; // FLAGTEST
- //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init center unused set l"<<dstlev<<" at "<<PRINT_VEC(dstx,dsty,dstz) );
-
- for(int l=1; l<this->cDirNum; l++) {
- int dstni=dstx+this->dfVecX[l], dstnj=dsty+this->dfVecY[l], dstnk=dstz+this->dfVecZ[l];
- if(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)&(CFFluid)) {
- RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet) = CFFluid|CFGrFromCoarse;
- }
- if(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)&(CFInter)) {
- //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init CHECK Warning - deleting interface cell...");
- this->mFixMass += QCELL( dstlev, dstni,dstnj,dstnk, dstFineSet, dMass);
- RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet) = CFFluid|CFGrFromCoarse;
- }
- } // l
-
- // again check nb flags of all surrounding cells to see if any from coarse
- // can be convted to unused
- for(int l=1; l<this->cDirNum; l++) {
- int dstni=dstx+this->dfVecX[l], dstnj=dsty+this->dfVecY[l], dstnk=dstz+this->dfVecZ[l];
- // have to be at least from coarse here...
- //errMsg("performCoarsening","CFGrFromFine subcube init unused check l"<<dstlev<<" at "<<PRINT_VEC(dstni,dstnj,dstnk)<<" "<< convertCellFlagType2String(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)) );
- if(!(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)&(CFUnused) )) {
- bool delok = true;
- // careful long range here... check domain bounds?
- for(int m=1; m<this->cDirNum; m++) {
- int chkni=dstni+this->dfVecX[m], chknj=dstnj+this->dfVecY[m], chknk=dstnk+this->dfVecZ[m];
- if(RFLAG(dstlev, chkni,chknj,chknk, dstFineSet)&(CFUnused|CFGrFromCoarse)) {
- // this nb cell is ok for deletion
- } else {
- delok=false; // keep it!
- }
- //errMsg("performCoarsening"," CHECK "<<PRINT_VEC(dstni,dstnj,dstnk)<<" to "<<PRINT_VEC( chkni,chknj,chknk )<<" f:"<< convertCellFlagType2String( RFLAG(dstlev, chkni,chknj,chknk, dstFineSet))<<" nbsok"<<delok );
- }
- //errMsg("performCoarsening","CFGrFromFine subcube init unused check l"<<dstlev<<" at "<<PRINT_VEC(dstni,dstnj,dstnk)<<" ok"<<delok );
- if(delok) {
- mNumFsgrChanges++;
- RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet) = CFUnused;
- RFLAG(dstlev, dstni,dstnj,dstnk, mLevel[dstlev].setOther) = CFUnused; // FLAGTEST
- if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(dstlev,dstni,dstnj,dstnk);
- }
- }
- } // l
- // treat subcube
- //ebugMarkCell(lev,i+dx,j+dy,k+dz);
- //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init, dir:"<<PRINT_VEC(dx,dy,dz) );
- }
- } } }
-
- } // ?
- } // convert regions of from fine
- }}} // TEST!
- // PASS 4 */
-
- // reinit cell area value
- /*if( RFLAG(lev, i,j,k,srcSet) & CFFluid) {
- if( RFLAG(lev+1, i*2,j*2,k*2,dstFineSet) & CFGrFromCoarse) {
- LbmFloat totArea = mFsgrCellArea[0]; // for l=0
- for(int l=1; l<this->cDirNum; l++) {
- int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l];
- if(RFLAG(lev+1, ni,nj,nk, dstFineSet)&
- (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
- //(CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)
- ) {
- //LbmFloat area = 0.25; if(this->dfVecX[l]!=0) area *= 0.5; if(this->dfVecY[l]!=0) area *= 0.5; if(this->dfVecZ[l]!=0) area *= 0.5;
- totArea += mFsgrCellArea[l];
- }
- } // l
- QCELL(lev, i,j,k,mLevel[lev].setOther, dFlux) =
- QCELL(lev, i,j,k,srcSet, dFlux) = totArea;
- } else {
- QCELL(lev, i,j,k,mLevel[lev].setOther, dFlux) =
- QCELL(lev, i,j,k,srcSet, dFlux) = 1.0;
- }
- //errMsg("DFINI"," at l"<<lev<<" "<<PRINT_IJK<<" v:"<<QCELL(lev, i,j,k,srcSet, dFlux) );
- }
- // */
-
-
- // PASS 5 org
- /*if(strstr(this->getName().c_str(),"Debug"))
- if((changeToFromFine)&&(lev+1==mMaxRefine)) { // mixborder
- for(int l=0;((l<this->cDirNum) && (changeToFromFine)); l++) { // FARBORD
- int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l];
- if(RFLAG(lev+1, ni,nj,nk, dstFineSet)&CFBnd) { // NEWREFT
- changeToFromFine=false; }
- }
- }// FARBORD */
- //if(!this->mInitDone) {
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k) {
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
-
-
- if(RFLAG(lev, i,j,k, srcSet) & CFEmpty) {
- // check empty -> from fine conversion
- bool changeToFromFine = false;
- const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine);
- CellFlagType reqType = CFGrNorm;
- if(lev+1==mMaxRefine) reqType = CFNoBndFluid;
-
- if( (RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & reqType) &&
- (!(RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & (notAllowed)) ) ){
- // DEBUG
- changeToFromFine=true;
- }
-
- // FARBORD
-
- if(changeToFromFine) {
- change = true;
- mNumFsgrChanges++;
- RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrFromFine;
- if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(lev,i,j,k);
- // same as restr from fine func! not necessary ?!
- // coarseRestrictFromFine part
- }
- } // only check empty cells
-
- }}} // TEST!
- //} // init done
- // PASS 5 */
- } // coarsening, PASS 4,5
-
- if(!this->mSilent){ errMsg("adaptGrid"," for l"<<lev<<" done " ); }
- return change;
-}
-
-/*****************************************************************************/
-//! cell restriction and prolongation
-/*****************************************************************************/
-
-void LbmFsgrSolver::coarseRestrictCell(int lev, int i,int j,int k, int srcSet, int dstSet)
-{
- LbmFloat *ccel = RACPNT(lev+1, 2*i,2*j,2*k,srcSet);
- LbmFloat *tcel = RACPNT(lev , i,j,k ,dstSet);
-
- LbmFloat rho=0.0, ux=0.0, uy=0.0, uz=0.0;
- //LbmFloat *ccel = NULL;
- //LbmFloat *tcel = NULL;
-#if OPT3D==1
- LbmFloat m[LBM_DFNUM];
- // for macro add
- LbmFloat usqr;
- //LbmFloat *addfcel, *dstcell;
- LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM];
- LbmFloat lcsmDstOmega, lcsmSrcOmega, lcsmdfscale;
-#else // OPT3D==true
- LbmFloat df[LBM_DFNUM];
- LbmFloat omegaDst, omegaSrc;
- LbmFloat feq[LBM_DFNUM];
- LbmFloat dfScale = mDfScaleUp;
-#endif // OPT3D==true
-
-# if OPT3D==0
- // add up weighted dfs
- FORDF0{ df[l] = 0.0;}
- for(int n=0;(n<this->cDirNum); n++) {
- int ni=2*i+1*this->dfVecX[n], nj=2*j+1*this->dfVecY[n], nk=2*k+1*this->dfVecZ[n];
- ccel = RACPNT(lev+1, ni,nj,nk,srcSet);// CFINTTEST
- const LbmFloat weight = mGaussw[n];
- FORDF0{
- LbmFloat cdf = weight * RAC(ccel,l);
-# if FSGR_STRICT_DEBUG==1
- if( cdf<-1.0 ){ errMsg("INVDFCREST_DFCHECK", PRINT_IJK<<" s"<<dstSet<<" from "<<PRINT_VEC(2*i,2*j,2*k)<<" s"<<srcSet<<" df"<<l<<":"<< df[l]); }
-# endif
- //errMsg("INVDFCREST_DFCHECK", PRINT_IJK<<" s"<<dstSet<<" from "<<PRINT_VEC(2*i,2*j,2*k)<<" s"<<srcSet<<" df"<<l<<":"<< df[l]<<" = "<<cdf<<" , w"<<weight);
- df[l] += cdf;
- }
- }
-
- // calc rho etc. from weighted dfs
- rho = ux = uy = uz = 0.0;
- FORDF0{
- LbmFloat cdf = df[l];
- rho += cdf;
- ux += (this->dfDvecX[l]*cdf);
- uy += (this->dfDvecY[l]*cdf);
- uz += (this->dfDvecZ[l]*cdf);
- }
-
- FORDF0{ feq[l] = this->getCollideEq(l, rho,ux,uy,uz); }
- if(mLevel[lev ].lcsmago>0.0) {
- const LbmFloat Qo = this->getLesNoneqTensorCoeff(df,feq);
- omegaDst = this->getLesOmega(mLevel[lev ].omega,mLevel[lev ].lcsmago,Qo);
- omegaSrc = this->getLesOmega(mLevel[lev+1].omega,mLevel[lev+1].lcsmago,Qo);
- } else {
- omegaDst = mLevel[lev+0].omega; /* NEWSMAGOT*/
- omegaSrc = mLevel[lev+1].omega;
- }
- dfScale = (mLevel[lev ].timestep/mLevel[lev+1].timestep)* (1.0/omegaDst-1.0)/ (1.0/omegaSrc-1.0); // yu
- FORDF0{
- RAC(tcel, l) = feq[l]+ (df[l]-feq[l])*dfScale;
- }
-# else // OPT3D
- // similar to OPTIMIZED_STREAMCOLLIDE_UNUSED
-
- //rho = ux = uy = uz = 0.0;
- MSRC_C = CCELG_C(0) ;
- MSRC_N = CCELG_N(0) ;
- MSRC_S = CCELG_S(0) ;
- MSRC_E = CCELG_E(0) ;
- MSRC_W = CCELG_W(0) ;
- MSRC_T = CCELG_T(0) ;
- MSRC_B = CCELG_B(0) ;
- MSRC_NE = CCELG_NE(0);
- MSRC_NW = CCELG_NW(0);
- MSRC_SE = CCELG_SE(0);
- MSRC_SW = CCELG_SW(0);
- MSRC_NT = CCELG_NT(0);
- MSRC_NB = CCELG_NB(0);
- MSRC_ST = CCELG_ST(0);
- MSRC_SB = CCELG_SB(0);
- MSRC_ET = CCELG_ET(0);
- MSRC_EB = CCELG_EB(0);
- MSRC_WT = CCELG_WT(0);
- MSRC_WB = CCELG_WB(0);
- for(int n=1;(n<this->cDirNum); n++) {
- ccel = RACPNT(lev+1, 2*i+1*this->dfVecX[n], 2*j+1*this->dfVecY[n], 2*k+1*this->dfVecZ[n] ,srcSet);
- MSRC_C += CCELG_C(n) ;
- MSRC_N += CCELG_N(n) ;
- MSRC_S += CCELG_S(n) ;
- MSRC_E += CCELG_E(n) ;
- MSRC_W += CCELG_W(n) ;
- MSRC_T += CCELG_T(n) ;
- MSRC_B += CCELG_B(n) ;
- MSRC_NE += CCELG_NE(n);
- MSRC_NW += CCELG_NW(n);
- MSRC_SE += CCELG_SE(n);
- MSRC_SW += CCELG_SW(n);
- MSRC_NT += CCELG_NT(n);
- MSRC_NB += CCELG_NB(n);
- MSRC_ST += CCELG_ST(n);
- MSRC_SB += CCELG_SB(n);
- MSRC_ET += CCELG_ET(n);
- MSRC_EB += CCELG_EB(n);
- MSRC_WT += CCELG_WT(n);
- MSRC_WB += CCELG_WB(n);
- }
- rho = MSRC_C + MSRC_N + MSRC_S + MSRC_E + MSRC_W + MSRC_T
- + MSRC_B + MSRC_NE + MSRC_NW + MSRC_SE + MSRC_SW + MSRC_NT
- + MSRC_NB + MSRC_ST + MSRC_SB + MSRC_ET + MSRC_EB + MSRC_WT + MSRC_WB;
- ux = MSRC_E - MSRC_W + MSRC_NE - MSRC_NW + MSRC_SE - MSRC_SW
- + MSRC_ET + MSRC_EB - MSRC_WT - MSRC_WB;
- uy = MSRC_N - MSRC_S + MSRC_NE + MSRC_NW - MSRC_SE - MSRC_SW
- + MSRC_NT + MSRC_NB - MSRC_ST - MSRC_SB;
- uz = MSRC_T - MSRC_B + MSRC_NT - MSRC_NB + MSRC_ST - MSRC_SB
- + MSRC_ET - MSRC_EB + MSRC_WT - MSRC_WB;
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- \
- lcsmeq[dC] = EQC ; \
- COLL_CALCULATE_DFEQ(lcsmeq); \
- COLL_CALCULATE_NONEQTENSOR(lev+0, MSRC_ )\
- COLL_CALCULATE_CSMOMEGAVAL(lev+0, lcsmDstOmega); \
- COLL_CALCULATE_CSMOMEGAVAL(lev+1, lcsmSrcOmega); \
- \
- lcsmdfscale = (mLevel[lev+0].timestep/mLevel[lev+1].timestep)* (1.0/lcsmDstOmega-1.0)/ (1.0/lcsmSrcOmega-1.0); \
- RAC(tcel, dC ) = (lcsmeq[dC ] + (MSRC_C -lcsmeq[dC ] )*lcsmdfscale);
- RAC(tcel, dN ) = (lcsmeq[dN ] + (MSRC_N -lcsmeq[dN ] )*lcsmdfscale);
- RAC(tcel, dS ) = (lcsmeq[dS ] + (MSRC_S -lcsmeq[dS ] )*lcsmdfscale);
- RAC(tcel, dE ) = (lcsmeq[dE ] + (MSRC_E -lcsmeq[dE ] )*lcsmdfscale);
- RAC(tcel, dW ) = (lcsmeq[dW ] + (MSRC_W -lcsmeq[dW ] )*lcsmdfscale);
- RAC(tcel, dT ) = (lcsmeq[dT ] + (MSRC_T -lcsmeq[dT ] )*lcsmdfscale);
- RAC(tcel, dB ) = (lcsmeq[dB ] + (MSRC_B -lcsmeq[dB ] )*lcsmdfscale);
- RAC(tcel, dNE) = (lcsmeq[dNE] + (MSRC_NE-lcsmeq[dNE] )*lcsmdfscale);
- RAC(tcel, dNW) = (lcsmeq[dNW] + (MSRC_NW-lcsmeq[dNW] )*lcsmdfscale);
- RAC(tcel, dSE) = (lcsmeq[dSE] + (MSRC_SE-lcsmeq[dSE] )*lcsmdfscale);
- RAC(tcel, dSW) = (lcsmeq[dSW] + (MSRC_SW-lcsmeq[dSW] )*lcsmdfscale);
- RAC(tcel, dNT) = (lcsmeq[dNT] + (MSRC_NT-lcsmeq[dNT] )*lcsmdfscale);
- RAC(tcel, dNB) = (lcsmeq[dNB] + (MSRC_NB-lcsmeq[dNB] )*lcsmdfscale);
- RAC(tcel, dST) = (lcsmeq[dST] + (MSRC_ST-lcsmeq[dST] )*lcsmdfscale);
- RAC(tcel, dSB) = (lcsmeq[dSB] + (MSRC_SB-lcsmeq[dSB] )*lcsmdfscale);
- RAC(tcel, dET) = (lcsmeq[dET] + (MSRC_ET-lcsmeq[dET] )*lcsmdfscale);
- RAC(tcel, dEB) = (lcsmeq[dEB] + (MSRC_EB-lcsmeq[dEB] )*lcsmdfscale);
- RAC(tcel, dWT) = (lcsmeq[dWT] + (MSRC_WT-lcsmeq[dWT] )*lcsmdfscale);
- RAC(tcel, dWB) = (lcsmeq[dWB] + (MSRC_WB-lcsmeq[dWB] )*lcsmdfscale);
-# endif // OPT3D==0
-}
-
-void LbmFsgrSolver::interpolateCellFromCoarse(int lev, int i, int j,int k, int dstSet, LbmFloat t, CellFlagType flagSet, bool markNbs) {
- LbmFloat rho=0.0, ux=0.0, uy=0.0, uz=0.0;
- LbmFloat intDf[19] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
-
-#if OPT3D==1
- // for macro add
- LbmFloat addDfFacT, addVal, usqr;
- LbmFloat *addfcel, *dstcell;
- LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM];
- LbmFloat lcsmDstOmega, lcsmSrcOmega, lcsmdfscale;
-#endif // OPT3D==true
-
- // SET required nbs to from coarse (this might overwrite flag several times)
- // this is not necessary for interpolateFineFromCoarse
- if(markNbs) {
- FORDF1{
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if(RFLAG(lev,ni,nj,nk,dstSet)&CFUnused) {
- // parents have to be inited!
- interpolateCellFromCoarse(lev, ni, nj, nk, dstSet, t, CFFluid|CFGrFromCoarse, false);
- }
- } }
-
- // change flag of cell to be interpolated
- RFLAG(lev,i,j,k, dstSet) = flagSet;
- mNumInterdCells++;
-
- // interpolation lines...
- int betx = i&1;
- int bety = j&1;
- int betz = k&1;
-
- if((!betx) && (!bety) && (!betz)) {
- ADD_INT_DFS(lev-1, i/2 ,j/2 ,k/2 , 0.0, 1.0);
- }
- else if(( betx) && (!bety) && (!betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D1);
- }
- else if((!betx) && ( bety) && (!betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D1);
- }
- else if((!betx) && (!bety) && ( betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D1);
- }
- else if(( betx) && ( bety) && (!betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2) , t, WO1D2);
- }
- else if((!betx) && ( bety) && ( betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2)+1, t, WO1D2);
- }
- else if(( betx) && (!bety) && ( betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D2);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2)+1, t, WO1D2);
- }
- else if(( betx) && ( bety) && ( betz)) {
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2)+1, t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2) , t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2)+1, t, WO1D3);
- ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2)+1, t, WO1D3);
- }
- else {
- CAUSE_PANIC;
- errFatal("interpolateCellFromCoarse","Invalid!?", SIMWORLD_GENERICERROR);
- }
-
- IDF_WRITEBACK;
- return;
-}
-
-
-
-#define MPTADAP_INTERV 4
-
-/*****************************************************************************/
-/*! change the size of the LBM time step */
-/*****************************************************************************/
-void LbmFsgrSolver::adaptTimestep() {
- LbmFloat massTOld=0.0, massTNew=0.0;
- LbmFloat volTOld=0.0, volTNew=0.0;
-
- bool rescale = false; // do any rescale at all?
- LbmFloat scaleFac = -1.0; // timestep scaling
- if(mPanic) return;
-
- LbmFloat levOldOmega[FSGR_MAXNOOFLEVELS];
- LbmFloat levOldStepsize[FSGR_MAXNOOFLEVELS];
- for(int lev=mMaxRefine; lev>=0 ; lev--) {
- levOldOmega[lev] = mLevel[lev].omega;
- levOldStepsize[lev] = mLevel[lev].timestep;
- }
-
- const LbmFloat reduceFac = 0.8; // modify time step by 20%, TODO? do multiple times for large changes?
- LbmFloat diffPercent = 0.05; // dont scale if less than 5%
- LbmFloat allowMax = mpParam->getTadapMaxSpeed(); // maximum allowed velocity
- LbmFloat nextmax = mpParam->getSimulationMaxSpeed() + norm(mLevel[mMaxRefine].gravity);
-
- // sync nextmax
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(glob_mpactive) {
- if(mLevel[mMaxRefine].lsteps % MPTADAP_INTERV != MPTADAP_INTERV-1) {
- debMsgStd("LbmFsgrSolver::TAdp",DM_MSG, "mpact:"<<glob_mpactive<<","<<glob_mpindex<<"/"<<glob_mpnum<<" step:"<<mLevel[mMaxRefine].lsteps<<" skipping tadap...",8);
- return;
- }
- nextmax = mrInitTadap(nextmax);
- }
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
- LbmFloat newdt = mpParam->getTimestep(); // newtr
- if(nextmax > allowMax/reduceFac) {
- mTimeMaxvelStepCnt++; }
- else { mTimeMaxvelStepCnt=0; }
-
- // emergency, or 10 steps with high vel
- if((mTimeMaxvelStepCnt>5) || (nextmax> (1.0/3.0)) || (mForceTimeStepReduce) ) {
- newdt = mpParam->getTimestep() * reduceFac;
- } else {
- if(nextmax<allowMax*reduceFac) {
- newdt = mpParam->getTimestep() / reduceFac;
- }
- } // newtr
- //errMsg("LbmFsgrSolver::adaptTimestep","nextmax="<<nextmax<<" allowMax="<<allowMax<<" fac="<<reduceFac<<" simmaxv="<< mpParam->getSimulationMaxSpeed() );
-
- bool minCutoff = false;
- LbmFloat desireddt = newdt;
- if(newdt>mpParam->getMaxTimestep()){ newdt = mpParam->getMaxTimestep(); }
- if(newdt<mpParam->getMinTimestep()){
- newdt = mpParam->getMinTimestep();
- if(nextmax>allowMax/reduceFac){ minCutoff=true; } // only if really large vels...
- }
-
- LbmFloat dtdiff = fabs(newdt - mpParam->getTimestep());
- if(!mSilent) {
- debMsgStd("LbmFsgrSolver::TAdp",DM_MSG, "new"<<newdt
- <<" max"<<mpParam->getMaxTimestep()<<" min"<<mpParam->getMinTimestep()<<" diff"<<dtdiff
- <<" simt:"<<mSimulationTime<<" minsteps:"<<(mSimulationTime/mMaxTimestep)<<" maxsteps:"<<(mSimulationTime/mMinTimestep)<<
- " olddt"<<levOldStepsize[mMaxRefine]<<" redlock"<<mTimestepReduceLock
- , 10); }
-
- // in range, and more than X% change?
- //if( newdt < mpParam->getTimestep() ) // DEBUG
- LbmFloat rhoAvg = mCurrentMass/mCurrentVolume;
- if( (newdt<=mpParam->getMaxTimestep()) && (newdt>=mpParam->getMinTimestep())
- && (dtdiff>(mpParam->getTimestep()*diffPercent)) ) {
- if((newdt>levOldStepsize[mMaxRefine])&&(mTimestepReduceLock)) {
- // wait some more...
- //debMsgNnl("LbmFsgrSolver::TAdp",DM_NOTIFY," Delayed... "<<mTimestepReduceLock<<" ",10);
- debMsgDirect("D");
- } else {
- mpParam->setDesiredTimestep( newdt );
- rescale = true;
- if(!mSilent) {
- debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"\n\n\n\n",10);
- debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Timestep changing: new="<<newdt<<" old="<<mpParam->getTimestep()
- <<" maxSpeed:"<<mpParam->getSimulationMaxSpeed()<<" next:"<<nextmax<<" step:"<<mStepCnt, 10 );
- //debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Timestep changing: "<< "rhoAvg="<<rhoAvg<<" cMass="<<mCurrentMass<<" cVol="<<mCurrentVolume,10);
- }
- } // really change dt
- }
-
- if(mTimestepReduceLock>0) mTimestepReduceLock--;
-
-
- // forced back and forth switchting (for testing)
- /*const int tadtogInter = 100;
- const double tadtogSwitch = 0.66;
- errMsg("TIMESWITCHTOGGLETEST","warning enabled "<< tadtogSwitch<<","<<tadtogSwitch<<" !!!!!!!!!!!!!!!!!!!");
- if( ((mStepCnt% tadtogInter)== (tadtogInter/4*1)-1) ||
- ((mStepCnt% tadtogInter)== (tadtogInter/4*2)-1) ){
- rescale = true; minCutoff = false;
- newdt = tadtogSwitch * mpParam->getTimestep();
- mpParam->setDesiredTimestep( newdt );
- } else
- if( ((mStepCnt% tadtogInter)== (tadtogInter/4*3)-1) ||
- ((mStepCnt% tadtogInter)== (tadtogInter/4*4)-1) ){
- rescale = true; minCutoff = false;
- newdt = mpParam->getTimestep()/tadtogSwitch ;
- mpParam->setDesiredTimestep( newdt );
- } else {
- rescale = false; minCutoff = false;
- }
- // */
-
- // test mass rescale
-
- scaleFac = newdt/mpParam->getTimestep();
- if(rescale) {
- // perform acutal rescaling...
- mTimeMaxvelStepCnt=0;
- mForceTimeStepReduce = false;
-
- // FIXME - approximate by averaging, take gravity direction here?
- //mTimestepReduceLock = 4*(mLevel[mMaxRefine].lSizey+mLevel[mMaxRefine].lSizez+mLevel[mMaxRefine].lSizex)/3;
- // use z as gravity direction
- mTimestepReduceLock = 4*mLevel[mMaxRefine].lSizez;
-
- mTimeSwitchCounts++;
- mpParam->calculateAllMissingValues( mSimulationTime, mSilent );
- recalculateObjectSpeeds();
- // calc omega, force for all levels
- mLastOmega=1e10; mLastGravity=1e10;
- initLevelOmegas();
- if(mpParam->getTimestep()<mMinTimestep) mMinTimestep = mpParam->getTimestep();
- if(mpParam->getTimestep()>mMaxTimestep) mMaxTimestep = mpParam->getTimestep();
-
- // this might be called during init, before we have any particles
- if(mpParticles) { mpParticles->adaptPartTimestep(scaleFac); }
-#if LBM_INCLUDE_TESTSOLVERS==1
- if((mUseTestdata)&&(mpTest)) {
- mpTest->adaptTimestep(scaleFac, mLevel[mMaxRefine].omega, mLevel[mMaxRefine].timestep, vec2L( mpParam->calculateGravity(mSimulationTime)) );
- mpTest->mGrav3d = mLevel[mMaxRefine].gravity;
- }
-#endif // LBM_INCLUDE_TESTSOLVERS!=1
-
- for(int lev=mMaxRefine; lev>=0 ; lev--) {
- LbmFloat newSteptime = mLevel[lev].timestep;
- LbmFloat dfScaleFac = (newSteptime/1.0)/(levOldStepsize[lev]/levOldOmega[lev]);
-
- if(!mSilent) {
- debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Level: "<<lev<<" Timestep chlevel: "<<
- " scaleFac="<<dfScaleFac<<" newDt="<<newSteptime<<" newOmega="<<mLevel[lev].omega,10);
- }
- if(lev!=mMaxRefine) coarseCalculateFluxareas(lev);
-
- int wss = 0, wse = 1;
- // only change currset (necessary for compressed grids, better for non-compr.gr.)
- wss = wse = mLevel[lev].setCurr;
- for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT
- // warning - check sets for higher levels...?
- FSGR_FORIJK1(lev) {
- if( (RFLAG(lev,i,j,k, workSet) & CFBndMoving) ) {
- /*
- // paranoid check - shouldnt be necessary!
- if(QCELL(lev, i, j, k, workSet, dFlux)!=mSimulationTime) {
- errMsg("TTTT","found invalid bnd cell.... removing at "<<PRINT_IJK);
- RFLAG(lev,i,j,k, workSet) = CFInter;
- // init empty zero vel interface cell...
- initVelocityCell(lev, i,j,k, CFInter, 1.0, 0.01, LbmVec(0.) );
- } else {// */
- for(int l=0; l<cDfNum; l++) {
- QCELL(lev, i, j, k, workSet, l) = QCELL(lev, i, j, k, workSet, l)* scaleFac;
- }
- //} // ok
- continue;
- }
- if(
- (RFLAG(lev,i,j,k, workSet) & CFFluid) ||
- (RFLAG(lev,i,j,k, workSet) & CFInter) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrFromCoarse) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrFromFine) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrNorm)
- ) {
- // these cells have to be scaled...
- } else {
- continue;
- }
-
- // collide on current set
- LbmFloat rhoOld;
- LbmVec velOld;
- LbmFloat rho, ux,uy,uz;
- rho=0.0; ux = uy = uz = 0.0;
- for(int l=0; l<cDfNum; l++) {
- LbmFloat m = QCELL(lev, i, j, k, workSet, l);
- rho += m;
- ux += (dfDvecX[l]*m);
- uy += (dfDvecY[l]*m);
- uz += (dfDvecZ[l]*m);
- }
- rhoOld = rho;
- velOld = LbmVec(ux,uy,uz);
-
- LbmFloat rhoNew = (rhoOld-rhoAvg)*scaleFac +rhoAvg;
- LbmVec velNew = velOld * scaleFac;
-
- LbmFloat df[LBM_DFNUM];
- LbmFloat feqOld[LBM_DFNUM];
- LbmFloat feqNew[LBM_DFNUM];
- for(int l=0; l<cDfNum; l++) {
- feqOld[l] = getCollideEq(l,rhoOld, velOld[0],velOld[1],velOld[2] );
- feqNew[l] = getCollideEq(l,rhoNew, velNew[0],velNew[1],velNew[2] );
- df[l] = QCELL(lev, i,j,k,workSet, l);
- }
- const LbmFloat Qo = getLesNoneqTensorCoeff(df,feqOld);
- const LbmFloat oldOmega = getLesOmega(levOldOmega[lev], mLevel[lev].lcsmago,Qo);
- const LbmFloat newOmega = getLesOmega(mLevel[lev].omega,mLevel[lev].lcsmago,Qo);
- //newOmega = mLevel[lev].omega; // FIXME debug test
-
- //LbmFloat dfScaleFac = (newSteptime/1.0)/(levOldStepsize[lev]/levOldOmega[lev]);
- const LbmFloat dfScale = (newSteptime/newOmega)/(levOldStepsize[lev]/oldOmega);
- //dfScale = dfScaleFac/newOmega;
-
- for(int l=0; l<cDfNum; l++) {
- // org scaling
- //df = eqOld + (df-eqOld)*dfScale; df *= (eqNew/eqOld); // non-eq. scaling, important
- // new scaling
- LbmFloat dfn = feqNew[l] + (df[l]-feqOld[l])*dfScale*feqNew[l]/feqOld[l]; // non-eq. scaling, important
- //df = eqNew + (df-eqOld)*dfScale; // modified ig scaling, no real difference?
- QCELL(lev, i,j,k,workSet, l) = dfn;
- }
-
- if(RFLAG(lev,i,j,k, workSet) & CFInter) {
- //if(workSet==mLevel[lev].setCurr)
- LbmFloat area = 1.0;
- if(lev!=mMaxRefine) area = QCELL(lev, i,j,k,workSet, dFlux);
- massTOld += QCELL(lev, i,j,k,workSet, dMass) * area;
- volTOld += QCELL(lev, i,j,k,workSet, dFfrac);
-
- // wrong... QCELL(i,j,k,workSet, dMass] = (QCELL(i,j,k,workSet, dFfrac]*rhoNew);
- QCELL(lev, i,j,k,workSet, dMass) = (QCELL(lev, i,j,k,workSet, dMass)/rhoOld*rhoNew);
- QCELL(lev, i,j,k,workSet, dFfrac) = (QCELL(lev, i,j,k,workSet, dMass)/rhoNew);
-
- //if(workSet==mLevel[lev].setCurr)
- massTNew += QCELL(lev, i,j,k,workSet, dMass);
- volTNew += QCELL(lev, i,j,k,workSet, dFfrac);
- }
- if(RFLAG(lev,i,j,k, workSet) & CFFluid) { // DEBUG
- if(RFLAG(lev,i,j,k, workSet) & (CFGrFromFine|CFGrFromCoarse)) { // DEBUG
- // dont include
- } else {
- LbmFloat area = 1.0;
- if(lev!=mMaxRefine) area = QCELL(lev, i,j,k,workSet, dFlux) * mLevel[lev].lcellfactor;
- //if(workSet==mLevel[lev].setCurr)
- massTOld += rhoOld*area;
- //if(workSet==mLevel[lev].setCurr)
- massTNew += rhoNew*area;
- volTOld += area;
- volTNew += area;
- }
- }
-
- } // IJK
- } // workSet
-
- } // lev
-
- if(!mSilent) {
- debMsgStd("LbmFsgrSolver::step",DM_MSG,"REINIT DONE "<<mStepCnt<<
- " no"<<mTimeSwitchCounts<<" maxdt"<<mMaxTimestep<<
- " mindt"<<mMinTimestep<<" currdt"<<mLevel[mMaxRefine].timestep, 10);
- debMsgStd("LbmFsgrSolver::step",DM_MSG,"REINIT DONE masst:"<<massTNew<<","<<massTOld<<" org:"<<mCurrentMass<<"; "<<
- " volt:"<<volTNew<<","<<volTOld<<" org:"<<mCurrentVolume, 10);
- } else {
- debMsgStd("\nLbmOptSolver::step",DM_MSG,"Timestep changed by "<< (newdt/levOldStepsize[mMaxRefine]) <<" newDt:"<<newdt
- <<", oldDt:"<<levOldStepsize[mMaxRefine]<<" newOmega:"<<mOmega<<" gStar:"<<mpParam->getCurrentGStar()<<", step:"<<mStepCnt , 10);
- }
- } // rescale?
- //NEWDEBCHECK("tt2");
-
- //errMsg("adaptTimestep","Warning - brute force rescale off!"); minCutoff = false; // DEBUG
- if(minCutoff) {
- errMsg("adaptTimestep","Warning - performing Brute-Force rescale... (sim:"<<mName<<" step:"<<mStepCnt<<" newdt="<<desireddt<<" mindt="<<mpParam->getMinTimestep()<<") " );
- //brute force resacle all the time?
-
- for(int lev=mMaxRefine; lev>=0 ; lev--) {
- int rescs=0;
- int wss = 0, wse = 1;
-#if COMPRESSGRIDS==1
- if(lev== mMaxRefine) wss = wse = mLevel[lev].setCurr;
-#endif // COMPRESSGRIDS==1
- for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT
- //for(int workSet = 0; workSet<=1; workSet++) {
- FSGR_FORIJK1(lev) {
-
- //if( (RFLAG(lev, i,j,k, workSet) & CFFluid) || (RFLAG(lev, i,j,k, workSet) & CFInter) ) {
- if(
- (RFLAG(lev,i,j,k, workSet) & CFFluid) ||
- (RFLAG(lev,i,j,k, workSet) & CFInter) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrFromCoarse) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrFromFine) ||
- (RFLAG(lev,i,j,k, workSet) & CFGrNorm)
- ) {
- // these cells have to be scaled...
- } else {
- continue;
- }
-
- // collide on current set
- LbmFloat rho, ux,uy,uz;
- rho=0.0; ux = uy = uz = 0.0;
- for(int l=0; l<cDfNum; l++) {
- LbmFloat m = QCELL(lev, i, j, k, workSet, l);
- rho += m;
- ux += (dfDvecX[l]*m);
- uy += (dfDvecY[l]*m);
- uz += (dfDvecZ[l]*m);
- }
-#ifndef WIN32
- if (!isfinite(rho)) {
- errMsg("adaptTimestep","Brute force non-finite rho at"<<PRINT_IJK); // DEBUG!
- rho = 1.0;
- ux = uy = uz = 0.0;
- QCELL(lev, i, j, k, workSet, dMass) = 1.0;
- QCELL(lev, i, j, k, workSet, dFfrac) = 1.0;
- }
-#endif // WIN32
-
- if( (ux*ux+uy*uy+uz*uz)> (allowMax*allowMax) ) {
- LbmFloat cfac = allowMax/sqrt(ux*ux+uy*uy+uz*uz);
- ux *= cfac;
- uy *= cfac;
- uz *= cfac;
- for(int l=0; l<cDfNum; l++) {
- QCELL(lev, i, j, k, workSet, l) = getCollideEq(l, rho, ux,uy,uz); }
- rescs++;
- debMsgDirect("B");
- }
-
- } }
- //if(rescs>0) { errMsg("adaptTimestep","!!!!! Brute force rescaling was necessary !!!!!!!"); }
- debMsgStd("adaptTimestep",DM_MSG,"Brute force rescale done. level:"<<lev<<" rescs:"<<rescs, 1);
- //TTT mNumProblems += rescs; // add to problem display...
- } // lev,set,ijk
-
- } // try brute force rescale?
-
- // time adap done...
-}
-
-
-
diff --git a/intern/elbeem/intern/solver_class.h b/intern/elbeem/intern/solver_class.h
deleted file mode 100644
index ac02f2cc85a..00000000000
--- a/intern/elbeem/intern/solver_class.h
+++ /dev/null
@@ -1,1036 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - the visual lattice boltzmann freesurface simulator
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Combined 2D/3D Lattice Boltzmann standard solver classes
- *
- *****************************************************************************/
-
-
-#ifndef LBM_SOLVERCLASS_H
-#define LBM_SOLVERCLASS_H
-
-#include "utilities.h"
-#include "solver_interface.h"
-#include "ntl_ray.h"
-#include <stdio.h>
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-#if PARALLEL==1
-#include <omp.h>
-#endif // PARALLEL=1
-#ifndef PARALLEL
-#define PARALLEL 0
-#endif // PARALLEL
-
-
-// general solver setting defines
-
-//! debug coordinate accesses and the like? (much slower)
-// might be enabled by compilation
-#ifndef FSGR_STRICT_DEBUG
-#define FSGR_STRICT_DEBUG 0
-#endif // FSGR_STRICT_DEBUG
-
-//! debug coordinate accesses and the like? (much slower)
-#define FSGR_OMEGA_DEBUG 0
-
-//! OPT3D quick LES on/off, only debug/benchmarking
-#define USE_LES 1
-
-//! order of interpolation (0=always current/1=interpolate/2=always other)
-//#define TIMEINTORDER 0
-// TODO remove interpol t param, also interTime
-
-// use optimized 3D code?
-#if LBMDIM==2
-#define OPT3D 0
-#else
-// determine with debugging...
-# if FSGR_STRICT_DEBUG==1
-# define OPT3D 0
-# else // FSGR_STRICT_DEBUG==1
-// usually switch optimizations for 3d on, when not debugging
-# define OPT3D 1
-// COMPRT
-//# define OPT3D 0
-# endif // FSGR_STRICT_DEBUG==1
-#endif
-
-//! invalid mass value for unused mass data
-#define MASS_INVALID -1000.0
-
-// empty/fill cells without fluid/empty NB's by inserting them into the full/empty lists?
-#define FSGR_LISTTRICK 1
-#define FSGR_LISTTTHRESHEMPTY 0.10
-#define FSGR_LISTTTHRESHFULL 0.90
-#define FSGR_MAGICNR 0.025
-//0.04
-
-//! maxmimum no. of grid levels
-#define FSGR_MAXNOOFLEVELS 5
-
-// enable/disable fine grid compression for finest level
-// make sure this is same as useGridComp in calculateMemreqEstimate
-#if LBMDIM==3
-#define COMPRESSGRIDS 1
-#else
-#define COMPRESSGRIDS 0
-#endif
-
-// helper for comparing floats with epsilon
-#define GFX_FLOATNEQ(x,y) ( ABS((x)-(y)) > (VECTOR_EPSILON) )
-#define LBM_FLOATNEQ(x,y) ( ABS((x)-(y)) > (10.0*LBM_EPSILON) )
-
-
-// macros for loops over all DFs
-#define FORDF0 for(int l= 0; l< LBM_DFNUM; ++l)
-#define FORDF1 for(int l= 1; l< LBM_DFNUM; ++l)
-// and with different loop var to prevent shadowing
-#define FORDF0M for(int m= 0; m< LBM_DFNUM; ++m)
-#define FORDF1M for(int m= 1; m< LBM_DFNUM; ++m)
-
-// iso value defines
-// border for marching cubes
-#define ISOCORR 3
-
-#define LBM_INLINED inline
-
-// sirdude fix for solaris
-#if !defined(linux) && defined(sun)
-#include "ieeefp.h"
-#ifndef expf
-#define expf(x) exp((double)(x))
-#endif
-#endif
-
-#include "solver_control.h"
-
-#if LBM_INCLUDE_TESTSOLVERS==1
-#include "solver_test.h"
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
-/*****************************************************************************/
-/*! cell access classes */
-class UniformFsgrCellIdentifier :
- public CellIdentifierInterface , public LbmCellContents
-{
- public:
- //! which grid level?
- int level;
- //! location in grid
- int x,y,z;
-
- //! reset constructor
- UniformFsgrCellIdentifier() :
- x(0), y(0), z(0) { };
-
- // implement CellIdentifierInterface
- virtual string getAsString() {
- std::ostringstream ret;
- ret <<"{ i"<<x<<",j"<<y;
- if(LBMDIM>2) ret<<",k"<<z;
- ret <<" }";
- return ret.str();
- }
-
- virtual bool equal(CellIdentifierInterface* other) {
- UniformFsgrCellIdentifier *cid = (UniformFsgrCellIdentifier *)( other );
- if(!cid) return false;
- if( x==cid->x && y==cid->y && z==cid->z && level==cid->level ) return true;
- return false;
- }
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:UniformFsgrCellIdentifier")
-#endif
-};
-
-//! information needed for each level in the simulation
-class FsgrLevelData {
-public:
- int id; // level number
-
- //! node size on this level (geometric, in world coordinates, not simulation units!)
- LbmFloat nodeSize;
- //! node size on this level in simulation units
- LbmFloat simCellSize;
- //! quadtree node relaxation parameter
- LbmFloat omega;
- //! size this level was advanced to
- LbmFloat time;
- //! size of a single lbm step in time units on this level
- LbmFloat timestep;
- //! step count
- int lsteps;
- //! gravity force for this level
- LbmVec gravity;
- //! level array
- LbmFloat *mprsCells[2];
- CellFlagType *mprsFlags[2];
-
- //! smago params and precalculated values
- LbmFloat lcsmago;
- LbmFloat lcsmago_sqr;
- LbmFloat lcnu;
-
- // LES statistics per level
- double avgOmega;
- double avgOmegaCnt;
-
- //! current set of dist funcs
- int setCurr;
- //! target/other set of dist funcs
- int setOther;
-
- //! mass&volume for this level
- LbmFloat lmass;
- LbmFloat lvolume;
- LbmFloat lcellfactor;
-
- //! local storage of mSizes
- int lSizex, lSizey, lSizez;
- int lOffsx, lOffsy, lOffsz;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:FsgrLevelData")
-#endif
-};
-
-
-
-/*****************************************************************************/
-/*! class for solving a LBM problem */
-class LbmFsgrSolver :
- public LbmSolverInterface // this means, the solver is a lbmData object and implements the lbmInterface
-{
-
- public:
- //! Constructor
- LbmFsgrSolver();
- //! Destructor
- virtual ~LbmFsgrSolver();
-
- //! initilize variables fom attribute list
- virtual void parseAttrList();
- //! Initialize omegas and forces on all levels (for init/timestep change)
- void initLevelOmegas();
-
- // multi step solver init
- /*! finish the init with config file values (allocate arrays...) */
- virtual bool initializeSolverMemory();
- /*! init solver arrays */
- virtual bool initializeSolverGrids();
- /*! prepare actual simulation start, setup viz etc */
- virtual bool initializeSolverPostinit();
-
- //! notify object that dump is in progress (e.g. for field dump)
- virtual void notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename);
-
-# if LBM_USE_GUI==1
- //! show simulation info (implement LbmSolverInterface pure virtual func)
- virtual void debugDisplay(int set);
-# endif
-
- // implement CellIterator<UniformFsgrCellIdentifier> interface
- typedef UniformFsgrCellIdentifier stdCellId;
- virtual CellIdentifierInterface* getFirstCell( );
- virtual void advanceCell( CellIdentifierInterface* );
- virtual bool noEndCell( CellIdentifierInterface* );
- virtual void deleteCellIterator( CellIdentifierInterface** );
- virtual CellIdentifierInterface* getCellAt( ntlVec3Gfx pos );
- virtual int getCellSet ( CellIdentifierInterface* );
- virtual ntlVec3Gfx getCellOrigin ( CellIdentifierInterface* );
- virtual ntlVec3Gfx getCellSize ( CellIdentifierInterface* );
- virtual int getCellLevel ( CellIdentifierInterface* );
- virtual LbmFloat getCellDensity ( CellIdentifierInterface* ,int set);
- virtual LbmVec getCellVelocity ( CellIdentifierInterface* ,int set);
- virtual LbmFloat getCellDf ( CellIdentifierInterface* ,int set, int dir);
- virtual LbmFloat getCellMass ( CellIdentifierInterface* ,int set);
- virtual LbmFloat getCellFill ( CellIdentifierInterface* ,int set);
- virtual CellFlagType getCellFlag ( CellIdentifierInterface* ,int set);
- virtual LbmFloat getEquilDf ( int );
- virtual ntlVec3Gfx getVelocityAt (float x, float y, float z);
- // convert pointers
- stdCellId* convertBaseCidToStdCid( CellIdentifierInterface* basecid);
-
- //! perform geometry init (if switched on)
- bool initGeometryFlags();
- //! init part for all freesurface testcases
- void initFreeSurfaces();
- //! init density gradient if enabled
- void initStandingFluidGradient();
-
- /*! init a given cell with flag, density, mass and equilibrium dist. funcs */
- LBM_INLINED void initEmptyCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass);
- LBM_INLINED void initVelocityCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass, LbmVec vel);
- LBM_INLINED void changeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag);
- LBM_INLINED void forceChangeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag);
- LBM_INLINED void initInterfaceVars(int level, int i,int j,int k,int workSet, bool initMass);
- //! interpolate velocity and density at a given position
- void interpolateCellValues(int level,int ei,int ej,int ek,int workSet, LbmFloat &retrho, LbmFloat &retux, LbmFloat &retuy, LbmFloat &retuz);
-
- /*! perform a single LBM step */
- void stepMain();
- //! advance fine grid
- void fineAdvance();
- //! advance coarse grid
- void coarseAdvance(int lev);
- //! update flux area values on coarse grids
- void coarseCalculateFluxareas(int lev);
- // adaptively coarsen grid
- bool adaptGrid(int lev);
- // restrict fine grid DFs to coarse grid
- void coarseRestrictFromFine(int lev);
-
- /* simulation object interface, just calls stepMain */
- virtual void step();
- /*! init particle positions */
- virtual int initParticles();
- /*! move all particles */
- virtual void advanceParticles();
- /*! move a particle at a boundary */
- void handleObstacleParticle(ParticleObject *p);
- /*! check whether to add particle
- bool checkAddParticle();
- void performAddParticle();*/
-
-
- /*! debug object display (used e.g. for preview surface) */
- virtual vector<ntlGeometryObject*> getDebugObjects();
-
- // gui/output debugging functions
-# if LBM_USE_GUI==1
- virtual void debugDisplayNode(int dispset, CellIdentifierInterface* cell );
- virtual void lbmDebugDisplay(int dispset);
- virtual void lbmMarkedCellDisplay();
-# endif // LBM_USE_GUI==1
- virtual void debugPrintNodeInfo(CellIdentifierInterface* cell, int forceSet=-1);
-
- //! for raytracing, preprocess
- void prepareVisualization( void );
-
- /* surface generation settings */
- virtual void setSurfGenSettings(short value);
-
- protected:
-
- //! internal quick print function (for debugging)
- void printLbmCell(int level, int i, int j, int k,int set);
- // debugging use CellIterator interface to mark cell
- void debugMarkCellCall(int level, int vi,int vj,int vk);
-
- // loop over grid, stream&collide update
- void mainLoop(const int lev);
- // change time step size
- void adaptTimestep();
- //! init mObjectSpeeds for current parametrization
- void recalculateObjectSpeeds();
- //! init moving obstacles for next sim step sim
- void initMovingObstacles(bool staticInit);
- //! flag reinit step - always works on finest grid!
- void reinitFlags( int workSet );
- //! mass dist weights
- LbmFloat getMassdWeight(bool dirForw, int i,int j,int k,int workSet, int l);
- //! compute surface normals: fluid, fluid more accurate, and for obstacles
- void computeFluidSurfaceNormal(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret);
- void computeFluidSurfaceNormalAcc(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret);
- void computeObstacleSurfaceNormal(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret);
- void computeObstacleSurfaceNormalAcc(int i,int j,int k, LbmFloat *snret);
- //! add point to mListNewInter list
- LBM_INLINED void addToNewInterList( int ni, int nj, int nk );
- //! cell is interpolated from coarse level (inited into set, source sets are determined by t)
- void interpolateCellFromCoarse(int lev, int i, int j,int k, int dstSet, LbmFloat t, CellFlagType flagSet,bool markNbs);
- void coarseRestrictCell(int lev, int i,int j,int k, int srcSet, int dstSet);
-
- //! minimal and maximal z-coords (for 2D/3D loops)
- LBM_INLINED int getForZMinBnd();
- LBM_INLINED int getForZMin1();
- LBM_INLINED int getForZMaxBnd(int lev);
- LBM_INLINED int getForZMax1(int lev);
- LBM_INLINED bool checkDomainBounds(int lev,int i,int j,int k);
- LBM_INLINED bool checkDomainBoundsPos(int lev,LbmVec pos);
-
- // touch grid and flags once
- void preinitGrids();
- // one relaxation step for standing fluid
- void standingFluidPreinit();
-
-
- // member vars
-
- //! mass calculated during streaming step
- LbmFloat mCurrentMass;
- LbmFloat mCurrentVolume;
- LbmFloat mInitialMass;
-
- //! count problematic cases, that occured so far...
- int mNumProblems;
-
- // average mlsups, count how many so far...
- double mAvgMLSUPS;
- double mAvgMLSUPSCnt;
-
- //! Mcubes object for surface reconstruction
- IsoSurface *mpPreviewSurface;
-
- //! use time adaptivity?
- bool mTimeAdap;
- //! force smaller timestep for next LBM step? (eg for mov obj)
- bool mForceTimeStepReduce;
-
- //! fluid vol height
- LbmFloat mFVHeight;
- LbmFloat mFVArea;
- bool mUpdateFVHeight;
-
- //! force quit for gfx
- LbmFloat mGfxEndTime;
- //! smoother surface initialization?
- int mInitSurfaceSmoothing;
- //! surface generation settings, default is all off (=0)
- // each flag switches side on off, fssgNoObs is for obstacle sides
- // -1 equals all on
- typedef enum {
- fssgNormal = 0,
- fssgNoNorth = 1,
- fssgNoSouth = 2,
- fssgNoEast = 4,
- fssgNoWest = 8,
- fssgNoTop = 16,
- fssgNoBottom = 32,
- fssgNoObs = 64
- } fsSurfaceGen;
- int mFsSurfGenSetting;
-
- //! lock time step down switching
- int mTimestepReduceLock;
- //! count no. of switches
- int mTimeSwitchCounts;
- // only switch of maxvel is higher for several steps...
- int mTimeMaxvelStepCnt;
-
- //! total simulation time so far
- LbmFloat mSimulationTime, mLastSimTime;
- //! smallest and largest step size so far
- LbmFloat mMinTimestep, mMaxTimestep;
- //! track max. velocity
- LbmFloat mMxvx, mMxvy, mMxvz, mMaxVlen;
-
- //! list of the cells to empty at the end of the step
- vector<LbmPoint> mListEmpty;
- //! list of the cells to make fluid at the end of the step
- vector<LbmPoint> mListFull;
- //! list of new interface cells to init
- vector<LbmPoint> mListNewInter;
- //! class for handling redist weights in reinit flag function
- class lbmFloatSet {
- public:
- LbmFloat val[dTotalNum];
- LbmFloat numNbs;
- };
- //! normalized vectors for all neighboring cell directions (for e.g. massdweight calc)
- LbmVec mDvecNrm[27];
-
-
- //! debugging
- bool checkSymmetry(string idstring);
- //! kepp track of max/min no. of filled cells
- int mMaxNoCells, mMinNoCells;
- LONGINT mAvgNumUsedCells;
-
- //! precalculated objects speeds for current parametrization
- vector<LbmVec> mObjectSpeeds;
- //! partslip bc. values for obstacle boundary conditions
- vector<LbmFloat> mObjectPartslips;
- //! moving object mass boundary condition values
- vector<LbmFloat> mObjectMassMovnd;
-
- //! permanent movobj vert storage
- vector<ntlVec3Gfx> mMOIVertices;
- vector<ntlVec3Gfx> mMOIVerticesOld;
- vector<ntlVec3Gfx> mMOINormals;
-
- //! get isofield weights
- int mIsoWeightMethod;
- float mIsoWeight[27];
-
- // grid coarsening vars
-
- /*! vector for the data for each level */
- FsgrLevelData mLevel[FSGR_MAXNOOFLEVELS];
-
- /*! minimal and maximal refinement levels */
- int mMaxRefine;
-
- /*! df scale factors for level up/down */
- LbmFloat mDfScaleUp, mDfScaleDown;
-
- /*! precomputed cell area values */
- LbmFloat mFsgrCellArea[27];
- /*! restriction interpolation weights */
- LbmFloat mGaussw[27];
-
- /*! LES C_smago paramter for finest grid */
- float mInitialCsmago;
- /*! LES stats for non OPT3D */
- LbmFloat mDebugOmegaRet;
- /*! remember last init for animated params */
- LbmFloat mLastOmega;
- LbmVec mLastGravity;
-
- //! fluid stats
- int mNumInterdCells;
- int mNumInvIfCells;
- int mNumInvIfTotal;
- int mNumFsgrChanges;
-
- //! debug function to disable standing f init
- int mDisableStandingFluidInit;
- //! init 2d with skipped Y/Z coords
- bool mInit2dYZ;
- //! debug function to force tadap syncing
- int mForceTadapRefine;
- //! border cutoff value
- int mCutoff;
-
- // strict debug interface
-# if FSGR_STRICT_DEBUG==1
- int debLBMGI(int level, int ii,int ij,int ik, int is);
- CellFlagType& debRFLAG(int level, int xx,int yy,int zz,int set);
- CellFlagType& debRFLAG_NB(int level, int xx,int yy,int zz,int set, int dir);
- CellFlagType& debRFLAG_NBINV(int level, int xx,int yy,int zz,int set, int dir);
- int debLBMQI(int level, int ii,int ij,int ik, int is, int l);
- LbmFloat& debQCELL(int level, int xx,int yy,int zz,int set,int l);
- LbmFloat& debQCELL_NB(int level, int xx,int yy,int zz,int set, int dir,int l);
- LbmFloat& debQCELL_NBINV(int level, int xx,int yy,int zz,int set, int dir,int l);
- LbmFloat* debRACPNT(int level, int ii,int ij,int ik, int is );
- LbmFloat& debRAC(LbmFloat* s,int l);
-# endif // FSGR_STRICT_DEBUG==1
-
- LbmControlData *mpControl;
-
- void initCpdata();
- void handleCpdata();
- void cpDebugDisplay(int dispset);
-
- bool mUseTestdata;
-# if LBM_INCLUDE_TESTSOLVERS==1
- // test functions
- LbmTestdata *mpTest;
- void initTestdata();
- void destroyTestdata();
- void handleTestdata();
- void set3dHeight(int ,int );
-
- int mMpNum,mMpIndex;
- int mOrgSizeX;
- LbmFloat mOrgStartX;
- LbmFloat mOrgEndX;
- void mrSetup();
- void mrExchange();
- void mrIsoExchange();
- LbmFloat mrInitTadap(LbmFloat max);
- void gcFillBuffer( LbmGridConnector *gc, int *retSizeCnt, const int *bdfs);
- void gcUnpackBuffer(LbmGridConnector *gc, int *retSizeCnt, const int *bdfs);
- public:
- // needed for testdata
- void find3dHeight(int i,int j, LbmFloat prev, LbmFloat &ret, LbmFloat *retux, LbmFloat *retuy, LbmFloat *retuz);
- // mptest
- int getMpIndex() { return mMpIndex; };
-# endif // LBM_INCLUDE_TESTSOLVERS==1
-
- // former LbmModelLBGK functions
- // relaxation funtions - implemented together with relax macros
- static inline LbmFloat getVelVecLen(int l, LbmFloat ux,LbmFloat uy,LbmFloat uz);
- static inline LbmFloat getCollideEq(int l, LbmFloat rho, LbmFloat ux, LbmFloat uy, LbmFloat uz);
- inline LbmFloat getLesNoneqTensorCoeff( LbmFloat df[], LbmFloat feq[] );
- inline LbmFloat getLesOmega(LbmFloat omega, LbmFloat csmago, LbmFloat Qo);
- inline void collideArrays( int lev, int i, int j, int k, // position - more for debugging
- LbmFloat df[], LbmFloat &outrho, // out only!
- // velocity modifiers (returns actual velocity!)
- LbmFloat &mux, LbmFloat &muy, LbmFloat &muz,
- LbmFloat omega, LbmVec gravity, LbmFloat csmago,
- LbmFloat *newOmegaRet, LbmFloat *newQoRet);
-
-
- // former LBM models
- //! shorten static const definitions
-# define STCON static const
-
-# if LBMDIM==3
-
- //! id string of solver
- virtual string getIdString() { return string("FreeSurfaceFsgrSolver[BGK_D3Q19]"); }
-
- //! how many dimensions? UNUSED? replace by LBMDIM?
- STCON int cDimension;
-
- // Wi factors for collide step
- STCON LbmFloat cCollenZero;
- STCON LbmFloat cCollenOne;
- STCON LbmFloat cCollenSqrtTwo;
-
- //! threshold value for filled/emptied cells
- STCON LbmFloat cMagicNr2;
- STCON LbmFloat cMagicNr2Neg;
- STCON LbmFloat cMagicNr;
- STCON LbmFloat cMagicNrNeg;
-
- //! size of a single set of distribution functions
- STCON int cDfNum;
- //! direction vector contain vecs for all spatial dirs, even if not used for LBM model
- STCON int cDirNum;
-
- //! distribution functions directions
- typedef enum {
- cDirInv= -1,
- cDirC = 0,
- cDirN = 1,
- cDirS = 2,
- cDirE = 3,
- cDirW = 4,
- cDirT = 5,
- cDirB = 6,
- cDirNE = 7,
- cDirNW = 8,
- cDirSE = 9,
- cDirSW = 10,
- cDirNT = 11,
- cDirNB = 12,
- cDirST = 13,
- cDirSB = 14,
- cDirET = 15,
- cDirEB = 16,
- cDirWT = 17,
- cDirWB = 18
- } dfDir;
-
- /* Vector Order 3D:
- * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
- * 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1
- * 0, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1
- * 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1
- */
-
- /*! name of the dist. function
- only for nicer output */
- STCON char* dfString[ 19 ];
-
- /*! index of normal dist func, not used so far?... */
- STCON int dfNorm[ 19 ];
-
- /*! index of inverse dist func, not fast, but useful... */
- STCON int dfInv[ 19 ];
-
- /*! index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefX[ 19 ];
- /*! index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefY[ 19 ];
- /*! index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefZ[ 19 ];
-
- /*! dist func vectors */
- STCON int dfVecX[ 27 ];
- STCON int dfVecY[ 27 ];
- STCON int dfVecZ[ 27 ];
-
- /*! arrays as before with doubles */
- STCON LbmFloat dfDvecX[ 27 ];
- STCON LbmFloat dfDvecY[ 27 ];
- STCON LbmFloat dfDvecZ[ 27 ];
-
- /*! principal directions */
- STCON int princDirX[ 2*3 ];
- STCON int princDirY[ 2*3 ];
- STCON int princDirZ[ 2*3 ];
-
- /*! vector lengths */
- STCON LbmFloat dfLength[ 19 ];
-
- /*! equilibrium distribution functions, precalculated = getCollideEq(i, 0,0,0,0) */
- static LbmFloat dfEquil[ dTotalNum ];
-
- /*! arrays for les model coefficients */
- static LbmFloat lesCoeffDiag[ (3-1)*(3-1) ][ 27 ];
- static LbmFloat lesCoeffOffdiag[ 3 ][ 27 ];
-
-# else // end LBMDIM==3 , LBMDIM==2
-
- //! id string of solver
- virtual string getIdString() { return string("FreeSurfaceFsgrSolver[BGK_D2Q9]"); }
-
- //! how many dimensions?
- STCON int cDimension;
-
- //! Wi factors for collide step
- STCON LbmFloat cCollenZero;
- STCON LbmFloat cCollenOne;
- STCON LbmFloat cCollenSqrtTwo;
-
- //! threshold value for filled/emptied cells
- STCON LbmFloat cMagicNr2;
- STCON LbmFloat cMagicNr2Neg;
- STCON LbmFloat cMagicNr;
- STCON LbmFloat cMagicNrNeg;
-
- //! size of a single set of distribution functions
- STCON int cDfNum;
- STCON int cDirNum;
-
- //! distribution functions directions
- typedef enum {
- cDirInv= -1,
- cDirC = 0,
- cDirN = 1,
- cDirS = 2,
- cDirE = 3,
- cDirW = 4,
- cDirNE = 5,
- cDirNW = 6,
- cDirSE = 7,
- cDirSW = 8
- } dfDir;
-
- /* Vector Order 2D:
- * 0 1 2 3 4 5 6 7 8
- * 0, 0,0, 1,-1, 1,-1,1,-1
- * 0, 1,-1, 0,0, 1,1,-1,-1 */
-
- /* name of the dist. function
- only for nicer output */
- STCON char* dfString[ 9 ];
-
- /* index of normal dist func, not used so far?... */
- STCON int dfNorm[ 9 ];
-
- /* index of inverse dist func, not fast, but useful... */
- STCON int dfInv[ 9 ];
-
- /* index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefX[ 9 ];
- /* index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefY[ 9 ];
- /* index of x reflected dist func for free slip, not valid for all DFs... */
- STCON int dfRefZ[ 9 ];
-
- /* dist func vectors */
- STCON int dfVecX[ 9 ];
- STCON int dfVecY[ 9 ];
- /* Z, 2D values are all 0! */
- STCON int dfVecZ[ 9 ];
-
- /* arrays as before with doubles */
- STCON LbmFloat dfDvecX[ 9 ];
- STCON LbmFloat dfDvecY[ 9 ];
- /* Z, 2D values are all 0! */
- STCON LbmFloat dfDvecZ[ 9 ];
-
- /*! principal directions */
- STCON int princDirX[ 2*2 ];
- STCON int princDirY[ 2*2 ];
- STCON int princDirZ[ 2*2 ];
-
- /* vector lengths */
- STCON LbmFloat dfLength[ 9 ];
-
- /* equilibrium distribution functions, precalculated = getCollideEq(i, 0,0,0,0) */
- static LbmFloat dfEquil[ dTotalNum ];
-
- /*! arrays for les model coefficients */
- static LbmFloat lesCoeffDiag[ (2-1)*(2-1) ][ 9 ];
- static LbmFloat lesCoeffOffdiag[ 2 ][ 9 ];
-
-# endif // LBMDIM==2
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:LbmFsgrSolver")
-#endif
-};
-
-#undef STCON
-
-
-/*****************************************************************************/
-// relaxation_macros
-
-
-
-// cell mark debugging
-#if FSGR_STRICT_DEBUG==10
-#define debugMarkCell(lev,x,y,z) \
- errMsg("debugMarkCell",this->mName<<" step: "<<this->mStepCnt<<" lev:"<<(lev)<<" marking "<<PRINT_VEC((x),(y),(z))<<" line "<< __LINE__ ); \
- debugMarkCellCall((lev),(x),(y),(z));
-#else // FSGR_STRICT_DEBUG==1
-#define debugMarkCell(lev,x,y,z) \
- debugMarkCellCall((lev),(x),(y),(z));
-#endif // FSGR_STRICT_DEBUG==1
-
-
-// flag array defines -----------------------------------------------------------------------------------------------
-
-// lbm testsolver get index define, note - ignores is (set) as flag
-// array is only a single entry
-#define _LBMGI(level, ii,ij,ik, is) ( (LONGINT)((LONGINT)mLevel[level].lOffsy*(LONGINT)(ik)) + ((LONGINT)mLevel[level].lOffsx*(LONGINT)(ij)) + (LONGINT)(ii) )
-
-//! flag array acces macro
-#define _RFLAG(level,xx,yy,zz,set) mLevel[level].mprsFlags[set][ (LONGINT)LBMGI((level),(xx),(yy),(zz),(set)) ]
-#define _RFLAG_NB(level,xx,yy,zz,set, dir) mLevel[level].mprsFlags[set][ (LONGINT)LBMGI((level),(xx)+this->dfVecX[dir],(yy)+this->dfVecY[dir],(zz)+this->dfVecZ[dir],set) ]
-#define _RFLAG_NBINV(level,xx,yy,zz,set, dir) mLevel[level].mprsFlags[set][ (LONGINT)LBMGI((level),(xx)+this->dfVecX[this->dfInv[dir]],(yy)+this->dfVecY[this->dfInv[dir]],(zz)+this->dfVecZ[this->dfInv[dir]],set) ]
-
-// array handling -----------------------------------------------------------------------------------------------
-
-#define _LBMQI(level, ii,ij,ik, is, lunused) ( (LONGINT)((LONGINT)mLevel[level].lOffsy*(LONGINT)(ik)) + (LONGINT)((LONGINT)mLevel[level].lOffsx*(LONGINT)(ij)) + (LONGINT)(ii) )
-#define _QCELL(level,xx,yy,zz,set,l) (mLevel[level].mprsCells[(set)][ (LONGINT)LBMQI((level),(xx),(yy),(zz),(set), l)*(LONGINT)dTotalNum +(LONGINT)(l)])
-#define _QCELL_NB(level,xx,yy,zz,set, dir,l) (mLevel[level].mprsCells[(set)][ (LONGINT)LBMQI((level),(xx)+this->dfVecX[dir],(yy)+this->dfVecY[dir],(zz)+this->dfVecZ[dir],set, l)*dTotalNum +(l)])
-#define _QCELL_NBINV(level,xx,yy,zz,set, dir,l) (mLevel[level].mprsCells[(set)][ (LONGINT)LBMQI((level),(xx)+this->dfVecX[this->dfInv[dir]],(yy)+this->dfVecY[this->dfInv[dir]],(zz)+this->dfVecZ[this->dfInv[dir]],set, l)*dTotalNum +(l)])
-
-#define QCELLSTEP dTotalNum
-#define _RACPNT(level, ii,ij,ik, is ) &QCELL(level,ii,ij,ik,is,0)
-#define _RAC(s,l) (s)[(l)]
-
-
-#if FSGR_STRICT_DEBUG==1
-
-#define LBMGI(level,ii,ij,ik, is) debLBMGI(level,ii,ij,ik, is)
-#define RFLAG(level,xx,yy,zz,set) debRFLAG(level,xx,yy,zz,set)
-#define RFLAG_NB(level,xx,yy,zz,set, dir) debRFLAG_NB(level,xx,yy,zz,set, dir)
-#define RFLAG_NBINV(level,xx,yy,zz,set, dir) debRFLAG_NBINV(level,xx,yy,zz,set, dir)
-
-#define LBMQI(level,ii,ij,ik, is, l) debLBMQI(level,ii,ij,ik, is, l)
-#define QCELL(level,xx,yy,zz,set,l) debQCELL(level,xx,yy,zz,set,l)
-#define QCELL_NB(level,xx,yy,zz,set, dir,l) debQCELL_NB(level,xx,yy,zz,set, dir,l)
-#define QCELL_NBINV(level,xx,yy,zz,set, dir,l) debQCELL_NBINV(level,xx,yy,zz,set, dir,l)
-#define RACPNT(level, ii,ij,ik, is ) debRACPNT(level, ii,ij,ik, is )
-#define RAC(s,l) debRAC(s,l)
-
-#else // FSGR_STRICT_DEBUG==1
-
-#define LBMGI(level,ii,ij,ik, is) _LBMGI(level,ii,ij,ik, is)
-#define RFLAG(level,xx,yy,zz,set) _RFLAG(level,xx,yy,zz,set)
-#define RFLAG_NB(level,xx,yy,zz,set, dir) _RFLAG_NB(level,xx,yy,zz,set, dir)
-#define RFLAG_NBINV(level,xx,yy,zz,set, dir) _RFLAG_NBINV(level,xx,yy,zz,set, dir)
-
-#define LBMQI(level,ii,ij,ik, is, l) _LBMQI(level,ii,ij,ik, is, l)
-#define QCELL(level,xx,yy,zz,set,l) _QCELL(level,xx,yy,zz,set,l)
-#define QCELL_NB(level,xx,yy,zz,set, dir,l) _QCELL_NB(level,xx,yy,zz,set, dir, l)
-#define QCELL_NBINV(level,xx,yy,zz,set, dir,l) _QCELL_NBINV(level,xx,yy,zz,set, dir,l)
-#define RACPNT(level, ii,ij,ik, is ) _RACPNT(level, ii,ij,ik, is )
-#define RAC(s,l) _RAC(s,l)
-
-#endif // FSGR_STRICT_DEBUG==1
-
-// general defines -----------------------------------------------------------------------------------------------
-
-// replace TESTFLAG
-#define FLAGISEXACT(flag, compflag) ((flag & compflag)==compflag)
-
-#if LBMDIM==2
-#define dC 0
-#define dN 1
-#define dS 2
-#define dE 3
-#define dW 4
-#define dNE 5
-#define dNW 6
-#define dSE 7
-#define dSW 8
-#else
-// direction indices
-#define dC 0
-#define dN 1
-#define dS 2
-#define dE 3
-#define dW 4
-#define dT 5
-#define dB 6
-#define dNE 7
-#define dNW 8
-#define dSE 9
-#define dSW 10
-#define dNT 11
-#define dNB 12
-#define dST 13
-#define dSB 14
-#define dET 15
-#define dEB 16
-#define dWT 17
-#define dWB 18
-#endif
-//? #define dWB 18
-
-// default init for dFlux values
-#define FLUX_INIT 0.5f * (float)(this->cDfNum)
-
-// only for non DF dir handling!
-#define dNET 19
-#define dNWT 20
-#define dSET 21
-#define dSWT 22
-#define dNEB 23
-#define dNWB 24
-#define dSEB 25
-#define dSWB 26
-
-//! fill value for boundary cells
-#define BND_FILL 0.0
-
-#define DFL1 (1.0/ 3.0)
-#define DFL2 (1.0/18.0)
-#define DFL3 (1.0/36.0)
-
-// loops over _all_ cells (including boundary layer)
-#define FSGR_FORIJK_BOUNDS(leveli) \
- for(int k= getForZMinBnd(); k< getForZMaxBnd(leveli); ++k) \
- for(int j=0;j<mLevel[leveli].lSizey-0;++j) \
- for(int i=0;i<mLevel[leveli].lSizex-0;++i) \
-
-// loops over _only inner_ cells
-#define FSGR_FORIJK1(leveli) \
- for(int k= getForZMin1(); k< getForZMax1(leveli); ++k) \
- for(int j=1;j<mLevel[leveli].lSizey-1;++j) \
- for(int i=1;i<mLevel[leveli].lSizex-1;++i) \
-
-// relaxation_macros end
-
-
-
-/******************************************************************************/
-/*! equilibrium functions */
-/******************************************************************************/
-
-/*! calculate length of velocity vector */
-inline LbmFloat LbmFsgrSolver::getVelVecLen(int l, LbmFloat ux,LbmFloat uy,LbmFloat uz) {
- return ((ux)*dfDvecX[l]+(uy)*dfDvecY[l]+(uz)*dfDvecZ[l]);
-};
-
-/*! calculate equilibrium DF for given values */
-inline LbmFloat LbmFsgrSolver::getCollideEq(int l, LbmFloat rho, LbmFloat ux, LbmFloat uy, LbmFloat uz) {
-#if FSGR_STRICT_DEBUG==1
- if((l<0)||(l>LBM_DFNUM)) { errFatal("LbmFsgrSolver::getCollideEq","Invalid DFEQ call "<<l, SIMWORLD_PANIC ); /* no access to mPanic here */ }
-#endif // FSGR_STRICT_DEBUG==1
- LbmFloat tmp = getVelVecLen(l,ux,uy,uz);
- return( dfLength[l] *(
- + rho - (3.0/2.0*(ux*ux + uy*uy + uz*uz))
- + 3.0 *tmp
- + 9.0/2.0 *(tmp*tmp) )
- ); // */
-};
-
-/*****************************************************************************/
-/* init a given cell with flag, density, mass and equilibrium dist. funcs */
-
-void LbmFsgrSolver::forceChangeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag) {
- // also overwrite persisting flags
- // function is useful for tracking accesses...
- RFLAG(level,xx,yy,zz,set) = newflag;
-}
-void LbmFsgrSolver::changeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag) {
- CellFlagType pers = RFLAG(level,xx,yy,zz,set) & CFPersistMask;
- RFLAG(level,xx,yy,zz,set) = newflag | pers;
-}
-
-void
-LbmFsgrSolver::initEmptyCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass) {
- /* init eq. dist funcs */
- LbmFloat *ecel;
- int workSet = mLevel[level].setCurr;
-
- ecel = RACPNT(level, i,j,k, workSet);
- FORDF0 { RAC(ecel, l) = this->dfEquil[l] * rho; }
- RAC(ecel, dMass) = mass;
- RAC(ecel, dFfrac) = mass/rho;
- RAC(ecel, dFlux) = FLUX_INIT;
- changeFlag(level, i,j,k, workSet, flag);
-
- workSet ^= 1;
- changeFlag(level, i,j,k, workSet, flag);
- return;
-}
-
-void
-LbmFsgrSolver::initVelocityCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass, LbmVec vel) {
- LbmFloat *ecel;
- int workSet = mLevel[level].setCurr;
-
- ecel = RACPNT(level, i,j,k, workSet);
- FORDF0 { RAC(ecel, l) = getCollideEq(l, rho,vel[0],vel[1],vel[2]); }
- RAC(ecel, dMass) = mass;
- RAC(ecel, dFfrac) = mass/rho;
- RAC(ecel, dFlux) = FLUX_INIT;
- changeFlag(level, i,j,k, workSet, flag);
-
- workSet ^= 1;
- changeFlag(level, i,j,k, workSet, flag);
- return;
-}
-
-int LbmFsgrSolver::getForZMinBnd() {
- return 0;
-}
-int LbmFsgrSolver::getForZMin1() {
- if(LBMDIM==2) return 0;
- return 1;
-}
-
-int LbmFsgrSolver::getForZMaxBnd(int lev) {
- if(LBMDIM==2) return 1;
- return mLevel[lev].lSizez -0;
-}
-int LbmFsgrSolver::getForZMax1(int lev) {
- if(LBMDIM==2) return 1;
- return mLevel[lev].lSizez -1;
-}
-
-bool LbmFsgrSolver::checkDomainBounds(int lev,int i,int j,int k) {
- if(i<0) return false;
- if(j<0) return false;
- if(k<0) return false;
- if(i>mLevel[lev].lSizex-1) return false;
- if(j>mLevel[lev].lSizey-1) return false;
- if(k>mLevel[lev].lSizez-1) return false;
- return true;
-}
-bool LbmFsgrSolver::checkDomainBoundsPos(int lev,LbmVec pos) {
- const int i= (int)pos[0];
- if(i<0) return false;
- if(i>mLevel[lev].lSizex-1) return false;
- const int j= (int)pos[1];
- if(j<0) return false;
- if(j>mLevel[lev].lSizey-1) return false;
- const int k= (int)pos[2];
- if(k<0) return false;
- if(k>mLevel[lev].lSizez-1) return false;
- return true;
-}
-
-void LbmFsgrSolver::initInterfaceVars(int level, int i,int j,int k,int workSet, bool initMass) {
- LbmFloat *ccel = &QCELL(level ,i,j,k, workSet,0);
- LbmFloat nrho = 0.0;
- FORDF0 { nrho += RAC(ccel,l); }
- if(initMass) {
- RAC(ccel,dMass) = nrho;
- RAC(ccel, dFfrac) = 1.;
- } else {
- // preinited, e.g. from reinitFlags
- RAC(ccel, dFfrac) = RAC(ccel, dMass)/nrho;
- RAC(ccel, dFlux) = FLUX_INIT;
- }
-}
-
-
-#endif
-
-
diff --git a/intern/elbeem/intern/solver_control.cpp b/intern/elbeem/intern/solver_control.cpp
deleted file mode 100644
index 7064dba8e22..00000000000
--- a/intern/elbeem/intern/solver_control.cpp
+++ /dev/null
@@ -1,876 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - the visual lattice boltzmann freesurface simulator
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- *
- * Copyright 2003-2008 Nils Thuerey
- *
- * control extensions
- *
- *****************************************************************************/
-#include "solver_class.h"
-#include "solver_relax.h"
-#include "particletracer.h"
-
-#include "solver_control.h"
-
-#include "controlparticles.h"
-
-#include "elbeem.h"
-
-#include "ntl_geometrymodel.h"
-
-/******************************************************************************
- * LbmControlData control set
- *****************************************************************************/
-
-LbmControlSet::LbmControlSet() :
- mCparts(NULL), mCpmotion(NULL), mContrPartFile(""), mCpmotionFile(""),
- mcForceAtt(0.), mcForceVel(0.), mcForceMaxd(0.),
- mcRadiusAtt(0.), mcRadiusVel(0.), mcRadiusMind(0.), mcRadiusMaxd(0.),
- mcCpScale(1.), mcCpOffset(0.)
-{
-}
-LbmControlSet::~LbmControlSet() {
- if(mCparts) delete mCparts;
- if(mCpmotion) delete mCpmotion;
-}
-void LbmControlSet::initCparts() {
- mCparts = new ControlParticles();
- mCpmotion = new ControlParticles();
-}
-
-
-
-/******************************************************************************
- * LbmControlData control
- *****************************************************************************/
-
-LbmControlData::LbmControlData() :
- mSetForceStrength(0.),
- mCons(),
- mCpUpdateInterval(8), // DG: was 16 --> causes problems (big sphere after some time), unstable
- mCpOutfile(""),
- mCpForces(), mCpKernel(), mMdKernel(),
- mDiffVelCon(1.),
- mDebugCpscale(0.),
- mDebugVelScale(0.),
- mDebugCompavScale(0.),
- mDebugAttScale(0.),
- mDebugMaxdScale(0.),
- mDebugAvgVelScale(0.)
-{
-}
-
-LbmControlData::~LbmControlData()
-{
- while (!mCons.empty()) {
- delete mCons.back(); mCons.pop_back();
- }
-}
-
-
-void LbmControlData::parseControldataAttrList(AttributeList *attr) {
- // controlpart vars
- mSetForceStrength = attr->readFloat("tforcestrength", mSetForceStrength,"LbmControlData", "mSetForceStrength", false);
- //errMsg("tforcestrength set to "," "<<mSetForceStrength);
- mCpUpdateInterval = attr->readInt("controlparticle_updateinterval", mCpUpdateInterval,"LbmControlData","mCpUpdateInterval", false);
- // tracer output file
- mCpOutfile = attr->readString("controlparticle_outfile",mCpOutfile,"LbmControlData","mCpOutfile", false);
- if(getenv("ELBEEM_CPOUTFILE")) {
- string outfile(getenv("ELBEEM_CPOUTFILE"));
- mCpOutfile = outfile;
- debMsgStd("LbmControlData::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_CPOUTFILE to set mCpOutfile to "<<outfile<<","<<mCpOutfile,7);
- }
-
- for(int cpii=0; cpii<10; cpii++) {
- string suffix("");
- //if(cpii>0)
- { suffix = string("0"); suffix[0]+=cpii; }
- LbmControlSet *cset;
- cset = new LbmControlSet();
- cset->initCparts();
-
- cset->mContrPartFile = attr->readString("controlparticle"+suffix+"_file",cset->mContrPartFile,"LbmControlData","cset->mContrPartFile", false);
- if((cpii==0) && (getenv("ELBEEM_CPINFILE")) ) {
- string infile(getenv("ELBEEM_CPINFILE"));
- cset->mContrPartFile = infile;
- debMsgStd("LbmControlData::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_CPINFILE to set mContrPartFile to "<<infile<<","<<cset->mContrPartFile,7);
- }
-
- LbmFloat cpvort=0.;
- cset->mcRadiusAtt = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusatt", 0., "LbmControlData","mcRadiusAtt" );
- cset->mcRadiusVel = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusvel", 0., "LbmControlData","mcRadiusVel" );
- cset->mcRadiusVel = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusvel", 0., "LbmControlData","mcRadiusVel" );
- cset->mCparts->setRadiusAtt(cset->mcRadiusAtt.get(0.));
- cset->mCparts->setRadiusVel(cset->mcRadiusVel.get(0.));
-
- // WARNING currently only for first set
- //if(cpii==0) {
- cset->mcForceAtt = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_attraction", 0. , "LbmControlData","cset->mcForceAtt", false);
- cset->mcForceVel = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_velocity", 0. , "LbmControlData","mcForceVel", false);
- cset->mcForceMaxd = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_maxdist", 0. , "LbmControlData","mcForceMaxd", false);
- cset->mCparts->setInfluenceAttraction(cset->mcForceAtt.get(0.) );
- // warning - stores temprorarily, value converted to dt dep. factor
- cset->mCparts->setInfluenceVelocity(cset->mcForceVel.get(0.) , 0.01 ); // dummy dt
- cset->mCparts->setInfluenceMaxdist(cset->mcForceMaxd.get(0.) );
- cpvort = attr->readFloat("controlparticle"+suffix+"_vorticity", cpvort, "LbmControlData","cpvort", false);
- cset->mCparts->setInfluenceTangential(cpvort);
-
- cset->mcRadiusMind = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusmin", cset->mcRadiusMind.get(0.), "LbmControlData","mcRadiusMind", false);
- cset->mcRadiusMaxd = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusmax", cset->mcRadiusMind.get(0.), "LbmControlData","mcRadiusMaxd", false);
- cset->mCparts->setRadiusMinMaxd(cset->mcRadiusMind.get(0.));
- cset->mCparts->setRadiusMaxd(cset->mcRadiusMaxd.get(0.));
- //}
-
- // now local...
- //LbmVec cpOffset(0.), cpScale(1.);
- LbmFloat cpTimescale = 1.;
- string cpMirroring("");
-
- //cset->mcCpOffset = attr->readChannelVec3f("controlparticle"+suffix+"_offset", ntlVec3f(0.),"LbmControlData","mcCpOffset", false);
- //cset->mcCpScale = attr->readChannelVec3f("controlparticle"+suffix+"_scale", ntlVec3f(1.), "LbmControlData","mcCpScale", false);
- cset->mcCpOffset = attr->readChannelVec3f("controlparticle"+suffix+"_offset", ntlVec3f(0.),"LbmControlData","mcCpOffset", false);
- cset->mcCpScale = attr->readChannelVec3f("controlparticle"+suffix+"_scale", ntlVec3f(1.), "LbmControlData","mcCpScale", false);
- cpTimescale = attr->readFloat("controlparticle"+suffix+"_timescale", cpTimescale, "LbmControlData","cpTimescale", false);
- cpMirroring = attr->readString("controlparticle"+suffix+"_mirror", cpMirroring, "LbmControlData","cpMirroring", false);
-
- LbmFloat cpsWidth = cset->mCparts->getCPSWith();
- cpsWidth = attr->readFloat("controlparticle"+suffix+"_cpswidth", cpsWidth, "LbmControlData","cpsWidth", false);
- LbmFloat cpsDt = cset->mCparts->getCPSTimestep();
- cpsDt = attr->readFloat("controlparticle"+suffix+"_cpstimestep", cpsDt, "LbmControlData","cpsDt", false);
- LbmFloat cpsTstart = cset->mCparts->getCPSTimeStart();
- cpsTstart = attr->readFloat("controlparticle"+suffix+"_cpststart", cpsTstart, "LbmControlData","cpsTstart", false);
- LbmFloat cpsTend = cset->mCparts->getCPSTimeEnd();
- cpsTend = attr->readFloat("controlparticle"+suffix+"_cpstend", cpsTend, "LbmControlData","cpsTend", false);
- LbmFloat cpsMvmfac = cset->mCparts->getCPSMvmWeightFac();
- cpsMvmfac = attr->readFloat("controlparticle"+suffix+"_cpsmvmfac", cpsMvmfac, "LbmControlData","cpsMvmfac", false);
- cset->mCparts->setCPSWith(cpsWidth);
- cset->mCparts->setCPSTimestep(cpsDt);
- cset->mCparts->setCPSTimeStart(cpsTstart);
- cset->mCparts->setCPSTimeEnd(cpsTend);
- cset->mCparts->setCPSMvmWeightFac(cpsMvmfac);
-
- cset->mCparts->setOffset( vec2L(cset->mcCpOffset.get(0.)) );
- cset->mCparts->setScale( vec2L(cset->mcCpScale.get(0.)) );
- cset->mCparts->setInitTimeScale( cpTimescale );
- cset->mCparts->setInitMirror( cpMirroring );
-
- int mDebugInit = 0;
- mDebugInit = attr->readInt("controlparticle"+suffix+"_debuginit", mDebugInit,"LbmControlData","mDebugInit", false);
- cset->mCparts->setDebugInit(mDebugInit);
-
- // motion particle settings
- LbmVec mcpOffset(0.), mcpScale(1.);
- LbmFloat mcpTimescale = 1.;
- string mcpMirroring("");
-
- cset->mCpmotionFile = attr->readString("cpmotion"+suffix+"_file",cset->mCpmotionFile,"LbmControlData","mCpmotionFile", false);
- mcpTimescale = attr->readFloat("cpmotion"+suffix+"_timescale", mcpTimescale, "LbmControlData","mcpTimescale", false);
- mcpMirroring = attr->readString("cpmotion"+suffix+"_mirror", mcpMirroring, "LbmControlData","mcpMirroring", false);
- mcpOffset = vec2L( attr->readVec3d("cpmotion"+suffix+"_offset", vec2P(mcpOffset),"LbmControlData","cpOffset", false) );
- mcpScale = vec2L( attr->readVec3d("cpmotion"+suffix+"_scale", vec2P(mcpScale), "LbmControlData","cpScale", false) );
-
- cset->mCpmotion->setOffset( vec2L(mcpOffset) );
- cset->mCpmotion->setScale( vec2L(mcpScale) );
- cset->mCpmotion->setInitTimeScale( mcpTimescale );
- cset->mCpmotion->setInitMirror( mcpMirroring );
-
- if(cset->mContrPartFile.length()>1) {
- errMsg("LbmControlData","Using control particle set "<<cpii<<" file:"<<cset->mContrPartFile<<" cpmfile:"<<cset->mCpmotionFile<<" mirr:'"<<cset->mCpmotion->getInitMirror()<<"' " );
- mCons.push_back( cset );
- } else {
- delete cset;
- }
- }
-
- // debug, testing - make sure theres at least an empty set
- if(mCons.size()<1) {
- mCons.push_back( new LbmControlSet() );
- mCons[0]->initCparts();
- }
-
- // take from first set
- for(int cpii=1; cpii<(int)mCons.size(); cpii++) {
- mCons[cpii]->mCparts->setRadiusMinMaxd( mCons[0]->mCparts->getRadiusMinMaxd() );
- mCons[cpii]->mCparts->setRadiusMaxd( mCons[0]->mCparts->getRadiusMaxd() );
- mCons[cpii]->mCparts->setInfluenceAttraction( mCons[0]->mCparts->getInfluenceAttraction() );
- mCons[cpii]->mCparts->setInfluenceTangential( mCons[0]->mCparts->getInfluenceTangential() );
- mCons[cpii]->mCparts->setInfluenceVelocity( mCons[0]->mCparts->getInfluenceVelocity() , 0.01 ); // dummy dt
- mCons[cpii]->mCparts->setInfluenceMaxdist( mCons[0]->mCparts->getInfluenceMaxdist() );
- }
-
- // invert for usage in relax macro
- mDiffVelCon = 1.-attr->readFloat("cpdiffvelcon", mDiffVelCon, "LbmControlData","mDiffVelCon", false);
-
- mDebugCpscale = attr->readFloat("cpdebug_cpscale", mDebugCpscale, "LbmControlData","mDebugCpscale", false);
- mDebugMaxdScale = attr->readFloat("cpdebug_maxdscale", mDebugMaxdScale, "LbmControlData","mDebugMaxdScale", false);
- mDebugAttScale = attr->readFloat("cpdebug_attscale", mDebugAttScale, "LbmControlData","mDebugAttScale", false);
- mDebugVelScale = attr->readFloat("cpdebug_velscale", mDebugVelScale, "LbmControlData","mDebugVelScale", false);
- mDebugCompavScale = attr->readFloat("cpdebug_compavscale", mDebugCompavScale, "LbmControlData","mDebugCompavScale", false);
- mDebugAvgVelScale = attr->readFloat("cpdebug_avgvelsc", mDebugAvgVelScale, "LbmControlData","mDebugAvgVelScale", false);
-}
-
-
-void
-LbmFsgrSolver::initCpdata()
-{
- // enable for cps via env. vars
- //if( (getenv("ELBEEM_CPINFILE")) || (getenv("ELBEEM_CPOUTFILE")) ){ mUseTestdata=1; }
-
-
- // manually switch on! if this is zero, nothing is done...
- mpControl->mSetForceStrength = this->mTForceStrength = 1.;
- while (!mpControl->mCons.empty()) {
- delete mpControl->mCons.back(); mpControl->mCons.pop_back();
- }
-
-
- // init all control fluid objects
- int numobjs = (int)(mpGiObjects->size());
- for(int o=0; o<numobjs; o++) {
- ntlGeometryObjModel *obj = (ntlGeometryObjModel *)(*mpGiObjects)[o];
- if(obj->getGeoInitType() & FGI_CONTROL) {
- // add new control set per object
- LbmControlSet *cset;
-
- cset = new LbmControlSet();
- cset->initCparts();
-
- // dont load any file
- cset->mContrPartFile = string("");
-
- cset->mcForceAtt = obj->getCpsAttrFStr();
- cset->mcRadiusAtt = obj->getCpsAttrFRad();
- cset->mcForceVel = obj->getCpsVelFStr();
- cset->mcRadiusVel = obj->getCpsVelFRad();
-
- cset->mCparts->setCPSTimeStart(obj->getCpsTimeStart());
- cset->mCparts->setCPSTimeEnd(obj->getCpsTimeEnd());
-
- if(obj->getCpsQuality() > LBM_EPSILON)
- cset->mCparts->setCPSWith(1.0 / obj->getCpsQuality());
-
- // this value can be left at 0.5:
- cset->mCparts->setCPSMvmWeightFac(0.5);
-
- mpControl->mCons.push_back( cset );
- mpControl->mCons[mpControl->mCons.size()-1]->mCparts->initFromObject(obj);
- }
- }
-
- // NT blender integration manual test setup
- if(0) {
- // manually switch on! if this is zero, nothing is done...
- mpControl->mSetForceStrength = this->mTForceStrength = 1.;
- while (!mpControl->mCons.empty()) {
- delete mpControl->mCons.back(); mpControl->mCons.pop_back();
- }
-
- // add new set
- LbmControlSet *cset;
-
- cset = new LbmControlSet();
- cset->initCparts();
- // dont load any file
- cset->mContrPartFile = string("");
-
- // set radii for attraction & velocity forces
- // set strength of the forces
- // don't set directly! but use channels:
- // mcForceAtt, mcForceVel, mcForceMaxd, mcRadiusAtt, mcRadiusVel, mcRadiusMind, mcRadiusMaxd etc.
-
- // wrong: cset->mCparts->setInfluenceAttraction(1.15); cset->mCparts->setRadiusAtt(1.5);
- // right, e.g., to init some constant values:
- cset->mcForceAtt = AnimChannel<float>(0.2);
- cset->mcRadiusAtt = AnimChannel<float>(0.75);
- cset->mcForceVel = AnimChannel<float>(0.2);
- cset->mcRadiusVel = AnimChannel<float>(0.75);
-
- // this value can be left at 0.5:
- cset->mCparts->setCPSMvmWeightFac(0.5);
-
- mpControl->mCons.push_back( cset );
-
- // instead of reading from file (cset->mContrPartFile), manually init some particles
- mpControl->mCons[0]->mCparts->initBlenderTest();
-
- // other values that might be interesting to change:
- //cset->mCparts->setCPSTimestep(0.02);
- //cset->mCparts->setCPSTimeStart(0.);
- //cset->mCparts->setCPSTimeEnd(1.);
-
- //mpControl->mDiffVelCon = 1.; // more rigid velocity control, 0 (default) allows more turbulence
- }
-
- // control particle -------------------------------------------------------------------------------------
-
- // init cppf stage, use set 0!
- if(mCppfStage>0) {
- if(mpControl->mCpOutfile.length()<1) mpControl->mCpOutfile = string("cpout"); // use getOutFilename !?
- char strbuf[100];
- const char *cpFormat = "_d%dcppf%d";
-
- // initial coarse stage, no input
- if(mCppfStage==1) {
- mpControl->mCons[0]->mContrPartFile = "";
- } else {
- // read from prev stage
- snprintf(strbuf,100, cpFormat ,LBMDIM,mCppfStage-1);
- mpControl->mCons[0]->mContrPartFile = mpControl->mCpOutfile;
- mpControl->mCons[0]->mContrPartFile += strbuf;
- mpControl->mCons[0]->mContrPartFile += ".cpart2";
- }
-
- snprintf(strbuf,100, cpFormat ,LBMDIM,mCppfStage);
- mpControl->mCpOutfile += strbuf;
- } // */
-
- for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
- ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion;
-
- // now set with real dt
- cparts->setInfluenceVelocity( mpControl->mCons[cpssi]->mcForceVel.get(0.), mLevel[mMaxRefine].timestep);
- cparts->setCharLength( mLevel[mMaxRefine].nodeSize );
- cparts->setCharLength( mLevel[mMaxRefine].nodeSize );
- errMsg("LbmControlData","CppfStage "<<mCppfStage<<" in:"<<mpControl->mCons[cpssi]->mContrPartFile<<
- " out:"<<mpControl->mCpOutfile<<" cl:"<< cparts->getCharLength() );
-
- // control particle test init
- if(mpControl->mCons[cpssi]->mCpmotionFile.length()>=1) cpmotion->initFromTextFile(mpControl->mCons[cpssi]->mCpmotionFile);
- // not really necessary...
- //? cparts->setFluidSpacing( mLevel[mMaxRefine].nodeSize ); // use grid coords!?
- //? cparts->calculateKernelWeight();
- //? debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - motion inited: "<<cparts->getSize() ,10);
-
- // ensure both are on for env. var settings
- // when no particles, but outfile enabled, initialize
- const int lev = mMaxRefine;
- if((mpParticles) && (mpControl->mCpOutfile.length()>=1) && (cpssi==0)) {
- // check if auto num
- if( (mpParticles->getNumInitialParticles()<=1) &&
- (mpParticles->getNumParticles()<=1) ) { // initParticles done afterwards anyway
- int tracers = 0;
- const int workSet = mLevel[lev].setCurr;
- FSGR_FORIJK_BOUNDS(lev) {
- if(RFLAG(lev,i,j,k, workSet)&(CFFluid)) tracers++;
- }
- if(LBMDIM==3) tracers /= 8;
- else tracers /= 4;
- mpParticles->setNumInitialParticles(tracers);
- mpParticles->setDumpTextFile(mpControl->mCpOutfile);
- debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - set tracers #"<<tracers<<", actual #"<<mpParticles->getNumParticles() ,10);
- }
- if(mpParticles->getDumpTextInterval()<=0.) {
- mpParticles->setDumpTextInterval(mLevel[lev].timestep * mLevel[lev].lSizex);
- debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - dump delta t not set, using dti="<< mpParticles->getDumpTextInterval()<<", sim dt="<<mLevel[lev].timestep, 5 );
- }
- mpParticles->setDumpParts(true); // DEBUG? also dump as particle system
- }
-
- if(mpControl->mCons[cpssi]->mContrPartFile.length()>=1) cparts->initFromTextFile(mpControl->mCons[cpssi]->mContrPartFile);
- cparts->setFluidSpacing( mLevel[lev].nodeSize ); // use grid coords!?
- cparts->calculateKernelWeight();
- debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles mCons"<<cpssi<<" - inited, parts:"<<cparts->getTotalSize()<<","<<cparts->getSize()<<" dt:"<<mpParam->getTimestep()<<" control time:"<<cparts->getControlTimStart()<<" to "<<cparts->getControlTimEnd() ,10);
- } // cpssi
-
- if(getenv("ELBEEM_CPINFILE")) {
- this->mTForceStrength = 1.0;
- }
- this->mTForceStrength = mpControl->mSetForceStrength;
- if(mpControl->mCpOutfile.length()>=1) mpParticles->setDumpTextFile(mpControl->mCpOutfile);
-
- // control particle init end -------------------------------------------------------------------------------------
-
- // make sure equiv to solver init
- if(this->mTForceStrength>0.) { \
- mpControl->mCpForces.resize( mMaxRefine+1 );
- for(int lev = 0; lev<=mMaxRefine; lev++) {
- LONGINT rcellSize = (mLevel[lev].lSizex*mLevel[lev].lSizey*mLevel[lev].lSizez);
- debMsgStd("LbmFsgrSolver::initControl",DM_MSG,"mCpForces init, lev="<<lev<<" rcs:"<<(int)(rcellSize+4)<<","<<(rcellSize*sizeof(ControlForces)/(1024*1024)), 9 );
- mpControl->mCpForces[lev].resize( (int)(rcellSize+4) );
- //for(int i=0 ;i<rcellSize; i++) mpControl->mCpForces.push_back( ControlForces() );
- for(int i=0 ;i<rcellSize; i++) mpControl->mCpForces[lev][i].resetForces();
- }
- } // on?
-
- debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles #mCons "<<mpControl->mCons.size()<<" done", 6);
-}
-
-
-#define CPODEBUG 0
-//define CPINTER ((int)(mpControl->mCpUpdateInterval))
-
-#define KERN(x,y,z) mpControl->mCpKernel[ (((z)*cpkarWidth + (y))*cpkarWidth + (x)) ]
-#define MDKERN(x,y,z) mpControl->mMdKernel[ (((z)*mdkarWidth + (y))*mdkarWidth + (x)) ]
-
-#define BOUNDCHECK(x,low,high) ( ((x)<low) ? low : (((x)>high) ? high : (x) ) )
-#define BOUNDSKIP(x,low,high) ( ((x)<low) || ((x)>high) )
-
-void
-LbmFsgrSolver::handleCpdata()
-{
- myTime_t cpstart = getTime();
- int cpChecks=0;
- int cpInfs=0;
- //debMsgStd("ControlData::handleCpdata",DM_MSG,"called... "<<this->mTForceStrength,1);
-
- // add cp influence
- if((true) && (this->mTForceStrength>0.)) {
- // ok continue...
- } // on off
- else {
- return;
- }
-
- // check if we have control objects
- if(mpControl->mCons.size()==0)
- return;
-
- if((mpControl->mCpUpdateInterval<1) || (this->mStepCnt%mpControl->mCpUpdateInterval==0)) {
- // do full reinit later on...
- }
- else if(this->mStepCnt>mpControl->mCpUpdateInterval) {
- // only reinit new cells
- // TODO !? remove loop dependance!?
-#define NOFORCEENTRY(lev, i,j,k) (LBMGET_FORCE(lev, i,j,k).maxDistance==CPF_MAXDINIT)
- // interpolate missing
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) {
- if( (RFLAG(lev,i,j,k, mLevel[lev].setCurr)) & (CFFluid|CFInter) )
- //if( (RFLAG(lev,i,j,k, mLevel[lev].setCurr)) & (CFInter) )
- //if(0)
- { // only check new inter? RFLAG?check
- if(NOFORCEENTRY(lev, i,j,k)) {
- //errMsg("CP","FE_MISSING at "<<PRINT_IJK<<" f"<<LBMGET_FORCE(lev, i,j,k).weightAtt<<" md"<<LBMGET_FORCE(lev, i,j,k).maxDistance );
-
- LbmFloat nbs=0.;
- ControlForces vals;
- vals.resetForces(); vals.maxDistance = 0.;
- for(int l=1; l<this->cDirNum; l++) {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- //errMsg("CP","FE_MISSING check "<<PRINT_VEC(ni,nj,nk)<<" f"<<LBMGET_FORCE(lev, ni,nj,nk).weightAtt<<" md"<<LBMGET_FORCE(lev, ni,nj,nk).maxDistance );
- if(!NOFORCEENTRY(lev, ni,nj,nk)) {
- //? vals.weightAtt += LBMGET_FORCE(lev, ni,nj,nk).weightAtt;
- //? vals.forceAtt += LBMGET_FORCE(lev, ni,nj,nk).forceAtt;
- vals.maxDistance += LBMGET_FORCE(lev, ni,nj,nk).maxDistance;
- vals.forceMaxd += LBMGET_FORCE(lev, ni,nj,nk).forceMaxd;
- vals.weightVel += LBMGET_FORCE(lev, ni,nj,nk).weightVel;
- vals.forceVel += LBMGET_FORCE(lev, ni,nj,nk).forceVel;
- // ignore att/compAv/avgVel here for now
- nbs += 1.;
- }
- }
- if(nbs>0.) {
- nbs = 1./nbs;
- //? LBMGET_FORCE(lev, i,j,k).weightAtt = vals.weightAtt*nbs;
- //? LBMGET_FORCE(lev, i,j,k).forceAtt = vals.forceAtt*nbs;
- LBMGET_FORCE(lev, i,j,k).maxDistance = vals.maxDistance*nbs;
- LBMGET_FORCE(lev, i,j,k).forceMaxd = vals.forceMaxd*nbs;
- LBMGET_FORCE(lev, i,j,k).weightVel = vals.weightVel*nbs;
- LBMGET_FORCE(lev, i,j,k).forceVel = vals.forceVel*nbs;
- }
- /*ControlForces *ff = &LBMGET_FORCE(lev, i,j,k); // DEBUG
- errMsg("CP","FE_MISSING rec at "<<PRINT_IJK // DEBUG
- <<" w:"<<ff->weightAtt<<" wa:" <<PRINT_VEC( ff->forceAtt[0],ff->forceAtt[1],ff->forceAtt[2] )
- <<" v:"<<ff->weightVel<<" wv:" <<PRINT_VEC( ff->forceVel[0],ff->forceVel[1],ff->forceVel[2] )
- <<" v:"<<ff->maxDistance<<" wv:" <<PRINT_VEC( ff->forceMaxd[0],ff->forceMaxd[1],ff->forceMaxd[2] ) ); // DEBUG */
- // else errMsg("CP","FE_MISSING rec at "<<PRINT_IJK<<" failed!"); // DEBUG
-
- }
- }
- }} // ijk, lev
-
- // mStepCnt > mpControl->mCpUpdateInterval
- return;
- } else {
- // nothing to do ...
- return;
- }
-
- // reset
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) { LBMGET_FORCE(lev,i,j,k).resetForces(); }
- }
- // do setup for coarsest level
- const int coarseLev = 0;
- const int fineLev = mMaxRefine;
-
- // init for current time
- for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
- LbmControlSet *cset = mpControl->mCons[cpssi];
-
- cparts->setRadiusAtt(cset->mcRadiusAtt.get(mSimulationTime));
- cparts->setRadiusVel(cset->mcRadiusVel.get(mSimulationTime));
- cparts->setInfluenceAttraction(cset->mcForceAtt.get(mSimulationTime) );
- cparts->setInfluenceMaxdist(cset->mcForceMaxd.get(mSimulationTime) );
- cparts->setRadiusMinMaxd(cset->mcRadiusMind.get(mSimulationTime));
- cparts->setRadiusMaxd(cset->mcRadiusMaxd.get(mSimulationTime));
- cparts->calculateKernelWeight(); // always necessary!?
- cparts->setOffset( vec2L(cset->mcCpOffset.get(mSimulationTime)) );
- cparts->setScale( vec2L(cset->mcCpScale.get(mSimulationTime)) );
-
- cparts->setInfluenceVelocity( cset->mcForceVel.get(mSimulationTime), mLevel[fineLev].timestep );
- cparts->setLastOffset( vec2L(cset->mcCpOffset.get(mSimulationTime-mLevel[fineLev].timestep)) );
- cparts->setLastScale( vec2L(cset->mcCpScale.get(mSimulationTime-mLevel[fineLev].timestep)) );
-
- }
-
- // check actual values
- LbmFloat iatt = ABS(mpControl->mCons[0]->mCparts->getInfluenceAttraction());
- LbmFloat ivel = mpControl->mCons[0]->mCparts->getInfluenceVelocity();
- LbmFloat imaxd = mpControl->mCons[0]->mCparts->getInfluenceMaxdist();
- //errMsg("FINCIT","iatt="<<iatt<<" ivel="<<ivel<<" imaxd="<<imaxd);
- for(int cpssi=1; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- LbmFloat iatt2 = ABS(mpControl->mCons[cpssi]->mCparts->getInfluenceAttraction());
- LbmFloat ivel2 = mpControl->mCons[cpssi]->mCparts->getInfluenceVelocity();
- LbmFloat imaxd2 = mpControl->mCons[cpssi]->mCparts->getInfluenceMaxdist();
-
- // we allow negative attraction force here!
- if(iatt2 > iatt) iatt = iatt2;
-
- if(ivel2 >ivel) ivel = ivel2;
- if(imaxd2>imaxd) imaxd= imaxd2;
- //errMsg("FINCIT"," "<<cpssi<<" iatt2="<<iatt2<<" ivel2="<<ivel2<<" imaxd2="<<imaxd<<" NEW "<<" iatt="<<iatt<<" ivel="<<ivel<<" imaxd="<<imaxd);
- }
-
- if(iatt==0. && ivel==0. && imaxd==0.) {
- debMsgStd("ControlData::initControl",DM_MSG,"Skipped, all zero...",4);
- return;
- }
- //iatt = mpControl->mCons[1]->mCparts->getInfluenceAttraction(); //ivel = mpControl->mCons[1]->mCparts->getInfluenceVelocity(); //imaxd = mpControl->mCons[1]->mCparts->getInfluenceMaxdist(); // TTTTTT
-
- // do control setup
- for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
- ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion;
-
- // TEST!?
- bool radmod = false;
- const LbmFloat minRadSize = mLevel[coarseLev].nodeSize * 1.5;
- if((cparts->getRadiusAtt()>0.) && (cparts->getRadiusAtt()<minRadSize) && (!radmod) ) {
- LbmFloat radfac = minRadSize / cparts->getRadiusAtt(); radmod=true;
- debMsgStd("ControlData::initControl",DM_MSG,"Modified radii att, fac="<<radfac, 7);
- cparts->setRadiusAtt(cparts->getRadiusAtt()*radfac);
- cparts->setRadiusVel(cparts->getRadiusVel()*radfac);
- cparts->setRadiusMaxd(cparts->getRadiusMaxd()*radfac);
- cparts->setRadiusMinMaxd(cparts->getRadiusMinMaxd()*radfac);
- } else if((cparts->getRadiusVel()>0.) && (cparts->getRadiusVel()<minRadSize) && (!radmod) ) {
- LbmFloat radfac = minRadSize / cparts->getRadiusVel();
- debMsgStd("ControlData::initControl",DM_MSG,"Modified radii vel, fac="<<radfac, 7);
- cparts->setRadiusVel(cparts->getRadiusVel()*radfac);
- cparts->setRadiusMaxd(cparts->getRadiusMaxd()*radfac);
- cparts->setRadiusMinMaxd(cparts->getRadiusMinMaxd()*radfac);
- } else if((cparts->getRadiusMaxd()>0.) && (cparts->getRadiusMaxd()<minRadSize) && (!radmod) ) {
- LbmFloat radfac = minRadSize / cparts->getRadiusMaxd();
- debMsgStd("ControlData::initControl",DM_MSG,"Modified radii maxd, fac="<<radfac, 7);
- cparts->setRadiusMaxd(cparts->getRadiusMaxd()*radfac);
- cparts->setRadiusMinMaxd(cparts->getRadiusMinMaxd()*radfac);
- }
- if(radmod) {
- debMsgStd("ControlData::initControl",DM_MSG,"Modified radii: att="<<
- cparts->getRadiusAtt()<<", vel=" << cparts->getRadiusVel()<<", maxd=" <<
- cparts->getRadiusMaxd()<<", mind=" << cparts->getRadiusMinMaxd() ,5);
- }
-
- cpmotion->prepareControl( mSimulationTime+((LbmFloat)mpControl->mCpUpdateInterval)*(mpParam->getTimestep()), mpParam->getTimestep(), NULL );
- cparts->prepareControl( mSimulationTime+((LbmFloat)mpControl->mCpUpdateInterval)*(mpParam->getTimestep()), mpParam->getTimestep(), cpmotion );
- }
-
- // do control...
- for(int lev=0; lev<=mMaxRefine; lev++) {
- LbmFloat levVolume = 1.;
- LbmFloat levForceScale = 1.;
- for(int ll=lev; ll<mMaxRefine; ll++) {
- if(LBMDIM==3) levVolume *= 8.;
- else levVolume *= 4.;
- levForceScale *= 2.;
- }
- errMsg("LbmFsgrSolver::handleCpdata","levVolume="<<levVolume<<" levForceScale="<<levForceScale );
- //todo: scale velocity, att by level timestep!?
-
- for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
- // ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion;
-
- // if control set is not active skip it
- if((cparts->getControlTimStart() > mSimulationTime) || (cparts->getControlTimEnd() < mLastSimTime))
- {
- continue;
- }
-
- const LbmFloat velLatticeScale = mLevel[lev].timestep/mLevel[lev].nodeSize;
- LbmFloat gsx = ((mvGeoEnd[0]-mvGeoStart[0])/(LbmFloat)mLevel[lev].lSizex);
- LbmFloat gsy = ((mvGeoEnd[1]-mvGeoStart[1])/(LbmFloat)mLevel[lev].lSizey);
- LbmFloat gsz = ((mvGeoEnd[2]-mvGeoStart[2])/(LbmFloat)mLevel[lev].lSizez);
-#if LBMDIM==2
- gsz = gsx;
-#endif
- LbmFloat goffx = mvGeoStart[0];
- LbmFloat goffy = mvGeoStart[1];
- LbmFloat goffz = mvGeoStart[2];
-
- //const LbmFloat cpwIncFac = 2.0;
- // max to two thirds of domain size
- const int cpw = MIN( mLevel[lev].lSizex/3, MAX( (int)( cparts->getRadiusAtt() /gsx) +1 , 2) ); // normal kernel, att,vel
- const int cpkarWidth = 2*cpw+1;
- mpControl->mCpKernel.resize(cpkarWidth* cpkarWidth* cpkarWidth);
- ControlParticle cpt; cpt.reset();
- cpt.pos = LbmVec( (gsx*(LbmFloat)cpw)+goffx, (gsy*(LbmFloat)cpw)+goffy, (gsz*(LbmFloat)cpw)+goffz ); // optimize?
- cpt.density = 0.5; cpt.densityWeight = 0.5;
-#if LBMDIM==3
- for(int k= 0; k<cpkarWidth; ++k) {
-#else // LBMDIM==3
- { int k = cpw;
-#endif
- for(int j= 0; j<cpkarWidth; ++j)
- for(int i= 0; i<cpkarWidth; ++i) {
- KERN(i,j,k).resetForces();
- //LbmFloat dx = i-cpw; LbmFloat dy = j-cpw; LbmFloat dz = k-cpw;
- //LbmVec dv = ( LbmVec(dx,dy,dz) );
- //LbmFloat dl = norm( dv ); //LbmVec dir = dv / dl;
- LbmVec pos = LbmVec( (gsx*(LbmFloat)i)+goffx, (gsy*(LbmFloat)j)+goffy, (gsz*(LbmFloat)k)+goffz ); // optimize?
- cparts->calculateCpInfluenceOpt( &cpt, pos, LbmVec(0,0,0), &KERN(i,j,k) ,1. );
- /*if((CPODEBUG)&&(k==cpw)) errMsg("kern"," at "<<PRINT_IJK<<" pos"<<pos<<" cpp"<<cpt.pos
- <<" wf:"<<KERN(i,j,k).weightAtt<<" wa:"<< PRINT_VEC( KERN(i,j,k).forceAtt[0],KERN(i,j,k).forceAtt[1],KERN(i,j,k).forceAtt[2] )
- <<" wf:"<<KERN(i,j,k).weightVel<<" wa:"<< PRINT_VEC( KERN(i,j,k).forceVel[0],KERN(i,j,k).forceVel[1],KERN(i,j,k).forceVel[2] )
- <<" wf:"<<KERN(i,j,k).maxDistance<<" wa:"<< PRINT_VEC( KERN(i,j,k).forceMaxd[0],KERN(i,j,k).forceMaxd[1],KERN(i,j,k).forceMaxd[2] ) ); // */
- KERN(i,j,k).weightAtt *= 2.;
- KERN(i,j,k).forceAtt *= 2.;
- //KERN(i,j,k).forceAtt[1] *= 2.; KERN(i,j,k).forceAtt[2] *= 2.;
- KERN(i,j,k).weightVel *= 2.;
- KERN(i,j,k).forceVel *= 2.;
- //KERN(i,j,k).forceVel[1] *= 2.; KERN(i,j,k).forceVel[2] *= 2.;
- }
- }
-
- if(CPODEBUG) errMsg("cpw"," = "<<cpw<<" f"<< cparts->getRadiusAtt()<<" gsx"<<gsx<<" kpw"<<cpkarWidth); // DEBUG
- // first cp loop - add att and vel forces
- for(int cppi=0; cppi<cparts->getSize(); cppi++) {
- ControlParticle *cp = cparts->getParticle(cppi);
- if(cp->influence<=0.) continue;
- const int cpi = (int)( (cp->pos[0]-goffx)/gsx );
- const int cpj = (int)( (cp->pos[1]-goffy)/gsy );
- int cpk = (int)( (cp->pos[2]-goffz)/gsz );
- /*if( ((LBMDIM==3)&&(BOUNDSKIP(cpk - cpwsm, getForZMinBnd(), getForZMaxBnd(lev) ))) ||
- ((LBMDIM==3)&&(BOUNDSKIP(cpk + cpwsm, getForZMinBnd(), getForZMaxBnd(lev) ))) ||
- BOUNDSKIP(cpj - cpwsm, 0, mLevel[lev].lSizey ) ||
- BOUNDSKIP(cpj + cpwsm, 0, mLevel[lev].lSizey ) ||
- BOUNDSKIP(cpi - cpwsm, 0, mLevel[lev].lSizex ) ||
- BOUNDSKIP(cpi + cpwsm, 0, mLevel[lev].lSizex ) ) {
- continue;
- } // */
- int is,ie,js,je,ks,ke;
- ks = BOUNDCHECK(cpk - cpw, getForZMinBnd(), getForZMaxBnd(lev) );
- ke = BOUNDCHECK(cpk + cpw, getForZMinBnd(), getForZMaxBnd(lev) );
- js = BOUNDCHECK(cpj - cpw, 0, mLevel[lev].lSizey );
- je = BOUNDCHECK(cpj + cpw, 0, mLevel[lev].lSizey );
- is = BOUNDCHECK(cpi - cpw, 0, mLevel[lev].lSizex );
- ie = BOUNDCHECK(cpi + cpw, 0, mLevel[lev].lSizex );
- if(LBMDIM==2) { cpk = 0; ks = 0; ke = 1; }
- if(CPODEBUG) errMsg("cppft","i"<<cppi<<" cpw"<<cpw<<" gpos"<<PRINT_VEC(cpi,cpj,cpk)<<" i:"<<is<<","<<ie<<" j:"<<js<<","<<je<<" k:"<<ks<<","<<ke<<" "); // DEBUG
- cpInfs++;
-
- for(int k= ks; k<ke; ++k) {
- for(int j= js; j<je; ++j) {
-
- CellFlagType *pflag = &RFLAG(lev,is,j,k, mLevel[lev].setCurr);
- ControlForces *kk = &KERN( is-cpi+cpw, j-cpj+cpw, k-cpk+cpw);
- ControlForces *ff = &LBMGET_FORCE(lev,is,j,k);
- pflag--; kk--; ff--;
-
- for(int i= is; i<ie; ++i) {
- // first cp loop (att,vel)
- pflag++; kk++; ff++;
-
- //add weight for bnd cells
- const LbmFloat pwforce = kk->weightAtt;
- // control particle mod,
- // dont add multiple CFFluid fsgr boundaries
- if(lev==mMaxRefine) {
- //if( ( ((*pflag)&(CFFluid )) && (lev==mMaxRefine) ) ||
- //( ((*pflag)&(CFGrNorm)) && (lev <mMaxRefine) ) ) {
- if((*pflag)&(CFFluid|CFUnused)) {
- // check not fromcoarse?
- cp->density += levVolume* kk->weightAtt; // old CFFluid
- } else if( (*pflag) & (CFEmpty) ) {
- cp->density -= levVolume* 0.5;
- } else { //if( ((*pflag) & (CFBnd)) ) {
- cp->density -= levVolume* 0.2; // penalty
- }
- } else {
- //if((*pflag)&(CFGrNorm)) {
- //cp->density += levVolume* kk->weightAtt; // old CFFluid
- //}
- }
- //else if(!((*pflag) & (CFUnused)) ) { cp->density -= levVolume* 0.2; } // penalty
-
- if( (*pflag) & (CFFluid|CFInter) ) // RFLAG_check
- {
-
- cpChecks++;
- //const LbmFloat pwforce = kk->weightAtt;
- LbmFloat pwvel = kk->weightVel;
- if((pwforce==0.)&&(pwvel==0.)) { continue; }
- ff->weightAtt += 1e-6; // for distance
-
- if(pwforce>0.) {
- ff->weightAtt += pwforce *cp->densityWeight *cp->influence;
- ff->forceAtt += kk->forceAtt *levForceScale *cp->densityWeight *cp->influence;
-
- // old fill handling here
- const int workSet =mLevel[lev].setCurr;
- LbmFloat ux=0., uy=0., uz=0.;
- FORDF1{
- const LbmFloat dfn = QCELL(lev, i,j,k, workSet, l);
- ux += (this->dfDvecX[l]*dfn);
- uy += (this->dfDvecY[l]*dfn);
- uz += (this->dfDvecZ[l]*dfn);
- }
- // control particle mod
- cp->avgVelWeight += levVolume*pwforce;
- cp->avgVelAcc += LbmVec(ux,uy,uz) * levVolume*pwforce;
- }
-
- if(pwvel>0.) {
- // TODO make switch? vel.influence depends on density weight...
- // (reduced lowering with 0.75 factor)
- pwvel *= cp->influence *(1.-0.75*cp->densityWeight);
- // control particle mod
- // todo use Omega instead!?
- ff->forceVel += cp->vel*levVolume*pwvel * velLatticeScale; // levVolume?
- ff->weightVel += levVolume*pwvel; // levVolume?
- ff->compAv += cp->avgVel*levVolume*pwvel; // levVolume?
- ff->compAvWeight += levVolume*pwvel; // levVolume?
- }
-
- if(CPODEBUG) errMsg("cppft","i"<<cppi<<" at "<<PRINT_IJK<<" kern:"<<
- PRINT_VEC(i-cpi+cpw, j-cpj+cpw, k-cpk+cpw )
- //<<" w:"<<ff->weightAtt<<" wa:"
- //<<PRINT_VEC( ff->forceAtt[0],ff->forceAtt[1],ff->forceAtt[2] )
- //<<" v:"<<ff->weightVel<<" wv:"
- //<<PRINT_VEC( ff->forceVel[0],ff->forceVel[1],ff->forceVel[2] )
- //<<" v:"<<ff->maxDistance<<" wv:"
- //<<PRINT_VEC( ff->forceMaxd[0],ff->forceMaxd[1],ff->forceMaxd[2] )
- );
- } // celltype
-
- } // ijk
- } // ijk
- } // ijk
- } // cpi, end first cp loop (att,vel)
- debMsgStd("LbmFsgrSolver::handleCpdata",DM_MSG,"Force cpgrid "<<cpssi<<" generated checks:"<<cpChecks<<" infs:"<<cpInfs ,9);
- } //cpssi
- } // lev
-
- // second loop
- for(int lev=0; lev<=mMaxRefine; lev++) {
- LbmFloat levVolume = 1.;
- LbmFloat levForceScale = 1.;
- for(int ll=lev; ll<mMaxRefine; ll++) {
- if(LBMDIM==3) levVolume *= 8.;
- else levVolume *= 4.;
- levForceScale *= 2.;
- }
- // prepare maxd forces
- for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
- ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
-
- // WARNING copied from above!
- const LbmFloat velLatticeScale = mLevel[lev].timestep/mLevel[lev].nodeSize;
- LbmFloat gsx = ((mvGeoEnd[0]-mvGeoStart[0])/(LbmFloat)mLevel[lev].lSizex);
- LbmFloat gsy = ((mvGeoEnd[1]-mvGeoStart[1])/(LbmFloat)mLevel[lev].lSizey);
- LbmFloat gsz = ((mvGeoEnd[2]-mvGeoStart[2])/(LbmFloat)mLevel[lev].lSizez);
-#if LBMDIM==2
- gsz = gsx;
-#endif
- LbmFloat goffx = mvGeoStart[0];
- LbmFloat goffy = mvGeoStart[1];
- LbmFloat goffz = mvGeoStart[2];
-
- //const LbmFloat cpwIncFac = 2.0;
- const int mdw = MIN( mLevel[lev].lSizex/2, MAX( (int)( cparts->getRadiusMaxd() /gsx) +1 , 2) ); // wide kernel, md
- const int mdkarWidth = 2*mdw+1;
- mpControl->mMdKernel.resize(mdkarWidth* mdkarWidth* mdkarWidth);
- ControlParticle cpt; cpt.reset();
- cpt.density = 0.5; cpt.densityWeight = 0.5;
- cpt.pos = LbmVec( (gsx*(LbmFloat)mdw)+goffx, (gsy*(LbmFloat)mdw)+goffy, (gsz*(LbmFloat)mdw)+goffz ); // optimize?
-#if LBMDIM==3
- for(int k= 0; k<mdkarWidth; ++k) {
-#else // LBMDIM==3
- { int k = mdw;
-#endif
- for(int j= 0; j<mdkarWidth; ++j)
- for(int i= 0; i<mdkarWidth; ++i) {
- MDKERN(i,j,k).resetForces();
- LbmVec pos = LbmVec( (gsx*(LbmFloat)i)+goffx, (gsy*(LbmFloat)j)+goffy, (gsz*(LbmFloat)k)+goffz ); // optimize?
- cparts->calculateMaxdForce( &cpt, pos, &MDKERN(i,j,k) );
- }
- }
-
- // second cpi loop, maxd forces
- if(cparts->getInfluenceMaxdist()>0.) {
- for(int cppi=0; cppi<cparts->getSize(); cppi++) {
- ControlParticle *cp = cparts->getParticle(cppi);
- if(cp->influence<=0.) continue;
- const int cpi = (int)( (cp->pos[0]-goffx)/gsx );
- const int cpj = (int)( (cp->pos[1]-goffy)/gsy );
- int cpk = (int)( (cp->pos[2]-goffz)/gsz );
-
- int is,ie,js,je,ks,ke;
- ks = BOUNDCHECK(cpk - mdw, getForZMinBnd(), getForZMaxBnd(lev) );
- ke = BOUNDCHECK(cpk + mdw, getForZMinBnd(), getForZMaxBnd(lev) );
- js = BOUNDCHECK(cpj - mdw, 0, mLevel[lev].lSizey );
- je = BOUNDCHECK(cpj + mdw, 0, mLevel[lev].lSizey );
- is = BOUNDCHECK(cpi - mdw, 0, mLevel[lev].lSizex );
- ie = BOUNDCHECK(cpi + mdw, 0, mLevel[lev].lSizex );
- if(LBMDIM==2) { cpk = 0; ks = 0; ke = 1; }
- if(CPODEBUG) errMsg("cppft","i"<<cppi<<" mdw"<<mdw<<" gpos"<<PRINT_VEC(cpi,cpj,cpk)<<" i:"<<is<<","<<ie<<" j:"<<js<<","<<je<<" k:"<<ks<<","<<ke<<" "); // DEBUG
- cpInfs++;
-
- for(int k= ks; k<ke; ++k)
- for(int j= js; j<je; ++j) {
- CellFlagType *pflag = &RFLAG(lev,is-1,j,k, mLevel[lev].setCurr);
- for(int i= is; i<ie; ++i) {
- // second cpi loop, maxd forces
- pflag++;
- if( (*pflag) & (CFFluid|CFInter) ) // RFLAG_check
- {
- cpChecks++;
- ControlForces *ff = &LBMGET_FORCE(lev,i,j,k);
- if(ff->weightAtt == 0.) {
- ControlForces *kk = &MDKERN( i-cpi+mdw, j-cpj+mdw, k-cpk+mdw);
- const LbmFloat pmdf = kk->maxDistance;
- if((ff->maxDistance > pmdf) || (ff->maxDistance<0.))
- ff->maxDistance = pmdf;
- ff->forceMaxd = kk->forceMaxd;
- // todo use Omega instead!?
- ff->forceVel = cp->vel* velLatticeScale;
- }
- } // celltype
- } } // ijk
- } // cpi, md loop
- } // maxd inf>0 */
-
-
- debMsgStd("ControlData::initControl",DM_MSG,"Maxd cpgrid "<<cpssi<<" generated checks:"<<cpChecks<<" infs:"<<cpInfs ,9);
- } //cpssi
-
- // normalize, only done once for the whole array
- mpControl->mCons[0]->mCparts->finishControl( mpControl->mCpForces[lev], iatt,ivel,imaxd );
-
- } // lev loop
-
- myTime_t cpend = getTime();
- debMsgStd("ControlData::handleCpdata",DM_MSG,"Time for cpgrid generation:"<< getTimeString(cpend-cpstart)<<", checks:"<<cpChecks<<" infs:"<<cpInfs<<" " ,8);
-
- // warning, may return before
-}
-
-void LbmFsgrSolver::cpDebugDisplay(int dispset) { }
diff --git a/intern/elbeem/intern/solver_control.h b/intern/elbeem/intern/solver_control.h
deleted file mode 100644
index 809cac17297..00000000000
--- a/intern/elbeem/intern/solver_control.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - the visual lattice boltzmann freesurface simulator
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * testing extensions
- *
- *****************************************************************************/
-
-
-#ifndef LBM_TESTCLASS_H
-#define LBM_TESTCLASS_H
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-//class IsoSurface;
-class ParticleObject;
-class ControlParticles;
-class ControlForces;
-
-//#define NUMGRIDS 2
-//#define MAXNUMSWS 10
-
-// farfield modes
-#define FARF_3DONLY -1
-#define FARF_BOTH 0
-#define FARF_SWEONLY 1
-// dont reuse 3d vars/init
-#define FARF_SEPSWE 2
-
-// relaxation macros for solver_relax.h
-
-// WARNING has to match controlparts.h
-#define CPF_ENTRIES 12
-#define CPF_FORCE 0
-#define CPF_VELWEIGHT 3
-#define CPF_VELOCITY 4
-#define CPF_FORCEWEIGHT 7
-#define CPF_MINCPDIST 8
-#define CPF_MINCPDIR 9
-
-#include "controlparticles.h"
-
-#include "ntl_geometrymodel.h"
-
-// get force entry, set=0 is unused anyway
-#define LBMGET_FORCE(lev, i,j,k) mpControl->mCpForces[lev][ (LBMGI(lev,i,j,k,0)) ]
-
-// debug mods off...
-// same as in src/solver_relax.h!
-#define __PRECOLLIDE_MODS(rho,ux,uy,uz, grav) \
- ux += (grav)[0]; \
- uy += (grav)[1]; \
- uz += (grav)[2];
-
-//void testMaxdmod(int i, int j,int k, LbmFloat &ux,LbmFloat &uy,LbmFloat &uz,ControlForces &ff);
-#if LBMDIM==3
-#define MAXDGRAV \
- if(myforce->forceMaxd[0]*ux+myforce->forceMaxd[1]*uy<LBM_EPSILON) { \
- ux = v2w*myforce->forceVel[0]+ v2wi*ux; \
- uy = v2w*myforce->forceVel[1]+ v2wi*uy; } \
- /* movement inverse to g? */ \
- if((uz>LBM_EPSILON)&&(uz>myforce->forceVel[2])) { \
- uz = v2w*myforce->forceVel[2]+ v2wi*uz; }
-#else // LBMDIM==3
-#define MAXDGRAV \
- if(myforce->forceMaxd[0]*ux<LBM_EPSILON) { \
- ux = v2w*myforce->forceVel[0]+ v2wi*ux; } \
- /* movement inverse to g? */ \
- if((uy>LBM_EPSILON)&&(uy>myforce->forceVel[1])) { \
- uy = v2w*myforce->forceVel[1]+ v2wi*uy; }
-#endif // LBMDIM==3
-
-// debug modifications of collide vars (testing)
-// requires: lev,i,j,k
-#define PRECOLLIDE_MODS(rho,ux,uy,uz, grav) \
- LbmFloat attforce = 1.; \
- if(this->mTForceStrength>0.) { \
- ControlForces* myforce = &LBMGET_FORCE(lev,i,j,k); \
- const LbmFloat vf = myforce->weightAtt;\
- const LbmFloat vw = myforce->weightVel;\
- if(vf!=0.) { attforce = MAX(0., 1.-vf); /* TODO FIXME? use ABS(vf) for repulsion force? */ \
- ux += myforce->forceAtt[0]; \
- uy += myforce->forceAtt[1]; \
- uz += myforce->forceAtt[2]; \
- \
- } else if(( myforce->maxDistance>0.) && ( myforce->maxDistance<CPF_MAXDINIT)) {\
- const LbmFloat v2w = mpControl->mCons[0]->mCparts->getInfluenceMaxdist() * \
- (myforce->maxDistance-mpControl->mCons[0]->mCparts->getRadiusMinMaxd()) / (mpControl->mCons[0]->mCparts->getRadiusMaxd()-mpControl->mCons[0]->mCparts->getRadiusMinMaxd()); \
- const LbmFloat v2wi = 1.-v2w; \
- if(v2w>0.){ MAXDGRAV; \
- /* errMsg("ERRMDTT","at "<<PRINT_IJK<<" maxd="<<myforce->maxDistance<<", newu"<<PRINT_VEC(ux,uy,uz)<<", org"<<PRINT_VEC(oux,ouy,ouz)<<", fv"<<myforce->forceVel<<" " ); */ \
- }\
- } \
- if(vw>0.) { \
- const LbmFloat vwi = 1.-vw;\
- const LbmFloat vwd = mpControl->mDiffVelCon;\
- ux += vw*(myforce->forceVel[0]-myforce->compAv[0] + vwd*(myforce->compAv[0]-ux) ); \
- uy += vw*(myforce->forceVel[1]-myforce->compAv[1] + vwd*(myforce->compAv[1]-uy) ); \
- uz += vw*(myforce->forceVel[2]-myforce->compAv[2] + vwd*(myforce->compAv[2]-uz) ); \
- /* TODO test!? modify smooth vel by influence of force for each lbm step, to account for force update only each N steps */ \
- myforce->compAv = (myforce->forceVel*vw+ myforce->compAv*vwi); \
- } \
- } \
- ux += (grav)[0]*attforce; \
- uy += (grav)[1]*attforce; \
- uz += (grav)[2]*attforce; \
- /* end PRECOLLIDE_MODS */
-
-#define TEST_IF_CHECK \
- if((!iffilled)&&(LBMGET_FORCE(lev,i,j,k).weightAtt!=0.)) { \
- errMsg("TESTIFFILL"," at "<<PRINT_IJK<<" "<<mass<<" "<<rho); \
- iffilled = true; \
- if(mass<rho*1.0) mass = rho*1.0; myfrac = 1.0; \
- }
-
-
-// a single set of control particles and params
-class LbmControlSet {
- public:
- LbmControlSet();
- ~LbmControlSet();
- void initCparts();
-
- // control particles
- ControlParticles *mCparts;
- // control particle overall motion (for easier manual generation)
- ControlParticles *mCpmotion;
- // cp data file
- string mContrPartFile;
- string mCpmotionFile;
- // cp debug displau
- LbmFloat mDebugCpscale, mDebugVelScale, mDebugCompavScale, mDebugAttScale, mDebugMaxdScale, mDebugAvgVelScale;
-
- // params
- AnimChannel<float> mcForceAtt;
- AnimChannel<float> mcForceVel;
- AnimChannel<float> mcForceMaxd;
-
- AnimChannel<float> mcRadiusAtt;
- AnimChannel<float> mcRadiusVel;
- AnimChannel<float> mcRadiusMind;
- AnimChannel<float> mcRadiusMaxd;
-
- AnimChannel<ntlVec3f> mcCpScale;
- AnimChannel<ntlVec3f> mcCpOffset;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:LbmControlSet")
-#endif
-};
-
-
-
-// main control data storage
-class LbmControlData
-{
- public:
- LbmControlData();
- virtual ~LbmControlData();
-
- // control data
-
- // contorl params
- void parseControldataAttrList(AttributeList *attr);
-
- // control strength, set for solver interface
- LbmFloat mSetForceStrength;
- // cp vars
- std::vector<LbmControlSet*> mCons;
- // update interval
- int mCpUpdateInterval;
- // output
- string mCpOutfile;
- // control particle precomputed influence
- std::vector< std::vector<ControlForces> > mCpForces;
- std::vector<ControlForces> mCpKernel;
- std::vector<ControlForces> mMdKernel;
- // activate differential velcon
- LbmFloat mDiffVelCon;
-
- // cp debug displau
- LbmFloat mDebugCpscale, mDebugVelScale, mDebugCompavScale, mDebugAttScale, mDebugMaxdScale, mDebugAvgVelScale;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:LbmControlData ")
-#endif
-};
-
-#endif // LBM_TESTCLASS_H
diff --git a/intern/elbeem/intern/solver_init.cpp b/intern/elbeem/intern/solver_init.cpp
deleted file mode 100644
index 664b1f2555e..00000000000
--- a/intern/elbeem/intern/solver_init.cpp
+++ /dev/null
@@ -1,2396 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Standard LBM Factory implementation
- *
- *****************************************************************************/
-
-
-#include "solver_class.h"
-#include "solver_relax.h"
-// for geo init FGI_ defines
-#include "elbeem.h"
-#include "globals.h"
-
-
-// helper for 2d init
-#define SWAPYZ(vec) { \
- const LbmFloat tmp = (vec)[2]; \
- (vec)[2] = (vec)[1]; (vec)[1] = tmp; }
-
-
-/*****************************************************************************/
-//! common variables
-
-/*****************************************************************************/
-/*! 3D implementation D3Q19 */
-#if LBMDIM==3
-
- //! how many dimensions?
- const int LbmFsgrSolver::cDimension = 3;
-
- // Wi factors for collide step
- const LbmFloat LbmFsgrSolver::cCollenZero = (1.0/3.0);
- const LbmFloat LbmFsgrSolver::cCollenOne = (1.0/18.0);
- const LbmFloat LbmFsgrSolver::cCollenSqrtTwo = (1.0/36.0);
-
- //! threshold value for filled/emptied cells
- const LbmFloat LbmFsgrSolver::cMagicNr2 = 1.0005;
- const LbmFloat LbmFsgrSolver::cMagicNr2Neg = -0.0005;
- const LbmFloat LbmFsgrSolver::cMagicNr = 1.010001;
- const LbmFloat LbmFsgrSolver::cMagicNrNeg = -0.010001;
-
- //! size of a single set of distribution functions
- const int LbmFsgrSolver::cDfNum = 19;
- //! direction vector contain vecs for all spatial dirs, even if not used for LBM model
- const int LbmFsgrSolver::cDirNum = 27;
-
- //const string LbmFsgrSolver::dfString[ cDfNum ] = {
- const char* LbmFsgrSolver::dfString[ cDfNum ] = {
- " C", " N"," S"," E"," W"," T"," B",
- "NE","NW","SE","SW",
- "NT","NB","ST","SB",
- "ET","EB","WT","WB"
- };
-
- const int LbmFsgrSolver::dfNorm[ cDfNum ] = {
- cDirC, cDirN, cDirS, cDirE, cDirW, cDirT, cDirB,
- cDirNE, cDirNW, cDirSE, cDirSW,
- cDirNT, cDirNB, cDirST, cDirSB,
- cDirET, cDirEB, cDirWT, cDirWB
- };
-
- const int LbmFsgrSolver::dfInv[ cDfNum ] = {
- cDirC, cDirS, cDirN, cDirW, cDirE, cDirB, cDirT,
- cDirSW, cDirSE, cDirNW, cDirNE,
- cDirSB, cDirST, cDirNB, cDirNT,
- cDirWB, cDirWT, cDirEB, cDirET
- };
-
- const int LbmFsgrSolver::dfRefX[ cDfNum ] = {
- 0, 0, 0, 0, 0, 0, 0,
- cDirSE, cDirSW, cDirNE, cDirNW,
- 0, 0, 0, 0,
- cDirEB, cDirET, cDirWB, cDirWT
- };
-
- const int LbmFsgrSolver::dfRefY[ cDfNum ] = {
- 0, 0, 0, 0, 0, 0, 0,
- cDirNW, cDirNE, cDirSW, cDirSE,
- cDirNB, cDirNT, cDirSB, cDirST,
- 0, 0, 0, 0
- };
-
- const int LbmFsgrSolver::dfRefZ[ cDfNum ] = {
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- cDirST, cDirSB, cDirNT, cDirNB,
- cDirWT, cDirWB, cDirET, cDirEB
- };
-
- // Vector Order 3D:
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
- // 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1
- // 0, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1
- // 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1
-
- const int LbmFsgrSolver::dfVecX[ cDirNum ] = {
- 0, 0,0, 1,-1, 0,0,
- 1,-1,1,-1,
- 0,0,0,0,
- 1,1,-1,-1,
- 1,-1, 1,-1,
- 1,-1, 1,-1,
- };
- const int LbmFsgrSolver::dfVecY[ cDirNum ] = {
- 0, 1,-1, 0,0,0,0,
- 1,1,-1,-1,
- 1,1,-1,-1,
- 0,0,0,0,
- 1, 1,-1,-1,
- 1, 1,-1,-1
- };
- const int LbmFsgrSolver::dfVecZ[ cDirNum ] = {
- 0, 0,0,0,0,1,-1,
- 0,0,0,0,
- 1,-1,1,-1,
- 1,-1,1,-1,
- 1, 1, 1, 1,
- -1,-1,-1,-1
- };
-
- const LbmFloat LbmFsgrSolver::dfDvecX[ cDirNum ] = {
- 0, 0,0, 1,-1, 0,0,
- 1,-1,1,-1,
- 0,0,0,0,
- 1,1,-1,-1,
- 1,-1, 1,-1,
- 1,-1, 1,-1
- };
- const LbmFloat LbmFsgrSolver::dfDvecY[ cDirNum ] = {
- 0, 1,-1, 0,0,0,0,
- 1,1,-1,-1,
- 1,1,-1,-1,
- 0,0,0,0,
- 1, 1,-1,-1,
- 1, 1,-1,-1
- };
- const LbmFloat LbmFsgrSolver::dfDvecZ[ cDirNum ] = {
- 0, 0,0,0,0,1,-1,
- 0,0,0,0,
- 1,-1,1,-1,
- 1,-1,1,-1,
- 1, 1, 1, 1,
- -1,-1,-1,-1
- };
-
- /* principal directions */
- const int LbmFsgrSolver::princDirX[ 2*LbmFsgrSolver::cDimension ] = {
- 1,-1, 0,0, 0,0
- };
- const int LbmFsgrSolver::princDirY[ 2*LbmFsgrSolver::cDimension ] = {
- 0,0, 1,-1, 0,0
- };
- const int LbmFsgrSolver::princDirZ[ 2*LbmFsgrSolver::cDimension ] = {
- 0,0, 0,0, 1,-1
- };
-
- /*! arrays for les model coefficients, inited in lbmsolver constructor */
- LbmFloat LbmFsgrSolver::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ];
- LbmFloat LbmFsgrSolver::lesCoeffOffdiag[ cDimension ][ cDirNum ];
-
-
- const LbmFloat LbmFsgrSolver::dfLength[ cDfNum ]= {
- cCollenZero,
- cCollenOne, cCollenOne, cCollenOne,
- cCollenOne, cCollenOne, cCollenOne,
- cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo,
- cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo,
- cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo
- };
-
- /* precalculated equilibrium dfs, inited in lbmsolver constructor */
- LbmFloat LbmFsgrSolver::dfEquil[ dTotalNum ];
-
-#else // end LBMDIM==3 , LBMDIM==2
-
-/*****************************************************************************/
-/*! 2D implementation D2Q9 */
-
- //! how many dimensions?
- const int LbmFsgrSolver::cDimension = 2;
-
- //! Wi factors for collide step
- const LbmFloat LbmFsgrSolver::cCollenZero = (4.0/9.0);
- const LbmFloat LbmFsgrSolver::cCollenOne = (1.0/9.0);
- const LbmFloat LbmFsgrSolver::cCollenSqrtTwo = (1.0/36.0);
-
- //! threshold value for filled/emptied cells
- const LbmFloat LbmFsgrSolver::cMagicNr2 = 1.0005;
- const LbmFloat LbmFsgrSolver::cMagicNr2Neg = -0.0005;
- const LbmFloat LbmFsgrSolver::cMagicNr = 1.010001;
- const LbmFloat LbmFsgrSolver::cMagicNrNeg = -0.010001;
-
- //! size of a single set of distribution functions
- const int LbmFsgrSolver::cDfNum = 9;
- const int LbmFsgrSolver::cDirNum = 9;
-
- //const string LbmFsgrSolver::dfString[ cDfNum ] = {
- const char* LbmFsgrSolver::dfString[ cDfNum ] = {
- " C",
- " N", " S", " E", " W",
- "NE", "NW", "SE","SW"
- };
-
- const int LbmFsgrSolver::dfNorm[ cDfNum ] = {
- cDirC,
- cDirN, cDirS, cDirE, cDirW,
- cDirNE, cDirNW, cDirSE, cDirSW
- };
-
- const int LbmFsgrSolver::dfInv[ cDfNum ] = {
- cDirC,
- cDirS, cDirN, cDirW, cDirE,
- cDirSW, cDirSE, cDirNW, cDirNE
- };
-
- const int LbmFsgrSolver::dfRefX[ cDfNum ] = {
- 0,
- 0, 0, 0, 0,
- cDirSE, cDirSW, cDirNE, cDirNW
- };
-
- const int LbmFsgrSolver::dfRefY[ cDfNum ] = {
- 0,
- 0, 0, 0, 0,
- cDirNW, cDirNE, cDirSW, cDirSE
- };
-
- const int LbmFsgrSolver::dfRefZ[ cDfNum ] = {
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0
- };
-
- // Vector Order 2D:
- // 0 1 2 3 4 5 6 7 8
- // 0, 0,0, 1,-1, 1,-1,1,-1
- // 0, 1,-1, 0,0, 1,1,-1,-1
-
- const int LbmFsgrSolver::dfVecX[ cDirNum ] = {
- 0,
- 0,0, 1,-1,
- 1,-1,1,-1
- };
- const int LbmFsgrSolver::dfVecY[ cDirNum ] = {
- 0,
- 1,-1, 0,0,
- 1,1,-1,-1
- };
- const int LbmFsgrSolver::dfVecZ[ cDirNum ] = {
- 0, 0,0,0,0, 0,0,0,0
- };
-
- const LbmFloat LbmFsgrSolver::dfDvecX[ cDirNum ] = {
- 0,
- 0,0, 1,-1,
- 1,-1,1,-1
- };
- const LbmFloat LbmFsgrSolver::dfDvecY[ cDirNum ] = {
- 0,
- 1,-1, 0,0,
- 1,1,-1,-1
- };
- const LbmFloat LbmFsgrSolver::dfDvecZ[ cDirNum ] = {
- 0, 0,0,0,0, 0,0,0,0
- };
-
- const int LbmFsgrSolver::princDirX[ 2*LbmFsgrSolver::cDimension ] = {
- 1,-1, 0,0
- };
- const int LbmFsgrSolver::princDirY[ 2*LbmFsgrSolver::cDimension ] = {
- 0,0, 1,-1
- };
- const int LbmFsgrSolver::princDirZ[ 2*LbmFsgrSolver::cDimension ] = {
- 0,0, 0,0
- };
-
-
- /*! arrays for les model coefficients, inited in lbmsolver constructor */
- LbmFloat LbmFsgrSolver::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ];
- LbmFloat LbmFsgrSolver::lesCoeffOffdiag[ cDimension ][ cDirNum ];
-
-
- const LbmFloat LbmFsgrSolver::dfLength[ cDfNum ]= {
- cCollenZero,
- cCollenOne, cCollenOne, cCollenOne, cCollenOne,
- cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo
- };
-
- /* precalculated equilibrium dfs, inited in lbmsolver constructor */
- LbmFloat LbmFsgrSolver::dfEquil[ dTotalNum ];
-
-// D2Q9 end
-#endif // LBMDIM==2
-
-
-
-
-/******************************************************************************
- * Lbm Constructor
- *****************************************************************************/
-LbmFsgrSolver::LbmFsgrSolver() :
- //D(),
- mCurrentMass(0.0), mCurrentVolume(0.0),
- mNumProblems(0),
- mAvgMLSUPS(0.0), mAvgMLSUPSCnt(0.0),
- mpPreviewSurface(NULL),
- mTimeAdap(true), mForceTimeStepReduce(false),
- mFVHeight(0.0), mFVArea(1.0), mUpdateFVHeight(false),
- mInitSurfaceSmoothing(0), mFsSurfGenSetting(0),
- mTimestepReduceLock(0),
- mTimeSwitchCounts(0), mTimeMaxvelStepCnt(0),
- mSimulationTime(0.0), mLastSimTime(0.0),
- mMinTimestep(0.0), mMaxTimestep(0.0),
- mMaxNoCells(0), mMinNoCells(0), mAvgNumUsedCells(0),
- mObjectSpeeds(), mObjectPartslips(), mObjectMassMovnd(),
- mMOIVertices(), mMOIVerticesOld(), mMOINormals(),
- mIsoWeightMethod(1),
- mMaxRefine(1),
- mDfScaleUp(-1.0), mDfScaleDown(-1.0),
- mInitialCsmago(0.02), // set to 0.02 for mMaxRefine==0 below and default for fine level, coarser ones are 0.03
- mDebugOmegaRet(0.0),
- mLastOmega(1e10), mLastGravity(1e10),
- mNumInvIfTotal(0), mNumFsgrChanges(0),
- mDisableStandingFluidInit(0),
- mInit2dYZ(false),
- mForceTadapRefine(-1), mCutoff(-1)
-{
- mpControl = new LbmControlData();
-
-#if LBM_INCLUDE_TESTSOLVERS==1
- mpTest = new LbmTestdata();
- mMpNum = mMpIndex = 0;
- mOrgSizeX = 0;
- mOrgStartX = 0.;
- mOrgEndX = 0.;
-#endif // LBM_INCLUDE_TESTSOLVERS!=1
- mpIso = new IsoSurface( mIsoValue );
-
- // init equilibrium dist. func
- LbmFloat rho=1.0;
- FORDF0 {
- dfEquil[l] = this->getCollideEq( l,rho, 0.0, 0.0, 0.0);
- }
- dfEquil[dMass] = 1.;
- dfEquil[dFfrac] = 1.;
- dfEquil[dFlux] = FLUX_INIT;
-
- // init LES
- int odm = 0;
- for(int m=0; m<LBMDIM; m++) {
- for(int l=0; l<cDfNum; l++) {
- this->lesCoeffDiag[m][l] =
- this->lesCoeffOffdiag[m][l] = 0.0;
- }
- }
- for(int m=0; m<LBMDIM; m++) {
- for(int n=0; n<LBMDIM; n++) {
- for(int l=1; l<cDfNum; l++) {
- LbmFloat em;
- switch(m) {
- case 0: em = dfDvecX[l]; break;
- case 1: em = dfDvecY[l]; break;
- case 2: em = dfDvecZ[l]; break;
- default: em = -1.0; errFatal("SMAGO1","err m="<<m, SIMWORLD_GENERICERROR);
- }
- LbmFloat en;
- switch(n) {
- case 0: en = dfDvecX[l]; break;
- case 1: en = dfDvecY[l]; break;
- case 2: en = dfDvecZ[l]; break;
- default: en = -1.0; errFatal("SMAGO2","err n="<<n, SIMWORLD_GENERICERROR);
- }
- const LbmFloat coeff = em*en;
- if(m==n) {
- this->lesCoeffDiag[m][l] = coeff;
- } else {
- if(m>n) {
- this->lesCoeffOffdiag[odm][l] = coeff;
- }
- }
- }
-
- if(m==n) {
- } else {
- if(m>n) odm++;
- }
- }
- }
-
- mDvecNrm[0] = LbmVec(0.0);
- FORDF1 {
- mDvecNrm[l] = getNormalized(
- LbmVec(dfDvecX[dfInv[l]], dfDvecY[dfInv[l]], dfDvecZ[dfInv[l]] )
- ) * -1.0;
- }
-
- // calculate gauss weights for restriction
- //LbmFloat mGaussw[27];
- LbmFloat totGaussw = 0.0;
- const LbmFloat alpha = 1.0;
- const LbmFloat gw = sqrt(2.0*LBMDIM);
-#if ELBEEM_PLUGIN!=1
- errMsg("coarseRestrictFromFine", "TCRFF_DFDEBUG2 test df/dir num!");
-#endif
- for(int n=0;(n<cDirNum); n++) { mGaussw[n] = 0.0; }
- //for(int n=0;(n<cDirNum); n++) {
- for(int n=0;(n<cDfNum); n++) {
- const LbmFloat d = norm(LbmVec(dfVecX[n], dfVecY[n], dfVecZ[n]));
- LbmFloat w = expf( -alpha*d*d ) - expf( -alpha*gw*gw );
- mGaussw[n] = w;
- totGaussw += w;
- }
- for(int n=0;(n<cDirNum); n++) {
- mGaussw[n] = mGaussw[n]/totGaussw;
- }
-
-}
-
-/*****************************************************************************/
-/* Destructor */
-/*****************************************************************************/
-LbmFsgrSolver::~LbmFsgrSolver()
-{
- if(!mInitDone){ debMsgStd("LbmFsgrSolver::LbmFsgrSolver",DM_MSG,"not inited...",0); return; }
-#if COMPRESSGRIDS==1
- delete [] mLevel[mMaxRefine].mprsCells[1];
- mLevel[mMaxRefine].mprsCells[0] = mLevel[mMaxRefine].mprsCells[1] = NULL;
-#endif // COMPRESSGRIDS==1
-
- for(int i=0; i<=mMaxRefine; i++) {
- for(int s=0; s<2; s++) {
- if(mLevel[i].mprsCells[s]) delete [] mLevel[i].mprsCells[s];
- if(mLevel[i].mprsFlags[s]) delete [] mLevel[i].mprsFlags[s];
- }
- }
- delete mpIso;
- if(mpPreviewSurface) delete mpPreviewSurface;
- // cleanup done during scene deletion...
-
- if(mpControl) delete mpControl;
-
- // always output performance estimate
- debMsgStd("LbmFsgrSolver::~LbmFsgrSolver",DM_MSG," Avg. MLSUPS:"<<(mAvgMLSUPS/mAvgMLSUPSCnt), 5);
- if(!mSilent) debMsgStd("LbmFsgrSolver::~LbmFsgrSolver",DM_MSG,"Deleted...",10);
-}
-
-
-
-
-/******************************************************************************
- * initilize variables fom attribute list
- *****************************************************************************/
-void LbmFsgrSolver::parseAttrList()
-{
- LbmSolverInterface::parseStdAttrList();
-
- string matIso("default");
- matIso = mpSifAttrs->readString("material_surf", matIso, "SimulationLbm","mpIso->material", false );
- mpIso->setMaterialName( matIso );
- mOutputSurfacePreview = mpSifAttrs->readInt("surfacepreview", mOutputSurfacePreview, "SimulationLbm","mOutputSurfacePreview", false );
- mTimeAdap = mpSifAttrs->readBool("timeadap", mTimeAdap, "SimulationLbm","mTimeAdap", false );
- mDomainBound = mpSifAttrs->readString("domainbound", mDomainBound, "SimulationLbm","mDomainBound", false );
- mDomainPartSlipValue = mpSifAttrs->readFloat("domainpartslip", mDomainPartSlipValue, "SimulationLbm","mDomainPartSlipValue", false );
-
- mIsoWeightMethod= mpSifAttrs->readInt("isoweightmethod", mIsoWeightMethod, "SimulationLbm","mIsoWeightMethod", false );
- mInitSurfaceSmoothing = mpSifAttrs->readInt("initsurfsmooth", mInitSurfaceSmoothing, "SimulationLbm","mInitSurfaceSmoothing", false );
- mSmoothSurface = mpSifAttrs->readFloat("smoothsurface", mSmoothSurface, "SimulationLbm","mSmoothSurface", false );
- mSmoothNormals = mpSifAttrs->readFloat("smoothnormals", mSmoothNormals, "SimulationLbm","mSmoothNormals", false );
- mFsSurfGenSetting = mpSifAttrs->readInt("fssurfgen", mFsSurfGenSetting, "SimulationLbm","mFsSurfGenSetting", false );
-
- // refinement
- mMaxRefine = mRefinementDesired;
- mMaxRefine = mpSifAttrs->readInt("maxrefine", mMaxRefine ,"LbmFsgrSolver", "mMaxRefine", false);
- if(mMaxRefine<0) mMaxRefine=0;
- if(mMaxRefine>FSGR_MAXNOOFLEVELS) mMaxRefine=FSGR_MAXNOOFLEVELS-1;
- mDisableStandingFluidInit = mpSifAttrs->readInt("disable_stfluidinit", mDisableStandingFluidInit,"LbmFsgrSolver", "mDisableStandingFluidInit", false);
- mInit2dYZ = mpSifAttrs->readBool("init2dyz", mInit2dYZ,"LbmFsgrSolver", "mInit2dYZ", false);
- mForceTadapRefine = mpSifAttrs->readInt("forcetadaprefine", mForceTadapRefine,"LbmFsgrSolver", "mForceTadapRefine", false);
-
- // demo mode settings
- mFVHeight = mpSifAttrs->readFloat("fvolheight", mFVHeight, "LbmFsgrSolver","mFVHeight", false );
- // FIXME check needed?
- mFVArea = mpSifAttrs->readFloat("fvolarea", mFVArea, "LbmFsgrSolver","mFArea", false );
-
- // debugging - skip some time...
- double starttimeskip = 0.;
- starttimeskip = mpSifAttrs->readFloat("forcestarttimeskip", starttimeskip, "LbmFsgrSolver","starttimeskip", false );
- mSimulationTime += starttimeskip;
- if(starttimeskip>0.) debMsgStd("LbmFsgrSolver::parseStdAttrList",DM_NOTIFY,"Used starttimeskip="<<starttimeskip<<", t="<<mSimulationTime, 1);
-
- mpControl->parseControldataAttrList(mpSifAttrs);
-
-#if LBM_INCLUDE_TESTSOLVERS==1
- mUseTestdata = 0;
- mUseTestdata = mpSifAttrs->readBool("use_testdata", mUseTestdata,"LbmFsgrSolver", "mUseTestdata", false);
- mpTest->parseTestdataAttrList(mpSifAttrs);
-#ifdef ELBEEM_PLUGIN
- mUseTestdata=1; // DEBUG
-#endif // ELBEEM_PLUGIN
-
- mMpNum = mpSifAttrs->readInt("mpnum", mMpNum ,"LbmFsgrSolver", "mMpNum", false);
- mMpIndex = mpSifAttrs->readInt("mpindex", mMpIndex ,"LbmFsgrSolver", "mMpIndex", false);
- if(glob_mpactive) {
- // used instead...
- mMpNum = glob_mpnum;
- mMpIndex = glob_mpindex;
- } else {
- glob_mpnum = mMpNum;
- glob_mpindex = 0;
- }
- errMsg("LbmFsgrSolver::parseAttrList"," mpactive:"<<glob_mpactive<<", "<<glob_mpindex<<"/"<<glob_mpnum);
- if(mMpNum>0) {
- mUseTestdata=1; // needed in this case...
- }
-
- errMsg("LbmFsgrSolver::LBM_INCLUDE_TESTSOLVERS","Active, mUseTestdata:"<<mUseTestdata<<" ");
-#else // LBM_INCLUDE_TESTSOLVERS!=1
- // not testsolvers, off by default
- mUseTestdata = 0;
- if(mFarFieldSize>=2.) mUseTestdata=1; // equiv. to test solver check
-#endif // LBM_INCLUDE_TESTSOLVERS!=1
-
- mInitialCsmago = mpSifAttrs->readFloat("csmago", mInitialCsmago, "SimulationLbm","mInitialCsmago", false );
- // deprecated!
- float mInitialCsmagoCoarse = 0.0;
- mInitialCsmagoCoarse = mpSifAttrs->readFloat("csmago_coarse", mInitialCsmagoCoarse, "SimulationLbm","mInitialCsmagoCoarse", false );
-#if USE_LES==1
-#else // USE_LES==1
- debMsgStd("LbmFsgrSolver", DM_WARNING, "LES model switched off!",2);
- mInitialCsmago = 0.0;
-#endif // USE_LES==1
-}
-
-
-/******************************************************************************
- * (part of enabling chapter 6 of "Free Surface Flows with Moving and Deforming Objects for LBM")
- *****************************************************************************/
-void LbmFsgrSolver::setSurfGenSettings(short value)
-{
- mFsSurfGenSetting = value;
-}
-
-
-/******************************************************************************
- * Initialize omegas and forces on all levels (for init/timestep change)
- *****************************************************************************/
-void LbmFsgrSolver::initLevelOmegas()
-{
- // no explicit settings
- mOmega = mpParam->calculateOmega(mSimulationTime);
- mGravity = vec2L( mpParam->calculateGravity(mSimulationTime) );
- mSurfaceTension = 0.; //mpParam->calculateSurfaceTension(); // unused
- if(mInit2dYZ) { SWAPYZ(mGravity); }
-
- // check if last init was ok
- LbmFloat gravDelta = norm(mGravity-mLastGravity);
- //errMsg("ChannelAnimDebug","t:"<<mSimulationTime<<" om:"<<mOmega<<" - lom:"<<mLastOmega<<" gv:"<<mGravity<<" - "<<mLastGravity<<" , "<<gravDelta );
- if((mOmega == mLastOmega) && (gravDelta<=0.0)) return;
-
- if(mInitialCsmago<=0.0) {
- if(OPT3D==1) {
- errFatal("LbmFsgrSolver::initLevelOmegas","Csmago-LES = 0 not supported for optimized 3D version...",SIMWORLD_INITERROR);
- return;
- }
- }
-
- LbmFloat fineCsmago = mInitialCsmago;
- LbmFloat coarseCsmago = mInitialCsmago;
- LbmFloat maxFineCsmago1 = 0.026;
- LbmFloat maxCoarseCsmago1 = 0.029; // try stabilizing
- LbmFloat maxFineCsmago2 = 0.028;
- LbmFloat maxCoarseCsmago2 = 0.032; // try stabilizing some more
- if((mMaxRefine==1)&&(mInitialCsmago<maxFineCsmago1)) {
- fineCsmago = maxFineCsmago1;
- coarseCsmago = maxCoarseCsmago1;
- }
- if((mMaxRefine>1)&&(mInitialCsmago<maxFineCsmago2)) {
- fineCsmago = maxFineCsmago2;
- coarseCsmago = maxCoarseCsmago2;
- }
-
-
- // use Tau instead of Omega for calculations
- { // init base level
- int i = mMaxRefine;
- mLevel[i].omega = mOmega;
- mLevel[i].timestep = mpParam->getTimestep();
- mLevel[i].lcsmago = fineCsmago; //CSMAGO_INITIAL;
- mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago;
- mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0);
- }
-
- // init all sub levels
- for(int i=mMaxRefine-1; i>=0; i--) {
- //mLevel[i].omega = 2.0 * (mLevel[i+1].omega-0.5) + 0.5;
- double nomega = 0.5 * ( (1.0/(double)mLevel[i+1].omega) -0.5) + 0.5;
- nomega = 1.0/nomega;
- mLevel[i].omega = (LbmFloat)nomega;
- mLevel[i].timestep = 2.0 * mLevel[i+1].timestep;
- mLevel[i].lcsmago = coarseCsmago;
- mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago;
- mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0);
- }
-
- // for lbgk
- mLevel[ mMaxRefine ].gravity = mGravity / mLevel[ mMaxRefine ].omega;
- for(int i=mMaxRefine-1; i>=0; i--) {
- // should be the same on all levels...
- // for lbgk
- mLevel[i].gravity = (mLevel[i+1].gravity * mLevel[i+1].omega) * 2.0 / mLevel[i].omega;
- }
-
- mLastOmega = mOmega;
- mLastGravity = mGravity;
- // debug? invalidate old values...
- mGravity = -100.0;
- mOmega = -100.0;
-
- for(int i=0; i<=mMaxRefine; i++) {
- if(!mSilent) {
- errMsg("LbmFsgrSolver", "Level init "<<i<<" - sizes:"<<mLevel[i].lSizex<<","<<mLevel[i].lSizey<<","<<mLevel[i].lSizez<<" offs:"<<mLevel[i].lOffsx<<","<<mLevel[i].lOffsy<<","<<mLevel[i].lOffsz
- <<" omega:"<<mLevel[i].omega<<" grav:"<<mLevel[i].gravity<< ", "
- <<" cmsagp:"<<mLevel[i].lcsmago<<", "
- << " ss"<<mLevel[i].timestep<<" ns"<<mLevel[i].nodeSize<<" cs"<<mLevel[i].simCellSize );
- } else {
- if(!mInitDone) {
- debMsgStd("LbmFsgrSolver", DM_MSG, "Level init "<<i<<" - sizes:"<<mLevel[i].lSizex<<","<<mLevel[i].lSizey<<","<<mLevel[i].lSizez<<" "
- <<"omega:"<<mLevel[i].omega<<" grav:"<<mLevel[i].gravity , 5);
- }
- }
- }
- if(mMaxRefine>0) {
- mDfScaleUp = (mLevel[0 ].timestep/mLevel[0+1].timestep)* (1.0/mLevel[0 ].omega-1.0)/ (1.0/mLevel[0+1].omega-1.0); // yu
- mDfScaleDown = (mLevel[0+1].timestep/mLevel[0 ].timestep)* (1.0/mLevel[0+1].omega-1.0)/ (1.0/mLevel[0 ].omega-1.0); // yu
- }
-}
-
-
-/******************************************************************************
- * Init Solver (values should be read from config file)
- *****************************************************************************/
-
-/*! finish the init with config file values (allocate arrays...) */
-bool LbmFsgrSolver::initializeSolverMemory()
-{
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Init start... "<<mInitDone<<" "<<(void*)this,1);
-
- // init cppf stage
- if(mCppfStage>0) {
- mSizex *= mCppfStage;
- mSizey *= mCppfStage;
- mSizez *= mCppfStage;
- }
- if(mFsSurfGenSetting==-1) {
- // all on
- mFsSurfGenSetting =
- fssgNormal | fssgNoNorth | fssgNoSouth | fssgNoEast |
- fssgNoWest | fssgNoTop | fssgNoBottom | fssgNoObs ;
- }
-
- // size inits to force cubic cells and mult4 level dimensions
- // and make sure we dont allocate too much...
- bool memOk = false;
- int orgSx = mSizex;
- int orgSy = mSizey;
- int orgSz = mSizez;
- double sizeReduction = 1.0;
- double memEstFromFunc = -1.0;
- double memEstFine = -1.0;
- string memreqStr("");
- bool firstMInit = true;
- int minitTries=0;
- while(!memOk) {
- minitTries++;
- initGridSizes( mSizex, mSizey, mSizez,
- mvGeoStart, mvGeoEnd, mMaxRefine, PARALLEL);
-
- // MPT
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(firstMInit) {
- mrSetup();
- }
-#else
- (void)firstMInit;
-#endif // LBM_INCLUDE_TESTSOLVERS==1
- firstMInit=false;
-
- calculateMemreqEstimate( mSizex, mSizey, mSizez,
- mMaxRefine, mFarFieldSize, &memEstFromFunc, &memEstFine, &memreqStr );
-
- bool noLimit = false;
- double memLimit = 0.;
- string memLimStr("-");
- if(sizeof(void*)==4) {
- // 32bit system, limit to 2GB
- memLimit = 2.0* 1024.0*1024.0*1024.0;
- memLimStr = string("2GB");
- } else {
- // 64bit, just take 16GB as limit for now...
- // memLimit = 16.0* 1024.0*1024.0*1024.0;
- // memLimStr = string("16GB");
- noLimit = true;
- }
-
- // restrict max. chunk of 1 mem block to 1GB for windos
- bool memBlockAllocProblem = false;
- double maxDefaultMemChunk = 2.*1024.*1024.*1024.;
- //std::cerr<<" memEstFine "<< memEstFine <<" maxWin:" <<maxWinMemChunk <<" maxMac:" <<maxMacMemChunk ; // DEBUG
-#ifdef WIN32
- double maxWinMemChunk = 1100.*1024.*1024.;
- if(sizeof(void *)==4 && memEstFine>maxWinMemChunk) {
- memBlockAllocProblem = true;
- }
-#endif // WIN32
-#ifdef __APPLE__
- double maxMacMemChunk = 1200.*1024.*1024.;
- if(memEstFine> maxMacMemChunk) {
- memBlockAllocProblem = true;
- }
-#endif // Mac
- if(sizeof(void*)==4 && memEstFine>maxDefaultMemChunk) {
- // max memory chunk for 32bit systems 2gig
- memBlockAllocProblem = true;
- }
-
- if(!noLimit && (memEstFromFunc>memLimit || memBlockAllocProblem)) {
- sizeReduction *= 0.9;
- mSizex = (int)(orgSx * sizeReduction);
- mSizey = (int)(orgSy * sizeReduction);
- mSizez = (int)(orgSz * sizeReduction);
- debMsgStd("LbmFsgrSolver::initialize",DM_WARNING,"initGridSizes: memory limit exceeded "<<
- //memEstFromFunc<<"/"<<memLimit<<", "<<
- //memEstFine<<"/"<<maxWinMemChunk<<", "<<
- memreqStr<<"/"<<memLimStr<<", "<<
- "retrying: "<<PRINT_VEC(mSizex,mSizey,mSizez)<<" org:"<<PRINT_VEC(orgSx,orgSy,orgSz)
- , 3 );
- } else {
- memOk = true;
- }
- }
-
- mPreviewFactor = (LbmFloat)mOutputSurfacePreview / (LbmFloat)mSizex;
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"initGridSizes: Final domain size X:"<<mSizex<<" Y:"<<mSizey<<" Z:"<<mSizez<<
- ", Domain: "<<mvGeoStart<<":"<<mvGeoEnd<<", "<<(mvGeoEnd-mvGeoStart)<<
- ", PointerSize: "<< sizeof(void*) << ", IntSize: "<< sizeof(int) <<
- ", est. Mem.Req.: "<<memreqStr ,2);
- mpParam->setSize(mSizex, mSizey, mSizez);
- if((minitTries>1)&&(glob_mpnum)) { errMsg("LbmFsgrSolver::initialize","Warning!!!!!!!!!!!!!!! Original gridsize changed........."); }
-
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Definitions: "
- <<"LBM_EPSILON="<<LBM_EPSILON <<" "
- <<"FSGR_STRICT_DEBUG="<<FSGR_STRICT_DEBUG <<" "
- <<"OPT3D="<<OPT3D <<" "
- <<"COMPRESSGRIDS="<<COMPRESSGRIDS<<" "
- <<"MASS_INVALID="<<MASS_INVALID <<" "
- <<"FSGR_LISTTRICK="<<FSGR_LISTTRICK <<" "
- <<"FSGR_LISTTTHRESHEMPTY="<<FSGR_LISTTTHRESHEMPTY <<" "
- <<"FSGR_LISTTTHRESHFULL="<<FSGR_LISTTTHRESHFULL <<" "
- <<"FSGR_MAGICNR="<<FSGR_MAGICNR <<" "
- <<"USE_LES="<<USE_LES <<" "
- ,10);
-
- // perform 2D corrections...
- if(LBMDIM == 2) mSizez = 1;
-
- mpParam->setSimulationMaxSpeed(0.0);
- if(mFVHeight>0.0) mpParam->setFluidVolumeHeight(mFVHeight);
- mpParam->setTadapLevels( mMaxRefine+1 );
-
- if(mForceTadapRefine>mMaxRefine) {
- mpParam->setTadapLevels( mForceTadapRefine+1 );
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Forcing a t-adap refine level of "<<mForceTadapRefine, 6);
- }
-
- if(!mpParam->calculateAllMissingValues(mSimulationTime, false)) {
- errFatal("LbmFsgrSolver::initialize","Fatal: failed to init parameters! Aborting...",SIMWORLD_INITERROR);
- return false;
- }
-
-
- // init vectors
- for(int i=0; i<=mMaxRefine; i++) {
- mLevel[i].id = i;
- mLevel[i].nodeSize = 0.0;
- mLevel[i].simCellSize = 0.0;
- mLevel[i].omega = 0.0;
- mLevel[i].time = 0.0;
- mLevel[i].timestep = 1.0;
- mLevel[i].gravity = LbmVec(0.0);
- mLevel[i].mprsCells[0] = NULL;
- mLevel[i].mprsCells[1] = NULL;
- mLevel[i].mprsFlags[0] = NULL;
- mLevel[i].mprsFlags[1] = NULL;
-
- mLevel[i].avgOmega = 0.0;
- mLevel[i].avgOmegaCnt = 0.0;
- }
-
-#if PARALLEL == 1
- /*
- // DG: this would be the correct sanity check, not the "hack below" */
- // if(( mSizey / mNumOMPThreads) * mNumOMPThreads != mSizey) {
- // setNumOMPThreads();
- //}
- if( mSizey < mNumOMPThreads ) {
- setNumOMPThreads(mSizey);
- }
-#endif
-
- // init sizes
- mLevel[mMaxRefine].lSizex = mSizex;
- mLevel[mMaxRefine].lSizey = mSizey;
- mLevel[mMaxRefine].lSizez = mSizez;
- for(int i=mMaxRefine-1; i>=0; i--) {
- mLevel[i].lSizex = mLevel[i+1].lSizex/2;
- mLevel[i].lSizey = mLevel[i+1].lSizey/2;
- mLevel[i].lSizez = mLevel[i+1].lSizez/2;
- }
-
- // safety check
- if(sizeof(CellFlagType) != CellFlagTypeSize) {
- errFatal("LbmFsgrSolver::initialize","Fatal Error: CellFlagType has wrong size! Is:"<<sizeof(CellFlagType)<<", should be:"<<CellFlagTypeSize, SIMWORLD_GENERICERROR);
- return false;
- }
-
- double ownMemCheck = 0.0;
- mLevel[ mMaxRefine ].nodeSize = ((mvGeoEnd[0]-mvGeoStart[0]) / (LbmFloat)(mSizex));
- mLevel[ mMaxRefine ].simCellSize = mpParam->getCellSize();
- mLevel[ mMaxRefine ].lcellfactor = 1.0;
- LONGINT rcellSize = (LONGINT)((LONGINT)((LONGINT)mLevel[mMaxRefine].lSizex*(LONGINT)mLevel[mMaxRefine].lSizey*(LONGINT)mLevel[mMaxRefine].lSizez) * (LONGINT)dTotalNum);
-
-#if COMPRESSGRIDS==0
- mLevel[ mMaxRefine ].mprsCells[0] = new LbmFloat[ rcellSize +4 ];
- mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +4 ];
- ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4);
-#else // COMPRESSGRIDS==0
- LONGINT compressOffset = (LONGINT)((LONGINT)mLevel[mMaxRefine].lSizex * (LONGINT)mLevel[mMaxRefine].lSizey * (LONGINT)dTotalNum * 2);
- // LONGINT tmp = ( (rcellSize +compressOffset +4)/(1024*1024) )*sizeof(LbmFloat);
- // printf("Debug MEMMMM excee: %I64d, %I64d, %I64d, %d, %d\n", tmp, compressOffset, rcellSize, mLevel[mMaxRefine].lSizex, mLevel[mMaxRefine].lSizey );
- mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +compressOffset +4 ];
- mLevel[ mMaxRefine ].mprsCells[0] = mLevel[ mMaxRefine ].mprsCells[1]+compressOffset;
- ownMemCheck += sizeof(LbmFloat) * (rcellSize +compressOffset +4);
-#endif // COMPRESSGRIDS==0
-
- if(!mLevel[ mMaxRefine ].mprsCells[1] || !mLevel[ mMaxRefine ].mprsCells[0]) {
- errFatal("LbmFsgrSolver::initialize","Fatal: Couldnt allocate memory (1)! Aborting...",SIMWORLD_INITERROR);
- return false;
- }
-
- // +4 for safety ?
- mLevel[ mMaxRefine ].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ];
- mLevel[ mMaxRefine ].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ];
- ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4);
- if(!mLevel[ mMaxRefine ].mprsFlags[1] || !mLevel[ mMaxRefine ].mprsFlags[0]) {
- errFatal("LbmFsgrSolver::initialize","Fatal: Couldnt allocate memory (2)! Aborting...",SIMWORLD_INITERROR);
-
-#if COMPRESSGRIDS==0
- delete[] mLevel[ mMaxRefine ].mprsCells[0];
- delete[] mLevel[ mMaxRefine ].mprsCells[1];
-#else // COMPRESSGRIDS==0
- delete[] mLevel[ mMaxRefine ].mprsCells[1];
-#endif // COMPRESSGRIDS==0
- return false;
- }
-
- LbmFloat lcfdimFac = 8.0;
- if(LBMDIM==2) lcfdimFac = 4.0;
- for(int i=mMaxRefine-1; i>=0; i--) {
- mLevel[i].nodeSize = 2.0 * mLevel[i+1].nodeSize;
- mLevel[i].simCellSize = 2.0 * mLevel[i+1].simCellSize;
- mLevel[i].lcellfactor = mLevel[i+1].lcellfactor * lcfdimFac;
-
- if(LBMDIM==2){ mLevel[i].lSizez = 1; } // 2D
- rcellSize = ((mLevel[i].lSizex*mLevel[i].lSizey*mLevel[i].lSizez) *dTotalNum);
- mLevel[i].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ];
- mLevel[i].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ];
- ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4);
- mLevel[i].mprsCells[0] = new LbmFloat[ rcellSize +4 ];
- mLevel[i].mprsCells[1] = new LbmFloat[ rcellSize +4 ];
- ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4);
- }
-
- // isosurface memory, use orig res values
- if(mFarFieldSize>0.) {
- ownMemCheck += (double)( (3*sizeof(int)+sizeof(float)) * ((mSizex+2)*(mSizey+2)*(mSizez+2)) );
- } else {
- // ignore 3 int slices...
- ownMemCheck += (double)( ( sizeof(float)) * ((mSizex+2)*(mSizey+2)*(mSizez+2)) );
- }
-
- // sanity check
-#if ELBEEM_PLUGIN!=1
- if(ABS(1.0-ownMemCheck/memEstFromFunc)>0.01) {
- errMsg("LbmFsgrSolver::initialize","Sanity Error - memory estimate is off! real:"<<ownMemCheck<<" vs. estimate:"<<memEstFromFunc );
- }
-#endif // ELBEEM_PLUGIN!=1
-
- // init sizes for _all_ levels
- for(int i=mMaxRefine; i>=0; i--) {
- mLevel[i].lOffsx = mLevel[i].lSizex;
- mLevel[i].lOffsy = mLevel[i].lOffsx*mLevel[i].lSizey;
- mLevel[i].lOffsz = mLevel[i].lOffsy*mLevel[i].lSizez;
- mLevel[i].setCurr = 0;
- mLevel[i].setOther = 1;
- mLevel[i].lsteps = 0;
- mLevel[i].lmass = 0.0;
- mLevel[i].lvolume = 0.0;
- }
-
- // calc omega, force for all levels
- initLevelOmegas();
- mMinTimestep = mpParam->getTimestep();
- mMaxTimestep = mpParam->getTimestep();
-
- // init isosurf
- mpIso->setIsolevel( mIsoValue );
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(mUseTestdata) {
- mpTest->setMaterialName( mpIso->getMaterialName() );
- delete mpIso;
- mpIso = mpTest;
- if(mpTest->mFarfMode>0) { // 3d off
- mpTest->setIsolevel(-100.0);
- } else {
- mpTest->setIsolevel( mIsoValue );
- }
- }
-#endif // LBM_INCLUDE_TESTSOLVERS!=1
- // approximate feature size with mesh resolution
- float featureSize = mLevel[ mMaxRefine ].nodeSize*0.5;
- // smooth vars defined in solver_interface, set by simulation object
- // reset for invalid values...
- if((mSmoothSurface<0.)||(mSmoothSurface>50.)) mSmoothSurface = 1.;
- if((mSmoothNormals<0.)||(mSmoothNormals>50.)) mSmoothNormals = 1.;
- mpIso->setSmoothSurface( mSmoothSurface * featureSize );
- mpIso->setSmoothNormals( mSmoothNormals * featureSize );
-
- // init iso weight values mIsoWeightMethod
- int wcnt = 0;
- float totw = 0.0;
- for(int ak=-1;ak<=1;ak++)
- for(int aj=-1;aj<=1;aj++)
- for(int ai=-1;ai<=1;ai++) {
- switch(mIsoWeightMethod) {
- case 1: // light smoothing
- mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) );
- break;
- case 2: // very light smoothing
- mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) );
- mIsoWeight[wcnt] *= mIsoWeight[wcnt];
- break;
- case 3: // no smoothing
- if(ai==0 && aj==0 && ak==0) mIsoWeight[wcnt] = 1.0;
- else mIsoWeight[wcnt] = 0.0;
- break;
- default: // strong smoothing (=0)
- mIsoWeight[wcnt] = 1.0;
- break;
- }
- totw += mIsoWeight[wcnt];
- wcnt++;
- }
- for(int i=0; i<27; i++) mIsoWeight[i] /= totw;
-
- LbmVec isostart = vec2L(mvGeoStart);
- LbmVec isoend = vec2L(mvGeoEnd);
- int twodOff = 0; // 2d slices
- if(LBMDIM==2) {
- LbmFloat sn,se;
- sn = isostart[2]+(isoend[2]-isostart[2])*0.5 - ((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5;
- se = isostart[2]+(isoend[2]-isostart[2])*0.5 + ((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5;
- isostart[2] = sn;
- isoend[2] = se;
- twodOff = 2;
- }
- int isosx = mSizex+2;
- int isosy = mSizey+2;
- int isosz = mSizez+2+twodOff;
-
- // MPT
-#if LBM_INCLUDE_TESTSOLVERS==1
- //if( strstr( this->getName().c_str(), "mpfluid1" ) != NULL) {
- if( (mMpNum>0) && (mMpIndex==0) ) {
- //? mpindex==0
- // restore original value for node0
- isosx = mOrgSizeX + 2;
- isostart[0] = mOrgStartX;
- isoend[0] = mOrgEndX;
- }
- errMsg("LbmFsgrSolver::initialize", "MPT: gcon "<<mMpNum<<","<<mMpIndex<<" src"<< PRINT_VEC(mpTest->mGCMin.mSrcx,mpTest->mGCMin.mSrcy,mpTest->mGCMin.mSrcz)<<" dst"
- << PRINT_VEC(mpTest->mGCMin.mDstx,mpTest->mGCMin.mDsty,mpTest->mGCMin.mDstz)<<" consize"
- << PRINT_VEC(mpTest->mGCMin.mConSizex,mpTest->mGCMin.mConSizey,mpTest->mGCMin.mConSizez)<<" ");
- errMsg("LbmFsgrSolver::initialize", "MPT: gcon "<<mMpNum<<","<<mMpIndex<<" src"<< PRINT_VEC(mpTest->mGCMax.mSrcx,mpTest->mGCMax.mSrcy,mpTest->mGCMax.mSrcz)<<" dst"
- << PRINT_VEC(mpTest->mGCMax.mDstx,mpTest->mGCMax.mDsty,mpTest->mGCMax.mDstz)<<" consize"
- << PRINT_VEC(mpTest->mGCMax.mConSizex,mpTest->mGCMax.mConSizey,mpTest->mGCMax.mConSizez)<<" ");
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
- errMsg(" SETISO ", "iso "<<isostart<<" - "<<isoend<<" "<<(((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5)<<" "<<(LbmFloat)(mSizex+1.0) );
- errMsg("LbmFsgrSolver::initialize", "MPT: geo "<< mvGeoStart<<","<<mvGeoEnd<<
- " grid:"<<PRINT_VEC(mSizex,mSizey,mSizez)<<",iso:"<< PRINT_VEC(isosx,isosy,isosz) );
- mpIso->setStart( vec2G(isostart) );
- mpIso->setEnd( vec2G(isoend) );
- LbmVec isodist = isoend-isostart;
-
- int isosubs = mIsoSubdivs;
- if(mFarFieldSize>1.) {
- errMsg("LbmFsgrSolver::initialize","Warning - resetting isosubdivs, using fulledge!");
- isosubs = 1;
- mpIso->setUseFulledgeArrays(true);
- }
- mpIso->setSubdivs(isosubs);
-
- mpIso->initializeIsosurface( isosx,isosy,isosz, vec2G(isodist) );
-
- // reset iso field
- for(int ak=0;ak<isosz;ak++)
- for(int aj=0;aj<isosy;aj++)
- for(int ai=0;ai<isosx;ai++) { *mpIso->getData(ai,aj,ak) = 0.0; }
-
-
- /* init array (set all invalid first) */
- preinitGrids();
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) {
- RFLAG(lev,i,j,k,0) = 0, RFLAG(lev,i,j,k,0) = 0; // reset for changeFlag usage
- if(!mAllfluid) {
- initEmptyCell(lev, i,j,k, CFEmpty, -1.0, -1.0);
- } else {
- initEmptyCell(lev, i,j,k, CFFluid, 1.0, 1.0);
- }
- }
- }
-
-
- if(LBMDIM==2) {
- if(mOutputSurfacePreview) {
- errMsg("LbmFsgrSolver::init","No preview in 2D allowed!");
- mOutputSurfacePreview = 0; }
- }
- if((glob_mpactive) && (glob_mpindex>0)) {
- mOutputSurfacePreview = 0;
- }
-
-#if LBM_USE_GUI==1
- if(mOutputSurfacePreview) {
- errMsg("LbmFsgrSolver::init","No preview in GUI mode... mOutputSurfacePreview=0");
- mOutputSurfacePreview = 0; }
-#endif // LBM_USE_GUI==1
- if(mOutputSurfacePreview) {
- // same as normal one, but use reduced size
- mpPreviewSurface = new IsoSurface( mIsoValue );
- mpPreviewSurface->setMaterialName( mpPreviewSurface->getMaterialName() );
- mpPreviewSurface->setIsolevel( mIsoValue );
- // usually dont display for rendering
- mpPreviewSurface->setVisible( false );
-
- mpPreviewSurface->setStart( vec2G(isostart) );
- mpPreviewSurface->setEnd( vec2G(isoend) );
- LbmVec pisodist = isoend-isostart;
- LbmFloat pfac = mPreviewFactor;
- mpPreviewSurface->initializeIsosurface( (int)(pfac*mSizex)+2, (int)(pfac*mSizey)+2, (int)(pfac*mSizez)+2, vec2G(pisodist) );
- //mpPreviewSurface->setName( getName() + "preview" );
- mpPreviewSurface->setName( "preview" );
-
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Preview with sizes "<<(pfac*mSizex)<<","<<(pfac*mSizey)<<","<<(pfac*mSizez)<<" enabled",10);
- }
-
- // init defaults
- mAvgNumUsedCells = 0;
- mFixMass= 0.0;
- return true;
-}
-
-/*! init solver arrays */
-bool LbmFsgrSolver::initializeSolverGrids() {
- /* init boundaries */
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Boundary init...",10);
- // init obstacles, and reinit time step size
- initGeometryFlags();
- mLastSimTime = -1.0;
- // TODO check for invalid cells? nitGenericTestCases();
-
- // new - init noslip 1 everywhere...
- // half fill boundary cells?
-
- CellFlagType domainBoundType = CFInvalid;
- // TODO use normal object types instad...
- if(mDomainBound.find(string("free")) != string::npos) {
- domainBoundType = CFBnd | CFBndFreeslip;
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Domain Boundary Type: FreeSlip, value:"<<mDomainBound,10);
- } else if(mDomainBound.find(string("part")) != string::npos) {
- domainBoundType = CFBnd | CFBndPartslip; // part slip type
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Domain Boundary Type: PartSlip ("<<mDomainPartSlipValue<<"), value:"<<mDomainBound,10);
- } else {
- domainBoundType = CFBnd | CFBndNoslip;
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Domain Boundary Type: NoSlip, value:"<<mDomainBound,10);
- }
-
- // use ar[numobjs] as entry for domain (used e.g. for mDomainPartSlipValue in mObjectPartslips)
- int domainobj = (int)(mpGiObjects->size());
- domainBoundType |= (domainobj<<24);
- //for(int i=0; i<(int)(domainobj+0); i++) {
- //errMsg("GEOIN","i"<<i<<" "<<(*mpGiObjects)[i]->getName());
- //if((*mpGiObjects)[i] == mpIso) { //check...
- //}
- //}
- //errMsg("GEOIN"," dm "<<(domainBoundType>>24));
-
- for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
- for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
- initEmptyCell(mMaxRefine, i,0,k, domainBoundType, 0.0, BND_FILL);
- initEmptyCell(mMaxRefine, i,mLevel[mMaxRefine].lSizey-1,k, domainBoundType, 0.0, BND_FILL);
- }
-
- for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
- initEmptyCell(mMaxRefine, 0,j,k, domainBoundType, 0.0, BND_FILL);
- initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-1,j,k, domainBoundType, 0.0, BND_FILL);
- // DEBUG BORDER!
- //initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-2,j,k, domainBoundType, 0.0, BND_FILL);
- }
-
- if(LBMDIM == 3) {
- // only for 3D
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++)
- for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
- initEmptyCell(mMaxRefine, i,j,0, domainBoundType, 0.0, BND_FILL);
- initEmptyCell(mMaxRefine, i,j,mLevel[mMaxRefine].lSizez-1, domainBoundType, 0.0, BND_FILL);
- }
- }
-
- // TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11
- /*for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
- initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-2,j,k, domainBoundType, 0.0, BND_FILL);
- }
- for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
- for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
- initEmptyCell(mMaxRefine, i,1,k, domainBoundType, 0.0, BND_FILL);
- }
- // */
-
- /*for(int ii=0; ii<(int)po w_change?(2.0,mMaxRefine)-1; ii++) {
- errMsg("BNDTESTSYMM","set "<<mLevel[mMaxRefine].lSizex-2-ii );
- for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
- initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-2-ii,j,k, domainBoundType, 0.0, BND_FILL); // SYMM!? 2D?
- }
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++)
- for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
- initEmptyCell(mMaxRefine, i,j,mLevel[mMaxRefine].lSizez-2-ii, domainBoundType, 0.0, BND_FILL); // SYMM!? 3D?
- }
- }
- // Symmetry tests */
- // vortt
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(( strstr( this->getName().c_str(), "vorttfluid" ) != NULL) && (LBMDIM==2)) {
- errMsg("VORTT","init");
- int level=mMaxRefine;
- int cx = mLevel[level].lSizex/2;
- int cyo = mLevel[level].lSizey/2;
- int sx = mLevel[level].lSizex/8;
- int sy = mLevel[level].lSizey/8;
- LbmFloat rho = 1.;
- LbmFloat rhomass = 1.;
- LbmFloat uFactor = 0.15;
- LbmFloat vdist = 1.0;
-
- int cy1=cyo-(int)(vdist*sy);
- int cy2=cyo+(int)(vdist*sy);
-
- //for(int j=cy-sy;j<cy+sy;j++) for(int i=cx-sx;i<cx+sx;i++) {
- for(int j=1;j<mLevel[level].lSizey-1;j++)
- for(int i=1;i<mLevel[level].lSizex-1;i++) {
- LbmFloat d1 = norm(LbmVec(cx,cy1,0.)-LbmVec(i,j,0));
- LbmFloat d2 = norm(LbmVec(cx,cy2,0.)-LbmVec(i,j,0));
- bool in1 = (d1<=(LbmFloat)(sx));
- bool in2 = (d2<=(LbmFloat)(sx));
- LbmVec uvec(0.);
- LbmVec v1 = getNormalized( cross( LbmVec(cx,cy1,0.)-LbmVec(i,j,0), LbmVec(0.,0.,1.)) )* uFactor;
- LbmVec v2 = getNormalized( cross( LbmVec(cx,cy2,0.)-LbmVec(i,j,0), LbmVec(0.,0.,1.)) )* uFactor;
- LbmFloat w1=1., w2=1.;
- if(!in1) w1=(LbmFloat)(sx)/(1.5*d1);
- if(!in2) w2=(LbmFloat)(sx)/(1.5*d2);
- if(!in1) w1=0.; if(!in2) w2=0.; // sharp falloff
- uvec += v1*w1;
- uvec += v2*w2;
- initVelocityCell(level, i,j,0, CFFluid, rho, rhomass, uvec );
- //errMsg("VORTT","init uvec"<<uvec);
- }
-
- }
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
- //if(getGlobalBakeState()<0) { CAUSE_PANIC; errMsg("LbmFsgrSolver::initialize","Got abort signal1, causing panic, aborting..."); return false; }
-
- // prepare interface cells
- initFreeSurfaces();
- initStandingFluidGradient();
-
- // perform first step to init initial mass
- mInitialMass = 0.0;
- int inmCellCnt = 0;
- FSGR_FORIJK1(mMaxRefine) {
- if( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFFluid) {
- LbmFloat fluidRho = QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, 0);
- FORDF1 { fluidRho += QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, l); }
- mInitialMass += fluidRho;
- inmCellCnt ++;
- } else if( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFInter) {
- mInitialMass += QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, dMass);
- inmCellCnt ++;
- }
- }
- mCurrentVolume = mCurrentMass = mInitialMass;
-
- ParamVec cspv = mpParam->calculateCellSize();
- if(LBMDIM==2) cspv[2] = 1.0;
- inmCellCnt = 1;
- double nrmMass = (double)mInitialMass / (double)(inmCellCnt) *cspv[0]*cspv[1]*cspv[2] * 1000.0;
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Initial Mass:"<<mInitialMass<<" normalized:"<<nrmMass, 3);
- mInitialMass = 0.0; // reset, and use actual value after first step
-
- //mStartSymm = false;
-#if ELBEEM_PLUGIN!=1
- if((LBMDIM==2)&&(mSizex<200)) {
- if(!checkSymmetry("init")) {
- errMsg("LbmFsgrSolver::initialize","Unsymmetric init...");
- } else {
- errMsg("LbmFsgrSolver::initialize","Symmetric init!");
- }
- }
-#endif // ELBEEM_PLUGIN!=1
- return true;
-}
-
-
-/*! prepare actual simulation start, setup viz etc */
-bool LbmFsgrSolver::initializeSolverPostinit() {
- // coarsen region
- myTime_t fsgrtstart = getTime();
- for(int lev=mMaxRefine-1; lev>=0; lev--) {
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Coarsening level "<<lev<<".",8);
- adaptGrid(lev);
- coarseRestrictFromFine(lev);
- adaptGrid(lev);
- coarseRestrictFromFine(lev);
- }
- markedClearList();
- myTime_t fsgrtend = getTime();
- if(!mSilent){ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"FSGR init done ("<< getTimeString(fsgrtend-fsgrtstart)<<"), changes:"<<mNumFsgrChanges , 10 ); }
- mNumFsgrChanges = 0;
-
- for(int l=0; l<cDirNum; l++) {
- LbmFloat area = 0.5 * 0.5 *0.5;
- if(LBMDIM==2) area = 0.5 * 0.5;
-
- if(dfVecX[l]!=0) area *= 0.5;
- if(dfVecY[l]!=0) area *= 0.5;
- if(dfVecZ[l]!=0) area *= 0.5;
- mFsgrCellArea[l] = area;
- } // l
-
- // make sure both sets are ok
- // copy from other to curr
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) {
- RFLAG(lev, i,j,k,mLevel[lev].setOther) = RFLAG(lev, i,j,k,mLevel[lev].setCurr);
- } } // first copy flags */
-
-
- // old mpPreviewSurface init
- //if(getGlobalBakeState()<0) { CAUSE_PANIC; errMsg("LbmFsgrSolver::initialize","Got abort signal2, causing panic, aborting..."); return false; }
- // make sure fill fracs are right for first surface generation
- stepMain();
-
- // prepare once...
- mpIso->setParticles(mpParticles, mPartDropMassSub);
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Iso Settings, subdivs="<<mpIso->getSubdivs()<<", partsize="<<mPartDropMassSub, 9);
- prepareVisualization();
- // copy again for stats counting
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) {
- RFLAG(lev, i,j,k,mLevel[lev].setOther) = RFLAG(lev, i,j,k,mLevel[lev].setCurr);
- } } // first copy flags */
-
-
- // now really done...
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"SurfaceGen: SmsOrg("<<mSmoothSurface<<","<<mSmoothNormals<< /*","<<featureSize<<*/ "), Iso("<<mpIso->getSmoothSurface()<<","<<mpIso->getSmoothNormals()<<") ",10);
- debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Init done ... ",10);
- mInitDone = 1;
-
- // init fluid control
- initCpdata();
-
-#if LBM_INCLUDE_TESTSOLVERS==1
- initTestdata();
-#endif // ELBEEM_PLUGIN!=1
- // not inited? dont use...
- if(mCutoff<0) mCutoff=0;
-
- initParticles();
- return true;
-}
-
-
-
-// macros for mov obj init
-#if LBMDIM==2
-
-#define POS2GRID_CHECK(vec,n) \
- monTotal++;\
- int k=(int)( ((vec)[n][2]-iniPos[2])/dvec[2] +0.0); \
- if(k!=0) continue; \
- const int i=(int)( ((vec)[n][0]-iniPos[0])/dvec[0] +0.0); \
- if(i<=0) continue; \
- if(i>=mLevel[level].lSizex-1) continue; \
- const int j=(int)( ((vec)[n][1]-iniPos[1])/dvec[1] +0.0); \
- if(j<=0) continue; \
- if(j>=mLevel[level].lSizey-1) continue; \
-
-#else // LBMDIM -> 3
-#define POS2GRID_CHECK(vec,n) \
- monTotal++;\
- const int i=(int)( ((vec)[n][0]-iniPos[0])/dvec[0] +0.0); \
- if(i<=0) continue; \
- if(i>=mLevel[level].lSizex-1) continue; \
- const int j=(int)( ((vec)[n][1]-iniPos[1])/dvec[1] +0.0); \
- if(j<=0) continue; \
- if(j>=mLevel[level].lSizey-1) continue; \
- const int k=(int)( ((vec)[n][2]-iniPos[2])/dvec[2] +0.0); \
- if(k<=0) continue; \
- if(k>=mLevel[level].lSizez-1) continue; \
-
-#endif // LBMDIM
-
-// calculate object velocity from vert arrays in objvel vec
-#define OBJVEL_CALC \
- LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); { \
- const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; \
- USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); \
- if(usqr>maxusqr) { \
- /* cutoff at maxVelVal */ \
- for(int jj=0; jj<3; jj++) { \
- if(objvel[jj]>0.) objvel[jj] = maxVelVal; \
- if(objvel[jj]<0.) objvel[jj] = -maxVelVal; \
- } \
- } } \
- if(ntype&(CFBndFreeslip)) { \
- const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); \
- /* const LbmVec oldov=objvel; */ /*DEBUG*/ \
- objvel = vec2L((*pNormals)[n]) *dp; \
- /* if((j==24)&&(n%5==2)) errMsg("FSBT","n"<<n<<" v"<<objvel<<" nn"<<(*pNormals)[n]<<" dp"<<dp<<" oldov"<<oldov ); */ \
- } \
- else if(ntype&(CFBndPartslip)) { \
- const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); \
- /* const LbmVec oldov=objvel; */ /*DEBUG*/ \
- /* if((j==24)&&(n%5==2)) errMsg("FSBT","n"<<n<<" v"<<objvel<<" nn"<<(*pNormals)[n]<<" dp"<<dp<<" oldov"<<oldov ); */ \
- const LbmFloat partv = mObjectPartslips[OId]; \
- /*errMsg("PARTSLIP_DEBUG","l="<<l<<" ccel="<<RAC(ccel, dfInv[l] )<<" partv="<<partv<<",id="<<(int)(mnbf>>24)<<" newval="<<newval ); / part slip debug */ \
- /* m[l] = (RAC(ccel, dfInv[l] ) ) * partv + newval * (1.-partv); part slip */ \
- objvel = objvel*partv + vec2L((*pNormals)[n]) *dp*(1.-partv); \
- }
-
-#define TTT \
-
-
-/*****************************************************************************/
-//! init moving obstacles for next sim step sim
-/*****************************************************************************/
-void LbmFsgrSolver::initMovingObstacles(bool staticInit) {
- myTime_t monstart = getTime();
-
- // movobj init
- const int level = mMaxRefine;
- const int workSet = mLevel[level].setCurr;
- const int otherSet = mLevel[level].setOther;
- LbmFloat sourceTime = mSimulationTime; // should be equal to mLastSimTime!
- // for debugging - check targetTime check during DEFAULT STREAM
- LbmFloat targetTime = mSimulationTime + mpParam->getTimestep();
- if(mLastSimTime == targetTime) {
- debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_WARNING,"Called for same time! (t="<<mSimulationTime<<" , targett="<<targetTime<<")", 1);
- return;
- }
- //debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_WARNING,"time: "<<mSimulationTime<<" lasttt:"<<mLastSimTime,10);
- //if(mSimulationTime!=mLastSimTime) errMsg("LbmFsgrSolver::initMovingObstacles","time: "<<mSimulationTime<<" lasttt:"<<mLastSimTime);
-
- const LbmFloat maxVelVal = 0.1666;
- const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5;
-
- LbmFloat rhomass = 0.0;
- CellFlagType otype = CFInvalid; // verify type of last step, might be non moving obs!
- CellFlagType ntype = CFInvalid;
- // WARNING - copied from geo init!
- int numobjs = (int)(mpGiObjects->size());
- ntlVec3Gfx dvec = ntlVec3Gfx(mLevel[level].nodeSize); //dvec*1.0;
- // 2d display as rectangles
- ntlVec3Gfx iniPos(0.0);
- if(LBMDIM==2) {
- dvec[2] = 1.0;
- iniPos = (mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (mvGeoEnd[2]-mvGeoStart[2])*0.5 ))-(dvec*0.0);
- } else {
- iniPos = (mvGeoStart + ntlVec3Gfx( 0.0 ))-(dvec*0.0);
- }
-
- if( (int)mObjectMassMovnd.size() < numobjs) {
- for(int i=mObjectMassMovnd.size(); i<numobjs; i++) {
- mObjectMassMovnd.push_back(0.);
- }
- }
-
- // stats
- int monPoints=0, monObsts=0, monFluids=0, monTotal=0, monTrafo=0;
- int nbored;
- for(int OId=0; OId<numobjs; OId++) {
- ntlGeometryObject *obj = (*mpGiObjects)[OId];
- bool skip = false;
- if(obj->getGeoInitId() != mLbmInitId) skip=true;
- if( (!staticInit) && (!obj->getIsAnimated()) ) skip=true;
- if( ( staticInit) && ( obj->getIsAnimated()) ) skip=true;
- if(skip) continue;
- debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" skip:"<<skip<<", static:"<<staticInit<<" anim:"<<obj->getIsAnimated()<<" gid:"<<obj->getGeoInitId()<<" simgid:"<<mLbmInitId, 10);
-
- if( (obj->getGeoInitType()&FGI_ALLBOUNDS) ||
- ((obj->getGeoInitType()&FGI_FLUID) && staticInit) ) {
-
- otype = ntype = CFInvalid;
- switch(obj->getGeoInitType()) {
- /* case FGI_BNDPART: // old, use noslip for moving part/free objs
- case FGI_BNDFREE:
- if(!staticInit) {
- errMsg("LbmFsgrSolver::initMovingObstacles","Warning - moving free/part slip objects NYI "<<obj->getName() );
- otype = ntype = CFBnd|CFBndNoslip;
- } else {
- if(obj->getGeoInitType()==FGI_BNDPART) otype = ntype = CFBnd|CFBndPartslip;
- if(obj->getGeoInitType()==FGI_BNDFREE) otype = ntype = CFBnd|CFBndFreeslip;
- }
- break;
- // off */
- case FGI_BNDPART: rhomass = BND_FILL;
- otype = ntype = CFBnd|CFBndPartslip|(OId<<24);
- break;
- case FGI_BNDFREE: rhomass = BND_FILL;
- otype = ntype = CFBnd|CFBndFreeslip|(OId<<24);
- break;
- // off */
- case FGI_BNDNO: rhomass = BND_FILL;
- otype = ntype = CFBnd|CFBndNoslip|(OId<<24);
- break;
- case FGI_FLUID:
- otype = ntype = CFFluid;
- break;
- case FGI_MBNDINFLOW:
- otype = ntype = CFMbndInflow;
- break;
- case FGI_MBNDOUTFLOW:
- otype = ntype = CFMbndOutflow;
- break;
- }
- int wasActive = ((obj->getGeoActive(sourceTime)>0.)? 1:0);
- int active = ((obj->getGeoActive(targetTime)>0.)? 1:0);
- //errMsg("GEOACTT"," obj "<<obj->getName()<<" a:"<<active<<","<<wasActive<<" s"<<sourceTime<<" t"<<targetTime <<" v"<<mObjectSpeeds[OId] );
- // skip inactive in/out flows
- if(ntype==CFInvalid){ errMsg("LbmFsgrSolver::initMovingObstacles","Invalid obj type "<<obj->getGeoInitType()); continue; }
- if((!active) && (otype&(CFMbndOutflow|CFMbndInflow)) ) continue;
-
- // copied from recalculateObjectSpeeds
- mObjectSpeeds[OId] = vec2L(mpParam->calculateLattVelocityFromRw( vec2P( (*mpGiObjects)[OId]->getInitialVelocity(mSimulationTime) )));
- debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG,"id"<<OId<<" "<<obj->getName()<<" inivel set to "<< mObjectSpeeds[OId]<<", unscaled:"<< (*mpGiObjects)[OId]->getInitialVelocity(mSimulationTime) ,10 );
-
- //vector<ntlVec3Gfx> tNormals;
- vector<ntlVec3Gfx> *pNormals = NULL;
- mMOINormals.clear();
- if(ntype&(CFBndFreeslip|CFBndPartslip)) { pNormals = &mMOINormals; }
-
- mMOIVertices.clear();
- if(obj->getMeshAnimated()) {
- // do two full update
- // TODO tNormals handling!?
- mMOIVerticesOld.clear();
- obj->initMovingPointsAnim(sourceTime,mMOIVerticesOld, targetTime, mMOIVertices, pNormals, mLevel[mMaxRefine].nodeSize, mvGeoStart, mvGeoEnd);
- monTrafo += mMOIVerticesOld.size();
- obj->applyTransformation(sourceTime, &mMOIVerticesOld,pNormals, 0, mMOIVerticesOld.size(), false );
- monTrafo += mMOIVertices.size();
- obj->applyTransformation(targetTime, &mMOIVertices,NULL /* no old normals needed */, 0, mMOIVertices.size(), false );
- } else {
- // only do transform update
- obj->getMovingPoints(mMOIVertices,pNormals); // mMOIVertices = mCachedMovPoints
- mMOIVerticesOld = mMOIVertices;
- // WARNING - assumes mSimulationTime is global!?
- obj->applyTransformation(targetTime, &mMOIVertices,pNormals, 0, mMOIVertices.size(), false );
- monTrafo += mMOIVertices.size();
-
- // correct flags from last position, but extrapolate
- // velocity to next timestep
- obj->applyTransformation(sourceTime, &mMOIVerticesOld, NULL /* no old normals needed */, 0, mMOIVerticesOld.size(), false );
- monTrafo += mMOIVerticesOld.size();
- }
-
- // object types
- if(ntype&CFBnd){
-
- // check if object is moving at all
- if(obj->getIsAnimated()) {
- ntlVec3Gfx objMaxVel = obj->calculateMaxVel(sourceTime,targetTime);
- // FIXME?
- if(normNoSqrt(objMaxVel)>0.0) { ntype |= CFBndMoving; }
- // get old type - CHECK FIXME , timestep could have changed - cause trouble?
- ntlVec3Gfx oldobjMaxVel = obj->calculateMaxVel(sourceTime - mpParam->getTimestep(),sourceTime);
- if(normNoSqrt(oldobjMaxVel)>0.0) { otype |= CFBndMoving; }
- }
- if(obj->getMeshAnimated()) { ntype |= CFBndMoving; otype |= CFBndMoving; }
- CellFlagType rflagnb[27];
- LbmFloat massCheck = 0.;
- int massReinits=0;
- bool fillCells = (mObjectMassMovnd[OId]<=-1.);
- LbmFloat impactCorrFactor = obj->getGeoImpactFactor(targetTime);
-
-
- // first pass - set new obs. cells
- if(active) {
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- //errMsg("initMovingObstacles_Debug","OId"<<OId<<" n"<<n<<" -> "<<PRINT_IJK);
- POS2GRID_CHECK(mMOIVertices,n);
- //{ errMsg("initMovingObstacles_Debug","OId"<<OId<<" n"<<n<<" -> "<<PRINT_IJK<<", t="<<targetTime); }
- if(QCELL(level, i,j,k, workSet, dFlux)==targetTime) continue;
- monPoints++;
-
- // check mass
- if(RFLAG(level, i,j,k, workSet)&(CFFluid)) {
- FORDF0 { massCheck -= QCELL(level, i,j,k, workSet, l); }
- massReinits++;
- }
- else if(RFLAG(level, i,j,k, workSet)&(CFInter)) {
- massCheck -= QCELL(level, i,j,k, workSet, dMass);
- massReinits++;
- }
-
- RFLAG(level, i,j,k, workSet) = ntype;
- FORDF1 {
- //CellFlagType flag = RFLAG_NB(level, i,j,k,workSet,l);
- rflagnb[l] = RFLAG_NB(level, i,j,k,workSet,l);
- if(rflagnb[l]&(CFFluid|CFInter)) {
- rflagnb[l] &= (~CFNoBndFluid); // remove CFNoBndFluid flag
- RFLAG_NB(level, i,j,k,workSet,l) &= rflagnb[l];
- }
- }
- LbmFloat *dstCell = RACPNT(level, i,j,k,workSet);
- RAC(dstCell,0) = 0.0;
- if(ntype&CFBndMoving) {
- OBJVEL_CALC;
-
- // compute fluid acceleration
- FORDF1 {
- if(rflagnb[l]&(CFFluid|CFInter)) {
- const LbmFloat ux = dfDvecX[l]*objvel[0];
- const LbmFloat uy = dfDvecY[l]*objvel[1];
- const LbmFloat uz = dfDvecZ[l]*objvel[2];
-
- LbmFloat factor = 2. * dfLength[l] * 3.0 * (ux+uy+uz); //
- if(ntype&(CFBndFreeslip|CFBndPartslip)) {
- // missing, diag mass checks...
- //if(l<=LBMDIM*2) factor *= 1.4142;
- factor *= 2.0; // TODO, optimize
- } else {
- factor *= 1.2; // TODO, optimize
- }
- factor *= impactCorrFactor; // use manual tweaking channel
- RAC(dstCell,l) = factor;
- massCheck += factor;
- } else {
- RAC(dstCell,l) = 0.;
- }
- }
-
-#if NEWDIRVELMOTEST==1
- FORDF1 { RAC(dstCell,l) = 0.; }
- RAC(dstCell,dMass) = objvel[0];
- RAC(dstCell,dFfrac) = objvel[1];
- RAC(dstCell,dC) = objvel[2];
-#endif // NEWDIRVELMOTEST==1
- } else {
- FORDF1 { RAC(dstCell,l) = 0.0; }
- }
- RAC(dstCell, dFlux) = targetTime;
- //errMsg("initMovingObstacles_Debug","OId"<<OId<<" n"<<n<<" -> "<<PRINT_IJK" dflt="<<RAC(dstCell, dFlux) );
- monObsts++;
- } // points
- } // bnd, is active?
-
- // second pass, remove old ones
- // warning - initEmptyCell et. al dont overwrite OId or persist flags...
- if(wasActive) {
- for(size_t n=0; n<mMOIVerticesOld.size(); n++) {
- POS2GRID_CHECK(mMOIVerticesOld,n);
- monPoints++;
- if((RFLAG(level, i,j,k, workSet) == otype) &&
- (QCELL(level, i,j,k, workSet, dFlux) != targetTime)) {
- // from mainloop
- nbored = 0;
- // TODO: optimize for OPT3D==0
- FORDF1 {
- //rflagnb[l] = RFLAG_NB(level, i,j,k,workSet,l);
- rflagnb[l] = RFLAG_NB(level, i,j,k,otherSet,l); // test use other set to not have loop dependance
- nbored |= rflagnb[l];
- }
- CellFlagType settype = CFInvalid;
- if(nbored&CFFluid) {
- settype = CFInter|CFNoInterpolSrc;
- rhomass = 1.5;
- if(!fillCells) rhomass = 0.;
-
- OBJVEL_CALC;
- if(!(nbored&CFEmpty)) { settype=CFFluid|CFNoInterpolSrc; rhomass=1.; }
-
- // new interpolate values
- LbmFloat avgrho = 0.0;
- LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0;
- interpolateCellValues(level,i,j,k,workSet, avgrho,avgux,avguy,avguz);
- initVelocityCell(level, i,j,k, settype, avgrho, rhomass, LbmVec(avgux,avguy,avguz) );
- //errMsg("NMOCIT"," at "<<PRINT_IJK<<" "<<avgrho<<" "<<norm(LbmVec(avgux,avguy,avguz))<<" "<<LbmVec(avgux,avguy,avguz) );
- massCheck += rhomass;
- } else {
- settype = CFEmpty; rhomass = 0.0;
- initEmptyCell(level, i,j,k, settype, 1., rhomass );
- }
- monFluids++;
- massReinits++;
- } // flag & simtime
- }
- } // wasactive
-
- // only compute mass transfer when init is done
- if(mInitDone) {
- errMsg("initMov","dccd\n\nMassd test "<<obj->getName()<<" dccd massCheck="<<massCheck<<" massReinits"<<massReinits<<
- " fillCells"<<fillCells<<" massmovbnd:"<<mObjectMassMovnd[OId]<<" inim:"<<mInitialMass );
- mObjectMassMovnd[OId] += massCheck;
- }
- } // bnd, active
-
- else if(ntype&CFFluid){
- // second static init pass
- if(staticInit) {
- //debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" verts"<<mMOIVertices.size() ,9);
- CellFlagType setflflag = CFFluid; //|(OId<<24);
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- POS2GRID_CHECK(mMOIVertices,n);
- if(RFLAG(level, i,j,k, workSet)&(CFMbndInflow|CFMbndOutflow)){ continue; }
- if(RFLAG(level, i,j,k, workSet)&(CFEmpty)) {
- //changeFlag(level, i,j,k, workSet, setflflag);
- initVelocityCell(level, i,j,k, setflflag, 1., 1., mObjectSpeeds[OId] );
- }
- //else if(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter)) { changeFlag(level, i,j,k, workSet, RFLAG(level, i,j,k, workSet)|set2Flag); }
- }
- } // second static inflow pass
- } // fluid
-
- else if(ntype&CFMbndInflow){
- // inflow pass - add new fluid cells
- // this is slightly different for standing inflows,
- // as the fluid is forced to the desired velocity inside as
- // well...
- const LbmFloat iniRho = 1.0;
- const LbmVec vel(mObjectSpeeds[OId]);
- const LbmFloat usqr = (vel[0]*vel[0]+vel[1]*vel[1]+vel[2]*vel[2])*1.5;
- USQRMAXCHECK(usqr,vel[0],vel[1],vel[2], mMaxVlen, mMxvx,mMxvy,mMxvz);
- //errMsg("LbmFsgrSolver::initMovingObstacles","id"<<OId<<" "<<obj->getName()<<" inflow "<<staticInit<<" "<<mMOIVertices.size() );
-
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- POS2GRID_CHECK(mMOIVertices,n);
- // TODO - also reinit interface cells !?
- if(RFLAG(level, i,j,k, workSet)!=CFEmpty) {
- // test prevent particle gen for inflow inter cells
- if(RFLAG(level, i,j,k, workSet)&(CFInter)) { RFLAG(level, i,j,k, workSet) &= (~CFNoBndFluid); } // remove CFNoBndFluid flag
- continue; }
- monFluids++;
-
- // TODO add OPT3D treatment
- LbmFloat *tcel = RACPNT(level, i,j,k,workSet);
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, iniRho,vel[0],vel[1],vel[2]); }
- RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho;
- RAC(tcel, dFlux) = FLUX_INIT;
- CellFlagType setFlag = CFInter;
- changeFlag(level, i,j,k, workSet, setFlag);
- mInitialMass += iniRho;
- }
- // second static init pass
- if(staticInit) {
- CellFlagType set2Flag = CFMbndInflow|(OId<<24);
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- POS2GRID_CHECK(mMOIVertices,n);
- if(RFLAG(level, i,j,k, workSet)&(CFMbndInflow|CFMbndOutflow)){ continue; }
- if(RFLAG(level, i,j,k, workSet)&(CFEmpty)) {
- forceChangeFlag(level, i,j,k, workSet, set2Flag);
- } else if(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter)) {
- forceChangeFlag(level, i,j,k, workSet,
- (RFLAG(level, i,j,k, workSet)&CFNoPersistMask)|set2Flag);
- }
- }
- } // second static inflow pass
-
- } // inflow
-
- else if(ntype&CFMbndOutflow){
- const LbmFloat iniRho = 0.0;
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- POS2GRID_CHECK(mMOIVertices,n);
- // FIXME check fluid/inter cells for non-static!?
- if(!(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter))) {
- if((staticInit)&&(RFLAG(level, i,j,k, workSet)==CFEmpty)) {
- forceChangeFlag(level, i,j,k, workSet, CFMbndOutflow); }
- continue;
- }
- monFluids++;
- // interface cell - might be double empty? FIXME check?
-
- // remove fluid cells, shouldnt be here anyway
- LbmFloat *tcel = RACPNT(level, i,j,k,workSet);
- LbmFloat fluidRho = RAC(tcel,0); FORDF1 { fluidRho += RAC(tcel,l); }
- mInitialMass -= fluidRho;
- RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho;
- RAC(tcel, dFlux) = FLUX_INIT;
- CellFlagType setFlag = CFInter;
- changeFlag(level, i,j,k, workSet, setFlag);
-
- // same as ifemptied for if below
- LbmPoint emptyp;
- emptyp.x = i; emptyp.y = j; emptyp.z = k;
- mListEmpty.push_back( emptyp );
- //calcCellsEmptied++;
- } // points
- // second static init pass
- if(staticInit) {
- CellFlagType set2Flag = CFMbndOutflow|(OId<<24);
- for(size_t n=0; n<mMOIVertices.size(); n++) {
- POS2GRID_CHECK(mMOIVertices,n);
- if(RFLAG(level, i,j,k, workSet)&(CFMbndInflow|CFMbndOutflow)){ continue; }
- if(RFLAG(level, i,j,k, workSet)&(CFEmpty)) {
- forceChangeFlag(level, i,j,k, workSet, set2Flag);
- } else if(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter)) {
- forceChangeFlag(level, i,j,k, workSet,
- (RFLAG(level, i,j,k, workSet)&CFNoPersistMask)|set2Flag);
- }
- }
- } // second static outflow pass
- } // outflow
-
- } // allbound check
- } // OId
-
-
- /* { // DEBUG check
- int workSet = mLevel[level].setCurr;
- FSGR_FORIJK1(level) {
- if( (RFLAG(level,i,j,k, workSet) & CFBndMoving) ) {
- if(QCELL(level, i,j,k, workSet, dFlux)!=targetTime) {
- errMsg("lastt"," old val!? at "<<PRINT_IJK<<" t="<<QCELL(level, i,j,k, workSet, dFlux)<<" target="<<targetTime);
- }
- }
- }
- } // DEBUG */
-
-#undef POS2GRID_CHECK
- myTime_t monend = getTime();
- if(monend-monstart>0) debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG,"Total: "<<monTotal<<" Points :"<<monPoints<<" ObstInits:"<<monObsts<<" FlInits:"<<monFluids<<" Trafos:"<<monTotal<<", took "<<getTimeString(monend-monstart), 7);
- mLastSimTime = targetTime;
-}
-
-
-// geoinit position
-
-#define GETPOS(i,j,k) \
- ntlVec3Gfx ggpos = \
- ntlVec3Gfx( iniPos[0]+ dvec[0]*(gfxReal)(i), \
- iniPos[1]+ dvec[1]*(gfxReal)(j), \
- iniPos[2]+ dvec[2]*(gfxReal)(k) ); \
- if((LBMDIM==2)&&(mInit2dYZ)) { SWAPYZ(ggpos); }
-
-/*****************************************************************************/
-/*! perform geometry init (if switched on) */
-/*****************************************************************************/
-extern int globGeoInitDebug; //solver_interface
-bool LbmFsgrSolver::initGeometryFlags() {
- int level = mMaxRefine;
- myTime_t geotimestart = getTime();
- ntlGeometryObject *pObj;
- ntlVec3Gfx dvec = ntlVec3Gfx(mLevel[level].nodeSize); //dvec*1.0;
- debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Performing geometry init ("<< mLbmInitId <<") v"<<dvec,3);
- // WARNING - copied to movobj init!
-
- /* init object velocities, this has always to be called for init */
- initGeoTree();
- if(mAllfluid) {
- freeGeoTree();
- return true; }
-
- // make sure moving obstacles are inited correctly
- // preinit moving obj points
- int numobjs = (int)(mpGiObjects->size());
- for(int o=0; o<numobjs; o++) {
- ntlGeometryObject *obj = (*mpGiObjects)[o];
- //debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" type "<<obj->getGeoInitType()<<" anim"<<obj->getIsAnimated()<<" "<<obj->getVolumeInit() ,9);
- if(
- ((obj->getGeoInitType()&FGI_ALLBOUNDS) && (obj->getIsAnimated())) ||
- (obj->getVolumeInit()&VOLUMEINIT_SHELL) ) {
- if(!obj->getMeshAnimated()) {
- debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" type "<<obj->getGeoInitType()<<" anim"<<obj->getIsAnimated()<<" "<<obj->getVolumeInit() ,9);
- obj->initMovingPoints(mSimulationTime, mLevel[mMaxRefine].nodeSize);
- }
- }
- }
-
- // max speed init
- ntlVec3Gfx maxMovobjVelRw = getGeoMaxMovementVelocity( mSimulationTime, mpParam->getTimestep() );
- ntlVec3Gfx maxMovobjVel = vec2G( mpParam->calculateLattVelocityFromRw( vec2P( maxMovobjVelRw )) );
- mpParam->setSimulationMaxSpeed( norm(maxMovobjVel) + norm(mLevel[level].gravity) );
- LbmFloat allowMax = mpParam->getTadapMaxSpeed(); // maximum allowed velocity
- debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Maximum Velocity from geo init="<< maxMovobjVel <<" from mov. obj.="<<maxMovobjVelRw<<" , allowed Max="<<allowMax ,5);
- if(mpParam->getSimulationMaxSpeed() > allowMax) {
- // similar to adaptTimestep();
- LbmFloat nextmax = mpParam->getSimulationMaxSpeed();
- LbmFloat newdt = mpParam->getTimestep() * (allowMax / nextmax); // newtr
- debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Performing reparametrization, newdt="<< newdt<<" prevdt="<< mpParam->getTimestep() <<" ",5);
- mpParam->setDesiredTimestep( newdt );
- mpParam->calculateAllMissingValues( mSimulationTime, mSilent );
- maxMovobjVel = vec2G( mpParam->calculateLattVelocityFromRw( vec2P(getGeoMaxMovementVelocity(
- mSimulationTime, mpParam->getTimestep() )) ));
- debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"New maximum Velocity from geo init="<< maxMovobjVel,5);
- }
- recalculateObjectSpeeds();
- // */
-
- // init obstacles for first time step (requires obj speeds)
- initMovingObstacles(true);
-
- /* set interface cells */
- ntlVec3Gfx pos,iniPos; // position of current cell
- LbmFloat rhomass = 0.0;
- CellFlagType ntype = CFInvalid;
- int savedNodes = 0;
- int OId = -1;
- gfxReal distance;
-
- // 2d display as rectangles
- if(LBMDIM==2) {
- dvec[2] = 0.0;
- iniPos =(mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (mvGeoEnd[2]-mvGeoStart[2])*0.5 ))+(dvec*0.5);
- //if(mInit2dYZ) { SWAPYZ(mGravity); for(int lev=0; lev<=mMaxRefine; lev++){ SWAPYZ( mLevel[lev].gravity ); } }
- } else {
- iniPos =(mvGeoStart + ntlVec3Gfx( 0.0 ))+(dvec*0.5);
- }
-
-
- // first init boundary conditions
- // invalid cells are set to empty afterwards
- // TODO use floop macros!?
- for(int k= getForZMin1(); k< getForZMax1(level); ++k) {
- for(int j=1;j<mLevel[level].lSizey-1;j++) {
- for(int i=1;i<mLevel[level].lSizex-1;i++) {
- ntype = CFInvalid;
-
- GETPOS(i,j,k);
- const bool inside = geoInitCheckPointInside( ggpos, FGI_ALLBOUNDS, OId, distance);
- if(inside) {
- pObj = (*mpGiObjects)[OId];
- switch( pObj->getGeoInitType() ){
- case FGI_MBNDINFLOW:
- if(! pObj->getIsAnimated() ) {
- rhomass = 1.0;
- ntype = CFFluid | CFMbndInflow;
- } else {
- ntype = CFInvalid;
- }
- break;
- case FGI_MBNDOUTFLOW:
- if(! pObj->getIsAnimated() ) {
- rhomass = 0.0;
- ntype = CFEmpty|CFMbndOutflow;
- } else {
- ntype = CFInvalid;
- }
- break;
- case FGI_BNDNO:
- rhomass = BND_FILL;
- ntype = CFBnd|CFBndNoslip;
- break;
- case FGI_BNDPART:
- rhomass = BND_FILL;
- ntype = CFBnd|CFBndPartslip; break;
- case FGI_BNDFREE:
- rhomass = BND_FILL;
- ntype = CFBnd|CFBndFreeslip; break;
- default: // warn here?
- rhomass = BND_FILL;
- ntype = CFBnd|CFBndNoslip; break;
- }
- }
- if(ntype != CFInvalid) {
- // initDefaultCell
- if((ntype & CFMbndInflow) || (ntype & CFMbndOutflow) ) { }
- ntype |= (OId<<24); // NEWTEST2
- initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
- }
-
- // walk along x until hit for following inits
- if(distance<=-1.0) { distance = 100.0; } // FIXME dangerous
- if(distance>=0.0) {
- gfxReal dcnt=dvec[0];
- while(( dcnt< distance-dvec[0] )&&(i+1<mLevel[level].lSizex-1)) {
- dcnt += dvec[0]; i++;
- savedNodes++;
- if(ntype != CFInvalid) {
- // rho,mass,OId are still inited from above
- initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
- }
- }
- }
- // */
-
- }
- }
- } // zmax
- // */
-
- // now init fluid layer
- for(int k= getForZMin1(); k< getForZMax1(level); ++k) {
- for(int j=1;j<mLevel[level].lSizey-1;j++) {
- for(int i=1;i<mLevel[level].lSizex-1;i++) {
- if(!(RFLAG(level, i,j,k, mLevel[level].setCurr)==CFEmpty)) continue;
- ntype = CFInvalid;
- int inits = 0;
- GETPOS(i,j,k);
- const bool inside = geoInitCheckPointInside( ggpos, FGI_FLUID, OId, distance);
- if(inside) {
- ntype = CFFluid;
- }
- if(ntype != CFInvalid) {
- // initDefaultCell
- rhomass = 1.0;
- initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
- inits++;
- }
-
- // walk along x until hit for following inits
- if(distance<=-1.0) { distance = 100.0; }
- if(distance>=0.0) {
- gfxReal dcnt=dvec[0];
- while((dcnt< distance )&&(i+1<mLevel[level].lSizex-1)) {
- dcnt += dvec[0]; i++;
- savedNodes++;
- if(!(RFLAG(level, i,j,k, mLevel[level].setCurr)==CFEmpty)) continue;
- if(ntype != CFInvalid) {
- // rhomass are still inited from above
- initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
- inits++;
- }
- }
- } // distance>0
-
- }
- }
- } // zmax
-
- // reset invalid to empty again
- for(int k= getForZMin1(); k< getForZMax1(level); ++k) {
- for(int j=1;j<mLevel[level].lSizey-1;j++) {
- for(int i=1;i<mLevel[level].lSizex-1;i++) {
- if(RFLAG(level, i,j,k, mLevel[level].setCurr)==CFInvalid) {
- RFLAG(level, i,j,k, mLevel[level].setOther) =
- RFLAG(level, i,j,k, mLevel[level].setCurr) = CFEmpty;
- }
- }
- }
- }
-
- freeGeoTree();
- myTime_t geotimeend = getTime();
- debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Geometry init done ("<< getTimeString(geotimeend-geotimestart)<<","<<savedNodes<<") " , 10 );
- //errMsg(" SAVED "," "<<savedNodes<<" of "<<(mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*mLevel[mMaxRefine].lSizez));
- return true;
-}
-
-#undef GETPOS
-
-/*****************************************************************************/
-/* init part for all freesurface testcases */
-void LbmFsgrSolver::initFreeSurfaces() {
- double interfaceFill = 0.45; // filling level of interface cells
- //interfaceFill = 1.0; // DEUG!! GEOMTEST!!!!!!!!!!!!
-
- // set interface cells
- FSGR_FORIJK1(mMaxRefine) {
- if( ( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFFluid )) {
- FORDF1 {
- int ni=i+dfVecX[l], nj=j+dfVecY[l], nk=k+dfVecZ[l];
- if( ( RFLAG(mMaxRefine, ni, nj, nk, mLevel[mMaxRefine].setCurr)& CFEmpty ) ) {
- LbmFloat arho=0., aux=0., auy=0., auz=0.;
- interpolateCellValues(mMaxRefine, ni,nj,nk, mLevel[mMaxRefine].setCurr, arho,aux,auy,auz);
- //errMsg("TINI"," "<<PRINT_VEC(ni,nj,nk)<<" v"<<LbmVec(aux,auy,auz) );
- // unnecessary? initEmptyCell(mMaxRefine, ni,nj,nk, CFInter, arho, interfaceFill);
- initVelocityCell(mMaxRefine, ni,nj,nk, CFInter, arho, interfaceFill, LbmVec(aux,auy,auz) );
- }
- }
- }
- }
-
- // remove invalid interface cells
- FSGR_FORIJK1(mMaxRefine) {
- // remove invalid interface cells
- if( ( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFInter) ) {
- int delit = 0;
- int NBs = 0; // neighbor flags or'ed
- int noEmptyNB = 1;
-
- FORDF1 {
- if( ( RFLAG_NBINV(mMaxRefine, i, j, k, mLevel[mMaxRefine].setCurr,l )& CFEmpty ) ) {
- noEmptyNB = 0;
- }
- NBs |= RFLAG_NBINV(mMaxRefine, i, j, k, mLevel[mMaxRefine].setCurr, l);
- }
- // remove cells with no fluid or interface neighbors
- if((NBs & CFFluid)==0) { delit = 1; }
- if((NBs & CFInter)==0) { delit = 1; }
- // remove cells with no empty neighbors
- if(noEmptyNB) { delit = 2; }
-
- // now we can remove the cell
- if(delit==1) {
- initEmptyCell(mMaxRefine, i,j,k, CFEmpty, 1.0, 0.0);
- }
- if(delit==2) {
- //initEmptyCell(mMaxRefine, i,j,k, CFFluid, 1.0, 1.0);
- LbmFloat arho=0., aux=0., auy=0., auz=0.;
- interpolateCellValues(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, arho,aux,auy,auz);
- initVelocityCell(mMaxRefine, i,j,k, CFFluid, arho,1., LbmVec(aux,auy,auz) );
- }
- } // interface
- } // */
-
- // another brute force init, make sure the fill values are right...
- // and make sure both sets are equal
- for(int lev=0; lev<=mMaxRefine; lev++) {
- FSGR_FORIJK_BOUNDS(lev) {
- if( (RFLAG(lev, i,j,k,0) & (CFBnd)) ) {
- QCELL(lev, i,j,k,mLevel[mMaxRefine].setCurr, dFfrac) = BND_FILL;
- continue;
- }
- if( (RFLAG(lev, i,j,k,0) & (CFEmpty)) ) {
- QCELL(lev, i,j,k,mLevel[mMaxRefine].setCurr, dFfrac) = 0.0;
- continue;
- }
- } }
-
- // ----------------------------------------------------------------------
- // smoother surface...
- if(mInitSurfaceSmoothing>0) {
- debMsgStd("Surface Smoothing init", DM_MSG, "Performing "<<(mInitSurfaceSmoothing)<<" smoothing timestep ",10);
-#if COMPRESSGRIDS==1
- //errFatal("NYI","COMPRESSGRIDS mInitSurfaceSmoothing",SIMWORLD_INITERROR); return;
-#endif // COMPRESSGRIDS==0
- }
- for(int s=0; s<mInitSurfaceSmoothing; s++) {
- //SGR_FORIJK1(mMaxRefine) {
-
- int kstart=getForZMin1(), kend=getForZMax1(mMaxRefine);
- int lev = mMaxRefine;
-#if COMPRESSGRIDS==0
- for(int k=kstart;k<kend;++k) {
-#else // COMPRESSGRIDS==0
- int kdir = 1; // COMPRT ON
- if(mLevel[lev].setCurr==1) {
- kdir = -1;
- int temp = kend;
- kend = kstart-1;
- kstart = temp-1;
- } // COMPRT
- for(int k=kstart;k!=kend;k+=kdir) {
-#endif // COMPRESSGRIDS==0
- for(int j=1;j<mLevel[lev].lSizey-1;++j) {
- for(int i=1;i<mLevel[lev].lSizex-1;++i) {
- if( ( RFLAG(lev, i,j,k, mLevel[lev].setCurr)& CFInter) ) {
- LbmFloat mass = 0.0;
- //LbmFloat nbdiv;
- //FORDF0 {
- for(int l=0;(l<cDirNum); l++) {
- int ni=i+dfVecX[l], nj=j+dfVecY[l], nk=k+dfVecZ[l];
- if( RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr) & CFFluid ){
- mass += 1.0;
- }
- if( RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr) & CFInter ){
- mass += QCELL(lev, ni,nj,nk, mLevel[lev].setCurr, dMass);
- }
- //nbdiv+=1.0;
- }
-
- //errMsg(" I ", PRINT_IJK<<" m"<<mass );
- QCELL(lev, i,j,k, mLevel[lev].setOther, dMass) = (mass/ ((LbmFloat)cDirNum) );
- QCELL(lev, i,j,k, mLevel[lev].setOther, dFfrac) = QCELL(lev, i,j,k, mLevel[lev].setOther, dMass);
- }
- }}}
-
- mLevel[lev].setOther = mLevel[lev].setCurr;
- mLevel[lev].setCurr ^= 1;
- }
- // copy back...?
-}
-
-/*****************************************************************************/
-/* init part for all freesurface testcases */
-void LbmFsgrSolver::initStandingFluidGradient() {
- // ----------------------------------------------------------------------
- // standing fluid preinit
- const int debugStandingPreinit = 0;
- int haveStandingFluid = 0;
-
-#define STANDFLAGCHECK(iindex) \
- if( ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFInter)) ) || \
- ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFEmpty)) ) ){ \
- if((iindex)>1) { haveStandingFluid=(iindex); } \
- j = mLevel[mMaxRefine].lSizey; i=mLevel[mMaxRefine].lSizex; k=getForZMaxBnd(); \
- continue; \
- }
- int gravIndex[3] = {0,0,0};
- int gravDir[3] = {1,1,1};
- int maxGravComp = 1; // by default y
- int gravComp1 = 0; // by default y
- int gravComp2 = 2; // by default y
- if( ABS(mLevel[mMaxRefine].gravity[0]) > ABS(mLevel[mMaxRefine].gravity[1]) ){ maxGravComp = 0; gravComp1=1; gravComp2=2; }
- if( ABS(mLevel[mMaxRefine].gravity[2]) > ABS(mLevel[mMaxRefine].gravity[0]) ){ maxGravComp = 2; gravComp1=0; gravComp2=1; }
-
- int gravIMin[3] = { 0 , 0 , 0 };
- int gravIMax[3] = {
- mLevel[mMaxRefine].lSizex + 0,
- mLevel[mMaxRefine].lSizey + 0,
- mLevel[mMaxRefine].lSizez + 0 };
- if(LBMDIM==2) gravIMax[2] = 1;
-
- //int gravDir = 1;
- if( mLevel[mMaxRefine].gravity[maxGravComp] > 0.0 ) {
- // swap directions
- int i=maxGravComp;
- int tmp = gravIMin[i];
- gravIMin[i] = gravIMax[i] - 1;
- gravIMax[i] = tmp - 1;
- gravDir[i] = -1;
- }
-#define PRINTGDIRS \
- errMsg("Standing fp","X start="<<gravIMin[0]<<" end="<<gravIMax[0]<<" dir="<<gravDir[0] ); \
- errMsg("Standing fp","Y start="<<gravIMin[1]<<" end="<<gravIMax[1]<<" dir="<<gravDir[1] ); \
- errMsg("Standing fp","Z start="<<gravIMin[2]<<" end="<<gravIMax[2]<<" dir="<<gravDir[2] );
- // _PRINTGDIRS;
-
- bool gravAbort = false;
-#define GRAVLOOP \
- gravAbort=false; \
- for(gravIndex[2]= gravIMin[2]; (gravIndex[2]!=gravIMax[2])&&(!gravAbort); gravIndex[2] += gravDir[2]) \
- for(gravIndex[1]= gravIMin[1]; (gravIndex[1]!=gravIMax[1])&&(!gravAbort); gravIndex[1] += gravDir[1]) \
- for(gravIndex[0]= gravIMin[0]; (gravIndex[0]!=gravIMax[0])&&(!gravAbort); gravIndex[0] += gravDir[0])
-
- GRAVLOOP {
- int i = gravIndex[0], j = gravIndex[1], k = gravIndex[2];
- if( ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFInter)) ) ||
- ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFBndMoving)) ) ||
- ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFEmpty)) ) ) {
- int fluidHeight = (ABS(gravIndex[maxGravComp] - gravIMin[maxGravComp]));
- if(debugStandingPreinit) errMsg("Standing fp","fh="<<fluidHeight<<" gmax="<<gravIMax[maxGravComp]<<" gi="<<gravIndex[maxGravComp] );
- if(fluidHeight>1) {
- haveStandingFluid = fluidHeight; //gravIndex[maxGravComp];
- gravIMax[maxGravComp] = gravIndex[maxGravComp] + gravDir[maxGravComp];
- }
- gravAbort = true; continue;
- }
- } // GRAVLOOP
- // _PRINTGDIRS;
-
- LbmFloat fluidHeight;
- fluidHeight = (LbmFloat)(ABS(gravIMax[maxGravComp]-gravIMin[maxGravComp]));
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(mUseTestdata) mpTest->mFluidHeight = (int)fluidHeight;
-#endif // ELBEEM_PLUGIN!=1
- if(debugStandingPreinit) debMsgStd("Standing fluid preinit", DM_MSG, "fheight="<<fluidHeight<<" min="<<PRINT_VEC(gravIMin[0],gravIMin[1], gravIMin[2])<<" max="<<PRINT_VEC(gravIMax[0], gravIMax[1],gravIMax[2])<<
- " mgc="<<maxGravComp<<" mc1="<<gravComp1<<" mc2="<<gravComp2<<" dir="<<gravDir[maxGravComp]<<" have="<<haveStandingFluid ,10);
-
- if(mDisableStandingFluidInit) {
- debMsgStd("Standing fluid preinit", DM_MSG, "Should be performed - but skipped due to mDisableStandingFluidInit flag set!", 2);
- haveStandingFluid=0;
- }
-
- // copy flags and init , as no flags will be changed during grav init
- // also important for corasening later on
- const int lev = mMaxRefine;
- CellFlagType nbflag[LBM_DFNUM], nbored;
- for(int k=getForZMinBnd();k<getForZMaxBnd(mMaxRefine);++k) {
- for(int j=0;j<mLevel[lev].lSizey-0;++j) {
- for(int i=0;i<mLevel[lev].lSizex-0;++i) {
- if( (RFLAG(lev, i,j,k,SRCS(lev)) & (CFFluid)) ) {
- nbored = 0;
- FORDF1 {
- nbflag[l] = RFLAG_NB(lev, i,j,k, SRCS(lev),l);
- nbored |= nbflag[l];
- }
- if(nbored&CFBnd) {
- RFLAG(lev, i,j,k,SRCS(lev)) &= (~CFNoBndFluid);
- } else {
- RFLAG(lev, i,j,k,SRCS(lev)) |= CFNoBndFluid;
- }
- }
- RFLAG(lev, i,j,k,TSET(lev)) = RFLAG(lev, i,j,k,SRCS(lev));
- } } }
-
- if(haveStandingFluid) {
- int rhoworkSet = mLevel[lev].setCurr;
- myTime_t timestart = getTime(); // FIXME use user time here?
-
- GRAVLOOP {
- int i = gravIndex[0], j = gravIndex[1], k = gravIndex[2];
- //debMsgStd("Standing fluid preinit", DM_MSG, " init check "<<PRINT_IJK<<" "<< haveStandingFluid, 1 );
- if( ( (RFLAG(lev, i,j,k,rhoworkSet) & (CFInter)) ) ||
- ( (RFLAG(lev, i,j,k,rhoworkSet) & (CFEmpty)) ) ){
- //gravAbort = true;
- continue;
- }
-
- LbmFloat rho = 1.0;
- // 1/6 velocity from denisty gradient, 1/2 for delta of two cells
- rho += 1.0* (fluidHeight-gravIndex[maxGravComp]) *
- (mLevel[lev].gravity[maxGravComp])* (-3.0/1.0)*(mLevel[lev].omega);
- if(debugStandingPreinit)
- if((gravIndex[gravComp1]==gravIMin[gravComp1]) && (gravIndex[gravComp2]==gravIMin[gravComp2])) {
- errMsg("Standing fp","gi="<<gravIndex[maxGravComp]<<" rho="<<rho<<" at "<<PRINT_IJK);
- }
-
- if( (RFLAG(lev, i,j,k, rhoworkSet) & CFFluid) ||
- (RFLAG(lev, i,j,k, rhoworkSet) & CFInter) ) {
- FORDF0 { QCELL(lev, i,j,k, rhoworkSet, l) *= rho; }
- QCELL(lev, i,j,k, rhoworkSet, dMass) *= rho;
- }
-
- } // GRAVLOOP
-
- debMsgStd("Standing fluid preinit", DM_MSG, "Density gradient inited (max-rho:"<<
- (1.0+ (fluidHeight) * (mLevel[lev].gravity[maxGravComp])* (-3.0/1.0)*(mLevel[lev].omega)) <<", h:"<< fluidHeight<<") ", 8);
-
- int preinitSteps = (haveStandingFluid* ((mLevel[lev].lSizey+mLevel[lev].lSizez+mLevel[lev].lSizex)/3) );
- preinitSteps = (haveStandingFluid>>2); // not much use...?
- //preinitSteps = 0;
- debMsgStd("Standing fluid preinit", DM_MSG, "Performing "<<preinitSteps<<" prerelaxations ",10);
- for(int s=0; s<preinitSteps; s++) {
- // in solver main cpp
- standingFluidPreinit();
- }
-
- myTime_t timeend = getTime();
- debMsgStd("Standing fluid preinit", DM_MSG, " done, "<<getTimeString(timeend-timestart), 9);
-#undef NBFLAG
- }
-}
-
-
-
-bool LbmFsgrSolver::checkSymmetry(string idstring)
-{
- bool erro = false;
- bool symm = true;
- int msgs = 0;
- const int maxMsgs = 10;
- const bool markCells = false;
-
- //for(int lev=0; lev<=mMaxRefine; lev++) {
- { int lev = mMaxRefine;
-
- // no point if not symm.
- if( (mLevel[lev].lSizex==mLevel[lev].lSizey) && (mLevel[lev].lSizex==mLevel[lev].lSizez)) {
- // ok
- } else {
- return false;
- }
-
- for(int s=0; s<2; s++) {
- FSGR_FORIJK1(lev) {
- if(i<(mLevel[lev].lSizex/2)) {
- int inb = (mLevel[lev].lSizey-1-i);
-
- if(lev==mMaxRefine) inb -= 1; // FSGR_SYMM_T
-
- if( RFLAG(lev, i,j,k,s) != RFLAG(lev, inb,j,k,s) ) { erro = true;
- if(LBMDIM==2) {
- if(msgs<maxMsgs) { msgs++;
- errMsg("EFLAG", PRINT_IJK<<"s"<<s<<" flag "<<RFLAG(lev, i,j,k,s)<<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" flag "<<RFLAG(lev, inb,j,k,s) );
- }
- }
- if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
- symm = false;
- }
- if( LBM_FLOATNEQ(QCELL(lev, i,j,k,s, dMass), QCELL(lev, inb,j,k,s, dMass)) ) { erro = true;
- if(LBMDIM==2) {
- if(msgs<maxMsgs) { msgs++;
- //debMsgDirect(" mass1 "<<QCELL(lev, i,j,k,s, dMass)<<" mass2 "<<QCELL(lev, inb,j,k,s, dMass) <<std::endl);
- errMsg("EMASS", PRINT_IJK<<"s"<<s<<" mass "<<QCELL(lev, i,j,k,s, dMass)<<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" mass "<<QCELL(lev, inb,j,k,s, dMass) );
- }
- }
- if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
- symm = false;
- }
-
- LbmFloat nbrho = QCELL(lev, i,j,k, s, dC);
- FORDF1 { nbrho += QCELL(lev, i,j,k, s, l); }
- LbmFloat otrho = QCELL(lev, inb,j,k, s, dC);
- FORDF1 { otrho += QCELL(lev, inb,j,k, s, l); }
- if( LBM_FLOATNEQ(nbrho, otrho) ) { erro = true;
- if(LBMDIM==2) {
- if(msgs<maxMsgs) { msgs++;
- //debMsgDirect(" rho 1 "<<nbrho <<" rho 2 "<<otrho <<std::endl);
- errMsg("ERHO ", PRINT_IJK<<"s"<<s<<" rho "<<nbrho <<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" rho "<<otrho );
- }
- }
- if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
- symm = false;
- }
- }
- } }
- } // lev
- LbmFloat maxdiv =0.0;
- if(erro) {
- errMsg("SymCheck Failed!", idstring<<" rho maxdiv:"<< maxdiv );
- //if(LBMDIM==2) mPanic = true;
- //return false;
- } else {
- errMsg("SymCheck OK!", idstring<<" rho maxdiv:"<< maxdiv );
- }
- // all ok...
- return symm;
-}// */
-
-
-void
-LbmFsgrSolver::interpolateCellValues(
- int level,int ei,int ej,int ek,int workSet,
- LbmFloat &retrho, LbmFloat &retux, LbmFloat &retuy, LbmFloat &retuz)
-{
- LbmFloat avgrho = 0.0;
- LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0;
- LbmFloat cellcnt = 0.0;
-
- for(int nbl=1; nbl< cDfNum ; ++nbl) {
- if(RFLAG_NB(level,ei,ej,ek,workSet,nbl) & CFNoInterpolSrc) continue;
- if( (RFLAG_NB(level,ei,ej,ek,workSet,nbl) & (CFFluid|CFInter)) ){
- //((!(RFLAG_NB(level,ei,ej,ek,workSet,nbl) & CFNoInterpolSrc) ) &&
- //(RFLAG_NB(level,ei,ej,ek,workSet,nbl) & CFInter) ) {
- cellcnt += 1.0;
- for(int rl=0; rl< cDfNum ; ++rl) {
- LbmFloat nbdf = QCELL_NB(level,ei,ej,ek, workSet,nbl, rl);
- avgux += (dfDvecX[rl]*nbdf);
- avguy += (dfDvecY[rl]*nbdf);
- avguz += (dfDvecZ[rl]*nbdf);
- avgrho += nbdf;
- }
- }
- }
-
- if(cellcnt<=0.0) {
- // no nbs? just use eq.
- avgrho = 1.0;
- avgux = avguy = avguz = 0.0;
- //TTT mNumProblems++;
-#if ELBEEM_PLUGIN!=1
- //mPanic=1;
- // this can happen for worst case moving obj scenarios...
- errMsg("LbmFsgrSolver::interpolateCellValues","Cellcnt<=0.0 at "<<PRINT_VEC(ei,ej,ek));
-#endif // ELBEEM_PLUGIN
- } else {
- // init speed
- avgux /= cellcnt; avguy /= cellcnt; avguz /= cellcnt;
- avgrho /= cellcnt;
- }
-
- retrho = avgrho;
- retux = avgux;
- retuy = avguy;
- retuz = avguz;
-} // interpolateCellValues
-
-
-/******************************************************************************
- * instantiation
- *****************************************************************************/
-
-//! lbm factory functions
-LbmSolverInterface* createSolver() { return new LbmFsgrSolver(); }
-
-
diff --git a/intern/elbeem/intern/solver_interface.cpp b/intern/elbeem/intern/solver_interface.cpp
deleted file mode 100644
index 7f8fe9256e1..00000000000
--- a/intern/elbeem/intern/solver_interface.cpp
+++ /dev/null
@@ -1,753 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Combined 2D/3D Lattice Boltzmann Interface Class
- * contains stuff to be statically compiled
- *
- *****************************************************************************/
-
-/* LBM Files */
-#include "ntl_matrices.h"
-#include "solver_interface.h"
-#include "ntl_ray.h"
-#include "ntl_world.h"
-#include "elbeem.h"
-
-
-
-
-/******************************************************************************
- * Interface Constructor
- *****************************************************************************/
-LbmSolverInterface::LbmSolverInterface() :
- mPanic( false ),
- mSizex(10), mSizey(10), mSizez(10),
- mAllfluid(false), mStepCnt( 0 ),
- mFixMass( 0.0 ),
- mOmega( 1.0 ),
- mGravity(0.0),
- mSurfaceTension( 0.0 ),
- mBoundaryEast( (CellFlagType)(CFBnd) ),mBoundaryWest( (CellFlagType)(CFBnd) ),mBoundaryNorth( (CellFlagType)(CFBnd) ),
- mBoundarySouth( (CellFlagType)(CFBnd) ),mBoundaryTop( (CellFlagType)(CFBnd) ),mBoundaryBottom( (CellFlagType)(CFBnd) ),
- mInitDone( false ),
- mInitDensityGradient( false ),
- mpSifAttrs( NULL ), mpSifSwsAttrs(NULL), mpParam( NULL ), mpParticles(NULL),
- mNumParticlesLost(0),
- mNumInvalidDfs(0), mNumFilledCells(0), mNumEmptiedCells(0), mNumUsedCells(0), mMLSUPS(0),
- mDebugVelScale( 0.01 ), mNodeInfoString("+"),
- mvGeoStart(-1.0), mvGeoEnd(1.0), mpSimTrafo(NULL),
- mAccurateGeoinit(0),
- mName("lbm_default") ,
- mpIso( NULL ), mIsoValue(0.499),
- mSilent(false) ,
- mLbmInitId(1) ,
- mpGiTree( NULL ),
- mpGiObjects( NULL ), mGiObjInside(), mpGlob( NULL ),
- mRefinementDesired(0),
- mOutputSurfacePreview(0), mPreviewFactor(0.25),
- mSmoothSurface(1.0), mSmoothNormals(1.0),
- mIsoSubdivs(1), mPartGenProb(0.),
- mDumpVelocities(false),
- mMarkedCells(), mMarkedCellIndex(0),
- mDomainBound("noslip"), mDomainPartSlipValue(0.1),
- mFarFieldSize(0.),
- mPartDropMassSub(0.1), // good default
- mPartUsePhysModel(false),
- mTForceStrength(0.0),
- mCppfStage(0),
- mDumpRawText(false),
- mDumpRawBinary(false),
- mDumpRawBinaryZip(true)
-#if PARALLEL==1
- , mNumOMPThreads(1)
-#endif // PARALLEL==1
-{
-#if ELBEEM_PLUGIN==1
- if(gDebugLevel<=1) setSilent(true);
-#endif
- mpSimTrafo = new ntlMat4Gfx(0.0);
- mpSimTrafo->initId();
-
- if(getenv("ELBEEM_RAWDEBUGDUMP")) {
- debMsgStd("LbmSolverInterface",DM_MSG,"Using env var ELBEEM_RAWDEBUGDUMP, mDumpRawText on",2);
- mDumpRawText = true;
- }
-
- if(getenv("ELBEEM_BINDEBUGDUMP")) {
- debMsgStd("LbmSolverInterface",DM_MSG,"Using env var ELBEEM_RAWDEBUGDUMP, mDumpRawText on",2);
- mDumpRawBinary = true;
- }
-}
-
-LbmSolverInterface::~LbmSolverInterface()
-{
- if(mpSimTrafo) delete mpSimTrafo;
-}
-
-
-/******************************************************************************
- * initialize correct grid sizes given a geometric bounding box
- * and desired grid resolutions, all params except maxrefine
- * will be modified
- *****************************************************************************/
-void initGridSizes(int &sizex, int &sizey, int &sizez,
- ntlVec3Gfx &geoStart, ntlVec3Gfx &geoEnd,
- int mMaxRefine, bool parallel)
-{
- // fix size inits to force cubic cells and mult4 level dimensions
- const int debugGridsizeInit = 1;
- if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Called - size X:"<<sizex<<" Y:"<<sizey<<" Z:"<<sizez<<" "<<geoStart<<","<<geoEnd ,10);
-
- int maxGridSize = sizex; // get max size
- if(sizey>maxGridSize) maxGridSize = sizey;
- if(sizez>maxGridSize) maxGridSize = sizez;
- LbmFloat maxGeoSize = (geoEnd[0]-geoStart[0]); // get max size
- if((geoEnd[1]-geoStart[1])>maxGeoSize) maxGeoSize = (geoEnd[1]-geoStart[1]);
- if((geoEnd[2]-geoStart[2])>maxGeoSize) maxGeoSize = (geoEnd[2]-geoStart[2]);
- // FIXME better divide max geo size by corresponding resolution rather than max? no prob for rx==ry==rz though
- LbmFloat cellSize = (maxGeoSize / (LbmFloat)maxGridSize);
- if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Start:"<<geoStart<<" End:"<<geoEnd<<" maxS:"<<maxGeoSize<<" maxG:"<<maxGridSize<<" cs:"<<cellSize, 10);
- // force grid sizes according to geom. size, rounded
- sizex = (int) ((geoEnd[0]-geoStart[0]) / cellSize +0.5);
- sizey = (int) ((geoEnd[1]-geoStart[1]) / cellSize +0.5);
- sizez = (int) ((geoEnd[2]-geoStart[2]) / cellSize +0.5);
- // match refinement sizes, round downwards to multiple of 4
- int sizeMask = 0;
- int maskBits = mMaxRefine;
- if(parallel==1) maskBits+=2;
- for(int i=0; i<maskBits; i++) { sizeMask |= (1<<i); }
-
- // at least size 4 on coarsest level
- int minSize = 4<<mMaxRefine; //(maskBits+2);
- if(sizex<minSize) sizex = minSize;
- if(sizey<minSize) sizey = minSize;
- if(sizez<minSize) sizez = minSize;
-
- sizeMask = ~sizeMask;
- if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Size X:"<<sizex<<" Y:"<<sizey<<" Z:"<<sizez<<" m"<<convertFlags2String(sizeMask)<<", maskBits:"<<maskBits<<",minSize:"<<minSize ,10);
- sizex &= sizeMask;
- sizey &= sizeMask;
- sizez &= sizeMask;
- // debug
- int nextinc = (~sizeMask)+1;
- debMsgStd("initGridSizes",DM_MSG,"MPTeffMLtest, curr size:"<<PRINT_VEC(sizex,sizey,sizez)<<", next size:"<<PRINT_VEC(sizex+nextinc,sizey+nextinc,sizez+nextinc) ,10);
-
- // force geom size to match rounded/modified grid sizes
- geoEnd[0] = geoStart[0] + cellSize*(LbmFloat)sizex;
- geoEnd[1] = geoStart[1] + cellSize*(LbmFloat)sizey;
- geoEnd[2] = geoStart[2] + cellSize*(LbmFloat)sizez;
-}
-
-void calculateMemreqEstimate( int resx,int resy,int resz,
- int refine, float farfield,
- double *reqret, double *reqretFine, string *reqstr) {
- // debug estimation?
- const bool debugMemEst = true;
- // COMPRESSGRIDS define is not available here, make sure it matches
- const bool useGridComp = true;
- // make sure we can handle bid numbers here... all double
- double memCnt = 0.0;
- double ddTotalNum = (double)dTotalNum;
- if(reqretFine) *reqretFine = -1.;
-
- double currResx = (double)resx;
- double currResy = (double)resy;
- double currResz = (double)resz;
- double rcellSize = ((currResx*currResy*currResz) *ddTotalNum);
- memCnt += (double)(sizeof(CellFlagType) * (rcellSize/ddTotalNum +4.0) *2.0);
- if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"res:"<<PRINT_VEC(currResx,currResy,currResz)<<" rcellSize:"<<rcellSize<<" mc:"<<memCnt, 10);
- if(!useGridComp) {
- memCnt += (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0);
- if(reqretFine) *reqretFine = (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0);
- if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG," no-comp, mc:"<<memCnt, 10);
- } else {
- double compressOffset = (double)(currResx*currResy*ddTotalNum*2.0);
- memCnt += (double)(sizeof(LbmFloat) * (rcellSize+compressOffset +4.0));
- if(reqretFine) *reqretFine = (double)(sizeof(LbmFloat) * (rcellSize+compressOffset +4.0));
- if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG," w-comp, mc:"<<memCnt, 10);
- }
- for(int i=refine-1; i>=0; i--) {
- currResx /= 2.0;
- currResy /= 2.0;
- currResz /= 2.0;
- rcellSize = ((currResz*currResy*currResx) *ddTotalNum);
- memCnt += (double)(sizeof(CellFlagType) * (rcellSize/ddTotalNum +4.0) *2.0);
- memCnt += (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0);
- if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"refine "<<i<<", mc:"<<memCnt, 10);
- }
-
- // isosurface memory, use orig res values
- if(farfield>0.) {
- memCnt += (double)( (3*sizeof(int)+sizeof(float)) * ((resx+2)*(resy+2)*(resz+2)) );
- } else {
- // ignore 3 int slices...
- memCnt += (double)( ( sizeof(float)) * ((resx+2)*(resy+2)*(resz+2)) );
- }
- if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"iso, mc:"<<memCnt, 10);
-
- // cpdata init check missing...
-
- double memd = memCnt;
- const char *sizeStr = "";
- const double sfac = 1024.0;
- if(memd>sfac){ memd /= sfac; sizeStr="KB"; }
- if(memd>sfac){ memd /= sfac; sizeStr="MB"; }
- if(memd>sfac){ memd /= sfac; sizeStr="GB"; }
- if(memd>sfac){ memd /= sfac; sizeStr="TB"; }
-
- // return values
- std::ostringstream ret;
- if(memCnt< 1024.0*1024.0) {
- // show full MBs
- ret << (ceil(memd));
- } else {
- // two digits for anything larger than MB
- ret << (ceil(memd*100.0)/100.0);
- }
- ret << " "<< sizeStr;
- *reqret = memCnt;
- *reqstr = ret.str();
- //debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Required Grid memory: "<< memd <<" "<< sizeStr<<" ",4);
-}
-
-void LbmSolverInterface::initDomainTrafo(float *mat) {
- mpSimTrafo->initArrayCheck(mat);
-}
-
-/*******************************************************************************/
-/*! parse a boundary flag string */
-CellFlagType LbmSolverInterface::readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed) {
- string val = mpSifAttrs->readString(name, "", source, target, needed);
- if(!strcmp(val.c_str(),"")) {
- // no value given...
- return CFEmpty;
- }
- if(!strcmp(val.c_str(),"bnd_no")) {
- return (CellFlagType)( CFBnd );
- }
- if(!strcmp(val.c_str(),"bnd_free")) {
- return (CellFlagType)( CFBnd );
- }
- if(!strcmp(val.c_str(),"fluid")) {
- /* might be used for some in/out flow cases */
- return (CellFlagType)( CFFluid );
- }
- errMsg("LbmSolverInterface::readBoundaryFlagInt","Invalid value '"<<val<<"' " );
-# if FSGR_STRICT_DEBUG==1
- errFatal("readBoundaryFlagInt","Strict abort..."<<val, SIMWORLD_INITERROR);
-# endif
- return defaultValue;
-}
-
-/*******************************************************************************/
-/*! parse standard attributes */
-void LbmSolverInterface::parseStdAttrList() {
- if(!mpSifAttrs) {
- errFatal("LbmSolverInterface::parseAttrList","mpSifAttrs pointer not initialized!",SIMWORLD_INITERROR);
- return; }
-
- // st currently unused
- mBoundaryEast = readBoundaryFlagInt("boundary_east", mBoundaryEast, "LbmSolverInterface", "mBoundaryEast", false);
- mBoundaryWest = readBoundaryFlagInt("boundary_west", mBoundaryWest, "LbmSolverInterface", "mBoundaryWest", false);
- mBoundaryNorth = readBoundaryFlagInt("boundary_north", mBoundaryNorth,"LbmSolverInterface", "mBoundaryNorth", false);
- mBoundarySouth = readBoundaryFlagInt("boundary_south", mBoundarySouth,"LbmSolverInterface", "mBoundarySouth", false);
- mBoundaryTop = readBoundaryFlagInt("boundary_top", mBoundaryTop,"LbmSolverInterface", "mBoundaryTop", false);
- mBoundaryBottom= readBoundaryFlagInt("boundary_bottom", mBoundaryBottom,"LbmSolverInterface", "mBoundaryBottom", false);
-
- mpSifAttrs->readMat4Gfx("domain_trafo" , (*mpSimTrafo), "ntlBlenderDumper","mpSimTrafo", false, mpSimTrafo );
-
- LbmVec sizeVec(mSizex,mSizey,mSizez);
- sizeVec = vec2L( mpSifAttrs->readVec3d("size", vec2P(sizeVec), "LbmSolverInterface", "sizeVec", false) );
- mSizex = (int)sizeVec[0];
- mSizey = (int)sizeVec[1];
- mSizez = (int)sizeVec[2];
- // param needs size in any case
- // test solvers might not have mpPara, though
- if(mpParam) mpParam->setSize(mSizex, mSizey, mSizez );
-
- mInitDensityGradient = mpSifAttrs->readBool("initdensitygradient", mInitDensityGradient,"LbmSolverInterface", "mInitDensityGradient", false);
- mIsoValue = mpSifAttrs->readFloat("isovalue", mIsoValue, "LbmOptSolver","mIsoValue", false );
-
- mDebugVelScale = mpSifAttrs->readFloat("debugvelscale", mDebugVelScale,"LbmSolverInterface", "mDebugVelScale", false);
- mNodeInfoString = mpSifAttrs->readString("nodeinfo", mNodeInfoString, "SimulationLbm","mNodeInfoString", false );
-
- mDumpVelocities = mpSifAttrs->readBool("dump_velocities", mDumpVelocities, "SimulationLbm","mDumpVelocities", false );
- if(getenv("ELBEEM_DUMPVELOCITIES")) {
- int get = atoi(getenv("ELBEEM_DUMPVELOCITIES"));
- if((get==0)||(get==1)) {
- mDumpVelocities = get;
- debMsgStd("LbmSolverInterface::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_DUMPVELOCITIES to set mDumpVelocities to "<<get<<","<<mDumpVelocities,8);
- }
- }
-
- // new test vars
- // mTForceStrength set from test solver
- mFarFieldSize = mpSifAttrs->readFloat("farfieldsize", mFarFieldSize,"LbmSolverInterface", "mFarFieldSize", false);
- // old compat
- float sizeScale = mpSifAttrs->readFloat("test_scale", 0.,"LbmTestdata", "mSizeScale", false);
- if((mFarFieldSize<=0.)&&(sizeScale>0.)) { mFarFieldSize=sizeScale; errMsg("LbmTestdata","Warning - using mSizeScale..."); }
-
- mPartDropMassSub = mpSifAttrs->readFloat("part_dropmass", mPartDropMassSub,"LbmSolverInterface", "mPartDropMassSub", false);
-
- mCppfStage = mpSifAttrs->readInt("cppfstage", mCppfStage,"LbmSolverInterface", "mCppfStage", false);
- mPartGenProb = mpSifAttrs->readFloat("partgenprob", mPartGenProb,"LbmFsgrSolver", "mPartGenProb", false);
- mPartUsePhysModel = mpSifAttrs->readBool("partusephysmodel", mPartUsePhysModel,"LbmFsgrSolver", "mPartUsePhysModel", false);
- mIsoSubdivs = mpSifAttrs->readInt("isosubdivs", mIsoSubdivs,"LbmFsgrSolver", "mIsoSubdivs", false);
-}
-
-
-/*******************************************************************************/
-/*! geometry initialization */
-/*******************************************************************************/
-
-/*****************************************************************************/
-/*! init tree for certain geometry init */
-void LbmSolverInterface::initGeoTree() {
- if(mpGlob == NULL) { errFatal("LbmSolverInterface::initGeoTree","Requires globals!",SIMWORLD_INITERROR); return; }
- ntlScene *scene = mpGlob->getSimScene();
- mpGiObjects = scene->getObjects();
- mGiObjInside.resize( mpGiObjects->size() );
- mGiObjDistance.resize( mpGiObjects->size() );
- mGiObjSecondDist.resize( mpGiObjects->size() );
- for(size_t i=0; i<mpGiObjects->size(); i++) {
- if((*mpGiObjects)[i]->getGeoInitIntersect()) mAccurateGeoinit=true;
- //debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"id:"<<mLbmInitId<<" obj:"<< (*mpGiObjects)[i]->getName() <<" gid:"<<(*mpGiObjects)[i]->getGeoInitId(), 9 );
- }
- debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"Accurate geo init: "<<mAccurateGeoinit, 9)
- debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"Objects: "<<mpGiObjects->size() ,10);
-
- if(mpGiTree != NULL) delete mpGiTree;
- char treeFlag = (1<<(this->mLbmInitId+4));
- mpGiTree = new ntlTree(
-# if FSGR_STRICT_DEBUG!=1
- 15, 8, // TREEwarning - fixed values for depth & maxtriangles here...
-# else // FSGR_STRICT_DEBUG==1
- 10, 20, // reduced/slower debugging values
-# endif // FSGR_STRICT_DEBUG==1
- scene, treeFlag );
-}
-
-/*****************************************************************************/
-/*! destroy tree etc. when geometry init done */
-void LbmSolverInterface::freeGeoTree() {
- if(mpGiTree != NULL) {
- delete mpGiTree;
- mpGiTree = NULL;
- }
-}
-
-
-int globGeoInitDebug = 0;
-int globGICPIProblems = 0;
-/*****************************************************************************/
-/*! check for a certain flag type at position org */
-bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance, int shootDir) {
- // shift ve ctors to avoid rounding errors
- org += ntlVec3Gfx(0.0001);
- OId = -1;
-
- // select shooting direction
- ntlVec3Gfx dir = ntlVec3Gfx(1., 0., 0.);
- if(shootDir==1) dir = ntlVec3Gfx(0., 1., 0.);
- else if(shootDir==2) dir = ntlVec3Gfx(0., 0., 1.);
- else if(shootDir==-2) dir = ntlVec3Gfx(0., 0., -1.);
- else if(shootDir==-1) dir = ntlVec3Gfx(0., -1., 0.);
-
- ntlRay ray(org, dir, 0, 1.0, mpGlob);
- bool done = false;
- bool inside = false;
-
- vector<int> giObjFirstHistSide;
- giObjFirstHistSide.resize( mpGiObjects->size() );
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- mGiObjInside[i] = 0;
- mGiObjDistance[i] = -1.0;
- mGiObjSecondDist[i] = -1.0;
- giObjFirstHistSide[i] = 0;
- }
- // if not inside, return distance to first hit
- gfxReal firstHit=-1.0;
- int firstOId = -1;
- if(globGeoInitDebug) errMsg("IIIstart"," isect "<<org<<" f"<<flags<<" acc"<<mAccurateGeoinit);
-
- if(mAccurateGeoinit) {
- while(!done) {
- // find first inside intersection
- ntlTriangle *triIns = NULL;
- distance = -1.0;
- ntlVec3Gfx normal(0.0);
- if(shootDir==0) mpGiTree->intersectX(ray,distance,normal, triIns, flags, true);
- else mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
- if(triIns) {
- ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
- LbmFloat orientation = dot(normal, dir);
- OId = triIns->getObjectId();
- if(orientation<=0.0) {
- // outside hit
- normal *= -1.0;
- mGiObjInside[OId]++;
- if(giObjFirstHistSide[OId]==0) giObjFirstHistSide[OId] = 1;
- if(globGeoInitDebug) errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation);
- } else {
- // inside hit
- mGiObjInside[OId]++;
- if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
- if(globGeoInitDebug) errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation);
- if(giObjFirstHistSide[OId]==0) giObjFirstHistSide[OId] = -1;
- }
- norg += normal * getVecEpsilon();
- ray = ntlRay(norg, dir, 0, 1.0, mpGlob);
- // remember first hit distance, in case we're not
- // inside anything
- if(firstHit<0.0) {
- firstHit = distance;
- firstOId = OId;
- }
- } else {
- // no more intersections... return false
- done = true;
- }
- }
-
- distance = -1.0;
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- if(mGiObjInside[i]>0) {
- bool mess = false;
- if((mGiObjInside[i]%2)==1) {
- if(giObjFirstHistSide[i] != -1) mess=true;
- } else {
- if(giObjFirstHistSide[i] != 1) mess=true;
- }
- if(mess) {
- //errMsg("IIIproblem","At "<<org<<" obj "<<i<<" inside:"<<mGiObjInside[i]<<" firstside:"<<giObjFirstHistSide[i] );
- globGICPIProblems++;
- mGiObjInside[i]++; // believe first hit side...
- }
- }
- }
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- if(globGeoInitDebug) errMsg("CHIII","i"<<i<<" ins="<<mGiObjInside[i]<<" t"<<mGiObjDistance[i]<<" d"<<distance);
- if(((mGiObjInside[i]%2)==1)&&(mGiObjDistance[i]>0.0)) {
- if( (distance<0.0) || // first intersection -> good
- ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
- ) {
- distance = mGiObjDistance[i];
- OId = i;
- inside = true;
- }
- }
- }
- if(!inside) {
- distance = firstHit;
- OId = firstOId;
- }
- if(globGeoInitDebug) errMsg("CHIII","i"<<inside<<" fh"<<firstHit<<" fo"<<firstOId<<" - h"<<distance<<" o"<<OId);
-
- return inside;
- } else {
-
- // find first inside intersection
- ntlTriangle *triIns = NULL;
- distance = -1.0;
- ntlVec3Gfx normal(0.0);
- if(shootDir==0) mpGiTree->intersectX(ray,distance,normal, triIns, flags, true);
- else mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
- if(triIns) {
- // check outside intersect
- LbmFloat orientation = dot(normal, dir);
- if(orientation<=0.0) return false;
-
- OId = triIns->getObjectId();
- return true;
- }
- return false;
- }
-}
-bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, ntlVec3Gfx dir, int flags, int &OId, gfxReal &distance, const gfxReal halfCellsize, bool &thinHit, bool recurse) {
- // shift ve ctors to avoid rounding errors
- org += ntlVec3Gfx(0.0001); //?
- OId = -1;
- ntlRay ray(org, dir, 0, 1.0, mpGlob);
- //int insCnt = 0;
- bool done = false;
- bool inside = false;
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- mGiObjInside[i] = 0;
- mGiObjDistance[i] = -1.0;
- mGiObjSecondDist[i] = -1.0;
- }
- // if not inside, return distance to first hit
- gfxReal firstHit=-1.0;
- int firstOId = -1;
- thinHit = false;
-
- if(mAccurateGeoinit) {
- while(!done) {
- // find first inside intersection
- ntlTriangle *triIns = NULL;
- distance = -1.0;
- ntlVec3Gfx normal(0.0);
- mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
- if(triIns) {
- ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
- LbmFloat orientation = dot(normal, dir);
- OId = triIns->getObjectId();
- if(orientation<=0.0) {
- // outside hit
- normal *= -1.0;
- //mGiObjDistance[OId] = -1.0;
- //errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
- } else {
- // inside hit
- //if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
- //errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
- if(mGiObjInside[OId]==1) {
- // second inside hit
- if(mGiObjSecondDist[OId]<0.0) mGiObjSecondDist[OId] = distance;
- }
- }
- mGiObjInside[OId]++;
- // always store first hit for thin obj init
- if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
-
- norg += normal * getVecEpsilon();
- ray = ntlRay(norg, dir, 0, 1.0, mpGlob);
- // remember first hit distance, in case we're not
- // inside anything
- if(firstHit<0.0) {
- firstHit = distance;
- firstOId = OId;
- }
- } else {
- // no more intersections... return false
- done = true;
- //if(insCnt%2) inside=true;
- }
- }
-
- distance = -1.0;
- // standard inside check
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- if(((mGiObjInside[i]%2)==1)&&(mGiObjDistance[i]>0.0)) {
- if( (distance<0.0) || // first intersection -> good
- ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
- ) {
- distance = mGiObjDistance[i];
- OId = i;
- inside = true;
- }
- }
- }
- // now check for thin hits
- if(!inside) {
- distance = -1.0;
- for(size_t i=0; i<mGiObjInside.size(); i++) {
- if((mGiObjInside[i]>=2)&&(mGiObjDistance[i]>0.0)&&(mGiObjSecondDist[i]>0.0)&&
- (mGiObjDistance[i]<1.0*halfCellsize)&&(mGiObjSecondDist[i]<2.0*halfCellsize) ) {
- if( (distance<0.0) || // first intersection -> good
- ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
- ) {
- distance = mGiObjDistance[i];
- OId = i;
- inside = true;
- thinHit = true;
- }
- }
- }
- }
- if(!inside) {
- // check for hit in this cell, opposite to current dir (only recurse once)
- if(recurse) {
- gfxReal r_distance;
- int r_OId;
- bool ret = geoInitCheckPointInside(org, dir*-1.0, flags, r_OId, r_distance, halfCellsize, thinHit, false);
- if((ret)&&(thinHit)) {
- OId = r_OId;
- distance = 0.0;
- return true;
- }
- }
- }
- // really no hit...
- if(!inside) {
- distance = firstHit;
- OId = firstOId;
- /*if((mGiObjDistance[OId]>0.0)&&(mGiObjSecondDist[OId]>0.0)) {
- const gfxReal thisdist = mGiObjSecondDist[OId]-mGiObjDistance[OId];
- // dont walk over this cell...
- if(thisdist<halfCellsize) distance-=2.0*halfCellsize;
- } // ? */
- }
- //errMsg("CHIII","i"<<inside<<" fh"<<firstHit<<" fo"<<firstOId<<" - h"<<distance<<" o"<<OId);
-
- return inside;
- } else {
-
- // find first inside intersection
- ntlTriangle *triIns = NULL;
- distance = -1.0;
- ntlVec3Gfx normal(0.0);
- mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
- if(triIns) {
- // check outside intersect
- LbmFloat orientation = dot(normal, dir);
- if(orientation<=0.0) return false;
-
- OId = triIns->getObjectId();
- return true;
- }
- return false;
- }
-}
-
-
-/*****************************************************************************/
-ntlVec3Gfx LbmSolverInterface::getGeoMaxMovementVelocity(LbmFloat simtime, LbmFloat stepsize) {
- ntlVec3Gfx max(0.0);
- if(mpGlob == NULL) return max;
- // mpGiObjects has to be inited here...
-
- for(int i=0; i< (int)mpGiObjects->size(); i++) {
- //errMsg("LbmSolverInterface::getGeoMaxMovementVelocity","i="<<i<<" "<< (*mpGiObjects)[i]->getName() ); // DEBUG
- if( (*mpGiObjects)[i]->getGeoInitType() & (FGI_FLUID|FGI_MBNDINFLOW) ){
- //ntlVec3Gfx objMaxVel = obj->calculateMaxVel(sourceTime,targetTime);
- ntlVec3Gfx orgvel = (*mpGiObjects)[i]->calculateMaxVel( simtime, simtime+stepsize );
- if( normNoSqrt(orgvel) > normNoSqrt(max) ) { max = orgvel; }
- //errMsg("MVT","i"<<i<<" a"<< (*mpGiObjects)[i]->getInitialVelocity(simtime)<<" o"<<orgvel ); // DEBUG
- // TODO check if inflow and simtime
- ntlVec3Gfx inivel = (*mpGiObjects)[i]->getInitialVelocity(simtime);
- if( normNoSqrt(inivel) > normNoSqrt(max) ) { max = inivel; }
- }
- }
- errMsg("LbmSolverInterface::getGeoMaxMovementVelocity", "max="<< max ); // DEBUG
- return max;
-}
-
-
-
-
-/*******************************************************************************/
-/*! cell iteration functions */
-/*******************************************************************************/
-
-
-
-
-/*****************************************************************************/
-//! add cell to mMarkedCells list
-void
-LbmSolverInterface::addCellToMarkedList( CellIdentifierInterface *cid ) {
- for(size_t i=0; i<mMarkedCells.size(); i++) {
- // check if cids alreay in
- if( mMarkedCells[i]->equal(cid) ) return;
- //mMarkedCells[i]->setEnd(false);
- }
- mMarkedCells.push_back( cid );
- //cid->setEnd(true);
-}
-
-/*****************************************************************************/
-//! marked cell iteration methods
-CellIdentifierInterface*
-LbmSolverInterface::markedGetFirstCell( ) {
- if(mMarkedCells.size() > 0){ return mMarkedCells[0]; }
- return NULL;
-}
-
-CellIdentifierInterface*
-LbmSolverInterface::markedAdvanceCell() {
- mMarkedCellIndex++;
- if(mMarkedCellIndex>=(int)mMarkedCells.size()) return NULL;
- return mMarkedCells[mMarkedCellIndex];
-}
-
-void LbmSolverInterface::markedClearList() {
- // FIXME free cids?
- mMarkedCells.clear();
-}
-
-#if PARALLEL==1
-void LbmSolverInterface::setNumOMPThreads(int num_threads) {
- mNumOMPThreads = num_threads;
-}
-#endif // PARALLEL==1
-
-/*******************************************************************************/
-/*! string helper functions */
-/*******************************************************************************/
-
-
-
-// 32k
-string convertSingleFlag2String(CellFlagType cflag) {
- CellFlagType flag = cflag;
- if(flag == CFUnused ) return string("cCFUnused");
- if(flag == CFEmpty ) return string("cCFEmpty");
- if(flag == CFBnd ) return string("cCFBnd");
- if(flag == CFBndNoslip ) return string("cCFBndNoSlip");
- if(flag == CFBndFreeslip ) return string("cCFBndFreeSlip");
- if(flag == CFBndPartslip ) return string("cCFBndPartSlip");
- if(flag == CFNoInterpolSrc ) return string("cCFNoInterpolSrc");
- if(flag == CFFluid ) return string("cCFFluid");
- if(flag == CFInter ) return string("cCFInter");
- if(flag == CFNoNbFluid ) return string("cCFNoNbFluid");
- if(flag == CFNoNbEmpty ) return string("cCFNoNbEmpty");
- if(flag == CFNoDelete ) return string("cCFNoDelete");
- if(flag == CFNoBndFluid ) return string("cCFNoBndFluid");
- if(flag == CFGrNorm ) return string("cCFGrNorm");
- if(flag == CFGrFromFine ) return string("cCFGrFromFine");
- if(flag == CFGrFromCoarse ) return string("cCFGrFromCoarse");
- if(flag == CFGrCoarseInited ) return string("cCFGrCoarseInited");
- if(flag == CFMbndInflow ) return string("cCFMbndInflow");
- if(flag == CFMbndOutflow ) return string("cCFMbndOutflow");
- if(flag == CFInvalid ) return string("cfINVALID");
-
- std::ostringstream mult;
- int val = 0;
- if(flag != 0) {
- while(! (flag&1) ) {
- flag = flag>>1;
- val++;
- }
- } else {
- val = -1;
- }
- if(val>=24) {
- mult << "cfOID_" << (flag>>24) <<"_TYPE";
- } else {
- mult << "cfUNKNOWN_" << val <<"_TYPE";
- }
- return mult.str();
-}
-
-//! helper function to convert flag to string (for debuggin)
-string convertCellFlagType2String( CellFlagType cflag ) {
- int flag = cflag;
-
- const int jmax = sizeof(CellFlagType)*8;
- bool somefound = false;
- std::ostringstream mult;
- mult << "[";
- for(int j=0; j<jmax ; j++) {
- if(flag& (1<<j)) {
- if(somefound) mult << "|";
- mult << j<<"<"<< convertSingleFlag2String( (CellFlagType)(1<<j) ); // this call should always be _non_-recursive
- somefound = true;
- }
- };
- mult << "]";
-
- // return concatenated string
- if(somefound) return mult.str();
-
- // empty?
- return string("[emptyCFT]");
-}
-
diff --git a/intern/elbeem/intern/solver_interface.h b/intern/elbeem/intern/solver_interface.h
deleted file mode 100644
index 1301e0f6ebb..00000000000
--- a/intern/elbeem/intern/solver_interface.h
+++ /dev/null
@@ -1,639 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Header for Combined 2D/3D Lattice Boltzmann Interface Class
- *
- *****************************************************************************/
-#ifndef LBMINTERFACE_H
-#define LBMINTERFACE_H
-
-//! include gui support?
-#ifndef NOGUI
-#define LBM_USE_GUI 1
-#else
-#define LBM_USE_GUI 0
-#endif
-
-#if LBM_USE_GUI==1
-#define USE_GLUTILITIES
-// for debug display
-//#include <GL/gl.h>
-#include "../gui/guifuncs.h"
-#endif
-
-#include <sstream>
-#include "utilities.h"
-#include "ntl_bsptree.h"
-#include "ntl_geometryobject.h"
-#include "parametrizer.h"
-#include "attributes.h"
-#include "isosurface.h"
-
-#ifdef WITH_CXX_GUARDEDALLOC
-# include "MEM_guardedalloc.h"
-#endif
-
-class ParticleTracer;
-class ParticleObject;
-
-// use which fp-precision for LBM? 1=float, 2=double
-#ifdef PRECISION_LBM_SINGLE
-#define LBM_PRECISION 1
-#else
-#ifdef PRECISION_LBM_DOUBLE
-#define LBM_PRECISION 2
-#else
-// default to floats
-#define LBM_PRECISION 1
-#endif
-#endif
-
-#if LBM_PRECISION==1
-/* low precision for LBM solver */
-typedef float LbmFloat;
-typedef ntlVec3f LbmVec;
-#define LBM_EPSILON (1e-5)
-#else
-/* standard precision for LBM solver */
-typedef double LbmFloat;
-typedef ntlVec3d LbmVec;
-#define LBM_EPSILON (1e-10)
-#endif
-
-// long integer, needed e.g. for memory calculations
-#ifndef USE_MSVC6FIXES
-#define LONGINT long long int
-#else
-#define LONGINT _int64
-#endif
-
-
-// default to 3dim
-#ifndef LBMDIM
-#define LBMDIM 3
-#endif // LBMDIM
-
-#if LBMDIM==2
-#define LBM_DFNUM 9
-#else
-#define LBM_DFNUM 19
-#endif
-
-// conversions (lbm and parametrizer)
-template<class T> inline LbmVec vec2L(T v) { return LbmVec(v[0],v[1],v[2]); }
-template<class T> inline ParamVec vec2P(T v) { return ParamVec(v[0],v[1],v[2]); }
-
-template<class Scalar> class ntlMatrix4x4;
-
-
-// bubble id type
-typedef int BubbleId;
-
-// basic cell type distinctions
-#define CFUnused (1<< 0)
-#define CFEmpty (1<< 1)
-#define CFBnd (1<< 2)
-#define CFMbndInflow (1<< 3)
-#define CFMbndOutflow (1<< 4)
-#define CFFluid (1<< 5)
-#define CFInter (1<< 6)
-// additional for fluid (needed separately for adaptive grids)
-#define CFNoBndFluid (1<< 7)
-#define CFNoDelete (1<< 8)
-
-// additional bnd add flags
-#define CFBndNoslip (1<< 9)
-#define CFBndFreeslip (1<<10)
-#define CFBndPartslip (1<<11)
-#define CFBndMoving (1<<12)
-
-// additional for fluid/interface
-// force symmetry for flag reinit
-#define CFNoInterpolSrc (1<<13)
-#define CFNoNbFluid (1<<14)
-#define CFNoNbEmpty (1<<15)
-
-// cell treated normally on coarser grids
-#define CFGrNorm (1<<16)
-#define CFGrCoarseInited (1<<17)
-
-// (the following values shouldnt overlap to ensure
-// proper coarsening)
-// border cells to be interpolated from finer grid
-#define CFGrFromFine (1<<18)
-// 32k aux border marker
-#define CFGrToFine (1<<19)
-// also needed on finest level
-#define CFGrFromCoarse (1<<20)
-// additional refinement tags (coarse grids only?)
-// */
-
-// above 24 is used to encode in/outflow object type
-#define CFPersistMask (0xFF000000 | CFMbndInflow | CFMbndOutflow)
-#define CFNoPersistMask (~CFPersistMask)
-
-
-// nk
-#define CFInvalid (CellFlagType)(1<<31)
-
-// use 32bit flag types
-//#ifdef __x86_64__
- //typedef int cfINT32;
-//#else
- //typedef long cfINT32;
-//#endif // defined (_IA64)
-//#define CellFlagType cfINT32
-#define CellFlagType int
-#define CellFlagTypeSize 4
-
-
-// aux. field indices (same for 2d)
-#define dFfrac 19
-#define dMass 20
-#define dFlux 21
-// max. no. of cell values for 3d
-#define dTotalNum 22
-
-
-/*****************************************************************************/
-/*! a single lbm cell */
-/* the template is only needed for
- * dimension dependend constants e.g.
- * number of df's in model */
-class LbmCellContents {
- public:
- LbmFloat df[ 27 ]; // be on the safe side here...
- LbmFloat rho;
- LbmVec vel;
- LbmFloat mass;
- CellFlagType flag;
- BubbleId bubble;
- LbmFloat ffrac;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:LbmCellContents")
-#endif
-};
-
-/* struct for the coordinates of a cell in the grid */
-typedef struct {
- int x,y,z;
- int flag; // special handling?
-} LbmPoint;
-
-/* struct for the coordinates of a cell in the grid */
-typedef struct {
- char active; // bubble in use, oder may be overwritten?
- LbmFloat volume; // volume of this bubble (0 vor atmosphere)
- LbmFloat mass; // "mass" of bubble
- int i,j,k; // index of a cell in the bubble
-} LbmBubble;
-
-
-
-
-//! choose which data to display
-#define FLUIDDISPINVALID 0
-#define FLUIDDISPNothing 1
-#define FLUIDDISPCelltypes 2
-#define FLUIDDISPVelocities 3
-#define FLUIDDISPCellfills 4
-#define FLUIDDISPDensity 5
-#define FLUIDDISPGrid 6
-#define FLUIDDISPSurface 7
-
-
-
-/*****************************************************************************/
-//! cell identifier interface
-class CellIdentifierInterface {
- public:
- //! reset constructor
- CellIdentifierInterface():mEnd(false) { };
- //! virtual destructor
- virtual ~CellIdentifierInterface() {};
-
- //! return node as string (with some basic info)
- virtual string getAsString() = 0;
-
- //! compare cids
- virtual bool equal(CellIdentifierInterface* other) = 0;
-
- //! set/get end flag for grid traversal (not needed for marked cells)
- inline void setEnd(bool set){ mEnd = set; }
- inline bool getEnd( ) { return mEnd; }
-
- //! has the grid been traversed?
- bool mEnd;
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:CellIdentifierInterface")
-#endif
-};
-
-
-
-/*****************************************************************************/
-/*! class defining abstract function interface */
-/* has to provide iterating functionality */
-class LbmSolverInterface
-{
- public:
- //! Constructor
- LbmSolverInterface();
- //! Destructor
- virtual ~LbmSolverInterface();
- //! id string of solver
- virtual string getIdString() = 0;
-
- // multi step solver init
- /*! finish the init with config file values (allocate arrays...) */
- virtual bool initializeSolverMemory() =0;
- /*! init solver arrays */
- virtual bool initializeSolverGrids() =0;
- /*! prepare actual simulation start, setup viz etc */
- virtual bool initializeSolverPostinit() =0;
-
- /*! notify object that dump is in progress (e.g. for field dump) */
- virtual void notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) = 0;
-
- /*! parse a boundary flag string */
- CellFlagType readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed);
- /*! parse standard attributes */
- void parseStdAttrList();
- /*! initilize variables fom attribute list (should at least call std parse) */
- virtual void parseAttrList() = 0;
-
- virtual void step() = 0;
- virtual void prepareVisualization() { /* by default off */ };
-
- /*! particle handling */
- virtual int initParticles() = 0;
- virtual void advanceParticles() = 0;
- /*! get surface object (NULL if no surface) */
- IsoSurface* getSurfaceGeoObj() { return mpIso; }
-
- /*! debug object display */
- virtual vector<ntlGeometryObject*> getDebugObjects() { vector<ntlGeometryObject*> empty(0); return empty; }
-
- /* surface generation settings */
- virtual void setSurfGenSettings(short value) = 0;
-
-#if LBM_USE_GUI==1
- /*! show simulation info */
- virtual void debugDisplay(int) = 0;
-#endif
-
- /*! init tree for certain geometry init */
- void initGeoTree();
- /*! destroy tree etc. when geometry init done */
- void freeGeoTree();
- /*! check for a certain flag type at position org (needed for e.g. quadtree refinement) */
- bool geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance,int shootDir=0);
- bool geoInitCheckPointInside(ntlVec3Gfx org, ntlVec3Gfx dir, int flags, int &OId, gfxReal &distance,
- const gfxReal halfCellsize, bool &thinHit, bool recurse);
- /*! set render globals, for scene/tree access */
- void setRenderGlobals(ntlRenderGlobals *glob) { mpGlob = glob; };
- /*! get max. velocity of all objects to initialize as fluid regions, and of all moving objects */
- ntlVec3Gfx getGeoMaxMovementVelocity(LbmFloat simtime, LbmFloat stepsize);
-
- /* rt interface functions */
- unsigned int getIsoVertexCount() { return mpIso->getIsoVertexCount(); }
- unsigned int getIsoIndexCount() { return mpIso->getIsoIndexCount(); }
- char* getIsoVertexArray() { return mpIso->getIsoVertexArray(); }
- unsigned int *getIsoIndexArray() { return mpIso->getIsoIndexArray(); }
- void triangulateSurface() { mpIso->triangulate(); }
-
- /* access functions */
-
- /*! return grid sizes */
- int getSizeX( void ) { return mSizex; }
- int getSizeY( void ) { return mSizey; }
- int getSizeZ( void ) { return mSizez; }
- /*! return grid sizes */
- void setSizeX( int ns ) { mSizex = ns; }
- void setSizeY( int ns ) { mSizey = ns; }
- void setSizeZ( int ns ) { mSizez = ns; }
- /*! access fluid only simulation flag */
- void setAllfluid(bool set) { mAllfluid=set; }
- bool getAllfluid() { return mAllfluid; }
-
- /*! set attr list pointer */
- void setAttrList(AttributeList *set) { mpSifAttrs = set; }
- /*! Returns the attribute list pointer */
- inline AttributeList *getAttributeList() { return mpSifAttrs; }
- /*! set sws attr list pointer */
- void setSwsAttrList(AttributeList *set) { mpSifSwsAttrs = set; }
- inline AttributeList *getSwsAttributeList() { return mpSifSwsAttrs; }
-
- /*! set parametrizer pointer */
- inline void setParametrizer(Parametrizer *set) { mpParam = set; }
- /*! get parametrizer pointer */
- inline Parametrizer *getParametrizer() { return mpParam; }
- /*! get/set particle pointer */
- inline void setParticleTracer(ParticleTracer *set) { mpParticles = set; }
- inline ParticleTracer *getParticleTracer() { return mpParticles; }
-
- /*! set density gradient init from e.g. init test cases */
- inline void setInitDensityGradient(bool set) { mInitDensityGradient = set; }
-
- /*! access geometry start vector */
- inline void setGeoStart(ntlVec3Gfx set) { mvGeoStart = set; }
- inline ntlVec3Gfx getGeoStart() const { return mvGeoStart; }
-
- /*! access geometry end vector */
- inline void setGeoEnd(ntlVec3Gfx set) { mvGeoEnd = set; }
- inline ntlVec3Gfx getGeoEnd() const { return mvGeoEnd; }
-
- /*! access geo init vars */
- inline void setLbmInitId(int set) { mLbmInitId = set; }
- inline int getLbmInitId() const { return mLbmInitId; }
-
- /*! init domain transformation matrix from float array */
- void initDomainTrafo(float *mat);
- /*! get domain transformation matrix to have object centered fluid vertices */
- inline ntlMatrix4x4<gfxReal> *getDomainTrafo() { return mpSimTrafo; }
-
- /*! access name string */
- inline void setName(string set) { mName = set; }
- inline string getName() const { return mName; }
-
- /*! access string for node info debugging output */
- inline string getNodeInfoString() const { return mNodeInfoString; }
-
- /*! get panic flag */
- inline bool getPanic() { return mPanic; }
-
- //! set silent mode?
- inline void setSilent(bool set){ mSilent = set; }
-
- //! set amount of surface/normal smoothing
- inline void setSmoothing(float setss,float setns){ mSmoothSurface=setss; mSmoothNormals=setns; }
- //! set amount of iso subdivisions
- inline void setIsoSubdivs(int s){ mIsoSubdivs=s; }
- //! set desired refinement
- inline void setPreviewSize(int set){ mOutputSurfacePreview = set; }
- //! set desired refinement
- inline void setRefinementDesired(int set){ mRefinementDesired = set; }
-
- //! set/get dump velocities flag
- inline void setDumpVelocities(bool set) { mDumpVelocities = set; }
- inline bool getDumpVelocities() const { return mDumpVelocities; }
-
- //! set/get particle generation prob.
- inline void setGenerateParticles(LbmFloat set) { mPartGenProb = set; }
- inline LbmFloat getGenerateParticles() const { return mPartGenProb; }
-
- //! set/get dump velocities flag
- inline void setDomainBound(string set) { mDomainBound = set; }
- inline string getDomainBound() const { return mDomainBound; }
- //! set/get dump velocities flag
- inline void setDomainPartSlip(LbmFloat set) { mDomainPartSlipValue = set; }
- inline LbmFloat getDomainPartSlip() const { return mDomainPartSlipValue; }
- //! set/get far field size
- inline void setFarFieldSize(LbmFloat set) { mFarFieldSize = set; }
- inline LbmFloat getFarFieldSize() const { return mFarFieldSize; }
- //! set/get cp stage
- inline void setCpStage(int set) { mCppfStage = set; }
- inline int getCpStage() const { return mCppfStage; }
- //! set/get dump modes
- inline void setDumpRawText(bool set) { mDumpRawText = set; }
- inline bool getDumpRawText() const { return mDumpRawText; }
- inline void setDumpRawBinary(bool set) { mDumpRawBinary = set; }
- inline bool getDumpRawBinary() const { return mDumpRawBinary; }
- inline void setDumpRawBinaryZip(bool set) { mDumpRawBinaryZip = set; }
- inline bool getDumpRawBinaryZip() const { return mDumpRawBinaryZip; }
- //! set/get debug vel scale
- inline void setDebugVelScale(LbmFloat set) { mDebugVelScale = set; }
- inline LbmFloat getDebugVelScale() const { return mDebugVelScale; }
-
- // cell iterator interface
-
- // cell id type
- typedef CellIdentifierInterface* CellIdentifier;
-
- //! cell iteration methods
- virtual CellIdentifierInterface* getFirstCell( ) = 0;
- virtual void advanceCell( CellIdentifierInterface* ) = 0;
- virtual bool noEndCell( CellIdentifierInterface* ) = 0;
- //! clean up iteration, this should be called, when the iteration is not completely finished
- virtual void deleteCellIterator( CellIdentifierInterface** ) = 0;
-
- //! find cell at a given position (returns NULL if not in domain)
- virtual CellIdentifierInterface* getCellAt( ntlVec3Gfx pos ) = 0;
-
- //! return node information
- virtual int getCellSet ( CellIdentifierInterface* ) = 0;
- virtual ntlVec3Gfx getCellOrigin ( CellIdentifierInterface* ) = 0;
- virtual ntlVec3Gfx getCellSize ( CellIdentifierInterface* ) = 0;
- virtual int getCellLevel ( CellIdentifierInterface* ) = 0;
- virtual LbmFloat getCellDensity ( CellIdentifierInterface*,int ) = 0;
- virtual LbmVec getCellVelocity ( CellIdentifierInterface*,int ) = 0;
- /*! get equilibrium distribution functions */
- virtual LbmFloat getEquilDf ( int ) = 0;
- /*! redundant cell functions */
- virtual LbmFloat getCellDf ( CellIdentifierInterface* ,int set, int dir) = 0;
- virtual LbmFloat getCellMass ( CellIdentifierInterface* ,int set) = 0;
- virtual LbmFloat getCellFill ( CellIdentifierInterface* ,int set) = 0;
- virtual CellFlagType getCellFlag ( CellIdentifierInterface* ,int set) = 0;
-
- /*! get velocity directly from position */
- virtual ntlVec3Gfx getVelocityAt(float x, float y, float z) = 0;
-
- // gui/output debugging functions
-#if LBM_USE_GUI==1
- virtual void debugDisplayNode(int dispset, CellIdentifier cell ) = 0;
- virtual void lbmDebugDisplay(int dispset) = 0;
- virtual void lbmMarkedCellDisplay() = 0;
-#endif // LBM_USE_GUI==1
- virtual void debugPrintNodeInfo(CellIdentifier cell, int forceSet=-1) = 0;
-
- // debugging cell marker functions
-
- //! add cell to mMarkedCells list
- void addCellToMarkedList( CellIdentifierInterface *cid );
- //! marked cell iteration methods
- CellIdentifierInterface* markedGetFirstCell( );
- CellIdentifierInterface* markedAdvanceCell();
- void markedClearList();
-
-#if PARALLEL==1
- void setNumOMPThreads(int num_threads);
-#endif // PARALLEL==1
- protected:
-
- /*! abort simulation on error... */
- bool mPanic;
-
-
- /*! Size of the array in x,y,z direction */
- int mSizex, mSizey, mSizez;
- /*! only fluid in sim? */
- bool mAllfluid;
-
-
- /*! step counter */
- int mStepCnt;
-
- /*! mass change from one step to the next, for extreme cases fix globally */
- LbmFloat mFixMass;
-
- // deprecated param vars
- /*! omega for lbm */
- LbmFloat mOmega;
- /*! gravity strength in neg. z direction */
- LbmVec mGravity;
- /*! Surface tension of the fluid */
- LbmFloat mSurfaceTension;
-
-
- /* boundary inits */
- CellFlagType mBoundaryEast, mBoundaryWest,
- mBoundaryNorth, mBoundarySouth,
- mBoundaryTop, mBoundaryBottom;
-
- /*! initialization from config file done? */
- int mInitDone;
-
- /*! init density gradient? */
- bool mInitDensityGradient;
-
- /*! pointer to the attribute list, only pointer to obj attrs */
- AttributeList *mpSifAttrs;
- AttributeList *mpSifSwsAttrs;
-
- /*! get parameters from this parametrize in finishInit */
- Parametrizer *mpParam;
- //! store particle tracer
- ParticleTracer *mpParticles;
-
- /*! number of particles lost so far */
- int mNumParticlesLost;
- /*! number of particles lost so far */
- int mNumInvalidDfs;
- /*! no of filled/emptied cells per time step */
- int mNumFilledCells, mNumEmptiedCells;
- /*! counter number of used cells for performance */
- int mNumUsedCells;
- /*! MLSUPS counter */
- LbmFloat mMLSUPS;
- /*! debug - velocity output scaling factor */
- LbmFloat mDebugVelScale;
- /*! string for node info debugging output */
- string mNodeInfoString;
-
- // geo init vars
- // TODO deprecate SimulationObject vars
-
- /*! for display - start and end vectors for geometry */
- ntlVec3Gfx mvGeoStart, mvGeoEnd;
- //! domain vertex trafos
- ntlMatrix4x4<gfxReal> *mpSimTrafo;
-
- /*! perform accurate geometry init? */
- bool mAccurateGeoinit;
-
- /*! name of this lbm object (for debug output) */
- string mName;
-
- //! Mcubes object for surface reconstruction
- IsoSurface *mpIso;
- /*! isolevel value for marching cubes surface reconstruction */
- LbmFloat mIsoValue;
-
- //! debug output?
- bool mSilent;
-
- /*! geometry init id, passed from ntl_geomclass */
- int mLbmInitId;
- /*! tree object for geomerty initialization */
- ntlTree *mpGiTree;
- /*! object vector for geo init */
- vector<ntlGeometryObject*> *mpGiObjects;
- /*! inside which objects? */
- vector<int> mGiObjInside;
- /*! inside which objects? */
- vector<gfxReal> mGiObjDistance;
- vector<gfxReal> mGiObjSecondDist;
- /*! remember globals */
- ntlRenderGlobals *mpGlob;
-
- //! use refinement/coarsening?
- int mRefinementDesired;
-
- //! output surface preview? if >0 yes, and use as reduzed size
- int mOutputSurfacePreview;
- LbmFloat mPreviewFactor;
-
- /*! enable surface and normals smoothing? */
- float mSmoothSurface;
- float mSmoothNormals;
- /*! isosurface subdivisions */
- int mIsoSubdivs;
-
- //! particle generation probability
- LbmFloat mPartGenProb;
-
- //! dump velocities?
- bool mDumpVelocities;
-
- // list for marked cells
- vector<CellIdentifierInterface *> mMarkedCells;
- int mMarkedCellIndex;
-
- //! domain boundary free/no slip type
- string mDomainBound;
- //! part slip value for domain
- LbmFloat mDomainPartSlipValue;
-
- // size of far field area
- LbmFloat mFarFieldSize;
- // amount of drop mass to subtract
- LbmFloat mPartDropMassSub;
- // use physical drop model for particles?
- bool mPartUsePhysModel;
-
- //! test vars
- // strength of applied force
- LbmFloat mTForceStrength;
- int mCppfStage;
-
- //! dumping modes
- bool mDumpRawText;
- bool mDumpRawBinary;
- bool mDumpRawBinaryZip;
-
-#if PARALLEL==1
- int mNumOMPThreads;
-#endif // PARALLEL==1
-
-private:
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("ELBEEM:LbmSolverInterface")
-#endif
-};
-
-
-// helper function to create consistent grid resolutions
-void initGridSizes(int &mSizex, int &mSizey, int &mSizez,
- ntlVec3Gfx &mvGeoStart, ntlVec3Gfx &mvGeoEnd,
- int mMaxRefine, bool parallel);
-// return the amount of memory required in total (reqret)
-// and for the finest grid only (reqretFine, can be NULL)
-void calculateMemreqEstimate(int resx,int resy,int resz, int refine,
- float farfieldsize, double *reqret, double *reqretFine, string *reqstr);
-
-//! helper function to convert flag to string (for debuggin)
-string convertCellFlagType2String( CellFlagType flag );
-string convertSingleFlag2String(CellFlagType cflag);
-
-#endif // LBMINTERFACE_H
diff --git a/intern/elbeem/intern/solver_main.cpp b/intern/elbeem/intern/solver_main.cpp
deleted file mode 100644
index 961bd44e08f..00000000000
--- a/intern/elbeem/intern/solver_main.cpp
+++ /dev/null
@@ -1,1723 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Standard LBM Factory implementation
- *
- *****************************************************************************/
-
-#include "solver_class.h"
-#include "solver_relax.h"
-#include "particletracer.h"
-#include "loop_tools.h"
-#include "globals.h"
-
-#include <stdlib.h>
-#include <cmath>
-
-using std::isfinite;
-
-/*****************************************************************************/
-/*! perform a single LBM step */
-/*****************************************************************************/
-
-double globdfcnt;
-double globdfavg[19];
-double globdfmax[19];
-double globdfmin[19];
-
-// simulation object interface
-void LbmFsgrSolver::step() {
- stepMain();
-}
-
-// lbm main step
-void messageOutputForce(string from);
-void LbmFsgrSolver::stepMain() {
- myTime_t timestart = getTime();
-
- initLevelOmegas();
- markedClearList(); // DMC clearMarkedCellsList
-
- // safety check, counter reset
- mNumUsedCells = 0;
- mNumInterdCells = 0;
- mNumInvIfCells = 0;
-
- //debugOutNnl("LbmFsgrSolver::step : "<<mStepCnt, 10);
- if(!mSilent){ debMsgStd("LbmFsgrSolver::step", DM_MSG, mName<<" cnt:"<<mStepCnt<<" t:"<<mSimulationTime, 10); }
- //debMsgDirect( "LbmFsgrSolver::step : "<<mStepCnt<<" ");
- //myTime_t timestart = 0;
- //if(mStartSymm) { checkSymmetry("step1"); } // DEBUG
-
- // time adapt
- mMaxVlen = mMxvz = mMxvy = mMxvx = 0.0;
-
- // init moving bc's, can change mMaxVlen
- initMovingObstacles(false);
-
- // handle fluid control
- handleCpdata();
-
- // important - keep for tadap
- LbmFloat lastMass = mCurrentMass;
- mCurrentMass = mFixMass; // reset here for next step
- mCurrentVolume = 0.0;
-
- //change to single step advance!
- int levsteps = 0;
- int dsbits = mStepCnt ^ (mStepCnt-1);
- //errMsg("S"," step:"<<mStepCnt<<" s-1:"<<(mStepCnt-1)<<" xf:"<<convertCellFlagType2String(dsbits));
- for(int lev=0; lev<=mMaxRefine; lev++) {
- //if(! (mStepCnt&(1<<lev)) ) {
- if( dsbits & (1<<(mMaxRefine-lev)) ) {
- //errMsg("S"," l"<<lev);
-
- if(lev==mMaxRefine) {
- // always advance fine level...
- fineAdvance();
- } else {
- adaptGrid(lev);
- coarseRestrictFromFine(lev);
- coarseAdvance(lev);
- }
-#if FSGR_OMEGA_DEBUG==1
- errMsg("LbmFsgrSolver::step","LES stats l="<<lev<<" omega="<<mLevel[lev].omega<<" avgOmega="<< (mLevel[lev].avgOmega/mLevel[lev].avgOmegaCnt) );
- mLevel[lev].avgOmega = 0.0; mLevel[lev].avgOmegaCnt = 0.0;
-#endif // FSGR_OMEGA_DEBUG==1
- levsteps++;
- }
- mCurrentMass += mLevel[lev].lmass;
- mCurrentVolume += mLevel[lev].lvolume;
- }
-
- // prepare next step
- mStepCnt++;
-
-
- // some dbugging output follows
- // calculate MLSUPS
- myTime_t timeend = getTime();
-
- mNumUsedCells += mNumInterdCells; // count both types for MLSUPS
- mAvgNumUsedCells += mNumUsedCells;
- mMLSUPS = ((double)mNumUsedCells / ((timeend-timestart)/(double)1000.0) ) / (1000000.0);
- if(mMLSUPS>10000){ mMLSUPS = -1; }
- //else { mAvgMLSUPS += mMLSUPS; mAvgMLSUPSCnt += 1.0; } // track average mlsups
-
- LbmFloat totMLSUPS = ( ((mLevel[mMaxRefine].lSizex-2)*(mLevel[mMaxRefine].lSizey-2)*(getForZMax1(mMaxRefine)-getForZMin1())) / ((timeend-timestart)/(double)1000.0) ) / (1000000);
- if(totMLSUPS>10000) totMLSUPS = -1;
- mNumInvIfTotal += mNumInvIfCells; // debug
-
- // do some formatting
- if(!mSilent){
- int avgcls = (int)(mAvgNumUsedCells/(LONGINT)mStepCnt);
- debMsgStd("LbmFsgrSolver::step", DM_MSG, mName<<" cnt:"<<mStepCnt<<" t:"<<mSimulationTime<<
- " cur-mlsups:"<<mMLSUPS<< //" avg:"<<(mAvgMLSUPS/mAvgMLSUPSCnt)<<"), "<<
- " totcls:"<<mNumUsedCells<< " avgcls:"<< avgcls<<
- " intd:"<<mNumInterdCells<< " invif:"<<mNumInvIfCells<<
- " invift:"<<mNumInvIfTotal<< " fsgrcs:"<<mNumFsgrChanges<<
- " filled:"<<mNumFilledCells<<", emptied:"<<mNumEmptiedCells<<
- " mMxv:"<<PRINT_VEC(mMxvx,mMxvy,mMxvz)<<", tscnts:"<<mTimeSwitchCounts<<
- //" RWmxv:"<<ntlVec3Gfx(mMxvx,mMxvy,mMxvz)*(mLevel[mMaxRefine].simCellSize / mLevel[mMaxRefine].timestep)<<" "<< /* realworld vel output */
- " probs:"<<mNumProblems<< " simt:"<<mSimulationTime<<
- " took:"<< getTimeString(timeend-timestart)<<
- " for '"<<mName<<"' " , 10);
- } else { debMsgDirect("."); }
-
- if(mStepCnt==1) {
- mMinNoCells = mMaxNoCells = mNumUsedCells;
- } else {
- if(mNumUsedCells>mMaxNoCells) mMaxNoCells = mNumUsedCells;
- if(mNumUsedCells<mMinNoCells) mMinNoCells = mNumUsedCells;
- }
-
- // mass scale test
- if((mMaxRefine>0)&&(mInitialMass>0.0)) {
- LbmFloat mscale = mInitialMass/mCurrentMass;
-
- mscale = 1.0;
- const LbmFloat dchh = 0.001;
- if(mCurrentMass<mInitialMass) mscale = 1.0+dchh;
- if(mCurrentMass>mInitialMass) mscale = 1.0-dchh;
-
- // use mass rescaling?
- // with float precision this seems to be nonsense...
- const bool MREnable = false;
-
- const int MSInter = 2;
- static int mscount = 0;
- if( (MREnable) && ((mLevel[0].lsteps%MSInter)== (MSInter-1)) && ( ABS( (mInitialMass/mCurrentMass)-1.0 ) > 0.01) && ( dsbits & (1<<(mMaxRefine-0)) ) ){
- // example: FORCE RESCALE MASS! ini:1843.5, cur:1817.6, f=1.01425 step:22153 levstep:5539 msc:37
- // mass rescale MASS RESCALE check
- errMsg("MDTDD","\n\n");
- errMsg("MDTDD","FORCE RESCALE MASS! "
- <<"ini:"<<mInitialMass<<", cur:"<<mCurrentMass<<", f="<<ABS(mInitialMass/mCurrentMass)
- <<" step:"<<mStepCnt<<" levstep:"<<mLevel[0].lsteps<<" msc:"<<mscount<<" "
- );
- errMsg("MDTDD","\n\n");
-
- mscount++;
- for(int lev=mMaxRefine; lev>=0 ; lev--) {
- //for(int workSet = 0; workSet<=1; workSet++) {
- int wss = 0;
- int wse = 1;
-#if COMPRESSGRIDS==1
- if(lev== mMaxRefine) wss = wse = mLevel[lev].setCurr;
-#endif // COMPRESSGRIDS==1
- for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT
-
- FSGR_FORIJK1(lev) {
- if( (RFLAG(lev,i,j,k, workSet) & (CFFluid| CFInter| CFGrFromCoarse| CFGrFromFine| CFGrNorm))
- ) {
-
- FORDF0 { QCELL(lev, i,j,k,workSet, l) *= mscale; }
- QCELL(lev, i,j,k,workSet, dMass) *= mscale;
- QCELL(lev, i,j,k,workSet, dFfrac) *= mscale;
-
- } else {
- continue;
- }
- }
- }
- mLevel[lev].lmass *= mscale;
- }
- }
-
- mCurrentMass *= mscale;
- }// if mass scale test */
- else {
- // use current mass after full step for initial setting
- if((mMaxRefine>0)&&(mInitialMass<=0.0) && (levsteps == (mMaxRefine+1))) {
- mInitialMass = mCurrentMass;
- debMsgStd("MDTDD",DM_NOTIFY,"Second Initial Mass Init: "<<mInitialMass, 2);
- }
- }
-
-#if LBM_INCLUDE_TESTSOLVERS==1
- if((mUseTestdata)&&(mInitDone)) { handleTestdata(); }
- mrExchange();
-#endif
-
- // advance positions with current grid
- advanceParticles();
- if(mpParticles) {
- mpParticles->checkDumpTextPositions(mSimulationTime);
- mpParticles->checkTrails(mSimulationTime);
- }
-
- // one of the last things to do - adapt timestep
- // was in fineAdvance before...
- if(mTimeAdap) {
- adaptTimestep();
- } // time adaptivity
-
-
-#ifndef WIN32
- // good indicator for instabilities
- if( (!isfinite(mMxvx)) || (!isfinite(mMxvy)) || (!isfinite(mMxvz)) ) { CAUSE_PANIC; }
- if( (!isfinite(mCurrentMass)) || (!isfinite(mCurrentVolume)) ) { CAUSE_PANIC; }
-#endif // WIN32
-
- // output total step time
- myTime_t timeend2 = getTime();
- double mdelta = (lastMass-mCurrentMass);
- if(ABS(mdelta)<1e-12) mdelta=0.;
- double effMLSUPS = ((double)mNumUsedCells / ((timeend2-timestart)/(double)1000.0) ) / (1000000.0);
- if(mInitDone) {
- if(effMLSUPS>10000){ effMLSUPS = -1; }
- else { mAvgMLSUPS += effMLSUPS; mAvgMLSUPSCnt += 1.0; } // track average mlsups
- }
-
- debMsgStd("LbmFsgrSolver::stepMain", DM_MSG, "mmpid:"<<glob_mpindex<<" step:"<<mStepCnt
- <<" dccd="<< mCurrentMass
- //<<",d"<<mdelta
- //<<",ds"<<(mCurrentMass-mObjectMassMovnd[1])
- //<<"/"<<mCurrentVolume<<"(fix="<<mFixMass<<",ini="<<mInitialMass<<"), "
- <<" effMLSUPS=("<< effMLSUPS
- <<",avg:"<<(mAvgMLSUPS/mAvgMLSUPSCnt)<<"), "
- <<" took totst:"<< getTimeString(timeend2-timestart), 3);
- // nicer output
- //debMsgDirect(std::endl);
- // */
-
- messageOutputForce("");
- //#endif // ELBEEM_PLUGIN!=1
-}
-
-#define NEWDEBCHECK(str) \
- if(!this->mPanic){ FSGR_FORIJK_BOUNDS(mMaxRefine) { \
- if(RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr)&(CFFluid|CFInter)) { \
- for(int l=0;l<dTotalNum;l++) { \
- if(!isfinite(QCELL(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr,l))) { errMsg("NNOFIN"," "<<str<<" at "<<PRINT_IJK<<" l"<<l<<" "); }\
- }/*for*/ \
- }/*if*/ \
- } }
-
-void LbmFsgrSolver::fineAdvance()
-{
- // do the real thing...
- //NEWDEBCHECK("t1");
- mainLoop( mMaxRefine );
- if(mUpdateFVHeight) {
- // warning assume -Y gravity...
- mFVHeight = mCurrentMass*mFVArea/((LbmFloat)(mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizez));
- if(mFVHeight<1.0) mFVHeight = 1.0;
- mpParam->setFluidVolumeHeight(mFVHeight);
- }
-
- // advance time before timestep change
- mSimulationTime += mpParam->getTimestep();
- // time adaptivity
- mpParam->setSimulationMaxSpeed( sqrt(mMaxVlen / 1.5) );
- //if(mStartSymm) { checkSymmetry("step2"); } // DEBUG
- if(!mSilent){ debMsgStd("fineAdvance",DM_NOTIFY," stepped from "<<mLevel[mMaxRefine].setCurr<<" to "<<mLevel[mMaxRefine].setOther<<" step"<< (mLevel[mMaxRefine].lsteps), 3 ); }
-
- // update other set
- mLevel[mMaxRefine].setOther = mLevel[mMaxRefine].setCurr;
- mLevel[mMaxRefine].setCurr ^= 1;
- mLevel[mMaxRefine].lsteps++;
-
- // flag init... (work on current set, to simplify flag checks)
- reinitFlags( mLevel[mMaxRefine].setCurr );
- if(!mSilent){ debMsgStd("fineAdvance",DM_NOTIFY," flags reinit on set "<< mLevel[mMaxRefine].setCurr, 3 ); }
-
- // DEBUG VEL CHECK
- if(0) {
- int lev = mMaxRefine;
- int workSet = mLevel[lev].setCurr;
- int mi=0,mj=0,mk=0;
- LbmFloat compRho=0.;
- LbmFloat compUx=0.;
- LbmFloat compUy=0.;
- LbmFloat compUz=0.;
- LbmFloat maxUlen=0.;
- LbmVec maxU(0.);
- LbmFloat maxRho=-100.;
- int ri=0,rj=0,rk=0;
-
- FSGR_FORIJK1(lev) {
- if( (RFLAG(lev,i,j,k, workSet) & (CFFluid| CFInter| CFGrFromCoarse| CFGrFromFine| CFGrNorm)) ) {
- compRho=QCELL(lev, i,j,k,workSet, dC);
- compUx = compUy = compUz = 0.0;
- for(int l=1; l<this->cDfNum; l++) {
- LbmFloat df = QCELL(lev, i,j,k,workSet, l);
- compRho += df;
- compUx += (this->dfDvecX[l]*df);
- compUy += (this->dfDvecY[l]*df);
- compUz += (this->dfDvecZ[l]*df);
- }
- LbmVec u(compUx,compUy,compUz);
- LbmFloat nu = norm(u);
- if(nu>maxUlen) {
- maxU = u;
- maxUlen = nu;
- mi=i; mj=j; mk=k;
- }
- if(compRho>maxRho) {
- maxRho=compRho;
- ri=i; rj=j; rk=k;
- }
- } else {
- continue;
- }
- }
-
- errMsg("MAXVELCHECK"," at "<<PRINT_VEC(mi,mj,mk)<<" norm:"<<maxUlen<<" u:"<<maxU);
- errMsg("MAXRHOCHECK"," at "<<PRINT_VEC(ri,rj,rk)<<" rho:"<<maxRho);
- printLbmCell(lev, 30,36,23, -1);
- } // DEBUG VEL CHECK
-
-}
-
-
-
-// fine step defines
-
-// access to own dfs during step (may be changed to local array)
-#define MYDF(l) RAC(ccel, l)
-
-// drop model definitions
-#define RWVEL_THRESH 1.5
-#define RWVEL_WINDTHRESH (RWVEL_THRESH*0.5)
-
-#if LBMDIM==3
-// normal
-#define SLOWDOWNREGION (mSizez/4)
-#else // LBMDIM==2
-// off
-#define SLOWDOWNREGION 10
-#endif // LBMDIM==2
-#define P_LCSMQO 0.01
-
-/*****************************************************************************/
-//! fine step function
-/*****************************************************************************/
-void
-LbmFsgrSolver::mainLoop(const int lev)
-{
- // loops over _only inner_ cells -----------------------------------------------------------------------------------
-
- // slow surf regions smooth (if below)
- const LbmFloat smoothStrength = 0.0; //0.01;
- const LbmFloat sssUsqrLimit = 1.5 * 0.03*0.03;
- const LbmFloat sssUsqrLimitInv = 1.0/sssUsqrLimit;
-
- const int cutMin = 1;
- const int cutConst = mCutoff+2;
-
-
-# if LBM_INCLUDE_TESTSOLVERS==1
- // 3d region off... quit
- if((mUseTestdata)&&(mpTest->mFarfMode>0)) { return; }
-# endif // ELBEEM_PLUGIN!=1
-
- // main loop region
- const bool doReduce = true;
- const int gridLoopBound=1;
- int calcNumInvIfCells = 0;
- LbmFloat calcInitialMass = 0;
- GRID_REGION_INIT();
-#if PARALLEL==1
- const int gDebugLevel = ::gDebugLevel;
-#pragma omp parallel num_threads(mNumOMPThreads) \
- reduction(+: \
- calcCurrentMass,calcCurrentVolume, \
- calcCellsFilled,calcCellsEmptied, \
- calcNumUsedCells,calcNumInvIfCells,calcInitialMass)
- GRID_REGION_START();
-#else // PARALLEL==1
- GRID_REGION_START();
-#endif // PARALLEL==1
-
- // local to main
- CellFlagType nbflag[LBM_DFNUM];
- int oldFlag, newFlag, nbored;
- LbmFloat m[LBM_DFNUM];
- LbmFloat rho, ux, uy, uz, tmp, usqr;
-
- // smago vars
- LbmFloat lcsmqadd, lcsmeq[LBM_DFNUM], lcsmomega;
-
- // ifempty cell conversion flags
- bool iffilled, ifemptied;
- LbmFloat nbfracs[LBM_DFNUM]; // ffracs of neighbors
- int recons[LBM_DFNUM]; // reconstruct this DF?
- int numRecons; // how many are reconstructed?
-
- LbmFloat mass=0., change=0., lcsmqo=0.;
- rho= ux= uy= uz= usqr= tmp= 0.;
- lcsmqadd = lcsmomega = 0.;
- FORDF0{ lcsmeq[l] = 0.; }
-
- // ---
- // now stream etc.
- // use //template functions for 2D/3D
-
- GRID_LOOP_START();
- // loop start
- // stream from current set to other, then collide and store
- //errMsg("l2"," at "<<PRINT_IJK<<" id"<<id);
-
-# if FSGR_STRICT_DEBUG==1
- // safety pointer check
- rho = ux = uy = uz = tmp = usqr = -100.0; // DEBUG
- if( (&RFLAG(lev, i,j,k,mLevel[lev].setCurr) != pFlagSrc) ||
- (&RFLAG(lev, i,j,k,mLevel[lev].setOther) != pFlagDst) ) {
- errMsg("LbmFsgrSolver::mainLoop","Err flagp "<<PRINT_IJK<<"="<<
- RFLAG(lev, i,j,k,mLevel[lev].setCurr)<<","<<RFLAG(lev, i,j,k,mLevel[lev].setOther)<<" but is "<<
- (*pFlagSrc)<<","<<(*pFlagDst) <<", pointers "<<
- (long)(&RFLAG(lev, i,j,k,mLevel[lev].setCurr))<<","<<(long)(&RFLAG(lev, i,j,k,mLevel[lev].setOther))<<" but is "<<
- (long)(pFlagSrc)<<","<<(long)(pFlagDst)<<" "
- );
- CAUSE_PANIC;
- }
- if( (&QCELL(lev, i,j,k,mLevel[lev].setCurr,0) != ccel) ||
- (&QCELL(lev, i,j,k,mLevel[lev].setOther,0) != tcel) ) {
- errMsg("LbmFsgrSolver::mainLoop","Err cellp "<<PRINT_IJK<<"="<<
- (long)(&QCELL(lev, i,j,k,mLevel[lev].setCurr,0))<<","<<(long)(&QCELL(lev, i,j,k,mLevel[lev].setOther,0))<<" but is "<<
- (long)(ccel)<<","<<(long)(tcel)<<" "
- );
- CAUSE_PANIC;
- }
-# endif
- oldFlag = *pFlagSrc;
-
- // old INTCFCOARSETEST==1
- if( (oldFlag & (CFGrFromCoarse)) ) {
- if(( mStepCnt & (1<<(mMaxRefine-lev)) ) ==1) {
- FORDF0 { RAC(tcel,l) = RAC(ccel,l); }
- } else {
- interpolateCellFromCoarse( lev, i,j,k, TSET(lev), 0.0, CFFluid|CFGrFromCoarse, false);
- calcNumUsedCells++;
- }
- continue; // interpolateFineFromCoarse test!
- } // interpolateFineFromCoarse test!
-
- if(oldFlag & (CFMbndInflow)) {
- // fluid & if are ok, fill if later on
- int isValid = oldFlag & (CFFluid|CFInter);
- const LbmFloat iniRho = 1.0;
- const int OId = oldFlag>>24;
- if(!isValid) {
- // make new if cell
- const LbmVec vel(mObjectSpeeds[OId]);
- // TODO add OPT3D treatment
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, iniRho,vel[0],vel[1],vel[2]); }
- RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho;
- RAC(tcel, dFlux) = FLUX_INIT;
- changeFlag(lev, i,j,k, TSET(lev), CFInter);
- calcCurrentMass += iniRho;
- calcCurrentVolume += 1.0;
- calcNumUsedCells++;
- calcInitialMass += iniRho;
- // dont treat cell until next step
- continue;
- }
- }
- else // these are exclusive
- if(oldFlag & (CFMbndOutflow)) {
- int isnotValid = oldFlag & (CFFluid);
- if(isnotValid) {
- // remove fluid cells, shouldnt be here anyway
- LbmFloat fluidRho = m[0]; FORDF1 { fluidRho += m[l]; }
- calcInitialMass -= fluidRho;
- const LbmFloat iniRho = 0.0;
- RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho;
- RAC(tcel, dFlux) = FLUX_INIT;
- changeFlag(lev, i,j,k, TSET(lev), CFInter);
-
- // same as ifemptied for if below
- LbmPoint oemptyp; oemptyp.flag = 0;
- oemptyp.x = i; oemptyp.y = j; oemptyp.z = k;
- LIST_EMPTY(oemptyp);
- calcCellsEmptied++;
- continue;
- }
- }
-
- if(oldFlag & (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)) {
- *pFlagDst = oldFlag;
- continue;
- }
- /*if( oldFlag & CFNoBndFluid ) { // TEST ME FASTER?
- OPTIMIZED_STREAMCOLLIDE; PERFORM_USQRMAXCHECK;
- RAC(tcel,dFfrac) = 1.0;
- *pFlagDst = (CellFlagType)oldFlag; // newFlag;
- calcCurrentMass += rho; calcCurrentVolume += 1.0;
- calcNumUsedCells++;
- continue;
- }// TEST ME FASTER? */
-
- // only neighbor flags! not own flag
- nbored = 0;
-
-#if OPT3D==0
- FORDF1 {
- nbflag[l] = RFLAG_NB(lev, i,j,k,SRCS(lev),l);
- nbored |= nbflag[l];
- }
-#else
- nbflag[dSB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dSB];
- nbflag[dWB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWB];
- nbflag[ dB] = *(pFlagSrc + (-mLevel[lev].lOffsy)); nbored |= nbflag[dB];
- nbflag[dEB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dEB];
- nbflag[dNB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNB];
-
- nbflag[dSW] = *(pFlagSrc + (-mLevel[lev].lOffsx+-1)); nbored |= nbflag[dSW];
- nbflag[ dS] = *(pFlagSrc + (-mLevel[lev].lOffsx)); nbored |= nbflag[dS];
- nbflag[dSE] = *(pFlagSrc + (-mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dSE];
-
- nbflag[ dW] = *(pFlagSrc + (-1)); nbored |= nbflag[dW];
- nbflag[ dE] = *(pFlagSrc + ( 1)); nbored |= nbflag[dE];
-
- nbflag[dNW] = *(pFlagSrc + ( mLevel[lev].lOffsx+-1)); nbored |= nbflag[dNW];
- nbflag[ dN] = *(pFlagSrc + ( mLevel[lev].lOffsx)); nbored |= nbflag[dN];
- nbflag[dNE] = *(pFlagSrc + ( mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dNE];
-
- nbflag[dST] = *(pFlagSrc + ( mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dST];
- nbflag[dWT] = *(pFlagSrc + ( mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWT];
- nbflag[ dT] = *(pFlagSrc + ( mLevel[lev].lOffsy)); nbored |= nbflag[dT];
- nbflag[dET] = *(pFlagSrc + ( mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dET];
- nbflag[dNT] = *(pFlagSrc + ( mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNT];
- // */
-#endif
-
- // pointer to destination cell
- calcNumUsedCells++;
-
- // FLUID cells
- if( oldFlag & CFFluid ) {
- // only standard fluid cells (with nothing except fluid as nbs
-
- if(oldFlag&CFMbndInflow) {
- // force velocity for inflow, necessary to have constant direction of flow
- // FIXME , test also set interface cells?
- const int OId = oldFlag>>24;
- //? DEFAULT_STREAM;
- //const LbmFloat fluidRho = 1.0;
- // for submerged inflows, streaming would have to be performed...
- LbmFloat fluidRho = m[0]; FORDF1 { fluidRho += m[l]; }
- const LbmVec vel(mObjectSpeeds[OId]);
- ux=vel[0], uy=vel[1], uz=vel[2];
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz);
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, fluidRho,ux,uy,uz); }
- rho = fluidRho;
- //errMsg("INFLOW_DEBUG","std at "<<PRINT_IJK<<" v="<<vel<<" rho="<<rho);
- } else {
- if(nbored&CFBnd) {
- DEFAULT_STREAM;
- //ux = [0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2];
- DEFAULT_COLLIDEG(mLevel[lev].gravity);
- oldFlag &= (~CFNoBndFluid);
- } else {
- // do standard stream/collide
- OPTIMIZED_STREAMCOLLIDE;
- oldFlag |= CFNoBndFluid;
- }
- }
-
- PERFORM_USQRMAXCHECK;
- // "normal" fluid cells
- RAC(tcel,dFfrac) = 1.0;
- *pFlagDst = (CellFlagType)oldFlag; // newFlag;
- calcCurrentMass += rho;
- calcCurrentVolume += 1.0;
- continue;
- }
-
- newFlag = oldFlag;
- // make sure here: always check which flags to really unset...!
- newFlag = newFlag & (~(
- CFNoNbFluid|CFNoNbEmpty| CFNoDelete
- | CFNoInterpolSrc
- | CFNoBndFluid
- ));
- if(!(nbored&CFBndNoslip)) { //NEWSURFT NEWSURFTNOS
- newFlag |= CFNoBndFluid;
- }
- /*if(!(nbored&CFBnd)) { //NEWSURFT NEWSURFTNOS
- // explicitly check for noslip neighbors
- bool hasnoslipnb = false;
- FORDF1 { if((nbflag[l]&CFBnd)&&(nbflag[l]&CFBndNoslip)) hasnoslipnb=true; }
- if(!hasnoslipnb) newFlag |= CFNoBndFluid;
- } // */
-
- // store own dfs and mass
- mass = RAC(ccel,dMass);
-
- // WARNING - only interface cells arrive here!
- // read distribution funtions of adjacent cells = stream step
- DEFAULT_STREAM;
-
- if((nbored & CFFluid)==0) { newFlag |= CFNoNbFluid; calcNumInvIfCells++; }
- if((nbored & CFEmpty)==0) { newFlag |= CFNoNbEmpty; calcNumInvIfCells++; }
-
- // calculate mass exchange for interface cells
- LbmFloat myfrac = RAC(ccel,dFfrac);
- if(myfrac<0.) myfrac=0.; // NEWSURFT
-# define nbdf(l) m[ this->dfInv[(l)] ]
-
- // update mass
- // only do boundaries for fluid cells, and interface cells without
- // any fluid neighbors (assume that interface cells _with_ fluid
- // neighbors are affected enough by these)
- // which Df's have to be reconstructed?
- // for fluid cells - just the f_i difference from streaming to empty cells ----
- numRecons = 0;
- bool onlyBndnb = ((!(oldFlag&CFNoBndFluid))&&(oldFlag&CFNoNbFluid)&&(nbored&CFBndNoslip));
- //onlyBndnb = false; // DEBUG test off
-
- FORDF1 { // dfl loop
- recons[l] = 0;
- nbfracs[l] = 0.0;
- // finally, "normal" interface cells ----
- if( nbflag[l]&(CFFluid|CFBnd) ) { // NEWTEST! FIXME check!!!!!!!!!!!!!!!!!!
- change = nbdf(l) - MYDF(l);
- }
- // interface cells - distuingish cells that shouldn't fill/empty
- else if( nbflag[l] & CFInter ) {
-
- LbmFloat mynbfac,nbnbfac;
- // NEW TEST t1
- // t2 -> off
- if((oldFlag&CFNoBndFluid)&&(nbflag[l]&CFNoBndFluid)) {
- mynbfac = QCELL_NB(lev, i,j,k,SRCS(lev),l, dFlux) / QCELL(lev, i,j,k,SRCS(lev), dFlux);
- nbnbfac = 1.0/mynbfac;
- onlyBndnb = false;
- } else {
- mynbfac = nbnbfac = 1.0; // switch calc flux off
- goto changeDefault; // NEWSURFT
- //change = 0.; goto changeDone; // NEWSURFT
- }
- //mynbfac = nbnbfac = 1.0; // switch calc flux off t3
-
- // perform interface case handling
- if ((oldFlag|nbflag[l])&(CFNoNbFluid|CFNoNbEmpty)) {
- switch (oldFlag&(CFNoNbFluid|CFNoNbEmpty)) {
- case 0:
- // we are a normal cell so...
- switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) {
- case CFNoNbFluid:
- // just fill current cell = empty neighbor
- change = nbnbfac*nbdf(l) ; goto changeDone;
- case CFNoNbEmpty:
- // just empty current cell = fill neighbor
- change = - mynbfac*MYDF(l) ; goto changeDone;
- }
- break;
-
- case CFNoNbFluid:
- // we dont have fluid nb's so...
- switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) {
- case 0:
- case CFNoNbEmpty:
- // we have no fluid nb's -> just empty
- change = - mynbfac*MYDF(l) ; goto changeDone;
- }
- break;
-
- case CFNoNbEmpty:
- // we dont have empty nb's so...
- switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) {
- case 0:
- case CFNoNbFluid:
- // we have no empty nb's -> just fill
- change = nbnbfac*nbdf(l); goto changeDone;
- }
- break;
- }} // inter-inter exchange
-
- changeDefault: ;
- // just do normal mass exchange...
- change = ( nbnbfac*nbdf(l) - mynbfac*MYDF(l) ) ;
- changeDone: ;
- nbfracs[l] = QCELL_NB(lev, i,j,k, SRCS(lev),l, dFfrac);
- if(nbfracs[l]<0.) nbfracs[l] = 0.; // NEWSURFT
- change *= (myfrac + nbfracs[l]) * 0.5;
- } // the other cell is interface
-
- // last alternative - reconstruction in this direction
- else {
- // empty + bnd case
- recons[l] = 1;
- numRecons++;
- change = 0.0;
- }
-
- // modify mass at SRCS
- mass += change;
- } // l
- // normal interface, no if empty/fluid
-
- // computenormal
- LbmFloat surfaceNormal[3];
- computeFluidSurfaceNormal(ccel,pFlagSrc, surfaceNormal);
-
- if( (ABS(surfaceNormal[0])+ABS(surfaceNormal[1])+ABS(surfaceNormal[2])) > LBM_EPSILON) {
- // normal ok and usable...
- FORDF1 {
- if( (this->dfDvecX[l]*surfaceNormal[0] + this->dfDvecY[l]*surfaceNormal[1] + this->dfDvecZ[l]*surfaceNormal[2]) // dot Dvec,norml
- > LBM_EPSILON) {
- recons[l] = 2;
- numRecons++;
- }
- }
- }
-
- // calculate macroscopic cell values
- LbmFloat oldUx, oldUy, oldUz;
- LbmFloat oldRho; // OLD rho = ccel->rho;
-# define REFERENCE_PRESSURE 1.0 // always atmosphere...
-# if OPT3D==0
- oldRho=RAC(ccel,0);
- oldUx = oldUy = oldUz = 0.0;
- for(int l=1; l<this->cDfNum; l++) {
- oldRho += RAC(ccel,l);
- oldUx += (this->dfDvecX[l]*RAC(ccel,l));
- oldUy += (this->dfDvecY[l]*RAC(ccel,l));
- oldUz += (this->dfDvecZ[l]*RAC(ccel,l));
- }
- // reconstruct dist funcs from empty cells
- FORDF1 {
- if(recons[ l ]) {
- m[ this->dfInv[l] ] =
- this->getCollideEq(l, REFERENCE_PRESSURE, oldUx,oldUy,oldUz) +
- this->getCollideEq(this->dfInv[l], REFERENCE_PRESSURE, oldUx,oldUy,oldUz)
- - MYDF( l );
- }
- }
- ux=oldUx, uy=oldUy, uz=oldUz; // no local vars, only for usqr
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); // needed later on
-# else // OPT3D==0
- oldRho = + RAC(ccel,dC) + RAC(ccel,dN )
- + RAC(ccel,dS ) + RAC(ccel,dE )
- + RAC(ccel,dW ) + RAC(ccel,dT )
- + RAC(ccel,dB ) + RAC(ccel,dNE)
- + RAC(ccel,dNW) + RAC(ccel,dSE)
- + RAC(ccel,dSW) + RAC(ccel,dNT)
- + RAC(ccel,dNB) + RAC(ccel,dST)
- + RAC(ccel,dSB) + RAC(ccel,dET)
- + RAC(ccel,dEB) + RAC(ccel,dWT)
- + RAC(ccel,dWB);
-
- oldUx = + RAC(ccel,dE) - RAC(ccel,dW)
- + RAC(ccel,dNE) - RAC(ccel,dNW)
- + RAC(ccel,dSE) - RAC(ccel,dSW)
- + RAC(ccel,dET) + RAC(ccel,dEB)
- - RAC(ccel,dWT) - RAC(ccel,dWB);
-
- oldUy = + RAC(ccel,dN) - RAC(ccel,dS)
- + RAC(ccel,dNE) + RAC(ccel,dNW)
- - RAC(ccel,dSE) - RAC(ccel,dSW)
- + RAC(ccel,dNT) + RAC(ccel,dNB)
- - RAC(ccel,dST) - RAC(ccel,dSB);
-
- oldUz = + RAC(ccel,dT) - RAC(ccel,dB)
- + RAC(ccel,dNT) - RAC(ccel,dNB)
- + RAC(ccel,dST) - RAC(ccel,dSB)
- + RAC(ccel,dET) - RAC(ccel,dEB)
- + RAC(ccel,dWT) - RAC(ccel,dWB);
-
- (void)oldRho;
-
- // now reconstruction
- ux=oldUx, uy=oldUy, uz=oldUz; // no local vars, only for usqr
- rho = REFERENCE_PRESSURE;
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); // needed later on
- if(recons[dN ]) { m[dS ] = EQN + EQS - MYDF(dN ); }
- if(recons[dS ]) { m[dN ] = EQS + EQN - MYDF(dS ); }
- if(recons[dE ]) { m[dW ] = EQE + EQW - MYDF(dE ); }
- if(recons[dW ]) { m[dE ] = EQW + EQE - MYDF(dW ); }
- if(recons[dT ]) { m[dB ] = EQT + EQB - MYDF(dT ); }
- if(recons[dB ]) { m[dT ] = EQB + EQT - MYDF(dB ); }
- if(recons[dNE]) { m[dSW] = EQNE + EQSW - MYDF(dNE); }
- if(recons[dNW]) { m[dSE] = EQNW + EQSE - MYDF(dNW); }
- if(recons[dSE]) { m[dNW] = EQSE + EQNW - MYDF(dSE); }
- if(recons[dSW]) { m[dNE] = EQSW + EQNE - MYDF(dSW); }
- if(recons[dNT]) { m[dSB] = EQNT + EQSB - MYDF(dNT); }
- if(recons[dNB]) { m[dST] = EQNB + EQST - MYDF(dNB); }
- if(recons[dST]) { m[dNB] = EQST + EQNB - MYDF(dST); }
- if(recons[dSB]) { m[dNT] = EQSB + EQNT - MYDF(dSB); }
- if(recons[dET]) { m[dWB] = EQET + EQWB - MYDF(dET); }
- if(recons[dEB]) { m[dWT] = EQEB + EQWT - MYDF(dEB); }
- if(recons[dWT]) { m[dEB] = EQWT + EQEB - MYDF(dWT); }
- if(recons[dWB]) { m[dET] = EQWB + EQET - MYDF(dWB); }
-# endif
-
-
- // inflow bc handling
- if(oldFlag & (CFMbndInflow)) {
- // fill if cells in inflow region
- if(myfrac<0.5) {
- mass += 0.25;
- calcInitialMass += 0.25;
- }
- const int OId = oldFlag>>24;
- const LbmVec vel(mObjectSpeeds[OId]);
- ux=vel[0], uy=vel[1], uz=vel[2];
- //? usqr = 1.5 * (ux*ux + uy*uy + uz*uz);
- //FORDF0 { RAC(tcel, l) = this->getCollideEq(l, fluidRho,ux,uy,uz); } rho = fluidRho;
- rho = REFERENCE_PRESSURE;
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, rho,ux,uy,uz); }
- //errMsg("INFLOW_DEBUG","if at "<<PRINT_IJK<<" v="<<vel<<" rho="<<rho);
- } else {
- // NEWSURFT, todo optimize!
- if(onlyBndnb) { //if(usqr<0.001*0.001) {
- rho = ux = uy = uz = 0.;
- FORDF0{
- rho += m[l];
- ux += (this->dfDvecX[l]*m[l]);
- uy += (this->dfDvecY[l]*m[l]);
- uz += (this->dfDvecZ[l]*m[l]);
- }
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, rho,ux,uy,uz); }
- } else {// NEWSURFT */
- if(usqr>0.3*0.3) {
- // force reset! , warning causes distortions...
- FORDF0 { RAC(tcel, l) = this->getCollideEq(l, rho,0.,0.,0.); }
- } else {
- // normal collide
- // mass streaming done... do normal collide
- LbmVec grav = mLevel[lev].gravity*mass;
- DEFAULT_COLLIDEG(grav);
- PERFORM_USQRMAXCHECK; }
- // rho init from default collide necessary for fill/empty check below
- } // test
- }
-
- // testing..., particle generation
- // also check oldFlag for CFNoNbFluid, test
- // for inflow no pargen test // NOBUBBB!
- if((mInitDone)
- // dont allow new if cells, or submerged ones
- && (!((oldFlag|newFlag)& (CFNoDelete|CFNoNbEmpty) ))
- // dont try to subtract from empty cells
- && (mass>0.) && (mPartGenProb>0.0)) {
- bool doAdd = true;
- bool bndOk=true;
- if( (i<cutMin)||(i>mSizex-cutMin)||
- (j<cutMin)||(j>mSizey-cutMin)||
- (k<cutMin)||(k>mSizez-cutMin) ) { bndOk=false; }
- if(!bndOk) doAdd=false;
-
- LbmFloat prob = (rand()/(RAND_MAX+1.0));
- LbmFloat basethresh = mPartGenProb*lcsmqo*(LbmFloat)(mSizez+mSizey+mSizex)*0.5*0.333;
-
- // physical drop model
- if(mPartUsePhysModel) {
- LbmFloat realWorldFac = (mLevel[lev].simCellSize / mLevel[lev].timestep);
- LbmVec ru(ux * realWorldFac, uy * realWorldFac, uz * realWorldFac);
- LbmFloat rl = norm(ru);
- basethresh *= rl;
-
- // reduce probability in outer region?
- const int pibord = mLevel[mMaxRefine].lSizex/2-cutConst;
- const int pjbord = mLevel[mMaxRefine].lSizey/2-cutConst;
- LbmFloat pifac = 1.-(LbmFloat)(ABS(i-pibord)) / (LbmFloat)(pibord);
- LbmFloat pjfac = 1.-(LbmFloat)(ABS(j-pjbord)) / (LbmFloat)(pjbord);
- if(pifac<0.) pifac=0.;
- if(pjfac<0.) pjfac=0.;
-
- //if( (prob< (basethresh*rl)) && (lcsmqo>0.0095) && (rl>RWVEL_THRESH) ) {
- if( (prob< (basethresh*rl*pifac*pjfac)) && (lcsmqo>0.0095) && (rl>RWVEL_THRESH) ) {
- // add
- } else {
- doAdd = false; // dont...
- }
-
- // "wind" disturbance
- // use realworld relative velocity here instead?
- if( (doAdd &&
- ((rl>RWVEL_WINDTHRESH) && (lcsmqo<P_LCSMQO)) )// normal checks
- ||(k>mSizez-SLOWDOWNREGION) ) {
- LbmFloat nuz = uz;
- if(k>mSizez-SLOWDOWNREGION) {
- // special case
- LbmFloat zfac = (LbmFloat)( k-(mSizez-SLOWDOWNREGION) );
- zfac /= (LbmFloat)(SLOWDOWNREGION);
- nuz += (1.0) * zfac; // check max speed? OFF?
- //errMsg("TOPT"," at "<<PRINT_IJK<<" zfac"<<zfac);
- } else {
- // normal probability
- //? LbmFloat fac = P_LCSMQO-lcsmqo;
- //? jdf *= fac;
- }
- FORDF1 {
- const LbmFloat jdf = 0.05 * (rand()/(RAND_MAX+1.0));
- // TODO use wind velocity?
- if(jdf>0.025) {
- const LbmFloat add = this->dfLength[l]*(-ux*this->dfDvecX[l]-uy*this->dfDvecY[l]-nuz*this->dfDvecZ[l])*jdf;
- RAC(tcel,l) += add; }
- }
- //errMsg("TOPDOWNCORR"," jdf:"<<jdf<<" rl"<<rl<<" vel "<<norm(LbmVec(ux,uy,nuz))<<" rwv"<<norm(LbmVec(rux,ruy,ruz)) );
- } // wind disturbance
- } // mPartUsePhysModel
- else {
- // empirical model
- //if((prob<basethresh) && (lcsmqo>0.0095)) { // add
- if((prob<basethresh) && (lcsmqo>0.012)) { // add
- } else { doAdd = false; }// dont...
- }
-
-
- // remove noise
- if(usqr<0.0001) doAdd=false; // TODO check!?
-
- // dont try to subtract from empty cells
- // ensure cell has enough mass for new drop
- LbmFloat newPartsize = 1.0;
- if(mPartUsePhysModel) {
- // 1-10
- newPartsize += 9.0* (rand()/(RAND_MAX+1.0));
- } else {
- // 1-5, overall size has to be less than
- // .62 (ca. 0.5) to make drops significantly smaller
- // than a full cell!
- newPartsize += 4.0* (rand()/(RAND_MAX+1.0));
- }
- LbmFloat dropmass = ParticleObject::getMass(mPartDropMassSub*newPartsize); //PARTMASS(mPartDropMassSub*newPartsize); // mass: 4/3 pi r^3 rho
- while(dropmass>mass) {
- newPartsize -= 0.2;
- dropmass = ParticleObject::getMass(mPartDropMassSub*newPartsize);
- }
- if(newPartsize<=1.) doAdd=false;
-
- if( (doAdd) ) { // init new particle
- for(int s=0; s<1; s++) { // one part!
- const LbmFloat posjitter = 0.05;
- const LbmFloat posjitteroffs = posjitter*-0.5;
- LbmFloat jpx = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0));
- LbmFloat jpy = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0));
- LbmFloat jpz = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0));
-
- const LbmFloat jitterstr = 1.0;
- const LbmFloat jitteroffs = jitterstr*-0.5;
- LbmFloat jx = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0));
- LbmFloat jy = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0));
- LbmFloat jz = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0));
-
- // average normal & velocity
- // -> mostly along velocity dir, many into surface
- // fluid velocity (not normalized!)
- LbmVec flvelVel(ux,uy,uz);
- LbmFloat flvelLen = norm(flvelVel);
- // surface normal
- LbmVec normVel(surfaceNormal[0],surfaceNormal[1],surfaceNormal[2]);
- normalize(normVel);
- LbmFloat normScale = (0.01+flvelLen);
- // jitter vector, 0.2 * flvel
- LbmVec jittVel(jx,jy,jz);
- jittVel *= (0.05+flvelLen)*0.1;
- // weighten velocities
- const LbmFloat flvelWeight = 0.9;
- LbmVec newpartVel = normVel*normScale*(1.-flvelWeight) + flvelVel*(flvelWeight) + jittVel;
-
- // offset towards surface (hide popping)
- jpx += -normVel[0]*0.4;
- jpy += -normVel[1]*0.4;
- jpz += -normVel[2]*0.4;
-
- LbmFloat srci=i+0.5+jpx, srcj=j+0.5+jpy, srck=k+0.5+jpz;
- int type=0;
- type = PART_DROP;
-
-# if LBMDIM==2
- newpartVel[2]=0.; srck=0.5;
-# endif // LBMDIM==2
- // subtract drop mass
- mass -= dropmass;
- // init new particle
- {
- ParticleObject np( ntlVec3Gfx(srci,srcj,srck) );
- np.setVel(newpartVel[0],newpartVel[1],newpartVel[2]);
- np.setStatus(PART_IN);
- np.setType(type);
- //if((s%3)==2) np.setType(PART_FLOAT);
- np.setSize(newPartsize);
- //errMsg("NEWPART"," at "<<PRINT_IJK<<" u="<<norm(LbmVec(ux,uy,uz)) <<" add"<<doAdd<<" pvel="<<norm(newpartVel)<<" size="<<newPartsize );
- //errMsg("NEWPT","u="<<newpartVel<<" norm="<<normVel<<" flvel="<<flvelVel<<" jitt="<<jittVel );
- FSGR_ADDPART(np);
- } // new part
- //errMsg("PIT","NEW pit"<<np.getId()<<" pos:"<< np.getPos()<<" status:"<<convertFlags2String(np.getFlags())<<" vel:"<< np.getVel() );
- } // multiple parts
- } // doAdd
- } // */
-
-
- // interface cell filled or emptied?
- iffilled = ifemptied = 0;
- // interface cells empty/full?, WARNING: to mark these cells, better do it at the end of reinitCellFlags
- // interface cell if full?
- if( (mass) >= (rho * (1.0+FSGR_MAGICNR)) ) { iffilled = 1; }
- // interface cell if empty?
- if( (mass) <= (rho * ( -FSGR_MAGICNR)) ) { ifemptied = 1; }
-
- if(oldFlag & (CFMbndOutflow)) {
- calcInitialMass -= mass;
- mass = myfrac = 0.0;
- iffilled = 0; ifemptied = 1;
- }
-
- // looks much nicer... LISTTRICK
-# if FSGR_LISTTRICK==1
- //if((oldFlag&CFNoNbEmpty)&&(newFlag&CFNoNbEmpty)) { TEST_IF_CHECK; }
- if(newFlag&CFNoBndFluid) { // test NEW TEST
- if(!iffilled) {
- // remove cells independent from amount of change...
- if( (oldFlag & CFNoNbEmpty)&&(newFlag & CFNoNbEmpty)&&
- ( (mass>(rho*FSGR_LISTTTHRESHFULL)) || ((nbored&CFInter)==0) )) {
- //if((nbored&CFInter)==0){ errMsg("NBORED!CFINTER","filled "<<PRINT_IJK); };
- iffilled = 1;
- }
- }
- if(!ifemptied) {
- if( (oldFlag & CFNoNbFluid)&&(newFlag & CFNoNbFluid)&&
- ( (mass<(rho*FSGR_LISTTTHRESHEMPTY)) || ((nbored&CFInter)==0) )) {
- //if((nbored&CFInter)==0){ errMsg("NBORED!CFINTER","emptied "<<PRINT_IJK); };
- ifemptied = 1;
- }
- }
- } // nobndfluid only */
-# endif
- //iffilled = ifemptied = 0; // DEBUG!!!!!!!!!!!!!!!
-
-
- // now that all dfs are known, handle last changes
- if(iffilled) {
- LbmPoint filledp; filledp.flag=0;
- if(!(newFlag&CFNoBndFluid)) filledp.flag |= 1; // NEWSURFT
- filledp.x = i; filledp.y = j; filledp.z = k;
- LIST_FULL(filledp);
- //mNumFilledCells++; // DEBUG
- calcCellsFilled++;
- }
- else if(ifemptied) {
- LbmPoint emptyp; emptyp.flag=0;
- if(!(newFlag&CFNoBndFluid)) emptyp.flag |= 1; // NEWSURFT
- emptyp.x = i; emptyp.y = j; emptyp.z = k;
- LIST_EMPTY(emptyp);
- //mNumEmptiedCells++; // DEBUG
- calcCellsEmptied++;
- }
- // dont cutoff values -> better cell conversions
- RAC(tcel,dFfrac) = (mass/rho);
-
- // init new flux value
- float flux = FLUX_INIT; // dxqn on
- if(newFlag&CFNoBndFluid) {
- //flux = 50.0; // extreme on
- for(int nn=1; nn<this->cDfNum; nn++) {
- if(nbflag[nn] & (CFFluid|CFInter|CFBnd)) { flux += this->dfLength[nn]; }
- }
- // optical hack - smooth slow moving
- // surface regions
- if(usqr< sssUsqrLimit) {
- for(int nn=1; nn<this->cDfNum; nn++) {
- if(nbfracs[nn]!=0.0) {
- LbmFloat curSmooth = (sssUsqrLimit-usqr)*sssUsqrLimitInv;
- if(curSmooth>1.0) curSmooth=1.0;
- flux *= (1.0+ smoothStrength*curSmooth * (nbfracs[nn]-myfrac)) ;
- }
- } }
- // NEW TEST */
- }
- // flux = FLUX_INIT; // calc flux off
- QCELL(lev, i,j,k,TSET(lev), dFlux) = flux; // */
-
- // perform mass exchange with streamed values
- QCELL(lev, i,j,k,TSET(lev), dMass) = mass; // MASST
- // set new flag
- *pFlagDst = (CellFlagType)newFlag;
- calcCurrentMass += mass;
- calcCurrentVolume += RAC(tcel,dFfrac);
-
- // interface cell handling done...
-
-#if PARALLEL!=1
- GRID_LOOPREG_END();
-#else // PARALLEL==1
-#include "paraloopend.h" // = GRID_LOOPREG_END();
-#endif // PARALLEL==1
-
- // write vars from computations to class
- mLevel[lev].lmass = calcCurrentMass;
- mLevel[lev].lvolume = calcCurrentVolume;
- mNumFilledCells = calcCellsFilled;
- mNumEmptiedCells = calcCellsEmptied;
- mNumUsedCells = calcNumUsedCells;
- mNumInvIfCells += calcNumInvIfCells;
- mInitialMass += calcInitialMass;
-}
-
-
-
-void
-LbmFsgrSolver::preinitGrids()
-{
- const int lev = mMaxRefine;
- const bool doReduce = false;
- const int gridLoopBound=0;
-
- // preinit both grids
- for(int s=0; s<2; s++) {
-
- GRID_REGION_INIT();
-#if PARALLEL==1
- const int gDebugLevel = ::gDebugLevel;
-#pragma omp parallel num_threads(mNumOMPThreads) \
- reduction(+: \
- calcCurrentMass,calcCurrentVolume, \
- calcCellsFilled,calcCellsEmptied, \
- calcNumUsedCells )
-#endif // PARALLEL==1
- GRID_REGION_START();
- GRID_LOOP_START();
- for(int l=0; l<dTotalNum; l++) { RAC(ccel,l) = 0.; }
- *pFlagSrc =0;
- *pFlagDst =0;
- //errMsg("l1"," at "<<PRINT_IJK<<" id"<<id);
-#if PARALLEL!=1
- GRID_LOOPREG_END();
-#else // PARALLEL==1
-#include "paraloopend.h" // = GRID_LOOPREG_END();
-#endif // PARALLEL==1
-
- /* dummy, remove warnings */
- calcCurrentMass = calcCurrentVolume = 0.;
- calcCellsFilled = calcCellsEmptied = calcNumUsedCells = 0;
-
- // change grid
- mLevel[mMaxRefine].setOther = mLevel[mMaxRefine].setCurr;
- mLevel[mMaxRefine].setCurr ^= 1;
- }
-}
-
-void
-LbmFsgrSolver::standingFluidPreinit()
-{
- const int lev = mMaxRefine;
- const bool doReduce = false;
- const int gridLoopBound=1;
-
- GRID_REGION_INIT();
-#if PARALLEL==1
- const int gDebugLevel = ::gDebugLevel;
-#pragma omp parallel num_threads(mNumOMPThreads) \
- reduction(+: \
- calcCurrentMass,calcCurrentVolume, \
- calcCellsFilled,calcCellsEmptied, \
- calcNumUsedCells )
-#endif // PARALLEL==1
- GRID_REGION_START();
-
- LbmFloat rho, ux,uy,uz, usqr;
- CellFlagType nbflag[LBM_DFNUM];
- LbmFloat m[LBM_DFNUM];
- LbmFloat lcsmqo;
-# if OPT3D==1
- LbmFloat lcsmqadd, lcsmeq[LBM_DFNUM], lcsmomega;
-# endif // OPT3D==true
-
- GRID_LOOP_START();
- //errMsg("l1"," at "<<PRINT_IJK<<" id"<<id);
- const CellFlagType currFlag = *pFlagSrc; //RFLAG(lev, i,j,k,workSet);
- if( (currFlag & (CFEmpty|CFBnd)) ) continue;
-
- if( (currFlag & (CFInter)) ) {
- // copy all values
- for(int l=0; l<dTotalNum;l++) { RAC(tcel,l) = RAC(ccel,l); }
- continue;
- }
-
- if( (currFlag & CFNoBndFluid)) {
- OPTIMIZED_STREAMCOLLIDE;
- } else {
- FORDF1 {
- nbflag[l] = RFLAG_NB(lev, i,j,k, SRCS(lev),l);
- }
- DEFAULT_STREAM;
- DEFAULT_COLLIDEG(mLevel[lev].gravity);
- }
- for(int l=LBM_DFNUM; l<dTotalNum;l++) { RAC(tcel,l) = RAC(ccel,l); }
-#if PARALLEL!=1
- GRID_LOOPREG_END();
-#else // PARALLEL==1
-#include "paraloopend.h" // = GRID_LOOPREG_END();
-#endif // PARALLEL==1
-
- /* dummy remove warnings */
- calcCurrentMass = calcCurrentVolume = 0.;
- calcCellsFilled = calcCellsEmptied = calcNumUsedCells = 0;
-
- // change grid
- mLevel[mMaxRefine].setOther = mLevel[mMaxRefine].setCurr;
- mLevel[mMaxRefine].setCurr ^= 1;
-}
-
-
-/******************************************************************************
- * work on lists from updateCellMass to reinit cell flags
- *****************************************************************************/
-
-LbmFloat LbmFsgrSolver::getMassdWeight(bool dirForw, int i,int j,int k,int workSet, int l) {
- //return 0.0; // test
- int level = mMaxRefine;
- LbmFloat *ccel = RACPNT(level, i,j,k, workSet);
-
- // computenormal
- CellFlagType *cflag = &RFLAG(level, i,j,k, workSet);
- LbmFloat n[3];
- computeFluidSurfaceNormal(ccel,cflag, n);
- LbmFloat scal = mDvecNrm[l][0]*n[0] + mDvecNrm[l][1]*n[1] + mDvecNrm[l][2]*n[2];
-
- LbmFloat ret = 1.0;
- // forward direction, add mass (for filling cells):
- if(dirForw) {
- if(scal<LBM_EPSILON) ret = 0.0;
- else ret = scal;
- } else {
- // backward for emptying
- if(scal>-LBM_EPSILON) ret = 0.0;
- else ret = scal * -1.0;
- }
- //errMsg("massd", PRINT_IJK<<" nv"<<nvel<<" : ret="<<ret ); //xit(1); //VECDEB
- return ret;
-}
-
-// warning - normal compuations are without
-// boundary checks &
-// normalization
-void LbmFsgrSolver::computeFluidSurfaceNormal(LbmFloat *ccel, CellFlagType *cflagpnt,LbmFloat *snret) {
- const int level = mMaxRefine;
- LbmFloat nx,ny,nz, nv1,nv2;
- const CellFlagType flagE = *(cflagpnt+1);
- const CellFlagType flagW = *(cflagpnt-1);
- if(flagE &(CFFluid|CFInter)){ nv1 = RAC((ccel+QCELLSTEP ),dFfrac); }
- else if(flagE &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagW &(CFFluid|CFInter)){ nv2 = RAC((ccel-QCELLSTEP ),dFfrac); }
- else if(flagW &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- nx = 0.5* (nv2-nv1);
-
- const CellFlagType flagN = *(cflagpnt+mLevel[level].lOffsx);
- const CellFlagType flagS = *(cflagpnt-mLevel[level].lOffsx);
- if(flagN &(CFFluid|CFInter)){ nv1 = RAC((ccel+(mLevel[level].lOffsx*QCELLSTEP)),dFfrac); }
- else if(flagN &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagS &(CFFluid|CFInter)){ nv2 = RAC((ccel-(mLevel[level].lOffsx*QCELLSTEP)),dFfrac); }
- else if(flagS &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- ny = 0.5* (nv2-nv1);
-
-#if LBMDIM==3
- const CellFlagType flagT = *(cflagpnt+mLevel[level].lOffsy);
- const CellFlagType flagB = *(cflagpnt-mLevel[level].lOffsy);
- if(flagT &(CFFluid|CFInter)){ nv1 = RAC((ccel+(mLevel[level].lOffsy*QCELLSTEP)),dFfrac); }
- else if(flagT &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagB &(CFFluid|CFInter)){ nv2 = RAC((ccel-(mLevel[level].lOffsy*QCELLSTEP)),dFfrac); }
- else if(flagB &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- nz = 0.5* (nv2-nv1);
-#else //LBMDIM==3
- nz = 0.0;
-#endif //LBMDIM==3
-
- // return vals
- snret[0]=nx; snret[1]=ny; snret[2]=nz;
-}
-void LbmFsgrSolver::computeFluidSurfaceNormalAcc(LbmFloat *ccel, CellFlagType *cflagpnt, LbmFloat *snret) {
- LbmFloat nx=0.,ny=0.,nz=0.;
- ccel = NULL; cflagpnt=NULL; // remove warning
- snret[0]=nx; snret[1]=ny; snret[2]=nz;
-}
-void LbmFsgrSolver::computeObstacleSurfaceNormal(LbmFloat *ccel, CellFlagType *cflagpnt, LbmFloat *snret) {
- const int level = mMaxRefine;
- LbmFloat nx,ny,nz, nv1,nv2;
- ccel = NULL; // remove warning
-
- const CellFlagType flagE = *(cflagpnt+1);
- const CellFlagType flagW = *(cflagpnt-1);
- if(flagE &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagW &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- nx = 0.5* (nv2-nv1);
-
- const CellFlagType flagN = *(cflagpnt+mLevel[level].lOffsx);
- const CellFlagType flagS = *(cflagpnt-mLevel[level].lOffsx);
- if(flagN &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagS &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- ny = 0.5* (nv2-nv1);
-
-#if LBMDIM==3
- const CellFlagType flagT = *(cflagpnt+mLevel[level].lOffsy);
- const CellFlagType flagB = *(cflagpnt-mLevel[level].lOffsy);
- if(flagT &(CFBnd)){ nv1 = 1.; }
- else nv1 = 0.0;
- if(flagB &(CFBnd)){ nv2 = 1.; }
- else nv2 = 0.0;
- nz = 0.5* (nv2-nv1);
-#else //LBMDIM==3
- nz = 0.0;
-#endif //LBMDIM==3
-
- // return vals
- snret[0]=nx; snret[1]=ny; snret[2]=nz;
-}
-void LbmFsgrSolver::computeObstacleSurfaceNormalAcc(int i,int j,int k, LbmFloat *snret) {
- bool nonorm = false;
- LbmFloat nx=0.,ny=0.,nz=0.;
- if(i<=0) { nx = 1.; nonorm = true; }
- if(i>=mSizex-1) { nx = -1.; nonorm = true; }
- if(j<=0) { ny = 1.; nonorm = true; }
- if(j>=mSizey-1) { ny = -1.; nonorm = true; }
-# if LBMDIM==3
- if(k<=0) { nz = 1.; nonorm = true; }
- if(k>=mSizez-1) { nz = -1.; nonorm = true; }
-# endif // LBMDIM==3
- if(!nonorm) {
- // in domain, revert to helper, use setCurr&mMaxRefine
- LbmVec bnormal;
- CellFlagType *bflag = &RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr);
- LbmFloat *bcell = RACPNT(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr);
- computeObstacleSurfaceNormal(bcell,bflag, &bnormal[0]);
- // TODO check if there is a normal near here?
- // use wider range otherwise...
- snret[0]=bnormal[0]; snret[1]=bnormal[0]; snret[2]=bnormal[0];
- return;
- }
- snret[0]=nx; snret[1]=ny; snret[2]=nz;
-}
-
-void LbmFsgrSolver::addToNewInterList( int ni, int nj, int nk ) {
-#if FSGR_STRICT_DEBUG==10
- // dangerous, this can change the simulation...
- /*for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
- iter != mListNewInter.end(); iter++ ) {
- if(ni!=iter->x) continue;
- if(nj!=iter->y) continue;
- if(nk!=iter->z) continue;
- // all 3 values match... skip point
- return;
- } */
-#endif // FSGR_STRICT_DEBUG==1
- // store point
- LbmPoint newinter; newinter.flag = 0;
- newinter.x = ni; newinter.y = nj; newinter.z = nk;
- mListNewInter.push_back(newinter);
-}
-
-void LbmFsgrSolver::reinitFlags( int workSet ) {
- // reinitCellFlags OLD mods:
- // add all to intel list?
- // check ffrac for new cells
- // new if cell inits (last loop)
- // vweights handling
-
- const int debugFlagreinit = 0;
-
- // some things need to be read/modified on the other set
- int otherSet = (workSet^1);
- // fixed level on which to perform
- int workLev = mMaxRefine;
-
- /* modify interface cells from lists */
- /* mark filled interface cells as fluid, or emptied as empty */
- /* count neighbors and distribute excess mass to interface neighbor cells
- * problems arise when there are no interface neighbors anymore
- * then just distribute to any fluid neighbors...
- */
-
- // for symmetry, first init all neighbor cells */
- for( vector<LbmPoint>::iterator iter=mListFull.begin();
- iter != mListFull.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- if(debugFlagreinit) errMsg("FULL", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) ); // DEBUG SYMM
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- //if((LBMDIM>2)&&( (ni<=0) || (nj<=0) || (nk<=0) || (ni>=mLevel[workLev].lSizex-1) || (nj>=mLevel[workLev].lSizey-1) || (nk>=mLevel[workLev].lSizez-1) )) {
- if( (ni<=0) || (nj<=0) ||
- (ni>=mLevel[workLev].lSizex-1) ||
- (nj>=mLevel[workLev].lSizey-1)
-# if LBMDIM==3
- || (nk<=0) || (nk>=mLevel[workLev].lSizez-1)
-# endif // LBMDIM==1
- ) {
- continue; } // new bc, dont treat cells on boundary NEWBC
- if( RFLAG(workLev, ni,nj,nk, workSet) & CFEmpty ){
-
- // preinit speed, get from average surrounding cells
- // interpolate from non-workset to workset, sets are handled in function
-
- // new and empty interface cell, dont change old flag here!
- addToNewInterList(ni,nj,nk);
-
- LbmFloat avgrho = 0.0;
- LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0;
- interpolateCellValues(workLev,ni,nj,nk,workSet, avgrho,avgux,avguy,avguz);
-
- // careful with l's...
- FORDF0M {
- QCELL(workLev,ni,nj,nk, workSet, m) = this->getCollideEq( m,avgrho, avgux, avguy, avguz );
- //QCELL(workLev,ni,nj,nk, workSet, l) = avgnbdf[l]; // CHECK FIXME test?
- }
- //errMsg("FNEW", PRINT_VEC(ni,nj,nk)<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<<avgrho<<" vel"<<PRINT_VEC(avgux,avguy,avguz) ); // DEBUG SYMM
- QCELL(workLev,ni,nj,nk, workSet, dMass) = 0.0; //?? new
- QCELL(workLev,ni,nj,nk, workSet, dFfrac) = 0.0; //?? new
- //RFLAG(workLev,ni,nj,nk,workSet) = (CellFlagType)(CFInter|CFNoInterpolSrc);
- changeFlag(workLev,ni,nj,nk,workSet, (CFInter|CFNoInterpolSrc));
- if(debugFlagreinit) errMsg("NEWE", PRINT_IJK<<" newif "<<PRINT_VEC(ni,nj,nk)<<" rho"<<avgrho<<" vel("<<avgux<<","<<avguy<<","<<avguz<<") " );
- }
- /* prevent surrounding interface cells from getting removed as empty cells
- * (also cells that are not newly inited) */
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
- //RFLAG(workLev,ni,nj,nk, workSet) = (CellFlagType)(RFLAG(workLev,ni,nj,nk, workSet) | CFNoDelete);
- changeFlag(workLev,ni,nj,nk, workSet, (RFLAG(workLev,ni,nj,nk, workSet) | CFNoDelete));
- // also add to list...
- addToNewInterList(ni,nj,nk);
- } // NEW?
- }
-
- // NEW? no extra loop...
- //RFLAG(workLev,i,j,k, workSet) = CFFluid;
- changeFlag(workLev,i,j,k, workSet,CFFluid);
- }
-
- /* remove empty interface cells that are not allowed to be removed anyway
- * this is important, otherwise the dreaded cell-type-flickering can occur! */
- for(int n=0; n<(int)mListEmpty.size(); n++) {
- int i=mListEmpty[n].x, j=mListEmpty[n].y, k=mListEmpty[n].z;
- if((RFLAG(workLev,i,j,k, workSet)&(CFInter|CFNoDelete)) == (CFInter|CFNoDelete)) {
- // treat as "new inter"
- addToNewInterList(i,j,k);
- // remove entry
- if(debugFlagreinit) errMsg("EMPT REMOVED!!!", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) ); // DEBUG SYMM
- if(n<(int)mListEmpty.size()-1) mListEmpty[n] = mListEmpty[mListEmpty.size()-1];
- mListEmpty.pop_back();
- n--;
- }
- }
-
-
- /* problems arise when adjacent cells empty&fill ->
- let fill cells+surrounding interface cells have the higher importance */
- for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
- iter != mListEmpty.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- if((RFLAG(workLev,i,j,k, workSet)&(CFInter|CFNoDelete)) == (CFInter|CFNoDelete)){ errMsg("A"," ARGHARGRAG "); } // DEBUG
- if(debugFlagreinit) errMsg("EMPT", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) );
-
- /* set surrounding fluid cells to interface cells */
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFFluid){
- // init fluid->interface
- //RFLAG(workLev,ni,nj,nk, workSet) = (CellFlagType)(CFInter);
- changeFlag(workLev,ni,nj,nk, workSet, CFInter);
- /* new mass = current density */
- LbmFloat nbrho = QCELL(workLev,ni,nj,nk, workSet, dC);
- for(int rl=1; rl< this->cDfNum ; ++rl) { nbrho += QCELL(workLev,ni,nj,nk, workSet, rl); }
- QCELL(workLev,ni,nj,nk, workSet, dMass) = nbrho;
- QCELL(workLev,ni,nj,nk, workSet, dFfrac) = 1.0;
-
- // store point
- addToNewInterList(ni,nj,nk);
- }
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter){
- // test, also add to list...
- addToNewInterList(ni,nj,nk);
- } // NEW?
- }
-
- /* for symmetry, set our flag right now */
- changeFlag(workLev,i,j,k, workSet, CFEmpty);
- // mark cell not be changed mass... - not necessary, not in list anymore anyway!
- } // emptylist
-
-
-
- // precompute weights to get rid of order dependancies
- vector<lbmFloatSet> vWeights;
- vWeights.resize( mListFull.size() + mListEmpty.size() );
- int weightIndex = 0;
- int nbCount = 0;
- LbmFloat nbWeights[LBM_DFNUM];
- LbmFloat nbTotWeights = 0.0;
- for( vector<LbmPoint>::iterator iter=mListFull.begin();
- iter != mListFull.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- nbCount = 0; nbTotWeights = 0.0;
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
- nbCount++;
- if(iter->flag&1) nbWeights[l] = 1.; // NEWSURFT
- else nbWeights[l] = getMassdWeight(1,i,j,k,workSet,l); // NEWSURFT
- nbTotWeights += nbWeights[l];
- } else {
- nbWeights[l] = -100.0; // DEBUG;
- }
- }
- if(nbCount>0) {
- //errMsg("FF I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeights);
- vWeights[weightIndex].val[0] = nbTotWeights;
- FORDF1 { vWeights[weightIndex].val[l] = nbWeights[l]; }
- vWeights[weightIndex].numNbs = (LbmFloat)nbCount;
- } else {
- vWeights[weightIndex].numNbs = 0.0;
- }
- weightIndex++;
- }
- for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
- iter != mListEmpty.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- nbCount = 0; nbTotWeights = 0.0;
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
- nbCount++;
- if(iter->flag&1) nbWeights[l] = 1.; // NEWSURFT
- else nbWeights[l] = getMassdWeight(0,i,j,k,workSet,l); // NEWSURFT
- nbTotWeights += nbWeights[l];
- } else {
- nbWeights[l] = -100.0; // DEBUG;
- }
- }
- if(nbCount>0) {
- //errMsg("EE I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeights);
- vWeights[weightIndex].val[0] = nbTotWeights;
- FORDF1 { vWeights[weightIndex].val[l] = nbWeights[l]; }
- vWeights[weightIndex].numNbs = (LbmFloat)nbCount;
- } else {
- vWeights[weightIndex].numNbs = 0.0;
- }
- weightIndex++;
- }
- weightIndex = 0;
-
-
- /* process full list entries, filled cells are done after this loop */
- for( vector<LbmPoint>::iterator iter=mListFull.begin();
- iter != mListFull.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
-
- LbmFloat myrho = QCELL(workLev,i,j,k, workSet, dC);
- FORDF1 { myrho += QCELL(workLev,i,j,k, workSet, l); } // QCELL.rho
-
- LbmFloat massChange = QCELL(workLev,i,j,k, workSet, dMass) - myrho;
- if(vWeights[weightIndex].numNbs>0.0) {
- const LbmFloat nbTotWeightsp = vWeights[weightIndex].val[0];
- //errMsg("FF I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeightsp);
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
- LbmFloat change = -1.0;
- if(nbTotWeightsp>0.0) {
- //change = massChange * ( nbWeights[l]/nbTotWeightsp );
- change = massChange * ( vWeights[weightIndex].val[l]/nbTotWeightsp );
- } else {
- change = (LbmFloat)(massChange/vWeights[weightIndex].numNbs);
- }
- QCELL(workLev,ni,nj,nk, workSet, dMass) += change;
- }
- }
- massChange = 0.0;
- } else {
- // Problem! no interface neighbors
- mFixMass += massChange;
- //TTT mNumProblems++;
- //errMsg(" FULL PROBLEM ", PRINT_IJK<<" "<<mFixMass);
- }
- weightIndex++;
-
- // already done? RFLAG(workLev,i,j,k, workSet) = CFFluid;
- QCELL(workLev,i,j,k, workSet, dMass) = myrho; // should be rho... but unused?
- QCELL(workLev,i,j,k, workSet, dFfrac) = 1.0; // should be rho... but unused?
- } // fulllist
-
-
- /* now, finally handle the empty cells - order is important, has to be after
- * full cell handling */
- for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
- iter != mListEmpty.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
-
- LbmFloat massChange = QCELL(workLev, i,j,k, workSet, dMass);
- if(vWeights[weightIndex].numNbs>0.0) {
- const LbmFloat nbTotWeightsp = vWeights[weightIndex].val[0];
- //errMsg("EE I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeightsp);
- FORDF1 {
- int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
- if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) {
- LbmFloat change = -1.0;
- if(nbTotWeightsp>0.0) {
- change = massChange * ( vWeights[weightIndex].val[l]/nbTotWeightsp );
- } else {
- change = (LbmFloat)(massChange/vWeights[weightIndex].numNbs);
- }
- QCELL(workLev, ni,nj,nk, workSet, dMass) += change;
- }
- }
- massChange = 0.0;
- } else {
- // Problem! no interface neighbors
- mFixMass += massChange;
- //TTT mNumProblems++;
- //errMsg(" EMPT PROBLEM ", PRINT_IJK<<" "<<mFixMass);
- }
- weightIndex++;
-
- // finally... make it empty
- // already done? RFLAG(workLev,i,j,k, workSet) = CFEmpty;
- QCELL(workLev,i,j,k, workSet, dMass) = 0.0;
- QCELL(workLev,i,j,k, workSet, dFfrac) = 0.0;
- }
- for( vector<LbmPoint>::iterator iter=mListEmpty.begin();
- iter != mListEmpty.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- changeFlag(workLev,i,j,k, otherSet, CFEmpty);
- }
-
-
- // check if some of the new interface cells can be removed again
- // never happens !!! not necessary
- // calculate ffrac for new IF cells NEW
-
- // how many are really new interface cells?
- int numNewIf = 0;
- for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
- iter != mListNewInter.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) {
- continue;
- // FIXME remove from list?
- }
- numNewIf++;
- }
-
- // redistribute mass, reinit flags
- if(debugFlagreinit) errMsg("NEWIF", "total:"<<mListNewInter.size());
- float newIfFac = 1.0/(LbmFloat)numNewIf;
- for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
- iter != mListNewInter.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- if((i<=0) || (j<=0) ||
- (i>=mLevel[workLev].lSizex-1) ||
- (j>=mLevel[workLev].lSizey-1) ||
- ((LBMDIM==3) && ((k<=0) || (k>=mLevel[workLev].lSizez-1) ) )
- ) {
- continue; } // new bc, dont treat cells on boundary NEWBC
- if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) {
- //errMsg("???"," "<<PRINT_IJK);
- continue;
- } // */
-
- QCELL(workLev,i,j,k, workSet, dMass) += (mFixMass * newIfFac);
-
- int nbored = 0;
- FORDF1 { nbored |= RFLAG_NB(workLev, i,j,k, workSet,l); }
- if(!(nbored & CFBndNoslip)) { RFLAG(workLev,i,j,k, workSet) |= CFNoBndFluid; }
- if(!(nbored & CFFluid)) { RFLAG(workLev,i,j,k, workSet) |= CFNoNbFluid; }
- if(!(nbored & CFEmpty)) { RFLAG(workLev,i,j,k, workSet) |= CFNoNbEmpty; }
-
- if(!(RFLAG(workLev,i,j,k, otherSet)&CFInter)) {
- RFLAG(workLev,i,j,k, workSet) = (CellFlagType)(RFLAG(workLev,i,j,k, workSet) | CFNoDelete);
- }
- if(debugFlagreinit) errMsg("NEWIF", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" f"<< convertCellFlagType2String(RFLAG(workLev,i,j,k, workSet))<<" wl"<<workLev );
- }
-
- // reinit fill fraction
- for( vector<LbmPoint>::iterator iter=mListNewInter.begin();
- iter != mListNewInter.end(); iter++ ) {
- int i=iter->x, j=iter->y, k=iter->z;
- if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { continue; }
-
- initInterfaceVars(workLev, i,j,k, workSet, false); //int level, int i,int j,int k,int workSet, bool initMass) {
- //LbmFloat nrho = 0.0;
- //FORDF0 { nrho += QCELL(workLev, i,j,k, workSet, l); }
- //QCELL(workLev,i,j,k, workSet, dFfrac) = QCELL(workLev,i,j,k, workSet, dMass)/nrho;
- //QCELL(workLev,i,j,k, workSet, dFlux) = FLUX_INIT;
- }
-
- if(mListNewInter.size()>0){
- //errMsg("FixMassDisted"," fm:"<<mFixMass<<" nif:"<<mListNewInter.size() );
- mFixMass = 0.0;
- }
-
- // empty lists for next step
- mListFull.clear();
- mListEmpty.clear();
- mListNewInter.clear();
-} // reinitFlags
-
-
-
diff --git a/intern/elbeem/intern/solver_relax.h b/intern/elbeem/intern/solver_relax.h
deleted file mode 100644
index d665025ba33..00000000000
--- a/intern/elbeem/intern/solver_relax.h
+++ /dev/null
@@ -1,1169 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - the visual lattice boltzmann freesurface simulator
- * All code distributed as part of El'Beem is covered by the version 2 of the
- * GNU General Public License. See the file COPYING for details.
- * Copyright 2003-2006 Nils Thuerey
- *
- * Combined 2D/3D Lattice Boltzmann relaxation macros
- *
- *****************************************************************************/
-
-#if FSGR_STRICT_DEBUG==1
-#define CAUSE_PANIC { this->mPanic=1; /* *((int*)(0x0)) = 1; crash*/ }
-#else // FSGR_STRICT_DEBUG==1
-#define CAUSE_PANIC { this->mPanic=1; } /*set flag*/
-#endif // FSGR_STRICT_DEBUG==1
-
-/******************************************************************************
- * normal relaxation
- *****************************************************************************/
-
-// standard arrays
-#define CSRC_C RAC(ccel , dC )
-#define CSRC_E RAC(ccel + (-1) *(dTotalNum), dE )
-#define CSRC_W RAC(ccel + (+1) *(dTotalNum), dW )
-#define CSRC_N RAC(ccel + (-mLevel[lev].lOffsx) *(dTotalNum), dN )
-#define CSRC_S RAC(ccel + (+mLevel[lev].lOffsx) *(dTotalNum), dS )
-#define CSRC_NE RAC(ccel + (-mLevel[lev].lOffsx-1) *(dTotalNum), dNE)
-#define CSRC_NW RAC(ccel + (-mLevel[lev].lOffsx+1) *(dTotalNum), dNW)
-#define CSRC_SE RAC(ccel + (+mLevel[lev].lOffsx-1) *(dTotalNum), dSE)
-#define CSRC_SW RAC(ccel + (+mLevel[lev].lOffsx+1) *(dTotalNum), dSW)
-#define CSRC_T RAC(ccel + (-mLevel[lev].lOffsy) *(dTotalNum), dT )
-#define CSRC_B RAC(ccel + (+mLevel[lev].lOffsy) *(dTotalNum), dB )
-#define CSRC_ET RAC(ccel + (-mLevel[lev].lOffsy-1) *(dTotalNum), dET)
-#define CSRC_EB RAC(ccel + (+mLevel[lev].lOffsy-1) *(dTotalNum), dEB)
-#define CSRC_WT RAC(ccel + (-mLevel[lev].lOffsy+1) *(dTotalNum), dWT)
-#define CSRC_WB RAC(ccel + (+mLevel[lev].lOffsy+1) *(dTotalNum), dWB)
-#define CSRC_NT RAC(ccel + (-mLevel[lev].lOffsy-mLevel[lev].lOffsx) *(dTotalNum), dNT)
-#define CSRC_NB RAC(ccel + (+mLevel[lev].lOffsy-mLevel[lev].lOffsx) *(dTotalNum), dNB)
-#define CSRC_ST RAC(ccel + (-mLevel[lev].lOffsy+mLevel[lev].lOffsx) *(dTotalNum), dST)
-#define CSRC_SB RAC(ccel + (+mLevel[lev].lOffsy+mLevel[lev].lOffsx) *(dTotalNum), dSB)
-
-#define XSRC_C(x) RAC(ccel + (x) *dTotalNum, dC )
-#define XSRC_E(x) RAC(ccel + ((x)-1) *dTotalNum, dE )
-#define XSRC_W(x) RAC(ccel + ((x)+1) *dTotalNum, dW )
-#define XSRC_N(x) RAC(ccel + ((x)-mLevel[lev].lOffsx) *dTotalNum, dN )
-#define XSRC_S(x) RAC(ccel + ((x)+mLevel[lev].lOffsx) *dTotalNum, dS )
-#define XSRC_NE(x) RAC(ccel + ((x)-mLevel[lev].lOffsx-1) *dTotalNum, dNE)
-#define XSRC_NW(x) RAC(ccel + ((x)-mLevel[lev].lOffsx+1) *dTotalNum, dNW)
-#define XSRC_SE(x) RAC(ccel + ((x)+mLevel[lev].lOffsx-1) *dTotalNum, dSE)
-#define XSRC_SW(x) RAC(ccel + ((x)+mLevel[lev].lOffsx+1) *dTotalNum, dSW)
-#define XSRC_T(x) RAC(ccel + ((x)-mLevel[lev].lOffsy) *dTotalNum, dT )
-#define XSRC_B(x) RAC(ccel + ((x)+mLevel[lev].lOffsy) *dTotalNum, dB )
-#define XSRC_ET(x) RAC(ccel + ((x)-mLevel[lev].lOffsy-1) *dTotalNum, dET)
-#define XSRC_EB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy-1) *dTotalNum, dEB)
-#define XSRC_WT(x) RAC(ccel + ((x)-mLevel[lev].lOffsy+1) *dTotalNum, dWT)
-#define XSRC_WB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy+1) *dTotalNum, dWB)
-#define XSRC_NT(x) RAC(ccel + ((x)-mLevel[lev].lOffsy-mLevel[lev].lOffsx) *dTotalNum, dNT)
-#define XSRC_NB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy-mLevel[lev].lOffsx) *dTotalNum, dNB)
-#define XSRC_ST(x) RAC(ccel + ((x)-mLevel[lev].lOffsy+mLevel[lev].lOffsx) *dTotalNum, dST)
-#define XSRC_SB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy+mLevel[lev].lOffsx) *dTotalNum, dSB)
-
-
-
-#define OMEGA(l) mLevel[(l)].omega
-
-#define EQC ( DFL1*(rho - usqr))
-#define EQN ( DFL2*(rho + uy*(4.5*uy + 3.0) - usqr))
-#define EQS ( DFL2*(rho + uy*(4.5*uy - 3.0) - usqr))
-#define EQE ( DFL2*(rho + ux*(4.5*ux + 3.0) - usqr))
-#define EQW ( DFL2*(rho + ux*(4.5*ux - 3.0) - usqr))
-#define EQT ( DFL2*(rho + uz*(4.5*uz + 3.0) - usqr))
-#define EQB ( DFL2*(rho + uz*(4.5*uz - 3.0) - usqr))
-
-#define EQNE ( DFL3*(rho + (+ux+uy)*(4.5*(+ux+uy) + 3.0) - usqr))
-#define EQNW ( DFL3*(rho + (-ux+uy)*(4.5*(-ux+uy) + 3.0) - usqr))
-#define EQSE ( DFL3*(rho + (+ux-uy)*(4.5*(+ux-uy) + 3.0) - usqr))
-#define EQSW ( DFL3*(rho + (-ux-uy)*(4.5*(-ux-uy) + 3.0) - usqr))
-#define EQNT ( DFL3*(rho + (+uy+uz)*(4.5*(+uy+uz) + 3.0) - usqr))
-#define EQNB ( DFL3*(rho + (+uy-uz)*(4.5*(+uy-uz) + 3.0) - usqr))
-#define EQST ( DFL3*(rho + (-uy+uz)*(4.5*(-uy+uz) + 3.0) - usqr))
-#define EQSB ( DFL3*(rho + (-uy-uz)*(4.5*(-uy-uz) + 3.0) - usqr))
-#define EQET ( DFL3*(rho + (+ux+uz)*(4.5*(+ux+uz) + 3.0) - usqr))
-#define EQEB ( DFL3*(rho + (+ux-uz)*(4.5*(+ux-uz) + 3.0) - usqr))
-#define EQWT ( DFL3*(rho + (-ux+uz)*(4.5*(-ux+uz) + 3.0) - usqr))
-#define EQWB ( DFL3*(rho + (-ux-uz)*(4.5*(-ux-uz) + 3.0) - usqr))
-
-
-// this is a bit ugly, but necessary for the CSRC_ access...
-#define MSRC_C m[dC ]
-#define MSRC_N m[dN ]
-#define MSRC_S m[dS ]
-#define MSRC_E m[dE ]
-#define MSRC_W m[dW ]
-#define MSRC_T m[dT ]
-#define MSRC_B m[dB ]
-#define MSRC_NE m[dNE]
-#define MSRC_NW m[dNW]
-#define MSRC_SE m[dSE]
-#define MSRC_SW m[dSW]
-#define MSRC_NT m[dNT]
-#define MSRC_NB m[dNB]
-#define MSRC_ST m[dST]
-#define MSRC_SB m[dSB]
-#define MSRC_ET m[dET]
-#define MSRC_EB m[dEB]
-#define MSRC_WT m[dWT]
-#define MSRC_WB m[dWB]
-
-// this is a bit ugly, but necessary for the ccel local access...
-#define CCEL_C RAC(ccel, dC )
-#define CCEL_N RAC(ccel, dN )
-#define CCEL_S RAC(ccel, dS )
-#define CCEL_E RAC(ccel, dE )
-#define CCEL_W RAC(ccel, dW )
-#define CCEL_T RAC(ccel, dT )
-#define CCEL_B RAC(ccel, dB )
-#define CCEL_NE RAC(ccel, dNE)
-#define CCEL_NW RAC(ccel, dNW)
-#define CCEL_SE RAC(ccel, dSE)
-#define CCEL_SW RAC(ccel, dSW)
-#define CCEL_NT RAC(ccel, dNT)
-#define CCEL_NB RAC(ccel, dNB)
-#define CCEL_ST RAC(ccel, dST)
-#define CCEL_SB RAC(ccel, dSB)
-#define CCEL_ET RAC(ccel, dET)
-#define CCEL_EB RAC(ccel, dEB)
-#define CCEL_WT RAC(ccel, dWT)
-#define CCEL_WB RAC(ccel, dWB)
-// for coarse to fine interpol access
-#define CCELG_C(f) (RAC(ccel, dC )*mGaussw[(f)])
-#define CCELG_N(f) (RAC(ccel, dN )*mGaussw[(f)])
-#define CCELG_S(f) (RAC(ccel, dS )*mGaussw[(f)])
-#define CCELG_E(f) (RAC(ccel, dE )*mGaussw[(f)])
-#define CCELG_W(f) (RAC(ccel, dW )*mGaussw[(f)])
-#define CCELG_T(f) (RAC(ccel, dT )*mGaussw[(f)])
-#define CCELG_B(f) (RAC(ccel, dB )*mGaussw[(f)])
-#define CCELG_NE(f) (RAC(ccel, dNE)*mGaussw[(f)])
-#define CCELG_NW(f) (RAC(ccel, dNW)*mGaussw[(f)])
-#define CCELG_SE(f) (RAC(ccel, dSE)*mGaussw[(f)])
-#define CCELG_SW(f) (RAC(ccel, dSW)*mGaussw[(f)])
-#define CCELG_NT(f) (RAC(ccel, dNT)*mGaussw[(f)])
-#define CCELG_NB(f) (RAC(ccel, dNB)*mGaussw[(f)])
-#define CCELG_ST(f) (RAC(ccel, dST)*mGaussw[(f)])
-#define CCELG_SB(f) (RAC(ccel, dSB)*mGaussw[(f)])
-#define CCELG_ET(f) (RAC(ccel, dET)*mGaussw[(f)])
-#define CCELG_EB(f) (RAC(ccel, dEB)*mGaussw[(f)])
-#define CCELG_WT(f) (RAC(ccel, dWT)*mGaussw[(f)])
-#define CCELG_WB(f) (RAC(ccel, dWB)*mGaussw[(f)])
-
-
-#if PARALLEL==1
-#define CSMOMEGA_STATS(dlev, domega)
-#else // PARALLEL==1
-#if FSGR_OMEGA_DEBUG==1
-#define CSMOMEGA_STATS(dlev, domega) \
- mLevel[dlev].avgOmega += domega; mLevel[dlev].avgOmegaCnt+=1.0;
-#else // FSGR_OMEGA_DEBUG==1
-#define CSMOMEGA_STATS(dlev, domega)
-#endif // FSGR_OMEGA_DEBUG==1
-#endif // PARALLEL==1
-
-
-// used for main loops and grav init
-// source set
-#define SRCS(l) mLevel[(l)].setCurr
-// target set
-#define TSET(l) mLevel[(l)].setOther
-
-// handle mov. obj
-#if FSGR_STRICT_DEBUG==1
-
-#define LBMDS_ADDMOV(linv,l) \
- \
- if((nbflag[linv]&CFBndMoving)&&(!(nbflag[l]&CFBnd))){ \
- \
- LbmFloat dte=QCELL_NBINV(lev, i, j, k, SRCS(lev), l,dFlux)-(mSimulationTime+this->mpParam->getTimestep()); \
- if( ABS(dte)< 1e-15 ) { \
- m[l]+=QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l); \
- } else { \
- const int sdx = i+this->dfVecX[linv], sdy = j+this->dfVecY[linv], sdz = k+this->dfVecZ[linv]; \
- \
- errMsg("INVALID_MOV_OBJ_TIME"," at "<<PRINT_IJK<<" from l"<<l<<" "<<PRINT_VEC(sdx,sdy,sdz)<<" t="<<(mSimulationTime+this->mpParam->getTimestep())<<" ct="<<QCELL_NBINV(lev, i, j, k, SRCS(lev), l,dFlux)<<" dte="<<dte); \
- debugMarkCell(lev,sdx,sdy,sdz); \
- } \
- } \
-
-
-
-#else // FSGR_STRICT_DEBUG==1
-
-#define LBMDS_ADDMOV(linv,l) \
- \
- \
- if((nbflag[linv]&CFBndMoving)&&(!(nbflag[l]&CFBnd))){ \
- \
- m[l]+=QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l); \
- } \
-
-
-
-#endif // !FSGR_STRICT_DEBUG==1
-
-// treatment of freeslip reflection
-// used both for OPT and nonOPT
-#define DEFAULT_STREAM_FREESLIP(l,invl,mnbf) \
- \
- int nb1 = 0, nb2 = 0; \
- LbmFloat newval = 0.0; \
- const int dx = this->dfVecX[invl], dy = this->dfVecY[invl], dz = this->dfVecZ[invl]; \
- \
- \
- \
- const LbmFloat movadd = ( \
- ((nbflag[invl]&CFBndMoving)&&(!(nbflag[l]&CFBnd))) ? \
- (QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l)) : 0.); \
- \
- if(dz==0) { \
- nb1 = !(RFLAG(lev, i, j+dy,k, SRCS(lev))&(CFFluid|CFInter)); \
- nb2 = !(RFLAG(lev, i+dx,j, k, SRCS(lev))&(CFFluid|CFInter)); \
- if((nb1)&&(!nb2)) { \
- \
- newval = QCELL(lev, i+dx,j,k,SRCS(lev), this->dfRefX[l]); \
- } else \
- if((!nb1)&&(nb2)) { \
- \
- newval = QCELL(lev, i,j+dy,k,SRCS(lev), this->dfRefY[l]); \
- } else { \
- \
- newval = RAC(ccel, this->dfInv[l] ) +movadd /* */; \
- } \
- } else \
- if(dy==0) { \
- nb1 = !(RFLAG(lev, i,j,k+dz, SRCS(lev))&(CFFluid|CFInter)); \
- nb2 = !(RFLAG(lev, i+dx,j,k, SRCS(lev))&(CFFluid|CFInter)); \
- if((nb1)&&(!nb2)) { \
- \
- newval = QCELL(lev, i+dx,j,k,SRCS(lev), this->dfRefX[l]); \
- } else \
- if((!nb1)&&(nb2)) { \
- \
- newval = QCELL(lev, i,j,k+dz,SRCS(lev), this->dfRefZ[l]); \
- } else { \
- \
- newval = RAC(ccel, this->dfInv[l] ) +movadd /* */; \
- } \
- \
- } else \
- \
- { \
- \
- nb1 = !(RFLAG(lev, i,j,k+dz, SRCS(lev))&(CFFluid|CFInter)); \
- nb2 = !(RFLAG(lev, i,j+dy,k, SRCS(lev))&(CFFluid|CFInter)); \
- if((nb1)&&(!nb2)) { \
- \
- newval = QCELL(lev, i,j+dy,k,SRCS(lev), this->dfRefY[l]); \
- } else \
- if((!nb1)&&(nb2)) { \
- \
- newval = QCELL(lev, i,j,k+dz,SRCS(lev), this->dfRefZ[l]); \
- } else { \
- \
- newval = RAC(ccel, this->dfInv[l] ) +movadd /* */; \
- } \
- } \
- \
- if(mnbf & CFBndPartslip) { \
- const LbmFloat partv = mObjectPartslips[(int)(mnbf>>24)]; \
- \
- m[l] = (RAC(ccel, this->dfInv[l] ) +movadd /* d *(1./1.) */ ) * partv + newval * (1.0-partv); \
- } else { \
- m[l] = newval; \
- } \
- \
-
-
-
-
-// complete default stream&collide, 2d/3d
-/* read distribution funtions of adjacent cells = sweep step */
-#if OPT3D==0
-
-#if FSGR_STRICT_DEBUG==1
-#define MARKCELLCHECK \
- debugMarkCell(lev,i,j,k); CAUSE_PANIC;
-#define STREAMCHECK(id,ni,nj,nk,nl) \
- if((!(m[nl] > -1.0) && (m[nl]<1.0)) ) {\
- errMsg("STREAMCHECK","ID"<<id<<" Invalid streamed DF nl"<<nl<<" value:"<<m[nl]<<" at "<<PRINT_IJK<<" from "<<PRINT_VEC(ni,nj,nk)<<" nl"<<(nl)<<\
- " nfc"<< RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr)<<" nfo"<< RFLAG(lev, ni,nj,nk, mLevel[lev].setOther) ); \
- /*FORDF0{ errMsg("STREAMCHECK"," at "<<PRINT_IJK<<" df "<<l<<"="<<m[l] ); } */ \
- MARKCELLCHECK; \
- m[nl] = dfEquil[nl]; /* REPAIR */ \
- }
-#define COLLCHECK \
- if( (rho>2.0) || (rho<-1.0) || (ABS(ux)>1.0) || (ABS(uy)>1.0) |(ABS(uz)>1.0) ) {\
- errMsg("COLLCHECK","Invalid collision values r:"<<rho<<" u:"PRINT_VEC(ux,uy,uz)<<" at? "<<PRINT_IJK ); \
- /*FORDF0{ errMsg("COLLCHECK"," at? "<<PRINT_IJK<<" df "<<l<<"="<<m[l] ); }*/ \
- rho=ux=uy=uz= 0.; /* REPAIR */ \
- MARKCELLCHECK; \
- }
-#else
-#define STREAMCHECK(id, ni,nj,nk,nl)
-#define COLLCHECK
-#endif
-
-// careful ux,uy,uz need to be inited before!
-#define DEFAULT_STREAM \
- m[dC] = RAC(ccel,dC); \
- STREAMCHECK(1, i,j,k, dC); \
- FORDF1 { \
- CellFlagType nbf = nbflag[ this->dfInv[l] ]; \
- if(nbf & CFBnd) { \
- if(nbf & CFBndNoslip) { \
- \
- m[l] = RAC(ccel, this->dfInv[l] ); \
- LBMDS_ADDMOV(this->dfInv[l],l); \
- STREAMCHECK(2, i,j,k, l); \
- } else if(nbf & (CFBndFreeslip|CFBndPartslip)) { \
- \
- if(l<=LBMDIM*2) { \
- m[l] = RAC(ccel, this->dfInv[l] ); STREAMCHECK(3, i,j,k, l); \
- LBMDS_ADDMOV(this->dfInv[l],l); \
- } else { \
- const int inv_l = this->dfInv[l]; \
- DEFAULT_STREAM_FREESLIP(l,inv_l,nbf); \
- } \
- \
- } \
- else { \
- errMsg("LbmFsgrSolver","Invalid Bnd type at "<<PRINT_IJK<<" f"<<convertCellFlagType2String(nbf)<<",nbdir"<<this->dfInv[l] ); \
- } \
- } else { \
- m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l); \
- if(RFLAG(lev, i,j,k, mLevel[lev].setCurr)&CFFluid) { \
- if(!(nbf&(CFFluid|CFInter)) ) { \
- int ni=i+this->dfVecX[this->dfInv[l]], nj=j+this->dfVecY[this->dfInv[l]], nk=k+this->dfVecZ[this->dfInv[l]]; \
- errMsg("STREAMCHECK"," Invalid nbflag, streamed DF l"<<l<<" value:"<<m[l]<<" at "<<PRINT_IJK<<" from "<< \
- PRINT_VEC(ni,nj,nk) <<" l"<<(l)<< \
- " nfc"<< RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr)<<" nfo"<< RFLAG(lev, ni,nj,nk, mLevel[lev].setOther) ); \
- \
- \
- } } \
- STREAMCHECK(4, i+this->dfVecX[this->dfInv[l]], j+this->dfVecY[this->dfInv[l]],k+this->dfVecZ[this->dfInv[l]], l); \
- } \
- } \
-
-
-
-
-// careful ux,uy,uz need to be inited before!
-#define DEFAULT_COLLIDEG(grav) \
- this->collideArrays(lev, i,j,k, m, rho,ux,uy,uz, OMEGA(lev), grav, mLevel[lev].lcsmago, &mDebugOmegaRet, &lcsmqo ); \
- CSMOMEGA_STATS(lev,mDebugOmegaRet); \
- FORDF0 { RAC(tcel,l) = m[l]; } \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- COLLCHECK; \
-
-
-
-#define OPTIMIZED_STREAMCOLLIDE \
- m[0] = RAC(ccel,0); \
- FORDF1 { \
- \
- if(RFLAG_NBINV(lev, i,j,k,SRCS(lev),l)&CFBnd) { errMsg("???", "bnd-err-nobndfl"); CAUSE_PANIC; \
- } else { m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l, l); } \
- STREAMCHECK(8, i+this->dfVecX[this->dfInv[l]], j+this->dfVecY[this->dfInv[l]],k+this->dfVecZ[this->dfInv[l]], l); \
- } \
- rho=m[0]; \
- DEFAULT_COLLIDEG(mLevel[lev].gravity) \
-
-
-
-#define OPTIMIZED_STREAMCOLLIDE___UNUSED \
- \
- this->collideArrays(lev, i,j,k, m, rho,ux,uy,uz, OMEGA(lev), mLevel[lev].gravity, mLevel[lev].lcsmago , &mDebugOmegaRet, &lcsmqo ); \
- CSMOMEGA_STATS(lev,mDebugOmegaRet); \
- FORDF0 { RAC(tcel,l) = m[l]; } \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- COLLCHECK; \
-
-
-
-#else // 3D, opt OPT3D==true
-
-
-// default stream opt3d add moving bc val
-#define DEFAULT_STREAM \
- m[dC] = RAC(ccel,dC); \
- \
- if(0 /* ((!nbored) & CFBnd) */) { \
- \
- m[dN ] = CSRC_N ; m[dS ] = CSRC_S ; \
- m[dE ] = CSRC_E ; m[dW ] = CSRC_W ; \
- m[dT ] = CSRC_T ; m[dB ] = CSRC_B ; \
- m[dNE] = CSRC_NE; m[dNW] = CSRC_NW; m[dSE] = CSRC_SE; m[dSW] = CSRC_SW; \
- m[dNT] = CSRC_NT; m[dNB] = CSRC_NB; m[dST] = CSRC_ST; m[dSB] = CSRC_SB; \
- m[dET] = CSRC_ET; m[dEB] = CSRC_EB; m[dWT] = CSRC_WT; m[dWB] = CSRC_WB; \
- } else { \
- \
- if(nbflag[dS ]&CFBnd) { m[dN ] = RAC(ccel,dS ); LBMDS_ADDMOV(dS ,dN ); } else { m[dN ] = CSRC_N ; } \
- if(nbflag[dN ]&CFBnd) { m[dS ] = RAC(ccel,dN ); LBMDS_ADDMOV(dN ,dS ); } else { m[dS ] = CSRC_S ; } \
- if(nbflag[dW ]&CFBnd) { m[dE ] = RAC(ccel,dW ); LBMDS_ADDMOV(dW ,dE ); } else { m[dE ] = CSRC_E ; } \
- if(nbflag[dE ]&CFBnd) { m[dW ] = RAC(ccel,dE ); LBMDS_ADDMOV(dE ,dW ); } else { m[dW ] = CSRC_W ; } \
- if(nbflag[dB ]&CFBnd) { m[dT ] = RAC(ccel,dB ); LBMDS_ADDMOV(dB ,dT ); } else { m[dT ] = CSRC_T ; } \
- if(nbflag[dT ]&CFBnd) { m[dB ] = RAC(ccel,dT ); LBMDS_ADDMOV(dT ,dB ); } else { m[dB ] = CSRC_B ; } \
- \
- \
- if(nbflag[dSW]&CFBnd) { if(nbflag[dSW]&CFBndNoslip){ m[dNE] = RAC(ccel,dSW); LBMDS_ADDMOV(dSW,dNE); }else{ DEFAULT_STREAM_FREESLIP(dNE,dSW,nbflag[dSW]);} } else { m[dNE] = CSRC_NE; } \
- if(nbflag[dSE]&CFBnd) { if(nbflag[dSE]&CFBndNoslip){ m[dNW] = RAC(ccel,dSE); LBMDS_ADDMOV(dSE,dNW); }else{ DEFAULT_STREAM_FREESLIP(dNW,dSE,nbflag[dSE]);} } else { m[dNW] = CSRC_NW; } \
- if(nbflag[dNW]&CFBnd) { if(nbflag[dNW]&CFBndNoslip){ m[dSE] = RAC(ccel,dNW); LBMDS_ADDMOV(dNW,dSE); }else{ DEFAULT_STREAM_FREESLIP(dSE,dNW,nbflag[dNW]);} } else { m[dSE] = CSRC_SE; } \
- if(nbflag[dNE]&CFBnd) { if(nbflag[dNE]&CFBndNoslip){ m[dSW] = RAC(ccel,dNE); LBMDS_ADDMOV(dNE,dSW); }else{ DEFAULT_STREAM_FREESLIP(dSW,dNE,nbflag[dNE]);} } else { m[dSW] = CSRC_SW; } \
- if(nbflag[dSB]&CFBnd) { if(nbflag[dSB]&CFBndNoslip){ m[dNT] = RAC(ccel,dSB); LBMDS_ADDMOV(dSB,dNT); }else{ DEFAULT_STREAM_FREESLIP(dNT,dSB,nbflag[dSB]);} } else { m[dNT] = CSRC_NT; } \
- if(nbflag[dST]&CFBnd) { if(nbflag[dST]&CFBndNoslip){ m[dNB] = RAC(ccel,dST); LBMDS_ADDMOV(dST,dNB); }else{ DEFAULT_STREAM_FREESLIP(dNB,dST,nbflag[dST]);} } else { m[dNB] = CSRC_NB; } \
- if(nbflag[dNB]&CFBnd) { if(nbflag[dNB]&CFBndNoslip){ m[dST] = RAC(ccel,dNB); LBMDS_ADDMOV(dNB,dST); }else{ DEFAULT_STREAM_FREESLIP(dST,dNB,nbflag[dNB]);} } else { m[dST] = CSRC_ST; } \
- if(nbflag[dNT]&CFBnd) { if(nbflag[dNT]&CFBndNoslip){ m[dSB] = RAC(ccel,dNT); LBMDS_ADDMOV(dNT,dSB); }else{ DEFAULT_STREAM_FREESLIP(dSB,dNT,nbflag[dNT]);} } else { m[dSB] = CSRC_SB; } \
- if(nbflag[dWB]&CFBnd) { if(nbflag[dWB]&CFBndNoslip){ m[dET] = RAC(ccel,dWB); LBMDS_ADDMOV(dWB,dET); }else{ DEFAULT_STREAM_FREESLIP(dET,dWB,nbflag[dWB]);} } else { m[dET] = CSRC_ET; } \
- if(nbflag[dWT]&CFBnd) { if(nbflag[dWT]&CFBndNoslip){ m[dEB] = RAC(ccel,dWT); LBMDS_ADDMOV(dWT,dEB); }else{ DEFAULT_STREAM_FREESLIP(dEB,dWT,nbflag[dWT]);} } else { m[dEB] = CSRC_EB; } \
- if(nbflag[dEB]&CFBnd) { if(nbflag[dEB]&CFBndNoslip){ m[dWT] = RAC(ccel,dEB); LBMDS_ADDMOV(dEB,dWT); }else{ DEFAULT_STREAM_FREESLIP(dWT,dEB,nbflag[dEB]);} } else { m[dWT] = CSRC_WT; } \
- if(nbflag[dET]&CFBnd) { if(nbflag[dET]&CFBndNoslip){ m[dWB] = RAC(ccel,dET); LBMDS_ADDMOV(dET,dWB); }else{ DEFAULT_STREAM_FREESLIP(dWB,dET,nbflag[dET]);} } else { m[dWB] = CSRC_WB; } \
- } \
-
-
-
-
-
-#define COLL_CALCULATE_DFEQ(dstarray) \
- dstarray[dN ] = EQN ; dstarray[dS ] = EQS ; \
- dstarray[dE ] = EQE ; dstarray[dW ] = EQW ; \
- dstarray[dT ] = EQT ; dstarray[dB ] = EQB ; \
- dstarray[dNE] = EQNE; dstarray[dNW] = EQNW; dstarray[dSE] = EQSE; dstarray[dSW] = EQSW; \
- dstarray[dNT] = EQNT; dstarray[dNB] = EQNB; dstarray[dST] = EQST; dstarray[dSB] = EQSB; \
- dstarray[dET] = EQET; dstarray[dEB] = EQEB; dstarray[dWT] = EQWT; dstarray[dWB] = EQWB; \
-
-
-
-#define COLL_CALCULATE_NONEQTENSOR(csolev, srcArray ) \
- lcsmqadd = (srcArray##NE - lcsmeq[ dNE ]); \
- lcsmqadd -= (srcArray##NW - lcsmeq[ dNW ]); \
- lcsmqadd -= (srcArray##SE - lcsmeq[ dSE ]); \
- lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \
- lcsmqo = (lcsmqadd* lcsmqadd); \
- lcsmqadd = (srcArray##ET - lcsmeq[ dET ]); \
- lcsmqadd -= (srcArray##EB - lcsmeq[ dEB ]); \
- lcsmqadd -= (srcArray##WT - lcsmeq[ dWT ]); \
- lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \
- lcsmqo += (lcsmqadd* lcsmqadd); \
- lcsmqadd = (srcArray##NT - lcsmeq[ dNT ]); \
- lcsmqadd -= (srcArray##NB - lcsmeq[ dNB ]); \
- lcsmqadd -= (srcArray##ST - lcsmeq[ dST ]); \
- lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \
- lcsmqo += (lcsmqadd* lcsmqadd); \
- lcsmqo *= 2.0; \
- lcsmqadd = (srcArray##E - lcsmeq[ dE ]); \
- lcsmqadd += (srcArray##W - lcsmeq[ dW ]); \
- lcsmqadd += (srcArray##NE - lcsmeq[ dNE ]); \
- lcsmqadd += (srcArray##NW - lcsmeq[ dNW ]); \
- lcsmqadd += (srcArray##SE - lcsmeq[ dSE ]); \
- lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \
- lcsmqadd += (srcArray##ET - lcsmeq[ dET ]); \
- lcsmqadd += (srcArray##EB - lcsmeq[ dEB ]); \
- lcsmqadd += (srcArray##WT - lcsmeq[ dWT ]); \
- lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \
- lcsmqo += (lcsmqadd* lcsmqadd); \
- lcsmqadd = (srcArray##N - lcsmeq[ dN ]); \
- lcsmqadd += (srcArray##S - lcsmeq[ dS ]); \
- lcsmqadd += (srcArray##NE - lcsmeq[ dNE ]); \
- lcsmqadd += (srcArray##NW - lcsmeq[ dNW ]); \
- lcsmqadd += (srcArray##SE - lcsmeq[ dSE ]); \
- lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \
- lcsmqadd += (srcArray##NT - lcsmeq[ dNT ]); \
- lcsmqadd += (srcArray##NB - lcsmeq[ dNB ]); \
- lcsmqadd += (srcArray##ST - lcsmeq[ dST ]); \
- lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \
- lcsmqo += (lcsmqadd* lcsmqadd); \
- lcsmqadd = (srcArray##T - lcsmeq[ dT ]); \
- lcsmqadd += (srcArray##B - lcsmeq[ dB ]); \
- lcsmqadd += (srcArray##NT - lcsmeq[ dNT ]); \
- lcsmqadd += (srcArray##NB - lcsmeq[ dNB ]); \
- lcsmqadd += (srcArray##ST - lcsmeq[ dST ]); \
- lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \
- lcsmqadd += (srcArray##ET - lcsmeq[ dET ]); \
- lcsmqadd += (srcArray##EB - lcsmeq[ dEB ]); \
- lcsmqadd += (srcArray##WT - lcsmeq[ dWT ]); \
- lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \
- lcsmqo += (lcsmqadd* lcsmqadd); \
- lcsmqo = sqrt(lcsmqo); \
-
-
-
-// COLL_CALCULATE_CSMOMEGAVAL(csolev, lcsmomega);
-
-// careful - need lcsmqo
-#define COLL_CALCULATE_CSMOMEGAVAL(csolev, dstomega ) \
- dstomega = 1.0/ \
- ( 3.0*( mLevel[(csolev)].lcnu+mLevel[(csolev)].lcsmago_sqr*( \
- -mLevel[(csolev)].lcnu + sqrt( mLevel[(csolev)].lcnu*mLevel[(csolev)].lcnu + 18.0*mLevel[(csolev)].lcsmago_sqr* lcsmqo ) \
- / (6.0*mLevel[(csolev)].lcsmago_sqr)) \
- ) +0.5 ); \
-
-
-
-#define DEFAULT_COLLIDE_LES(grav) \
- rho = + MSRC_C + MSRC_N \
- + MSRC_S + MSRC_E \
- + MSRC_W + MSRC_T \
- + MSRC_B + MSRC_NE \
- + MSRC_NW + MSRC_SE \
- + MSRC_SW + MSRC_NT \
- + MSRC_NB + MSRC_ST \
- + MSRC_SB + MSRC_ET \
- + MSRC_EB + MSRC_WT \
- + MSRC_WB; \
- \
- ux = MSRC_E - MSRC_W \
- + MSRC_NE - MSRC_NW \
- + MSRC_SE - MSRC_SW \
- + MSRC_ET + MSRC_EB \
- - MSRC_WT - MSRC_WB ; \
- \
- uy = MSRC_N - MSRC_S \
- + MSRC_NE + MSRC_NW \
- - MSRC_SE - MSRC_SW \
- + MSRC_NT + MSRC_NB \
- - MSRC_ST - MSRC_SB ; \
- \
- uz = MSRC_T - MSRC_B \
- + MSRC_NT - MSRC_NB \
- + MSRC_ST - MSRC_SB \
- + MSRC_ET - MSRC_EB \
- + MSRC_WT - MSRC_WB ; \
- PRECOLLIDE_MODS(rho,ux,uy,uz, grav); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- COLL_CALCULATE_DFEQ(lcsmeq); \
- COLL_CALCULATE_NONEQTENSOR(lev, MSRC_); \
- COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \
- CSMOMEGA_STATS(lev,lcsmomega); \
- \
- RAC(tcel,dC ) = (1.0-lcsmomega)*MSRC_C + lcsmomega*EQC ; \
- \
- RAC(tcel,dN ) = (1.0-lcsmomega)*MSRC_N + lcsmomega*lcsmeq[ dN ]; \
- RAC(tcel,dS ) = (1.0-lcsmomega)*MSRC_S + lcsmomega*lcsmeq[ dS ]; \
- RAC(tcel,dE ) = (1.0-lcsmomega)*MSRC_E + lcsmomega*lcsmeq[ dE ]; \
- RAC(tcel,dW ) = (1.0-lcsmomega)*MSRC_W + lcsmomega*lcsmeq[ dW ]; \
- RAC(tcel,dT ) = (1.0-lcsmomega)*MSRC_T + lcsmomega*lcsmeq[ dT ]; \
- RAC(tcel,dB ) = (1.0-lcsmomega)*MSRC_B + lcsmomega*lcsmeq[ dB ]; \
- \
- RAC(tcel,dNE) = (1.0-lcsmomega)*MSRC_NE + lcsmomega*lcsmeq[ dNE]; \
- RAC(tcel,dNW) = (1.0-lcsmomega)*MSRC_NW + lcsmomega*lcsmeq[ dNW]; \
- RAC(tcel,dSE) = (1.0-lcsmomega)*MSRC_SE + lcsmomega*lcsmeq[ dSE]; \
- RAC(tcel,dSW) = (1.0-lcsmomega)*MSRC_SW + lcsmomega*lcsmeq[ dSW]; \
- RAC(tcel,dNT) = (1.0-lcsmomega)*MSRC_NT + lcsmomega*lcsmeq[ dNT]; \
- RAC(tcel,dNB) = (1.0-lcsmomega)*MSRC_NB + lcsmomega*lcsmeq[ dNB]; \
- RAC(tcel,dST) = (1.0-lcsmomega)*MSRC_ST + lcsmomega*lcsmeq[ dST]; \
- RAC(tcel,dSB) = (1.0-lcsmomega)*MSRC_SB + lcsmomega*lcsmeq[ dSB]; \
- RAC(tcel,dET) = (1.0-lcsmomega)*MSRC_ET + lcsmomega*lcsmeq[ dET]; \
- RAC(tcel,dEB) = (1.0-lcsmomega)*MSRC_EB + lcsmomega*lcsmeq[ dEB]; \
- RAC(tcel,dWT) = (1.0-lcsmomega)*MSRC_WT + lcsmomega*lcsmeq[ dWT]; \
- RAC(tcel,dWB) = (1.0-lcsmomega)*MSRC_WB + lcsmomega*lcsmeq[ dWB]; \
-
-
-
-#define DEFAULT_COLLIDE_NOLES(grav) \
- rho = + MSRC_C + MSRC_N \
- + MSRC_S + MSRC_E \
- + MSRC_W + MSRC_T \
- + MSRC_B + MSRC_NE \
- + MSRC_NW + MSRC_SE \
- + MSRC_SW + MSRC_NT \
- + MSRC_NB + MSRC_ST \
- + MSRC_SB + MSRC_ET \
- + MSRC_EB + MSRC_WT \
- + MSRC_WB; \
- \
- ux = MSRC_E - MSRC_W \
- + MSRC_NE - MSRC_NW \
- + MSRC_SE - MSRC_SW \
- + MSRC_ET + MSRC_EB \
- - MSRC_WT - MSRC_WB ; \
- \
- uy = MSRC_N - MSRC_S \
- + MSRC_NE + MSRC_NW \
- - MSRC_SE - MSRC_SW \
- + MSRC_NT + MSRC_NB \
- - MSRC_ST - MSRC_SB ; \
- \
- uz = MSRC_T - MSRC_B \
- + MSRC_NT - MSRC_NB \
- + MSRC_ST - MSRC_SB \
- + MSRC_ET - MSRC_EB \
- + MSRC_WT - MSRC_WB ; \
- PRECOLLIDE_MODS(rho, ux,uy,uz, grav); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- \
- RAC(tcel,dC ) = (1.0-OMEGA(lev))*MSRC_C + OMEGA(lev)*EQC ; \
- \
- RAC(tcel,dN ) = (1.0-OMEGA(lev))*MSRC_N + OMEGA(lev)*EQN ; \
- RAC(tcel,dS ) = (1.0-OMEGA(lev))*MSRC_S + OMEGA(lev)*EQS ; \
- RAC(tcel,dE ) = (1.0-OMEGA(lev))*MSRC_E + OMEGA(lev)*EQE ; \
- RAC(tcel,dW ) = (1.0-OMEGA(lev))*MSRC_W + OMEGA(lev)*EQW ; \
- RAC(tcel,dT ) = (1.0-OMEGA(lev))*MSRC_T + OMEGA(lev)*EQT ; \
- RAC(tcel,dB ) = (1.0-OMEGA(lev))*MSRC_B + OMEGA(lev)*EQB ; \
- \
- RAC(tcel,dNE) = (1.0-OMEGA(lev))*MSRC_NE + OMEGA(lev)*EQNE; \
- RAC(tcel,dNW) = (1.0-OMEGA(lev))*MSRC_NW + OMEGA(lev)*EQNW; \
- RAC(tcel,dSE) = (1.0-OMEGA(lev))*MSRC_SE + OMEGA(lev)*EQSE; \
- RAC(tcel,dSW) = (1.0-OMEGA(lev))*MSRC_SW + OMEGA(lev)*EQSW; \
- RAC(tcel,dNT) = (1.0-OMEGA(lev))*MSRC_NT + OMEGA(lev)*EQNT; \
- RAC(tcel,dNB) = (1.0-OMEGA(lev))*MSRC_NB + OMEGA(lev)*EQNB; \
- RAC(tcel,dST) = (1.0-OMEGA(lev))*MSRC_ST + OMEGA(lev)*EQST; \
- RAC(tcel,dSB) = (1.0-OMEGA(lev))*MSRC_SB + OMEGA(lev)*EQSB; \
- RAC(tcel,dET) = (1.0-OMEGA(lev))*MSRC_ET + OMEGA(lev)*EQET; \
- RAC(tcel,dEB) = (1.0-OMEGA(lev))*MSRC_EB + OMEGA(lev)*EQEB; \
- RAC(tcel,dWT) = (1.0-OMEGA(lev))*MSRC_WT + OMEGA(lev)*EQWT; \
- RAC(tcel,dWB) = (1.0-OMEGA(lev))*MSRC_WB + OMEGA(lev)*EQWB; \
-
-
-
-
-
-#define OPTIMIZED_STREAMCOLLIDE_LES \
- \
- m[dC ] = CSRC_C ; \
- m[dN ] = CSRC_N ; m[dS ] = CSRC_S ; \
- m[dE ] = CSRC_E ; m[dW ] = CSRC_W ; \
- m[dT ] = CSRC_T ; m[dB ] = CSRC_B ; \
- m[dNE] = CSRC_NE; m[dNW] = CSRC_NW; m[dSE] = CSRC_SE; m[dSW] = CSRC_SW; \
- m[dNT] = CSRC_NT; m[dNB] = CSRC_NB; m[dST] = CSRC_ST; m[dSB] = CSRC_SB; \
- m[dET] = CSRC_ET; m[dEB] = CSRC_EB; m[dWT] = CSRC_WT; m[dWB] = CSRC_WB; \
- \
- rho = MSRC_C + MSRC_N + MSRC_S + MSRC_E + MSRC_W + MSRC_T \
- + MSRC_B + MSRC_NE + MSRC_NW + MSRC_SE + MSRC_SW + MSRC_NT \
- + MSRC_NB + MSRC_ST + MSRC_SB + MSRC_ET + MSRC_EB + MSRC_WT + MSRC_WB; \
- ux = MSRC_E - MSRC_W + MSRC_NE - MSRC_NW + MSRC_SE - MSRC_SW \
- + MSRC_ET + MSRC_EB - MSRC_WT - MSRC_WB; \
- uy = MSRC_N - MSRC_S + MSRC_NE + MSRC_NW - MSRC_SE - MSRC_SW \
- + MSRC_NT + MSRC_NB - MSRC_ST - MSRC_SB; \
- uz = MSRC_T - MSRC_B + MSRC_NT - MSRC_NB + MSRC_ST - MSRC_SB \
- + MSRC_ET - MSRC_EB + MSRC_WT - MSRC_WB; \
- PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- COLL_CALCULATE_DFEQ(lcsmeq); \
- COLL_CALCULATE_NONEQTENSOR(lev, MSRC_) \
- COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \
- CSMOMEGA_STATS(lev,lcsmomega); \
- \
- RAC(tcel,dC ) = (1.0-lcsmomega)*MSRC_C + lcsmomega*EQC ; \
- RAC(tcel,dN ) = (1.0-lcsmomega)*MSRC_N + lcsmomega*lcsmeq[ dN ]; \
- RAC(tcel,dS ) = (1.0-lcsmomega)*MSRC_S + lcsmomega*lcsmeq[ dS ]; \
- RAC(tcel,dE ) = (1.0-lcsmomega)*MSRC_E + lcsmomega*lcsmeq[ dE ]; \
- RAC(tcel,dW ) = (1.0-lcsmomega)*MSRC_W + lcsmomega*lcsmeq[ dW ]; \
- RAC(tcel,dT ) = (1.0-lcsmomega)*MSRC_T + lcsmomega*lcsmeq[ dT ]; \
- RAC(tcel,dB ) = (1.0-lcsmomega)*MSRC_B + lcsmomega*lcsmeq[ dB ]; \
- \
- RAC(tcel,dNE) = (1.0-lcsmomega)*MSRC_NE + lcsmomega*lcsmeq[ dNE]; \
- RAC(tcel,dNW) = (1.0-lcsmomega)*MSRC_NW + lcsmomega*lcsmeq[ dNW]; \
- RAC(tcel,dSE) = (1.0-lcsmomega)*MSRC_SE + lcsmomega*lcsmeq[ dSE]; \
- RAC(tcel,dSW) = (1.0-lcsmomega)*MSRC_SW + lcsmomega*lcsmeq[ dSW]; \
- \
- RAC(tcel,dNT) = (1.0-lcsmomega)*MSRC_NT + lcsmomega*lcsmeq[ dNT]; \
- RAC(tcel,dNB) = (1.0-lcsmomega)*MSRC_NB + lcsmomega*lcsmeq[ dNB]; \
- RAC(tcel,dST) = (1.0-lcsmomega)*MSRC_ST + lcsmomega*lcsmeq[ dST]; \
- RAC(tcel,dSB) = (1.0-lcsmomega)*MSRC_SB + lcsmomega*lcsmeq[ dSB]; \
- \
- RAC(tcel,dET) = (1.0-lcsmomega)*MSRC_ET + lcsmomega*lcsmeq[ dET]; \
- RAC(tcel,dEB) = (1.0-lcsmomega)*MSRC_EB + lcsmomega*lcsmeq[ dEB]; \
- RAC(tcel,dWT) = (1.0-lcsmomega)*MSRC_WT + lcsmomega*lcsmeq[ dWT]; \
- RAC(tcel,dWB) = (1.0-lcsmomega)*MSRC_WB + lcsmomega*lcsmeq[ dWB]; \
-
-
-
-#define OPTIMIZED_STREAMCOLLIDE_UNUSED \
- \
- rho = CSRC_C + CSRC_N + CSRC_S + CSRC_E + CSRC_W + CSRC_T \
- + CSRC_B + CSRC_NE + CSRC_NW + CSRC_SE + CSRC_SW + CSRC_NT \
- + CSRC_NB + CSRC_ST + CSRC_SB + CSRC_ET + CSRC_EB + CSRC_WT + CSRC_WB; \
- ux = CSRC_E - CSRC_W + CSRC_NE - CSRC_NW + CSRC_SE - CSRC_SW \
- + CSRC_ET + CSRC_EB - CSRC_WT - CSRC_WB; \
- uy = CSRC_N - CSRC_S + CSRC_NE + CSRC_NW - CSRC_SE - CSRC_SW \
- + CSRC_NT + CSRC_NB - CSRC_ST - CSRC_SB; \
- uz = CSRC_T - CSRC_B + CSRC_NT - CSRC_NB + CSRC_ST - CSRC_SB \
- + CSRC_ET - CSRC_EB + CSRC_WT - CSRC_WB; \
- PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- COLL_CALCULATE_DFEQ(lcsmeq); \
- COLL_CALCULATE_NONEQTENSOR(lev, CSRC_) \
- COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \
- \
- RAC(tcel,dC ) = (1.0-lcsmomega)*CSRC_C + lcsmomega*EQC ; \
- RAC(tcel,dN ) = (1.0-lcsmomega)*CSRC_N + lcsmomega*lcsmeq[ dN ]; \
- RAC(tcel,dS ) = (1.0-lcsmomega)*CSRC_S + lcsmomega*lcsmeq[ dS ]; \
- RAC(tcel,dE ) = (1.0-lcsmomega)*CSRC_E + lcsmomega*lcsmeq[ dE ]; \
- RAC(tcel,dW ) = (1.0-lcsmomega)*CSRC_W + lcsmomega*lcsmeq[ dW ]; \
- RAC(tcel,dT ) = (1.0-lcsmomega)*CSRC_T + lcsmomega*lcsmeq[ dT ]; \
- RAC(tcel,dB ) = (1.0-lcsmomega)*CSRC_B + lcsmomega*lcsmeq[ dB ]; \
- \
- RAC(tcel,dNE) = (1.0-lcsmomega)*CSRC_NE + lcsmomega*lcsmeq[ dNE]; \
- RAC(tcel,dNW) = (1.0-lcsmomega)*CSRC_NW + lcsmomega*lcsmeq[ dNW]; \
- RAC(tcel,dSE) = (1.0-lcsmomega)*CSRC_SE + lcsmomega*lcsmeq[ dSE]; \
- RAC(tcel,dSW) = (1.0-lcsmomega)*CSRC_SW + lcsmomega*lcsmeq[ dSW]; \
- \
- RAC(tcel,dNT) = (1.0-lcsmomega)*CSRC_NT + lcsmomega*lcsmeq[ dNT]; \
- RAC(tcel,dNB) = (1.0-lcsmomega)*CSRC_NB + lcsmomega*lcsmeq[ dNB]; \
- RAC(tcel,dST) = (1.0-lcsmomega)*CSRC_ST + lcsmomega*lcsmeq[ dST]; \
- RAC(tcel,dSB) = (1.0-lcsmomega)*CSRC_SB + lcsmomega*lcsmeq[ dSB]; \
- \
- RAC(tcel,dET) = (1.0-lcsmomega)*CSRC_ET + lcsmomega*lcsmeq[ dET]; \
- RAC(tcel,dEB) = (1.0-lcsmomega)*CSRC_EB + lcsmomega*lcsmeq[ dEB]; \
- RAC(tcel,dWT) = (1.0-lcsmomega)*CSRC_WT + lcsmomega*lcsmeq[ dWT]; \
- RAC(tcel,dWB) = (1.0-lcsmomega)*CSRC_WB + lcsmomega*lcsmeq[ dWB]; \
-
-
-
-#define OPTIMIZED_STREAMCOLLIDE_NOLES \
- \
- rho = CSRC_C + CSRC_N + CSRC_S + CSRC_E + CSRC_W + CSRC_T \
- + CSRC_B + CSRC_NE + CSRC_NW + CSRC_SE + CSRC_SW + CSRC_NT \
- + CSRC_NB + CSRC_ST + CSRC_SB + CSRC_ET + CSRC_EB + CSRC_WT + CSRC_WB; \
- ux = CSRC_E - CSRC_W + CSRC_NE - CSRC_NW + CSRC_SE - CSRC_SW \
- + CSRC_ET + CSRC_EB - CSRC_WT - CSRC_WB; \
- uy = CSRC_N - CSRC_S + CSRC_NE + CSRC_NW - CSRC_SE - CSRC_SW \
- + CSRC_NT + CSRC_NB - CSRC_ST - CSRC_SB; \
- uz = CSRC_T - CSRC_B + CSRC_NT - CSRC_NB + CSRC_ST - CSRC_SB \
- + CSRC_ET - CSRC_EB + CSRC_WT - CSRC_WB; \
- PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- RAC(tcel,dC ) = (1.0-OMEGA(lev))*CSRC_C + OMEGA(lev)*EQC ; \
- RAC(tcel,dN ) = (1.0-OMEGA(lev))*CSRC_N + OMEGA(lev)*EQN ; \
- RAC(tcel,dS ) = (1.0-OMEGA(lev))*CSRC_S + OMEGA(lev)*EQS ; \
- RAC(tcel,dE ) = (1.0-OMEGA(lev))*CSRC_E + OMEGA(lev)*EQE ; \
- RAC(tcel,dW ) = (1.0-OMEGA(lev))*CSRC_W + OMEGA(lev)*EQW ; \
- RAC(tcel,dT ) = (1.0-OMEGA(lev))*CSRC_T + OMEGA(lev)*EQT ; \
- RAC(tcel,dB ) = (1.0-OMEGA(lev))*CSRC_B + OMEGA(lev)*EQB ; \
- \
- RAC(tcel,dNE) = (1.0-OMEGA(lev))*CSRC_NE + OMEGA(lev)*EQNE; \
- RAC(tcel,dNW) = (1.0-OMEGA(lev))*CSRC_NW + OMEGA(lev)*EQNW; \
- RAC(tcel,dSE) = (1.0-OMEGA(lev))*CSRC_SE + OMEGA(lev)*EQSE; \
- RAC(tcel,dSW) = (1.0-OMEGA(lev))*CSRC_SW + OMEGA(lev)*EQSW; \
- \
- RAC(tcel,dNT) = (1.0-OMEGA(lev))*CSRC_NT + OMEGA(lev)*EQNT; \
- RAC(tcel,dNB) = (1.0-OMEGA(lev))*CSRC_NB + OMEGA(lev)*EQNB; \
- RAC(tcel,dST) = (1.0-OMEGA(lev))*CSRC_ST + OMEGA(lev)*EQST; \
- RAC(tcel,dSB) = (1.0-OMEGA(lev))*CSRC_SB + OMEGA(lev)*EQSB; \
- \
- RAC(tcel,dET) = (1.0-OMEGA(lev))*CSRC_ET + OMEGA(lev)*EQET; \
- RAC(tcel,dEB) = (1.0-OMEGA(lev))*CSRC_EB + OMEGA(lev)*EQEB; \
- RAC(tcel,dWT) = (1.0-OMEGA(lev))*CSRC_WT + OMEGA(lev)*EQWT; \
- RAC(tcel,dWB) = (1.0-OMEGA(lev))*CSRC_WB + OMEGA(lev)*EQWB; \
-
-
-
-
-
-// LES switching for OPT3D
-#if USE_LES==1
-#define DEFAULT_COLLIDEG(grav) DEFAULT_COLLIDE_LES(grav)
-#define OPTIMIZED_STREAMCOLLIDE OPTIMIZED_STREAMCOLLIDE_LES
-#else
-#define DEFAULT_COLLIDEG(grav) DEFAULT_COLLIDE_NOLES(grav)
-#define OPTIMIZED_STREAMCOLLIDE OPTIMIZED_STREAMCOLLIDE_NOLES
-#endif
-
-#endif // 3D, opt OPT3D==true
-
-#define USQRMAXCHECK(Cusqr,Cux,Cuy,Cuz, CmMaxVlen,CmMxvx,CmMxvy,CmMxvz) \
- if(Cusqr>CmMaxVlen) { \
- CmMxvx = Cux; CmMxvy = Cuy; CmMxvz = Cuz; CmMaxVlen = Cusqr; \
- } /* stats */
-
-
-
-/******************************************************************************
- * interpolateCellFromCoarse macros
- *****************************************************************************/
-
-
-// WOXDY_N = Weight Order X Dimension Y _ number N
-#define WO1D1 ( 1.0/ 2.0)
-#define WO1D2 ( 1.0/ 4.0)
-#define WO1D3 ( 1.0/ 8.0)
-
-#define WO2D1_1 (-1.0/16.0)
-#define WO2D1_9 ( 9.0/16.0)
-
-#define WO2D2_11 (WO2D1_1 * WO2D1_1)
-#define WO2D2_19 (WO2D1_9 * WO2D1_1)
-#define WO2D2_91 (WO2D1_9 * WO2D1_1)
-#define WO2D2_99 (WO2D1_9 * WO2D1_9)
-
-#define WO2D3_111 (WO2D1_1 * WO2D1_1 * WO2D1_1)
-#define WO2D3_191 (WO2D1_9 * WO2D1_1 * WO2D1_1)
-#define WO2D3_911 (WO2D1_9 * WO2D1_1 * WO2D1_1)
-#define WO2D3_991 (WO2D1_9 * WO2D1_9 * WO2D1_1)
-#define WO2D3_119 (WO2D1_1 * WO2D1_1 * WO2D1_9)
-#define WO2D3_199 (WO2D1_9 * WO2D1_1 * WO2D1_9)
-#define WO2D3_919 (WO2D1_9 * WO2D1_1 * WO2D1_9)
-#define WO2D3_999 (WO2D1_9 * WO2D1_9 * WO2D1_9)
-
-#if FSGR_STRICT_DEBUG==1
-#define ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l) \
- if( (((1.0-(at))>0.0) && (!(QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr , l) > -1.0 ))) || \
- ((( (at))>0.0) && (!(QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setOther, l) > -1.0 ))) ){ \
- errMsg("INVDFSCHECK", " l"<<(alev)<<" "<<PRINT_VEC((ai),(aj),(ak))<<" fc:"<<RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr )<<" fo:"<<RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setOther )<<" dfl"<<l ); \
- debugMarkCell((alev), (ai),(aj),(ak));\
- CAUSE_PANIC; \
- }
- // end ADD_INT_DFSCHECK
-#define ADD_INT_FLAGCHECK(alev, ai,aj,ak, at, afac) \
- if( (((1.0-(at))>0.0) && (!(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr )&(CFInter|CFFluid|CFGrCoarseInited) ))) || \
- ((( (at))>0.0) && (!(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setOther)&(CFInter|CFFluid|CFGrCoarseInited) ))) ){ \
- errMsg("INVFLAGCINTCHECK", " l"<<(alev)<<" at:"<<(at)<<" "<<PRINT_VEC((ai),(aj),(ak))<<\
- " fc:"<< convertCellFlagType2String(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr )) <<\
- " fold:"<< convertCellFlagType2String(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setOther )) ); \
- debugMarkCell((alev), (ai),(aj),(ak));\
- CAUSE_PANIC; \
- }
- // end ADD_INT_DFSCHECK
-
-#define INTUNUTCHECK(ix,iy,iz) \
- if( (RFLAG(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr) != (CFFluid|CFGrFromCoarse)) ){\
- errMsg("INTFLAGUNU_CHECK", PRINT_VEC(i,j,k)<<" child not unused at l"<<(lev+1)<<" "<<PRINT_VEC((ix),(iy),(iz))<<" flag: "<< RFLAG(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr) ); \
- debugMarkCell((lev+1), (ix),(iy),(iz));\
- CAUSE_PANIC; \
- }\
- RFLAG(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr) |= CFGrCoarseInited; \
- // INTUNUTCHECK
-#define INTSTRICTCHECK(ix,iy,iz,caseId) \
- if( QCELL(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr, l) <= 0.0 ){\
- errMsg("INVDFCCELLCHECK", "caseId:"<<caseId<<" "<<PRINT_VEC(i,j,k)<<" child inter at "<<PRINT_VEC((ix),(iy),(iz))<<" invalid df "<<l<<" = "<< QCELL(lev+1, (ix),(iy),(iz), mLevel[lev+1].setCurr, l) ); \
- debugMarkCell((lev+1), (ix),(iy),(iz));\
- CAUSE_PANIC; \
- }\
- // INTSTRICTCHECK
-
-#else// FSGR_STRICT_DEBUG==1
-#define ADD_INT_FLAGCHECK(alev, ai,aj,ak, at, afac)
-#define ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l)
-#define INTSTRICTCHECK(x,y,z,caseId)
-#define INTUNUTCHECK(ix,iy,iz)
-#endif// FSGR_STRICT_DEBUG==1
-
-
-#if FSGR_STRICT_DEBUG==1
-#define INTDEBOUT \
- { /*LbmFloat rho,ux,uy,uz;*/ \
- rho = ux=uy=uz=0.0; \
- FORDF0{ LbmFloat m = QCELL(lev,i,j,k, dstSet, l); \
- rho += m; ux += (this->dfDvecX[l]*m); uy += (this->dfDvecY[l]*m); uz += (this->dfDvecZ[l]*m); \
- if(ABS(m)>1.0) { errMsg("interpolateCellFromCoarse", "ICFC_DFCHECK cell "<<PRINT_IJK<<" m"<<l<<":"<< m );CAUSE_PANIC;}\
- /*errMsg("interpolateCellFromCoarse", " cell "<<PRINT_IJK<<" df"<<l<<":"<<m );*/ \
- } \
- /*if(this->mPanic) { errMsg("interpolateCellFromCoarse", "ICFC_DFOUT cell "<<PRINT_IJK<<" rho:"<<rho<<" u:"<<PRINT_VEC(ux,uy,uz)<<" b"<<PRINT_VEC(betx,bety,betz) ); }*/ \
- if(markNbs) errMsg("interpolateCellFromCoarse", " cell "<<PRINT_IJK<<" rho:"<<rho<<" u:"<<PRINT_VEC(ux,uy,uz)<<" b"<<PRINT_VEC(betx,bety,betz) ); \
- /*errMsg("interpolateCellFromCoarse", "ICFC_DFDEBUG cell "<<PRINT_IJK<<" rho:"<<rho<<" u:"<<PRINT_VEC(ux,uy,uz)<<" b"<<PRINT_VEC(betx,bety,betz) ); */\
- } \
- /* both cases are ok to interpolate */ \
- if( (!(RFLAG(lev,i,j,k, dstSet) & CFGrFromCoarse)) && \
- (!(RFLAG(lev,i,j,k, dstSet) & CFUnused)) ) { \
- /* might also have CFGrCoarseInited (shouldnt be a problem here)*/ \
- errMsg("interpolateCellFromCoarse", "CHECK cell not CFGrFromCoarse? "<<PRINT_IJK<<" flag:"<< RFLAG(lev,i,j,k, dstSet)<<" fstr:"<<convertCellFlagType2String( RFLAG(lev,i,j,k, dstSet) )); \
- /* FIXME check this warning...? return; this can happen !? */ \
- /*CAUSE_PANIC;*/ \
- } \
- // end INTDEBOUT
-#else // FSGR_STRICT_DEBUG==1
-#define INTDEBOUT
-#endif // FSGR_STRICT_DEBUG==1
-
-
-// t=0.0 -> only current
-// t=0.5 -> mix
-// t=1.0 -> only other
-#if OPT3D==0
-#define ADD_INT_DFS(alev, ai,aj,ak, at, afac) \
- ADD_INT_FLAGCHECK(alev, ai,aj,ak, at, afac); \
- FORDF0{ \
- LbmFloat df = ( \
- QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr , l)*(1.0-(at)) + \
- QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setOther, l)*( (at)) \
- ) ; \
- ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l); \
- df *= (afac); \
- rho += df; \
- ux += (this->dfDvecX[l]*df); \
- uy += (this->dfDvecY[l]*df); \
- uz += (this->dfDvecZ[l]*df); \
- intDf[l] += df; \
- }
-// write interpolated dfs back to cell (correct non-eq. parts)
-#define IDF_WRITEBACK_ \
- FORDF0{ \
- LbmFloat eq = getCollideEq(l, rho,ux,uy,uz);\
- QCELL(lev,i,j,k, dstSet, l) = (eq+ (intDf[l]-eq)*mDfScaleDown);\
- } \
- /* check that all values are ok */ \
- INTDEBOUT
-#define IDF_WRITEBACK \
- LbmFloat omegaDst, omegaSrc;\
- /* smago new */ \
- LbmFloat feq[LBM_DFNUM]; \
- LbmFloat dfScale = mDfScaleDown; \
- FORDF0{ \
- feq[l] = getCollideEq(l, rho,ux,uy,uz); \
- } \
- if(mLevel[lev ].lcsmago>0.0) {\
- LbmFloat Qo = this->getLesNoneqTensorCoeff(intDf,feq); \
- omegaDst = this->getLesOmega(mLevel[lev+0].omega,mLevel[lev+0].lcsmago,Qo); \
- omegaSrc = this->getLesOmega(mLevel[lev-1].omega,mLevel[lev-1].lcsmago,Qo); \
- } else {\
- omegaDst = mLevel[lev+0].omega; \
- omegaSrc = mLevel[lev-1].omega;\
- } \
- \
- dfScale = (mLevel[lev+0].timestep/mLevel[lev-1].timestep)* (1.0/omegaDst-1.0)/ (1.0/omegaSrc-1.0); \
- FORDF0{ \
- /*errMsg("SMAGO"," org"<<mDfScaleDown<<" n"<<dfScale<<" qc"<< QCELL(lev,i,j,k, dstSet, l)<<" idf"<<intDf[l]<<" eq"<<feq[l] ); */ \
- QCELL(lev,i,j,k, dstSet, l) = (feq[l]+ (intDf[l]-feq[l])*dfScale);\
- } \
- /* check that all values are ok */ \
- INTDEBOUT
-
-#else //OPT3D==0
-
-#define ADDALLVALS \
- addVal = addDfFacT * RAC(addfcel , dC ); \
- intDf[dC ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dN ); \
- uy+=addVal; intDf[dN ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dS ); \
- uy-=addVal; intDf[dS ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dE ); \
- ux+=addVal; intDf[dE ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dW ); \
- ux-=addVal; intDf[dW ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dT ); \
- uz+=addVal; intDf[dT ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dB ); \
- uz-=addVal; intDf[dB ] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dNE); \
- ux+=addVal; uy+=addVal; intDf[dNE] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dNW); \
- ux-=addVal; uy+=addVal; intDf[dNW] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dSE); \
- ux+=addVal; uy-=addVal; intDf[dSE] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dSW); \
- ux-=addVal; uy-=addVal; intDf[dSW] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dNT); \
- uy+=addVal; uz+=addVal; intDf[dNT] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dNB); \
- uy+=addVal; uz-=addVal; intDf[dNB] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dST); \
- uy-=addVal; uz+=addVal; intDf[dST] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dSB); \
- uy-=addVal; uz-=addVal; intDf[dSB] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dET); \
- ux+=addVal; uz+=addVal; intDf[dET] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dEB); \
- ux+=addVal; uz-=addVal; intDf[dEB] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dWT); \
- ux-=addVal; uz+=addVal; intDf[dWT] += addVal; rho += addVal; \
- addVal = addDfFacT * RAC(addfcel , dWB); \
- ux-=addVal; uz-=addVal; intDf[dWB] += addVal; rho += addVal;
-
-#define ADD_INT_DFS(alev, ai,aj,ak, at, afac) \
- addDfFacT = at*afac; \
- addfcel = RACPNT((alev), (ai),(aj),(ak),mLevel[(alev)].setOther); \
- ADDALLVALS\
- addDfFacT = (1.0-at)*afac; \
- addfcel = RACPNT((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr); \
- ADDALLVALS
-
-// also ugly...
-#define INTDF_C intDf[dC ]
-#define INTDF_N intDf[dN ]
-#define INTDF_S intDf[dS ]
-#define INTDF_E intDf[dE ]
-#define INTDF_W intDf[dW ]
-#define INTDF_T intDf[dT ]
-#define INTDF_B intDf[dB ]
-#define INTDF_NE intDf[dNE]
-#define INTDF_NW intDf[dNW]
-#define INTDF_SE intDf[dSE]
-#define INTDF_SW intDf[dSW]
-#define INTDF_NT intDf[dNT]
-#define INTDF_NB intDf[dNB]
-#define INTDF_ST intDf[dST]
-#define INTDF_SB intDf[dSB]
-#define INTDF_ET intDf[dET]
-#define INTDF_EB intDf[dEB]
-#define INTDF_WT intDf[dWT]
-#define INTDF_WB intDf[dWB]
-
-
-// write interpolated dfs back to cell (correct non-eq. parts)
-#define IDF_WRITEBACK_LES \
- dstcell = RACPNT(lev, i,j,k,dstSet); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- \
- lcsmeq[dC] = EQC ; \
- COLL_CALCULATE_DFEQ(lcsmeq); \
- COLL_CALCULATE_NONEQTENSOR(lev, INTDF_ )\
- COLL_CALCULATE_CSMOMEGAVAL(lev+0, lcsmDstOmega); \
- COLL_CALCULATE_CSMOMEGAVAL(lev-1, lcsmSrcOmega); \
- \
- lcsmdfscale = (mLevel[lev+0].timestep/mLevel[lev-1].timestep)* (1.0/lcsmDstOmega-1.0)/ (1.0/lcsmSrcOmega-1.0); \
- RAC(dstcell, dC ) = (lcsmeq[dC ] + (intDf[dC ]-lcsmeq[dC ] )*lcsmdfscale);\
- RAC(dstcell, dN ) = (lcsmeq[dN ] + (intDf[dN ]-lcsmeq[dN ] )*lcsmdfscale);\
- RAC(dstcell, dS ) = (lcsmeq[dS ] + (intDf[dS ]-lcsmeq[dS ] )*lcsmdfscale);\
- RAC(dstcell, dE ) = (lcsmeq[dE ] + (intDf[dE ]-lcsmeq[dE ] )*lcsmdfscale);\
- RAC(dstcell, dW ) = (lcsmeq[dW ] + (intDf[dW ]-lcsmeq[dW ] )*lcsmdfscale);\
- RAC(dstcell, dT ) = (lcsmeq[dT ] + (intDf[dT ]-lcsmeq[dT ] )*lcsmdfscale);\
- RAC(dstcell, dB ) = (lcsmeq[dB ] + (intDf[dB ]-lcsmeq[dB ] )*lcsmdfscale);\
- RAC(dstcell, dNE) = (lcsmeq[dNE] + (intDf[dNE]-lcsmeq[dNE] )*lcsmdfscale);\
- RAC(dstcell, dNW) = (lcsmeq[dNW] + (intDf[dNW]-lcsmeq[dNW] )*lcsmdfscale);\
- RAC(dstcell, dSE) = (lcsmeq[dSE] + (intDf[dSE]-lcsmeq[dSE] )*lcsmdfscale);\
- RAC(dstcell, dSW) = (lcsmeq[dSW] + (intDf[dSW]-lcsmeq[dSW] )*lcsmdfscale);\
- RAC(dstcell, dNT) = (lcsmeq[dNT] + (intDf[dNT]-lcsmeq[dNT] )*lcsmdfscale);\
- RAC(dstcell, dNB) = (lcsmeq[dNB] + (intDf[dNB]-lcsmeq[dNB] )*lcsmdfscale);\
- RAC(dstcell, dST) = (lcsmeq[dST] + (intDf[dST]-lcsmeq[dST] )*lcsmdfscale);\
- RAC(dstcell, dSB) = (lcsmeq[dSB] + (intDf[dSB]-lcsmeq[dSB] )*lcsmdfscale);\
- RAC(dstcell, dET) = (lcsmeq[dET] + (intDf[dET]-lcsmeq[dET] )*lcsmdfscale);\
- RAC(dstcell, dEB) = (lcsmeq[dEB] + (intDf[dEB]-lcsmeq[dEB] )*lcsmdfscale);\
- RAC(dstcell, dWT) = (lcsmeq[dWT] + (intDf[dWT]-lcsmeq[dWT] )*lcsmdfscale);\
- RAC(dstcell, dWB) = (lcsmeq[dWB] + (intDf[dWB]-lcsmeq[dWB] )*lcsmdfscale);\
- /* IDF_WRITEBACK optimized */
-
-#define IDF_WRITEBACK_NOLES \
- dstcell = RACPNT(lev, i,j,k,dstSet); \
- usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \
- \
- RAC(dstcell, dC ) = (EQC + (intDf[dC ]-EQC )*mDfScaleDown);\
- RAC(dstcell, dN ) = (EQN + (intDf[dN ]-EQN )*mDfScaleDown);\
- RAC(dstcell, dS ) = (EQS + (intDf[dS ]-EQS )*mDfScaleDown);\
- /*old*/ RAC(dstcell, dE ) = (EQE + (intDf[dE ]-EQE )*mDfScaleDown);\
- RAC(dstcell, dW ) = (EQW + (intDf[dW ]-EQW )*mDfScaleDown);\
- RAC(dstcell, dT ) = (EQT + (intDf[dT ]-EQT )*mDfScaleDown);\
- RAC(dstcell, dB ) = (EQB + (intDf[dB ]-EQB )*mDfScaleDown);\
- /*old*/ RAC(dstcell, dNE) = (EQNE + (intDf[dNE]-EQNE )*mDfScaleDown);\
- RAC(dstcell, dNW) = (EQNW + (intDf[dNW]-EQNW )*mDfScaleDown);\
- RAC(dstcell, dSE) = (EQSE + (intDf[dSE]-EQSE )*mDfScaleDown);\
- RAC(dstcell, dSW) = (EQSW + (intDf[dSW]-EQSW )*mDfScaleDown);\
- RAC(dstcell, dNT) = (EQNT + (intDf[dNT]-EQNT )*mDfScaleDown);\
- RAC(dstcell, dNB) = (EQNB + (intDf[dNB]-EQNB )*mDfScaleDown);\
- RAC(dstcell, dST) = (EQST + (intDf[dST]-EQST )*mDfScaleDown);\
- RAC(dstcell, dSB) = (EQSB + (intDf[dSB]-EQSB )*mDfScaleDown);\
- RAC(dstcell, dET) = (EQET + (intDf[dET]-EQET )*mDfScaleDown);\
- /*old*/ RAC(dstcell, dEB) = (EQEB + (intDf[dEB]-EQEB )*mDfScaleDown);\
- RAC(dstcell, dWT) = (EQWT + (intDf[dWT]-EQWT )*mDfScaleDown);\
- RAC(dstcell, dWB) = (EQWB + (intDf[dWB]-EQWB )*mDfScaleDown);\
- /* IDF_WRITEBACK optimized */
-
-#if USE_LES==1
-#define IDF_WRITEBACK IDF_WRITEBACK_LES
-#else
-#define IDF_WRITEBACK IDF_WRITEBACK_NOLES
-#endif
-
-#endif// OPT3D==0
-
-
-
-/******************************************************************************/
-/*! relaxation LES functions */
-/******************************************************************************/
-
-
-inline LbmFloat LbmFsgrSolver::getLesNoneqTensorCoeff(
- LbmFloat df[],
- LbmFloat feq[] ) {
- LbmFloat Qo = 0.0;
- for(int m=0; m< ((LBMDIM*LBMDIM)-LBMDIM)/2 ; m++) {
- LbmFloat qadd = 0.0;
- for(int l=1; l<this->cDfNum; l++) {
- if(this->lesCoeffOffdiag[m][l]==0.0) continue;
- qadd += this->lesCoeffOffdiag[m][l]*(df[l]-feq[l]);
- }
- Qo += (qadd*qadd);
- }
- Qo *= 2.0; // off diag twice
- for(int m=0; m<LBMDIM; m++) {
- LbmFloat qadd = 0.0;
- for(int l=1; l<this->cDfNum; l++) {
- if(this->lesCoeffDiag[m][l]==0.0) continue;
- qadd += this->lesCoeffDiag[m][l]*(df[l]-feq[l]);
- }
- Qo += (qadd*qadd);
- }
- Qo = sqrt(Qo);
- return Qo;
-};
-
-inline LbmFloat LbmFsgrSolver::getLesOmega(LbmFloat omega, LbmFloat csmago, LbmFloat Qo) {
- const LbmFloat tau = 1.0/omega;
- const LbmFloat nu = (2.0*tau-1.0) * (1.0/6.0);
- const LbmFloat C = csmago;
- const LbmFloat Csqr = C*C;
- LbmFloat S = -nu + sqrt( nu*nu + 18.0*Csqr*Qo ) / (6.0*Csqr);
- return( 1.0/( 3.0*( nu+Csqr*S ) +0.5 ) );
-}
-
-#define DEBUG_CALCPRINTCELL(str,df) {\
- LbmFloat prho=df[0], pux=0., puy=0., puz=0.; \
- for(int dfl=1; dfl<this->cDfNum; dfl++) { \
- prho += df[dfl]; \
- pux += (this->dfDvecX[dfl]*df[dfl]); \
- puy += (this->dfDvecY[dfl]*df[dfl]); \
- puz += (this->dfDvecZ[dfl]*df[dfl]); \
- } \
- errMsg("DEBUG_CALCPRINTCELL",">"<<str<<" rho="<<prho<<" vel="<<ntlVec3Gfx(pux,puy,puz) ); \
- } /* END DEBUG_CALCPRINTCELL */
-
-// "normal" collision
-inline void LbmFsgrSolver::collideArrays(
- int lev, int i, int j, int k, // position - more for debugging
- LbmFloat df[],
- LbmFloat &outrho, // out only!
- // velocity modifiers (returns actual velocity!)
- LbmFloat &mux, LbmFloat &muy, LbmFloat &muz,
- LbmFloat omega,
- LbmVec gravity,
- LbmFloat csmago,
- LbmFloat *newOmegaRet, LbmFloat *newQoRet
- ) {
- int l;
- LbmFloat rho=df[0];
- LbmFloat ux = 0; //mux;
- LbmFloat uy = 0; //muy;
- LbmFloat uz = 0; //muz;
- LbmFloat feq[19];
- LbmFloat omegaNew;
- LbmFloat Qo = 0.0;
-
- for(l=1; l<this->cDfNum; l++) {
- rho += df[l];
- ux += (this->dfDvecX[l]*df[l]);
- uy += (this->dfDvecY[l]*df[l]);
- uz += (this->dfDvecZ[l]*df[l]);
- }
-
-
- PRECOLLIDE_MODS(rho,ux,uy,uz, gravity);
- for(l=0; l<this->cDfNum; l++) {
- feq[l] = getCollideEq(l,rho,ux,uy,uz);
- }
-
- if(csmago>0.0) {
- Qo = getLesNoneqTensorCoeff(df,feq);
- omegaNew = getLesOmega(omega,csmago,Qo);
- } else {
- omegaNew = omega; // smago off...
- }
- if(newOmegaRet) *newOmegaRet = omegaNew; // return value for stats
- if(newQoRet) *newQoRet = Qo; // return value of non-eq. stress tensor
-
- for(l=0; l<this->cDfNum; l++) {
- df[l] = (1.0-omegaNew ) * df[l] + omegaNew * feq[l];
- }
- //if((i==16)&&(j==10)) DEBUG_CALCPRINTCELL( "2dcoll "<<PRINT_IJK, df);
-
- mux = ux;
- muy = uy;
- muz = uz;
- outrho = rho;
-
- lev=i=j=k; // debug, remove warnings
-};
-
diff --git a/intern/elbeem/intern/solver_util.cpp b/intern/elbeem/intern/solver_util.cpp
deleted file mode 100644
index ca98e26e875..00000000000
--- a/intern/elbeem/intern/solver_util.cpp
+++ /dev/null
@@ -1,1753 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Standard LBM Factory implementation
- *
- *****************************************************************************/
-
-#include "solver_class.h"
-#include "solver_relax.h"
-#include "particletracer.h"
-
-// MPT
-#include "ntl_world.h"
-#include "simulation_object.h"
-
-#include "globals.h"
-
-#include <stdlib.h>
-#include <zlib.h>
-#ifndef sqrtf
-#define sqrtf sqrt
-#endif
-
-/******************************************************************************
- * helper functions
- *****************************************************************************/
-
-// try to enhance surface?
-#define SURFACE_ENH 2
-
-//! for raytracing
-void LbmFsgrSolver::prepareVisualization( void ) {
- int lev = mMaxRefine;
- int workSet = mLevel[lev].setCurr;
-
- int mainGravDir=6; // if normalizing fails, we asume z-direction gravity
- LbmFloat mainGravLen = 0.;
- FORDF1{
- LbmFloat thisGravLen = dot(LbmVec(dfVecX[l],dfVecY[l],dfVecZ[l]), mLevel[mMaxRefine].gravity );
- if(thisGravLen>mainGravLen) {
- mainGravLen = thisGravLen;
- mainGravDir = l;
- }
- }
-
-#if LBMDIM==2
- // 2d, place in the middle of isofield slice (k=2)
-# define ZKD1 0
- // 2d z offset = 2, lbmGetData adds 1, so use one here
-# define ZKOFF 1
- // reset all values...
- for(int k= 0; k< 5; ++k)
- for(int j=0;j<mLevel[lev].lSizey-0;j++)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,j,ZKOFF)=0.0;
- }
-#else // LBMDIM==2
- // 3d, use normal bounds
-# define ZKD1 1
-# define ZKOFF k
- // reset all values...
- for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k)
- for(int j=0;j<mLevel[lev].lSizey-0;j++)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,j,ZKOFF)=0.0;
- }
-#endif // LBMDIM==2
-
- // MPT, ignore
- if((glob_mpactive) && (glob_mpnum>1) && (glob_mpindex==0)) {
- mpIso->resetAll(0.);
- }
-
-
- LbmFloat minval = mIsoValue*1.05; // / mIsoWeight[13];
- // add up...
- float val = 0.0;
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k)
- for(int j=1;j<mLevel[lev].lSizey-1;j++)
- for(int i=1;i<mLevel[lev].lSizex-1;i++) {
- const CellFlagType cflag = RFLAG(lev, i,j,k,workSet);
- //if(cflag&(CFBnd|CFEmpty)) {
-
-#if SURFACE_ENH==0
-
- // no enhancements...
- if( (cflag&(CFFluid|CFUnused)) ) {
- val = 1.;
- } else if( (cflag&CFInter) ) {
- val = (QCELL(lev, i,j,k,workSet, dFfrac));
- } else {
- continue;
- }
-
-#else // SURFACE_ENH!=1
- if(cflag&CFBnd) {
- // treated in second loop
- continue;
- } else if(cflag&CFUnused) {
- val = 1.;
- } else if( (cflag&CFFluid) && (cflag&CFNoBndFluid)) {
- // optimized fluid
- val = 1.;
- } else if( (cflag&(CFEmpty|CFInter|CFFluid)) ) {
- int noslipbnd = 0;
- int intercnt = 0;
- FORDF1 {
- const CellFlagType nbflag = RFLAG_NB(lev, i,j,k, workSet,l);
- if(nbflag&CFInter){ intercnt++; }
-
- // check all directions otherwise we get bugs with splashes on obstacles
- if(l!=mainGravDir) continue; // only check bnd along main grav. dir
- //if((nbflag&CFBnd)&&(nbflag&CFBndNoslip)){ noslipbnd=1; }
- if((nbflag&CFBnd)){ noslipbnd=1; }
- }
-
- if(cflag&CFEmpty) {
- // special empty treatment
- if((noslipbnd)&&(intercnt>6)) {
- *mpIso->lbmGetData(i,j,ZKOFF) += minval;
- } else if((noslipbnd)&&(intercnt>0)) {
- // necessary?
- *mpIso->lbmGetData(i,j,ZKOFF) += mIsoValue*0.9;
- } else {
- // nothing to do...
- }
-
- continue;
- } else if(cflag&(CFNoNbEmpty|CFFluid)) {
- // no empty nb interface cells are treated as full
- val=1.0;
- } else {
- val = (QCELL(lev, i,j,k,workSet, dFfrac));
- }
-
- if(noslipbnd) {
- if(val<minval) val = minval;
- *mpIso->lbmGetData(i,j,ZKOFF) += minval-( val * mIsoWeight[13] );
- }
- } else { // all others, unused?
- continue;
- }
-#endif // SURFACE_ENH>0
-
- *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[0] );
- *mpIso->lbmGetData( i , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[1] );
- *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[2] );
-
- *mpIso->lbmGetData( i-1 , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[3] );
- *mpIso->lbmGetData( i , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[4] );
- *mpIso->lbmGetData( i+1 , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[5] );
-
- *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[6] );
- *mpIso->lbmGetData( i , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[7] );
- *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[8] );
-
-
- *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF ) += ( val * mIsoWeight[9] );
- *mpIso->lbmGetData( i , j-1 ,ZKOFF ) += ( val * mIsoWeight[10] );
- *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF ) += ( val * mIsoWeight[11] );
-
- *mpIso->lbmGetData( i-1 , j ,ZKOFF ) += ( val * mIsoWeight[12] );
- *mpIso->lbmGetData( i , j ,ZKOFF ) += ( val * mIsoWeight[13] );
- *mpIso->lbmGetData( i+1 , j ,ZKOFF ) += ( val * mIsoWeight[14] );
-
- *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF ) += ( val * mIsoWeight[15] );
- *mpIso->lbmGetData( i , j+1 ,ZKOFF ) += ( val * mIsoWeight[16] );
- *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF ) += ( val * mIsoWeight[17] );
-
-
- *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[18] );
- *mpIso->lbmGetData( i , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[19] );
- *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[20] );
-
- *mpIso->lbmGetData( i-1 , j ,ZKOFF+ZKD1) += ( val * mIsoWeight[21] );
- *mpIso->lbmGetData( i , j ,ZKOFF+ZKD1)+= ( val * mIsoWeight[22] );
- *mpIso->lbmGetData( i+1 , j ,ZKOFF+ZKD1) += ( val * mIsoWeight[23] );
-
- *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[24] );
- *mpIso->lbmGetData( i , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[25] );
- *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[26] );
- }
-
- // TEST!?
-#if SURFACE_ENH>=2
-
- if(mFsSurfGenSetting&fssgNoObs) {
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k)
- for(int j=1;j<mLevel[lev].lSizey-1;j++)
- for(int i=1;i<mLevel[lev].lSizex-1;i++) {
- const CellFlagType cflag = RFLAG(lev, i,j,k,workSet);
- if(cflag&(CFBnd)) {
- CellFlagType nbored=0;
- LbmFloat avgfill=0.,avgfcnt=0.;
- FORDF1 {
- const int ni = i+dfVecX[l];
- const int nj = j+dfVecY[l];
- const int nk = ZKOFF+dfVecZ[l];
-
- const CellFlagType nbflag = RFLAG(lev, ni,nj,nk, workSet);
- nbored |= nbflag;
- if(nbflag&CFInter) {
- avgfill += QCELL(lev, ni,nj,nk, workSet,dFfrac); avgfcnt += 1.;
- } else if(nbflag&CFFluid) {
- avgfill += 1.; avgfcnt += 1.;
- } else if(nbflag&CFEmpty) {
- avgfill += 0.; avgfcnt += 1.;
- }
-
- //if( (ni<0) || (nj<0) || (nk<0)
- //|| (ni>=mLevel[mMaxRefine].lSizex)
- //|| (nj>=mLevel[mMaxRefine].lSizey)
- //|| (nk>=mLevel[mMaxRefine].lSizez) ) continue;
- }
-
- if(nbored&CFInter) {
- if(avgfcnt>0.) avgfill/=avgfcnt;
- *mpIso->lbmGetData(i,j,ZKOFF) = avgfill; continue;
- }
- else if(nbored&CFFluid) {
- *mpIso->lbmGetData(i,j,ZKOFF) = 1.; continue;
- }
-
- }
- }
-
- // move surface towards inner "row" of obstacle
- // cells if necessary (all obs cells without fluid/inter
- // nbs (=iso==0) next to obstacles...)
- for(int k= getForZMin1(); k< getForZMax1(lev); ++k)
- for(int j=1;j<mLevel[lev].lSizey-1;j++)
- for(int i=1;i<mLevel[lev].lSizex-1;i++) {
- const CellFlagType cflag = RFLAG(lev, i,j,k,workSet);
- if( (cflag&(CFBnd)) && (*mpIso->lbmGetData(i,j,ZKOFF)==0.)) {
- int bndnbcnt=0;
- FORDF1 {
- const int ni = i+dfVecX[l];
- const int nj = j+dfVecY[l];
- const int nk = ZKOFF+dfVecZ[l];
- const CellFlagType nbflag = RFLAG(lev, ni,nj,nk, workSet);
- if(nbflag&CFBnd) bndnbcnt++;
- }
- if(bndnbcnt>0) *mpIso->lbmGetData(i,j,ZKOFF)=mIsoValue*0.95;
- }
- }
- }
- // */
-
- if(mFsSurfGenSetting&fssgNoNorth)
- for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k)
- for(int j=0;j<mLevel[lev].lSizey-0;j++) {
- *mpIso->lbmGetData(0, j,ZKOFF) = *mpIso->lbmGetData(1, j,ZKOFF);
- }
- if(mFsSurfGenSetting&fssgNoEast)
- for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,0, ZKOFF) = *mpIso->lbmGetData(i,1, ZKOFF);
- }
- if(mFsSurfGenSetting&fssgNoSouth)
- for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k)
- for(int j=0;j<mLevel[lev].lSizey-0;j++) {
- *mpIso->lbmGetData(mLevel[lev].lSizex-1,j,ZKOFF) = *mpIso->lbmGetData(mLevel[lev].lSizex-2,j,ZKOFF);
- }
- if(mFsSurfGenSetting&fssgNoWest)
- for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,mLevel[lev].lSizey-1,ZKOFF) = *mpIso->lbmGetData(i,mLevel[lev].lSizey-2,ZKOFF);
- }
- if(LBMDIM>2) {
- if(mFsSurfGenSetting&fssgNoBottom)
- for(int j=0;j<mLevel[lev].lSizey-0;j++)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,j,0 ) = *mpIso->lbmGetData(i,j,1 );
- }
- if(mFsSurfGenSetting&fssgNoTop)
- for(int j=0;j<mLevel[lev].lSizey-0;j++)
- for(int i=0;i<mLevel[lev].lSizex-0;i++) {
- *mpIso->lbmGetData(i,j,mLevel[lev].lSizez-1) = *mpIso->lbmGetData(i,j,mLevel[lev].lSizez-2);
- }
- }
-#endif // SURFACE_ENH>=2
-
-
- // update preview, remove 2d?
- if((mOutputSurfacePreview)&&(LBMDIM==3)) {
- int pvsx = (int)(mPreviewFactor*mSizex);
- int pvsy = (int)(mPreviewFactor*mSizey);
- int pvsz = (int)(mPreviewFactor*mSizez);
- //float scale = (float)mSizex / previewSize;
- LbmFloat scalex = (LbmFloat)mSizex/(LbmFloat)pvsx;
- LbmFloat scaley = (LbmFloat)mSizey/(LbmFloat)pvsy;
- LbmFloat scalez = (LbmFloat)mSizez/(LbmFloat)pvsz;
- for(int k= 0; k< (pvsz-1); ++k)
- for(int j=0;j< pvsy;j++)
- for(int i=0;i< pvsx;i++) {
- *mpPreviewSurface->lbmGetData(i,j,k) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley), (int)(k*scalez) );
- }
- // set borders again...
- for(int k= 0; k< (pvsz-1); ++k) {
- for(int j=0;j< pvsy;j++) {
- *mpPreviewSurface->lbmGetData(0,j,k) = *mpIso->lbmGetData( 0, (int)(j*scaley), (int)(k*scalez) );
- *mpPreviewSurface->lbmGetData(pvsx-1,j,k) = *mpIso->lbmGetData( mSizex-1, (int)(j*scaley), (int)(k*scalez) );
- }
- for(int i=0;i< pvsx;i++) {
- *mpPreviewSurface->lbmGetData(i,0,k) = *mpIso->lbmGetData( (int)(i*scalex), 0, (int)(k*scalez) );
- *mpPreviewSurface->lbmGetData(i,pvsy-1,k) = *mpIso->lbmGetData( (int)(i*scalex), mSizey-1, (int)(k*scalez) );
- }
- }
- for(int j=0;j<pvsy;j++)
- for(int i=0;i<pvsx;i++) {
- *mpPreviewSurface->lbmGetData(i,j,0) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley) , 0);
- *mpPreviewSurface->lbmGetData(i,j,pvsz-1) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley) , mSizez-1);
- }
-
- if(mFarFieldSize>=1.2) {
- // also remove preview border
- for(int k= 0; k< (pvsz-1); ++k) {
- for(int j=0;j< pvsy;j++) {
- *mpPreviewSurface->lbmGetData(0,j,k) =
- *mpPreviewSurface->lbmGetData(1,j,k) =
- *mpPreviewSurface->lbmGetData(2,j,k);
- *mpPreviewSurface->lbmGetData(pvsx-1,j,k) =
- *mpPreviewSurface->lbmGetData(pvsx-2,j,k) =
- *mpPreviewSurface->lbmGetData(pvsx-3,j,k);
- //0.0;
- }
- for(int i=0;i< pvsx;i++) {
- *mpPreviewSurface->lbmGetData(i,0,k) =
- *mpPreviewSurface->lbmGetData(i,1,k) =
- *mpPreviewSurface->lbmGetData(i,2,k);
- *mpPreviewSurface->lbmGetData(i,pvsy-1,k) =
- *mpPreviewSurface->lbmGetData(i,pvsy-2,k) =
- *mpPreviewSurface->lbmGetData(i,pvsy-3,k);
- //0.0;
- }
- }
- for(int j=0;j<pvsy;j++)
- for(int i=0;i<pvsx;i++) {
- *mpPreviewSurface->lbmGetData(i,j,0) =
- *mpPreviewSurface->lbmGetData(i,j,1) =
- *mpPreviewSurface->lbmGetData(i,j,2);
- *mpPreviewSurface->lbmGetData(i,j,pvsz-1) =
- *mpPreviewSurface->lbmGetData(i,j,pvsz-2) =
- *mpPreviewSurface->lbmGetData(i,j,pvsz-3);
- //0.0;
- }
- }
- }
-
- // MPT
- #if LBM_INCLUDE_TESTSOLVERS==1
- mrIsoExchange();
- #endif // LBM_INCLUDE_TESTSOLVERS==1
-
- return;
-}
-
-/*! calculate speeds of fluid objects (or inflow) */
-void LbmFsgrSolver::recalculateObjectSpeeds() {
- const bool debugRecalc = false;
- int numobjs = (int)(this->mpGiObjects->size());
- // note - (numobjs + 1) is entry for domain settings
-
- if(debugRecalc) errMsg("recalculateObjectSpeeds","start, #obj:"<<numobjs);
- if(numobjs>255-1) {
- errFatal("LbmFsgrSolver::recalculateObjectSpeeds","More than 256 objects currently not supported...",SIMWORLD_INITERROR);
- return;
- }
- mObjectSpeeds.resize(numobjs+1);
- for(int i=0; i<(int)(numobjs+0); i++) {
- mObjectSpeeds[i] = vec2L(this->mpParam->calculateLattVelocityFromRw( vec2P( (*this->mpGiObjects)[i]->getInitialVelocity(mSimulationTime) )));
- if(debugRecalc) errMsg("recalculateObjectSpeeds","id"<<i<<" set to "<< mObjectSpeeds[i]<<", unscaled:"<< (*this->mpGiObjects)[i]->getInitialVelocity(mSimulationTime) );
- }
-
- // also reinit part slip values here
- mObjectPartslips.resize(numobjs+1);
- for(int i=0; i<=(int)(numobjs+0); i++) {
- if(i<numobjs) {
- mObjectPartslips[i] = (LbmFloat)(*this->mpGiObjects)[i]->getGeoPartSlipValue();
- } else {
- // domain setting
- mObjectPartslips[i] = this->mDomainPartSlipValue;
- }
- LbmFloat set = mObjectPartslips[i];
-
- // as in setInfluenceVelocity
- const LbmFloat dt = mLevel[mMaxRefine].timestep;
- const LbmFloat dtInter = 0.01;
- //LbmFloat facFv = 1.-set;
- // mLevel[mMaxRefine].timestep
- LbmFloat facNv = (LbmFloat)( 1.-pow( (double)(set), (double)(dt/dtInter)) );
- errMsg("mObjectPartslips","id:"<<i<<"/"<<numobjs<<" ts:"<<dt<< " its:"<<(dt/dtInter) <<" set"<<set<<" nv"<<facNv<<" test:"<<
- pow( (double)(1.-facNv),(double)(dtInter/dt)) );
- mObjectPartslips[i] = facNv;
-
- if(debugRecalc) errMsg("recalculateObjectSpeeds","id"<<i<<" parts "<< mObjectPartslips[i] );
- }
-
- if(debugRecalc) errMsg("recalculateObjectSpeeds","done, domain:"<<mObjectPartslips[numobjs]<<" n"<<numobjs);
-}
-
-
-
-/*****************************************************************************/
-/*! debug object display */
-/*****************************************************************************/
-vector<ntlGeometryObject*> LbmFsgrSolver::getDebugObjects() {
- vector<ntlGeometryObject*> debo;
- if(this->mOutputSurfacePreview) {
- debo.push_back( mpPreviewSurface );
- }
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(mUseTestdata) {
- vector<ntlGeometryObject*> tdebo;
- tdebo = mpTest->getDebugObjects();
- for(size_t i=0; i<tdebo.size(); i++) debo.push_back( tdebo[i] );
- }
-#endif // ELBEEM_PLUGIN
- return debo;
-}
-
-/******************************************************************************
- * particle handling
- *****************************************************************************/
-
-/*! init particle positions */
-int LbmFsgrSolver::initParticles() {
- int workSet = mLevel[mMaxRefine].setCurr;
- int tries = 0;
- int num = 0;
- ParticleTracer *partt = mpParticles;
-
- partt->setStart( this->mvGeoStart + ntlVec3Gfx(mLevel[mMaxRefine].nodeSize*0.5) );
- partt->setEnd ( this->mvGeoEnd + ntlVec3Gfx(mLevel[mMaxRefine].nodeSize*0.5) );
-
- partt->setSimStart( ntlVec3Gfx(0.0) );
- partt->setSimEnd ( ntlVec3Gfx(mSizex, mSizey, getForZMaxBnd(mMaxRefine)) );
-
- while( (num<partt->getNumInitialParticles()) && (tries<100*partt->getNumInitialParticles()) ) {
- LbmFloat x,y,z,t;
- x = 1.0+(( (LbmFloat)(mSizex-3.) ) * (rand()/(RAND_MAX+1.0)) );
- y = 1.0+(( (LbmFloat)(mSizey-3.) ) * (rand()/(RAND_MAX+1.0)) );
- z = 1.0+(( (LbmFloat) getForZMax1(mMaxRefine)-2. )* (rand()/(RAND_MAX+1.0)) );
- int i = (int)(x+0.5);
- int j = (int)(y+0.5);
- int k = (int)(z+0.5);
- if(LBMDIM==2) {
- k = 0; z = 0.5; // place in the middle of domain
- }
-
- //if( RFLAG(mMaxRefine, i,j,k, workSet)& (CFFluid) )
- //&& ( RFLAG(mMaxRefine, i,j,k, workSet)& CFNoNbFluid )
- //if( RFLAG(mMaxRefine, i,j,k, workSet) & (CFFluid|CFInter|CFMbndInflow) ) {
- if( RFLAG(mMaxRefine, i,j,k, workSet) & (CFNoBndFluid|CFUnused) ) {
- bool cellOk = true;
- //? FORDF1 { if(!(RFLAG_NB(mMaxRefine,i,j,k,workSet, l) & CFFluid)) cellOk = false; }
- if(!cellOk) continue;
- // in fluid...
- partt->addParticle(x,y,z);
- partt->getLast()->setStatus(PART_IN);
- partt->getLast()->setType(PART_TRACER);
-
- partt->getLast()->setSize(1.);
- // randomize size
- partt->getLast()->setSize(0.5 + (rand()/(RAND_MAX+1.0)));
-
- if( ( partt->getInitStart()>0.)
- && ( partt->getInitEnd()>0.)
- && ( partt->getInitEnd()>partt->getInitStart() )) {
- t = partt->getInitStart()+ (partt->getInitEnd()-partt->getInitStart())*(rand()/(RAND_MAX+1.0));
- partt->getLast()->setLifeTime( -t );
- }
- num++;
- }
- tries++;
- } // */
-
- /*FSGR_FORIJK1(mMaxRefine) {
- if( (RFLAG(mMaxRefine,i,j,k, workSet) & (CFNoBndFluid)) ) {
- LbmFloat rndn = (rand()/(RAND_MAX+1.0));
- if(rndn>0.0) {
- ntlVec3Gfx pos( (LbmFloat)(i)-0.5, (LbmFloat)(j)-0.5, (LbmFloat)(k)-0.5 );
- if(LBMDIM==2) { pos[2]=0.5; }
- partt->addParticle( pos[0],pos[1],pos[2] );
- partt->getLast()->setStatus(PART_IN);
- partt->getLast()->setType(PART_TRACER);
- partt->getLast()->setSize(1.0);
- }
- }
- } // */
-
-
- // DEBUG TEST
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(mUseTestdata) {
- const bool partDebug=false;
- if(mpTest->mPartTestcase==0){ errMsg("LbmTestdata"," part init "<<mpTest->mPartTestcase); }
- if(mpTest->mPartTestcase==-12){
- const int lev = mMaxRefine;
- for(int i=5;i<15;i++) {
- LbmFloat x,y,z;
- y = 0.5+(LbmFloat)(i);
- x = mLevel[lev].lSizex/20.0*10.0;
- z = mLevel[lev].lSizez/20.0*2.0;
- partt->addParticle(x,y,z);
- partt->getLast()->setStatus(PART_IN);
- partt->getLast()->setType(PART_BUBBLE);
- partt->getLast()->setSize( (-4.0+(LbmFloat)i)/1.0 );
- if(partDebug) errMsg("PARTTT","SET "<<PRINT_VEC(x,y,z)<<" p"<<partt->getLast()->getPos() <<" s"<<partt->getLast()->getSize() );
- }
- }
- if(mpTest->mPartTestcase==-11){
- const int lev = mMaxRefine;
- for(int i=5;i<15;i++) {
- LbmFloat x,y,z;
- y = 10.5+(LbmFloat)(i);
- x = mLevel[lev].lSizex/20.0*10.0;
- z = mLevel[lev].lSizez/20.0*40.0;
- partt->addParticle(x,y,z);
- partt->getLast()->setStatus(PART_IN);
- partt->getLast()->setType(PART_DROP);
- partt->getLast()->setSize( (-4.0+(LbmFloat)i)/1.0 );
- if(partDebug) errMsg("PARTTT","SET "<<PRINT_VEC(x,y,z)<<" p"<<partt->getLast()->getPos() <<" s"<<partt->getLast()->getSize() );
- }
- }
- // place floats on rectangular region FLOAT_JITTER_BND
- if(mpTest->mPartTestcase==-10){
- const int lev = mMaxRefine;
- const int sx = mLevel[lev].lSizex;
- const int sy = mLevel[lev].lSizey;
- //for(int j=-(int)(sy*0.25);j<-(int)(sy*0.25)+2;++j) { for(int i=-(int)(sx*0.25);i<-(int)(sy*0.25)+2;++i) {
- //for(int j=-(int)(sy*1.25);j<(int)(2.25*sy);++j) { for(int i=-(int)(sx*1.25);i<(int)(2.25*sx);++i) {
- for(int j=-(int)(sy*0.3);j<(int)(1.3*sy);++j) { for(int i=-(int)(sx*0.3);i<(int)(1.3*sx);++i) {
- //for(int j=-(int)(sy*0.2);j<(int)(0.2*sy);++j) { for(int i= (int)(sx*0.5);i<= (int)(0.51*sx);++i) {
- LbmFloat x,y,z;
- x = 0.0+(LbmFloat)(i);
- y = 0.0+(LbmFloat)(j);
- //z = mLevel[lev].lSizez/10.0*2.5 - 1.0;
- z = mLevel[lev].lSizez/20.0*9.5 - 1.0;
- //z = mLevel[lev].lSizez/20.0*4.5 - 1.0;
- partt->addParticle(x,y,z);
- //if( (i>0)&&(i<sx) && (j>0)&&(j<sy) ) { partt->getLast()->setStatus(PART_IN); } else { partt->getLast()->setStatus(PART_OUT); }
- partt->getLast()->setStatus(PART_IN);
- partt->getLast()->setType(PART_FLOAT);
- partt->getLast()->setSize( 15.0 );
- if(partDebug) errMsg("PARTTT","SET "<<PRINT_VEC(x,y,z)<<" p"<<partt->getLast()->getPos() <<" s"<<partt->getLast()->getSize() );
- }
- } }
- }
- // DEBUG TEST
-#endif // LBM_INCLUDE_TESTSOLVERS
-
-
- debMsgStd("LbmFsgrSolver::initParticles",DM_MSG,"Added "<<num<<" particles, genProb:"<<this->mPartGenProb<<", tries:"<<tries, 10);
- if(num != partt->getNumParticles()) return 1;
-
- return 0;
-}
-
-// helper function for particle debugging
-/*static string getParticleStatusString(int state) {
- std::ostringstream out;
- if(state&PART_DROP) out << "dropp ";
- if(state&PART_TRACER) out << "tracr ";
- if(state&PART_BUBBLE) out << "bubbl ";
- if(state&PART_FLOAT) out << "float ";
- if(state&PART_INTER) out << "inter ";
-
- if(state&PART_IN) out << "inn ";
- if(state&PART_OUT) out << "out ";
- if(state&PART_INACTIVE) out << "INACT ";
- if(state&PART_OUTFLUID) out << "outfluid ";
- return out.str();
-} // */
-
-#define P_CHANGETYPE(p, newtype) \
- p->setLifeTime(0.); \
- /* errMsg("PIT","U pit"<<(p)->getId()<<" pos:"<< (p)->getPos()<<" status:"<<convertFlags2String((p)->getFlags())<<" to "<< (newtype) ); */ \
- p->setType(newtype);
-
-// tracer defines
-#define TRACE_JITTER 0.025
-#define TRACE_RAND (rand()/(RAND_MAX+1.0))*TRACE_JITTER-(TRACE_JITTER*0.5)
-#define FFGET_NORM(var,dl) \
- if(RFLAG_NB(lev,i,j,k,workSet, dl) &(CFInter)){ (var) = QCELL_NB(lev,i,j,k,workSet,dl,dFfrac); } \
- else if(RFLAG_NB(lev,i,j,k,workSet, dl) &(CFFluid|CFUnused)){ (var) = 1.; } else (var) = 0.0;
-
-// float jitter
-#define FLOAT_JITTER_BND (FLOAT_JITTER*2.0)
-#define FLOAT_JITTBNDRAND(x) ((rand()/(RAND_MAX+1.0))*FLOAT_JITTER_BND*(1.-(x/(LbmFloat)maxdw))-(FLOAT_JITTER_BND*(1.-(x)/(LbmFloat)maxdw)*0.5))
-
-#define DEL_PART { \
- /*errMsg("PIT","DEL AT "<< __LINE__<<" type:"<<p->getType()<<" "); */ \
- p->setActive( false ); \
- continue; }
-
-void LbmFsgrSolver::advanceParticles() {
- const int level = mMaxRefine;
- const int workSet = mLevel[level].setCurr;
- LbmFloat vx=0.0,vy=0.0,vz=0.0;
- //int debugOutCounter=0; // debug output counter
-
- myTime_t parttstart = getTime();
- const LbmFloat cellsize = this->mpParam->getCellSize();
- const LbmFloat timestep = this->mpParam->getTimestep();
- //const LbmFloat viscAir = 1.79 * 1e-5; // RW2L kin. viscosity, mu
- //const LbmFloat viscWater = 1.0 * 1e-6; // RW2L kin. viscosity, mu
- const LbmFloat rhoAir = 1.2; // [kg m^-3] RW2L
- const LbmFloat rhoWater = 1000.0; // RW2L
- const LbmFloat minDropSize = 0.0005; // [m], = 2mm RW2L
- const LbmVec velAir(0.); // [m / s]
-
- const LbmFloat r1 = 0.005; // r max
- const LbmFloat r2 = 0.0005; // r min
- const LbmFloat v1 = 9.0; // v max
- const LbmFloat v2 = 2.0; // v min
- const LbmVec rwgrav = vec2L( this->mpParam->getGravity(mSimulationTime) );
- const bool useff = (mFarFieldSize>1.2); // if(mpTest->mFarfMode>0){
-
- // TODO scale bubble/part damping dep. on timestep, also drop bnd rev damping
- const int cutval = mCutoff; // use full border!?
- if(this->mStepCnt%50==49) { mpParticles->cleanup(); }
- for(vector<ParticleObject>::iterator pit= mpParticles->getParticlesBegin();
- pit!= mpParticles->getParticlesEnd(); pit++) {
- //if((*pit).getPos()[2]>10.) errMsg("PIT"," pit"<<(*pit).getId()<<" pos:"<< (*pit).getPos()<<" status:["<<getParticleStatusString((*pit).getFlags())<<"] vel:"<< (*pit).getVel() );
- if( (*pit).getActive()==false ) continue;
- // skip until reached
- ParticleObject *p = &(*pit);
- if(p->getLifeTime()<0.){
- if(p->getLifeTime() < -mSimulationTime) continue;
- else p->setLifeTime(-mLevel[level].timestep); // zero for following update
- }
- int i,j,k;
- p->setLifeTime(p->getLifeTime()+mLevel[level].timestep);
-
- // nearest neighbor, particle positions don't include empty bounds
- ntlVec3Gfx pos = p->getPos();
- i= (int)pos[0]; j= (int)pos[1]; k= (int)pos[2];// no offset necessary
- if(LBMDIM==2) { k = 0; }
-
- // only testdata handling, all for sws
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(useff && (mpTest->mFarfMode>0)) {
- p->setStatus(PART_OUT);
- mpTest->handleParticle(p, i,j,k); continue;
- }
-#endif // LBM_INCLUDE_TESTSOLVERS==1
-
- // in out tests
- if(p->getStatus()&PART_IN) { // IN
- if( (i<cutval)||(i>mSizex-1-cutval)||
- (j<cutval)||(j>mSizey-1-cutval)
- //||(k<cutval)||(k>mSizez-1-cutval)
- ) {
- if(!useff) { DEL_PART;
- } else {
- p->setStatus(PART_OUT);
- }
- }
- } else { // OUT rough check
- // check in again?
- if( (i>=cutval)&&(i<=mSizex-1-cutval)&&
- (j>=cutval)&&(j<=mSizey-1-cutval)
- ) {
- p->setStatus(PART_IN);
- }
- }
-
- if( (p->getType()==PART_BUBBLE) ||
- (p->getType()==PART_TRACER) ) {
-
- // no interpol
- vx = vy = vz = 0.0;
- if(p->getStatus()&PART_IN) { // IN
- if(k>=cutval) {
- if(k>mSizez-1-cutval) DEL_PART;
-
- if( RFLAG(level, i,j,k, workSet)&(CFFluid|CFUnused) ) {
- // still ok
- int partLev = level;
- int si=i, sj=j, sk=k;
- while(partLev>0 && RFLAG(partLev, si,sj,sk, workSet)&(CFUnused)) {
- partLev--;
- si/=2;
- sj/=2;
- sk/=2;
- }
- // get velocity from fluid cell
- if( RFLAG(partLev, si,sj,sk, workSet)&(CFFluid) ) {
- LbmFloat *ccel = RACPNT(partLev, si,sj,sk, workSet);
- FORDF1{
- LbmFloat cdf = RAC(ccel, l);
- // TODO update below
- vx += (this->dfDvecX[l]*cdf);
- vy += (this->dfDvecY[l]*cdf);
- vz += (this->dfDvecZ[l]*cdf);
- }
- // remove gravity influence
- const LbmFloat lesomega = mLevel[level].omega; // no les
- vx -= mLevel[level].gravity[0] * lesomega*0.5;
- vy -= mLevel[level].gravity[1] * lesomega*0.5;
- vz -= mLevel[level].gravity[2] * lesomega*0.5;
- } // fluid vel
-
- } else { // OUT
- // out of bounds, deactivate...
- // FIXME make fsgr treatment
- if(p->getType()==PART_BUBBLE) { P_CHANGETYPE(p, PART_FLOAT ); continue; }
- }
- } else {
- // below 3d region, just rise
- }
- } else { // OUT
-# if LBM_INCLUDE_TESTSOLVERS==1
- if(useff) { mpTest->handleParticle(p, i,j,k); }
- else DEL_PART;
-# else // LBM_INCLUDE_TESTSOLVERS==1
- DEL_PART;
-# endif // LBM_INCLUDE_TESTSOLVERS==1
- // TODO use x,y vel...?
- }
-
- ntlVec3Gfx v = p->getVel(); // dampen...
- if( (useff)&& (p->getType()==PART_BUBBLE) ) {
- // test rise
-
- if(mPartUsePhysModel) {
- LbmFloat radius = p->getSize() * minDropSize;
- //LbmVec velPart = vec2L(p->getVel()) *cellsize/timestep; // L2RW, lattice velocity
- //LbmVec velWater = LbmVec(vx,vy,vz) *cellsize/timestep;// L2RW, fluid velocity
- //LbmVec velRel = velWater - velPart;
- //LbmFloat velRelNorm = norm(velRel);
- //LbmFloat pvolume = rhoAir * 4.0/3.0 * M_PI* radius*radius*radius; // volume: 4/3 pi r^3
-
- //LbmVec fb = -rwgrav* pvolume *rhoWater;
- //LbmVec fd = velRel*6.0*M_PI*radius* (1e-3); //viscWater;
- //LbmVec change = (fb+fd) *10.0*timestep *(timestep/cellsize);
- /*if(debugOutCounter<0) {
- errMsg("PIT","BTEST1 vol="<<pvolume<<" radius="<<radius<<" vn="<<velRelNorm<<" velPart="<<velPart<<" velRel"<<velRel);
- errMsg("PIT","BTEST2 cellsize="<<cellsize<<" timestep="<<timestep<<" viscW="<<viscWater<<" ss/mb="<<(timestep/(pvolume*rhoAir)));
- errMsg("PIT","BTEST2 grav="<<rwgrav<<" " );
- errMsg("PIT","BTEST2 change="<<(change)<<" fb="<<(fb)<<" fd="<<(fd)<<" ");
- errMsg("PIT","BTEST2 change="<<norm(change)<<" fb="<<norm(fb)<<" fd="<<norm(fd)<<" ");
- } // DEBUG */
-
- LbmVec fd2 = (LbmVec(vx,vy,vz)-vec2L(p->getVel())) * 6.0*M_PI*radius* (1e-3); //viscWater;
- LbmFloat w = 0.99;
- vz = (1.0-w)*vz + w*(p->getVel()[2]-0.5*(p->getSize()/5.0)*mLevel[level].gravity[2]);
- v = ntlVec3Gfx(vx,vy,vz)+vec2G(fd2);
- p->setVel( v );
- } else {
- // non phys, half old, half fluid, use slightly slower acc
- v = v*0.5 + ntlVec3Gfx(vx,vy,vz)* 0.5-vec2G(mLevel[level].gravity)*0.5;
- p->setVel( v * 0.99 );
- }
- p->advanceVel();
-
- } else if(p->getType()==PART_TRACER) {
- v = ntlVec3Gfx(vx,vy,vz);
- CellFlagType fflag = RFLAG(level, i,j,k, workSet);
-
- if(fflag&(CFFluid|CFInter) ) { p->setInFluid(true);
- } else { p->setInFluid(false); }
-
- if( (( fflag&CFFluid ) && ( fflag&CFNoBndFluid )) ||
- (( fflag&CFInter ) && (!(fflag&CFNoNbFluid)) ) ) {
- // only real fluid
-# if LBMDIM==3
- p->advance( TRACE_RAND,TRACE_RAND,TRACE_RAND);
-# else
- p->advance( TRACE_RAND,TRACE_RAND, 0.);
-# endif
-
- } else {
- // move inwards along normal, make sure normal is valid first
- // todo use class funcs!
- const int lev = level;
- LbmFloat nx=0.,ny=0.,nz=0., nv1,nv2;
- bool nonorm = false;
- if(i<=0) { nx = -1.; nonorm = true; }
- if(i>=mSizex-1) { nx = 1.; nonorm = true; }
- if(j<=0) { ny = -1.; nonorm = true; }
- if(j>=mSizey-1) { ny = 1.; nonorm = true; }
-# if LBMDIM==3
- if(k<=0) { nz = -1.; nonorm = true; }
- if(k>=mSizez-1) { nz = 1.; nonorm = true; }
-# endif // LBMDIM==3
- if(!nonorm) {
- FFGET_NORM(nv1,dE); FFGET_NORM(nv2,dW);
- nx = 0.5* (nv2-nv1);
- FFGET_NORM(nv1,dN); FFGET_NORM(nv2,dS);
- ny = 0.5* (nv2-nv1);
-# if LBMDIM==3
- FFGET_NORM(nv1,dT); FFGET_NORM(nv2,dB);
- nz = 0.5* (nv2-nv1);
-# else // LBMDIM==3
- nz = 0.;
-# endif // LBMDIM==3
- } else {
- v = p->getVel() + vec2G(mLevel[level].gravity);
- }
- p->advanceVec( (ntlVec3Gfx(nx,ny,nz)) * -0.1 ); // + vec2G(mLevel[level].gravity);
- }
- }
-
- p->setVel( v );
- p->advanceVel();
- }
-
- // drop handling
- else if(p->getType()==PART_DROP) {
- ntlVec3Gfx v = p->getVel(); // dampen...
-
- if(mPartUsePhysModel) {
- LbmFloat radius = p->getSize() * minDropSize;
- LbmVec velPart = vec2L(p->getVel()) *cellsize /timestep; // * cellsize / timestep; // L2RW, lattice velocity
- LbmVec velRel = velAir - velPart;
- //LbmVec velRelLat = velRel /cellsize*timestep; // L2RW
- LbmFloat velRelNorm = norm(velRel);
- // TODO calculate values in lattice units, compute CD?!??!
- LbmFloat mb = rhoWater * 4.0/3.0 * M_PI* radius*radius*radius; // mass: 4/3 pi r^3 rho
- const LbmFloat rw = (r1-radius)/(r1-r2);
- const LbmFloat rmax = (0.5 + 0.5*rw);
- const LbmFloat vmax = (v2 + (v1-v2)* (1.0-rw) );
- const LbmFloat cd = (rmax) * (velRelNorm)/(vmax);
-
- LbmVec fg = rwgrav * mb;// * (1.0-rhoAir/rhoWater);
- LbmVec fd = velRel* velRelNorm* cd*M_PI *rhoAir *0.5 *radius*radius;
- LbmVec change = (fg+ fd ) *timestep / mb *(timestep/cellsize);
- //if(k>0) { errMsg("\nPIT","NTEST1 mb="<<mb<<" radius="<<radius<<" vn="<<velRelNorm<<" velPart="<<velPart<<" velRel"<<velRel<<" pgetVel="<<p->getVel() ); }
-
- v += vec2G(change);
- p->setVel(v);
- // NEW
- } else {
- p->setVel( v );
- int gravk = (int)(p->getPos()[2]+mLevel[level].gravity[2]);
- if(gravk>=0 && gravk<mSizez && RFLAG(level, i,j,gravk, workSet)&CFBnd) {
- // dont add for "resting" parts
- v[2] = 0.;
- p->setVel( v*0.9 ); // restdamping
- } else {
- p->addToVel( vec2G(mLevel[level].gravity) );
- }
- } // OLD
- p->advanceVel();
-
- if(p->getStatus()&PART_IN) { // IN
- if(k<cutval) { DEL_PART; continue; }
- if(k<=mSizez-1-cutval){
- CellFlagType pflag = RFLAG(level, i,j,k, workSet);
- //errMsg("PIT move"," at "<<PRINT_IJK<<" flag"<<convertCellFlagType2String(pflag) );
- if (pflag & CFMbndOutflow) {
- DEL_PART;
- continue;
- }
- if(pflag & (CFBnd)) {
- handleObstacleParticle(p);
- continue;
- } else if(pflag & (CFEmpty)) {
- // still ok
- } else if((pflag & CFInter)
- //&&(!(RFLAG(level, i,j,k, workSet)& CFNoNbFluid))
- ) {
- // add to no nb fluid i.f.'s, so skip if interface with fluid nb
- } else if(pflag & (CFFluid|CFUnused|CFInter) ){ // interface cells ignored here due to previous check!
- // add dropmass again, (these are only interf. with nonbfl.)
- int oi= (int)(pos[0]-1.25*v[0]+0.5);
- int oj= (int)(pos[1]-1.25*v[1]+0.5);
- int ok= (int)(pos[2]-1.25*v[2]+0.5);
- const LbmFloat size = p->getSize();
- const LbmFloat dropmass = ParticleObject::getMass(mPartDropMassSub*size);
- bool orgcellok = false;
- if( (oi<0)||(oi>mSizex-1)||
- (oj<0)||(oj>mSizey-1)||
- (ok<0)||(ok>mSizez-1) ) {
- // org cell not ok!
- } else if( RFLAG(level, oi,oj,ok, workSet) & (CFInter) ){
- orgcellok = true;
- } else {
- // search upward for interface
- oi=i; oj=j; ok=k;
- for(int kk=0; kk<5 && ok<=mSizez-2; kk++) {
- ok++; // check sizez-2 due to this increment!
- if( RFLAG(level, oi,oj,ok, workSet) & (CFInter) ){
- kk = 5; orgcellok = true;
- }
- }
- }
-
- //errMsg("PTIMPULSE"," new v"<<v<<" at "<<PRINT_VEC(oi,oj,ok)<<" , was "<<PRINT_VEC(i,j,k)<<" ok "<<orgcellok );
- if(orgcellok) {
- QCELL(level, oi,oj,ok, workSet, dMass) += dropmass;
- QCELL(level, oi,oj,ok, workSet, dFfrac) += dropmass; // assume rho=1?
-
- if(RFLAG(level, oi,oj,ok, workSet) & CFNoBndFluid){
- // check speed, perhaps normalize
- gfxReal vlensqr = normNoSqrt(v);
- if(vlensqr > 0.166*0.166) {
- v *= 1./sqrtf((float)vlensqr)*0.166;
- }
- // compute cell velocity
- LbmFloat *tcel = RACPNT(level, oi,oj,ok, workSet);
- LbmFloat velUx=0., velUy=0., velUz=0.;
- FORDF0 {
- velUx += (this->dfDvecX[l]*RAC(tcel,l));
- velUy += (this->dfDvecY[l]*RAC(tcel,l));
- velUz += (this->dfDvecZ[l]*RAC(tcel,l));
- }
- // add impulse
- /*
- LbmFloat cellVelSqr = velUx*velUx+ velUy*velUy+ velUz*velUz;
- //errMsg("PTIMPULSE"," new v"<<v<<" cvs"<<cellVelSqr<<"="<<sqrt(cellVelSqr));
- if(cellVelSqr< 0.166*0.166) {
- FORDF1 {
- const LbmFloat add = 3. * dropmass * this->dfLength[l]*(v[0]*this->dfDvecX[l]+v[1]*this->dfDvecY[l]+v[2]*this->dfDvecZ[l]);
- RAC(tcel,l) += add;
- } } // */
- } // only add impulse away from obstacles!
- } // orgcellok
-
- // FIXME make fsgr treatment
- P_CHANGETYPE(p, PART_FLOAT ); continue;
- // jitter in cell to prevent stacking when hitting a steep surface
- ntlVec3Gfx cpos = p->getPos();
- cpos[0] += (rand()/(RAND_MAX+1.0))-0.5;
- cpos[1] += (rand()/(RAND_MAX+1.0))-0.5;
- cpos[2] += (rand()/(RAND_MAX+1.0))-0.5;
- p->setPos(cpos);
- } else {
- DEL_PART;
- this->mNumParticlesLost++;
- }
- }
- } else { // OUT
-# if LBM_INCLUDE_TESTSOLVERS==1
- if(useff) { mpTest->handleParticle(p, i,j,k); }
- else{ DEL_PART; }
-# else // LBM_INCLUDE_TESTSOLVERS==1
- DEL_PART;
-# endif // LBM_INCLUDE_TESTSOLVERS==1
- }
-
- } // air particle
-
- // inter particle
- else if(p->getType()==PART_INTER) {
- // unused!?
- if(p->getStatus()&PART_IN) { // IN
- if((k<cutval)||(k>mSizez-1-cutval)) {
- // undecided particle above or below... remove?
- DEL_PART;
- }
-
- CellFlagType pflag = RFLAG(level, i,j,k, workSet);
- if(pflag& CFInter ) {
- // still ok
- } else if(pflag& (CFFluid|CFUnused) ) {
- P_CHANGETYPE(p, PART_FLOAT ); continue;
- } else if(pflag& CFEmpty ) {
- P_CHANGETYPE(p, PART_DROP ); continue;
- } else if(pflag& CFBnd ) {
- P_CHANGETYPE(p, PART_FLOAT ); continue;
- }
- } else { // OUT
- // undecided particle outside... remove?
- DEL_PART;
- }
- }
-
- // float particle
- else if(p->getType()==PART_FLOAT) {
-
- if(p->getStatus()&PART_IN) { // IN
- if(k<cutval) DEL_PART;
- // not valid for mass...
- vx = vy = vz = 0.0;
-
- // define from particletracer.h
-#if MOVE_FLOATS==1
- const int DEPTH_AVG=3; // only average interface vels
- int ccnt=0;
- for(int kk=0;kk<DEPTH_AVG;kk+=1) {
- if((k-kk)<1) continue;
- if(RFLAG(level, i,j,k, workSet)&(CFInter)) {} else continue;
- ccnt++;
- FORDF1{
- LbmFloat cdf = QCELL(level, i,j,k-kk, workSet, l);
- vx += (this->dfDvecX[l]*cdf);
- vy += (this->dfDvecY[l]*cdf);
- vz += (this->dfDvecZ[l]*cdf);
- }
- }
- if(ccnt) {
- // use halved surface velocity (todo, use omega instead)
- vx /=(LbmFloat)(ccnt * 2.0); // half xy speed! value2
- vy /=(LbmFloat)(ccnt * 2.0);
- vz /=(LbmFloat)(ccnt); }
-#else // MOVE_FLOATS==1
- vx=vy=0.; //p->setVel(ntlVec3Gfx(0.) ); // static_float
-#endif // MOVE_FLOATS==1
- vx += (rand()/(RAND_MAX+1.0))*(FLOAT_JITTER*0.2)-(FLOAT_JITTER*0.2*0.5);
- vy += (rand()/(RAND_MAX+1.0))*(FLOAT_JITTER*0.2)-(FLOAT_JITTER*0.2*0.5);
-
- //bool delfloat = false;
- if( ( RFLAG(level, i,j,k, workSet)& (CFFluid|CFUnused) ) ) {
- // in fluid cell
- vz = p->getVel()[2]-1.0*mLevel[level].gravity[2]; // simply rise...
- if(vz<0.) vz=0.;
- } else if( ( RFLAG(level, i,j,k, workSet)& CFBnd ) ) {
- // force downwards movement, move below obstacle...
- //vz = p->getVel()[2]+1.0*mLevel[level].gravity[2]; // fall...
- //if(vz>0.) vz=0.;
- DEL_PART;
- } else if( ( RFLAG(level, i,j,k, workSet)& CFInter ) ) {
- // keep in interface , one grid cell offset is added in part. gen
- } else { // all else...
- if( ( RFLAG(level, i,j,k-1, workSet)& (CFFluid|CFInter) ) ) {
- vz = p->getVel()[2]+2.0*mLevel[level].gravity[2]; // fall...
- if(vz>0.) vz=0.; }
- else { DEL_PART; }
- }
-
- p->setVel( vec2G( ntlVec3Gfx(vx,vy,vz) ) ); //?
- p->advanceVel();
- } else {
-#if LBM_INCLUDE_TESTSOLVERS==1
- if(useff) { mpTest->handleParticle(p, i,j,k); }
- else DEL_PART;
-#else // LBM_INCLUDE_TESTSOLVERS==1
- DEL_PART;
-#endif // LBM_INCLUDE_TESTSOLVERS==1
- }
-
- // additional bnd jitter
- if((0) && (useff) && (p->getLifeTime()<3.*mLevel[level].timestep)) {
- // use half butoff border 1/8
- int maxdw = (int)(mLevel[level].lSizex*0.125*0.5);
- if(maxdw<3) maxdw=3;
- if((j>=0)&&(j<=mSizey-1)) {
- if(ABS(i-( cutval))<maxdw) { p->advance( FLOAT_JITTBNDRAND( ABS(i-( cutval))), 0.,0.); }
- if(ABS(i-(mSizex-1-cutval))<maxdw) { p->advance( FLOAT_JITTBNDRAND( ABS(i-(mSizex-1-cutval))), 0.,0.); }
- }
- }
- } // PART_FLOAT
-
- // unknown particle type
- else {
- errMsg("LbmFsgrSolver::advanceParticles","PIT pit invalid type!? "<<p->getStatus() );
- }
- }
- myTime_t parttend = getTime();
- debMsgStd("LbmFsgrSolver::advanceParticles",DM_MSG,"Time for particle update:"<< getTimeString(parttend-parttstart)<<", #particles:"<<mpParticles->getNumParticles() , 10 );
-}
-
-void LbmFsgrSolver::notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) {
- int workSet = mLevel[mMaxRefine].setCurr;
- std::ostringstream name;
-
- // debug - raw dump of ffrac values, as text!
- if(mDumpRawText) {
- name << outfilename<< frameNrStr <<".dump";
- FILE *file = fopen(name.str().c_str(),"w");
- if(file) {
-
- for(int k= getForZMinBnd(); k< getForZMaxBnd(mMaxRefine); ++k) {
- for(int j=0;j<mLevel[mMaxRefine].lSizey-0;j++) {
- for(int i=0;i<mLevel[mMaxRefine].lSizex-0;i++) {
- float val = 0.;
- if(RFLAG(mMaxRefine, i,j,k, workSet) & CFInter) {
- val = QCELL(mMaxRefine,i,j,k, mLevel[mMaxRefine].setCurr,dFfrac);
- if(val<0.) val=0.;
- if(val>1.) val=1.;
- }
- if(RFLAG(mMaxRefine, i,j,k, workSet) & CFFluid) val = 1.;
- fprintf(file, "%f ",val); // text
- //errMsg("W", PRINT_IJK<<" val:"<<val);
- }
- fprintf(file, "\n"); // text
- }
- fprintf(file, "\n"); // text
- }
- fclose(file);
-
- } // file
- } // */
-
- if(mDumpRawBinary) {
- if(!mDumpRawBinaryZip) {
- // unzipped, only fill
- name << outfilename<< frameNrStr <<".bdump";
- FILE *file = fopen(name.str().c_str(),"w");
- if(file) {
- for(int k= getForZMinBnd(); k< getForZMaxBnd(mMaxRefine); ++k) {
- for(int j=0;j<mLevel[mMaxRefine].lSizey-0;j++) {
- for(int i=0;i<mLevel[mMaxRefine].lSizex-0;i++) {
- float val = 0.;
- if(RFLAG(mMaxRefine, i,j,k, workSet) & CFInter) {
- val = QCELL(mMaxRefine,i,j,k, mLevel[mMaxRefine].setCurr,dFfrac);
- if(val<0.) val=0.;
- if(val>1.) val=1.;
- }
- if(RFLAG(mMaxRefine, i,j,k, workSet) & CFFluid) val = 1.;
- fwrite( &val, sizeof(val), 1, file); // binary
- }
- }
- }
- fclose(file);
- } // file
- } // unzipped
- else {
- // zipped, use iso values
- prepareVisualization();
- name << outfilename<< frameNrStr <<".bdump.gz";
- gzFile gzf = gzopen(name.str().c_str(),"wb9");
- if(gzf) {
- // write size
- int s;
- s=mSizex; gzwrite(gzf, &s, sizeof(s));
- s=mSizey; gzwrite(gzf, &s, sizeof(s));
- s=mSizez; gzwrite(gzf, &s, sizeof(s));
-
- // write isovalues
- for(int k= getForZMinBnd(); k< getForZMaxBnd(mMaxRefine); ++k) {
- for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
- for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
- float val = 0.;
- val = *mpIso->lbmGetData( i,j,k );
- gzwrite(gzf, &val, sizeof(val));
- }
- }
- }
- gzclose(gzf);
- } // gzf
- } // zip
- } // bin dump
-
- dumptype = 0; frameNr = 0; // get rid of warning
-}
-
-/*! move a particle at a boundary */
-void LbmFsgrSolver::handleObstacleParticle(ParticleObject *p) {
- //if(normNoSqrt(v)<=0.) continue; // skip stuck
- /*
- p->setVel( v * -1. ); // revert
- p->advanceVel(); // move back twice...
- if( RFLAG(mMaxRefine, i,j,k, workSet)& (CFBndNoslip)) {
- p->setVel( v * -0.5 ); // revert & dampen
- }
- p->advanceVel();
- // */
- // TODO mark/remove stuck parts!?
-
- const int level = mMaxRefine;
- const int workSet = mLevel[level].setCurr;
- LbmVec v = vec2L( p->getVel() );
- if(normNoSqrt(v)<=0.) {
- p->setVel(vec2G(mLevel[level].gravity));
- }
-
- CellFlagType pflag = CFBnd;
- ntlVec3Gfx posOrg(p->getPos());
- ntlVec3Gfx npos(0.);
- int ni=1,nj=1,nk=1;
- int tries = 0;
-
- // try to undo movement
- p->advanceVec( (p->getVel()-vec2G(mLevel[level].gravity)) * -2.);
-
- npos = p->getPos(); ni= (int)npos[0];
- nj= (int)npos[1]; nk= (int)npos[2];
- if(LBMDIM==2) { nk = 0; }
- //errMsg("BOUNDCPAR"," t"<<PRINT_VEC(ni,nj,nk)<<" v"<<v<<" p"<<npos);
-
- // delete out of domain
- if(!checkDomainBounds(level,ni,nj,nk)) {
- //errMsg("BOUNDCPAR"," DEL! ");
- p->setActive( false );
- return;
- }
- pflag = RFLAG(level, ni,nj,nk, workSet);
-
- // try to force particle out of boundary
- bool haveNorm = false;
- LbmVec bnormal;
- if(pflag&CFBnd) {
- npos = posOrg; ni= (int)npos[0];
- nj= (int)npos[1]; nk= (int)npos[2];
- if(LBMDIM==2) { nk = 0; }
-
- computeObstacleSurfaceNormalAcc(ni,nj,nk, &bnormal[0]);
- haveNorm = true;
- normalize(bnormal);
- bnormal *= 0.25;
-
- tries = 1;
- while(pflag&CFBnd && tries<=5) {
- // use increasing step sizes
- p->advanceVec( vec2G( bnormal *0.5 *(gfxReal)tries ) );
- npos = p->getPos();
- ni= (int)npos[0];
- nj= (int)npos[1];
- nk= (int)npos[2];
-
- // delete out of domain
- if(!checkDomainBounds(level,ni,nj,nk)) {
- //errMsg("BOUNDCPAR"," DEL! ");
- p->setActive( false );
- return;
- }
- pflag = RFLAG(level, ni,nj,nk, workSet);
- tries++;
- }
-
- // really stuck, delete...
- if(pflag&CFBnd) {
- p->setActive( false );
- return;
- }
- }
-
- // not in bound anymore!
- if(!haveNorm) {
- CellFlagType *bflag = &RFLAG(level, ni,nj,nk, workSet);
- LbmFloat *bcell = RACPNT(level, ni,nj,nk, workSet);
- computeObstacleSurfaceNormal(bcell,bflag, &bnormal[0]);
- }
- normalize(bnormal);
- LbmVec normComp = bnormal * dot(vec2L(v),bnormal);
- //errMsg("BOUNDCPAR","bnormal"<<bnormal<<" normComp"<<normComp<<" newv"<<(v-normComp) );
- v = (v-normComp)*0.9; // only move tangential
- v *= 0.9; // restdamping , todo use timestep
- p->setVel(vec2G(v));
- p->advanceVel();
-}
-
-/*****************************************************************************/
-/*! internal quick print function (for debugging) */
-/*****************************************************************************/
-void
-LbmFsgrSolver::printLbmCell(int level, int i, int j, int k, int set) {
- stdCellId *newcid = new stdCellId;
- newcid->level = level;
- newcid->x = i;
- newcid->y = j;
- newcid->z = k;
-
- // this function is not called upon clicking, then its from setMouseClick
- debugPrintNodeInfo( newcid, set );
- delete newcid;
-}
-void
-LbmFsgrSolver::debugMarkCellCall(int level, int vi,int vj,int vk) {
- stdCellId *newcid = new stdCellId;
- newcid->level = level;
- newcid->x = vi;
- newcid->y = vj;
- newcid->z = vk;
- this->addCellToMarkedList( newcid );
-}
-
-
-/*****************************************************************************/
-// implement CellIterator<UniformFsgrCellIdentifier> interface
-/*****************************************************************************/
-
-
-
-// values from guiflkt.cpp
-extern double guiRoiSX, guiRoiSY, guiRoiSZ, guiRoiEX, guiRoiEY, guiRoiEZ;
-extern int guiRoiMaxLev, guiRoiMinLev;
-#define CID_SX (int)( (mLevel[cid->level].lSizex-1) * guiRoiSX )
-#define CID_SY (int)( (mLevel[cid->level].lSizey-1) * guiRoiSY )
-#define CID_SZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiSZ )
-
-#define CID_EX (int)( (mLevel[cid->level].lSizex-1) * guiRoiEX )
-#define CID_EY (int)( (mLevel[cid->level].lSizey-1) * guiRoiEY )
-#define CID_EZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiEZ )
-
-CellIdentifierInterface*
-LbmFsgrSolver::getFirstCell( ) {
- int level = mMaxRefine;
-
-#if LBMDIM==3
- if(mMaxRefine>0) { level = mMaxRefine-1; } // NO1HIGHESTLEV DEBUG
-#endif
- level = guiRoiMaxLev;
- if(level>mMaxRefine) level = mMaxRefine;
-
- //errMsg("LbmFsgrSolver::getFirstCell","Celliteration started...");
- stdCellId *cid = new stdCellId;
- cid->level = level;
- cid->x = CID_SX;
- cid->y = CID_SY;
- cid->z = CID_SZ;
- return cid;
-}
-
-LbmFsgrSolver::stdCellId*
-LbmFsgrSolver::convertBaseCidToStdCid( CellIdentifierInterface* basecid) {
- //stdCellId *cid = dynamic_cast<stdCellId*>( basecid );
- stdCellId *cid = (stdCellId*)( basecid );
- return cid;
-}
-
-void LbmFsgrSolver::advanceCell( CellIdentifierInterface* basecid) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- if(cid->getEnd()) return;
-
- //debugOut(" ADb "<<cid->x<<","<<cid->y<<","<<cid->z<<" e"<<cid->getEnd(), 10);
- cid->x++;
- if(cid->x > CID_EX){ cid->x = CID_SX; cid->y++;
- if(cid->y > CID_EY){ cid->y = CID_SY; cid->z++;
- if(cid->z > CID_EZ){
- cid->level--;
- cid->x = CID_SX;
- cid->y = CID_SY;
- cid->z = CID_SZ;
- if(cid->level < guiRoiMinLev) {
- cid->level = guiRoiMaxLev;
- cid->setEnd( true );
- }
- }
- }
- }
- //debugOut(" ADa "<<cid->x<<","<<cid->y<<","<<cid->z<<" e"<<cid->getEnd(), 10);
-}
-
-bool LbmFsgrSolver::noEndCell( CellIdentifierInterface* basecid) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return (!cid->getEnd());
-}
-
-void LbmFsgrSolver::deleteCellIterator( CellIdentifierInterface** cid ) {
- delete *cid;
- *cid = NULL;
-}
-
-CellIdentifierInterface* LbmFsgrSolver::getCellAt( ntlVec3Gfx pos ) {
- //int cellok = false;
- pos -= (this->mvGeoStart);
-
- LbmFloat mmaxsize = mLevel[mMaxRefine].nodeSize;
- for(int level=mMaxRefine; level>=0; level--) { // finest first
- //for(int level=0; level<=mMaxRefine; level++) { // coarsest first
- LbmFloat nsize = mLevel[level].nodeSize;
- int x,y,z;
- // CHECK +- maxsize?
- x = (int)((pos[0]+0.5*mmaxsize) / nsize );
- y = (int)((pos[1]+0.5*mmaxsize) / nsize );
- z = (int)((pos[2]+0.5*mmaxsize) / nsize );
- if(LBMDIM==2) z = 0;
-
- // double check...
- if(x<0) continue;
- if(y<0) continue;
- if(z<0) continue;
- if(x>=mLevel[level].lSizex) continue;
- if(y>=mLevel[level].lSizey) continue;
- if(z>=mLevel[level].lSizez) continue;
-
- // return fluid/if/border cells
- if( ( (RFLAG(level, x,y,z, mLevel[level].setCurr)&(CFUnused)) ) ||
- ( (level<mMaxRefine) && (RFLAG(level, x,y,z, mLevel[level].setCurr)&(CFUnused|CFEmpty)) ) ) {
- continue;
- } // */
-
- stdCellId *newcid = new stdCellId;
- newcid->level = level;
- newcid->x = x;
- newcid->y = y;
- newcid->z = z;
- //errMsg("cellAt",this->mName<<" "<<pos<<" l"<<level<<":"<<x<<","<<y<<","<<z<<" "<<convertCellFlagType2String(RFLAG(level, x,y,z, mLevel[level].setCurr)) );
- return newcid;
- }
-
- return NULL;
-}
-
-
-// INFO functions
-
-int LbmFsgrSolver::getCellSet ( CellIdentifierInterface* basecid) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return mLevel[cid->level].setCurr;
- //return mLevel[cid->level].setOther;
-}
-
-int LbmFsgrSolver::getCellLevel ( CellIdentifierInterface* basecid) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return cid->level;
-}
-
-ntlVec3Gfx LbmFsgrSolver::getCellOrigin ( CellIdentifierInterface* basecid) {
- ntlVec3Gfx ret;
-
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- ntlVec3Gfx cs( mLevel[cid->level].nodeSize );
- if(LBMDIM==2) { cs[2] = 0.0; }
-
- if(LBMDIM==2) {
- ret =(this->mvGeoStart + ntlVec3Gfx( cid->x *cs[0], cid->y *cs[1], (this->mvGeoEnd[2]-this->mvGeoStart[2])*0.5 )
- + ntlVec3Gfx(0.0,0.0,cs[1]*-0.25)*cid->level )
- +getCellSize(basecid);
- } else {
- ret =(this->mvGeoStart + ntlVec3Gfx( cid->x *cs[0], cid->y *cs[1], cid->z *cs[2] ))
- +getCellSize(basecid);
- }
- return (ret);
-}
-
-ntlVec3Gfx LbmFsgrSolver::getCellSize ( CellIdentifierInterface* basecid) {
- // return half size
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- ntlVec3Gfx retvec( mLevel[cid->level].nodeSize * 0.5 );
- // 2d display as rectangles
- if(LBMDIM==2) { retvec[2] = 0.0; }
- return (retvec);
-}
-
-LbmFloat LbmFsgrSolver::getCellDensity ( CellIdentifierInterface* basecid,int set) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
-
- // skip non-fluid cells
- if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&(CFFluid|CFInter)) {
- // ok go on...
- } else {
- return 0.;
- }
-
- LbmFloat rho = 0.0;
- FORDF0 { rho += QCELL(cid->level, cid->x,cid->y,cid->z, set, l); } // ORG
- return ((rho-1.0) * mLevel[cid->level].simCellSize / mLevel[cid->level].timestep) +1.0; // ORG
- /*if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFInter) { // test
- LbmFloat ux,uy,uz;
- ux=uy=uz= 0.0;
- int lev = cid->level;
- LbmFloat df[27], feqOld[27];
- FORDF0 {
- rho += QCELL(lev, cid->x,cid->y,cid->z, set, l);
- ux += this->dfDvecX[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l);
- uy += this->dfDvecY[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l);
- uz += this->dfDvecZ[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l);
- df[l] = QCELL(lev, cid->x,cid->y,cid->z, set, l);
- }
- FORDF0 {
- feqOld[l] = getCollideEq(l, rho,ux,uy,uz);
- }
- // debugging mods
- //const LbmFloat Qo = this->getLesNoneqTensorCoeff(df,feqOld);
- //const LbmFloat modOmega = this->getLesOmega(mLevel[lev].omega, mLevel[lev].lcsmago,Qo);
- //rho = (2.0-modOmega) *25.0;
- //rho = Qo*100.0;
- //if(cid->x==24){ errMsg("MODOMT"," at "<<PRINT_VEC(cid->x,cid->y,cid->z)<<" = "<<rho<<" "<<Qo); }
- //else{ rho=0.0; }
- } // test
- return rho; // test */
-}
-
-LbmVec LbmFsgrSolver::getCellVelocity ( CellIdentifierInterface* basecid,int set) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
-
- // skip non-fluid cells
- if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&(CFFluid|CFInter)) {
- // ok go on...
- } else {
- return LbmVec(0.0);
- }
-
- LbmFloat ux,uy,uz;
- ux=uy=uz= 0.0;
- FORDF0 {
- ux += this->dfDvecX[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l);
- uy += this->dfDvecY[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l);
- uz += this->dfDvecZ[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l);
- }
- LbmVec vel(ux,uy,uz);
- // TODO fix...
- return (vel * mLevel[cid->level].simCellSize / mLevel[cid->level].timestep * this->mDebugVelScale); // normal
-}
-
-LbmFloat LbmFsgrSolver::getCellDf( CellIdentifierInterface* basecid,int set, int dir) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return QCELL(cid->level, cid->x,cid->y,cid->z, set, dir);
-}
-LbmFloat LbmFsgrSolver::getCellMass( CellIdentifierInterface* basecid,int set) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return QCELL(cid->level, cid->x,cid->y,cid->z, set, dMass);
-}
-LbmFloat LbmFsgrSolver::getCellFill( CellIdentifierInterface* basecid,int set) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFInter) return QCELL(cid->level, cid->x,cid->y,cid->z, set, dFfrac);
- if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFFluid) return 1.0;
- return 0.0;
- //return QCELL(cid->level, cid->x,cid->y,cid->z, set, dFfrac);
-}
-CellFlagType LbmFsgrSolver::getCellFlag( CellIdentifierInterface* basecid,int set) {
- stdCellId *cid = convertBaseCidToStdCid(basecid);
- return RFLAG(cid->level, cid->x,cid->y,cid->z, set);
-}
-
-LbmFloat LbmFsgrSolver::getEquilDf( int l ) {
- return this->dfEquil[l];
-}
-
-
-ntlVec3Gfx LbmFsgrSolver::getVelocityAt (float xp, float yp, float zp) {
- ntlVec3Gfx avgvel(0.0);
- LbmFloat avgnum = 0.;
-
- // taken from getCellAt!
- const int level = mMaxRefine;
- const int workSet = mLevel[level].setCurr;
- const LbmFloat nsize = mLevel[level].nodeSize;
- const int x = (int)((-this->mvGeoStart[0]+xp-0.5*nsize) / nsize );
- const int y = (int)((-this->mvGeoStart[1]+yp-0.5*nsize) / nsize );
- int z = (int)((-this->mvGeoStart[2]+zp-0.5*nsize) / nsize );
- if(LBMDIM==2) z=0;
- //errMsg("DUMPVEL","p"<<PRINT_VEC(xp,yp,zp)<<" at "<<PRINT_VEC(x,y,z)<<" max"<<PRINT_VEC(mLevel[level].lSizex,mLevel[level].lSizey,mLevel[level].lSizez) );
-
- // return fluid/if/border cells
- // search neighborhood, do smoothing
- FORDF0{
- const int i = x+this->dfVecX[l];
- const int j = y+this->dfVecY[l];
- const int k = z+this->dfVecZ[l];
-
- if( (i<0) || (j<0) || (k<0)
- || (i>=mLevel[level].lSizex)
- || (j>=mLevel[level].lSizey)
- || (k>=mLevel[level].lSizez) ) continue;
-
- if( (RFLAG(level, i,j,k, mLevel[level].setCurr)&(CFFluid|CFInter)) ) {
- ntlVec3Gfx vel(0.0);
- LbmFloat *ccel = RACPNT(level, i,j,k ,workSet); // omp
- for(int n=1; n<this->cDfNum; n++) {
- vel[0] += (this->dfDvecX[n]*RAC(ccel,n));
- vel[1] += (this->dfDvecY[n]*RAC(ccel,n));
- vel[2] += (this->dfDvecZ[n]*RAC(ccel,n));
- }
-
- avgvel += vel;
- avgnum += 1.0;
- if(l==0) { // center slightly more weight
- avgvel += vel; avgnum += 1.0;
- }
- } // */
- }
-
- if(avgnum>0.) {
- ntlVec3Gfx retv = avgvel / avgnum;
- retv *= nsize/mLevel[level].timestep;
- // scale for current animation settings (frame time)
- retv *= mpParam->getCurrentAniFrameTime();
- //errMsg("DUMPVEL","t"<<mSimulationTime<<" at "<<PRINT_VEC(xp,yp,zp)<<" ret:"<<retv<<", avgv:"<<avgvel<<" n"<<avgnum<<" nsize"<<nsize<<" ts"<<mLevel[level].timestep<<" fr"<<mpParam->getCurrentAniFrameTime() );
- return retv;
- }
- // no cells here...?
- //errMsg("DUMPVEL"," at "<<PRINT_VEC(xp,yp,zp)<<" v"<<avgvel<<" n"<<avgnum<<" no vel !?");
- return ntlVec3Gfx(0.);
-}
-
-#if LBM_USE_GUI==1
-//! show simulation info (implement SimulationObject pure virtual func)
-void
-LbmFsgrSolver::debugDisplay(int set){
- //lbmDebugDisplay< LbmFsgrSolver >( set, this );
- lbmDebugDisplay( set );
-}
-#endif
-
-/*****************************************************************************/
-// strict debugging functions
-/*****************************************************************************/
-#if FSGR_STRICT_DEBUG==1
-#define STRICT_EXIT *((int *)0)=0;
-
-int LbmFsgrSolver::debLBMGI(int level, int ii,int ij,int ik, int is) {
- if(level < 0){ errMsg("LbmStrict::debLBMGI"," invLev- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(level > mMaxRefine){ errMsg("LbmStrict::debLBMGI"," invLev+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
-
- if((ii==-1)&&(ij==0)) {
- // special case for main loop, ok
- } else {
- if(ii<0){ errMsg("LbmStrict"," invX- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ij<0){ errMsg("LbmStrict"," invY- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ii>mLevel[level].lSizex-1){ errMsg("LbmStrict"," invX+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ij>mLevel[level].lSizey-1){ errMsg("LbmStrict"," invY+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- }
- if(ik<0){ errMsg("LbmStrict"," invZ- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ik>mLevel[level].lSizez-1){ errMsg("LbmStrict"," invZ+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(is<0){ errMsg("LbmStrict"," invS- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(is>1){ errMsg("LbmStrict"," invS+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- return _LBMGI(level, ii,ij,ik, is);
-};
-
-CellFlagType& LbmFsgrSolver::debRFLAG(int level, int xx,int yy,int zz,int set){
- return _RFLAG(level, xx,yy,zz,set);
-};
-
-CellFlagType& LbmFsgrSolver::debRFLAG_NB(int level, int xx,int yy,int zz,int set, int dir) {
- if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- // warning might access all spatial nbs
- if(dir>this->cDirNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- return _RFLAG_NB(level, xx,yy,zz,set, dir);
-};
-
-CellFlagType& LbmFsgrSolver::debRFLAG_NBINV(int level, int xx,int yy,int zz,int set, int dir) {
- if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- if(dir>this->cDirNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- return _RFLAG_NBINV(level, xx,yy,zz,set, dir);
-};
-
-int LbmFsgrSolver::debLBMQI(int level, int ii,int ij,int ik, int is, int l) {
- if(level < 0){ errMsg("LbmStrict::debLBMQI"," invLev- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(level > mMaxRefine){ errMsg("LbmStrict::debLBMQI"," invLev+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
-
- if((ii==-1)&&(ij==0)) {
- // special case for main loop, ok
- } else {
- if(ii<0){ errMsg("LbmStrict"," invX- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ij<0){ errMsg("LbmStrict"," invY- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ii>mLevel[level].lSizex-1){ errMsg("LbmStrict"," invX+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ij>mLevel[level].lSizey-1){ errMsg("LbmStrict"," invY+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- }
- if(ik<0){ errMsg("LbmStrict"," invZ- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(ik>mLevel[level].lSizez-1){ errMsg("LbmStrict"," invZ+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(is<0){ errMsg("LbmStrict"," invS- l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(is>1){ errMsg("LbmStrict"," invS+ l"<<level<<"|"<<ii<<","<<ij<<","<<ik<<" s"<<is); STRICT_EXIT; }
- if(l<0) { errMsg("LbmStrict"," invD- "<<" l"<<l); STRICT_EXIT; }
- if(l>this->cDfNum){ // dFfrac is an exception
- if((l != dMass) && (l != dFfrac) && (l != dFlux)){ errMsg("LbmStrict"," invD+ "<<" l"<<l); STRICT_EXIT; } }
-#if COMPRESSGRIDS==1
- //if((!this->mInitDone) && (is!=mLevel[level].setCurr)){ STRICT_EXIT; } // COMPRT debug
-#endif // COMPRESSGRIDS==1
- return _LBMQI(level, ii,ij,ik, is, l);
-};
-
-LbmFloat& LbmFsgrSolver::debQCELL(int level, int xx,int yy,int zz,int set,int l) {
- //errMsg("LbmStrict","debQCELL debug: l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" l"<<l<<" index"<<LBMGI(level, xx,yy,zz,set));
- return _QCELL(level, xx,yy,zz,set,l);
-};
-
-LbmFloat& LbmFsgrSolver::debQCELL_NB(int level, int xx,int yy,int zz,int set, int dir,int l) {
- if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- if(dir>this->cDfNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- return _QCELL_NB(level, xx,yy,zz,set, dir,l);
-};
-
-LbmFloat& LbmFsgrSolver::debQCELL_NBINV(int level, int xx,int yy,int zz,int set, int dir,int l) {
- if(dir<0) { errMsg("LbmStrict"," invD- l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- if(dir>this->cDfNum){ errMsg("LbmStrict"," invD+ l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" d"<<dir); STRICT_EXIT; }
- return _QCELL_NBINV(level, xx,yy,zz,set, dir,l);
-};
-
-LbmFloat* LbmFsgrSolver::debRACPNT(int level, int ii,int ij,int ik, int is ) {
- return _RACPNT(level, ii,ij,ik, is );
-};
-
-LbmFloat& LbmFsgrSolver::debRAC(LbmFloat* s,int l) {
- if(l<0) { errMsg("LbmStrict"," invD- "<<" l"<<l); STRICT_EXIT; }
- if(l>dTotalNum){ errMsg("LbmStrict"," invD+ "<<" l"<<l); STRICT_EXIT; }
- //if(l>this->cDfNum){ // dFfrac is an exception
- //if((l != dMass) && (l != dFfrac) && (l != dFlux)){ errMsg("LbmStrict"," invD+ "<<" l"<<l); STRICT_EXIT; } }
- return _RAC(s,l);
-};
-
-#endif // FSGR_STRICT_DEBUG==1
-
-
-/******************************************************************************
- * GUI&debugging functions
- *****************************************************************************/
-
-//! display a single node
-void LbmFsgrSolver::debugPrintNodeInfo(CellIdentifierInterface* cell, int forceSet) {
- //string printInfo,
- // force printing of one set? default = -1 = off
- bool printDF = false;
- bool printRho = false;
- bool printVel = false;
- bool printFlag = false;
- bool printGeom = false;
- bool printMass=false;
- bool printBothSets = false;
- string printInfo = this->getNodeInfoString();
-
- for(size_t i=0; i<printInfo.length()-0; i++) {
- char what = printInfo[i];
- switch(what) {
- case '+': // all on
- printDF = true; printRho = true; printVel = true; printFlag = true; printGeom = true; printMass = true ;
- printBothSets = true; break;
- case '-': // all off
- printDF = false; printRho = false; printVel = false; printFlag = false; printGeom = false; printMass = false;
- printBothSets = false; break;
- case 'd': printDF = true; break;
- case 'r': printRho = true; break;
- case 'v': printVel = true; break;
- case 'f': printFlag = true; break;
- case 'g': printGeom = true; break;
- case 'm': printMass = true; break;
- case 's': printBothSets = true; break;
- default:
- errFatal("debugPrintNodeInfo","Invalid node info id "<<what,SIMWORLD_GENERICERROR); return;
- }
- }
-
- ntlVec3Gfx org = this->getCellOrigin( cell );
- ntlVec3Gfx halfsize = this->getCellSize( cell );
- int set = this->getCellSet( cell );
- debMsgStd("debugPrintNodeInfo",DM_NOTIFY, "Printing cell info '"<<printInfo<<"' for node: "<<cell->getAsString()<<" from "<<this->getName()<<" currSet:"<<set , 1);
- if(printGeom) debMsgStd(" ",DM_MSG, "Org:"<<org<<" Halfsize:"<<halfsize<<" ", 1);
-
- int setmax = 2;
- if(!printBothSets) setmax = 1;
- if(forceSet>=0) setmax = 1;
-
- for(int s=0; s<setmax; s++) {
- int workset = set;
- if(s==1){ workset = (set^1); }
- if(forceSet>=0) workset = forceSet;
- debMsgStd(" ",DM_MSG, "Printing set:"<<workset<<" orgSet:"<<set, 1);
-
- if(printDF) {
- for(int l=0; l<LBM_DFNUM; l++) { // FIXME ??
- debMsgStd(" ",DM_MSG, " Df"<<l<<": "<<this->getCellDf(cell,workset,l), 1);
- }
- }
- if(printRho) {
- debMsgStd(" ",DM_MSG, " Rho: "<<this->getCellDensity(cell,workset), 1);
- }
- if(printVel) {
- debMsgStd(" ",DM_MSG, " Vel: "<<this->getCellVelocity(cell,workset), 1);
- }
- if(printFlag) {
- CellFlagType flag = this->getCellFlag(cell,workset);
- debMsgStd(" ",DM_MSG, " Flg: "<< flag<<" "<<convertFlags2String( flag ) <<" "<<convertCellFlagType2String( flag ), 1);
- }
- if(printMass) {
- debMsgStd(" ",DM_MSG, " Mss: "<<this->getCellMass(cell,workset), 1);
- }
- // dirty... TODO fixme
- debMsgStd(" ",DM_MSG, " Flx: "<<this->getCellDf(cell,workset,dFlux), 1);
- }
-}
-
-
diff --git a/intern/elbeem/intern/utilities.cpp b/intern/elbeem/intern/utilities.cpp
deleted file mode 100644
index 40596681b90..00000000000
--- a/intern/elbeem/intern/utilities.cpp
+++ /dev/null
@@ -1,498 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Global C style utility funcions
- *
- *****************************************************************************/
-
-
-#include <iostream>
-#include <sstream>
-#ifdef WIN32
-// for timing
-#include <windows.h>
-#else
-#include <time.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#endif
-
-#include "utilities.h"
-
-#ifndef NOPNG
-#ifdef WIN32
-#include "png.h"
-#else
-#include <png.h>
-#endif
-#endif // NOPNG
-#include <zlib.h>
-
-// global debug level
-#ifdef DEBUG
-int gDebugLevel = DEBUG;
-#else // DEBUG
-int gDebugLevel = 0;
-#endif // DEBUG
-
-// global world state, acces with get/setElbeemState
-int gElbeemState = SIMWORLD_INVALID;
-
-// access global state of elbeem simulator
-void setElbeemState(int set) {
- gElbeemState = set;
-}
-int getElbeemState(void) {
- return gElbeemState;
-}
-int isSimworldOk(void) {
- return (getElbeemState() >=0);
-}
-
-// last error as string, acces with get/setElbeemErrorString
-char gElbeemErrorString[256] = {'-','\0' };
-
-// access elbeem simulator error string
-void setElbeemErrorString(const char* set) {
- strncpy(gElbeemErrorString, set, 256);
-}
-char* getElbeemErrorString(void) { return gElbeemErrorString; }
-
-
-//! for interval debugging output
-myTime_t globalIntervalTime = 0;
-//! color output setting for messages (0==off, else on)
-#ifdef WIN32
-// switch off first call
-#define DEF_globalColorSetting -1
-#else // WIN32
-// linux etc., on by default
-#define DEF_globalColorSetting 1
-#endif // WIN32
-int globalColorSetting = DEF_globalColorSetting; // linux etc., on by default
-int globalFirstEnvCheck = 0;
-void resetGlobalColorSetting() { globalColorSetting = DEF_globalColorSetting; }
-
-// global string for formatting vector output, TODO test!?
-const char *globVecFormatStr = "V[%f,%f,%f]";
-
-
-// global mp on/off switch
-bool glob_mpactive = false;
-// global access to mpi index, for debugging (e.g. in utilities.cpp)
-int glob_mpnum = -1;
-int glob_mpindex = -1;
-int glob_mppn = -1;
-
-
-//-----------------------------------------------------------------------------
-// helper function that converts a string to integer,
-// and returns an alternative value if the conversion fails
-int convertString2Int(const char *str, int alt)
-{
- int val;
- char *endptr;
- bool success=true;
-
- val = strtol(str, &endptr, 10);
- if( (str==endptr) ||
- ((str!=endptr) && (*endptr != '\0')) ) success = false;
-
- if(!success) {
- return alt;
- }
- return val;
-}
-
-//-----------------------------------------------------------------------------
-//! helper function that converts a flag field to a readable integer
-string convertFlags2String(int flags) {
- std::ostringstream ret;
- ret <<"(";
- int max = sizeof(int)*8;
- for(int i=0; i<max; i++) {
- if(flags & (1<<31)) ret <<"1";
- else ret<<"0";
- if(i<max-1) {
- //ret << ",";
- if((i%8)==7) ret << " ";
- }
- flags = flags << 1;
- }
- ret <<")";
- return ret.str();
-}
-
-#ifndef NOPNG
-//-----------------------------------------------------------------------------
-//! write png image
-int writePng(const char *fileName, unsigned char **rowsp, int w, int h)
-{
- // defaults for elbeem
- const int colortype = PNG_COLOR_TYPE_RGBA;
- const int bitdepth = 8;
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- png_bytep *rows = rowsp;
-
- //FILE *fp = fopen(fileName, "wb");
- FILE *fp = NULL;
- string doing = "open for writing";
- if (!(fp = fopen(fileName, "wb"))) goto fail;
-
- if(!png_ptr) {
- doing = "create png write struct";
- if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail;
- }
- if(!info_ptr) {
- doing = "create png info struct";
- if (!(info_ptr = png_create_info_struct(png_ptr))) goto fail;
- }
-
- if (setjmp(png_jmpbuf(png_ptr))) goto fail;
- doing = "init IO";
- png_init_io(png_ptr, fp);
- doing = "write header";
- png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
- doing = "write info";
- png_write_info(png_ptr, info_ptr);
- doing = "write image";
- png_write_image(png_ptr, rows);
- doing = "write end";
- png_write_end(png_ptr, NULL);
- doing = "write destroy structs";
- png_destroy_write_struct(&png_ptr, &info_ptr);
-
- fclose( fp );
- return 0;
-
-fail:
- errMsg("writePng","Write_png: could not "<<doing<<" !");
- if(fp) fclose( fp );
- if(png_ptr || info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
- return -1;
-}
-#else // NOPNG
-// fallback - write ppm
-int writePng(const char *fileName, unsigned char **rowsp, int w, int h)
-{
- gzFile gzf;
- string filentemp(fileName);
- // remove suffix
- if((filentemp.length()>4) && (filentemp[filentemp.length()-4]=='.')) {
- filentemp[filentemp.length()-4] = '\0';
- }
- std::ostringstream filennew;
- filennew << filentemp.c_str();
- filennew << ".ppm.gz";
-
- gzf = gzopen(filennew.str().c_str(), "wb9");
- if(!gzf) goto fail;
-
- gzprintf(gzf,"P6\n%d %d\n255\n",w,h);
- // output binary pixels
- for(int j=0;j<h;j++) {
- for(int i=0;i<h;i++) {
- // remove alpha values
- gzwrite(gzf,&rowsp[j][i*4],3);
- }
- }
-
- gzclose( gzf );
- errMsg("writePng/ppm","Write_png/ppm: wrote to "<<filennew.str()<<".");
- return 0;
-
-fail:
- errMsg("writePng/ppm","Write_png/ppm: could not write to "<<filennew.str()<<" !");
- return -1;
-}
-#endif // NOPNG
-
-
-//-----------------------------------------------------------------------------
-// helper function to determine current time
-myTime_t getTime()
-{
- myTime_t ret = 0;
-#ifdef WIN32
- LARGE_INTEGER liTimerFrequency;
- QueryPerformanceFrequency(&liTimerFrequency);
- LARGE_INTEGER liLastTime;
- QueryPerformanceCounter(&liLastTime);
- ret = (INT)( ((double)liLastTime.QuadPart / liTimerFrequency.QuadPart)*1000 ); // - mFirstTime;
-#else
- struct timeval tv;
- struct timezone tz;
- tz.tz_minuteswest = 0;
- tz.tz_dsttime = 0;
- gettimeofday(&tv,&tz);
- ret = (tv.tv_sec*1000)+(tv.tv_usec/1000); //-mFirstTime;
-#endif
- return (myTime_t)ret;
-}
-//-----------------------------------------------------------------------------
-// convert time to readable string
-string getTimeString(myTime_t usecs) {
- std::ostringstream ret;
- //myTime_t us = usecs % 1000;
- myTime_t ms = (myTime_t)( (double)usecs / (60.0*1000.0) );
- myTime_t ss = (myTime_t)( ((double)usecs / 1000.0) - ((double)ms*60.0) );
- int ps = (int)( ((double)usecs - (double)ss*1000.0)/10.0 );
-
- //ret.setf(ios::showpoint|ios::fixed);
- //ret.precision(5); ret.width(7);
-
- if(ms>0) {
- ret << ms<<"m"<< ss<<"s" ;
- } else {
- if(ps>0) {
- ret << ss<<".";
- if(ps<10) { ret <<"0"; }
- ret <<ps<<"s" ;
- } else {
- ret << ss<<"s" ;
- }
- }
- return ret.str();
-}
-
-//! helper to check if a bounding box was specified in the right way
-bool checkBoundingBox(ntlVec3Gfx s, ntlVec3Gfx e, string checker) {
- if( (s[0]>e[0]) ||
- (s[1]>e[1]) ||
- (s[2]>e[2]) ) {
- errFatal("checkBoundingBox","Check by '"<<checker<<"' for BB "<<s<<":"<<e<<" failed! Aborting...",SIMWORLD_INITERROR);
- return 1;
- }
- return 0;
-}
-
-
-
-//-----------------------------------------------------------------------------
-// debug message output
-
-static string col_black ( "\033[0;30m");
-static string col_dark_gray ( "\033[1;30m");
-static string col_bright_gray ( "\033[0;37m");
-static string col_red ( "\033[0;31m");
-static string col_bright_red ( "\033[1;31m");
-static string col_green ( "\033[0;32m");
-static string col_bright_green ( "\033[1;32m");
-static string col_bright_yellow ( "\033[1;33m");
-static string col_yellow ( "\033[0;33m");
-static string col_cyan ( "\033[0;36m");
-static string col_bright_cyan ( "\033[1;36m");
-static string col_purple ( "\033[0;35m");
-static string col_bright_purple ( "\033[1;35m");
-static string col_neutral ( "\033[0m");
-static string col_std = col_bright_gray;
-
-std::ostringstream globOutstr;
-bool globOutstrForce=false;
-#define DM_NONE 100
-void messageOutputForce(string from) {
- bool org = globOutstrForce;
- globOutstrForce = true;
- messageOutputFunc(from, DM_NONE, "\n", 0);
- globOutstrForce = org;
-}
-
-void messageOutputFunc(string from, int id, string msg, myTime_t interval) {
- // fast skip
- if((id!=DM_FATAL)&&(gDebugLevel<=0)) return;
-
- if(interval>0) {
- myTime_t currTime = getTime();
- if((currTime - globalIntervalTime)>interval) {
- globalIntervalTime = getTime();
- } else {
- return;
- }
- }
-
- // colors off?
- if( (globalColorSetting == -1) || // off for e.g. win32
- ((globalColorSetting==1) && ((id==DM_FATAL)||( getenv("ELBEEM_NOCOLOROUT") )) )
- ) {
- // only reset once
- col_std = col_black = col_dark_gray = col_bright_gray =
- col_red = col_bright_red = col_green =
- col_bright_green = col_bright_yellow =
- col_yellow = col_cyan = col_bright_cyan =
- col_purple = col_bright_purple = col_neutral = "";
- globalColorSetting = 0;
- }
-
- std::ostringstream sout;
- if(id==DM_DIRECT) {
- sout << msg;
- } else {
- sout << col_cyan<< from;
- switch(id) {
- case DM_MSG:
- sout << col_std << " message:";
- break;
- case DM_NOTIFY:
- sout << col_bright_cyan << " note:" << col_std;
- break;
- case DM_IMPORTANT:
- sout << col_yellow << " important:" << col_std;
- break;
- case DM_WARNING:
- sout << col_bright_red << " warning:" << col_std;
- break;
- case DM_ERROR:
- sout << col_red << " error:" << col_red;
- break;
- case DM_FATAL:
- sout << col_red << " fatal("<<gElbeemState<<"):" << col_red;
- break;
- case DM_NONE:
- // only internal debugging msgs
- break;
- default:
- // this shouldnt happen...
- sout << col_red << " --- messageOutputFunc error: invalid id ("<<id<<") --- aborting... \n\n" << col_std;
- break;
- }
- sout <<" "<< msg << col_std;
- }
-
- if(id==DM_FATAL) {
- strncpy(gElbeemErrorString,sout.str().c_str(), 256);
- // dont print?
- if(gDebugLevel==0) return;
- sout << "\n"; // add newline for output
- }
-
- // determine output - file==1/stdout==0 / globstr==2
- char filen[256];
- strcpy(filen,"debug_unini.txt");
- int fileout = false;
-#if ELBEEM_MPI==1
- std::ostringstream mpin;
- if(glob_mpindex>=0) {
- mpin << "elbeem_log_"<< glob_mpindex <<".txt";
- } else {
- mpin << "elbeem_log_ini.txt";
- }
- fileout = 1;
- strncpy(filen, mpin.str().c_str(),255); filen[255]='\0';
-#else
- strncpy(filen, "elbeem_debug_log.txt",255);
-#endif
-
-#ifdef WIN32
- // windows causes trouble with direct output
- fileout = 1;
-#endif // WIN32
-
-#if PARALLEL==1
- fileout = 2;// buffer out, switch off again...
- if(globOutstrForce) fileout=1;
-#endif
- if(getenv("ELBEEM_FORCESTDOUT")) {
- fileout = 0;// always direct out
- }
- //fprintf(stdout,"out deb %d, %d, '%s',l%d \n",globOutstrForce,fileout, filen, globOutstr.str().size() );
-
-#if PARALLEL==1
-#pragma omp critical
-#endif // PARALLEL==1
- {
- if(fileout==1) {
- // debug level is >0 anyway, so write to file...
- FILE *logf = fopen(filen,"a+");
- // dont complain anymore here...
- if(logf) {
- if(globOutstrForce) {
- fprintf(logf, "%s",globOutstr.str().c_str() );
- globOutstr.str(""); // reset
- }
- fprintf(logf, "%s",sout.str().c_str() );
- fclose(logf);
- }
- } else if(fileout==2) {
- globOutstr << sout.str();
- } else {
- // normal stdout output
- fprintf(stdout, "%s",sout.str().c_str() );
- if(id!=DM_DIRECT) fflush(stdout);
- }
- } // omp crit
-}
-
-// helper functions from external program using elbeem lib (e.g. Blender)
-/* set gDebugLevel according to env. var */
-extern "C"
-void elbeemCheckDebugEnv(void) {
- const char *strEnvName = "BLENDER_ELBEEMDEBUG";
- const char *strEnvName2 = "ELBEEM_DEBUGLEVEL";
- if(globalFirstEnvCheck) return;
-
- if(getenv(strEnvName)) {
- gDebugLevel = atoi(getenv(strEnvName));
- if(gDebugLevel>0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<<strEnvName<<"'='"<<getenv(strEnvName)<<"', debugLevel set to: "<<gDebugLevel<<"\n", 1);
- }
- if(getenv(strEnvName2)) {
- gDebugLevel = atoi(getenv(strEnvName2));
- if(gDebugLevel>0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<<strEnvName2<<"'='"<<getenv(strEnvName2)<<"', debugLevel set to: "<<gDebugLevel<<"\n", 1);
- }
- if(gDebugLevel< 0) gDebugLevel = 0;
- if(gDebugLevel>10) gDebugLevel = 0; // only use valid values
- globalFirstEnvCheck = 1;
-}
-
-/* elbeem debug output function */
-extern "C"
-void elbeemDebugOut(char *msg) {
- elbeemCheckDebugEnv();
- // external messages default to debug level 5...
- if(gDebugLevel<5) return;
- // delegate to messageOutputFunc
- messageOutputFunc("[External]",DM_MSG,msg,0);
-}
-
-/* set elbeem debug output level (0=off to 10=full on) */
-extern "C"
-void elbeemSetDebugLevel(int level) {
- if(level<0) level=0;
- if(level>10) level=10;
- gDebugLevel=level;
-}
-
-
-/* estimate how much memory a given setup will require */
-#include "solver_interface.h"
-
-extern "C"
-double elbeemEstimateMemreq(int res,
- float sx, float sy, float sz,
- int refine, char *retstr) {
- int resx = res, resy = res, resz = res;
- // dont use real coords, just place from 0.0 to sizeXYZ
- ntlVec3Gfx vgs(0.0), vge(sx,sy,sz);
- initGridSizes( resx,resy,resz, vgs,vge, refine, 0);
-
- double memreq = -1.0;
- string memreqStr("");
- // ignore farfield for now...
- calculateMemreqEstimate(resx,resy,resz, refine, 0., &memreq, NULL, &memreqStr );
-
- if(retstr) {
- // copy at max. 32 characters
- strncpy(retstr, memreqStr.c_str(), 32 );
- retstr[31] = '\0';
- }
- return memreq;
-}
-
-
-
diff --git a/intern/elbeem/intern/utilities.h b/intern/elbeem/intern/utilities.h
deleted file mode 100644
index 274862b93b4..00000000000
--- a/intern/elbeem/intern/utilities.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/** \file
- * \ingroup elbeem
- */
-/******************************************************************************
- *
- * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
- * Copyright 2003-2006 Nils Thuerey
- *
- * Global C style utility funcions
- *
- *****************************************************************************/
-#ifndef UTILITIES_H
-#include "ntl_vector3dim.h"
-
-
-/* debugging outputs , debug level 0 (off) to 10 (max) */
-#ifdef ELBEEM_PLUGIN
-#ifdef DEBUG
-#undef DEBUG
-#endif
-#define DEBUG 0
-#else // ELBEEM_PLUGIN
-#define DEBUG 10
-#endif // ELBEEM_PLUGIN
-extern "C" int gDebugLevel;
-
-
-// time measurements
-typedef unsigned long myTime_t;
-
-
-// state of the simulation world
-// default
-#define SIMWORLD_INVALID 0
-// performing init
-#define SIMWORLD_INITIALIZING 1
-// after init, before starting simulation
-#define SIMWORLD_INITED 2
-// stop of the simulation run, can be continued later
-#define SIMWORLD_STOP 3
-// error during init
-#define SIMWORLD_INITERROR -1
-// error during simulation
-#define SIMWORLD_PANIC -2
-// general error
-#define SIMWORLD_GENERICERROR -3
-
-// access global state of elbeem simulator
-void setElbeemState(int set);
-int getElbeemState(void);
-int isSimworldOk(void);
-
-// access elbeem simulator error string
-void setElbeemErrorString(const char* set);
-char* getElbeemErrorString(void);
-
-
-/* debug output function */
-#define DM_MSG 1
-#define DM_NOTIFY 2
-#define DM_IMPORTANT 3
-#define DM_WARNING 4
-#define DM_ERROR 5
-#define DM_DIRECT 6
-#define DM_FATAL 7
-void messageOutputFunc(string from, int id, string msg, myTime_t interval);
-
-/* debugging messages defines */
-#ifdef DEBUG
-#if LBM_PRECISION==2
-#define MSGSTREAM std::ostringstream msg; msg.precision(15); msg.width(17);
-#else
-#define MSGSTREAM std::ostringstream msg; msg.precision(7); msg.width(9);
-#endif
-
-# define debMsgDirect(mStr) if(gDebugLevel>0) { std::ostringstream msg; msg << mStr; messageOutputFunc(string(""), DM_DIRECT, msg.str(), 0); }
-# define debMsgStd(from,id,mStr,level) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, id, msg.str(), 0); }
-# define debMsgNnl(from,id,mStr,level) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr ; messageOutputFunc(from, id, msg.str(), 0); }
-# define debMsgInter(from,id,mStr,level, interval) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, id, msg.str(), interval); }
-# define debugOut(mStr,level) if(gDebugLevel>=level) { debMsgStd("D",DM_MSG,mStr,level); }
-# define debugOutNnl(mStr,level) if(gDebugLevel>=level) { debMsgNnl("D",DM_MSG,mStr,level); }
-# define debugOutInter(mStr,level, interval) debMsgInter("D",DM_MSG ,mStr,level, interval);
-/* Error output function */
-#define errMsg(from,mStr) if(gDebugLevel>0){ MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, DM_ERROR, msg.str(), 0); }
-#define warnMsg(from,mStr) if(gDebugLevel>0){ MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, DM_WARNING, msg.str(), 0); }
-
-#else
-// no messages at all...
-# define debMsgDirect(mStr)
-# define debMsgStd(from,id,mStr,level)
-# define debMsgNnl(from,id,mStr,level)
-# define debMsgInter(from,id,mStr,level, interval)
-# define debugOut(mStr,level)
-# define debugOutNnl(mStr,level)
-# define debugOutInter(mStr,level, interval)
-# define errMsg(from,mStr)
-# define warnMsg(from,mStr)
-#endif
-
-#define errorOut(mStr) { errMsg("D",mStr); }
-
-// fatal errors - have to be handled
-#define errFatal(from,mStr,errCode) { \
- setElbeemState(errCode); \
- MSGSTREAM; msg << mStr; \
- messageOutputFunc(from, DM_FATAL, msg.str(), 0); \
-}
-
-
-//! helper function that converts a string to integer
-int convertString2Int(const char *str, int alt);
-
-//! helper function that converts a flag field to a readable integer
-string convertFlags2String(int flags);
-
-//! get the current system time
-myTime_t getTime();
-//! convert time to readable string
-string getTimeString(myTime_t usecs);
-
-//! helper to check if a bounding box was specified in the right way
-bool checkBoundingBox(ntlVec3Gfx s, ntlVec3Gfx e, string checker);
-
-//! reset color output for elbeem init
-void resetGlobalColorSetting();
-
-
-/*! print some vector from 3 values e.g. for ux,uy,uz */
-#define PRINT_VEC(x,y,z) " ["<<(x)<<","<<(y)<<","<<(z)<<"] "
-
-/*! print some vector from 3 values e.g. for ux,uy,uz */
-#define PRINT_VEC2D(x,y) " ["<<(x)<<","<<(y)<<"] "
-
-/*! print l'th neighbor of i,j,k as a vector, as we need ijk all the time */
-#define PRINT_IJK_NBL PRINT_VEC(i+D::dfVecX[l],j+D::dfVecY[l],k+D::dfVecZ[l])
-
-/*! print i,j,k as a vector, as we need ijk all the time */
-#define PRINT_IJK PRINT_VEC(i,j,k)
-
-/*! print i,j,k as a vector, as we need ijk all the time */
-#define PRINT_IJ PRINT_VEC2D(i,j)
-
-/*! print some vector from 3 values e.g. for ux,uy,uz */
-#define PRINT_NTLVEC(v) " ["<<(v)[0]<<","<<(v)[1]<<","<<(v)[2]<<"] "
-
-/*! print some vector from 3 values e.g. for ux,uy,uz */
-#define PRINT_NTLVEC2D(v) " ["<<(v)[0]<<","<<(v)[1]<<"] "
-
-/*! print a triangle */
-#define PRINT_TRIANGLE(t,mpV) " { "<<PRINT_VEC( (mpV[(t).getPoints()[0]][0]),(mpV[(t).getPoints()[0]][1]),(mpV[(t).getPoints()[0]][2]) )<<\
- PRINT_VEC( (mpV[(t).getPoints()[1]][0]),(mpV[(t).getPoints()[1]][1]),(mpV[(t).getPoints()[1]][2]) )<<" | "<<\
- PRINT_VEC( (mpV[(t).getPoints()[2]][0]),(mpV[(t).getPoints()[2]][1]),(mpV[(t).getPoints()[2]][2]) )<<" } "
-
-
-// write png image
-int writePng(const char *fileName, unsigned char **rowsp, int w, int h);
-
-/* some useful templated functions
- * may require some operators for the classes
- */
-
-/* minimum */
-#ifdef MIN
-#undef MIN
-#endif
-template < class T >
-inline T
-MIN( T a, T b )
-{ return (a < b) ? a : b ; }
-
-/* maximum */
-#ifdef MAX
-#undef MAX
-#endif
-template < class T >
-inline T
-MAX( T a, T b )
-{ return (a < b) ? b : a ; }
-
-/* sign of the value */
-template < class T >
-inline T
-SIGNUM( T a )
-{ return (0 < a) ? 1 : -1 ; }
-
-/* sign, returns -1,0,1 depending on sign/value=0 */
-template < class T >
-inline T
-SIGNUM0( T a )
-{ return (0 < a) ? 1 : ( a < 0 ? -1 : 0 ) ; }
-
-/* round to nearest integer */
-inline int
-ROUND(double d)
-{ return int(d + 0.5); }
-
-/* square function */
-template < class T >
-inline T
-SQUARE( T a )
-{ return a*a; }
-
-
-#define UTILITIES_H
-#endif
diff --git a/intern/mantaflow/CMakeLists.txt b/intern/mantaflow/CMakeLists.txt
new file mode 100644
index 00000000000..116bd60749a
--- /dev/null
+++ b/intern/mantaflow/CMakeLists.txt
@@ -0,0 +1,241 @@
+# ***** 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.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Sebastian Barschkis (sebbas)
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(MANTAVERSION "0.12")
+
+set(MANTA_DEP
+ intern/manta_develop/dependencies
+)
+set(MANTA_HLP
+ intern/manta_develop/helper
+)
+set(MANTA_PP
+ intern/manta_develop/preprocessed/tbb
+)
+add_definitions(-DTBB=1)
+
+if(WITH_OPENMP AND WITH_MANTA_OMP)
+ set(MANTA_PP
+ intern/manta_develop/preprocessed/omp
+ )
+ add_definitions(-DOPENMP=1)
+endif()
+
+if(WITH_OPENVDB)
+ add_definitions(-DOPENVDB=1)
+endif()
+
+set(INC
+ extern
+ intern/strings
+ ${MANTA_PP}
+ ${MANTA_PP}/fileio
+ ${MANTA_PP}/python
+ ${MANTA_PP}/plugin
+ ${MANTA_HLP}/pwrapper
+ ${MANTA_HLP}/util
+ ${MANTA_DEP}/cnpy
+ ../../source/blender/makesdna
+ ../../source/blender/blenlib
+)
+
+if(WITH_PYTHON)
+ add_definitions(-DWITH_PYTHON)
+endif()
+
+set(INC_SYS
+ ${PYTHON_INCLUDE_DIRS}
+ ${ZLIB_INCLUDE_DIRS}
+ ${TBB_INCLUDE_DIRS}
+)
+
+if(WITH_OPENVDB)
+ list(APPEND INC_SYS
+ ${BOOST_INCLUDE_DIR}
+ ${OPENEXR_INCLUDE_DIRS}
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+endif()
+
+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
+
+ ${MANTA_DEP}/cnpy/cnpy.cpp
+ ${MANTA_DEP}/cnpy/cnpy.h
+
+ ${MANTA_PP}/commonkernels.h
+ ${MANTA_PP}/commonkernels.h.reg
+ ${MANTA_PP}/commonkernels.h.reg.cpp
+ ${MANTA_PP}/conjugategrad.cpp
+ ${MANTA_PP}/conjugategrad.h
+ ${MANTA_PP}/conjugategrad.h.reg
+ ${MANTA_PP}/conjugategrad.h.reg.cpp
+ ${MANTA_PP}/edgecollapse.cpp
+ ${MANTA_PP}/edgecollapse.h
+ ${MANTA_PP}/edgecollapse.h.reg
+ ${MANTA_PP}/edgecollapse.h.reg.cpp
+ ${MANTA_PP}/fastmarch.cpp
+ ${MANTA_PP}/fastmarch.h
+ ${MANTA_PP}/fastmarch.h.reg
+ ${MANTA_PP}/fastmarch.h.reg.cpp
+ ${MANTA_PP}/fileio/iogrids.cpp
+ ${MANTA_PP}/fileio/iomeshes.cpp
+ ${MANTA_PP}/fileio/ioparticles.cpp
+ ${MANTA_PP}/fileio/mantaio.h
+ ${MANTA_PP}/fileio/mantaio.h.reg
+ ${MANTA_PP}/fileio/mantaio.h.reg.cpp
+ ${MANTA_PP}/fluidsolver.cpp
+ ${MANTA_PP}/fluidsolver.h
+ ${MANTA_PP}/fluidsolver.h.reg
+ ${MANTA_PP}/fluidsolver.h.reg.cpp
+ ${MANTA_PP}/general.cpp
+ ${MANTA_PP}/general.h
+ ${MANTA_PP}/general.h.reg
+ ${MANTA_PP}/general.h.reg.cpp
+ ${MANTA_PP}/gitinfo.h
+ ${MANTA_PP}/grid.cpp
+ ${MANTA_PP}/grid.h
+ ${MANTA_PP}/grid.h.reg
+ ${MANTA_PP}/grid.h.reg.cpp
+ ${MANTA_PP}/grid4d.cpp
+ ${MANTA_PP}/grid4d.h
+ ${MANTA_PP}/grid4d.h.reg
+ ${MANTA_PP}/grid4d.h.reg.cpp
+ ${MANTA_PP}/kernel.cpp
+ ${MANTA_PP}/kernel.h
+ ${MANTA_PP}/kernel.h.reg
+ ${MANTA_PP}/kernel.h.reg.cpp
+ ${MANTA_PP}/levelset.cpp
+ ${MANTA_PP}/levelset.h
+ ${MANTA_PP}/levelset.h.reg
+ ${MANTA_PP}/levelset.h.reg.cpp
+ ${MANTA_PP}/mesh.cpp
+ ${MANTA_PP}/mesh.h
+ ${MANTA_PP}/mesh.h.reg
+ ${MANTA_PP}/mesh.h.reg.cpp
+ ${MANTA_PP}/movingobs.cpp
+ ${MANTA_PP}/movingobs.h
+ ${MANTA_PP}/movingobs.h.reg
+ ${MANTA_PP}/movingobs.h.reg.cpp
+ ${MANTA_PP}/multigrid.cpp
+ ${MANTA_PP}/multigrid.h
+ ${MANTA_PP}/multigrid.h.reg
+ ${MANTA_PP}/multigrid.h.reg.cpp
+ ${MANTA_PP}/noisefield.cpp
+ ${MANTA_PP}/noisefield.h
+ ${MANTA_PP}/noisefield.h.reg
+ ${MANTA_PP}/noisefield.h.reg.cpp
+ ${MANTA_PP}/particle.cpp
+ ${MANTA_PP}/particle.h
+ ${MANTA_PP}/particle.h.reg
+ ${MANTA_PP}/particle.h.reg.cpp
+ ${MANTA_PP}/plugin/advection.cpp
+ ${MANTA_PP}/plugin/apic.cpp
+ ${MANTA_PP}/plugin/extforces.cpp
+ ${MANTA_PP}/plugin/fire.cpp
+ ${MANTA_PP}/plugin/flip.cpp
+ ${MANTA_PP}/plugin/fluidguiding.cpp
+ ${MANTA_PP}/plugin/initplugins.cpp
+ ${MANTA_PP}/plugin/kepsilon.cpp
+ ${MANTA_PP}/plugin/meshplugins.cpp
+# TODO (sebbas): add numpy to libraries
+# ${MANTA_PP}/plugin/numpyconvert.cpp
+ ${MANTA_PP}/plugin/pressure.cpp
+ ${MANTA_PP}/plugin/ptsplugins.cpp
+ ${MANTA_PP}/plugin/secondaryparticles.cpp
+ ${MANTA_PP}/plugin/surfaceturbulence.cpp
+# TODO (sebbas): add numpy to libraries
+# ${MANTA_PP}/plugin/tfplugins.cpp
+ ${MANTA_PP}/plugin/vortexplugins.cpp
+ ${MANTA_PP}/plugin/waveletturbulence.cpp
+ ${MANTA_PP}/plugin/waves.cpp
+ ${MANTA_PP}/python/defines.py
+ ${MANTA_PP}/python/defines.py.reg
+ ${MANTA_PP}/python/defines.py.reg.cpp
+ ${MANTA_PP}/registration.cpp
+ ${MANTA_PP}/shapes.cpp
+ ${MANTA_PP}/shapes.h
+ ${MANTA_PP}/shapes.h.reg
+ ${MANTA_PP}/shapes.h.reg.cpp
+ ${MANTA_PP}/test.cpp
+ ${MANTA_PP}/timing.cpp
+ ${MANTA_PP}/timing.h
+ ${MANTA_PP}/timing.h.reg
+ ${MANTA_PP}/timing.h.reg.cpp
+ ${MANTA_PP}/turbulencepart.cpp
+ ${MANTA_PP}/turbulencepart.h
+ ${MANTA_PP}/turbulencepart.h.reg
+ ${MANTA_PP}/turbulencepart.h.reg.cpp
+ ${MANTA_PP}/vortexpart.cpp
+ ${MANTA_PP}/vortexpart.h
+ ${MANTA_PP}/vortexpart.h.reg
+ ${MANTA_PP}/vortexpart.h.reg.cpp
+ ${MANTA_PP}/vortexsheet.cpp
+ ${MANTA_PP}/vortexsheet.h
+ ${MANTA_PP}/vortexsheet.h.reg
+ ${MANTA_PP}/vortexsheet.h.reg.cpp
+
+ ${MANTA_HLP}/pwrapper/manta.h
+# TODO (sebbas): add numpy to libraries
+# ${MANTA_HLP}/pwrapper/numpyWrap.cpp
+# ${MANTA_HLP}/pwrapper/numpyWrap.h
+ ${MANTA_HLP}/pwrapper/pclass.cpp
+ ${MANTA_HLP}/pwrapper/pclass.h
+ ${MANTA_HLP}/pwrapper/pconvert.cpp
+ ${MANTA_HLP}/pwrapper/pconvert.h
+ ${MANTA_HLP}/pwrapper/pvec3.cpp
+ ${MANTA_HLP}/pwrapper/pythonInclude.h
+ ${MANTA_HLP}/pwrapper/registry.cpp
+ ${MANTA_HLP}/pwrapper/registry.h
+ ${MANTA_HLP}/util/integrator.h
+ ${MANTA_HLP}/util/interpol.h
+ ${MANTA_HLP}/util/interpolHigh.h
+ ${MANTA_HLP}/util/matrixbase.h
+ ${MANTA_HLP}/util/mcubes.h
+ ${MANTA_HLP}/util/quaternion.h
+ ${MANTA_HLP}/util/randomstream.h
+ ${MANTA_HLP}/util/rcmatrix.h
+ ${MANTA_HLP}/util/simpleimage.cpp
+ ${MANTA_HLP}/util/simpleimage.h
+ ${MANTA_HLP}/util/solvana.h
+ ${MANTA_HLP}/util/vector4d.cpp
+ ${MANTA_HLP}/util/vector4d.h
+ ${MANTA_HLP}/util/vectorbase.cpp
+ ${MANTA_HLP}/util/vectorbase.h
+)
+
+set(LIB
+)
+
+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..76e6c9ca2fd
--- /dev/null
+++ b/intern/mantaflow/extern/manta_fluid_API.h
@@ -0,0 +1,229 @@
+/*
+ * ***** 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 MantaModifierData *mmd);
+void manta_free(struct MANTA *fluid);
+void manta_ensure_obstacle(struct MANTA *fluid, struct MantaModifierData *mmd);
+void manta_ensure_guiding(struct MANTA *fluid, struct MantaModifierData *mmd);
+void manta_ensure_invelocity(struct MANTA *fluid, struct MantaModifierData *mmd);
+void manta_ensure_outflow(struct MANTA *fluid, struct MantaModifierData *mmd);
+int manta_write_config(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_write_data(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_read_config(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_read_data(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_read_noise(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_read_mesh(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_read_particles(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_read_guiding(struct MANTA *fluid,
+ struct MantaModifierData *mmd,
+ int framenr,
+ bool sourceDomain);
+int manta_update_liquid_structures(struct MANTA *fluid,
+ struct MantaModifierData *mmd,
+ int framenr);
+int manta_update_mesh_structures(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_update_particle_structures(struct MANTA *fluid,
+ struct MantaModifierData *mmd,
+ int framenr);
+int manta_bake_data(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_bake_noise(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_bake_mesh(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_bake_particles(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+int manta_bake_guiding(struct MANTA *fluid, struct MantaModifierData *mmd, int framenr);
+void manta_update_variables(struct MANTA *fluid, struct MantaModifierData *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 MantaModifierData *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 MantaModifierData *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 MantaModifierData *mmd);
+void manta_smoke_ensure_fire(struct MANTA *smoke, struct MantaModifierData *mmd);
+void manta_smoke_ensure_colors(struct MANTA *smoke, struct MantaModifierData *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 MantaModifierData *mmd);
+void manta_liquid_ensure_sndparts(struct MANTA *fluid, struct MantaModifierData *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/source/blender/modifiers/intern/MOD_fluidsim_util.h b/intern/mantaflow/extern/manta_python_API.h
index 0d2be3e7074..b0f0bc74367 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.h
+++ b/intern/mantaflow/extern/manta_python_API.h
@@ -1,8 +1,10 @@
/*
+ * ***** 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.
+ * 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
@@ -13,29 +15,29 @@
* 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) Blender Foundation
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
*/
-/** \file
- * \ingroup modifiers
+/** \file mantaflow/extern/manta_python_API.h
+ * \ingroup mantaflow
*/
-#ifndef __MOD_FLUIDSIM_UTIL_H__
-#define __MOD_FLUIDSIM_UTIL_H__
+#ifndef MANTA_PYTHON_API_H
+#define MANTA_PYTHON_API_H
-struct FluidsimModifierData;
-struct Mesh;
-struct ModifierEvalContext;
-struct Object;
-struct Scene;
+#ifdef __cplusplus
+extern "C" {
+#endif
-/* new fluid-modifier interface */
-void fluidsim_init(struct FluidsimModifierData *fluidmd);
-void fluidsim_free(struct FluidsimModifierData *fluidmd);
+PyObject *Manta_initPython(void);
-struct Mesh *fluidsimModifier_do(struct FluidsimModifierData *fluidmd,
- const struct ModifierEvalContext *ctx,
- struct Mesh *me);
+#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..06e52918c78
--- /dev/null
+++ b/intern/mantaflow/intern/MANTA_main.cpp
@@ -0,0 +1,2566 @@
+/*
+ * ***** 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 <sstream>
+#include <fstream>
+#include <iostream>
+#include <iomanip>
+#include <zlib.h>
+
+#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_manta_types.h"
+
+std::atomic<bool> MANTA::mantaInitialized(false);
+std::atomic<int> MANTA::solverID(0);
+int MANTA::with_debug(0);
+
+MANTA::MANTA(int *res, MantaModifierData *mmd) : mCurrentID(++solverID)
+{
+ if (with_debug)
+ std::cout << "MANTA: " << mCurrentID << " with res(" << res[0] << ", " << res[1] << ", "
+ << res[2] << ")" << std::endl;
+
+ mmd->domain->fluid = this;
+
+ mUsingHeat = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT;
+ mUsingFire = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE;
+ mUsingColors = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS;
+ 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;
+ mUsingNoise = mmd->domain->flags & FLUID_DOMAIN_USE_NOISE;
+ mUsingMesh = mmd->domain->flags & FLUID_DOMAIN_USE_MESH;
+ mUsingMVel = mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS;
+ mUsingGuiding = mmd->domain->flags & FLUID_DOMAIN_USE_GUIDING;
+ mUsingLiquid = mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID;
+ mUsingSmoke = mmd->domain->type == FLUID_DOMAIN_TYPE_GAS;
+ mUsingDrops = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY;
+ mUsingBubbles = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE;
+ mUsingFloats = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM;
+ mUsingTracers = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER;
+
+ // 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);
+ }
+ updatePointers();
+
+ return;
+ }
+
+ // 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);
+ }
+ updatePointers(); // Needs to be after heat, fire, color init
+
+ 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);
+
+ updatePointersNoise(); // Needs to be after fire, color init
+ }
+ }
+}
+
+void MANTA::initDomain(MantaModifierData *mmd)
+{
+ // Vector will hold all python commands that are to be executed
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_variables_noise + fluid_solver_noise +
+ fluid_time_stepping_noise;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+}
+
+void MANTA::initSmoke(MantaModifierData *mmd)
+{
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ if (!mHeat) {
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ if (!mFuel) {
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ if (!mFuelHigh) {
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ if (!mColorR) {
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ if (!mColorRHigh) {
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ if (!mPhiIn) {
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_variables_mesh + fluid_solver_mesh;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingMesh = true;
+}
+
+void MANTA::initLiquidMesh(MantaModifierData *mmd)
+{
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ if (!mPhiObsIn) {
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ if (!mPhiGuideIn) {
+ std::vector<std::string> 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::initInVelocity(MantaModifierData *mmd)
+{
+ if (!mInVelocityX) {
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ if (!mPhiOutIn) {
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ std::vector<std::string> 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(MantaModifierData *mmd)
+{
+ if (!mSndParticleData) {
+ std::vector<std::string> 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<std::string> 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<std::string> commands)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ for (std::vector<std::string>::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<std::string> fill = std::vector<std::string>();
+
+ // 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, MantaModifierData *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 == "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 == "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 == "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 == "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_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
+ std::cout << "ERROR: Unknown option: " << varName << std::endl;
+ return ss.str();
+}
+
+std::string MANTA::parseLine(const std::string &line, MantaModifierData *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, MantaModifierData *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(MantaModifierData *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(MantaModifierData *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(MantaModifierData *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(MantaModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::writeConfiguration()" << std::endl;
+
+ MantaDomainSettings *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 << "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(MantaModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::writeData()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> 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 << "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(MantaModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readConfiguration()" << std::endl;
+
+ MantaDomainSettings *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 << "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(MantaModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readData()" << std::endl;
+
+ if (!mUsingSmoke && !mUsingLiquid)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> 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);
+
+ if (mUsingSmoke) {
+ 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());
+ ss.str("");
+ }
+ if (mUsingLiquid) {
+ 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());
+ ss.str("");
+ }
+ runPythonString(pythonCommands);
+ updatePointers();
+ return 1;
+}
+
+int MANTA::readNoise(MantaModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readNoise()" << std::endl;
+
+ if (!mUsingNoise)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirNoise[FILE_MAX];
+ cacheDirNoise[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);
+
+ if (mUsingSmoke && mUsingNoise) {
+ ss << "smoke_load_noise_" << mCurrentID << "('" << escapeSlashes(cacheDirNoise) << "', "
+ << framenr << ", '" << nformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ runPythonString(pythonCommands);
+ updatePointersNoise();
+ return 1;
+}
+
+int MANTA::readMesh(MantaModifierData *mmd, int framenr)
+{
+ // dummmy function, use updateMeshFromFile
+ if (with_debug)
+ std::cout << "MANTA::readMesh() - dummmy function, use updateMeshFromFile()" << std::endl;
+
+ if (!mUsingMesh)
+ return 0;
+
+ return 1;
+}
+
+int MANTA::readParticles(MantaModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readParticles()" << std::endl;
+
+ if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirParticles[FILE_MAX];
+ cacheDirParticles[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);
+
+ if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) {
+ 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());
+ ss.str("");
+ }
+ runPythonString(pythonCommands);
+ updatePointers();
+ return 1;
+}
+
+int MANTA::readGuiding(MantaModifierData *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<std::string> pythonCommands;
+
+ char cacheDirGuiding[FILE_MAX];
+ cacheDirGuiding[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);
+
+ if (sourceDomain) {
+ ss << "fluid_load_vel_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', "
+ << framenr << ", '" << gformat << "')";
+ }
+ else {
+ ss << "fluid_load_guiding_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', "
+ << framenr << ", '" << gformat << "')";
+ }
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ updatePointers();
+ return 1;
+}
+
+int MANTA::bakeData(MantaModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeData()" << std::endl;
+
+ std::string tmpString, finalString;
+ std::ostringstream ss;
+ std::vector<std::string> 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 << "bake_fluid_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirGuiding) << "', " << framenr << ", '" << dformat << "', '" << pformat
+ << "', '" << gformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeNoise(MantaModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeNoise()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> 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 << "bake_noise_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirNoise) << "', " << framenr << ", '" << dformat << "', '" << nformat
+ << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeMesh(MantaModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeMesh()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> 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 << "bake_mesh_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirMesh) << "', " << framenr << ", '" << dformat << "', '" << mformat
+ << "', '" << pformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeParticles(MantaModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeParticles()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> 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 << "bake_particles_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirParticles) << "', " << framenr << ", '" << dformat << "', '"
+ << pformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeGuiding(MantaModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeGuiding()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> 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 << "bake_guiding_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', " << framenr
+ << ", '" << gformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+void MANTA::updateVariables(MantaModifierData *mmd)
+{
+ std::string tmpString, finalString;
+ std::vector<std::string> 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(MantaModifierData *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_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;
+ if (noise) {
+ manta_script += fluid_time_stepping_noise;
+ }
+
+ // 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(MantaModifierData *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_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, *var, *func, *returnedValue;
+
+ // Get pyobject that holds result value
+ main = PyImport_ImportModule("__main__");
+ var = PyObject_GetAttrString(main, varName.c_str());
+ func = PyObject_GetAttrString(var, functionName.c_str());
+
+ Py_DECREF(var);
+
+ 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(MantaModifierData *mmd)
+{
+ MantaDomainSettings *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<std::string> 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<Node>::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<Node>::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<Triangle>::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<pVel> *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, &timestamp, 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<pVel>::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<pData> *dataPointer = NULL;
+ std::vector<pVel> *velocityPointer = NULL;
+ std::vector<float> *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, &timestamp, 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<pData>::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<pVel>::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<float>::iterator it = lifePointer->begin(); it != lifePointer->end(); ++it) {
+ gzread(gzf, fbuffer, sizeof(float));
+ bufferPLife = (float *)fbuffer;
+ *it = *bufferPLife;
+ }
+ }
+
+ gzclose(gzf);
+}
+
+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 solver_ext = "_" + solver;
+ std::string parts_ext = "_" + parts;
+ std::string snd_ext = "_" + snd;
+ std::string mesh_ext = "_" + mesh;
+ std::string mesh_ext2 = "_" + mesh2;
+
+ mObstacle = (int *)stringToPointer(
+ pyObjectToString(callPythonFunction("flags" + solver_ext, func)));
+ mPhiIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("phiIn" + solver_ext, func)));
+
+ mVelocityX = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("x_vel" + solver_ext, func)));
+ mVelocityY = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("y_vel" + solver_ext, func)));
+ mVelocityZ = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("z_vel" + solver_ext, func)));
+
+ mForceX = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("x_force" + solver_ext, func)));
+ mForceY = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("y_force" + solver_ext, func)));
+ mForceZ = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("z_force" + solver_ext, func)));
+
+ if (mUsingOutflow) {
+ mPhiOutIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("phiOutIn" + solver_ext, func)));
+ }
+
+ if (mUsingObstacle) {
+ mPhiObsIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("phiObsIn" + solver_ext, func)));
+ mNumObstacle = (int *)stringToPointer(
+ pyObjectToString(callPythonFunction("numObs" + solver_ext, func)));
+
+ mObVelocityX = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("x_obvel" + solver_ext, func)));
+ mObVelocityY = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("y_obvel" + solver_ext, func)));
+ mObVelocityZ = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("z_obvel" + solver_ext, func)));
+ }
+
+ if (mUsingGuiding) {
+ mPhiGuideIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("phiGuideIn" + solver_ext, func)));
+ mNumGuide = (int *)stringToPointer(
+ pyObjectToString(callPythonFunction("numGuides" + solver_ext, func)));
+
+ mGuideVelocityX = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("x_guidevel" + solver_ext, func)));
+ mGuideVelocityY = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("y_guidevel" + solver_ext, func)));
+ mGuideVelocityZ = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("z_guidevel" + solver_ext, func)));
+ }
+
+ if (mUsingInvel) {
+ mInVelocityX = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("x_invel" + solver_ext, func)));
+ mInVelocityY = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("y_invel" + solver_ext, func)));
+ mInVelocityZ = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("z_invel" + solver_ext, func)));
+ }
+
+ // Liquid
+ if (mUsingLiquid) {
+ mPhi = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("phi" + solver_ext, func)));
+
+ mFlipParticleData = (std::vector<pData> *)stringToPointer(
+ pyObjectToString(callPythonFunction("pp" + solver_ext, func)));
+ mFlipParticleVelocity = (std::vector<pVel> *)stringToPointer(
+ pyObjectToString(callPythonFunction("pVel" + parts_ext, func)));
+
+ if (mUsingMesh) {
+ mMeshNodes = (std::vector<Node> *)stringToPointer(
+ pyObjectToString(callPythonFunction("mesh" + mesh_ext, funcNodes)));
+ mMeshTriangles = (std::vector<Triangle> *)stringToPointer(
+ pyObjectToString(callPythonFunction("mesh" + mesh_ext, funcTris)));
+ if (mUsingMVel)
+ mMeshVelocities = (std::vector<pVel> *)stringToPointer(
+ pyObjectToString(callPythonFunction("mVel" + mesh_ext2, func)));
+ }
+
+ if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) {
+ mSndParticleData = (std::vector<pData> *)stringToPointer(
+ pyObjectToString(callPythonFunction("ppSnd" + snd_ext, func)));
+ mSndParticleVelocity = (std::vector<pVel> *)stringToPointer(
+ pyObjectToString(callPythonFunction("pVelSnd" + parts_ext, func)));
+ mSndParticleLife = (std::vector<float> *)stringToPointer(
+ pyObjectToString(callPythonFunction("pLifeSnd" + parts_ext, func)));
+ }
+ }
+
+ // Smoke
+ if (mUsingSmoke) {
+ mDensity = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("density" + solver_ext, func)));
+ mDensityIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("densityIn" + solver_ext, func)));
+ mShadow = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("shadow" + solver_ext, func)));
+ mEmissionIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("emissionIn" + solver_ext, func)));
+
+ if (mUsingHeat) {
+ mHeat = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("heat" + solver_ext, func)));
+ mHeatIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("heatIn" + solver_ext, func)));
+ }
+ if (mUsingFire) {
+ mFlame = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("flame" + solver_ext, func)));
+ mFuel = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("fuel" + solver_ext, func)));
+ mReact = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("react" + solver_ext, func)));
+
+ mFuelIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("fuelIn" + solver_ext, func)));
+ mReactIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("reactIn" + solver_ext, func)));
+ }
+ if (mUsingColors) {
+ mColorR = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("color_r" + solver_ext, func)));
+ mColorG = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("color_g" + solver_ext, func)));
+ mColorB = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("color_b" + solver_ext, func)));
+
+ mColorRIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("color_r_in" + solver_ext, func)));
+ mColorGIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("color_g_in" + solver_ext, func)));
+ mColorBIn = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("color_b_in" + solver_ext, func)));
+ }
+ }
+}
+
+void MANTA::updatePointersNoise()
+{
+ if (with_debug)
+ std::cout << "MANTA::updatePointersHigh()" << std::endl;
+
+ std::string func = "getDataPointer";
+ std::string id = std::to_string(mCurrentID);
+ std::string solver = "s" + id;
+ std::string solver_ext = "_" + solver;
+
+ std::string noise = "sn" + id;
+ std::string noise_ext = "_" + noise;
+
+ // Liquid
+ if (mUsingLiquid) {
+ // Nothing to do here
+ }
+
+ // Smoke
+ if (mUsingSmoke) {
+ mDensityHigh = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("density" + noise_ext, func)));
+ mShadow = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("shadow" + solver_ext, func)));
+ mTextureU = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("texture_u" + solver_ext, func)));
+ mTextureV = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("texture_v" + solver_ext, func)));
+ mTextureW = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("texture_w" + solver_ext, func)));
+ mTextureU2 = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("texture_u2" + solver_ext, func)));
+ mTextureV2 = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("texture_v2" + solver_ext, func)));
+ mTextureW2 = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("texture_w2" + solver_ext, func)));
+
+ if (mUsingFire) {
+ mFlameHigh = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("flame" + noise_ext, func)));
+ mFuelHigh = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("fuel" + noise_ext, func)));
+ mReactHigh = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("react" + noise_ext, func)));
+ }
+ if (mUsingColors) {
+ mColorRHigh = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("color_r" + noise_ext, func)));
+ mColorGHigh = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("color_g" + noise_ext, func)));
+ mColorBHigh = (float *)stringToPointer(
+ pyObjectToString(callPythonFunction("color_b" + noise_ext, func)));
+ }
+ }
+}
diff --git a/intern/mantaflow/intern/MANTA_main.h b/intern/mantaflow/intern/MANTA_main.h
new file mode 100644
index 00000000000..2235fddc570
--- /dev/null
+++ b/intern/mantaflow/intern/MANTA_main.h
@@ -0,0 +1,774 @@
+/*
+ * ***** 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 <string>
+#include <vector>
+#include <atomic>
+
+struct MANTA {
+ public:
+ MANTA(int *res, struct MantaModifierData *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 MantaModifierData *mmd, int startFrame);
+
+ // Grid initialization functions
+ void initHeat(struct MantaModifierData *mmd);
+ void initFire(struct MantaModifierData *mmd);
+ void initColors(struct MantaModifierData *mmd);
+ void initFireHigh(struct MantaModifierData *mmd);
+ void initColorsHigh(struct MantaModifierData *mmd);
+ void initLiquid(MantaModifierData *mmd);
+ void initLiquidMesh(MantaModifierData *mmd);
+ void initObstacle(MantaModifierData *mmd);
+ void initGuiding(MantaModifierData *mmd);
+ void initInVelocity(MantaModifierData *mmd);
+ void initOutflow(MantaModifierData *mmd);
+ void initSndParts(MantaModifierData *mmd);
+ void initLiquidSndParts(MantaModifierData *mmd);
+
+ // Pointer transfer: Mantaflow -> Blender
+ void updatePointers();
+ void updatePointersNoise();
+
+ // Write cache
+ int writeConfiguration(MantaModifierData *mmd, int framenr);
+ int writeData(MantaModifierData *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(MantaModifierData *mmd, int framenr);
+ int readData(MantaModifierData *mmd, int framenr);
+ int readNoise(MantaModifierData *mmd, int framenr);
+ int readMesh(MantaModifierData *mmd, int framenr);
+ int readParticles(MantaModifierData *mmd, int framenr);
+ int readGuiding(MantaModifierData *mmd, int framenr, bool sourceDomain);
+
+ // Read cache (via file read functions in MANTA - e.g. read .bobj.gz meshes, .uni particles)
+ int updateMeshStructures(MantaModifierData *mmd, int framenr);
+ int updateFlipStructures(MantaModifierData *mmd, int framenr);
+ int updateParticleStructures(MantaModifierData *mmd, int framenr);
+ void updateVariables(MantaModifierData *mmd);
+
+ // Bake cache
+ int bakeData(MantaModifierData *mmd, int framenr);
+ int bakeNoise(MantaModifierData *mmd, int framenr);
+ int bakeMesh(MantaModifierData *mmd, int framenr);
+ int bakeParticles(MantaModifierData *mmd, int framenr);
+ int bakeGuiding(MantaModifierData *mmd, int framenr);
+
+ // IO for Mantaflow scene script
+ void exportSmokeScript(struct MantaModifierData *mmd);
+ void exportLiquidScript(struct MantaModifierData *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<bool> mantaInitialized;
+ static std::atomic<int> 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)
+ {
+ return (mMeshNodes && !mMeshNodes->empty() && mMeshNodes->size() > i) ?
+ mMeshNodes->at(i).pos[0] :
+ 0.f;
+ }
+ inline float getVertexYAt(int i)
+ {
+ return (mMeshNodes && !mMeshNodes->empty() && mMeshNodes->size() > i) ?
+ mMeshNodes->at(i).pos[1] :
+ 0.f;
+ }
+ inline float getVertexZAt(int i)
+ {
+ return (mMeshNodes && !mMeshNodes->empty() && mMeshNodes->size() > i) ?
+ mMeshNodes->at(i).pos[2] :
+ 0.f;
+ }
+
+ inline float getNormalXAt(int i)
+ {
+ return (mMeshNodes && !mMeshNodes->empty() && mMeshNodes->size() > i) ?
+ mMeshNodes->at(i).normal[0] :
+ 0.f;
+ }
+ inline float getNormalYAt(int i)
+ {
+ return (mMeshNodes && !mMeshNodes->empty() && mMeshNodes->size() > i) ?
+ mMeshNodes->at(i).normal[1] :
+ 0.f;
+ }
+ inline float getNormalZAt(int i)
+ {
+ return (mMeshNodes && !mMeshNodes->empty() && mMeshNodes->size() > i) ?
+ mMeshNodes->at(i).normal[2] :
+ 0.f;
+ }
+
+ inline int getTriangleXAt(int i)
+ {
+ return (mMeshTriangles && !mMeshTriangles->empty() && mMeshTriangles->size() > i) ?
+ mMeshTriangles->at(i).c[0] :
+ 0;
+ }
+ inline int getTriangleYAt(int i)
+ {
+ return (mMeshTriangles && !mMeshTriangles->empty() && mMeshTriangles->size() > i) ?
+ mMeshTriangles->at(i).c[1] :
+ 0;
+ }
+ inline int getTriangleZAt(int i)
+ {
+ return (mMeshTriangles && !mMeshTriangles->empty() && mMeshTriangles->size() > i) ?
+ mMeshTriangles->at(i).c[2] :
+ 0;
+ }
+
+ inline float getVertVelXAt(int i)
+ {
+ return (mMeshVelocities && !mMeshVelocities->empty() && mMeshVelocities->size() > i) ?
+ mMeshVelocities->at(i).pos[0] :
+ 0.f;
+ }
+ inline float getVertVelYAt(int i)
+ {
+ return (mMeshVelocities && !mMeshVelocities->empty() && mMeshVelocities->size() > i) ?
+ mMeshVelocities->at(i).pos[1] :
+ 0.f;
+ }
+ inline float getVertVelZAt(int i)
+ {
+ return (mMeshVelocities && !mMeshVelocities->empty() && mMeshVelocities->size() > i) ?
+ mMeshVelocities->at(i).pos[2] :
+ 0.f;
+ }
+
+ // Particle getters
+ inline int getFlipParticleFlagAt(int i)
+ {
+ return (mFlipParticleData && !mFlipParticleData->empty() && mFlipParticleData->size() > i) ?
+ ((std::vector<pData> *)mFlipParticleData)->at(i).flag :
+ 0;
+ }
+ inline int getSndParticleFlagAt(int i)
+ {
+ return (mSndParticleData && !mSndParticleData->empty() && mSndParticleData->size() > i) ?
+ ((std::vector<pData> *)mSndParticleData)->at(i).flag :
+ 0;
+ }
+
+ inline float getFlipParticlePositionXAt(int i)
+ {
+ return (mFlipParticleData && !mFlipParticleData->empty() && mFlipParticleData->size() > i) ?
+ mFlipParticleData->at(i).pos[0] :
+ 0.f;
+ }
+ inline float getFlipParticlePositionYAt(int i)
+ {
+ return (mFlipParticleData && !mFlipParticleData->empty() && mFlipParticleData->size() > i) ?
+ mFlipParticleData->at(i).pos[1] :
+ 0.f;
+ }
+ inline float getFlipParticlePositionZAt(int i)
+ {
+ return (mFlipParticleData && !mFlipParticleData->empty() && mFlipParticleData->size() > i) ?
+ mFlipParticleData->at(i).pos[2] :
+ 0.f;
+ }
+
+ inline float getSndParticlePositionXAt(int i)
+ {
+ return (mSndParticleData && !mSndParticleData->empty() && mSndParticleData->size() > i) ?
+ mSndParticleData->at(i).pos[0] :
+ 0.f;
+ }
+ inline float getSndParticlePositionYAt(int i)
+ {
+ return (mSndParticleData && !mSndParticleData->empty() && mSndParticleData->size() > i) ?
+ mSndParticleData->at(i).pos[1] :
+ 0.f;
+ }
+ inline float getSndParticlePositionZAt(int i)
+ {
+ return (mSndParticleData && !mSndParticleData->empty() && mSndParticleData->size() > i) ?
+ mSndParticleData->at(i).pos[2] :
+ 0.f;
+ }
+
+ inline float getFlipParticleVelocityXAt(int i)
+ {
+ return (mFlipParticleVelocity && !mFlipParticleVelocity->empty() &&
+ mFlipParticleVelocity->size() > i) ?
+ mFlipParticleVelocity->at(i).pos[0] :
+ 0.f;
+ }
+ inline float getFlipParticleVelocityYAt(int i)
+ {
+ return (mFlipParticleVelocity && !mFlipParticleVelocity->empty() &&
+ mFlipParticleVelocity->size() > i) ?
+ mFlipParticleVelocity->at(i).pos[1] :
+ 0.f;
+ }
+ inline float getFlipParticleVelocityZAt(int i)
+ {
+ return (mFlipParticleVelocity && !mFlipParticleVelocity->empty() &&
+ mFlipParticleVelocity->size() > i) ?
+ mFlipParticleVelocity->at(i).pos[2] :
+ 0.f;
+ }
+
+ inline float getSndParticleVelocityXAt(int i)
+ {
+ return (mSndParticleVelocity && !mSndParticleVelocity->empty() &&
+ mSndParticleVelocity->size() > i) ?
+ mSndParticleVelocity->at(i).pos[0] :
+ 0.f;
+ }
+ inline float getSndParticleVelocityYAt(int i)
+ {
+ return (mSndParticleVelocity && !mSndParticleVelocity->empty() &&
+ mSndParticleVelocity->size() > i) ?
+ mSndParticleVelocity->at(i).pos[1] :
+ 0.f;
+ }
+ inline float getSndParticleVelocityZAt(int i)
+ {
+ return (mSndParticleVelocity && !mSndParticleVelocity->empty() &&
+ mSndParticleVelocity->size() > i) ?
+ mSndParticleVelocity->at(i).pos[2] :
+ 0.f;
+ }
+
+ 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(MantaModifierData *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 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<Node> *mMeshNodes;
+ std::vector<Triangle> *mMeshTriangles;
+ std::vector<pVel> *mMeshVelocities;
+
+ // Particle fields
+ std::vector<pData> *mFlipParticleData;
+ std::vector<pVel> *mFlipParticleVelocity;
+
+ std::vector<pData> *mSndParticleData;
+ std::vector<pVel> *mSndParticleVelocity;
+ std::vector<float> *mSndParticleLife;
+
+ void initDomain(struct MantaModifierData *mmd);
+ void initNoise(struct MantaModifierData *mmd);
+ void initMesh(struct MantaModifierData *mmd);
+ void initSmoke(struct MantaModifierData *mmd);
+ void initSmokeNoise(struct MantaModifierData *mmd);
+ void initializeMantaflow();
+ void terminateMantaflow();
+ void runPythonString(std::vector<std::string> commands);
+ std::string getRealValue(const std::string &varName, MantaModifierData *mmd);
+ std::string parseLine(const std::string &line, MantaModifierData *mmd);
+ std::string parseScript(const std::string &setup_string, MantaModifierData *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);
+};
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/dependencies/cnpy/LICENSE b/intern/mantaflow/intern/manta_develop/dependencies/cnpy/LICENSE
new file mode 100644
index 00000000000..e60eadbccb3
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/dependencies/cnpy/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) Carl Rogers, 2011
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/intern/mantaflow/intern/manta_develop/dependencies/cnpy/cnpy.cpp b/intern/mantaflow/intern/manta_develop/dependencies/cnpy/cnpy.cpp
new file mode 100644
index 00000000000..930ebe537cb
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/dependencies/cnpy/cnpy.cpp
@@ -0,0 +1,341 @@
+//Copyright (C) 2011 Carl Rogers
+//Released under MIT License
+//license available in LICENSE file, or at http://www.opensource.org/licenses/mit-license.php
+
+#include"cnpy.h"
+#include<complex>
+#include<cstdlib>
+#include<algorithm>
+#include<cstring>
+#include<iomanip>
+#include<stdint.h>
+#include<stdexcept>
+#include <regex>
+
+char cnpy::BigEndianTest() {
+ int x = 1;
+ return (((char *)&x)[0]) ? '<' : '>';
+}
+
+char cnpy::map_type(const std::type_info& t)
+{
+ if(t == typeid(float) ) return 'f';
+ if(t == typeid(double) ) return 'f';
+ if(t == typeid(long double) ) return 'f';
+
+ if(t == typeid(int) ) return 'i';
+ if(t == typeid(char) ) return 'i';
+ if(t == typeid(short) ) return 'i';
+ if(t == typeid(long) ) return 'i';
+ if(t == typeid(long long) ) return 'i';
+
+ if(t == typeid(unsigned char) ) return 'u';
+ if(t == typeid(unsigned short) ) return 'u';
+ if(t == typeid(unsigned long) ) return 'u';
+ if(t == typeid(unsigned long long) ) return 'u';
+ if(t == typeid(unsigned int) ) return 'u';
+
+ if(t == typeid(bool) ) return 'b';
+
+ if(t == typeid(std::complex<float>) ) return 'c';
+ if(t == typeid(std::complex<double>) ) return 'c';
+ if(t == typeid(std::complex<long double>) ) return 'c';
+
+ else return '?';
+}
+
+template<> std::vector<char>& cnpy::operator+=(std::vector<char>& lhs, const std::string rhs) {
+ lhs.insert(lhs.end(),rhs.begin(),rhs.end());
+ return lhs;
+}
+
+template<> std::vector<char>& cnpy::operator+=(std::vector<char>& lhs, const char* rhs) {
+ //write in little endian
+ size_t len = strlen(rhs);
+ lhs.reserve(len);
+ for(size_t byte = 0; byte < len; byte++) {
+ lhs.push_back(rhs[byte]);
+ }
+ return lhs;
+}
+
+void cnpy::parse_npy_header(unsigned char* buffer,size_t& word_size, std::vector<size_t>& shape, bool& fortran_order) {
+ //std::string magic_string(buffer,6);
+ uint8_t major_version = *reinterpret_cast<uint8_t*>(buffer+6);
+ uint8_t minor_version = *reinterpret_cast<uint8_t*>(buffer+7);
+ uint16_t header_len = *reinterpret_cast<uint16_t*>(buffer+8);
+ std::string header(reinterpret_cast<char*>(buffer+9),header_len);
+
+ size_t loc1, loc2;
+
+ //fortran order
+ loc1 = header.find("fortran_order")+16;
+ fortran_order = (header.substr(loc1,4) == "True" ? true : false);
+
+ //shape
+ loc1 = header.find("(");
+ loc2 = header.find(")");
+
+ std::regex num_regex("[0-9][0-9]*");
+ std::smatch sm;
+ shape.clear();
+
+ std::string str_shape = header.substr(loc1+1,loc2-loc1-1);
+ while(std::regex_search(str_shape, sm, num_regex)) {
+ shape.push_back(std::stoi(sm[0].str()));
+ str_shape = sm.suffix().str();
+ }
+
+ //endian, word size, data type
+ //byte order code | stands for not applicable.
+ //not sure when this applies except for byte array
+ loc1 = header.find("descr")+9;
+ bool littleEndian = (header[loc1] == '<' || header[loc1] == '|' ? true : false);
+ assert(littleEndian);
+
+ //char type = header[loc1+1];
+ //assert(type == map_type(T));
+
+ std::string str_ws = header.substr(loc1+2);
+ loc2 = str_ws.find("'");
+ word_size = atoi(str_ws.substr(0,loc2).c_str());
+}
+
+void cnpy::parse_npy_header(FILE* fp, size_t& word_size, std::vector<size_t>& shape, bool& fortran_order) {
+ char buffer[256];
+ size_t res = fread(buffer,sizeof(char),11,fp);
+ if(res != 11)
+ throw std::runtime_error("parse_npy_header: failed fread");
+ std::string header = fgets(buffer,256,fp);
+ assert(header[header.size()-1] == '\n');
+
+ size_t loc1, loc2;
+
+ //fortran order
+ loc1 = header.find("fortran_order");
+ if (loc1 == std::string::npos)
+ throw std::runtime_error("parse_npy_header: failed to find header keyword: 'fortran_order'");
+ loc1 += 16;
+ fortran_order = (header.substr(loc1,4) == "True" ? true : false);
+
+ //shape
+ loc1 = header.find("(");
+ loc2 = header.find(")");
+ if (loc1 == std::string::npos || loc2 == std::string::npos)
+ throw std::runtime_error("parse_npy_header: failed to find header keyword: '(' or ')'");
+
+ std::regex num_regex("[0-9][0-9]*");
+ std::smatch sm;
+ shape.clear();
+
+ std::string str_shape = header.substr(loc1+1,loc2-loc1-1);
+ while(std::regex_search(str_shape, sm, num_regex)) {
+ shape.push_back(std::stoi(sm[0].str()));
+ str_shape = sm.suffix().str();
+ }
+
+ //endian, word size, data type
+ //byte order code | stands for not applicable.
+ //not sure when this applies except for byte array
+ loc1 = header.find("descr");
+ if (loc1 == std::string::npos)
+ throw std::runtime_error("parse_npy_header: failed to find header keyword: 'descr'");
+ loc1 += 9;
+ bool littleEndian = (header[loc1] == '<' || header[loc1] == '|' ? true : false);
+ assert(littleEndian);
+
+ //char type = header[loc1+1];
+ //assert(type == map_type(T));
+
+ std::string str_ws = header.substr(loc1+2);
+ loc2 = str_ws.find("'");
+ word_size = atoi(str_ws.substr(0,loc2).c_str());
+}
+
+void cnpy::parse_zip_footer(FILE* fp, uint16_t& nrecs, size_t& global_header_size, size_t& global_header_offset)
+{
+ std::vector<char> footer(22);
+ fseek(fp,-22,SEEK_END);
+ size_t res = fread(&footer[0],sizeof(char),22,fp);
+ if(res != 22)
+ throw std::runtime_error("parse_zip_footer: failed fread");
+
+ uint16_t disk_no, disk_start, nrecs_on_disk, comment_len;
+ disk_no = *(uint16_t*) &footer[4];
+ disk_start = *(uint16_t*) &footer[6];
+ nrecs_on_disk = *(uint16_t*) &footer[8];
+ nrecs = *(uint16_t*) &footer[10];
+ global_header_size = *(uint32_t*) &footer[12];
+ global_header_offset = *(uint32_t*) &footer[16];
+ comment_len = *(uint16_t*) &footer[20];
+
+ assert(disk_no == 0);
+ assert(disk_start == 0);
+ assert(nrecs_on_disk == nrecs);
+ assert(comment_len == 0);
+}
+
+cnpy::NpyArray load_the_npy_file(FILE* fp) {
+ std::vector<size_t> shape;
+ size_t word_size;
+ bool fortran_order;
+ cnpy::parse_npy_header(fp,word_size,shape,fortran_order);
+
+ cnpy::NpyArray arr(shape, word_size, fortran_order);
+ size_t nread = fread(arr.data<char>(),1,arr.num_bytes(),fp);
+ if(nread != arr.num_bytes())
+ throw std::runtime_error("load_the_npy_file: failed fread");
+ return arr;
+}
+
+cnpy::NpyArray load_the_npz_array(FILE* fp, uint32_t compr_bytes, uint32_t uncompr_bytes) {
+
+ std::vector<unsigned char> buffer_compr(compr_bytes);
+ std::vector<unsigned char> buffer_uncompr(uncompr_bytes);
+ size_t nread = fread(&buffer_compr[0],1,compr_bytes,fp);
+ if(nread != compr_bytes)
+ throw std::runtime_error("load_the_npy_file: failed fread");
+
+ int err;
+ z_stream d_stream;
+
+ d_stream.zalloc = Z_NULL;
+ d_stream.zfree = Z_NULL;
+ d_stream.opaque = Z_NULL;
+ d_stream.avail_in = 0;
+ d_stream.next_in = Z_NULL;
+ err = inflateInit2(&d_stream, -MAX_WBITS);
+
+ d_stream.avail_in = compr_bytes;
+ d_stream.next_in = &buffer_compr[0];
+ d_stream.avail_out = uncompr_bytes;
+ d_stream.next_out = &buffer_uncompr[0];
+
+ err = inflate(&d_stream, Z_FINISH);
+ err = inflateEnd(&d_stream);
+
+ std::vector<size_t> shape;
+ size_t word_size;
+ bool fortran_order;
+ cnpy::parse_npy_header(&buffer_uncompr[0],word_size,shape,fortran_order);
+
+ cnpy::NpyArray array(shape, word_size, fortran_order);
+
+ size_t offset = uncompr_bytes - array.num_bytes();
+ memcpy(array.data<unsigned char>(),&buffer_uncompr[0]+offset,array.num_bytes());
+
+ return array;
+}
+
+cnpy::npz_t cnpy::npz_load(std::string fname) {
+ FILE* fp = fopen(fname.c_str(),"rb");
+
+ if(!fp) {
+ throw std::runtime_error("npz_load: Error! Unable to open file "+fname+"!");
+ }
+
+ cnpy::npz_t arrays;
+
+ while(1) {
+ std::vector<char> local_header(30);
+ size_t headerres = fread(&local_header[0],sizeof(char),30,fp);
+ if(headerres != 30)
+ throw std::runtime_error("npz_load: failed fread");
+
+ //if we've reached the global header, stop reading
+ if(local_header[2] != 0x03 || local_header[3] != 0x04) break;
+
+ //read in the variable name
+ uint16_t name_len = *(uint16_t*) &local_header[26];
+ std::string varname(name_len,' ');
+ size_t vname_res = fread(&varname[0],sizeof(char),name_len,fp);
+ if(vname_res != name_len)
+ throw std::runtime_error("npz_load: failed fread");
+
+ //erase the lagging .npy
+ varname.erase(varname.end()-4,varname.end());
+
+ //read in the extra field
+ uint16_t extra_field_len = *(uint16_t*) &local_header[28];
+ if(extra_field_len > 0) {
+ std::vector<char> buff(extra_field_len);
+ size_t efield_res = fread(&buff[0],sizeof(char),extra_field_len,fp);
+ if(efield_res != extra_field_len)
+ throw std::runtime_error("npz_load: failed fread");
+ }
+
+ uint16_t compr_method = *reinterpret_cast<uint16_t*>(&local_header[0]+8);
+ uint32_t compr_bytes = *reinterpret_cast<uint32_t*>(&local_header[0]+18);
+ uint32_t uncompr_bytes = *reinterpret_cast<uint32_t*>(&local_header[0]+22);
+
+ if(compr_method == 0) {arrays[varname] = load_the_npy_file(fp);}
+ else {arrays[varname] = load_the_npz_array(fp,compr_bytes,uncompr_bytes);}
+ }
+
+ fclose(fp);
+ return arrays;
+}
+
+cnpy::NpyArray cnpy::npz_load(std::string fname, std::string varname) {
+ FILE* fp = fopen(fname.c_str(),"rb");
+
+ if(!fp) throw std::runtime_error("npz_load: Unable to open file "+fname);
+
+ while(1) {
+ std::vector<char> local_header(30);
+ size_t header_res = fread(&local_header[0],sizeof(char),30,fp);
+ if(header_res != 30)
+ throw std::runtime_error("npz_load: failed fread");
+
+ //if we've reached the global header, stop reading
+ if(local_header[2] != 0x03 || local_header[3] != 0x04) break;
+
+ //read in the variable name
+ uint16_t name_len = *(uint16_t*) &local_header[26];
+ std::string vname(name_len,' ');
+ size_t vname_res = fread(&vname[0],sizeof(char),name_len,fp);
+ if(vname_res != name_len)
+ throw std::runtime_error("npz_load: failed fread");
+ vname.erase(vname.end()-4,vname.end()); //erase the lagging .npy
+
+ //read in the extra field
+ uint16_t extra_field_len = *(uint16_t*) &local_header[28];
+ fseek(fp,extra_field_len,SEEK_CUR); //skip past the extra field
+
+ uint16_t compr_method = *reinterpret_cast<uint16_t*>(&local_header[0]+8);
+ uint32_t compr_bytes = *reinterpret_cast<uint32_t*>(&local_header[0]+18);
+ uint32_t uncompr_bytes = *reinterpret_cast<uint32_t*>(&local_header[0]+22);
+
+ if(vname == varname) {
+ NpyArray array = (compr_method == 0) ? load_the_npy_file(fp) : load_the_npz_array(fp,compr_bytes,uncompr_bytes);
+ fclose(fp);
+ return array;
+ }
+ else {
+ //skip past the data
+ //uint32_t size = *(uint32_t*) &local_header[22];
+ uint32_t size = *(uint32_t*) &local_header[18]; // using index 18 instead of 22 enables support for compressed data
+ fseek(fp,size,SEEK_CUR);
+ }
+ }
+
+ fclose(fp);
+
+ //if we get here, we haven't found the variable in the file
+ throw std::runtime_error("npz_load: Variable name "+varname+" not found in "+fname);
+}
+
+cnpy::NpyArray cnpy::npy_load(std::string fname) {
+
+ FILE* fp = fopen(fname.c_str(), "rb");
+
+ if(!fp) throw std::runtime_error("npy_load: Unable to open file "+fname);
+
+ NpyArray arr = load_the_npy_file(fp);
+
+ fclose(fp);
+ return arr;
+}
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/dependencies/cnpy/cnpy.h b/intern/mantaflow/intern/manta_develop/dependencies/cnpy/cnpy.h
new file mode 100644
index 00000000000..0d3bb4c3c2e
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/dependencies/cnpy/cnpy.h
@@ -0,0 +1,269 @@
+//Copyright (C) 2011 Carl Rogers
+//Released under MIT License
+//license available in LICENSE file, or at http://www.opensource.org/licenses/mit-license.php
+
+#ifndef LIBCNPY_H_
+#define LIBCNPY_H_
+
+#include<string>
+#include<stdexcept>
+#include<sstream>
+#include<vector>
+#include<cstdio>
+#include<typeinfo>
+#include<iostream>
+#include<cassert>
+#include<zlib.h>
+#include<map>
+#include<memory>
+#include<stdint.h>
+#include<numeric>
+
+namespace cnpy {
+
+ struct NpyArray {
+ NpyArray(const std::vector<size_t>& _shape, size_t _word_size, bool _fortran_order) :
+ shape(_shape), word_size(_word_size), fortran_order(_fortran_order)
+ {
+ num_vals = 1;
+ for(size_t i = 0;i < shape.size();i++) num_vals *= shape[i];
+ data_holder = std::shared_ptr<std::vector<char>>(
+ new std::vector<char>(num_vals * word_size));
+ }
+
+ NpyArray() : shape(0), word_size(0), fortran_order(0), num_vals(0) { }
+
+ template<typename T>
+ T* data() {
+ return reinterpret_cast<T*>(&(*data_holder)[0]);
+ }
+
+ template<typename T>
+ const T* data() const {
+ return reinterpret_cast<T*>(&(*data_holder)[0]);
+ }
+
+ template<typename T>
+ std::vector<T> as_vec() const {
+ const T* p = data<T>();
+ return std::vector<T>(p, p+num_vals);
+ }
+
+ size_t num_bytes() const {
+ return data_holder->size();
+ }
+
+ std::shared_ptr<std::vector<char>> data_holder;
+ std::vector<size_t> shape;
+ size_t word_size;
+ bool fortran_order;
+ size_t num_vals;
+ };
+
+ using npz_t = std::map<std::string, NpyArray>;
+
+ char BigEndianTest();
+ char map_type(const std::type_info& t);
+ template<typename T> std::vector<char> create_npy_header(const std::vector<size_t>& shape);
+ void parse_npy_header(FILE* fp,size_t& word_size, std::vector<size_t>& shape, bool& fortran_order);
+ void parse_npy_header(unsigned char* buffer,size_t& word_size, std::vector<size_t>& shape, bool& fortran_order);
+ void parse_zip_footer(FILE* fp, uint16_t& nrecs, size_t& global_header_size, size_t& global_header_offset);
+ npz_t npz_load(std::string fname);
+ NpyArray npz_load(std::string fname, std::string varname);
+ NpyArray npy_load(std::string fname);
+
+ template<typename T> std::vector<char>& operator+=(std::vector<char>& lhs, const T rhs) {
+ //write in little endian
+ for(size_t byte = 0; byte < sizeof(T); byte++) {
+ char val = *((char*)&rhs+byte);
+ lhs.push_back(val);
+ }
+ return lhs;
+ }
+
+ template<> std::vector<char>& operator+=(std::vector<char>& lhs, const std::string rhs);
+ template<> std::vector<char>& operator+=(std::vector<char>& lhs, const char* rhs);
+
+
+ template<typename T> void npy_save(std::string fname, const T* data, const std::vector<size_t> shape, std::string mode = "w") {
+ FILE* fp = NULL;
+ std::vector<size_t> true_data_shape; //if appending, the shape of existing + new data
+
+ if(mode == "a") fp = fopen(fname.c_str(),"r+b");
+
+ if(fp) {
+ //file exists. we need to append to it. read the header, modify the array size
+ size_t word_size;
+ bool fortran_order;
+ parse_npy_header(fp,word_size,true_data_shape,fortran_order);
+ assert(!fortran_order);
+
+ if(word_size != sizeof(T)) {
+ std::cout<<"libnpy error: "<<fname<<" has word size "<<word_size<<" but npy_save appending data sized "<<sizeof(T)<<"\n";
+ assert( word_size == sizeof(T) );
+ }
+ if(true_data_shape.size() != shape.size()) {
+ std::cout<<"libnpy error: npy_save attempting to append misdimensioned data to "<<fname<<"\n";
+ assert(true_data_shape.size() != shape.size());
+ }
+
+ for(size_t i = 1; i < shape.size(); i++) {
+ if(shape[i] != true_data_shape[i]) {
+ std::cout<<"libnpy error: npy_save attempting to append misshaped data to "<<fname<<"\n";
+ assert(shape[i] == true_data_shape[i]);
+ }
+ }
+ true_data_shape[0] += shape[0];
+ }
+ else {
+ fp = fopen(fname.c_str(),"wb");
+ true_data_shape = shape;
+ }
+
+ std::vector<char> header = create_npy_header<T>(true_data_shape);
+ size_t nels = std::accumulate(shape.begin(),shape.end(),1,std::multiplies<size_t>());
+
+ fseek(fp,0,SEEK_SET);
+ fwrite(&header[0],sizeof(char),header.size(),fp);
+ fseek(fp,0,SEEK_END);
+ fwrite(data,sizeof(T),nels,fp);
+ fclose(fp);
+ }
+
+ template<typename T> void npz_save(std::string zipname, std::string fname, const T* data, const std::vector<size_t>& shape, std::string mode = "w")
+ {
+ //first, append a .npy to the fname
+ fname += ".npy";
+
+ //now, on with the show
+ FILE* fp = NULL;
+ uint16_t nrecs = 0;
+ size_t global_header_offset = 0;
+ std::vector<char> global_header;
+
+ if(mode == "a") fp = fopen(zipname.c_str(),"r+b");
+
+ if(fp) {
+ //zip file exists. we need to add a new npy file to it.
+ //first read the footer. this gives us the offset and size of the global header
+ //then read and store the global header.
+ //below, we will write the the new data at the start of the global header then append the global header and footer below it
+ size_t global_header_size;
+ parse_zip_footer(fp,nrecs,global_header_size,global_header_offset);
+ fseek(fp,global_header_offset,SEEK_SET);
+ global_header.resize(global_header_size);
+ size_t res = fread(&global_header[0],sizeof(char),global_header_size,fp);
+ if(res != global_header_size){
+ throw std::runtime_error("npz_save: header read error while adding to existing zip");
+ }
+ fseek(fp,global_header_offset,SEEK_SET);
+ }
+ else {
+ fp = fopen(zipname.c_str(),"wb");
+ }
+
+ std::vector<char> npy_header = create_npy_header<T>(shape);
+
+ size_t nels = std::accumulate(shape.begin(),shape.end(),1,std::multiplies<size_t>());
+ size_t nbytes = nels*sizeof(T) + npy_header.size();
+
+ //get the CRC of the data to be added
+ uint32_t crc = crc32(0L,(uint8_t*)&npy_header[0],npy_header.size());
+ crc = crc32(crc,(uint8_t*)data,nels*sizeof(T));
+
+ //build the local header
+ std::vector<char> local_header;
+ local_header += "PK"; //first part of sig
+ local_header += (uint16_t) 0x0403; //second part of sig
+ local_header += (uint16_t) 20; //min version to extract
+ local_header += (uint16_t) 0; //general purpose bit flag
+ local_header += (uint16_t) 0; //compression method
+ local_header += (uint16_t) 0; //file last mod time
+ local_header += (uint16_t) 0; //file last mod date
+ local_header += (uint32_t) crc; //crc
+ local_header += (uint32_t) nbytes; //compressed size
+ local_header += (uint32_t) nbytes; //uncompressed size
+ local_header += (uint16_t) fname.size(); //fname length
+ local_header += (uint16_t) 0; //extra field length
+ local_header += fname;
+
+ //build global header
+ global_header += "PK"; //first part of sig
+ global_header += (uint16_t) 0x0201; //second part of sig
+ global_header += (uint16_t) 20; //version made by
+ global_header.insert(global_header.end(),local_header.begin()+4,local_header.begin()+30);
+ global_header += (uint16_t) 0; //file comment length
+ global_header += (uint16_t) 0; //disk number where file starts
+ global_header += (uint16_t) 0; //internal file attributes
+ global_header += (uint32_t) 0; //external file attributes
+ global_header += (uint32_t) global_header_offset; //relative offset of local file header, since it begins where the global header used to begin
+ global_header += fname;
+
+ //build footer
+ std::vector<char> footer;
+ footer += "PK"; //first part of sig
+ footer += (uint16_t) 0x0605; //second part of sig
+ footer += (uint16_t) 0; //number of this disk
+ footer += (uint16_t) 0; //disk where footer starts
+ footer += (uint16_t) (nrecs+1); //number of records on this disk
+ footer += (uint16_t) (nrecs+1); //total number of records
+ footer += (uint32_t) global_header.size(); //nbytes of global headers
+ footer += (uint32_t) (global_header_offset + nbytes + local_header.size()); //offset of start of global headers, since global header now starts after newly written array
+ footer += (uint16_t) 0; //zip file comment length
+
+ //write everything
+ fwrite(&local_header[0],sizeof(char),local_header.size(),fp);
+ fwrite(&npy_header[0],sizeof(char),npy_header.size(),fp);
+ fwrite(data,sizeof(T),nels,fp);
+ fwrite(&global_header[0],sizeof(char),global_header.size(),fp);
+ fwrite(&footer[0],sizeof(char),footer.size(),fp);
+ fclose(fp);
+ }
+
+ template<typename T> void npy_save(std::string fname, const std::vector<T> data, std::string mode = "w") {
+ std::vector<size_t> shape;
+ shape.push_back(data.size());
+ npy_save(fname, &data[0], shape, mode);
+ }
+
+ template<typename T> void npz_save(std::string zipname, std::string fname, const std::vector<T> data, std::string mode = "w") {
+ std::vector<size_t> shape;
+ shape.push_back(data.size());
+ npz_save(zipname, fname, &data[0], shape, mode);
+ }
+
+ template<typename T> std::vector<char> create_npy_header(const std::vector<size_t>& shape) {
+
+ std::vector<char> dict;
+ dict += "{'descr': '";
+ dict += BigEndianTest();
+ dict += map_type(typeid(T));
+ dict += std::to_string(sizeof(T));
+ dict += "', 'fortran_order': False, 'shape': (";
+ dict += std::to_string(shape[0]);
+ for(size_t i = 1;i < shape.size();i++) {
+ dict += ", ";
+ dict += std::to_string(shape[i]);
+ }
+ if(shape.size() == 1) dict += ",";
+ dict += "), }";
+ //pad with spaces so that preamble+dict is modulo 16 bytes. preamble is 10 bytes. dict needs to end with \n
+ int remainder = 16 - (10 + dict.size()) % 16;
+ dict.insert(dict.end(),remainder,' ');
+ dict.back() = '\n';
+
+ std::vector<char> header;
+ header += (char) 0x93;
+ header += "NUMPY";
+ header += (char) 0x01; //major version of numpy format
+ header += (char) 0x00; //minor version of numpy format
+ header += (uint16_t) dict.size();
+ header.insert(header.end(),dict.begin(),dict.end());
+
+ return header;
+ }
+
+
+}
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/dependencies/cnpy/example1.cpp b/intern/mantaflow/intern/manta_develop/dependencies/cnpy/example1.cpp
new file mode 100644
index 00000000000..aba19322078
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/dependencies/cnpy/example1.cpp
@@ -0,0 +1,71 @@
+#include"cnpy.h"
+#include<complex>
+#include<cstdlib>
+#include<iostream>
+#include<map>
+#include<string>
+
+const int Nx = 128;
+const int Ny = 64;
+const int Nz = 32;
+
+int main()
+{
+ //set random seed so that result is reproducible (for testing)
+ srand(0);
+ //create random data
+ std::vector<std::complex<double>> data(Nx*Ny*Nz);
+ for(int i = 0;i < Nx*Ny*Nz;i++) data[i] = std::complex<double>(rand(),rand());
+
+ //save it to file
+ cnpy::npy_save("arr1.npy",&data[0],{Nz,Ny,Nx},"w");
+
+ //load it into a new array
+ cnpy::NpyArray arr = cnpy::npy_load("arr1.npy");
+ std::complex<double>* loaded_data = arr.data<std::complex<double>>();
+
+ //make sure the loaded data matches the saved data
+ assert(arr.word_size == sizeof(std::complex<double>));
+ assert(arr.shape.size() == 3 && arr.shape[0] == Nz && arr.shape[1] == Ny && arr.shape[2] == Nx);
+ for(int i = 0; i < Nx*Ny*Nz;i++) assert(data[i] == loaded_data[i]);
+
+ //append the same data to file
+ //npy array on file now has shape (Nz+Nz,Ny,Nx)
+ cnpy::npy_save("arr1.npy",&data[0],{Nz,Ny,Nx},"a");
+
+ //now write to an npz file
+ //non-array variables are treated as 1D arrays with 1 element
+ double myVar1 = 1.2;
+ char myVar2 = 'a';
+ cnpy::npz_save("out.npz","myVar1",&myVar1,{1},"w"); //"w" overwrites any existing file
+ cnpy::npz_save("out.npz","myVar2",&myVar2,{1},"a"); //"a" appends to the file we created above
+ cnpy::npz_save("out.npz","arr1",&data[0],{Nz,Ny,Nx},"a"); //"a" appends to the file we created above
+
+ //load a single var from the npz file
+ cnpy::NpyArray arr2 = cnpy::npz_load("out.npz","arr1");
+
+ //load the entire npz file
+ cnpy::npz_t my_npz = cnpy::npz_load("out.npz");
+
+ //check that the loaded myVar1 matches myVar1
+ cnpy::NpyArray arr_mv1 = my_npz["myVar1"];
+ double* mv1 = arr_mv1.data<double>();
+ assert(arr_mv1.shape.size() == 1 && arr_mv1.shape[0] == 1);
+ assert(mv1[0] == myVar1);
+
+ // std::cout << "Loading test.npz" << std::endl;
+ // cnpy::NpyArray test_npz_a = cnpy::npz_load("test.npz","a");
+ // cnpy::NpyArray test_npz_b = cnpy::npz_load("test.npz","b");
+
+ // std::cout << "test_npz_a: " << test_npz_a.word_size << std::endl;
+ // std::cout << "test_npz_b: " << test_npz_b.word_size << std::endl;
+
+ // auto b = test_npz_b.as_vec<float>();
+ // for ( auto b_entry : b)
+ // {
+ // std::cout << b_entry << " ";
+ // }
+ // std::cout << std::endl;
+ // cnpy::npz_save("test_a.npz", "a", test_npz_a.data<float>(), test_npz_a.shape, "w"); //"w" overwrites any existing file
+ // cnpy::npz_save("test_a.npz", "b", test_npz_b.data<float>(), test_npz_b.shape, "a"); //"a" appends to the file we created above
+}
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/manta.h b/intern/mantaflow/intern/manta_develop/helper/pwrapper/manta.h
new file mode 100644
index 00000000000..c0c22ae8ada
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/manta.h
@@ -0,0 +1,31 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Include pwrapper headers
+ *
+ ******************************************************************************/
+
+#ifndef _MANTA_H
+#define _MANTA_H
+
+// Remove preprocessor keywords, so there won't infere with autocompletion etc.
+#define KERNEL(...) extern int i,j,k,idx,X,Y,Z;
+#define PYTHON(...)
+#define returns(X) extern X;
+#define alias typedef
+
+#include "general.h"
+#include "vectorbase.h"
+#include "vector4d.h"
+#include "registry.h"
+#include "pclass.h"
+#include "pconvert.h"
+#include "fluidsolver.h"
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/numpyWrap.cpp b/intern/mantaflow/intern/manta_develop/helper/pwrapper/numpyWrap.cpp
new file mode 100644
index 00000000000..b9247b2e879
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/numpyWrap.cpp
@@ -0,0 +1,123 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2017-2018 Steffen Wiewel, Moritz Becher, Rachel Chu
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Convert mantaflow grids to/from numpy arrays
+ *
+ ******************************************************************************/
+
+#include "manta.h"
+#include "pythonInclude.h"
+
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+#include "numpy/arrayobject.h"
+
+namespace Manta {
+
+#if PY_VERSION_HEX < 0x03000000
+PyMODINIT_FUNC initNumpy() { import_array(); }
+#endif
+
+// ------------------------------------------------------------------------
+// Class Functions
+// ------------------------------------------------------------------------
+PyArrayContainer::PyArrayContainer(void *_pParentPyArray) :
+ pParentPyArray(_pParentPyArray)
+{
+ ExtractData(pParentPyArray);
+}
+// ------------------------------------------------------------------------
+PyArrayContainer::PyArrayContainer(const PyArrayContainer &_Other) :
+ pParentPyArray(_Other.pParentPyArray)
+{
+ ExtractData(pParentPyArray);
+ Py_INCREF(pParentPyArray);
+}
+// ------------------------------------------------------------------------
+PyArrayContainer::~PyArrayContainer()
+{
+ Py_DECREF(pParentPyArray);
+}
+// ------------------------------------------------------------------------
+PyArrayContainer &
+PyArrayContainer::operator=(const PyArrayContainer &_Other)
+{
+ if(this != &_Other) {
+ // DecRef the existing resource
+ Py_DECREF(pParentPyArray);
+
+ // Relink new data
+ pParentPyArray = _Other.pParentPyArray;
+ ExtractData(pParentPyArray);
+ Py_INCREF(pParentPyArray);
+ }
+ return *this;
+}
+// ------------------------------------------------------------------------
+void
+PyArrayContainer::ExtractData(void *_pParentPyArray)
+{
+ PyArrayObject *pParent = reinterpret_cast<PyArrayObject *>(pParentPyArray);
+
+ pData = PyArray_DATA(pParent);
+ TotalSize = PyArray_SIZE(pParent);
+
+ int iDataType = PyArray_TYPE(pParent);
+ switch(iDataType) {
+ case NPY_FLOAT:
+ DataType = N_FLOAT;
+ break;
+ case NPY_DOUBLE:
+ DataType = N_DOUBLE;
+ break;
+ case NPY_INT:
+ DataType = N_INT;
+ break;
+ default:
+ errMsg("unknown type of Numpy array");
+ break;
+ }
+}
+
+// ------------------------------------------------------------------------
+// Conversion Functions
+// ------------------------------------------------------------------------
+
+template<>
+PyArrayContainer
+fromPy<PyArrayContainer>(PyObject *obj)
+{
+ if(PyArray_API == NULL) {
+ // python 3 uses the return value
+# if PY_VERSION_HEX >= 0x03000000
+ import_array();
+# else
+ initNumpy();
+# endif
+ }
+
+ if(!PyArray_Check(obj)) {
+ errMsg("argument is not an numpy array");
+ }
+
+ PyArrayObject *obj_p = reinterpret_cast<PyArrayObject *>(PyArray_CheckFromAny(obj, NULL, 0, 0, /*NPY_ARRAY_ENSURECOPY*/ NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ENSUREARRAY | NPY_ARRAY_NOTSWAPPED, NULL));
+ PyArrayContainer container = PyArrayContainer(obj_p);
+
+ return container;
+}
+
+// template<> PyArrayContainer* fromPyPtr<PyArrayContainer>(PyObject* obj, std::vector<void*>* tmp)
+// {
+// if (!tmp) throw Error("dynamic de-ref not supported for this type");
+// void* ptr = malloc(sizeof(PyArrayContainer));
+// tmp->push_back(ptr);
+
+// *((PyArrayContainer*) ptr) = fromPy<PyArrayContainer>(obj);
+// return (PyArrayContainer*) ptr;
+// }
+}
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/numpyWrap.h b/intern/mantaflow/intern/manta_develop/helper/pwrapper/numpyWrap.h
new file mode 100644
index 00000000000..6db570409df
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/numpyWrap.h
@@ -0,0 +1,72 @@
+/******************************************************************************
+*
+* MantaFlow fluid solver framework
+* Copyright 2017 Steffen Wiewel, Moritz Baecher, Rachel Chu
+*
+* This program is free software, distributed under the terms of the
+* Apache License, Version 2.0
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Convert mantaflow grids to/from numpy arrays
+*
+******************************************************************************/
+
+#ifdef _PCONVERT_H
+#ifndef _NUMPYCONVERT_H
+#define _NUMPYCONVERT_H
+
+enum NumpyTypes
+{
+ N_BOOL = 0,
+ N_BYTE, N_UBYTE,
+ N_SHORT, N_USHORT,
+ N_INT, N_UINT,
+ N_LONG, N_ULONG,
+ N_LONGLONG, N_ULONGLONG,
+ N_FLOAT, N_DOUBLE, N_LONGDOUBLE,
+ N_CFLOAT, N_CDOUBLE, N_CLONGDOUBLE,
+ N_OBJECT = 17,
+ N_STRING, N_UNICODE,
+ N_VOID,
+ /*
+ * New 1.6 types appended, may be integrated
+ * into the above in 2.0.
+ */
+ N_DATETIME, N_TIMEDELTA, N_HALF,
+
+ N_NTYPES,
+ N_NOTYPE,
+ N_CHAR, /* special flag */
+ N_USERDEF = 256, /* leave room for characters */
+
+ /* The number of types not including the new 1.6 types */
+ N_NTYPES_ABI_COMPATIBLE = 21
+};
+
+namespace Manta
+{
+ class PyArrayContainer
+ {
+ public:
+ /// Constructors
+ PyArrayContainer(void *_pParentPyArray);
+ PyArrayContainer(const PyArrayContainer& _Other);
+ ~PyArrayContainer();
+ /// Operators
+ PyArrayContainer& operator=(const PyArrayContainer& _Other);
+ private:
+ void ExtractData(void* _pParentPyArray);
+ public:
+ void *pData;
+ NumpyTypes DataType;
+ unsigned int TotalSize;
+ private:
+ void *pParentPyArray;
+ };
+
+ //template<> PyArrayContainer* fromPyPtr<PyArrayContainer>(PyObject* obj, std::vector<void*>* tmp);
+ template<> PyArrayContainer fromPy<PyArrayContainer>(PyObject* obj);
+} // namespace
+
+#endif
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/pclass.cpp b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pclass.cpp
new file mode 100644
index 00000000000..0aa6bb1e709
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pclass.cpp
@@ -0,0 +1,188 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Functions for property setting/getting via python
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include "structmember.h"
+#include "manta.h"
+#include "general.h"
+#include "timing.h"
+
+#ifdef GUI
+# include <QMutex>
+#else
+class QMutex { public:
+ void lock() {};
+ void unlock() {};
+ bool tryLock() { return true; };
+};
+#endif
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// Free functions
+
+void pbPreparePlugin(FluidSolver* parent, const string& name, bool doTime) {
+ if(doTime) TimingData::instance().start(parent, name);
+}
+
+void pbFinalizePlugin(FluidSolver *parent, const string& name, bool doTime) {
+ if(doTime) TimingData::instance().stop(parent, name);
+
+ // GUI update, also print name of parent if there's more than one
+ std::ostringstream msg;
+ if (name != "FluidSolver::step")
+ {
+ if(parent && (parent->getNumInstances()>0) ) msg << parent->getName() << string(".");
+ msg << name;
+ }
+ updateQtGui(false, 0,0., msg.str() );
+
+ debMsg(name<<" done", 3);
+ // name unnamed PbClass Objects from var name
+ PbClass::renameObjects();
+}
+
+void pbSetError(const string& fn, const string& ex) {
+ debMsg("Error in " << fn, 1);
+ if (!ex.empty())
+ PyErr_SetString(PyExc_RuntimeError, ex.c_str());
+}
+
+//******************************************************************************
+// Helpers
+
+string PbTypeVec::str() const {
+ if (T.empty()) return "";
+ string s="<";
+ for (int i=0; i<(int)T.size(); i++) {
+ s += T[i].str();
+ s += (i!=(int)T.size()-1) ? ',' : '>';
+ }
+ return s;
+}
+string PbType::str() const {
+ if (S=="float") return "Real";
+ if (S=="manta.vec3") return "Vec3";
+ return S;
+}
+
+//******************************************************************************
+// PbClass
+
+vector<PbClass*> PbClass::mInstances;
+
+PbClass::PbClass(FluidSolver* parent, const string& name, PyObject* obj)
+ : mMutex(NULL), mParent(parent), mPyObject(obj), mName(name), mHidden(false)
+{
+ mMutex = new QMutex();
+}
+
+PbClass::PbClass(const PbClass& a) : mMutex(NULL), mParent(a.mParent), mPyObject(0), mName("_unnamed"), mHidden(false)
+{
+ mMutex = new QMutex();
+}
+
+
+PbClass::~PbClass() {
+ for(vector<PbClass*>::iterator it = mInstances.begin(); it != mInstances.end(); ++it) {
+ if (*it == this) {
+ mInstances.erase(it);
+ break;
+ }
+ }
+ delete mMutex;
+}
+
+void PbClass::lock() {
+ mMutex->lock();
+}
+void PbClass::unlock() {
+ mMutex->unlock();
+}
+bool PbClass::tryLock() {
+ return mMutex->tryLock();
+}
+
+PbClass* PbClass::getInstance(int idx) {
+ if (idx<0 || idx > (int)mInstances.size())
+ errMsg("PbClass::getInstance(): invalid index");
+ return mInstances[idx];
+}
+
+int PbClass::getNumInstances() {
+ return mInstances.size();
+}
+
+bool PbClass::isNullRef(PyObject* obj) {
+ return PyLong_Check(obj) && PyLong_AsDouble(obj)==0;
+}
+
+bool PbClass::isNoneRef(PyObject* obj) {
+ return (obj == Py_None);
+}
+
+void PbClass::registerObject(PyObject* obj, PbArgs* args) {
+ // cross link
+ Pb::setReference(this, obj);
+ mPyObject = obj;
+
+ mInstances.push_back(this);
+
+ if (args) {
+ string _name = args->getOpt<std::string>("name",-1,"");
+ if (!_name.empty()) setName(_name);
+ }
+}
+
+PbClass* PbClass::createPyObject(const string& classname, const string& name, PbArgs& args, PbClass* parent) {
+ return Pb::createPy(classname,name,args,parent);
+}
+
+void PbClass::checkParent() {
+ if (getParent() == NULL) {
+ errMsg("New class " + mName + ": no parent given -- specify using parent=xxx !");
+ }
+}
+//! Assign unnamed PbClass objects their Python variable name
+void PbClass::renameObjects() {
+ PyObject* sys_mod_dict = PyImport_GetModuleDict();
+ PyObject* loc_mod = PyMapping_GetItemString(sys_mod_dict, (char*)"__main__");
+ if (!loc_mod) return;
+ PyObject* locdict = PyObject_GetAttrString(loc_mod, "__dict__");
+ if (!locdict) return;
+
+ // iterate all PbClass instances
+ for (size_t i=0; i<mInstances.size(); i++) {
+ PbClass* obj = mInstances[i];
+ if (obj->getName().empty()) {
+ // empty, try to find instance in module local dictionary
+
+ PyObject *lkey, *lvalue;
+ Py_ssize_t lpos = 0;
+ while (PyDict_Next(locdict, &lpos, &lkey, &lvalue)) {
+ if (lvalue == obj->mPyObject) {
+ string varName = fromPy<string>(PyObject_Str(lkey));
+ obj->setName(varName);
+ //cout << "assigning variable name '" << varName << "' to unnamed instance" << endl;
+ break;
+ }
+ }
+ }
+ }
+ Py_DECREF(locdict);
+ Py_DECREF(loc_mod);
+}
+
+} // namespace
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/pclass.h b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pclass.h
new file mode 100644
index 00000000000..ccaefbcebd1
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pclass.h
@@ -0,0 +1,99 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Base class for all Python-exposed classes
+ *
+ ******************************************************************************/
+
+// -----------------------------------------------------------------
+// NOTE:
+// Do not include this file in user code, include "manta.h" instead
+// -----------------------------------------------------------------
+
+#ifdef _MANTA_H
+#ifndef _PTYPE_H
+#define _PTYPE_H
+
+#include <string>
+#include <vector>
+#include <map>
+
+class QMutex;
+
+namespace Manta {
+struct PbClassData;
+class FluidSolver;
+class PbArgs;
+
+struct PbType {
+ std::string S;
+ std::string str() const;
+};
+struct PbTypeVec {
+ std::vector<PbType> T;
+ std::string str() const;
+};
+
+//! Base class for all classes exposed to Python
+class PbClass {
+public:
+ PbClass(FluidSolver* parent, const std::string& name="", PyObject* obj=NULL);
+ PbClass(const PbClass& a);
+ virtual ~PbClass();
+
+ // basic property setter/getters
+ void setName(const std::string& name) { mName = name; }
+ std::string getName() const { return mName; }
+ PyObject* getPyObject() const { return mPyObject; }
+ void registerObject(PyObject* obj, PbArgs* args);
+ FluidSolver* getParent() const { return mParent; }
+ void setParent(FluidSolver* v) { mParent = v; }
+ void checkParent();
+
+ // hidden flag for GUI, debug output
+ inline bool isHidden() { return mHidden; }
+ inline void setHidden(bool v) { mHidden = v; }
+
+ void lock();
+ void unlock();
+ bool tryLock();
+
+ // PbClass instance registry
+ static int getNumInstances();
+ static PbClass* getInstance(int index);
+ static void renameObjects();
+
+ // converters
+ static bool isNullRef(PyObject* o);
+ static bool isNoneRef(PyObject* o);
+ static PbClass* createPyObject(const std::string& classname, const std::string& name, PbArgs& args, PbClass *parent);
+ inline bool canConvertTo(const std::string& classname) { return Pb::canConvert(mPyObject, classname); }
+
+protected:
+ QMutex* mMutex;
+ FluidSolver* mParent;
+ PyObject* mPyObject;
+ std::string mName;
+ bool mHidden;
+
+ static std::vector<PbClass*> mInstances;
+};
+
+//!\cond Register
+
+void pbFinalizePlugin(FluidSolver* parent, const std::string& name, bool doTime=true);
+void pbPreparePlugin(FluidSolver* parent, const std::string& name, bool doTime=true);
+void pbSetError(const std::string& fn, const std::string& ex);
+
+//!\endcond
+
+} // namespace
+
+#endif
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/pconvert.cpp b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pconvert.cpp
new file mode 100644
index 00000000000..a2fc2e9fd1b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pconvert.cpp
@@ -0,0 +1,471 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Python argument wrappers and conversion tools
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include <sstream>
+#include <algorithm>
+#include "vectorbase.h"
+#include "manta.h"
+
+using namespace std;
+
+//******************************************************************************
+// Explicit definition and instantiation of python object converters
+
+namespace Manta {
+
+extern PyTypeObject PbVec3Type;
+extern PyTypeObject PbVec4Type;
+
+struct PbVec3 {
+ PyObject_HEAD
+ float data[3];
+};
+
+struct PbVec4 {
+ PyObject_HEAD
+ float data[4];
+};
+
+PyObject* getPyNone() {
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+PyObject* incref(PyObject* obj) {
+ Py_INCREF(obj);
+ return obj;
+}
+
+
+/*template<> PyObject* toPy<PyObject*>(PyObject* obj) {
+ return obj;
+}*/
+template<> PyObject* toPy<int>( const int& v) {
+ return PyLong_FromLong(v);
+}
+/*template<> PyObject* toPy<char*>(const (char*) & val) {
+ return PyUnicode_DecodeLatin1(val,strlen(val),"replace");
+}*/
+template<> PyObject* toPy<string>( const string& val) {
+ return PyUnicode_DecodeLatin1(val.c_str(),val.length(),"replace");
+}
+template<> PyObject* toPy<float>( const float& v) {
+ return PyFloat_FromDouble(v);
+}
+template<> PyObject* toPy<double>( const double& v) {
+ return PyFloat_FromDouble(v);
+}
+template<> PyObject* toPy<bool>( const bool& v) {
+ return PyBool_FromLong(v);
+}
+template<> PyObject* toPy<Vec3i>(const Vec3i& v) {
+ float x=(float)v.x, y=(float)v.y, z=(float)v.z;
+ return PyObject_CallFunction((PyObject*)&PbVec3Type, (char*)"fff", x, y, z);
+}
+template<> PyObject* toPy<Vec3>(const Vec3& v) {
+ float x=(float)v.x, y=(float)v.y, z=(float)v.z;
+ return PyObject_CallFunction((PyObject*)&PbVec3Type, (char*)"fff", x, y, z);
+}
+template<> PyObject* toPy<Vec4i>(const Vec4i& v) {
+ float x=(float)v.x, y=(float)v.y, z=(float)v.z;
+ return PyObject_CallFunction((PyObject*)&PbVec4Type, (char*)"ffff", x, y, z);
+}
+template<> PyObject* toPy<Vec4>(const Vec4& v) {
+ float x=(float)v.x, y=(float)v.y, z=(float)v.z;
+ return PyObject_CallFunction((PyObject*)&PbVec4Type, (char*)"ffff", x, y, z);
+}
+template<> PyObject* toPy<PbClass*>(const PbClass_Ptr& obj) {
+ return obj->getPyObject();
+}
+
+template<> float fromPy<float>(PyObject* obj) {
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj)) return PyInt_AsLong(obj);
+#endif
+ if (PyFloat_Check(obj)) return PyFloat_AsDouble(obj);
+ if (PyLong_Check(obj)) return PyLong_AsDouble(obj);
+ errMsg("argument is not a float");
+}
+template<> double fromPy<double>(PyObject* obj) {
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj)) return PyInt_AsLong(obj);
+#endif
+ if (PyFloat_Check(obj)) return PyFloat_AsDouble(obj);
+ if (PyLong_Check(obj)) return PyLong_AsDouble(obj);
+ errMsg("argument is not a double");
+}
+template<> PyObject* fromPy<PyObject*>(PyObject *obj) {
+ return obj;
+}
+template<> int fromPy<int>(PyObject *obj) {
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj)) return PyInt_AsLong(obj);
+#endif
+ if (PyLong_Check(obj)) return PyLong_AsDouble(obj);
+ if (PyFloat_Check(obj)) {
+ double a = PyFloat_AsDouble(obj);
+ if (fabs(a-floor(a+0.5)) > 1e-5)
+ errMsg("argument is not an int");
+ return (int) (a+0.5);
+ }
+ errMsg("argument is not an int");
+}
+template<> string fromPy<string>(PyObject *obj) {
+ if (PyUnicode_Check(obj))
+ return PyBytes_AsString(PyUnicode_AsLatin1String(obj));
+#if PY_MAJOR_VERSION <= 2
+ else if (PyString_Check(obj))
+ return PyString_AsString(obj);
+#endif
+ else
+ errMsg("argument is not a string");
+}
+template<> const char* fromPy<const char*>(PyObject *obj) {
+ if (PyUnicode_Check(obj))
+ return PyBytes_AsString(PyUnicode_AsLatin1String(obj));
+#if PY_MAJOR_VERSION <= 2
+ else if (PyString_Check(obj))
+ return PyString_AsString(obj);
+#endif
+ else errMsg("argument is not a string");
+}
+template<> bool fromPy<bool>(PyObject *obj) {
+ if (!PyBool_Check(obj)) errMsg("argument is not a boolean");
+ return PyLong_AsLong(obj) != 0;
+}
+template<> Vec3 fromPy<Vec3>(PyObject* obj) {
+ if (PyObject_IsInstance(obj, (PyObject*)&PbVec3Type)) {
+ return Vec3(((PbVec3*)obj)->data);
+ }
+ else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
+ return Vec3(fromPy<Real>(PyTuple_GetItem(obj,0)),
+ fromPy<Real>(PyTuple_GetItem(obj,1)),
+ fromPy<Real>(PyTuple_GetItem(obj,2)));
+ }
+ errMsg("argument is not a Vec3");
+}
+template<> Vec3i fromPy<Vec3i>(PyObject* obj) {
+ if (PyObject_IsInstance(obj, (PyObject*)&PbVec3Type)) {
+ return toVec3iChecked(((PbVec3*)obj)->data);
+ }
+ else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
+ return Vec3i(fromPy<int>(PyTuple_GetItem(obj,0)),
+ fromPy<int>(PyTuple_GetItem(obj,1)),
+ fromPy<int>(PyTuple_GetItem(obj,2)));
+ }
+ errMsg("argument is not a Vec3i");
+}
+template<> Vec4 fromPy<Vec4>(PyObject* obj) {
+ if (PyObject_IsInstance(obj, (PyObject*)&PbVec4Type)) {
+ return Vec4(((PbVec4*)obj)->data);
+ }
+ else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
+ return Vec4(fromPy<Real>(PyTuple_GetItem(obj,0)),
+ fromPy<Real>(PyTuple_GetItem(obj,1)),
+ fromPy<Real>(PyTuple_GetItem(obj,2)),
+ fromPy<Real>(PyTuple_GetItem(obj,3)));
+ }
+ errMsg("argument is not a Vec4");
+}
+template<> Vec4i fromPy<Vec4i>(PyObject* obj) {
+ if (PyObject_IsInstance(obj, (PyObject*)&PbVec4Type)) {
+ return toVec4i(((PbVec4*)obj)->data);
+ }
+ else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
+ return Vec4i(fromPy<int>(PyTuple_GetItem(obj,0)),
+ fromPy<int>(PyTuple_GetItem(obj,1)),
+ fromPy<int>(PyTuple_GetItem(obj,2)),
+ fromPy<int>(PyTuple_GetItem(obj,3)));
+ }
+ errMsg("argument is not a Vec4i");
+}
+template<> PbType fromPy<PbType>(PyObject* obj) {
+ PbType pb = {""};
+ if (!PyType_Check(obj))
+ return pb;
+
+ const char* tname = ((PyTypeObject*)obj)->tp_name;
+ pb.S = tname;
+ return pb;
+}
+template<> PbTypeVec fromPy<PbTypeVec>(PyObject* obj) {
+ PbTypeVec vec;
+ if (PyType_Check(obj)) {
+ vec.T.push_back(fromPy<PbType>(obj));
+ } else if (PyTuple_Check(obj)) {
+ int sz = PyTuple_Size(obj);
+ for (int i=0; i< sz; i++)
+ vec.T.push_back(fromPy<PbType>(PyTuple_GetItem(obj,i)));
+ }
+ else
+ errMsg("argument is not a type tuple");
+ return vec;
+}
+
+template<class T> T* tmpAlloc(PyObject* obj,std::vector<void*>* tmp) {
+ if (!tmp) throw Error("dynamic de-ref not supported for this type");
+ void* ptr = malloc(sizeof(T));
+ tmp->push_back(ptr);
+
+ *((T*)ptr) = fromPy<T>(obj);
+ return (T*)ptr;
+}
+template<> float* fromPyPtr<float>(PyObject* obj, std::vector<void*>* tmp) { return tmpAlloc<float>(obj,tmp); }
+template<> double* fromPyPtr<double>(PyObject* obj, std::vector<void*>* tmp) { return tmpAlloc<double>(obj,tmp); }
+template<> int* fromPyPtr<int>(PyObject* obj, std::vector<void*>* tmp) { return tmpAlloc<int>(obj,tmp); }
+template<> std::string* fromPyPtr<std::string>(PyObject* obj, std::vector<void*>* tmp) { return tmpAlloc<std::string>(obj,tmp); }
+template<> bool* fromPyPtr<bool>(PyObject* obj, std::vector<void*>* tmp) { return tmpAlloc<bool>(obj,tmp); }
+template<> Vec3* fromPyPtr<Vec3>(PyObject* obj, std::vector<void*>* tmp) { return tmpAlloc<Vec3>(obj,tmp); }
+template<> Vec3i* fromPyPtr<Vec3i>(PyObject* obj, std::vector<void*>* tmp) { return tmpAlloc<Vec3i>(obj,tmp); }
+template<> Vec4* fromPyPtr<Vec4>(PyObject* obj, std::vector<void*>* tmp) { return tmpAlloc<Vec4>(obj,tmp); }
+template<> Vec4i* fromPyPtr<Vec4i>(PyObject* obj, std::vector<void*>* tmp) { return tmpAlloc<Vec4i>(obj,tmp); }
+
+template<> bool isPy<float>(PyObject* obj) {
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj)) return true;
+#endif
+ return PyFloat_Check(obj) || PyLong_Check(obj);
+}
+template<> bool isPy<double>(PyObject* obj) {
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj)) return true;
+#endif
+ return PyFloat_Check(obj) || PyLong_Check(obj);
+}
+template<> bool isPy<PyObject*>(PyObject *obj) {
+ return true;
+}
+template<> bool isPy<int>(PyObject *obj) {
+#if PY_MAJOR_VERSION <= 2
+ if (PyInt_Check(obj)) return true;
+#endif
+ if (PyLong_Check(obj)) return true;
+ if (PyFloat_Check(obj)) {
+ double a = PyFloat_AsDouble(obj);
+ return fabs(a-floor(a+0.5)) < 1e-5;
+ }
+ return false;
+}
+template<> bool isPy<string>(PyObject *obj) {
+ if (PyUnicode_Check(obj)) return true;
+#if PY_MAJOR_VERSION <= 2
+ if (PyString_Check(obj)) return true;
+#endif
+ return false;
+}
+template<> bool isPy<const char*>(PyObject *obj) {
+ if (PyUnicode_Check(obj)) return true;
+#if PY_MAJOR_VERSION <= 2
+ if (PyString_Check(obj)) return true;
+#endif
+ return false;
+}
+template<> bool isPy<bool>(PyObject *obj) {
+ return PyBool_Check(obj);
+}
+template<> bool isPy<Vec3>(PyObject* obj) {
+ if (PyObject_IsInstance(obj, (PyObject*)&PbVec3Type)) return true;
+ if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
+ return isPy<Real>(PyTuple_GetItem(obj,0)) &&
+ isPy<Real>(PyTuple_GetItem(obj,1)) &&
+ isPy<Real>(PyTuple_GetItem(obj,2));
+ }
+ return false;
+}
+template<> bool isPy<Vec3i>(PyObject* obj) {
+ if (PyObject_IsInstance(obj, (PyObject*)&PbVec3Type)) return true;
+ if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
+ return isPy<int>(PyTuple_GetItem(obj,0)) &&
+ isPy<int>(PyTuple_GetItem(obj,1)) &&
+ isPy<int>(PyTuple_GetItem(obj,2));
+ }
+ return false;
+}
+template<> bool isPy<Vec4>(PyObject* obj) {
+ if (PyObject_IsInstance(obj, (PyObject*)&PbVec4Type)) return true;
+ if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
+ return isPy<Real>(PyTuple_GetItem(obj,0)) &&
+ isPy<Real>(PyTuple_GetItem(obj,1)) &&
+ isPy<Real>(PyTuple_GetItem(obj,2)) &&
+ isPy<Real>(PyTuple_GetItem(obj,3));
+ }
+ return false;
+}
+template<> bool isPy<Vec4i>(PyObject* obj) {
+ if (PyObject_IsInstance(obj, (PyObject*)&PbVec4Type)) return true;
+ if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
+ return isPy<int>(PyTuple_GetItem(obj,0)) &&
+ isPy<int>(PyTuple_GetItem(obj,1)) &&
+ isPy<int>(PyTuple_GetItem(obj,2)) &&
+ isPy<int>(PyTuple_GetItem(obj,3));
+ }
+ return false;
+}
+template<> bool isPy<PbType>(PyObject* obj) {
+ return PyType_Check(obj);
+}
+
+//******************************************************************************
+// PbArgs class defs
+
+PbArgs PbArgs::EMPTY(NULL,NULL);
+
+PbArgs::PbArgs(PyObject* linarg, PyObject* dict) : mLinArgs(0), mKwds(0) {
+ setup(linarg, dict);
+}
+PbArgs::~PbArgs() {
+ for(int i=0; i<(int)mTmpStorage.size(); i++)
+ free(mTmpStorage[i]);
+ mTmpStorage.clear();
+}
+
+void PbArgs::copy(PbArgs& a) {
+ mKwds = a.mKwds;
+ mData = a.mData;
+ mLinData = a.mLinData;
+ mLinArgs = a.mLinArgs;
+
+}
+void PbArgs::clear() {
+ mLinArgs = 0;
+ mKwds = 0;
+ mData.clear();
+ mLinData.clear();
+}
+
+PbArgs& PbArgs::operator=(const PbArgs& a) {
+// mLinArgs = 0;
+// mKwds = 0;
+ return *this;
+}
+
+void PbArgs::setup(PyObject* linarg, PyObject* dict) {
+ if (dict) {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ DataElement el;
+ el.obj = value;
+ el.visited = false;
+ mData[fromPy<string>(key)] = el;
+ }
+ mKwds = dict;
+ }
+ if (linarg) {
+ size_t len = PyTuple_Size(linarg);
+ for (size_t i=0; i<len; i++) {
+ DataElement el;
+ el.obj = PyTuple_GetItem(linarg, i);
+ el.visited = false;
+ mLinData.push_back(el);
+ }
+ mLinArgs = linarg;
+ }
+}
+
+void PbArgs::addLinArg(PyObject* obj) {
+ DataElement el = { obj, false };
+ mLinData.push_back(el);
+}
+
+void PbArgs::check() {
+ if (has("nocheck")) return;
+
+ for(map<string, DataElement>::iterator it = mData.begin(); it != mData.end(); it++) {
+ if (!it->second.visited)
+ errMsg("Argument '" + it->first + "' unknown");
+ }
+ for(size_t i=0; i<mLinData.size(); i++) {
+ if (!mLinData[i].visited) {
+ stringstream s;
+ s << "Function does not read argument number #" << i;
+ errMsg(s.str());
+ }
+ }
+}
+
+FluidSolver* PbArgs::obtainParent() {
+ FluidSolver* solver = getPtrOpt<FluidSolver>("solver",-1,NULL);
+ if (solver != 0) return solver;
+
+ for(map<string, DataElement>::iterator it = mData.begin(); it != mData.end(); it++) {
+ PbClass* obj = Pb::objFromPy(it->second.obj);
+
+ if (obj) {
+ if (solver == NULL)
+ solver = obj->getParent();
+ }
+ }
+ for(vector<DataElement>::iterator it = mLinData.begin(); it != mLinData.end(); it++) {
+ PbClass* obj = Pb::objFromPy(it->obj);
+
+ if (obj) {
+ if (solver == NULL)
+ solver = obj->getParent();
+ }
+ }
+
+ return solver;
+}
+
+void PbArgs::visit(int number, const string& key) {
+ if (number >= 0 && number < (int)mLinData.size())
+ mLinData[number].visited = true;
+ map<string, DataElement>::iterator lu = mData.find(key);
+ if (lu != mData.end())
+ lu->second.visited = true;
+}
+
+PyObject* PbArgs::getItem(const std::string& key, bool strict, ArgLocker* lk) {
+ map<string, DataElement>::iterator lu = mData.find(key);
+ if (lu == mData.end()) {
+ if (strict)
+ errMsg ("Argument '" + key + "' is not defined.");
+ return NULL;
+ }
+ PbClass* pbo = Pb::objFromPy(lu->second.obj);
+ // try to lock
+ if (pbo && lk) lk->add(pbo);
+ return lu->second.obj;
+}
+
+PyObject* PbArgs::getItem(size_t number, bool strict, ArgLocker* lk) {
+ if (number >= mLinData.size()) {
+ if (!strict)
+ return NULL;
+ stringstream s;
+ s << "Argument number #" << number << " not specified.";
+ errMsg(s.str());
+ }
+ PbClass* pbo = Pb::objFromPy(mLinData[number].obj);
+ // try to lock
+ if (pbo && lk) lk->add(pbo);
+ return mLinData[number].obj;
+}
+
+//******************************************************************************
+// ArgLocker class defs
+
+void ArgLocker::add(PbClass* p) {
+ if (find(locks.begin(), locks.end(), p) == locks.end()) {
+ locks.push_back(p);
+ p->lock();
+ }
+}
+ArgLocker::~ArgLocker() {
+ for (size_t i=0; i<locks.size(); i++)
+ locks[i]->unlock();
+ locks.clear();
+}
+
+} // namespace
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/pconvert.h b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pconvert.h
new file mode 100644
index 00000000000..29b045af99e
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pconvert.h
@@ -0,0 +1,220 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Python argument wrappers and conversion tools
+ *
+ ******************************************************************************/
+
+// -----------------------------------------------------------------
+// NOTE:
+// Do not include this file in user code, include "manta.h" instead
+// -----------------------------------------------------------------
+
+#ifdef _MANTA_H
+#ifndef _PCONVERT_H
+#define _PCONVERT_H
+
+#include <string>
+#include <map>
+#include <vector>
+
+namespace Manta {
+template<class T> class Grid;
+
+
+//! Locks the given PbClass Arguments until ArgLocker goes out of scope
+struct ArgLocker {
+ void add(PbClass* p);
+ ~ArgLocker();
+ std::vector<PbClass*> locks;
+};
+
+PyObject* getPyNone();
+
+// for PbClass-derived classes
+template<class T> T* fromPyPtr(PyObject* obj, std::vector<void*>* tmp) {
+ if (PbClass::isNullRef(obj) || PbClass::isNoneRef(obj))
+ return 0;
+ PbClass* pbo = Pb::objFromPy(obj);
+ const std::string& type = Namify<T>::S;
+ if (!pbo || !(pbo->canConvertTo(type)))
+ throw Error("can't convert argument to " + type+"*");
+ return (T*)(pbo);
+}
+
+template<> float* fromPyPtr<float>(PyObject* obj, std::vector<void*>* tmp);
+template<> double* fromPyPtr<double>(PyObject* obj, std::vector<void*>* tmp);
+template<> int* fromPyPtr<int>(PyObject* obj, std::vector<void*>* tmp);
+template<> std::string* fromPyPtr<std::string>(PyObject* obj, std::vector<void*>* tmp);
+template<> bool* fromPyPtr<bool>(PyObject* obj, std::vector<void*>* tmp);
+template<> Vec3* fromPyPtr<Vec3>(PyObject* obj, std::vector<void*>* tmp);
+template<> Vec3i* fromPyPtr<Vec3i>(PyObject* obj, std::vector<void*>* tmp);
+template<> Vec4* fromPyPtr<Vec4>(PyObject* obj, std::vector<void*>* tmp);
+template<> Vec4i* fromPyPtr<Vec4i>(PyObject* obj, std::vector<void*>* tmp);
+
+PyObject* incref(PyObject* obj);
+template<class T> PyObject* toPy(const T& v) {
+ PyObject* obj = v.getPyObject();
+ if (obj) {
+ return incref(obj);
+ }
+ T* co = new T (v);
+ const std::string& type = Namify<typename remove_pointers<T>::type>::S;
+ return Pb::copyObject(co,type);
+}
+template<class T> bool isPy(PyObject* obj) {
+ if (PbClass::isNullRef(obj) || PbClass::isNoneRef(obj))
+ return false;
+ PbClass* pbo = Pb::objFromPy(obj);
+ const std::string& type = Namify<typename remove_pointers<T>::type>::S;
+ return pbo && pbo->canConvertTo(type);
+}
+
+template<class T> T fromPy(PyObject* obj) {
+ throw Error("Unknown type conversion. Did you pass a PbClass by value? Instead always pass grids/particlesystems/etc. by reference or using a pointer.");
+}
+
+// builtin types
+template<> float fromPy<float>(PyObject* obj);
+template<> double fromPy<double>(PyObject* obj);
+template<> int fromPy<int>(PyObject *obj);
+template<> PyObject* fromPy<PyObject*>(PyObject *obj);
+template<> std::string fromPy<std::string>(PyObject *obj);
+template<> const char* fromPy<const char*>(PyObject *obj);
+template<> bool fromPy<bool>(PyObject *obj);
+template<> Vec3 fromPy<Vec3>(PyObject* obj);
+template<> Vec3i fromPy<Vec3i>(PyObject* obj);
+template<> Vec4 fromPy<Vec4>(PyObject* obj);
+template<> Vec4i fromPy<Vec4i>(PyObject* obj);
+template<> PbType fromPy<PbType>(PyObject* obj);
+template<> PbTypeVec fromPy<PbTypeVec>(PyObject* obj);
+
+template<> PyObject* toPy<int>( const int& v);
+template<> PyObject* toPy<std::string>( const std::string& val);
+template<> PyObject* toPy<float>( const float& v);
+template<> PyObject* toPy<double>( const double& v);
+template<> PyObject* toPy<bool>( const bool& v);
+template<> PyObject* toPy<Vec3i>( const Vec3i& v);
+template<> PyObject* toPy<Vec3>( const Vec3& v);
+template<> PyObject* toPy<Vec4i>( const Vec4i& v);
+template<> PyObject* toPy<Vec4>( const Vec4& v);
+typedef PbClass* PbClass_Ptr;
+template<> PyObject* toPy<PbClass*>( const PbClass_Ptr & obj);
+
+template<> bool isPy<float>(PyObject* obj);
+template<> bool isPy<double>(PyObject* obj);
+template<> bool isPy<int>(PyObject *obj);
+template<> bool isPy<PyObject*>(PyObject *obj);
+template<> bool isPy<std::string>(PyObject *obj);
+template<> bool isPy<const char*>(PyObject *obj);
+template<> bool isPy<bool>(PyObject *obj);
+template<> bool isPy<Vec3>(PyObject* obj);
+template<> bool isPy<Vec3i>(PyObject* obj);
+template<> bool isPy<Vec4>(PyObject* obj);
+template<> bool isPy<Vec4i>(PyObject* obj);
+template<> bool isPy<PbType>(PyObject* obj);
+
+//! Encapsulation of python arguments
+class PbArgs {
+public:
+ PbArgs(PyObject *linargs = NULL, PyObject* dict = NULL);
+ ~PbArgs();
+ void setup(PyObject *linargs = NULL, PyObject* dict = NULL);
+
+ void check();
+ FluidSolver* obtainParent();
+
+ inline int numLinArgs() { return mLinData.size(); }
+
+ inline bool has(const std::string& key) {
+ return getItem(key, false) != NULL;
+ }
+ inline void deleteItem(const std::string& key) {
+ if( mData.find(key) != mData.end() )
+ mData.erase( mData.find(key) );
+ }
+
+ inline PyObject* linArgs() { return mLinArgs; }
+ inline PyObject* kwds() { return mKwds; }
+
+ void addLinArg(PyObject* obj);
+
+ template<class T> inline void add(const std::string& key, T arg) {
+ DataElement el = { toPy(arg), false };
+ mData[key] = el;
+ }
+ template<class T> inline T get(const std::string& key, int number=-1, ArgLocker *lk=NULL) {
+ visit(number, key);
+ PyObject* o = getItem(key, false, lk);
+ if (o) return fromPy<T>(o);
+ o = getItem(number, false, lk);
+ if (o) return fromPy<T>(o);
+ errMsg ("Argument '" + key + "' is not defined.");
+ }
+ template<class T> inline T getOpt(const std::string& key, int number, T defarg, ArgLocker *lk=NULL) {
+ visit(number, key);
+ PyObject* o = getItem(key, false, lk);
+ if (o) return fromPy<T>(o);
+ if (number >= 0) o = getItem(number, false, lk);
+ return (o) ? fromPy<T>(o) : defarg;
+ }
+ template<class T> inline T* getPtrOpt(const std::string& key, int number, T* defarg, ArgLocker *lk=NULL) {
+ visit(number, key);
+ PyObject* o = getItem(key, false, lk);
+ if (o) return fromPyPtr<T>(o,&mTmpStorage);
+ if (number >= 0) o = getItem(number, false, lk);
+ return o ? fromPyPtr<T>(o,&mTmpStorage) : defarg;
+ }
+ template<class T> inline T* getPtr(const std::string& key, int number = -1, ArgLocker *lk=NULL) {
+ visit(number, key);
+ PyObject* o = getItem(key, false, lk);
+ if (o) return fromPyPtr<T>(o,&mTmpStorage);
+ o = getItem(number, false, lk);
+ if(o) return fromPyPtr<T>(o,&mTmpStorage);
+ errMsg ("Argument '" + key + "' is not defined.");
+ }
+
+
+ // automatic template type deduction
+ template<class T> bool typeCheck(int num, const std::string& name) {
+ PyObject* o = getItem(name, false, 0);
+ if (!o)
+ o = getItem(num, false, 0);
+ return o ? isPy<typename remove_pointers<T>::type>(o) : false;
+ }
+
+ PbArgs& operator=(const PbArgs& a); // dummy
+ void copy(PbArgs& a);
+ void clear();
+ void visit(int num, const std::string& key);
+
+ static PbArgs EMPTY;
+
+protected:
+ PyObject* getItem(const std::string& key, bool strict, ArgLocker* lk = NULL);
+ PyObject* getItem(size_t number, bool strict, ArgLocker* lk = NULL);
+
+ struct DataElement {
+ PyObject *obj;
+ bool visited;
+ };
+ std::map<std::string, DataElement> mData;
+ std::vector<DataElement> mLinData;
+ PyObject* mLinArgs, *mKwds;
+ std::vector<void*> mTmpStorage;
+};
+
+} // namespace
+
+#if NUMPY==1
+#include "numpyWrap.h"
+#endif
+
+#endif
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/pvec3.cpp b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pvec3.cpp
new file mode 100644
index 00000000000..4af6eb16f94
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pvec3.cpp
@@ -0,0 +1,393 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vec3 class extension for python
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include <string>
+#include <sstream>
+#include "vectorbase.h"
+#include "structmember.h"
+#include "manta.h"
+
+using namespace std;
+
+namespace Manta {
+
+extern PyTypeObject PbVec3Type;
+
+struct PbVec3 {
+ PyObject_HEAD
+ float data[3];
+};
+
+static void PbVec3Dealloc(PbVec3* self) {
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * PbVec3New(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ return type->tp_alloc(type, 0);
+}
+
+static int PbVec3Init(PbVec3 *self, PyObject *args, PyObject *kwds) {
+
+ float x1 = numeric_limits<float>::quiet_NaN(), x2=x1, x3=x1;
+ if (!PyArg_ParseTuple(args,"|fff",&x1, &x2, &x3))
+ return -1;
+
+ if (!c_isnan(x1)) {
+ self->data[0] = x1;
+ if (!c_isnan(x2) && !c_isnan(x3)) {
+ self->data[1] = x2;
+ self->data[2] = x3;
+ } else {
+ if (!c_isnan(x2) || !c_isnan(x3)) { errMsg("Invalid partial init of vec3"); }
+ self->data[1] = x1;
+ self->data[2] = x1;
+ }
+ } else {
+ self->data[0] = 0;
+ self->data[1] = 0;
+ self->data[2] = 0;
+ }
+ return 0;
+}
+
+static PyObject* PbVec3Repr(PbVec3* self) {
+ Manta::Vec3 v(self->data[0], self->data[1], self->data[2]);
+ return PyUnicode_FromFormat(v.toString().c_str());
+}
+
+static PyMemberDef PbVec3Members[] = {
+ {(char*)"x", T_FLOAT, offsetof(PbVec3, data), 0, (char*)"X"},
+ {(char*)"y", T_FLOAT, offsetof(PbVec3, data)+sizeof(float), 0, (char*)"Y"},
+ {(char*)"z", T_FLOAT, offsetof(PbVec3, data)+sizeof(float)*2, 0, (char*)"Z"},
+ {NULL} // Sentinel
+};
+
+static PyMethodDef PbVec3Methods[] = {
+ //{"name", (PyCFunction)Noddy_name, METH_NOARGS, "Return the name, combining the first and last name" },
+ {NULL} // Sentinel
+};
+
+// operator overloads
+
+inline PyObject* PbNew(const Vec3& a) {
+ PbVec3* obj = (PbVec3*)PbVec3New(&PbVec3Type,0,0);
+ obj->data[0] = a.x;
+ obj->data[1] = a.y;
+ obj->data[2] = a.z;
+ return (PyObject*)obj;
+}
+
+#define CONVERTVEC(obj) \
+ Vec3 v##obj; \
+ if (PyObject_TypeCheck(obj, &PbVec3Type)) \
+ v##obj = Vec3(&( ((PbVec3*)obj)->data[0])); \
+ else if (PyFloat_Check(obj)) \
+ v##obj = Vec3(PyFloat_AsDouble(obj)); \
+ else if (PyLong_Check(obj)) \
+ v##obj = Vec3(PyLong_AsDouble(obj)); \
+ else { \
+ Py_INCREF(Py_NotImplemented); \
+ return Py_NotImplemented; \
+ } \
+
+#define OPHEADER \
+ if (!PyObject_TypeCheck(a, &PbVec3Type) && !PyObject_TypeCheck(b, &PbVec3Type)) { \
+ Py_INCREF(Py_NotImplemented); \
+ return Py_NotImplemented; \
+ } \
+ CONVERTVEC(a) \
+ CONVERTVEC(b)
+
+#define OPHEADER1 \
+ if (!PyObject_TypeCheck(a, &PbVec3Type)) { \
+ Py_INCREF(Py_NotImplemented); \
+ return Py_NotImplemented; \
+ } \
+ CONVERTVEC(a)
+
+PyObject* PbVec3Add(PyObject* a, PyObject* b) {
+ OPHEADER
+ return PbNew(va+vb);
+}
+
+PyObject* PbVec3Sub(PyObject* a, PyObject* b) {
+ OPHEADER
+ return PbNew(va-vb);
+}
+
+PyObject* PbVec3Mult(PyObject* a, PyObject* b) {
+ OPHEADER
+ return PbNew(va*vb);
+}
+
+PyObject* PbVec3Div(PyObject* a, PyObject* b) {
+ OPHEADER
+ return PbNew(va/vb);
+}
+
+PyObject* PbVec3Negative(PyObject* a) {
+ OPHEADER1
+ return PbNew(-va);
+}
+
+// numbers are defined subtely different in Py3 (WTF?)
+#if PY_MAJOR_VERSION >= 3
+static PyNumberMethods PbVec3NumberMethods = {
+ (binaryfunc)PbVec3Add, // binaryfunc nb_add;
+ (binaryfunc)PbVec3Sub, // binaryfunc nb_sub;
+ (binaryfunc)PbVec3Mult, // binaryfunc nb_mult;
+ 0, // binaryfunc nb_remainder;
+ 0, // binaryfunc nb_divmod;
+ 0, // ternaryfunc nb_power;
+ (unaryfunc)PbVec3Negative, // unaryfunc nb_negative;
+ 0, // unaryfunc nb_positive;
+ 0, // unaryfunc nb_absolute;
+ 0, // inquiry nb_bool;
+ 0, // unaryfunc nb_invert;
+ 0, // binaryfunc nb_lshift;
+ 0, // binaryfunc nb_rshift;
+ 0, // binaryfunc nb_and;
+ 0, // binaryfunc nb_xor;
+ 0, // binaryfunc nb_or;
+ 0, // unaryfunc nb_int;
+ 0, // void *nb_reserved;
+ 0, // unaryfunc nb_float;
+ 0, // binaryfunc nb_inplace_add;
+ 0, // binaryfunc nb_inplace_subtract;
+ 0, // binaryfunc nb_inplace_multiply;
+ 0, // binaryfunc nb_inplace_remainder;
+ 0, // ternaryfunc nb_inplace_power;
+ 0, // binaryfunc nb_inplace_lshift;
+ 0, // binaryfunc nb_inplace_rshift;
+ 0, // binaryfunc nb_inplace_and;
+ 0, // binaryfunc nb_inplace_xor;
+ 0, // binaryfunc nb_inplace_or;
+
+ 0, // binaryfunc nb_floor_divide;
+ (binaryfunc)PbVec3Div, // binaryfunc nb_true_divide;
+ 0, // binaryfunc nb_inplace_floor_divide;
+ 0, // binaryfunc nb_inplace_true_divide;
+
+ 0 // unaryfunc nb_index;
+};
+#else
+static PyNumberMethods PbVec3NumberMethods = {
+ (binaryfunc)PbVec3Add, // binaryfunc nb_add;
+ (binaryfunc)PbVec3Sub, // binaryfunc nb_sub;
+ (binaryfunc)PbVec3Mult, // binaryfunc nb_mult;
+ 0, // binaryfunc nb_divide;
+ 0, // binaryfunc nb_remainder;
+ 0, // binaryfunc nb_divmod;
+ 0, // ternaryfunc nb_power;
+ (unaryfunc)PbVec3Negative, // unaryfunc nb_negative;
+ 0, // unaryfunc nb_positive;
+ 0, // unaryfunc nb_absolute;
+ 0, // inquiry nb_nonzero;
+ 0, // unaryfunc nb_invert;
+ 0, // binaryfunc nb_lshift;
+ 0, // binaryfunc nb_rshift;
+ 0, // binaryfunc nb_and;
+ 0, // binaryfunc nb_xor;
+ 0, // binaryfunc nb_or;
+ 0, // coercion nb_coerce;
+ 0, // unaryfunc nb_int;
+ 0, // unaryfunc nb_long;
+ 0, // unaryfunc nb_float;
+ 0, // unaryfunc nb_oct;
+ 0, // unaryfunc nb_hex;
+ 0, // binaryfunc nb_inplace_add;
+ 0, // binaryfunc nb_inplace_subtract;
+ 0, // binaryfunc nb_inplace_multiply;
+ 0, // binaryfunc nb_inplace_divide;
+ 0, // binaryfunc nb_inplace_remainder;
+ 0, // ternaryfunc nb_inplace_power;
+ 0, // binaryfunc nb_inplace_lshift;
+ 0, // binaryfunc nb_inplace_rshift;
+ 0, // binaryfunc nb_inplace_and;
+ 0, // binaryfunc nb_inplace_xor;
+ 0, // binaryfunc nb_inplace_or;
+ 0, // binaryfunc nb_floor_divide;
+ (binaryfunc)PbVec3Div, // binaryfunc nb_true_divide;
+ 0, // binaryfunc nb_inplace_floor_divide;
+ 0, // binaryfunc nb_inplace_true_divide;
+ 0, // unaryfunc nb_index;
+};
+#endif
+
+PyTypeObject PbVec3Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "manta.vec3", /* tp_name */
+ sizeof(PbVec3), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)PbVec3Dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)PbVec3Repr, /* tp_repr */
+ &PbVec3NumberMethods, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /* tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ "float vector type", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ PbVec3Methods, /* tp_methods */
+ PbVec3Members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)PbVec3Init, /* tp_init */
+ 0, /* tp_alloc */
+ PbVec3New, /* tp_new */
+};
+
+inline PyObject* castPy(PyTypeObject* p) {
+ return reinterpret_cast<PyObject*>(static_cast<void*>(p));
+}
+
+
+// 4d vector
+
+extern PyTypeObject PbVec4Type;
+
+struct PbVec4 {
+ PyObject_HEAD
+ float data[4];
+};
+
+static PyMethodDef PbVec4Methods[] = {
+ {NULL} // Sentinel
+};
+
+static PyMemberDef PbVec4Members[] = {
+ {(char*)"x", T_FLOAT, offsetof(PbVec4, data), 0, (char*)"X"},
+ {(char*)"y", T_FLOAT, offsetof(PbVec4, data)+sizeof(float)*1, 0, (char*)"Y"},
+ {(char*)"z", T_FLOAT, offsetof(PbVec4, data)+sizeof(float)*2, 0, (char*)"Z"},
+ {(char*)"t", T_FLOAT, offsetof(PbVec4, data)+sizeof(float)*3, 0, (char*)"T"},
+ {NULL} // Sentinel
+};
+
+
+static void PbVec4Dealloc(PbVec4* self) {
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * PbVec4New(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ return type->tp_alloc(type, 0);
+}
+
+static int PbVec4Init(PbVec4 *self, PyObject *args, PyObject *kwds) {
+
+ float x1 = numeric_limits<float>::quiet_NaN(), x2=x1, x3=x1, x4=x1;
+ if (!PyArg_ParseTuple(args,"|ffff",&x1, &x2, &x3, &x4))
+ return -1;
+
+ if (!c_isnan(x1)) {
+ self->data[0] = x1;
+ if (!c_isnan(x2) && !c_isnan(x3) && !c_isnan(x4)) {
+ self->data[1] = x2;
+ self->data[2] = x3;
+ self->data[3] = x4;
+ } else {
+ if (!c_isnan(x2) || !c_isnan(x3) || !c_isnan(x4)) { errMsg("Invalid partial init of vec4"); }
+ self->data[1] = self->data[2] = self->data[3] = x1;
+ }
+ } else {
+ self->data[0] = self->data[1] = self->data[2] = self->data[3] = 0;
+ }
+ return 0;
+}
+
+static PyObject* PbVec4Repr(PbVec4* self) {
+ Manta::Vec4 v(self->data[0], self->data[1], self->data[2], self->data[3]);
+ return PyUnicode_FromFormat(v.toString().c_str());
+}
+
+PyTypeObject PbVec4Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "manta.vec4", /* tp_name */
+ sizeof(PbVec4), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)PbVec4Dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)PbVec4Repr, /* tp_repr */
+ NULL, // &PbVec4NumberMethods, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /* tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ "float vector type", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ PbVec4Methods, /* tp_methods */
+ PbVec4Members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)PbVec4Init, /* tp_init */
+ 0, /* tp_alloc */
+ PbVec4New, /* tp_new */
+};
+
+// register
+
+void PbVecInitialize(PyObject* module) {
+ if (PyType_Ready(&PbVec3Type) < 0) errMsg("can't initialize Vec3 type");
+ Py_INCREF(castPy(&PbVec3Type));
+ PyModule_AddObject(module, "vec3", (PyObject *)&PbVec3Type);
+
+ if (PyType_Ready(&PbVec4Type) < 0) errMsg("can't initialize Vec4 type");
+ Py_INCREF(castPy(&PbVec4Type));
+ PyModule_AddObject(module, "vec4", (PyObject *)&PbVec4Type);
+}
+const static Pb::Register _REG(PbVecInitialize);
+
+} // namespace
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/pymain.cpp b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pymain.cpp
new file mode 100644
index 00000000000..4225ecdef52
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pymain.cpp
@@ -0,0 +1,125 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Main file
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include <stdio.h>
+#include "manta.h"
+#include "general.h"
+#include "wchar.h"
+
+namespace Manta {
+ extern void guiMain(int argc, char* argv[]);
+ extern void guiWaitFinish();
+}
+
+using namespace std;
+using namespace Manta;
+
+#if PY_MAJOR_VERSION >= 3
+typedef wchar_t pyChar;
+typedef wstring pyString;
+#else
+typedef char pyChar;
+typedef string pyString;
+#endif
+
+//*****************************************************************************
+// main...
+
+void runScript(vector<string>& args) {
+ string filename = args[0];
+
+ // Initialize extension classes and wrappers
+ srand(0);
+ Pb::setup(filename, args);
+
+ // Pass through the command line arguments
+ // for Py3k compatability, convert to wstring
+ vector<pyString> pyArgs(args.size());
+ const pyChar ** cargs = new const pyChar* [args.size()];
+ for (size_t i=0; i<args.size(); i++) {
+ pyArgs[i] = pyString(args[i].begin(), args[i].end());
+ cargs[i] = pyArgs[i].c_str();
+ }
+ PySys_SetArgv( args.size(), (pyChar**) cargs);
+
+ // Try to load python script
+ FILE* fp = fopen(filename.c_str(),"rb");
+ if (fp == NULL) {
+ debMsg("Cannot open '" << filename << "'", 0);
+ Pb::finalize();
+ return;
+ }
+
+ // Run the python script file
+ debMsg("Loading script '" << filename << "'", 0);
+#if defined(WIN32) || defined(_WIN32)
+ // known bug workaround: use simplestring
+ fseek(fp,0,SEEK_END);
+ long filelen=ftell(fp);
+ fseek(fp,0,SEEK_SET);
+ char* buf = new char[filelen+1];
+ fread(buf,filelen,1,fp);
+ buf[filelen] = '\0';
+ fclose(fp);
+ PyRun_SimpleString(buf);
+ delete[] buf;
+#else
+ // for linux, use this as it produces nicer error messages
+ PyRun_SimpleFileEx(fp, filename.c_str(), 0);
+ fclose(fp);
+#endif
+
+ debMsg("Script finished.", 0);
+#ifdef GUI
+ guiWaitFinish();
+#endif
+
+ // finalize
+ Pb::finalize();
+
+ delete [] cargs;
+}
+
+int main(int argc,char* argv[]) {
+ debMsg("Version: "<< buildInfoString() , 1);
+
+ bool doScript = true;
+
+#ifdef GUI
+ // optionally, disable UI
+ bool doGui = true;
+ if( getenv("MANTA_DISABLE_UI") && atoi( getenv("MANTA_DISABLE_UI") )) {
+ debMsg("GUI disabled",0);
+ doGui = false;
+ }
+
+ if(doGui) {
+ guiMain(argc, argv);
+ doScript = false;
+ }
+#endif
+
+ if(doScript) {
+ if (argc<=1) {
+ cerr << "Usage : Syntax is 'manta <config.py>'" << endl;
+ return 1;
+ }
+
+ vector<string> args;
+ for (int i=1; i<argc; i++) args.push_back(argv[i]);
+ runScript(args);
+ }
+
+ return 0;
+}
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/pythonInclude.h b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pythonInclude.h
new file mode 100644
index 00000000000..238816830df
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/pythonInclude.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Base class for particle systems
+ *
+ ******************************************************************************/
+
+#ifndef _PYTHONINCLUDE_H
+#define _PYTHONINCLUDE_H
+
+#if defined(WIN32) || defined(_WIN32)
+
+ // note - we have to include these first!
+ #include <string>
+ #include <vector>
+ #include <iostream>
+
+#endif
+
+// the PYTHON_DEBUG_WITH_RELEASE define enables linking with python debug libraries
+#if (defined(_DEBUG)||(DEBUG==1)) && defined(DEBUG_PYTHON_WITH_RELEASE)
+
+ // special handling, disable linking with debug version of python libs
+ #undef _DEBUG
+ #define NDEBUG
+ #include <Python.h>
+ #if NUMPY==1
+ # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+ # include "numpy/arrayobject.h"
+ #endif
+ #define _DEBUG
+ #undef NDEBUG
+
+#else
+ #include <Python.h>
+ #if NUMPY==1
+ # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+ # include "numpy/arrayobject.h"
+ #endif
+#endif
+
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/registry.cpp b/intern/mantaflow/intern/manta_develop/helper/pwrapper/registry.cpp
new file mode 100644
index 00000000000..5eed4ef8b29
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/registry.cpp
@@ -0,0 +1,681 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Auto python registry
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "pythonInclude.h"
+#include "structmember.h"
+#include "manta.h"
+
+using namespace std;
+
+const string gDefaultModuleName = "manta";
+
+namespace Pb {
+
+//******************************************************************************
+// Custom object definition
+
+struct Method {
+ Method(const string& n, const string& d, GenericFunction f) : name(n), doc(d), func(f) {}
+ string name, doc;
+ GenericFunction func;
+
+ PyMethodDef def() {
+ PyMethodDef def = {&name[0], (PyCFunction)func, METH_VARARGS | METH_KEYWORDS, &doc[0]};
+ return def;
+ }
+};
+struct GetSet {
+ GetSet() : getter(0),setter(0) {}
+ GetSet(const string& n, const string& d, Getter g, Setter s) : name(n), doc(d), getter(g), setter(s) {}
+ string name, doc;
+ Getter getter;
+ Setter setter;
+
+ PyGetSetDef def() {
+ PyGetSetDef def = {&name[0], getter, setter, &doc[0], NULL};
+ return def;
+ }
+};
+
+struct ClassData {
+ string cName, pyName;
+ string cPureName, cTemplate;
+ InitFunc init;
+ PyTypeObject typeInfo;
+ PyNumberMethods numInfo;
+ //PySequenceMethods seqInfo;
+ vector<Method> methods;
+ map<string,GetSet> getset;
+ map<string,OperatorFunction> ops;
+ ClassData* baseclass;
+ string baseclassName;
+ Constructor constructor;
+
+ vector<PyMethodDef> genMethods;
+ vector<PyGetSetDef> genGetSet;
+};
+
+struct PbObject {
+ PyObject_HEAD
+ Manta::PbClass *instance;
+ ClassData *classdef;
+};
+
+//******************************************************
+// Internal wrapper class
+
+//! Registers all classes and methods exposed to Python.
+/*! This class is only used internally by Pb:: framwork.
+ * Please use the functionality of PbClass to lookup and translate pointers. */
+class WrapperRegistry {
+public:
+ static WrapperRegistry& instance();
+ void addClass(const std::string& name, const std::string& internalName, const std::string& baseclass);
+ void addEnumEntry(const std::string& name, int value);
+ void addExternalInitializer(InitFunc func);
+ void addMethod(const std::string& classname, const std::string& methodname, GenericFunction method);
+ void addOperator(const std::string& classname, const std::string& methodname, OperatorFunction method);
+ void addConstructor(const std::string& classname, Constructor method);
+ void addGetSet(const std::string& classname, const std::string& property, Getter getfunc, Setter setfunc);
+ void addPythonPath(const std::string& path);
+ void addPythonCode(const std::string& file, const std::string& code);
+ PyObject* createPyObject(const std::string& classname, const std::string& name, Manta::PbArgs& args, Manta::PbClass *parent);
+ void construct(const std::string& scriptname, const vector<string>& args);
+ void cleanup();
+ void renameObjects();
+ void runPreInit();
+ PyObject* initModule();
+ ClassData* lookup(const std::string& name);
+ bool canConvert(ClassData* from, ClassData* to);
+private:
+ ClassData* getOrConstructClass(const string& name);
+ void registerBaseclasses();
+ void registerDummyTypes();
+ void registerMeta();
+ void addConstants(PyObject* module);
+ void registerOperators(ClassData* cls);
+ void addParentMethods(ClassData* cls, ClassData* base);
+ WrapperRegistry();
+ std::map<std::string, ClassData*> mClasses;
+ std::vector<ClassData*> mClassList;
+ std::vector<InitFunc> mExtInitializers;
+ std::vector<std::string> mPaths;
+ std::string mCode, mScriptName;
+ std::vector<std::string> args;
+ std::map<std::string, int> mEnumValues;
+};
+
+//******************************************************************************
+// Callback functions
+
+PyObject* cbGetClass(PbObject* self, void* cl) {
+ return Manta::toPy(self->classdef->cPureName);
+}
+
+PyObject* cbGetTemplate(PbObject* self, void* cl) {
+ return Manta::toPy(self->classdef->cTemplate);
+}
+
+PyObject* cbGetCName(PbObject* self, void* cl) {
+ return Manta::toPy(self->classdef->cName);
+}
+
+void cbDealloc(PbObject* self) {
+ //cout << "dealloc " << self->instance->getName() << " " << self->classdef->cName << endl;
+ if (self->instance) {
+ #ifndef BLENDER
+ // don't delete top-level objects
+ if (self->instance->getParent() != self->instance)
+ delete self->instance;
+ #else
+ // in Blender we *have* to delete all objects
+ delete self->instance;
+ #endif
+ }
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+PyObject* cbNew(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PbObject *self = (PbObject*) type->tp_alloc(type, 0);
+ if (self != NULL) {
+ // lookup and link classdef
+ self->classdef = WrapperRegistry::instance().lookup(type->tp_name);
+ self->instance = NULL;
+ //cout << "creating " << self->classdef->cName << endl;
+ } else
+ errMsg("can't allocate new python class object");
+ return (PyObject*) self;
+}
+
+int cbDisableConstructor(PyObject* self, PyObject* args, PyObject* kwds) {
+ errMsg("Can't instantiate a class template without template arguments");
+ return -1;
+}
+
+PyMODINIT_FUNC PyInit_Main(void) {
+ MantaEnsureRegistration();
+#if PY_MAJOR_VERSION >= 3
+ return WrapperRegistry::instance().initModule();
+#else
+ WrapperRegistry::instance().initModule();
+#endif
+}
+
+//******************************************************
+// WrapperRegistry
+
+WrapperRegistry::WrapperRegistry() {
+ addClass("__modclass__", "__modclass__" , "");
+ addClass("PbClass", "PbClass", "");
+}
+
+ClassData* WrapperRegistry::getOrConstructClass(const string& classname) {
+ map<string,ClassData*>::iterator it = mClasses.find(classname);
+
+ if (it != mClasses.end())
+ return it->second;
+ ClassData* data = new ClassData;
+ data->cName = classname;
+ data->cPureName = classname;
+ data->cTemplate = "";
+ size_t tplIdx = classname.find('<');
+ if (tplIdx != string::npos) {
+ data->cPureName = classname.substr(0,tplIdx);
+ data->cTemplate = classname.substr(tplIdx+1, classname.find('>')-tplIdx-1);
+ }
+ data->baseclass = NULL;
+ data->constructor = cbDisableConstructor;
+ mClasses[classname] = data;
+ mClassList.push_back(data);
+ return data;
+}
+
+void replaceAll(string& source, string const& find, string const& replace) {
+ for(string::size_type i = 0; (i = source.find(find, i)) != std::string::npos;)
+ {
+ source.replace(i, find.length(), replace);
+ i += replace.length() - find.length() + 1;
+ }
+}
+
+void WrapperRegistry::addClass(const string& pyName, const string& internalName, const string& baseclass) {
+ ClassData* data = getOrConstructClass(internalName);
+
+ // regularize python name
+ string pythonName = pyName;
+ replaceAll(pythonName, "<", "_");
+ replaceAll(pythonName, ">", "");
+ replaceAll(pythonName, ",", "_");
+
+ if (data->pyName.empty())
+ data->pyName = pythonName;
+ mClasses[pythonName] = data;
+ if (!baseclass.empty())
+ data->baseclassName = baseclass;
+}
+
+void WrapperRegistry::addEnumEntry(const string& name, int value) {
+ /// Gather static definitions to add them as static python objects afterwards
+ if ( mEnumValues.insert( std::make_pair( name, value ) ).second == false) {
+ errMsg("Enum entry '"+name+"' already existing...");
+ }
+}
+
+void WrapperRegistry::addExternalInitializer(InitFunc func) {
+ mExtInitializers.push_back(func);
+}
+
+void WrapperRegistry::addPythonPath(const string& path) {
+ mPaths.push_back(path);
+}
+
+void WrapperRegistry::addPythonCode(const string& file, const string& code) {
+ mCode += code + "\n";
+}
+
+void WrapperRegistry::addGetSet(const string& classname, const string& property, Getter getfunc, Setter setfunc) {
+ ClassData* classdef = getOrConstructClass(classname);
+ GetSet& def = classdef->getset[property];
+ if (def.name.empty()) {
+ def.name = property;
+ def.doc = property;
+ }
+ if (getfunc) def.getter = getfunc;
+ if (setfunc) def.setter = setfunc;
+}
+
+void WrapperRegistry::addMethod(const string& classname, const string& methodname, GenericFunction func) {
+ string aclass = classname;
+ if (aclass.empty())
+ aclass = "__modclass__";
+
+ ClassData* classdef = getOrConstructClass(aclass);
+ for(int i=0; i<(int)classdef->methods.size(); i++)
+ if (classdef->methods[i].name == methodname) return; // avoid duplicates
+ classdef->methods.push_back(Method(methodname,methodname,func));
+}
+
+void WrapperRegistry::addOperator(const string& classname, const string& methodname, OperatorFunction func) {
+ if (classname.empty())
+ errMsg("PYTHON operators have to be defined within classes.");
+
+ string op = methodname.substr(8);
+ ClassData* classdef = getOrConstructClass(classname);
+ classdef->ops[op] = func;
+}
+
+void WrapperRegistry::addConstructor(const string& classname, Constructor func) {
+ ClassData* classdef = getOrConstructClass(classname);
+ classdef->constructor = func;
+}
+
+void WrapperRegistry::addParentMethods(ClassData* cur, ClassData* base) {
+ if (base == 0) return;
+
+ for (vector<Method>::iterator it = base->methods.begin(); it != base->methods.end(); ++it)
+ addMethod(cur->cName, it->name, it->func);
+
+ for (map<string,GetSet>::iterator it = base->getset.begin(); it != base->getset.end(); ++it)
+ addGetSet(cur->cName, it->first, it->second.getter, it->second.setter);
+
+ for (map<string,OperatorFunction>::iterator it = base->ops.begin(); it != base->ops.end(); ++it)
+ cur->ops[it->first] = it->second;
+
+ addParentMethods(cur, base->baseclass);
+}
+
+void WrapperRegistry::registerBaseclasses() {
+ for (int i=0; i<(int)mClassList.size(); i++) {
+ string bname = mClassList[i]->baseclassName;
+ if(!bname.empty()) {
+ mClassList[i]->baseclass = lookup(bname);
+ if (!mClassList[i]->baseclass)
+ errMsg("Registering class '" + mClassList[i]->cName + "' : Base class '" + bname + "' not found");
+ }
+ }
+
+ for (int i=0; i<(int)mClassList.size(); i++) {
+ addParentMethods(mClassList[i], mClassList[i]->baseclass);
+ }
+}
+
+void WrapperRegistry::registerMeta() {
+ for (int i=0; i<(int)mClassList.size(); i++) {
+ mClassList[i]->getset["_class"] = GetSet("_class", "C class name", (Getter)cbGetClass, 0);
+ mClassList[i]->getset["_cname"] = GetSet("_cname", "Full C name", (Getter)cbGetCName, 0);
+ mClassList[i]->getset["_T"] = GetSet("_T", "C template argument", (Getter)cbGetTemplate, 0);
+ }
+}
+
+void WrapperRegistry::registerOperators(ClassData* cls) {
+ PyNumberMethods& num = cls->numInfo;
+ for (map<string,OperatorFunction>::iterator it = cls->ops.begin(); it != cls->ops.end(); it++) {
+ const string& op = it->first;
+ OperatorFunction func = it->second;
+ if (op=="+=") num.nb_inplace_add = func;
+ else if (op=="-=") num.nb_inplace_subtract = func;
+ else if (op=="*=") num.nb_inplace_multiply = func;
+ else if (op=="+") num.nb_add = func;
+ else if (op=="-") num.nb_subtract = func;
+ else if (op=="*") num.nb_multiply = func;
+# if PY_MAJOR_VERSION < 3
+ else if (op=="/=") num.nb_inplace_divide = func;
+ else if (op=="/") num.nb_divide = func;
+# else
+ else if (op=="/=") num.nb_inplace_true_divide = func;
+ else if (op=="/") num.nb_true_divide = func;
+# endif
+ else
+ errMsg("PYTHON operator " + op + " not supported");
+ }
+}
+
+void WrapperRegistry::registerDummyTypes() {
+ vector<string> add;
+ for(vector<ClassData*>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
+ string cName = (*it)->cName;
+ if (cName.find('<') != string::npos)
+ add.push_back(cName.substr(0,cName.find('<')));
+ }
+ for (int i=0; i<(int)add.size(); i++)
+ addClass(add[i],add[i],"");
+}
+
+ClassData* WrapperRegistry::lookup(const string& name) {
+ for(map<string, ClassData*>::iterator it = mClasses.begin(); it != mClasses.end(); ++it) {
+ if (it->first == name || it->second->cName == name)
+ return it->second;
+ }
+ return NULL;
+}
+
+void WrapperRegistry::cleanup() {
+ for(vector<ClassData*>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
+ delete *it;
+ }
+ mClasses.clear();
+ mClassList.clear();
+}
+
+WrapperRegistry& WrapperRegistry::instance() {
+ static WrapperRegistry inst;
+ return inst;
+}
+
+bool WrapperRegistry::canConvert(ClassData* from, ClassData* to) {
+ if (from == to) return true;
+ if (from->baseclass)
+ return canConvert(from->baseclass, to);
+ return false;
+}
+
+void WrapperRegistry::addConstants(PyObject* module) {
+ // expose arguments
+ PyObject* list = PyList_New(args.size());
+ for (int i=0; i<(int)args.size(); i++)
+ PyList_SET_ITEM(list,i,Manta::toPy(args[i]));
+ PyModule_AddObject(module, "args", list);
+ PyModule_AddObject(module,"SCENEFILE",Manta::toPy(mScriptName));
+
+ // expose compile flags
+#ifdef DEBUG
+ PyModule_AddObject(module,"DEBUG",Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module,"DEBUG",Manta::toPy<bool>(false));
+#endif
+#ifdef MANTA_MT
+ PyModule_AddObject(module,"MT",Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module,"MT",Manta::toPy<bool>(false));
+#endif
+#ifdef GUI
+ PyModule_AddObject(module,"GUI",Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module,"GUI",Manta::toPy<bool>(false));
+#endif
+#if FLOATINGPOINT_PRECISION==2
+ PyModule_AddObject(module,"DOUBLEPRECISION",Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module,"DOUBLEPRECISION",Manta::toPy<bool>(false));
+#endif
+ // cuda off for now
+ PyModule_AddObject(module,"CUDA",Manta::toPy<bool>(false));
+
+ // expose enum entries
+ std::map<std::string, int>::iterator it;
+ for ( it = mEnumValues.begin(); it != mEnumValues.end(); it++ )
+ {
+ PyModule_AddObject(module, it->first.c_str(), Manta::toPy(it->second));
+ // Alternative would be:
+ // e.g. PyModule_AddIntConstant(module, "FlagFluid", 1);
+ }
+}
+
+void WrapperRegistry::runPreInit() {
+ // add python directories to path
+ PyObject *sys_path = PySys_GetObject((char*)"path");
+ for (size_t i=0; i<mPaths.size(); i++) {
+ PyObject *path = Manta::toPy(mPaths[i]);
+ if (sys_path == NULL || path == NULL || PyList_Append(sys_path, path) < 0) {
+ errMsg("unable to set python path");
+ }
+ Py_DECREF(path);
+ }
+ if (!mCode.empty()) {
+ mCode = "from manta import *\n" + mCode;
+ PyRun_SimpleString(mCode.c_str());
+ }
+}
+
+PyObject* WrapperRegistry::createPyObject(const string& classname, const string& name, Manta::PbArgs& args, Manta::PbClass *parent) {
+ ClassData* classdef = lookup(classname);
+ if (!classdef)
+ errMsg("Class " + classname + " doesn't exist.");
+
+ // create object
+ PyObject* obj = cbNew(&classdef->typeInfo, NULL, NULL);
+ PbObject* self = (PbObject*)obj;
+ PyObject* nkw = 0;
+
+ if (args.kwds())
+ nkw = PyDict_Copy(args.kwds());
+ else
+ nkw = PyDict_New();
+
+ PyObject* nocheck = Py_BuildValue("s","yes");
+ PyDict_SetItemString(nkw, "nocheck", nocheck);
+ if (parent) PyDict_SetItemString(nkw, "parent", parent->getPyObject());
+
+ // create instance
+ if (self->classdef->constructor(obj, args.linArgs(), nkw) < 0)
+ errMsg("error raised in constructor"); // assume condition is already set
+
+ Py_DECREF(nkw);
+ Py_DECREF(nocheck);
+ self->instance->setName(name);
+
+ return obj;
+}
+
+// prepare typeinfo and register python module
+void WrapperRegistry::construct(const string& scriptname, const vector<string>& args) {
+ mScriptName = scriptname;
+ this->args = args;
+
+ registerBaseclasses();
+ registerMeta();
+ registerDummyTypes();
+
+ // work around for certain gcc versions, cast to char*
+ PyImport_AppendInittab( (char*)gDefaultModuleName.c_str(), PyInit_Main );
+}
+
+inline PyObject* castPy(PyTypeObject* p) {
+ return reinterpret_cast<PyObject*>(static_cast<void*>(p));
+}
+
+PyObject* WrapperRegistry::initModule() {
+ // generate and terminate all method lists
+ PyMethodDef sentinelFunc = { NULL, NULL, 0, NULL };
+ PyGetSetDef sentinelGetSet = { NULL, NULL, NULL, NULL, NULL };
+ for (int i=0; i<(int)mClassList.size(); i++) {
+ ClassData* cls = mClassList[i];
+ cls->genMethods.clear();
+ cls->genGetSet.clear();
+ for (vector<Method>::iterator i2 = cls->methods.begin(); i2 != cls->methods.end(); ++i2)
+ cls->genMethods.push_back(i2->def());
+ for (map<string,GetSet>::iterator i2 = cls->getset.begin(); i2 != cls->getset.end(); ++i2)
+ cls->genGetSet.push_back(i2->second.def());
+
+ cls->genMethods.push_back(sentinelFunc);
+ cls->genGetSet.push_back(sentinelGetSet);
+ }
+
+ // prepare module info
+#if PY_MAJOR_VERSION >= 3
+ static PyModuleDef MainModule = {
+ PyModuleDef_HEAD_INIT,
+ gDefaultModuleName.c_str(),
+ "Bridge module to the C++ solver",
+ -1,
+ NULL, NULL, NULL, NULL, NULL
+ };
+ // get generic methods (plugin functions)
+ MainModule.m_methods = &mClasses["__modclass__"]->genMethods[0];
+
+ // create module
+ PyObject* module = PyModule_Create(&MainModule);
+#else
+ PyObject* module = Py_InitModule(gDefaultModuleName.c_str(), &mClasses["__modclass__"]->genMethods[0]);
+#endif
+ if (module == NULL)
+ return NULL;
+
+ // load classes
+ for(vector<ClassData*>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
+ ClassData& data = **it;
+ char* nameptr = (char*)data.pyName.c_str();
+
+ // define numeric substruct
+ PyNumberMethods* num = 0;
+ if (!data.ops.empty()) {
+ num = &data.numInfo;
+ memset(num,0,sizeof(PyNumberMethods));
+ registerOperators(&data);
+ }
+
+ // define python classinfo
+ PyTypeObject t = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ (char*)data.pyName.c_str(),// tp_name
+ sizeof(PbObject), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)cbDealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_reserved
+ 0, // tp_repr
+ num, // tp_as_number
+ 0, // tp_as_sequence
+ 0, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0, // tp_str
+ 0, // tp_getattro
+ 0, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT |
+ Py_TPFLAGS_BASETYPE, // tp_flags
+ nameptr, // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ &data.genMethods[0], // tp_methods
+ 0, // tp_members
+ &data.genGetSet[0], // tp_getset
+ 0, // tp_base
+ 0, // tp_dict
+ 0, // tp_descr_get
+ 0, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)(data.constructor),// tp_init
+ 0, // tp_alloc
+ cbNew // tp_new
+ };
+ data.typeInfo = t;
+
+ if (PyType_Ready(&data.typeInfo) < 0)
+ continue;
+
+ for(map<string,ClassData*>::iterator i2 = mClasses.begin(); i2 != mClasses.end(); ++i2) {
+ if (*it != i2->second) continue;
+ // register all aliases
+ Py_INCREF(castPy(&data.typeInfo));
+ PyModule_AddObject(module, (char*)i2->first.c_str(), (PyObject*) &data.typeInfo);
+ }
+ }
+
+ // externals
+ for(vector<InitFunc>::iterator it = mExtInitializers.begin(); it != mExtInitializers.end(); ++it) {
+ (*it)(module);
+ }
+
+ addConstants(module);
+
+ return module;
+}
+
+
+//******************************************************
+// Register members and exposed functions
+
+void setup(const std::string& filename, const std::vector<std::string>& args) {
+ WrapperRegistry::instance().construct(filename,args);
+ Py_Initialize();
+ WrapperRegistry::instance().runPreInit();
+}
+
+void finalize() {
+ Py_Finalize();
+ WrapperRegistry::instance().cleanup();
+}
+
+bool canConvert(PyObject* obj, const string& classname) {
+ ClassData* from = ((PbObject*)obj)->classdef;
+ ClassData* dest = WrapperRegistry::instance().lookup(classname);
+ if (!dest)
+ errMsg("Classname '" + classname + "' is not registered.");
+ return WrapperRegistry::instance().canConvert(from, dest);
+}
+
+Manta::PbClass* objFromPy(PyObject* obj) {
+ if (Py_TYPE(obj)->tp_dealloc != (destructor)cbDealloc) // not a manta object
+ return NULL;
+
+ return ((PbObject*) obj)->instance;
+}
+
+PyObject* copyObject(Manta::PbClass* cls, const string& classname) {
+ ClassData* classdef = WrapperRegistry::instance().lookup(classname);
+ assertMsg(classdef,"python class " + classname + " does not exist.");
+
+ // allocate new object
+ PbObject *obj = (PbObject*) classdef->typeInfo.tp_alloc(&(classdef->typeInfo), 0);
+ assertMsg(obj, "cannot allocate new python object");
+
+ obj->classdef = classdef;
+ cls->registerObject((PyObject*)obj, 0);
+
+ return cls->getPyObject();
+}
+
+Manta::PbClass* createPy(const std::string& classname, const std::string& name, Manta::PbArgs& args, Manta::PbClass* parent) {
+ PyObject* obj = WrapperRegistry::instance().createPyObject(classname, name, args, parent);
+ return ((PbObject*)obj)->instance;
+}
+
+void setReference(Manta::PbClass* cls, PyObject* obj) {
+ ((PbObject*) obj)->instance = cls;
+}
+
+Register::Register(const string& className, const string& funcName, GenericFunction func) {
+ WrapperRegistry::instance().addMethod(className, funcName, func);
+}
+Register::Register(const string& className, const string& funcName, OperatorFunction func) {
+ WrapperRegistry::instance().addOperator(className, funcName, func);
+}
+Register::Register(const string& className, const string& funcName, Constructor func) {
+ WrapperRegistry::instance().addConstructor(className, func);
+}
+Register::Register(const string& className, const string& property, Getter getter, Setter setter) {
+ WrapperRegistry::instance().addGetSet(className, property, getter, setter);
+}
+Register::Register(const string& className, const string& pyName, const string& baseClass) {
+ WrapperRegistry::instance().addClass(pyName, className, baseClass);
+}
+Register::Register(const string& name, const int value) {
+ WrapperRegistry::instance().addEnumEntry(name, value);
+}
+Register::Register(const string& file, const string& pythonCode) {
+ WrapperRegistry::instance().addPythonCode(file, pythonCode);
+}
+Register::Register(InitFunc func) {
+ WrapperRegistry::instance().addExternalInitializer(func);
+}
+
+} // namespace
diff --git a/intern/mantaflow/intern/manta_develop/helper/pwrapper/registry.h b/intern/mantaflow/intern/manta_develop/helper/pwrapper/registry.h
new file mode 100644
index 00000000000..cf3a1474648
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/pwrapper/registry.h
@@ -0,0 +1,97 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Auto python registry
+ *
+ ******************************************************************************/
+
+#ifndef _REGISTRY_H
+#define _REGISTRY_H
+
+#include <string>
+#include <vector>
+
+// forward declaration to minimize Python.h includes
+#ifndef PyObject_HEAD
+#ifndef PyObject_Fake
+struct _object;
+typedef _object PyObject;
+#define PyObject_Fake
+#endif
+#endif
+
+namespace Manta {
+ class PbClass;
+ class PbArgs;
+}
+
+// **************************************************
+// NOTE
+// Everything in this file is intend only for internal
+// use by the generated wrappers or pclass/pconvert.
+// For user code, use the functionality exposed in
+// pclass.h / pconvert.h instead.
+// **************************************************
+
+// Used to turn names into strings
+namespace Manta {
+template<class T> struct Namify {
+ static const char* S;
+};
+}
+namespace Pb {
+
+// internal registry access
+void setup(const std::string& filename, const std::vector<std::string>& args);
+void finalize();
+bool canConvert(PyObject* obj, const std::string& to);
+Manta::PbClass* objFromPy(PyObject* obj);
+Manta::PbClass* createPy(const std::string& classname, const std::string& name, Manta::PbArgs& args, Manta::PbClass* parent);
+void setReference(Manta::PbClass* cls, PyObject* obj);
+PyObject* copyObject(Manta::PbClass* cls, const std::string& classname);
+void MantaEnsureRegistration();
+
+#ifdef BLENDER
+#ifdef PyMODINIT_FUNC
+PyMODINIT_FUNC PyInit_Main(void);
+#endif
+#endif
+
+// callback type
+typedef void (*InitFunc)(PyObject*);
+typedef PyObject* (*GenericFunction)(PyObject* self, PyObject* args, PyObject* kwds);
+typedef PyObject* (*OperatorFunction)(PyObject* self, PyObject* o);
+typedef int (*Constructor)(PyObject* self, PyObject* args, PyObject* kwds);
+typedef PyObject* (*Getter)(PyObject* self, void* closure);
+typedef int (*Setter)(PyObject* self, PyObject* value, void* closure);
+
+//! Auto registry of python methods and classes
+struct Register {
+ //! register method
+ Register(const std::string& className, const std::string& funcName, GenericFunction func);
+ //! register operator
+ Register(const std::string& className, const std::string& funcName, OperatorFunction func);
+ //! register constructor
+ Register(const std::string& className, const std::string& funcName, Constructor func);
+ //! register getter/setter
+ Register(const std::string& className, const std::string& property, Getter getter, Setter setter);
+ //! register class
+ Register(const std::string& className, const std::string& pyName, const std::string& baseClass);
+ //! register enum entry
+ Register(const std::string& name, const int value);
+ //! register python code
+ Register(const std::string& file, const std::string& pythonCode);
+ //! register external code
+ Register(InitFunc func);
+};
+
+#define KEEP_UNUSED(var) do { (void)var; } while(false);
+
+}
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/integrator.h b/intern/mantaflow/intern/manta_develop/helper/util/integrator.h
new file mode 100644
index 00000000000..bd82bc44224
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/integrator.h
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Helper functions for simple integration
+ *
+ ******************************************************************************/
+
+#ifndef _INTEGRATE_H
+#define _INTEGRATE_H
+
+#include <vector>
+#include "vectorbase.h"
+#include "kernel.h"
+
+namespace Manta {
+
+enum IntegrationMode { IntEuler=0, IntRK2, IntRK4 };
+
+//! Integrate a particle set with a given velocity kernel
+template<class VelKernel>
+void integratePointSet(VelKernel& k, int mode) {
+ typedef typename VelKernel::type0 PosType;
+ PosType& x = k.getArg0();
+ const std::vector<Vec3>& u = k.getRet();
+ const int N = x.size();
+
+ if (mode == IntEuler) {
+ for(int i=0; i<N; i++) x[i].pos += u[i];
+ }
+ else if (mode == IntRK2) {
+ PosType x0(x);
+
+ for(int i=0; i<N; i++) x[i].pos = x0[i].pos + 0.5*u[i];
+
+ k.run();
+ for(int i=0; i<N; i++) x[i].pos = x0[i].pos + u[i];
+ }
+ else if (mode == IntRK4) {
+ PosType x0(x);
+ std::vector<Vec3> uTotal(u);
+
+ for(int i=0; i<N; i++) x[i].pos = x0[i].pos + 0.5*u[i];
+
+ k.run();
+ for(int i=0; i<N; i++) {
+ x[i].pos = x0[i].pos + 0.5*u[i];
+ uTotal[i] += 2*u[i];
+ }
+
+ k.run();
+ for(int i=0; i<N; i++) {
+ x[i].pos = x0[i].pos + u[i];
+ uTotal[i] += 2*u[i];
+ }
+
+ k.run();
+ for(int i=0; i<N; i++) x[i].pos = x0[i].pos + (Real)(1./6.) * (uTotal[i] + u[i]);
+ }
+ else
+ errMsg("unknown integration type");
+
+ //for(int i=0; i<N; i++) std::cout << x[i].pos.y-x[0].pos.y << std::endl;
+ //std::cout << "<><><>" << std::endl;
+}
+
+
+} // namespace
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/interpol.h b/intern/mantaflow/intern/manta_develop/helper/util/interpol.h
new file mode 100644
index 00000000000..37dafeaa2cd
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/interpol.h
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Helper functions for interpolation
+ *
+ ******************************************************************************/
+
+#ifndef _INTERPOL_H
+#define _INTERPOL_H
+
+#include "vectorbase.h"
+
+// Grid values are stored at i+0.5, j+0.5, k+0.5
+// MAC grid values are stored at i,j+0.5,k+0.5 (for x) ...
+
+namespace Manta {
+
+inline Vec3 fdTangent(const Vec3& p0, const Vec3& p1, const Vec3& p2) {
+ return 0.5*(getNormalized(p2-p1) + getNormalized(p1-p0));
+}
+
+inline Vec3 crTangent(const Vec3& p0, const Vec3& p1, const Vec3& p2) {
+ return 0.5*(p2-p0);
+}
+
+inline Vec3 hermiteSpline(const Vec3& p0, const Vec3& p1, const Vec3& m0, const Vec3& m1, Real t) {
+ const Real t2=t*t, t3=t2*t;
+ return (2.0*t3 - 3.0*t2 + 1.0)*p0 + (t3 - 2.0*t2 + t)*m0 + (-2.0*t3 + 3.0*t2)*p1 + (t3 - t2)*m1;
+}
+
+static inline void checkIndexInterpol(const Vec3i& size, IndexInt idx) {
+ if (idx<0 || idx > (IndexInt)size.x * size.y * size.z) {
+ std::ostringstream s;
+ s << "Grid interpol dim " << size << " : index " << idx << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+
+// ----------------------------------------------------------------------
+// Grid interpolators
+// ----------------------------------------------------------------------
+
+#define BUILD_INDEX \
+ Real px=pos.x-0.5f, py=pos.y-0.5f, pz=pos.z-0.5f; \
+ int xi = (int)px; \
+ int yi = (int)py; \
+ int zi = (int)pz; \
+ Real s1 = px-(Real)xi, s0 = 1.-s1; \
+ Real t1 = py-(Real)yi, t0 = 1.-t1; \
+ Real f1 = pz-(Real)zi, f0 = 1.-f1; \
+ /* clamp to border */ \
+ if (px < 0.) { xi = 0; s0 = 1.0; s1 = 0.0; } \
+ if (py < 0.) { yi = 0; t0 = 1.0; t1 = 0.0; } \
+ if (pz < 0.) { zi = 0; f0 = 1.0; f1 = 0.0; } \
+ if (xi >= size.x-1) { xi = size.x-2; s0 = 0.0; s1 = 1.0; } \
+ if (yi >= size.y-1) { yi = size.y-2; t0 = 0.0; t1 = 1.0; } \
+ if (size.z>1) { if (zi >= size.z-1) { zi = size.z-2; f0 = 0.0; f1 = 1.0; } } \
+ const int X = 1; \
+ const int Y = size.x;
+
+template <class T>
+inline T interpol(const T* data, const Vec3i& size, const int Z, const Vec3& pos) {
+ BUILD_INDEX
+ IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi;
+ DEBUG_ONLY(checkIndexInterpol(size,idx)); DEBUG_ONLY(checkIndexInterpol(size,idx+X+Y+Z));
+
+ return ((data[idx] *t0 + data[idx+Y] *t1) * s0
+ + (data[idx+X] *t0 + data[idx+X+Y] *t1) * s1) * f0
+ +((data[idx+Z] *t0 + data[idx+Y+Z] *t1) * s0
+ + (data[idx+X+Z]*t0 + data[idx+X+Y+Z]*t1) * s1) * f1;
+}
+
+template <int c>
+inline Real interpolComponent(const Vec3* data, const Vec3i& size, const int Z, const Vec3& pos) {
+ BUILD_INDEX
+ IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi;
+ DEBUG_ONLY(checkIndexInterpol(size,idx)); DEBUG_ONLY(checkIndexInterpol(size,idx+X+Y+Z));
+
+ return ((data[idx][c] *t0 + data[idx+Y][c] *t1) * s0
+ + (data[idx+X][c] *t0 + data[idx+X+Y][c] *t1) * s1) * f0
+ +((data[idx+Z][c] *t0 + data[idx+Y+Z][c] *t1) * s0
+ + (data[idx+X+Z][c]*t0 + data[idx+X+Y+Z][c]*t1) * s1) * f1;
+}
+
+template<class T>
+inline void setInterpol(T* data, const Vec3i& size, const int Z, const Vec3& pos, const T& v, Real* sumBuffer)
+{
+ BUILD_INDEX
+ IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi;
+ DEBUG_ONLY(checkIndexInterpol(size,idx)); DEBUG_ONLY(checkIndexInterpol(size,idx+X+Y+Z));
+
+ T* ref = &data[idx];
+ Real* sum = &sumBuffer[idx];
+ Real s0f0=s0*f0, s1f0=s1*f0, s0f1=s0*f1, s1f1=s1*f1;
+ Real w0 = t0*s0f0, wx = t0*s1f0, wy = t1*s0f0, wxy = t1*s1f0;
+ Real wz = t0*s0f1, wxz = t0*s1f1, wyz = t1*s0f1, wxyz = t1*s1f1;
+
+ sum[Z] += wz; sum[X+Z] += wxz; sum[Y+Z] += wyz; sum[X+Y+Z] += wxyz;
+ ref[Z] += wz*v; ref[X+Z] += wxz*v; ref[Y+Z] += wyz*v; ref[X+Y+Z] += wxyz*v;
+ sum[0] += w0; sum[X] += wx; sum[Y] += wy; sum[X+Y] += wxy;
+ ref[0] += w0*v; ref[X] += wx*v; ref[Y] += wy*v; ref[X+Y] += wxy*v;
+}
+
+
+#define BUILD_INDEX_SHIFT \
+ BUILD_INDEX \
+ /* shifted coords */ \
+ int s_xi = (int)pos.x, s_yi = (int)pos.y, s_zi = (int)pos.z; \
+ Real s_s1 = pos.x-(Real)s_xi, s_s0 = 1.-s_s1; \
+ Real s_t1 = pos.y-(Real)s_yi, s_t0 = 1.-s_t1; \
+ Real s_f1 = pos.z-(Real)s_zi, s_f0 = 1.-s_f1; \
+ /* clamp to border */ \
+ if (pos.x < 0) { s_xi = 0; s_s0 = 1.0; s_s1 = 0.0; } \
+ if (pos.y < 0) { s_yi = 0; s_t0 = 1.0; s_t1 = 0.0; } \
+ if (pos.z < 0) { s_zi = 0; s_f0 = 1.0; s_f1 = 0.0; } \
+ if (s_xi >= size.x-1) { s_xi = size.x-2; s_s0 = 0.0; s_s1 = 1.0; } \
+ if (s_yi >= size.y-1) { s_yi = size.y-2; s_t0 = 0.0; s_t1 = 1.0; } \
+ if (size.z>1) { if (s_zi >= size.z-1) { s_zi = size.z-2; s_f0 = 0.0; s_f1 = 1.0; } }
+
+inline Vec3 interpolMAC(const Vec3* data, const Vec3i& size, const int Z, const Vec3& pos)
+{
+ BUILD_INDEX_SHIFT;
+ DEBUG_ONLY(checkIndexInterpol(size, (zi*(IndexInt)size.y + yi)*(IndexInt)size.x + xi));
+ DEBUG_ONLY(checkIndexInterpol(size, (s_zi*(IndexInt)size.y + s_yi)*(IndexInt)size.x + s_xi + X + Y + Z));
+
+ // process individual components
+ Vec3 ret(0.);
+ { // X
+ const Vec3* ref = &data[((zi*size.y+yi)*size.x+s_xi)];
+ ret.x = f0 * ((ref[0].x *t0 + ref[Y].x *t1 )*s_s0 +
+ (ref[X].x *t0 + ref[X+Y].x *t1 )*s_s1) +
+ f1 * ((ref[Z].x *t0 + ref[Z+Y].x *t1 )*s_s0 +
+ (ref[X+Z].x*t0 + ref[X+Y+Z].x*t1 )*s_s1 );
+ }
+ { // Y
+ const Vec3* ref = &data[((zi*size.y+s_yi)*size.x+xi)];
+ ret.y = f0 * ((ref[0].y *s_t0 + ref[Y].y *s_t1 )*s0 +
+ (ref[X].y *s_t0 + ref[X+Y].y *s_t1 )*s1) +
+ f1 * ((ref[Z].y *s_t0 + ref[Z+Y].y *s_t1 )*s0 +
+ (ref[X+Z].y*s_t0 + ref[X+Y+Z].y*s_t1 )*s1 );
+ }
+ { // Z
+ const Vec3* ref = &data[((s_zi*size.y+yi)*size.x+xi)];
+ ret.z = s_f0 * ((ref[0].z *t0 + ref[Y].z *t1 )*s0 +
+ (ref[X].z *t0 + ref[X+Y].z *t1 )*s1) +
+ s_f1 * ((ref[Z].z *t0 + ref[Z+Y].z *t1 )*s0 +
+ (ref[X+Z].z*t0 + ref[X+Y+Z].z*t1 )*s1 );
+ }
+ return ret;
+}
+
+inline void setInterpolMAC(Vec3* data, const Vec3i& size, const int Z, const Vec3& pos, const Vec3& val, Vec3* sumBuffer)
+{
+ BUILD_INDEX_SHIFT;
+ DEBUG_ONLY(checkIndexInterpol(size, (zi*(IndexInt)size.y + yi)*(IndexInt)size.x + xi));
+ DEBUG_ONLY(checkIndexInterpol(size, (s_zi*(IndexInt)size.y + s_yi)*(IndexInt)size.x + s_xi + X + Y + Z));
+
+ // process individual components
+ { // X
+ const IndexInt idx = (IndexInt)(zi*size.y+yi)*size.x+s_xi;
+ Vec3 *ref = &data[idx], *sum = &sumBuffer[idx];
+ Real s0f0=s_s0*f0, s1f0=s_s1*f0, s0f1=s_s0*f1, s1f1=s_s1*f1;
+ Real w0 = t0*s0f0, wx = t0*s1f0, wy = t1*s0f0, wxy = t1*s1f0;
+ Real wz = t0*s0f1, wxz = t0*s1f1, wyz = t1*s0f1, wxyz = t1*s1f1;
+
+ sum[Z].x += wz; sum[X+Z].x += wxz; sum[Y+Z].x += wyz; sum[X+Y+Z].x += wxyz;
+ ref[Z].x += wz*val.x; ref[X+Z].x += wxz*val.x; ref[Y+Z].x += wyz*val.x; ref[X+Y+Z].x += wxyz*val.x;
+ sum[0].x += w0; sum[X].x += wx; sum[Y].x += wy; sum[X+Y].x += wxy;
+ ref[0].x += w0*val.x; ref[X].x += wx*val.x; ref[Y].x += wy*val.x; ref[X+Y].x += wxy*val.x;
+ }
+ { // Y
+ const IndexInt idx = (IndexInt)(zi*size.y+s_yi)*size.x+xi;
+ Vec3 *ref = &data[idx], *sum = &sumBuffer[idx];
+ Real s0f0=s0*f0, s1f0=s1*f0, s0f1=s0*f1, s1f1=s1*f1;
+ Real w0 = s_t0*s0f0, wx = s_t0*s1f0, wy = s_t1*s0f0, wxy = s_t1*s1f0;
+ Real wz = s_t0*s0f1, wxz = s_t0*s1f1, wyz = s_t1*s0f1, wxyz = s_t1*s1f1;
+
+ sum[Z].y += wz; sum[X+Z].y += wxz; sum[Y+Z].y += wyz; sum[X+Y+Z].y += wxyz;
+ ref[Z].y += wz*val.y; ref[X+Z].y += wxz*val.y; ref[Y+Z].y += wyz*val.y; ref[X+Y+Z].y += wxyz*val.y;
+ sum[0].y += w0; sum[X].y += wx; sum[Y].y += wy; sum[X+Y].y += wxy;
+ ref[0].y += w0*val.y; ref[X].y += wx*val.y; ref[Y].y += wy*val.y; ref[X+Y].y += wxy*val.y;
+ }
+ { // Z
+ const IndexInt idx = (IndexInt)(s_zi*size.y+yi)*size.x+xi;
+ Vec3 *ref = &data[idx], *sum = &sumBuffer[idx];
+ Real s0f0=s0*s_f0, s1f0=s1*s_f0, s0f1=s0*s_f1, s1f1=s1*s_f1;
+ Real w0 = t0*s0f0, wx = t0*s1f0, wy = t1*s0f0, wxy = t1*s1f0;
+ Real wz = t0*s0f1, wxz = t0*s1f1, wyz = t1*s0f1, wxyz = t1*s1f1;
+
+ sum[0].z += w0; sum[X].z += wx; sum[Y].z += wy; sum[X+Y].z += wxy;
+ sum[Z].z += wz; sum[X+Z].z += wxz; sum[Y+Z].z += wyz; sum[X+Y+Z].z += wxyz;
+ ref[0].z += w0*val.z; ref[X].z += wx*val.z; ref[Y].z += wy*val.z; ref[X+Y].z += wxy*val.z;
+ ref[Z].z += wz*val.z; ref[X+Z].z += wxz*val.z; ref[Y+Z].z += wyz*val.z; ref[X+Y+Z].z += wxyz*val.z;
+ }
+}
+
+#undef BUILD_INDEX
+#undef BUILD_INDEX_SHIFT
+
+} //namespace
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/interpolHigh.h b/intern/mantaflow/intern/manta_develop/helper/util/interpolHigh.h
new file mode 100644
index 00000000000..d5639a09ee1
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/interpolHigh.h
@@ -0,0 +1,187 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Helper functions for higher order interpolation
+ *
+ ******************************************************************************/
+
+#ifndef _INTERPOLHIGH_H
+#define _INTERPOLHIGH_H
+
+#include "vectorbase.h"
+
+namespace Manta {
+
+
+template <class T>
+inline T cubicInterp(const Real interp, const T* points)
+{
+ T d0 = (points[2] - points[0]) * 0.5;
+ T d1 = (points[3] - points[1]) * 0.5;
+ T deltak = (points[2] - points[1]);
+
+ // disabled: if (deltak * d0 < 0.0) d0 = 0;
+ // disabled: if (deltak * d1 < 0.0) d1 = 0;
+
+ T a0 = points[1];
+ T a1 = d0;
+ T a2 = 3.0 * deltak - 2.0 * d0 - d1;
+ T a3 = -2.0 * deltak + d0 + d1;
+
+ Real squared = interp * interp;
+ Real cubed = squared * interp;
+ return a3 * cubed + a2 * squared + a1 * interp + a0;
+}
+
+template <class T>
+inline T interpolCubic2D(const T* data, const Vec3i& size, const Vec3& pos) {
+ const Real px=pos.x-0.5f, py=pos.y-0.5f;
+
+ const int x1 = (int)px;
+ const int x2 = x1 + 1;
+ const int x3 = x1 + 2;
+ const int x0 = x1 - 1;
+
+ const int y1 = (int)py;
+ const int y2 = y1 + 1;
+ const int y3 = y1 + 2;
+ const int y0 = y1 - 1;
+
+ if (x0 < 0 || y0 < 0 || x3 >= size[0] || y3 >= size[1] ) {
+ return interpol(data, size, 0, pos);
+ }
+
+ const Real xInterp = px - x1;
+ const Real yInterp = py - y1;
+
+ const int y0x = y0 * size[0];
+ const int y1x = y1 * size[0];
+ const int y2x = y2 * size[0];
+ const int y3x = y3 * size[0];
+
+ const T p0[] = {data[x0 + y0x], data[x1 + y0x], data[x2 + y0x], data[x3 + y0x]};
+ const T p1[] = {data[x0 + y1x], data[x1 + y1x], data[x2 + y1x], data[x3 + y1x]};
+ const T p2[] = {data[x0 + y2x], data[x1 + y2x], data[x2 + y2x], data[x3 + y2x]};
+ const T p3[] = {data[x0 + y3x], data[x1 + y3x], data[x2 + y3x], data[x3 + y3x]};
+
+ const T finalPoints[] = {cubicInterp(xInterp, p0), cubicInterp(xInterp, p1), cubicInterp(xInterp, p2), cubicInterp(xInterp, p3)};
+
+ return cubicInterp(yInterp, finalPoints);
+}
+
+template <class T>
+inline T interpolCubic(const T* data, const Vec3i& size, const int Z, const Vec3& pos)
+{
+ if(Z==0) return interpolCubic2D(data, size, pos);
+
+ const Real px=pos.x-0.5f, py=pos.y-0.5f, pz=pos.z-0.5f;
+
+ const int x1 = (int)px;
+ const int x2 = x1 + 1;
+ const int x3 = x1 + 2;
+ const int x0 = x1 - 1;
+
+ const int y1 = (int)py;
+ const int y2 = y1 + 1;
+ const int y3 = y1 + 2;
+ const int y0 = y1 - 1;
+
+ const int z1 = (int)pz;
+ const int z2 = z1 + 1;
+ const int z3 = z1 + 2;
+ const int z0 = z1 - 1;
+
+ if (x0 < 0 || y0 < 0 || z0 < 0 || x3 >= size[0] || y3 >= size[1] || z3 >= size[2]) {
+ return interpol(data, size, Z, pos);
+ }
+
+ const Real xInterp = px - x1;
+ const Real yInterp = py - y1;
+ const Real zInterp = pz - z1;
+
+ const int slabsize = size[0]*size[1];
+ const int z0Slab = z0 * slabsize;
+ const int z1Slab = z1 * slabsize;
+ const int z2Slab = z2 * slabsize;
+ const int z3Slab = z3 * slabsize;
+
+ const int y0x = y0 * size[0];
+ const int y1x = y1 * size[0];
+ const int y2x = y2 * size[0];
+ const int y3x = y3 * size[0];
+
+ const int y0z0 = y0x + z0Slab;
+ const int y1z0 = y1x + z0Slab;
+ const int y2z0 = y2x + z0Slab;
+ const int y3z0 = y3x + z0Slab;
+
+ const int y0z1 = y0x + z1Slab;
+ const int y1z1 = y1x + z1Slab;
+ const int y2z1 = y2x + z1Slab;
+ const int y3z1 = y3x + z1Slab;
+
+ const int y0z2 = y0x + z2Slab;
+ const int y1z2 = y1x + z2Slab;
+ const int y2z2 = y2x + z2Slab;
+ const int y3z2 = y3x + z2Slab;
+
+ const int y0z3 = y0x + z3Slab;
+ const int y1z3 = y1x + z3Slab;
+ const int y2z3 = y2x + z3Slab;
+ const int y3z3 = y3x + z3Slab;
+
+ // get the z0 slice
+ const T p0[] = {data[x0 + y0z0], data[x1 + y0z0], data[x2 + y0z0], data[x3 + y0z0]};
+ const T p1[] = {data[x0 + y1z0], data[x1 + y1z0], data[x2 + y1z0], data[x3 + y1z0]};
+ const T p2[] = {data[x0 + y2z0], data[x1 + y2z0], data[x2 + y2z0], data[x3 + y2z0]};
+ const T p3[] = {data[x0 + y3z0], data[x1 + y3z0], data[x2 + y3z0], data[x3 + y3z0]};
+
+ // get the z1 slice
+ const T p4[] = {data[x0 + y0z1], data[x1 + y0z1], data[x2 + y0z1], data[x3 + y0z1]};
+ const T p5[] = {data[x0 + y1z1], data[x1 + y1z1], data[x2 + y1z1], data[x3 + y1z1]};
+ const T p6[] = {data[x0 + y2z1], data[x1 + y2z1], data[x2 + y2z1], data[x3 + y2z1]};
+ const T p7[] = {data[x0 + y3z1], data[x1 + y3z1], data[x2 + y3z1], data[x3 + y3z1]};
+
+ // get the z2 slice
+ const T p8[] = {data[x0 + y0z2], data[x1 + y0z2], data[x2 + y0z2], data[x3 + y0z2]};
+ const T p9[] = {data[x0 + y1z2], data[x1 + y1z2], data[x2 + y1z2], data[x3 + y1z2]};
+ const T p10[] = {data[x0 + y2z2], data[x1 + y2z2], data[x2 + y2z2], data[x3 + y2z2]};
+ const T p11[] = {data[x0 + y3z2], data[x1 + y3z2], data[x2 + y3z2], data[x3 + y3z2]};
+
+ // get the z3 slice
+ const T p12[] = {data[x0 + y0z3], data[x1 + y0z3], data[x2 + y0z3], data[x3 + y0z3]};
+ const T p13[] = {data[x0 + y1z3], data[x1 + y1z3], data[x2 + y1z3], data[x3 + y1z3]};
+ const T p14[] = {data[x0 + y2z3], data[x1 + y2z3], data[x2 + y2z3], data[x3 + y2z3]};
+ const T p15[] = {data[x0 + y3z3], data[x1 + y3z3], data[x2 + y3z3], data[x3 + y3z3]};
+
+ // interpolate
+ const T z0Points[] = {cubicInterp(xInterp, p0), cubicInterp(xInterp, p1), cubicInterp(xInterp, p2), cubicInterp(xInterp, p3)};
+ const T z1Points[] = {cubicInterp(xInterp, p4), cubicInterp(xInterp, p5), cubicInterp(xInterp, p6), cubicInterp(xInterp, p7)};
+ const T z2Points[] = {cubicInterp(xInterp, p8), cubicInterp(xInterp, p9), cubicInterp(xInterp, p10), cubicInterp(xInterp, p11)};
+ const T z3Points[] = {cubicInterp(xInterp, p12), cubicInterp(xInterp, p13), cubicInterp(xInterp, p14), cubicInterp(xInterp, p15)};
+
+ const T finalPoints[] = {cubicInterp(yInterp, z0Points), cubicInterp(yInterp, z1Points), cubicInterp(yInterp, z2Points), cubicInterp(yInterp, z3Points)};
+
+ return cubicInterp(zInterp, finalPoints);
+}
+
+inline Vec3 interpolCubicMAC(const Vec3* data, const Vec3i& size, const int Z, const Vec3& pos) {
+ // warning - not yet optimized...
+ Real vx = interpolCubic<Vec3>(data, size, Z, pos + Vec3(0.5,0,0) )[0];
+ Real vy = interpolCubic<Vec3>(data, size, Z, pos + Vec3(0,0.5,0) )[1];
+ Real vz = 0.f;
+ if(Z!=0) vz = interpolCubic<Vec3>(data, size, Z, pos + Vec3(0,0,0.5) )[2];
+ return Vec3(vx,vy,vz);
+}
+
+} //namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/matrixbase.h b/intern/mantaflow/intern/manta_develop/helper/util/matrixbase.h
new file mode 100644
index 00000000000..e9c0c682c45
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/matrixbase.h
@@ -0,0 +1,256 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2015 Kiwon Um, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * Matrix (3x3) class
+ *
+ ******************************************************************************/
+
+#ifndef MATRIXBASE_H
+#define MATRIXBASE_H
+
+#include "vectorbase.h"
+
+namespace Manta {
+
+template<typename T>
+class Matrix3x3 {
+public:
+ // NOTE: default is the identity matrix!
+ explicit Matrix3x3(const T &p00=1, const T &p01=0, const T &p02=0,
+ const T &p10=0, const T &p11=1, const T &p12=0,
+ const T &p20=0, const T &p21=0, const T &p22=1) {
+ v[0][0]=p00; v[0][1]=p01; v[0][2]=p02;
+ v[1][0]=p10; v[1][1]=p11; v[1][2]=p12;
+ v[2][0]=p20; v[2][1]=p21; v[2][2]=p22;
+ }
+
+ explicit Matrix3x3(const Vector3D<T> &diag) {
+ v[0][0]=diag.x; v[0][1]=0; v[0][2]=0;
+ v[1][0]=0; v[1][1]=diag.y; v[1][2]=0;
+ v[2][0]=0; v[2][1]=0; v[2][2]=diag.z;
+ }
+
+ Matrix3x3(const Vector3D<T> &c0, const Vector3D<T> &c1, const Vector3D<T> &c2) {
+ v[0][0]=c0.x; v[0][1]=c1.x; v[0][2]=c2.x;
+ v[1][0]=c0.y; v[1][1]=c1.y; v[1][2]=c2.y;
+ v[2][0]=c0.z; v[2][1]=c1.z; v[2][2]=c2.z;
+ }
+
+ // assignment operators
+ Matrix3x3& operator+=(const Matrix3x3 &m) {
+ v00 += m.v00; v01 += m.v01; v02 += m.v02;
+ v10 += m.v10; v11 += m.v11; v12 += m.v12;
+ v20 += m.v20; v21 += m.v21; v22 += m.v22;
+ return *this;
+ }
+ Matrix3x3& operator-=(const Matrix3x3 &m) {
+ v00 -= m.v00; v01 -= m.v01; v02 -= m.v02;
+ v10 -= m.v10; v11 -= m.v11; v12 -= m.v12;
+ v20 -= m.v20; v21 -= m.v21; v22 -= m.v22;
+ return *this;
+ }
+ Matrix3x3& operator*=(const T s) {
+ v00 *= s; v01 *= s; v02 *= s;
+ v10 *= s; v11 *= s; v12 *= s;
+ v20 *= s; v21 *= s; v22 *= s;
+ return *this;
+ }
+ Matrix3x3& operator/=(const T s) {
+ v00 /= s; v01 /= s; v02 /= s;
+ v10 /= s; v11 /= s; v12 /= s;
+ v20 /= s; v21 /= s; v22 /= s;
+ return *this;
+ }
+
+ // binary operators
+ Matrix3x3 operator+(const Matrix3x3 &m) const { return Matrix3x3(*this)+=m; }
+ Matrix3x3 operator-(const Matrix3x3 &m) const { return Matrix3x3(*this)-=m; }
+ Matrix3x3 operator*(const Matrix3x3 &m) const {
+ return Matrix3x3(v00*m.v00 + v01*m.v10 + v02*m.v20,
+ v00*m.v01 + v01*m.v11 + v02*m.v21,
+ v00*m.v02 + v01*m.v12 + v02*m.v22,
+
+ v10*m.v00 + v11*m.v10 + v12*m.v20,
+ v10*m.v01 + v11*m.v11 + v12*m.v21,
+ v10*m.v02 + v11*m.v12 + v12*m.v22,
+
+ v20*m.v00 + v21*m.v10 + v22*m.v20,
+ v20*m.v01 + v21*m.v11 + v22*m.v21,
+ v20*m.v02 + v21*m.v12 + v22*m.v22);
+ }
+ Matrix3x3 operator*(const T s) const { return Matrix3x3(*this)*=s; }
+ Vector3D<T> operator*(const Vector3D<T> &v) const {
+ return Vector3D<T>(v00*v.x+v01*v.y+v02*v.z,
+ v10*v.x+v11*v.y+v12*v.z,
+ v20*v.x+v21*v.y+v22*v.z);
+ }
+ Vector3D<T> transposedMul(const Vector3D<T> &v) const {
+ // M^T*v
+ return Vector3D<T>(v00*v.x+v10*v.y+v20*v.z,
+ v01*v.x+v11*v.y+v21*v.z,
+ v02*v.x+v12*v.y+v22*v.z);
+ }
+ Matrix3x3 transposedMul(const Matrix3x3 &m) const {
+ // M^T*M
+ return Matrix3x3(v00*m.v00 + v10*m.v10 + v20*m.v20,
+ v00*m.v01 + v10*m.v11 + v20*m.v21,
+ v00*m.v02 + v10*m.v12 + v20*m.v22,
+
+ v01*m.v00 + v11*m.v10 + v21*m.v20,
+ v01*m.v01 + v11*m.v11 + v21*m.v21,
+ v01*m.v02 + v11*m.v12 + v21*m.v22,
+
+ v02*m.v00 + v12*m.v10 + v22*m.v20,
+ v02*m.v01 + v12*m.v11 + v22*m.v21,
+ v02*m.v02 + v12*m.v12 + v22*m.v22);
+ }
+ Matrix3x3 mulTranspose(const Matrix3x3 &m) const {
+ // M*m^T
+ return Matrix3x3(v00*m.v00 + v01*m.v01 + v02*m.v02,
+ v00*m.v10 + v01*m.v11 + v02*m.v12,
+ v00*m.v20 + v01*m.v21 + v02*m.v22,
+
+ v10*m.v00 + v11*m.v01 + v12*m.v02,
+ v10*m.v10 + v11*m.v11 + v12*m.v12,
+ v10*m.v20 + v11*m.v21 + v12*m.v22,
+
+ v20*m.v00 + v21*m.v01 + v22*m.v02,
+ v20*m.v10 + v21*m.v11 + v22*m.v12,
+ v20*m.v20 + v21*m.v21 + v22*m.v22);
+ }
+
+ bool operator==(const Matrix3x3 &m) const {
+ return (v00==m.v00 && v01==m.v01 && v02==m.v02 &&
+ v10==m.v10 && v11==m.v11 && v12==m.v12 &&
+ v20==m.v20 && v21==m.v21 && v22==m.v22);
+ }
+
+ const T& operator()(const int r, const int c) const { return v[r][c]; }
+ T& operator()(const int r, const int c) { return const_cast<T &>(const_cast<const Matrix3x3 &>(*this)(r, c)); }
+
+ T trace() const { return v00 + v11 + v22; }
+ T sumSqr() const { return (v00*v00 + v01*v01 + v02*v02 + v10*v10 + v11*v11 + v12*v12 + v20*v20 + v21*v21 + v22*v22); }
+
+ Real determinant() const { return (v00*v11*v22 - v00*v12*v21 + v01*v12*v20 - v01*v10*v22 + v02*v10*v21 - v02*v11*v20); }
+ Matrix3x3& transpose() { return *this = transposed(); }
+ Matrix3x3 transposed() const { return Matrix3x3(v00, v10, v20, v01, v11, v21, v02, v12, v22); }
+ Matrix3x3& invert() { return *this = inverse(); }
+ Matrix3x3 inverse() const {
+ const Real det=determinant(); // FIXME: assert(det);
+ const Real idet=1e0/det;
+ return Matrix3x3(idet*(v11*v22-v12*v21), idet*(v02*v21-v01*v22), idet*(v01*v12-v02*v11),
+ idet*(v12*v20-v10*v22), idet*(v00*v22-v02*v20), idet*(v02*v10-v00*v12),
+ idet*(v10*v21-v11*v20), idet*(v01*v20-v00*v21), idet*(v00*v11-v01*v10));
+ }
+ bool getInverse(Matrix3x3 &inv) const {
+ const Real det=determinant();
+ if(det==0e0) return false; // FIXME: is it likely to happen the floating error?
+
+ const Real idet=1e0/det;
+ inv.v00=idet*(v11*v22-v12*v21);
+ inv.v01=idet*(v02*v21-v01*v22);
+ inv.v02=idet*(v01*v12-v02*v11);
+
+ inv.v10=idet*(v12*v20-v10*v22);
+ inv.v11=idet*(v00*v22-v02*v20);
+ inv.v12=idet*(v02*v10-v00*v12);
+
+ inv.v20=idet*(v10*v21-v11*v20);
+ inv.v21=idet*(v01*v20-v00*v21);
+ inv.v22=idet*(v00*v11-v01*v10);
+
+ return true;
+ }
+
+ Real normOne() const {
+ // the maximum absolute column sum of the matrix
+ return max(std::fabs(v00)+std::fabs(v10)+std::fabs(v20),
+ std::fabs(v01)+std::fabs(v11)+std::fabs(v21),
+ std::fabs(v02)+std::fabs(v12)+std::fabs(v22));
+ }
+ Real normInf() const {
+ // the maximum absolute row sum of the matrix
+ return max(std::fabs(v00)+std::fabs(v01)+std::fabs(v02),
+ std::fabs(v10)+std::fabs(v11)+std::fabs(v12),
+ std::fabs(v20)+std::fabs(v21)+std::fabs(v22));
+ }
+
+ Vector3D<T> eigenvalues() const {
+ Vector3D<T> eigen;
+
+ const Real b = - v00 - v11 - v22;
+ const Real c = v00*(v11+v22) + v11*v22 - v12*v21 - v01*v10 - v02*v20;
+ Real d =
+ - v00*(v11*v22-v12*v21) - v20*(v01*v12-v11*v02) - v10*(v02*v21-v22*v01);
+ const Real f = (3.0*c - b*b)/3.0;
+ const Real g = (2.0*b*b*b - 9.0*b*c + 27.0*d)/27.0;
+ const Real h = g*g/4.0 + f*f*f/27.0;
+
+ Real sign;
+ if(h>0) {
+ Real r = -g/2.0 + std::sqrt(h);
+ if(r<0) { r = -r; sign = -1.0; } else sign = 1.0;
+ Real s = sign*std::pow(r, 1.0/3.0);
+ Real t = -g/2.0-std::sqrt(h);
+ if(t<0) { t = -t; sign = -1.0; } else sign = 1.0;
+ Real u = sign*std::pow(t, 1.0/3.0);
+ eigen[0] = (s + u) - b/3.0; eigen[1] = eigen[2] = 0;
+ } else if(h==0) {
+ if(d<0) { d = -d; sign = -1.0; } sign = 1.0;
+ eigen[0] = -1.0*sign*std::pow(d, 1.0/3.0); eigen[1] = eigen[2] = 0;
+ } else {
+ const Real i = std::sqrt(g*g/4.0 - h);
+ const Real j = std::pow(i, 1.0/3.0);
+ const Real k = std::acos(-g/(2.0*i));
+ const Real l = -j;
+ const Real m = std::cos(k/3.0);
+ const Real n = std::sqrt(3.0)*std::sin(k/3.0);
+ const Real p = -b/3.0;
+ eigen[0] = 2e0*j*m + p;
+ eigen[1] = l*(m+n) + p;
+ eigen[2] = l*(m-n) + p;
+ }
+
+ return eigen;
+ }
+
+ static Matrix3x3 I() { return Matrix3x3(1,0,0, 0,1,0, 0,0,1); }
+
+#ifdef _WIN32
+#pragma warning(disable:4201)
+#endif
+ union {
+ struct { T v00, v01, v02, v10, v11, v12, v20, v21, v22; };
+ T v[3][3];
+ T v1[9];
+ };
+#ifdef _WIN32
+#pragma warning(default:4201)
+#endif
+};
+
+template<typename T1, typename T> inline Matrix3x3<T> operator*(const T1 s, const Matrix3x3<T> &m) {
+ return m*static_cast<T>(s);
+}
+
+template<typename T> inline Matrix3x3<T> crossProductMatrix(const Vector3D<T> &v) {
+ return Matrix3x3<T>(0, -v.z, v.y, v.z, 0, -v.x, -v.y, v.x, 0);
+}
+
+template<typename T> inline Matrix3x3<T> outerProduct(const Vector3D<T> &a, const Vector3D<T> &b) {
+ return Matrix3x3<T>(a.x*b.x, a.x*b.y, a.x*b.z,
+ a.y*b.x, a.y*b.y, a.y*b.z,
+ a.z*b.x, a.z*b.y, a.z*b.z);
+}
+
+typedef Matrix3x3<Real> Matrix3x3f;
+
+} // namespace
+
+#endif /* MATRIXBASE_H */
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/mcubes.h b/intern/mantaflow/intern/manta_develop/helper/util/mcubes.h
new file mode 100644
index 00000000000..5989beb1cc3
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/mcubes.h
@@ -0,0 +1,323 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Marching cubes lookup indices
+ *
+ ******************************************************************************/
+
+#ifndef _MCUBES_H_
+#define _MCUBES_H_
+
+static const int mcEdges[24] = {
+ 0,1, 1,2, 2,3, 3,0,
+ 4,5, 5,6, 6,7, 7,4,
+ 0,4, 1,5, 2,6, 3,7 };
+
+static const int cubieOffsetX[8] = { 0,1,1,0, 0,1,1,0 };
+static const int cubieOffsetY[8] = { 0,0,1,1, 0,0,1,1 };
+static const int cubieOffsetZ[8] = { 0,0,0,0, 1,1,1,1 };
+
+/* which edges are needed ? */
+/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
+static const short mcEdgeTable[256]={
+ 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
+ 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
+ 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
+ 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
+ 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
+ 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
+ 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
+ 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
+ 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
+ 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
+ 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
+ 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
+ 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
+ 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
+ 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
+ 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
+ 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
+ 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
+ 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
+ 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
+ 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
+ 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
+ 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
+ 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
+ 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
+ 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
+ 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
+ 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
+ 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
+ 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
+ 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
+ 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };
+
+/* triangles for the 256 intersection possibilities */
+/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
+static const short mcTriTable[256][16] = {
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
+ {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
+ {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
+ {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
+ {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
+ {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
+ {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
+ {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
+ {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
+ {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
+ {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
+ {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
+ {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
+ {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
+ {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
+ {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
+ {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
+ {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
+ {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
+ {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
+ {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
+ {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
+ {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
+ {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
+ {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
+ {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
+ {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
+ {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
+ {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
+ {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
+ {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
+ {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
+ {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
+ {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
+ {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
+ {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
+ {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
+ {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
+ {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
+ {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
+ {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
+ {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
+ {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
+ {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
+ {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
+ {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
+ {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
+ {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
+ {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
+ {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
+ {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
+ {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
+ {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
+ {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
+ {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
+ {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
+ {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
+ {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
+ {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
+ {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
+ {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
+ {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
+ {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
+ {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
+ {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
+ {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
+ {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
+ {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
+ {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
+ {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
+ {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
+ {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
+ {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
+ {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
+ {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
+ {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
+ {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
+ {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
+ {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
+ {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
+ {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
+ {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
+ {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
+ {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
+ {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
+ {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
+ {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
+ {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
+ {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
+ {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
+ {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
+ {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
+ {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
+ {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
+ {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
+ {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
+ {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
+ {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
+ {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
+ {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
+ {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
+ {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
+};
+
+#endif \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/quaternion.h b/intern/mantaflow/intern/manta_develop/helper/util/quaternion.h
new file mode 100644
index 00000000000..b7ba565a2b7
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/quaternion.h
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Basic quaternion class
+ *
+ ******************************************************************************/
+
+#ifndef _QUATERNION_H
+#define _QUATERNION_H
+
+#include "vectorbase.h"
+
+namespace Manta {
+
+//! Very basic quaternion class
+class Quaternion {
+public:
+
+ //! default constructor
+ Quaternion() : x(0), y(0), z(0), w(0) {}
+
+ //! copy constructor
+ Quaternion(const Quaternion& q) : x(q.x), y(q.y), z(q.z), w(q.w) {}
+
+ //! construct a quaternion from members
+ Quaternion(Real _x, Real _y, Real _z, Real _w) : x(_x), y(_y), z(_z), w(_w) {}
+
+ //! construct a quaternion from imag/real parts
+ Quaternion(Vec3 i, Real r) : x(i.x), y(i.y), z(i.z), w(r) {}
+
+ //! Assign operator
+ inline Quaternion& operator= (const Quaternion& q) {
+ x = q.x;
+ y = q.y;
+ z = q.z;
+ w = q.w;
+ return *this;
+ }
+
+ //! Assign multiplication operator
+ inline Quaternion& operator*= ( const Real a ) {
+ x *= a;
+ y *= a;
+ z *= a;
+ w *= a;
+ return *this;
+ }
+
+ //! return inverse quaternion
+ inline Quaternion inverse() const {
+ Real mag = 1.0/(x*x+y*y+z*z+w*w);
+ return Quaternion(-x*mag,-y*mag,-z*mag,w*mag);
+ }
+
+ //! imaginary part accessor
+ inline Vec3 imag() { return Vec3(x,y,z); }
+
+ // imaginary part
+ Real x;
+ Real y;
+ Real z;
+
+ // real part
+ Real w;
+};
+
+
+//! Multiplication operator
+inline Quaternion operator* ( const Quaternion &q1, const Quaternion &q2 ) {
+ return Quaternion ( q2.w * q1.x + q2.x * q1.w + q2.y * q1.z - q2.z * q1.y,
+ q2.w * q1.y + q2.y * q1.w + q2.z * q1.x - q2.x * q1.z,
+ q2.w * q1.z + q2.z * q1.w + q2.x * q1.y - q2.y * q1.x,
+ q2.w * q1.w - q2.x * q1.x - q2.y * q1.y - q2.z * q1.z );
+}
+
+//! Multiplication operator
+inline Quaternion operator* ( const Quaternion &q, const Real a ) {
+ return Quaternion ( q.x*a, q.y*a, q.z*a, q.w*a);
+}
+
+} // namespace
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/randomstream.h b/intern/mantaflow/intern/manta_develop/helper/util/randomstream.h
new file mode 100644
index 00000000000..3cb5c37197c
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/randomstream.h
@@ -0,0 +1,374 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Random numbers
+ *
+ * Based on an example by Makoto Matsumoto, Takuji Nishimura, Shawn Cokus, and Richard J. Wagner
+ *
+ ******************************************************************************/
+
+#ifndef _RANDOMSTREAM_H
+#define _RANDOMSTREAM_H
+
+namespace Manta {
+
+#include <iostream>
+#include <stdio.h>
+#include <time.h>
+#include "vectorbase.h"
+
+class MTRand {
+ // Data
+ public:
+ typedef unsigned long uint32; // unsigned integer type, at least 32 bits
+
+ enum { N = 624 }; // length of state vector
+ enum { SAVE = N + 1 }; // length of array for save()
+
+ protected:
+ enum { M = 397 }; // period parameter
+
+ uint32 state[N]; // internal state
+ uint32 *pNext; // next value to get from state
+ int left; // number of values left before reload needed
+
+
+ //Methods
+ public:
+ MTRand( const uint32& oneSeed ); // initialize with a simple uint32
+ MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or an array
+ MTRand(); // auto-initialize with /dev/urandom or time() and clock()
+
+ // Do NOT use for CRYPTOGRAPHY without securely hashing several returned
+ // values together, otherwise the generator state can be learned after
+ // reading 624 consecutive values.
+
+ // Access to 32-bit random numbers
+ double rand(); // real number in [0,1]
+ double rand( const double& n ); // real number in [0,n]
+ double randExc(); // real number in [0,1)
+ double randExc( const double& n ); // real number in [0,n)
+ double randDblExc(); // real number in (0,1)
+ double randDblExc( const double& n ); // real number in (0,n)
+ uint32 randInt(); // integer in [0,2^32-1]
+ uint32 randInt( const uint32& n ); // integer in [0,n] for n < 2^32
+ double operator()() { return rand(); } // same as rand()
+
+ // Access to 53-bit random numbers (capacity of IEEE double precision)
+ double rand53(); // real number in [0,1)
+
+ // Access to nonuniform random number distributions
+ double randNorm( const double& mean = 0.0, const double& variance = 1.0 );
+
+ // Re-seeding functions with same behavior as initializers
+ void seed( const uint32 oneSeed );
+ void seed( uint32 *const bigSeed, const uint32 seedLength = N );
+ void seed();
+
+ // Saving and loading generator state
+ void save( uint32* saveArray ) const; // to array of size SAVE
+ void load( uint32 *const loadArray ); // from such array
+ friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand );
+ friend std::istream& operator>>( std::istream& is, MTRand& mtrand );
+
+ protected:
+ void initialize( const uint32 oneSeed );
+ void reload();
+ uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; }
+ uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; }
+ uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; }
+ uint32 mixBits( const uint32& u, const uint32& v ) const {
+ return hiBit(u) | loBits(v);
+ }
+ uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const {
+ return m ^ (mixBits(s0,s1)>>1) ^ (-loBit(s1) & 0x9908b0dfUL);
+ }
+ static uint32 hash( time_t t, clock_t c );
+};
+
+
+inline MTRand::MTRand( const uint32& oneSeed )
+ { seed(oneSeed); }
+
+inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength )
+ { seed(bigSeed,seedLength); }
+
+inline MTRand::MTRand()
+ { seed(); }
+
+inline double MTRand::rand()
+ { return double(randInt()) * (1.0/4294967295.0); }
+
+inline double MTRand::rand( const double& n )
+ { return rand() * n; }
+
+inline double MTRand::randExc()
+ { return double(randInt()) * (1.0/4294967296.0); }
+
+inline double MTRand::randExc( const double& n )
+ { return randExc() * n; }
+
+inline double MTRand::randDblExc()
+ { return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); }
+
+inline double MTRand::randDblExc( const double& n )
+ { return randDblExc() * n; }
+
+inline double MTRand::rand53()
+{
+ uint32 a = randInt() >> 5, b = randInt() >> 6;
+ return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0); // by Isaku Wada
+}
+
+inline double MTRand::randNorm( const double& mean, const double& variance )
+{
+ // Return a real number from a normal (Gaussian) distribution with given
+ // mean and variance by Box-Muller method
+ double r = sqrt( -2.0 * log( 1.0-randDblExc()) ) * variance;
+ double phi = 2.0 * 3.14159265358979323846264338328 * randExc();
+ return mean + r * cos(phi);
+}
+
+inline MTRand::uint32 MTRand::randInt()
+{
+ // Pull a 32-bit integer from the generator state
+ // Every other access function simply transforms the numbers extracted here
+
+ if( left == 0 ) reload();
+ --left;
+
+ uint32 s1;
+ s1 = *pNext++;
+ s1 ^= (s1 >> 11);
+ s1 ^= (s1 << 7) & 0x9d2c5680UL;
+ s1 ^= (s1 << 15) & 0xefc60000UL;
+ return ( s1 ^ (s1 >> 18) );
+}
+
+inline MTRand::uint32 MTRand::randInt( const uint32& n )
+{
+ // Find which bits are used in n
+ // Optimized by Magnus Jonsson (magnus@smartelectronix.com)
+ uint32 used = n;
+ used |= used >> 1;
+ used |= used >> 2;
+ used |= used >> 4;
+ used |= used >> 8;
+ used |= used >> 16;
+
+ // Draw numbers until one is found in [0,n]
+ uint32 i;
+ do
+ i = randInt() & used; // toss unused bits to shorten search
+ while( i > n );
+ return i;
+}
+
+
+inline void MTRand::seed( const uint32 oneSeed )
+{
+ // Seed the generator with a simple uint32
+ initialize(oneSeed);
+ reload();
+}
+
+
+inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
+{
+ // Seed the generator with an array of uint32's
+ // There are 2^19937-1 possible initial states. This function allows
+ // all of those to be accessed by providing at least 19937 bits (with a
+ // default seed length of N = 624 uint32's). Any bits above the lower 32
+ // in each element are discarded.
+ // Just call seed() if you want to get array from /dev/urandom
+ initialize(19650218UL);
+ const unsigned int Nenum = N;
+ int i = 1;
+ uint32 j = 0;
+ int k = ( Nenum > seedLength ? Nenum : seedLength );
+ for( ; k; --k )
+ {
+ state[i] =
+ state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL );
+ state[i] += ( bigSeed[j] & 0xffffffffUL ) + j;
+ state[i] &= 0xffffffffUL;
+ ++i; ++j;
+ if( i >= N ) { state[0] = state[N-1]; i = 1; }
+ if( j >= seedLength ) j = 0;
+ }
+ for( k = N - 1; k; --k )
+ {
+ state[i] =
+ state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL );
+ state[i] -= i;
+ state[i] &= 0xffffffffUL;
+ ++i;
+ if( i >= N ) { state[0] = state[N-1]; i = 1; }
+ }
+ state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array
+ reload();
+}
+
+
+inline void MTRand::seed()
+{
+ // Seed the generator with an array from /dev/urandom if available
+ // Otherwise use a hash of time() and clock() values
+
+ // First try getting an array from /dev/urandom
+ FILE* urandom = fopen( "/dev/urandom", "rb" );
+ if( urandom )
+ {
+ uint32 bigSeed[N];
+ uint32 *s = bigSeed;
+ int i = N;
+ bool success = true;
+ while( success && i-- )
+ success = fread( s++, sizeof(uint32), 1, urandom );
+ fclose(urandom);
+ if( success ) { seed( bigSeed, N ); return; }
+ }
+
+ // Was not successful, so use time() and clock() instead
+ seed( hash( time(NULL), clock() ) );
+}
+
+
+inline void MTRand::initialize( const uint32 intseed )
+{
+ // Initialize generator state with seed
+ // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
+ // In previous versions, most significant bits (MSBs) of the seed affect
+ // only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
+ uint32 *s = state;
+ uint32 *r = state;
+ int i = 1;
+ *s++ = intseed & 0xffffffffUL;
+ for( ; i < N; ++i )
+ {
+ *s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL;
+ r++;
+ }
+}
+
+
+inline void MTRand::reload()
+{
+ // Generate N new values in state
+ // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
+ uint32 *p = state;
+ int i;
+ for( i = N - M; i--; ++p )
+ *p = twist( p[M], p[0], p[1] );
+ for( i = M; --i; ++p )
+ *p = twist( p[M-N], p[0], p[1] );
+ *p = twist( p[M-N], p[0], state[0] );
+
+ left = N, pNext = state;
+}
+
+
+inline MTRand::uint32 MTRand::hash( time_t t, clock_t c )
+{
+ // Get a uint32 from t and c
+ // Better than uint32(x) in case x is floating point in [0,1]
+ // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
+
+ static uint32 differ = 0; // guarantee time-based seeds will change
+
+ uint32 h1 = 0;
+ unsigned char *p = (unsigned char *) &t;
+ for( size_t i = 0; i < sizeof(t); ++i )
+ {
+ h1 *= std::numeric_limits<unsigned char>::max() + 2U;
+ h1 += p[i];
+ }
+ uint32 h2 = 0;
+ p = (unsigned char *) &c;
+ for( size_t j = 0; j < sizeof(c); ++j )
+ {
+ h2 *= std::numeric_limits<unsigned char>::max() + 2U;
+ h2 += p[j];
+ }
+ return ( h1 + differ++ ) ^ h2;
+}
+
+
+inline void MTRand::save( uint32* saveArray ) const
+{
+ uint32 *sa = saveArray;
+ const uint32 *s = state;
+ int i = N;
+ for( ; i--; *sa++ = *s++ ) {}
+ *sa = left;
+}
+
+
+inline void MTRand::load( uint32 *const loadArray )
+{
+ uint32 *s = state;
+ uint32 *la = loadArray;
+ int i = N;
+ for( ; i--; *s++ = *la++ ) {}
+ left = *la;
+ pNext = &state[N-left];
+}
+
+
+inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
+{
+ const MTRand::uint32 *s = mtrand.state;
+ int i = mtrand.N;
+ for( ; i--; os << *s++ << "\t" ) {}
+ return os << mtrand.left;
+}
+
+
+inline std::istream& operator>>( std::istream& is, MTRand& mtrand )
+{
+ MTRand::uint32 *s = mtrand.state;
+ int i = mtrand.N;
+ for( ; i--; is >> *s++ ) {}
+ is >> mtrand.left;
+ mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
+ return is;
+}
+
+// simple interface to mersenne twister
+class RandomStream
+{
+public:
+ inline RandomStream(long seed) : mtr(seed) {} ;
+ ~RandomStream() {}
+
+ /*! get a random number from the stream */
+ inline double getDouble( void ) { return mtr.rand(); };
+ inline float getFloat ( void ) { return (float)mtr.rand(); };
+
+ inline float getFloat( float min, float max ) { return mtr.rand(max-min) + min; };
+ inline float getRandNorm( float mean, float var) { return mtr.randNorm(mean, var); };
+
+ #if FLOATINGPOINT_PRECISION==1
+ inline Real getReal() { return getFloat(); }
+
+ #else
+ inline Real getReal() { return getDouble(); }
+ #endif
+
+ inline Vec3 getVec3 () { Real a=getReal(), b=getReal(), c=getReal(); return Vec3(a,b,c); }
+ inline Vec3 getVec3Norm () { Vec3 a=getVec3(); normalize(a); return a; }
+
+private:
+ MTRand mtr;
+};
+
+
+} // namespace
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/rcmatrix.h b/intern/mantaflow/intern/manta_develop/helper/util/rcmatrix.h
new file mode 100644
index 00000000000..39ebda6b222
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/rcmatrix.h
@@ -0,0 +1,921 @@
+//
+// Helper matrix class, RCMatrix.h
+// Required for PD optimizations (guiding)
+// Thanks to Ryoichi Ando, and Robert Bridson
+//
+
+#ifndef RCMATRIX3_H
+#define RCMATRIX3_H
+
+#include <iterator>
+#include <cassert>
+#include <vector>
+#include <fstream>
+
+// index type
+#define int_index long long
+
+// link to omp & tbb for now
+#if OPENMP==1 || TBB==1
+#define MANTA_ENABLE_PARALLEL 0
+// allow the preconditioner to be computed in parallel? (can lead to slightly non-deterministic results)
+#define MANTA_ENABLE_PARALLEL_PC 0
+// use c++11 code?
+#define MANTA_USE_CPP11 1
+#else
+#define MANTA_ENABLE_PARALLEL 0
+#define MANTA_ENABLE_PARALLEL_PC 0
+#define MANTA_USE_CPP11 0
+#endif
+
+#if MANTA_ENABLE_PARALLEL==1
+#include <thread>
+#include <algorithm>
+
+static const int manta_num_threads = std::thread::hardware_concurrency();
+
+// For clang
+#define parallel_for(total_size) { \
+int_index parallel_array_size = (total_size); \
+std::vector<std::thread> threads(manta_num_threads); \
+for( int thread_number=0; thread_number<manta_num_threads; thread_number++ ) { \
+ threads[thread_number] = std::thread([&](int_index parallel_array_size, int_index thread_number ) { \
+ for( int_index parallel_index=thread_number; parallel_index < parallel_array_size; parallel_index += manta_num_threads ) {
+
+#define parallel_end \
+ } \
+ },parallel_array_size,thread_number); \
+} \
+for(auto& thread : threads ) thread.join(); \
+}
+
+#define parallel_block { \
+ std::vector<std::thread> threads; { \
+
+#define do_parallel threads.push_back( std::thread([&]() {
+#define do_end } ) );
+
+#define block_end } \
+ for(auto& thread : threads) { \
+ thread.join(); \
+ } }
+
+#else
+
+#define parallel_for(size) { int thread_number = 0; int_index parallel_index=0; for( int_index parallel_index=0; parallel_index<(int_index)size; parallel_index++ ) {
+#define parallel_end } thread_number=parallel_index=0; }
+
+#define parallel_block
+#define do_parallel
+#define do_end
+#define block_end
+
+#endif
+
+#include "vectorbase.h"
+
+
+namespace Manta
+{
+
+static const unsigned default_expected_none_zeros = 7;
+
+template <class N, class T> struct RCMatrix {
+ struct RowEntry {
+ std::vector<N> index;
+ std::vector<T> value;
+ };
+ RCMatrix () : n(0), expected_none_zeros(default_expected_none_zeros) {}
+ RCMatrix ( N size, N expected_none_zeros=default_expected_none_zeros ) : n(0), expected_none_zeros(expected_none_zeros) { resize(size); }
+ RCMatrix ( const RCMatrix &m ) : n(0), expected_none_zeros(default_expected_none_zeros) {
+ init(m);
+ }
+ RCMatrix &operator=( const RCMatrix &m ) {
+ expected_none_zeros = m.expected_none_zeros;
+ init(m);
+ return *this;
+ }
+ RCMatrix &operator=( RCMatrix &&m ) {
+ matrix = m.matrix;
+ offsets = m.offsets;
+ expected_none_zeros = m.expected_none_zeros;
+ n = m.n;
+ m.n = 0;
+ m.matrix.clear();
+ m.offsets.clear();
+ return *this;
+ }
+ RCMatrix( RCMatrix &&m ) : n(m.n), expected_none_zeros(m.expected_none_zeros), matrix(m.matrix), offsets(m.offsets) {
+ m.n = 0;
+ m.matrix.clear();
+ m.offsets.clear();
+ }
+ void init( const RCMatrix &m ) {
+ expected_none_zeros = m.expected_none_zeros;
+ resize(m.n);
+ parallel_for(n) {
+ N i = parallel_index;
+ if( m.matrix[i] ) {
+ alloc_row(i);
+ matrix[i]->index = m.matrix[i]->index;
+ matrix[i]->value = m.matrix[i]->value;
+ } else {
+ dealloc_row(i);
+ }
+ } parallel_end
+ }
+ ~RCMatrix() {
+ clear();
+ }
+ void clear() {
+ for( N i=0; i<n; i++ ) {
+ dealloc_row(i);
+ matrix[i] = NULL;
+ if( offsets.size()) offsets[i] = 0;
+ }
+ };
+ bool empty( N i ) const {
+ return matrix[i] == NULL;
+ }
+ N row_nonzero_size( N i ) const {
+ return matrix[i] == NULL ? 0 : matrix[i]->index.size();
+ }
+ void resize( N size, N expected_none_zeros=0 ) {
+ if( ! expected_none_zeros ) {
+ expected_none_zeros = this->expected_none_zeros;
+ }
+ if( n > size ) {
+ // Shrinking
+ for( N i=size?size-1:0; i<n; i++ ) dealloc_row(i);
+ matrix.resize(size);
+ } else if( n < size ) {
+ // Expanding
+ matrix.resize(size);
+ for( N i=n; i<size; i++ ) {
+ matrix[i] = NULL;
+ if( offsets.size()) offsets[i] = 0;
+ }
+ }
+ n = size;
+ }
+ void alloc_row( N i ) {
+ assert( i < n );
+ if( ! matrix[i] ) {
+ matrix[i] = new RowEntry;
+ matrix[i]->index.reserve(expected_none_zeros);
+ matrix[i]->value.reserve(expected_none_zeros);
+ if( offsets.size()) offsets[i] = 0;
+ }
+ }
+ void dealloc_row( N i ) {
+ assert( i < n );
+ if( matrix[i] ) {
+ if( offsets.empty() || ! offsets[i] ) delete matrix[i];
+ matrix[i] = NULL;
+ if( offsets.size()) offsets[i] = 0;
+ }
+ }
+ T operator()(N i, N j) const {
+ assert( i < n );
+ for( Iterator it=row_begin(i); it; ++it ) {
+ if( it.index() == j ) return it.value();
+ }
+ return T(0.0);
+ }
+ void add_to_element_checked( N i, N j, T val ) {
+ if( (i<0) || (j<0) || (i>=n) || (j>=n) ) return;
+ add_to_element(i,j,val);
+ }
+ void add_to_element( N i, N j, T increment_value ) {
+ if( std::abs(increment_value) > VECTOR_EPSILON ) {
+ assert( i < n );
+ assert( offsets.empty() || offsets[i]==0 );
+ alloc_row(i);
+ std::vector<N> &index = matrix[i]->index;
+ std::vector<T> &value = matrix[i]->value;
+ for(N k=0; k<(N)index.size(); ++k){
+ if(index[k]==j){
+ value[k]+=increment_value;
+ return;
+ } else if( index[k] > j ){
+ index.insert(index.begin()+k,j);
+ value.insert(value.begin()+k,increment_value);
+ return;
+ }
+ }
+ index.push_back(j);
+ value.push_back(increment_value);
+ }
+ }
+
+ void set_element( N i, N j, T v ) {
+ if( std::abs(v) > VECTOR_EPSILON ) {
+ assert( i < n );
+ assert( offsets.empty() || offsets[i]==0 );
+ alloc_row(i);
+ std::vector<N> &index = matrix[i]->index;
+ std::vector<T> &value = matrix[i]->value;
+ for(N k=0; k<(N)index.size(); ++k){
+ if(index[k]==j){
+ value[k] = v;
+ return;
+ } else if( index[k] > j ){
+ index.insert(index.begin()+k,j);
+ value.insert(value.begin()+k,v);
+ return;
+ }
+ }
+ index.push_back(j);
+ value.push_back(v);
+ }
+ }
+
+ // Make sure that j is the biggest column in the row, no duplication allowed
+ void fix_element( N i, N j, T v ) {
+ if( std::abs(v) > VECTOR_EPSILON ) {
+ assert( i < n );
+ assert( offsets.empty() || offsets[i]==0 );
+ alloc_row(i);
+ std::vector<N> &index = matrix[i]->index;
+ std::vector<T> &value = matrix[i]->value;
+ index.push_back(j);
+ value.push_back(v);
+ }
+ }
+ int_index trim_zero_entries ( double e=VECTOR_EPSILON ) {
+ std::vector<int_index> deleted_entries(n,0);
+ parallel_for(n) {
+ N i = parallel_index;
+ if( matrix[i] ) {
+ std::vector<N> &index = matrix[i]->index;
+ std::vector<T> &value = matrix[i]->value;
+ N head=0;
+ N k=0;
+ for( k=0; k<index.size(); ++k ) {
+ if( std::abs(value[k]) > e ) {
+ index[head] = index[k];
+ value[head] = value[k];
+ ++ head;
+ }
+ }
+ if( head != k ) {
+ index.erase(index.begin()+head,index.end());
+ value.erase(value.begin()+head,value.end());
+ deleted_entries[i] += k-head;
+ }
+ if( ! offsets.size() && ! head ) {
+ remove_row(i);
+ }
+ }
+ } parallel_end
+ //
+ int_index sum_deleted(0);
+ for (int_index i = 0; i<n; i++) sum_deleted += deleted_entries[i];
+ return sum_deleted;
+ }
+ void remove_reference( N i ) {
+ if( offsets.size() && offsets[i] && matrix[i] ) {
+ RowEntry *save = matrix[i];
+ matrix[i] = new RowEntry;
+ *matrix[i] = *save;
+ for( N &index : matrix[i]->index ) index += offsets[i];
+ offsets[i] = 0;
+ }
+ }
+ void remove_row( N i ) {
+ dealloc_row(i);
+ }
+ bool is_symmetric( double e=VECTOR_EPSILON ) const {
+ std::vector<bool> flags(n,true);
+ parallel_for(n) {
+ N i = parallel_index;
+ bool flag = true;
+ for( Iterator it=row_begin(i); it; ++it ) {
+ N index = it.index();
+ T value = it.value();
+ if( std::abs(value) > e ) {
+ bool found_entry = false;
+ for( Iterator it_i=row_begin(index); it_i; ++it_i ) {
+ if( it_i.index()==i ) {
+ found_entry = true;
+ if( std::abs(value-it_i.value()) > e ) {
+ flag = false;
+ break;
+ }
+ }
+ }
+ if( ! found_entry ) flag = false;
+ if( ! flag ) break;
+ }
+ }
+ flags[i] = flag;
+ } parallel_end
+ for( N i=0; i<matrix.size(); ++i ) {
+ if( ! flags[i] ) return false;
+ }
+ return true;
+ }
+
+ void expand() {
+ if( offsets.empty() ) return;
+ for( N i=1; i<n; i++ ) {
+ if( offsets[i] ) {
+ RowEntry *ref = matrix[i];
+ matrix[i] = new RowEntry;
+ *matrix[i] = *ref;
+ for( N j=0; j<(N)matrix[i]->index.size(); j++ ) {
+ matrix[i]->index[j] += offsets[i];
+ }
+ }
+ }
+ offsets.resize(0);
+ }
+
+ N column( N i ) const {
+ return empty(i) ? 0 : row_begin(i,row_nonzero_size(i)-1).index();
+ }
+ N getColumnSize() const {
+ N max_column(0);
+ auto column = [&]( N i ) {
+ N max_column(0);
+ for( Iterator it=row_begin(i); it; ++it ) max_column = std::max(max_column,it.index());
+ return max_column+1;
+ };
+ for( N i=0; i<n; i++ ) max_column = std::max(max_column,column(i));
+ return max_column;
+ }
+ N getNonzeroSize() const {
+ N nonzeros(0);
+ for( N i=0; i<n; ++i ){
+ nonzeros += row_nonzero_size(i);
+ }
+ return nonzeros;
+ }
+ class Iterator : std::iterator<std::input_iterator_tag,T> {
+ public:
+ Iterator( const RowEntry* rowEntry, N k, N offset ) : rowEntry(rowEntry), k(k), offset(offset) {}
+ operator bool() const {
+ return rowEntry != NULL && k < (N)rowEntry->index.size();
+ }
+ Iterator& operator++() {
+ ++ k;
+ return *this;
+ }
+ T value() const {
+ return rowEntry->value[k];
+ }
+ N index() const {
+ return rowEntry->index[k]+offset;
+ }
+ N index_raw() const {
+ return rowEntry->index[k];
+ }
+ N size() const {
+ return rowEntry == NULL ? 0 : rowEntry->index.size();
+ }
+ protected:
+ const RowEntry *rowEntry;
+ N k, offset;
+ };
+ Iterator row_begin( N n, N k=0 ) const { return Iterator(matrix[n],k,offsets.size()?offsets[n]:0); }
+ class DynamicIterator : public Iterator {
+ public:
+ DynamicIterator( RowEntry* rowEntry, N k, N offset ) : rowEntry(rowEntry), Iterator(rowEntry,k,offset) {}
+ void setValue( T value ) {
+ rowEntry->value[Iterator::k] = value;
+ }
+ void setIndex( N index ) {
+ rowEntry->index[Iterator::k] = index;
+ }
+ protected:
+ RowEntry *rowEntry;
+ };
+ DynamicIterator dynamic_row_begin( N n, N k=0 ) {
+ N offset = offsets.size() ? offsets[n] : 0;
+ if( offset ) {
+ printf( "---- Warning ----\n");
+ printf( "Dynamic iterator is not allowed for referenced rows.\n");
+ printf( "You should be very careful otherwise this causes some bugs.\n");
+ printf( "We encourage you that you convert this row into a raw format, then loop over it...\n");
+ printf( "-----------------\n");
+ exit(0);
+ }
+ return DynamicIterator(matrix[n],k,offset);
+ }
+ RCMatrix transpose( N rowsize=0, unsigned expected_none_zeros=default_expected_none_zeros ) const {
+ if( ! rowsize ) rowsize = getColumnSize();
+ RCMatrix result(rowsize,expected_none_zeros);
+ for( N i=0; i<n; i++ ) {
+ for( Iterator it=row_begin(i); it; ++it ) result.fix_element(it.index(),i,it.value());
+ }
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+
+ RCMatrix getKtK() const {
+ RCMatrix m = transpose();
+ RCMatrix result(n,expected_none_zeros);
+ // Run in parallel
+ parallel_for(result.n) {
+ N i = parallel_index;
+ for( Iterator it_A=m.row_begin(i); it_A; ++it_A ) {
+ N j = it_A.index();
+ assert( j < n );
+ T a = it_A.value();
+ if( std::abs(a) > VECTOR_EPSILON ) {
+ for( Iterator it_B=row_begin(j); it_B; ++it_B ) {
+ //result.add_to_element(i,it_B.index(),it_B.value()*a);
+ double value = it_B.value()*a;
+ if( std::abs(value) > VECTOR_EPSILON ) result.add_to_element(i,it_B.index(),value);
+ }
+ }
+ }
+ } parallel_end
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+
+ RCMatrix operator*(const RCMatrix &m) const {
+ RCMatrix result(n,expected_none_zeros);
+ // Run in parallel
+ parallel_for(result.n) {
+ N i = parallel_index;
+ for( Iterator it_A=row_begin(i); it_A; ++it_A ) {
+ N j = it_A.index();
+ assert( j < m.n );
+ T a = it_A.value();
+ if( std::abs(a) > VECTOR_EPSILON ) {
+ for( Iterator it_B=m.row_begin(j); it_B; ++it_B ) {
+ //result.add_to_element(i,it_B.index(),it_B.value()*a);
+ double value = it_B.value()*a;
+ if( std::abs(value) > VECTOR_EPSILON ) result.add_to_element(i,it_B.index(),value);
+ }
+ }
+ }
+ } parallel_end
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+
+ RCMatrix sqrt() const {
+ RCMatrix result(n,expected_none_zeros);
+ // Run in parallel
+ parallel_for(result.n) {
+ N i = parallel_index;
+ for( Iterator it_A=row_begin(i); it_A; ++it_A ) {
+ N j = it_A.index();
+ result.set_element(i,j,std::sqrt(it_A.value()));
+ }
+ } parallel_end
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+
+RCMatrix operator*(const double k) const {
+ RCMatrix result(n,expected_none_zeros);
+ // Run in parallel
+ parallel_for(result.n) {
+ N i = parallel_index;
+ for( Iterator it_A=row_begin(i); it_A; ++it_A ) {
+ N j = it_A.index();
+ result.add_to_element(i,j,it_A.value()*k);
+ }
+ } parallel_end
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+
+RCMatrix applyKernel(const RCMatrix &kernel, const int nx, const int ny) const {
+ RCMatrix result(n,expected_none_zeros);
+ // find center position of kernel (half of kernel size)
+ int kCols = kernel.n, kRows = kernel.n, rows = nx, cols = ny;
+ int kCenterX = kCols / 2;
+ int kCenterY = kRows / 2;
+ // Run in parallel
+ parallel_for(result.n) {
+ N i = parallel_index;
+ if (i >= rows) break;
+ for( Iterator it_A=row_begin(i); it_A; ++it_A ) {
+ N j = it_A.index();
+ if (j >= cols) break;
+ for (int m = 0; m < kRows; ++m) { // kernel rows
+ int mm = kRows - 1 - m; // row index of flipped kernel
+ for (int n = 0; n < kCols; ++n) { // kernel columns
+ int nn = kCols - 1 - n; // column index of flipped kernel
+ // index of input signal, used for checking boundary
+ int ii = i + (m - kCenterY);
+ int jj = j + (n - kCenterX);
+ // ignore input samples which are out of bound
+ if (ii >= 0 && ii < rows && jj >= 0 && jj < cols)
+ result.add_to_element(i, j, (*this)(ii,jj) * kernel(mm,nn));
+ }
+ }
+ }
+ } parallel_end
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+
+RCMatrix applyHorizontalKernel(const RCMatrix &kernel, const int nx, const int ny) const {
+ RCMatrix result(n,expected_none_zeros);
+ // find center position of kernel (half of kernel size)
+ int kCols = kernel.n, kRows = 1, rows = nx, cols = ny;
+ int kCenterX = kCols / 2;
+ int kCenterY = kRows / 2;
+ // Run in parallel
+ parallel_for(result.n) {
+ N i = parallel_index;
+ if (i >= rows) break;
+ for( Iterator it_A=row_begin(i); it_A; ++it_A ) {
+ N j = it_A.index();
+ if (j >= cols) break;
+ for (int m = 0; m < kRows; ++m) { // kernel rows
+ int mm = kRows - 1 - m; // row index of flipped kernel
+ for (int n = 0; n < kCols; ++n) { // kernel columns
+ int nn = kCols - 1 - n; // column index of flipped kernel
+ // index of input signal, used for checking boundary
+ int ii = i + (m - kCenterY);
+ int jj = j + (n - kCenterX);
+ // ignore input samples which are out of bound
+ if (ii >= 0 && ii < rows && jj >= 0 && jj < cols)
+ result.add_to_element(i, j, (*this)(ii,jj) * kernel(mm,nn));
+ }
+ }
+ }
+ } parallel_end
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+
+RCMatrix applyVerticalKernel(const RCMatrix &kernel, const int nx, const int ny) const {
+ RCMatrix result(n,expected_none_zeros);
+ // find center position of kernel (half of kernel size)
+ int kCols = 1, kRows = kernel.n, rows = nx, cols = ny;
+ int kCenterX = kCols / 2;
+ int kCenterY = kRows / 2;
+ // Run in parallel
+ parallel_for(result.n) {
+ N i = parallel_index;
+ if (i >= rows) break;
+ for( Iterator it_A=row_begin(i); it_A; ++it_A ) {
+ N j = it_A.index();
+ if (j >= cols) break;
+ for (int m = 0; m < kRows; ++m) { // kernel rows
+ int mm = kRows - 1 - m; // row index of flipped kernel
+ for (int n = 0; n < kCols; ++n) { // kernel columns
+ int nn = kCols - 1 - n; // column index of flipped kernel
+ // index of input signal, used for checking boundary
+ int ii = i + (m - kCenterY);
+ int jj = j + (n - kCenterX);
+ // ignore input samples which are out of bound
+ if (ii >= 0 && ii < rows && jj >= 0 && jj < cols)
+ result.add_to_element(i, j, (*this)(ii,jj) * kernel(mm,nn));
+ }
+ }
+ }
+ } parallel_end
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+
+ RCMatrix applySeparableKernel(const RCMatrix &kernelH, const RCMatrix &kernelV, const int nx, const int ny) const {
+ return applyHorizontalKernel(kernelH, nx, ny).applyVerticalKernel(kernelV, nx, ny);
+ }
+
+ RCMatrix applySeparableKernelTwice(const RCMatrix &kernelH, const RCMatrix &kernelV, const int nx, const int ny) const {
+ return applySeparableKernel(kernelH, kernelV, nx, ny).applySeparableKernel(kernelH, kernelV, nx, ny);
+ }
+
+ std::vector<T> operator*( const std::vector<T> &rhs ) const {
+ std::vector<T> result(n,0.0);
+ multiply(rhs,result);
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+ void multiply( const std::vector<T> &rhs, std::vector<T> &result ) const {
+ result.resize(n);
+ for( N i=0; i<n; i++ ) {
+ T new_value = 0.0;
+ for( Iterator it=row_begin(i); it; ++it ) {
+ N j_index = it.index();
+ assert(j_index < rhs.size());
+ new_value += rhs[j_index] * it.value();
+ }
+ result[i] = new_value;
+ }
+ }
+ RCMatrix operator+( const RCMatrix &m ) const {
+ RCMatrix A(*this);
+ return std::move(A.add(m));
+ }
+ RCMatrix& add( const RCMatrix &m ) {
+ if( m.n > n ) resize(m.n);
+ parallel_for(m.n) {
+ N i = parallel_index;
+ for( Iterator it=m.row_begin(i); it; ++it ) {
+ add_to_element(i,it.index(),it.value());
+ }
+ } parallel_end
+ return *this;
+ }
+ RCMatrix operator-( const RCMatrix &m ) const {
+ RCMatrix A(*this);
+ return std::move(A.sub(m));
+ }
+ RCMatrix& sub( const RCMatrix &m ) {
+ if( m.n > n ) resize(m.n);
+ parallel_for(m.n) {
+ N i = parallel_index;
+ for( Iterator it=m.row_begin(i); it; ++it ) {
+ add_to_element(i,it.index(),-it.value());
+ }
+ } parallel_end
+ return *this;
+ }
+ RCMatrix& replace( const RCMatrix &m, int rowInd, int colInd) {
+ if( m.n > n ) resize(m.n);
+ parallel_for(m.n) {
+ N i = parallel_index;
+ for( Iterator it=m.row_begin(i); it; ++it ) {
+ set_element(i+rowInd,it.index()+colInd,it.value());
+ }
+ } parallel_end
+ return *this;
+ }
+ Real max_residual( const std::vector<T> &lhs, const std::vector<T> &rhs ) const {
+ std::vector<T> r = operator*(lhs);
+ Real max_residual = 0.0;
+ for( N i=0; i<rhs.size(); i++ ) {
+ if( ! empty(i) ) max_residual = std::max(max_residual,std::abs(r[i]-rhs[i]));
+ }
+ return max_residual;
+ }
+ std::vector<T> residual_vector( const std::vector<T> &lhs, const std::vector<T> &rhs ) const {
+ std::vector<T> result = operator*(lhs);
+ assert( result.size() == rhs.size() );
+ for( N i=0; i<result.size(); i++ ) {
+ result[i] = std::abs(result[i]-rhs[i]);
+ }
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+ T norm() const {
+ T result(0.0);
+ for( N i=0; i<n; ++i ) {
+ for( Iterator it=row_begin(i); it; ++it ) {
+ result = std::max(result,std::abs(it.value()));
+ }
+ }
+ return result;
+ }
+
+ T norm_L2_sqr() const {
+ T result(0.0);
+ for( N i=0; i<n; ++i ) {
+ for( Iterator it=row_begin(i); it; ++it ) {
+ result += (it.value())*(it.value());
+ }
+ }
+ return result;
+ }
+
+ void write_matlab(std::ostream &output, unsigned int rows, unsigned int columns, const char *variable_name)
+ {
+ output<<variable_name<<"=sparse([";
+ for(N i=0; i<n; ++i){
+ if( matrix[i] ) {
+ const std::vector<N> &index = matrix[i]->index;
+ for(N j=0; j<(N)index.size(); ++j){
+ output<<i+1<<" ";
+ }
+ }
+ }
+ output<<"],...\n [";
+ for(N i=0; i<n; ++i){
+ if( matrix[i] ) {
+ const std::vector<N> &index = matrix[i]->index;
+ for(N j=0; j<(N)index.size(); ++j){
+ output<<index[j]+(offsets.empty()?0:offsets[i])+1<<" ";
+ }
+ }
+ }
+ output<<"],...\n [";
+ for(N i=0; i<n; ++i){
+ if( matrix[i] ) {
+ const std::vector<T> &value = matrix[i]->value;
+ for(N j=0; j<value.size(); ++j){
+ output<<value[j]<<" ";
+ }
+ }
+ }
+ output<<"], "<<rows<<", "<<columns<<");"<<std::endl;
+ };
+ void export_matlab(std::string filename, std::string name) {
+ // Export this matrix
+ std::ofstream file;
+ file.open( filename.c_str() );
+ write_matlab(file,n,getColumnSize(),name.c_str());
+ file.close();
+ }
+ void print_readable(std::string name, bool printNonZero=true) {
+ std::cout <<name<<" \n";
+ for(int i=0; i<n; ++i) {
+ for(int j=0; j<n; ++j) {
+ if(printNonZero) {
+ if( (*this)(i,j) == 0) { std::cout <<" ."; continue; }
+ } else {
+ if( (*this)(i,j) == 0) { continue; }
+ }
+
+ if( (*this)(i,j) >= 0) std::cout <<" ";
+ std::cout <<" "<<(*this)(i,j);
+ }
+ std::cout <<" \n";
+ }
+ }
+ ///
+ N n;
+ N expected_none_zeros;
+ std::vector<RowEntry *> matrix;
+ std::vector<int> offsets;
+};
+
+template <class N, class T> static inline RCMatrix<N,T> operator*( const std::vector<T> &diagonal, const RCMatrix<N,T> &A) {
+ RCMatrix<N,T> result(A);
+ parallel_for(result.n) {
+ N row (parallel_index);
+ for( auto it=result.dynamic_row_begin(row); it; ++it ) {
+ it.setValue(it.value() * diagonal[row]);
+ }
+ } parallel_end
+ return std::move(result);
+}
+
+template <class N, class T> struct RCFixedMatrix {
+ std::vector<N> rowstart;
+ std::vector<N> index;
+ std::vector<T> value;
+ N n;
+ N max_rowlength;
+ //
+ RCFixedMatrix() : n(0), max_rowlength(0) {}
+ RCFixedMatrix( const RCMatrix<N,T> &matrix ) {
+ n = matrix.n;
+ rowstart.resize(n+1);
+ rowstart[0]=0;
+ max_rowlength = 0;
+ for(N i=0; i<n; i++){
+ if( ! matrix.empty(i) ) {
+ rowstart[i+1]=rowstart[i]+matrix.row_nonzero_size(i);
+ max_rowlength = std::max(max_rowlength,rowstart[i+1]-rowstart[i]);
+ } else {
+ rowstart[i+1]=rowstart[i];
+ }
+ }
+ value.resize(rowstart[n]);
+ index.resize(rowstart[n]);
+ N j=0;
+ for( N i=0; i<n; i++) {
+ for( typename RCMatrix<N,T>::Iterator it=matrix.row_begin(i); it; ++it ) {
+ value[j]=it.value();
+ index[j]=it.index();
+ ++j;
+ }
+ }
+ }
+ class Iterator : std::iterator<std::input_iterator_tag,T> {
+ public:
+ Iterator( N start, N end, const std::vector<N> &index, const std::vector<T> &value )
+ : index_array(index), value_array(value), k(start), start(start), end(end) {}
+ operator bool() const {
+ return k < end;
+ }
+ Iterator& operator++() {
+ ++ k;
+ return *this;
+ }
+ T value() const {
+ return value_array[k];
+ }
+ N index() const {
+ return index_array[k];
+ }
+ N size() const {
+ return end-start;
+ }
+ private:
+ const std::vector<N> &index_array;
+ const std::vector<T> &value_array;
+ N k, start, end;
+ };
+ Iterator row_begin( N n ) const { return Iterator(rowstart[n],rowstart[n+1],index,value); }
+ std::vector<T> operator*( const std::vector<T> &rhs ) const {
+ std::vector<T> result(n,0.0);
+ multiply(rhs,result);
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+ void multiply( const std::vector<T> &rhs, std::vector<T> &result ) const {
+ result.resize(n);
+ parallel_for(n) {
+ N i = parallel_index;
+ T new_value = 0.0;
+ for( Iterator it=row_begin(i); it; ++it ) {
+ N j_index = it.index();
+ assert(j_index < rhs.size());
+ new_value += rhs[j_index] * it.value();
+ }
+ result[i] = new_value;
+ } parallel_end
+ }
+ RCMatrix<N,T> operator*( const RCFixedMatrix &m ) const {
+ RCMatrix<N,T> result(n,max_rowlength);
+ // Run in parallel
+ parallel_for(result.n) {
+ N i = parallel_index;
+ for( Iterator it_A=row_begin(i); it_A; ++it_A ) {
+ N j = it_A.index();
+ assert( j < m.n );
+ T a = it_A.value();
+ if( std::abs(a) > VECTOR_EPSILON ) {
+ for( Iterator it_B=m.row_begin(j); it_B; ++it_B ) {
+ result.add_to_element(i,it_B.index(),it_B.value()*a);
+ }
+ }
+ }
+ } parallel_end
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+
+ RCMatrix<N,T> toRCMatrix () const {
+ RCMatrix<N,T> result(n,0);
+ parallel_for(n) {
+ N i = parallel_index;
+ N size = rowstart[i+1]-rowstart[i];
+ result.matrix[i] = new typename RCMatrix<N,T>::RowEntry;
+ result.matrix[i]->index.resize(size);
+ result.matrix[i]->value.resize(size);
+ for( N j=0; j<size; j++ ) {
+ result.matrix[i]->index[j] = index[rowstart[i]+j];
+ result.matrix[i]->value[j] = value[rowstart[i]+j];
+ }
+ } parallel_end
+# if MANTA_USE_CPP11==1
+ return std::move(result);
+# else
+ return result;
+# endif
+ }
+};
+
+typedef RCMatrix<int,Real> Matrix;
+typedef RCFixedMatrix<int,Real> FixedMatrix;
+
+}
+
+#undef parallel_for
+#undef parallel_end
+
+#undef parallel_block
+#undef do_parallel
+#undef do_end
+#undef block_end
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/simpleimage.cpp b/intern/mantaflow/intern/manta_develop/helper/util/simpleimage.cpp
new file mode 100644
index 00000000000..bd3b28abafa
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/simpleimage.cpp
@@ -0,0 +1,285 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Simple image IO
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "simpleimage.h"
+
+namespace Manta {
+
+// write rectangle to ppm
+bool SimpleImage::writePpm(std::string filename, int minx, int miny, int maxx, int maxy, bool invertXY) {
+ int w = maxx-minx;
+ int h = maxy-miny;
+
+ if (w<=0 || h<=0 || w>mSize[0] || h>mSize[1]) {
+ errMsg("SimpleImage::WritePPM Invalid rect: w="<<w<<", h="<<h<<", size="<<mSize[0]<<","<<mSize[1]<<" min/max: "<<minx<<","<<miny<<" to "<<maxx<<","<<maxy<<", resetting... " );
+ minx = miny = 0;
+ maxx = mSize[0]-1;
+ maxy = mSize[1]-1;
+ w = mSize[0]-1;
+ h = mSize[1]-1;
+ }
+
+ FILE* fp = fopen(filename.c_str(), "wb");
+ if (fp==NULL) {
+ errMsg("SimpleImage::WritePPM Unable to open '"<<filename<<"' for writing");
+ return false;
+ }
+ fprintf(fp, "P6\n%d %d\n255\n", w, h);
+
+ int pixCnt = 0;
+ for(int j=maxy-1; j>=miny; j--)
+ for(int i=minx; i<maxx; i++) {
+ unsigned char col[3];
+ for(int l=0; l<3; l++) {
+ float val;
+ if(invertXY) val = (float)get(j,i)[l];
+ else val =(float)get(i,j)[l];
+
+ val = clamp(val, (float)0.,(float)1.);
+ col[l] = (unsigned char)(255. * val );
+ }
+ //col[1] = col[2] = col[0];
+ //if (fwrite(col,1,3, fp) != 3) errMsg("SimpleImage::writePpm fwrite failed");
+ fwrite(col,1,3, fp);
+ pixCnt++;
+ //fprintf(stderr,"%d %d %d \n",col[0],i,j);
+ }
+
+ fclose(fp);
+ //debMsg("WritePPM Wrote '"<<filename<<"', region="<<minx<<","<<miny<<" to "<<maxx<<","<<maxy<<"; "<<pixCnt, 1);
+
+ return true;
+}
+
+bool SimpleImage::writePpm(std::string filename) {
+ return writePpm(filename, 0,0, getSize()[0], getSize()[1] );
+}
+
+
+// read in a ppm file, and init the image accordingly
+bool SimpleImage::initFromPpm (std::string filename) {
+ // maximum length of a line of text
+ const int MAXLINE=1024;
+
+ int filetype=0;
+ enum {PGM, PPM}; // possible file types
+
+ FILE *fp;
+ char line[MAXLINE];
+ int size, rowsize;
+
+ // Read in file type
+ fp = fopen(filename.c_str(), "rb");
+ if(!fp) {
+ if(mAbortOnError) debMsg("SimpleImage Error - unable to open file '"<< filename<<"' for reading", 1);
+ return 0;
+ }
+
+ // 1st line: PPM or PGM
+ if (fgets (line, MAXLINE, fp) == NULL) {
+ if(mAbortOnError) debMsg("SimpleImage::initFromPpm fgets failed", 1);
+ return 0;
+ }
+
+ if (line[1] == '5')
+ filetype = PGM;
+ else if (line[1] == '6')
+ filetype = PPM;
+ else {
+ if(mAbortOnError) debMsg("SimpleImage Error: need PPM or PGM file as input!", 1);
+ return 0;
+ }
+
+ // Read in width and height, & allocate space
+ // 2nd line: width height
+ if (fgets (line, MAXLINE, fp) == NULL) {
+ if(mAbortOnError) errMsg("SimpleImage::initFromPpm fgets failed");
+ return 0;
+ }
+ int windW=0, windH=0; // size of the window on the screen
+ int intsFound = sscanf(line, "%d %d", &windW, &windH);
+ if( intsFound == 1) {
+ // only X found, search on next line as well for Y...
+ if( sscanf(line, "%d", &windH) != 1) {
+ if(mAbortOnError) errMsg("initFromPpm Ppm dimensions not found!"<<windW<<","<<windH);
+ return 0;
+ } else {
+ // ok, found 2 lines
+ //debMsg("initFromPpm Ppm dimensions found!"<<windW<<","<<windH, 1);
+ }
+ } else if( intsFound == 2) {
+ // ok!
+ } else {
+ if(mAbortOnError) errMsg("initFromPpm Ppm dimensions not found at all!"<<windW<<","<<windH);
+ return 0;
+ }
+
+ if (filetype == PGM) {
+ size = windH * windW; // greymap: 1 byte per pixel
+ rowsize = windW;
+ } else {
+ // filetype == PPM
+ size = windH * windW * 3; // pixmap: 3 bytes per pixel
+ rowsize = windW * 3;
+ }
+
+ unsigned char *pic = new unsigned char[size]; // (GLubyte *)malloc (size);
+
+ // Read in maximum value (ignore) , could be scanned with sscanf as well, but this should be 255...
+ // 3rd line
+ if (fgets (line, MAXLINE, fp) == NULL) {
+ if(mAbortOnError) errMsg("SimpleImage::initFromPpm fgets failed");
+ return 0;
+ }
+
+ // Read in the pixel array row-by-row: 1st row = top scanline */
+ unsigned char *ptr = NULL;
+ ptr = &pic[(windH-1) * rowsize];
+ for (int i = windH; i > 0; i--) {
+ assertMsg( fread((void *)ptr, 1, rowsize, fp) == rowsize, "SimpleImage::initFromPpm couldn't read data");
+ ptr -= rowsize;
+ }
+
+ // init image
+ this->init(windW, windH);
+ if (filetype == PGM) {
+ // grayscale
+ for(int i=0; i<windW; i++) {
+ for(int j=0; j<windH; j++) {
+ double r = (double)pic[(j*windW+i)*1+0] / 255.;
+ (*this)(i,j) = Vec3(r,r,r);
+ }
+ }
+ } else {
+ // convert grid to RGB vec's
+ for(int i=0; i<windW; i++) {
+ for(int j=0; j<windH; j++) {
+ // return mpData[y*mSize[0]+x];
+ double r = (double)pic[(j*windW+i)*3+0] / 255.;
+ double g = (double)pic[(j*windW+i)*3+1] / 255.;
+ double b = (double)pic[(j*windW+i)*3+2] / 255.;
+
+ //(*this)(i,j) = Vec3(r,g,b);
+
+ // RGB values have to be rotated to get the right colors!?
+ // this might also be an artifact of photoshop export...?
+ (*this)(i,j) = Vec3(g,b,r);
+ }
+ }
+ }
+
+ delete [] pic;
+ fclose(fp);
+ return 1;
+}
+
+
+// check index is valid
+bool SimpleImage::indexIsValid(int i, int j)
+{
+ if(i<0) return false;
+ if(j<0) return false;
+ if(i>=mSize[0]) return false;
+ if(j>=mSize[1]) return false;
+ return true;
+}
+
+}; // manta
+
+//*****************************************************************************
+
+#include "grid.h"
+namespace Manta {
+
+// simple shaded output , note requires grid functionality!
+static void gridPrecompLight(const Grid<Real>& density, Grid<Real>& L, Vec3 light = Vec3(1,1,1) )
+{
+ FOR_IJK(density) {
+ Vec3 n = getGradient( density, i,j,k ) * -1.;
+ normalize(n);
+
+ Real d = dot( light, n );
+ L(i,j,k) = d;
+ }
+}
+
+// simple shading with pre-computed gradient
+static inline void shadeCell(Vec3& dst, int shadeMode, Real src, Real light, int depthPos, Real depthInv)
+{
+ switch(shadeMode) {
+
+ case 1: {
+ // surfaces
+ Vec3 ambient = Vec3(0.1,0.1,0.1);
+ Vec3 diffuse = Vec3(0.9,0.9,0.9);
+ Real alpha = src;
+
+ // different color for depth?
+ diffuse[0] *= ((Real)depthPos * depthInv) * 0.7 + 0.3;
+ diffuse[1] *= ((Real)depthPos * depthInv) * 0.7 + 0.3;
+
+ Vec3 col = ambient + diffuse * light;
+
+ //img( 0+i, j ) = (1.-alpha) * img( 0+i, j ) + alpha * col;
+ dst = (1.-alpha) * dst + alpha * col;
+ } break;
+
+ default: {
+ // volumetrics / smoke
+ dst += depthInv * Vec3(src,src,src);
+ } break;
+
+ }
+}
+
+//! helper to project a grid intro an image (used for ppm export and GUI displauy)
+void projectImg( SimpleImage& img, const Grid<Real>& val, int shadeMode=0, Real scale=1.)
+{
+ Vec3i s = val.getSize();
+ Vec3 si = Vec3( 1. / (Real)s[0], 1. / (Real)s[1], 1. / (Real)s[2] );
+
+ // init image size
+ int imgSx = s[0];
+ if(val.is3D()) imgSx += s[2]+s[0]; // mult views in 3D
+ img.init( imgSx, std::max(s[0], std::max( s[1],s[2])) );
+
+ // precompute lighting
+ Grid<Real> L(val);
+ gridPrecompLight( val, L , Vec3(1,1,1) );
+
+ FOR_IJK(val) {
+ Vec3i idx(i,j,k);
+ shadeCell( img( 0+i, j ) , shadeMode, val(idx), L(idx), k, si[2]);
+ }
+
+ if( val.is3D() ) {
+
+ FOR_IJK(val) {
+ Vec3i idx(i,j,k);
+ shadeCell( img( s[0]+k, j ) , shadeMode, val(idx), L(idx), i, si[0]);
+ }
+
+ FOR_IJK(val) {
+ Vec3i idx(i,j,k);
+ shadeCell( img( s[0]+s[2]+i, k ) , shadeMode, val(idx), L(idx), j, si[1]);
+ }
+
+ } // 3d
+
+ img.mapRange( 1./scale );
+}
+
+
+}; // manta
+
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/simpleimage.h b/intern/mantaflow/intern/manta_develop/helper/util/simpleimage.h
new file mode 100644
index 00000000000..a3f336d33fd
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/simpleimage.h
@@ -0,0 +1,183 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Simple image IO
+ *
+ ******************************************************************************/
+
+#ifndef MANTA_SIMPLEIMAGE_H
+#define MANTA_SIMPLEIMAGE_H
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "manta.h"
+#include "vectorbase.h"
+
+
+namespace Manta {
+
+
+//*****************************************************************************
+// simple 2d image class
+//template<class Scalar>
+class SimpleImage {
+ public:
+ // cons/des
+ SimpleImage() : mSize(-1), mpData(NULL), mAbortOnError(true) { };
+ virtual ~SimpleImage() {
+ if(mpData) delete [] mpData;
+ };
+
+ //! set to constant
+ void reset(Real val = 0.) {
+ const Vec3 v = Vec3(val);
+ for(int i=0; i<mSize[0]*mSize[1]; i++)
+ mpData[i] = v;
+ }
+ //! init memory & reset to zero
+ void init(int x,int y) {
+ mSize = Vec3i(x,y,0);
+ mpData = new Vec3[x*y];
+ reset();
+ };
+
+
+ inline bool checkIndex(int x,int y) {
+ if( (x<0) || (y<0) || (x>mSize[0]-1) || (y>mSize[1]-1) ) {
+ errMsg("SimpleImage::operator() Invalid access to "<<x<<","<<y<<", size="<<mSize);
+ return false;
+ }
+ return true;
+ }
+
+ // access element
+ inline Vec3& operator() (int x,int y) {
+ DEBUG_ONLY( checkIndex(x,y) );
+ return mpData[y*mSize[0]+x];
+ };
+ inline Vec3& get (int x, int y) { return (*this)(x,y); }
+ inline Vec3& getMap (int x, int y, int z, int axis) {
+ int i = x, j = y;
+ if(axis==1) j=z;
+ if(axis==0) {
+ i=y;
+ j=z;
+ }
+ return get(i,j);
+ }
+
+
+ // output as string, debug
+ std::string toString() {
+ std::ostringstream out;
+
+ for (int j=0; j<mSize[1]; j++) {
+ for (int i=0; i<mSize[0]; i++) {
+ // normal zyx order */
+ out << (*this)(i,j);
+ out <<" ";
+ }
+ //if (format)
+ out << std::endl;
+ }
+
+ return out.str();
+ }
+
+ // multiply all values by f
+ void add(Vec3 f) {
+ for (int j=0; j<mSize[1]; j++)
+ for (int i=0; i<mSize[0]; i++) {
+ get(i,j) += f;
+ }
+ }
+ // multiply all values by f
+ void multiply(Real f) {
+ for (int j=0; j<mSize[1]; j++)
+ for (int i=0; i<mSize[0]; i++) {
+ get(i,j) *= f;
+ }
+ }
+ // map 0-f to 0-1 range, clamp
+ void mapRange(Real f) {
+ for (int j=0; j<mSize[1]; j++)
+ for (int i=0; i<mSize[0]; i++) {
+ get(i,j) /= f;
+ for(int c=0; c<3; ++c)
+ get(i,j)[c] = clamp( get(i,j)[c], (Real)0.,(Real)1.);
+ }
+ }
+
+ // normalize max values
+ void normalizeMax() {
+ Real max = normSquare(get(0,0));
+ for (int j=0; j<mSize[1]; j++)
+ for (int i=0; i<mSize[0]; i++) {
+ if(normSquare(get(i,j))>max) max = normSquare(get(i,j));
+ }
+ max = sqrt(max);
+ Real invMax = 1./max;
+ for (int j=0; j<mSize[1]; j++)
+ for (int i=0; i<mSize[0]; i++) {
+ get(i,j) *= invMax;
+ }
+ };
+
+ // normalize min and max values
+ void normalizeMinMax() {
+ Real max = normSquare(get(0,0));
+ Real min = max;
+ for (int j=0; j<mSize[1]; j++)
+ for (int i=0; i<mSize[0]; i++) {
+ if(normSquare(get(i,j))>max) max = normSquare(get(i,j));
+ if(normSquare(get(i,j))<min) min = normSquare(get(i,j));
+ }
+ max = sqrt(max);
+ min = sqrt(min);
+ Real factor = 1./(max-min);
+ for (int j=0; j<mSize[1]; j++)
+ for (int i=0; i<mSize[0]; i++) {
+ get(i,j) -= min;
+ get(i,j) *= factor;
+ }
+ };
+
+ void setAbortOnError(bool set) { mAbortOnError = set; }
+
+ // ppm in/output
+
+ // write whole image
+ bool writePpm(std::string filename);
+ // write rectangle to ppm
+ bool writePpm(std::string filename, int minx, int miny, int maxx, int maxy, bool invertXY = false);
+ // read in a ppm file, and init the image accordingly
+ bool initFromPpm (std::string filename);
+
+ // check index is valid
+ bool indexIsValid(int i, int j);
+
+ //! access
+ inline Vec3i getSize() const { return mSize; }
+
+ protected:
+ //! size
+ Vec3i mSize;
+ //! data
+ Vec3* mpData;
+ // make errors fatal, or continue?
+ bool mAbortOnError;
+
+}; // SimpleImage
+
+
+}; // Manta
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/solvana.h b/intern/mantaflow/intern/manta_develop/helper/util/solvana.h
new file mode 100644
index 00000000000..2e0363d9fb7
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/solvana.h
@@ -0,0 +1,176 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Analytical solutions to some problems
+ * generated using MATLAB symbolic math ccode
+ *
+ ******************************************************************************/
+
+#ifndef _SOLVANA_H
+#define _SOLVANA_H
+
+//! solves the equation [e1 e2 e3; 1 1 1]*x = g using least squares
+inline void SolveOverconstraint34(float e1x, float e1y, float e1z,
+ float e2x, float e2y, float e2z,
+ float e3x, float e3y, float e3z,
+ float g1, float g2, float g3,
+ float& x1, float& x2, float& x3)
+{
+ float e1x2 = e1x*e1x, e1y2 = e1y*e1y, e1z2 = e1z*e1z;
+ float e2x2 = e2x*e2x, e2y2 = e2y*e2y, e2z2 = e2z*e2z;
+ float e3x2 = e3x*e3x, e3y2 = e3y*e3y, e3z2 = e3z*e3z;
+ float e1xy = e1x*e1y, e1xz = e1x*e1z, e1yz = e1y*e1z;
+ float e2xy = e2x*e2y, e2xz = e2x*e2z, e2yz = e2y*e2z;
+ float e3xy = e3x*e3y, e3xz = e3x*e3z, e3yz = e3y*e3z;
+ float e12x = e1x*e2x, e12y = e1y*e2y, e12z = e1z*e2z;
+ float e13x = e1x*e3x, e13y = e1y*e3y, e13z = e1z*e3z;
+ float e23x = e2x*e3x, e23y = e2y*e3y, e23z = e2z*e3z;
+ float t1543 = e3y2*e2x2;
+ float t1544 = e3x2*e2y2;
+ float t1545 = e3z2*e2x2;
+ float t1546 = e3x2*e2z2;
+ float t1547 = e3z2*e2y2;
+ float t1548 = e3y2*e2z2;
+ float t1549 = e2y2*e1x2;
+ float t1550 = e2x2*e1y2;
+ float t1551 = e2z2*e1x2;
+ float t1552 = e2x2*e1z2;
+ float t1553 = e2z2*e1y2;
+ float t1554 = e2y2*e1z2;
+ float t1555 = e3y2*e1x2;
+ float t1556 = e3x2*e1y2;
+ float t1557 = e3z2*e1x2;
+ float t1558 = e3x2*e1z2;
+ float t1559 = e3z2*e1y2;
+ float t1560 = e3y2*e1z2;
+ float t1561 = e3z2*e2y2*e1x2;
+ float t1562 = e3y2*e2z2*e1x2;
+ float t1563 = e3z2*e2x2*e1y2;
+ float t1564 = e3x2*e2z2*e1y2;
+ float t1565 = e3y2*e2x2*e1z2;
+ float t1566 = e3x2*e2y2*e1z2;
+ float t1567 = e1xy*e2x*e3y*2.0;
+ float t1568 = e1xy*e2y*e3x*2.0;
+ float t1569 = e1xz*e2x*e3z*2.0;
+ float t1570 = e1xz*e2z*e3x*2.0;
+ float t1571 = e1yz*e2y*e3z*2.0;
+ float t1572 = e1yz*e2z*e3y*2.0;
+ float t1573 = e1x*e2xy*e3y*2.0;
+ float t1574 = e1y*e2xy*e3x*2.0;
+ float t1575 = e1x*e2xz*e3z*2.0;
+ float t1576 = e1z*e2xz*e3x*2.0;
+ float t1577 = e1y*e2yz*e3z*2.0;
+ float t1578 = e1z*e2yz*e3y*2.0;
+ float t1579 = e1x*e2y*e3xy*2.0;
+ float t1580 = e1y*e2x*e3xy*2.0;
+ float t1581 = e1x*e2z*e3xz*2.0;
+ float t1582 = e1z*e2x*e3xz*2.0;
+ float t1583 = e1y*e2z*e3yz*2.0;
+ float t1584 = e1z*e2y*e3yz*2.0;
+ float t1585 = e1xy*e2xz*e3yz*2.0;
+ float t1586 = e1xy*e2yz*e3xz*2.0;
+ float t1587 = e1xz*e2xy*e3yz*2.0;
+ float t1588 = e1xz*e2yz*e3xy*2.0;
+ float t1589 = e1yz*e2xy*e3xz*2.0;
+ float t1590 = e1yz*e2xz*e3xy*2.0;
+ float t1596 = e12x*e3y2*2.0;
+ float t1597 = e13x*e2y2*2.0;
+ float t1598 = e23x*e1y2*2.0;
+ float t1599 = e12x*e3z2*2.0;
+ float t1600 = e13x*e2z2*2.0;
+ float t1601 = e12y*e3x2*2.0;
+ float t1602 = e13y*e2x2*2.0;
+ float t1603 = e23y*e1x2*2.0;
+ float t1604 = e23x*e1z2*2.0;
+ float t1605 = e12y*e3z2*2.0;
+ float t1606 = e13y*e2z2*2.0;
+ float t1607 = e12z*e3x2*2.0;
+ float t1608 = e13z*e2x2*2.0;
+ float t1609 = e23z*e1x2*2.0;
+ float t1610 = e23y*e1z2*2.0;
+ float t1611 = e12z*e3y2*2.0;
+ float t1612 = e13z*e2y2*2.0;
+ float t1613 = e23z*e1y2*2.0;
+ float t1614 = e1xy*e2xy*2.0;
+ float t1615 = e1xz*e2xz*2.0;
+ float t1616 = e1yz*e2yz*2.0;
+ float t1617 = e1xy*e3xy*2.0;
+ float t1618 = e1xz*e3xz*2.0;
+ float t1619 = e1yz*e3yz*2.0;
+ float t1620 = e2xy*e3xy*2.0;
+ float t1621 = e2xz*e3xz*2.0;
+ float t1622 = e2yz*e3yz*2.0;
+ float t1623 = e1xy*e2xy*e3z2*2.0;
+ float t1624 = e1xz*e2xz*e3y2*2.0;
+ float t1625 = e1yz*e2yz*e3x2*2.0;
+ float t1626 = e1xy*e3xy*e2z2*2.0;
+ float t1627 = e1xz*e3xz*e2y2*2.0;
+ float t1628 = e1yz*e3yz*e2x2*2.0;
+ float t1629 = e2xy*e3xy*e1z2*2.0;
+ float t1630 = e2xz*e3xz*e1y2*2.0;
+ float t1631 = e2yz*e3yz*e1x2*2.0;
+ float t1591 = t1550+t1551+t1560+t1543+t1552+t1561+t1570+t1544+t1553+t1562+t1571+t1580+t1545+t1554+t1563+t1572+t1581+t1590+t1546+t1555+t1564+t1573+t1582+t1547+t1556+t1565+t1574+t1583+t1548+t1557+t1566+t1575+t1584+t1549+t1558+t1567+t1576+t1585+t1559+t1568+t1577+t1586+t1569+t1578+t1587-t1596+t1579+t1588-t1597+t1589-t1598-t1599-t1600-t1601-t1610-t1602-t1611-t1620-t1603-t1612-t1621-t1630-t1604-t1613-t1622-t1631-t1605-t1614-t1623-t1606-t1615-t1624-t1607-t1616-t1625-t1608-t1617-t1626-t1609-t1618-t1627-t1619-t1628-t1629;
+ float t1592 = 1.0/t1591;
+ float t1635 = e13x*e2y2;
+ float t1636 = e13x*e2z2;
+ float t1637 = e13y*e2x2;
+ float t1638 = e13y*e2z2;
+ float t1639 = e13z*e2x2;
+ float t1640 = e13z*e2y2;
+ float t1653 = e23x*2.0;
+ float t1654 = e23y*2.0;
+ float t1655 = e23z*2.0;
+ float t1641 = e3x2+e3z2+e3y2+e2y2+t1543+e2z2+t1544+e2x2+t1545+t1546+t1547+t1548-t1620-t1621-t1622-t1653-t1654-t1655;
+ float t1642 = e12x*e3y2;
+ float t1643 = e12x*e3z2;
+ float t1644 = e12y*e3x2;
+ float t1645 = e12y*e3z2;
+ float t1646 = e12z*e3x2;
+ float t1647 = e12z*e3y2;
+ float t1656 = e1x*e2y*e3xy;
+ float t1657 = e1y*e2x*e3xy;
+ float t1658 = e1x*e2z*e3xz;
+ float t1659 = e1z*e2x*e3xz;
+ float t1660 = e1y*e2z*e3yz;
+ float t1661 = e1z*e2y*e3yz;
+ float t1648 = e3x2+e3z2+e3y2-e13x-e13y-e13z+e12x-e23y+e12y+t1642-e23z-t1660+e12z+t1643-t1661+t1644+t1645+t1646+t1647-t1656-t1657-e23x-t1658-t1659;
+ float t1679 = e1x*e2xy*e3y;
+ float t1680 = e1y*e2xy*e3x;
+ float t1681 = e1x*e2xz*e3z;
+ float t1682 = e1z*e2xz*e3x;
+ float t1683 = e1y*e2yz*e3z;
+ float t1684 = e1z*e2yz*e3y;
+ float t1652 = e2y2+e2z2+e2x2+e13x+e13y+e13z+t1640-e12x-e23y-e12y-e23z-e12z+t1635-t1680+t1636-t1681+t1637-t1682+t1638-t1683+t1639-t1684-e23x-t1679;
+ float t1662 = e23x*e1y2;
+ float t1663 = e23y*e1x2;
+ float t1664 = e23x*e1z2;
+ float t1665 = e23z*e1x2;
+ float t1666 = e23y*e1z2;
+ float t1667 = e23z*e1y2;
+ float t1670 = e1xy*e2x*e3y;
+ float t1671 = e1xy*e2y*e3x;
+ float t1672 = e1xz*e2x*e3z;
+ float t1673 = e1xz*e2z*e3x;
+ float t1674 = e1yz*e2y*e3z;
+ float t1675 = e1yz*e2z*e3y;
+ float t1668 = e1x2+e1y2+e1z2-e13x-e13y-e13z-e12x+e23y-e12y+e23z-e12z-t1670+t1662-t1671+t1663-t1672+t1664-t1673+t1665-t1674+t1666-t1675+e23x+t1667;
+ float t1676 = e13x*2.0;
+ float t1677 = e13y*2.0;
+ float t1678 = e13z*2.0;
+ float t1669 = e3x2+e3z2+e3y2+t1560+e1x2+t1555+e1y2+t1556+e1z2+t1557+t1558+t1559-t1617-t1618-t1619-t1676-t1677-t1678;
+ float t1686 = e12x*2.0;
+ float t1687 = e12y*2.0;
+ float t1688 = e12z*2.0;
+ float t1685 = t1550+t1551+e2y2+t1552+e2z2+t1553+e2x2+t1554+e1x2+e1y2+e1z2+t1549-t1614-t1615-t1616-t1686-t1687-t1688;
+ x1 =-g2*(-e1y*t1592*t1641+e2y*t1592*t1648+e3y*t1592*t1652)-g3*(-e1z*t1592*t1641+e2z*t1592*t1648+e3z*t1592*t1652)-g1*(-e1x*t1592*t1641+e2x*t1592*t1648+e3x*t1592*(e2y2+e2z2+e2x2+e13x+e13y+e13z+t1640+t1635+t1636+t1637+t1638+t1639-e12x-e12y-e12z-e23x-e23y-e23z-e1x*e2xy*e3y-e1y*e2xy*e3x-e1x*e2xz*e3z-e1z*e2xz*e3x-e1y*e2yz*e3z-e1z*e2yz*e3y));
+ x2 =-g1*(e1x*t1592*t1648-e2x*t1592*t1669+e3x*t1592*t1668)-g2*(e1y*t1592*t1648-e2y*t1592*t1669+e3y*t1592*t1668)-g3*(e1z*t1592*t1648-e2z*t1592*t1669+e3z*t1592*t1668);
+ x3 =-g1*(e1x*t1592*t1652+e2x*t1592*t1668-e3x*t1592*t1685)-g2*(e1y*t1592*t1652+e2y*t1592*t1668-e3y*t1592*t1685)-g3*(e1z*t1592*t1652+e2z*t1592*t1668-e3z*t1592*t1685);
+}
+
+#endif \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/vector4d.cpp b/intern/mantaflow/intern/manta_develop/helper/util/vector4d.cpp
new file mode 100644
index 00000000000..cd2cb8f1647
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/vector4d.cpp
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Basic vector class
+ *
+ ******************************************************************************/
+
+#include "vector4d.h"
+
+using namespace std;
+
+namespace Manta {
+
+template<> const Vector4D<int> Vector4D<int>::Zero( 0, 0, 0, 0 );
+template<> const Vector4D<float> Vector4D<float>::Zero( 0.f, 0.f, 0.f, 0.f );
+template<> const Vector4D<double> Vector4D<double>::Zero( 0., 0., 0., 0. );
+template<> const Vector4D<float> Vector4D<float>::Invalid( numeric_limits<float>::quiet_NaN(), numeric_limits<float>::quiet_NaN(), numeric_limits<float>::quiet_NaN() , numeric_limits<float>::quiet_NaN() );
+template<> const Vector4D<double> Vector4D<double>::Invalid( numeric_limits<double>::quiet_NaN(), numeric_limits<double>::quiet_NaN(), numeric_limits<double>::quiet_NaN() , numeric_limits<double>::quiet_NaN() );
+template<> bool Vector4D<float>::isValid() const { return !c_isnan(x) && !c_isnan(y) && !c_isnan(z) && !c_isnan(t); }
+template<> bool Vector4D<double>::isValid() const { return !c_isnan(x) && !c_isnan(y) && !c_isnan(z) && !c_isnan(t); }
+
+//! Specialization for readable ints
+template<> std::string Vector4D<int>::toString() const {
+ char buf[256];
+ snprintf ( buf,256,"[%d,%d,%d,%d]", ( *this ) [0], ( *this ) [1], ( *this ) [2] , ( *this ) [3] );
+ return std::string ( buf );
+}
+
+}
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/vector4d.h b/intern/mantaflow/intern/manta_develop/helper/util/vector4d.h
new file mode 100644
index 00000000000..5332c9ca428
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/vector4d.h
@@ -0,0 +1,447 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 4D vector class
+ *
+ ******************************************************************************/
+
+#ifndef _VECTOR4D_H
+#define _VECTOR4D_H
+
+#include "vectorbase.h"
+
+
+namespace Manta
+{
+
+//! Basic inlined vector class
+template<class S>
+class Vector4D
+{
+public:
+ //! Constructor
+ inline Vector4D() : x(0),y(0),z(0),t(0) {}
+
+ //! Copy-Constructor
+ inline Vector4D ( const Vector4D<S> &v ) : x(v.x), y(v.y), z(v.z),t(v.t) {}
+
+ //! Copy-Constructor
+ inline Vector4D ( const float * v) : x((S)v[0]), y((S)v[1]), z((S)v[2]), t((S)v[3]) {}
+
+ //! Copy-Constructor
+ inline Vector4D ( const double * v) : x((S)v[0]), y((S)v[1]), z((S)v[2]), t((S)v[3]) {}
+
+ //! Construct a vector from one S
+ inline Vector4D ( S v) : x(v), y(v), z(v), t(v) {}
+
+ //! Construct a vector from three Ss
+ inline Vector4D ( S vx, S vy, S vz, S vw) : x(vx), y(vy), z(vz), t(vw) {}
+
+ // Operators
+
+ //! Assignment operator
+ inline const Vector4D<S>& operator= ( const Vector4D<S>& v ) {
+ x = v.x;
+ y = v.y;
+ z = v.z;
+ t = v.t;
+ return *this;
+ }
+ //! Assignment operator
+ inline const Vector4D<S>& operator= ( S s ) {
+ x = y = z = t = s;
+ return *this;
+ }
+ //! Assign and add operator
+ inline const Vector4D<S>& operator+= ( const Vector4D<S>& v ) {
+ x += v.x;
+ y += v.y;
+ z += v.z;
+ t += v.t;
+ return *this;
+ }
+ //! Assign and add operator
+ inline const Vector4D<S>& operator+= ( S s ) {
+ x += s;
+ y += s;
+ z += s;
+ t += s;
+ return *this;
+ }
+ //! Assign and sub operator
+ inline const Vector4D<S>& operator-= ( const Vector4D<S>& v ) {
+ x -= v.x;
+ y -= v.y;
+ z -= v.z;
+ t -= v.t;
+ return *this;
+ }
+ //! Assign and sub operator
+ inline const Vector4D<S>& operator-= ( S s ) {
+ x -= s;
+ y -= s;
+ z -= s;
+ t -= s;
+ return *this;
+ }
+ //! Assign and mult operator
+ inline const Vector4D<S>& operator*= ( const Vector4D<S>& v ) {
+ x *= v.x;
+ y *= v.y;
+ z *= v.z;
+ t *= v.t;
+ return *this;
+ }
+ //! Assign and mult operator
+ inline const Vector4D<S>& operator*= ( S s ) {
+ x *= s;
+ y *= s;
+ z *= s;
+ t *= s;
+ return *this;
+ }
+ //! Assign and div operator
+ inline const Vector4D<S>& operator/= ( const Vector4D<S>& v ) {
+ x /= v.x;
+ y /= v.y;
+ z /= v.z;
+ t /= v.t;
+ return *this;
+ }
+ //! Assign and div operator
+ inline const Vector4D<S>& operator/= ( S s ) {
+ x /= s;
+ y /= s;
+ z /= s;
+ t /= s;
+ return *this;
+ }
+ //! Negation operator
+ inline Vector4D<S> operator- () const {
+ return Vector4D<S> (-x, -y, -z, -t);
+ }
+
+ //! Get smallest component
+ //inline S min() const { return ( x<y ) ? ( ( x<z ) ? x:z ) : ( ( y<z ) ? y:z ); }
+ //! Get biggest component
+ //inline S max() const { return ( x>y ) ? ( ( x>z ) ? x:z ) : ( ( y>z ) ? y:z ); }
+
+ //! Test if all components are zero
+ inline bool empty() {
+ return x==0 && y==0 && z==0 && t==0;
+ }
+
+ //! access operator
+ inline S& operator[] ( unsigned int i ) {
+ return value[i];
+ }
+ //! constant access operator
+ inline const S& operator[] ( unsigned int i ) const {
+ return value[i];
+ }
+
+ //! debug output vector to a string
+ std::string toString() const;
+
+ //! test if nans are present
+ bool isValid() const;
+
+ //! actual values
+ union {
+ S value[4];
+ struct {
+ S x;
+ S y;
+ S z;
+ S t;
+ };
+ struct {
+ S X;
+ S Y;
+ S Z;
+ S T;
+ };
+ };
+
+ // zero element
+ static const Vector4D<S> Zero, Invalid;
+
+protected:
+
+};
+
+//************************************************************************
+// Additional operators
+//************************************************************************
+
+//! Addition operator
+template<class S>
+inline Vector4D<S> operator+ ( const Vector4D<S> &v1, const Vector4D<S> &v2 ) {
+ return Vector4D<S> ( v1.x+v2.x, v1.y+v2.y, v1.z+v2.z, v1.t+v2.t );
+}
+//! Addition operator
+template<class S, class S2>
+inline Vector4D<S> operator+ ( const Vector4D<S>& v, S2 s ) {
+ return Vector4D<S> ( v.x+s, v.y+s, v.z+s, v.t+s );
+}
+//! Addition operator
+template<class S, class S2>
+inline Vector4D<S> operator+ ( S2 s, const Vector4D<S>& v ) {
+ return Vector4D<S> ( v.x+s, v.y+s, v.z+s, v.t+s );
+}
+
+//! Subtraction operator
+template<class S>
+inline Vector4D<S> operator- ( const Vector4D<S> &v1, const Vector4D<S> &v2 ) {
+ return Vector4D<S> ( v1.x-v2.x, v1.y-v2.y, v1.z-v2.z, v1.t-v2.t );
+}
+//! Subtraction operator
+template<class S, class S2>
+inline Vector4D<S> operator- ( const Vector4D<S>& v, S2 s ) {
+ return Vector4D<S> ( v.x-s, v.y-s, v.z-s, v.t-s );
+}
+//! Subtraction operator
+template<class S, class S2>
+inline Vector4D<S> operator- ( S2 s, const Vector4D<S>& v ) {
+ return Vector4D<S> ( s-v.x, s-v.y, s-v.z, s-v.t );
+}
+
+//! Multiplication operator
+template<class S>
+inline Vector4D<S> operator* ( const Vector4D<S> &v1, const Vector4D<S> &v2 ) {
+ return Vector4D<S> ( v1.x*v2.x, v1.y*v2.y, v1.z*v2.z, v1.t*v2.t );
+}
+//! Multiplication operator
+template<class S, class S2>
+inline Vector4D<S> operator* ( const Vector4D<S>& v, S2 s ) {
+ return Vector4D<S> ( v.x*s, v.y*s, v.z*s , v.t*s );
+}
+//! Multiplication operator
+template<class S, class S2>
+inline Vector4D<S> operator* ( S2 s, const Vector4D<S>& v ) {
+ return Vector4D<S> ( s*v.x, s*v.y, s*v.z, s*v.t );
+}
+
+//! Division operator
+template<class S>
+inline Vector4D<S> operator/ ( const Vector4D<S> &v1, const Vector4D<S> &v2 ) {
+ return Vector4D<S> ( v1.x/v2.x, v1.y/v2.y, v1.z/v2.z, v1.t/v2.t );
+}
+//! Division operator
+template<class S, class S2>
+inline Vector4D<S> operator/ ( const Vector4D<S>& v, S2 s ) {
+ return Vector4D<S> ( v.x/s, v.y/s, v.z/s, v.t/s );
+}
+//! Division operator
+template<class S, class S2>
+inline Vector4D<S> operator/ ( S2 s, const Vector4D<S>& v ) {
+ return Vector4D<S> ( s/v.x, s/v.y, s/v.z, s/v.t );
+}
+
+//! Comparison operator
+template<class S>
+inline bool operator== (const Vector4D<S>& s1, const Vector4D<S>& s2) {
+ return s1.x == s2.x && s1.y == s2.y && s1.z == s2.z && s1.t == s2.t;
+}
+
+//! Comparison operator
+template<class S>
+inline bool operator!= (const Vector4D<S>& s1, const Vector4D<S>& s2) {
+ return s1.x != s2.x || s1.y != s2.y || s1.z != s2.z || s1.t != s2.t;
+}
+
+//************************************************************************
+// External functions
+//************************************************************************
+
+//! Dot product
+template<class S>
+inline S dot ( const Vector4D<S> &t, const Vector4D<S> &v ) {
+ return t.x*v.x + t.y*v.y + t.z*v.z + t.t*v.t;
+}
+
+//! Cross product
+/*template<class S>
+inline Vector4D<S> cross ( const Vector4D<S> &t, const Vector4D<S> &v ) {
+ NYI Vector4D<S> cp (
+ ( ( t.y*v.z ) - ( t.z*v.y ) ),
+ ( ( t.z*v.x ) - ( t.x*v.z ) ),
+ ( ( t.x*v.y ) - ( t.y*v.x ) ) );
+ return cp;
+}*/
+
+
+//! Compute the magnitude (length) of the vector
+template<class S>
+inline S norm ( const Vector4D<S>& v ) {
+ S l = v.x*v.x + v.y*v.y + v.z*v.z + v.t*v.t;
+ return ( fabs ( l-1. ) < VECTOR_EPSILON*VECTOR_EPSILON ) ? 1. : sqrt ( l );
+}
+
+//! Compute squared magnitude
+template<class S>
+inline S normSquare ( const Vector4D<S>& v ) {
+ return v.x*v.x + v.y*v.y + v.z*v.z + v.t*v.t;
+}
+
+//! Returns a normalized vector
+template<class S>
+inline Vector4D<S> getNormalized ( const Vector4D<S>& v ) {
+ S l = v.x*v.x + v.y*v.y + v.z*v.z + v.t*v.t;
+ if ( fabs ( l-1. ) < VECTOR_EPSILON*VECTOR_EPSILON )
+ return v; /* normalized "enough"... */
+ else if ( l > VECTOR_EPSILON*VECTOR_EPSILON )
+ {
+ S fac = 1./sqrt ( l );
+ return Vector4D<S> ( v.x*fac, v.y*fac, v.z*fac , v.t*fac );
+ }
+ else
+ return Vector4D<S> ( ( S ) 0 );
+}
+
+//! Compute the norm of the vector and normalize it.
+/*! \return The value of the norm */
+template<class S>
+inline S normalize ( Vector4D<S> &v ) {
+ S norm;
+ S l = v.x*v.x + v.y*v.y + v.z*v.z + v.t*v.t;
+ if ( fabs ( l-1. ) < VECTOR_EPSILON*VECTOR_EPSILON ) {
+ norm = 1.;
+ } else if ( l > VECTOR_EPSILON*VECTOR_EPSILON ) {
+ norm = sqrt ( l );
+ v *= 1./norm;
+ } else {
+ v = Vector4D<S>::Zero;
+ norm = 0.;
+ }
+ return ( S ) norm;
+}
+
+
+//! Outputs the object in human readable form as string
+template<class S> std::string Vector4D<S>::toString() const {
+ char buf[256];
+ snprintf ( buf,256,"[%+4.6f,%+4.6f,%+4.6f,%+4.6f]", ( double ) ( *this ) [0], ( double ) ( *this ) [1], ( double ) ( *this ) [2] , ( double ) ( *this ) [3] );
+ // for debugging, optionally increase precision:
+ //snprintf ( buf,256,"[%+4.16f,%+4.16f,%+4.16f,%+4.16f]", ( double ) ( *this ) [0], ( double ) ( *this ) [1], ( double ) ( *this ) [2], ( double ) ( *this ) [3] );
+ return std::string ( buf );
+}
+
+template<> std::string Vector4D<int>::toString() const;
+
+
+//! Outputs the object in human readable form to stream
+template<class S>
+std::ostream& operator<< ( std::ostream& os, const Vector4D<S>& i ) {
+ os << i.toString();
+ return os;
+}
+
+//! Reads the contents of the object from a stream
+template<class S>
+std::istream& operator>> ( std::istream& is, Vector4D<S>& i ) {
+ char c;
+ char dummy[4];
+ is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> dummy >> i[3] >> c;
+ return is;
+}
+
+/**************************************************************************/
+// Define default vector alias
+/**************************************************************************/
+
+//! 3D vector class of type Real (typically float)
+typedef Vector4D<Real> Vec4;
+
+//! 3D vector class of type int
+typedef Vector4D<int> Vec4i;
+
+//! convert to Real Vector
+template<class T> inline Vec4 toVec4 ( T v ) {
+ return Vec4 ( v[0],v[1],v[2],v[3] );
+}
+template<class T> inline Vec4i toVec4i ( T v ) {
+ return Vec4i( v[0],v[1],v[2],v[3] );
+}
+
+
+/**************************************************************************/
+// Specializations for common math functions
+/**************************************************************************/
+
+template<> inline Vec4 clamp<Vec4>(const Vec4& a, const Vec4& b, const Vec4& c) {
+ return Vec4 ( clamp(a.x, b.x, c.x),
+ clamp(a.y, b.y, c.y),
+ clamp(a.z, b.z, c.z),
+ clamp(a.t, b.t, c.t) );
+}
+template<> inline Vec4 safeDivide<Vec4>(const Vec4 &a, const Vec4& b) {
+ return Vec4(safeDivide(a.x,b.x), safeDivide(a.y,b.y), safeDivide(a.z,b.z), safeDivide(a.t,b.t));
+}
+template<> inline Vec4 nmod<Vec4>(const Vec4& a, const Vec4& b) {
+ return Vec4(nmod(a.x,b.x),nmod(a.y,b.y),nmod(a.z,b.z) ,nmod(a.t,b.t) );
+}
+
+
+/**************************************************************************/
+// 4d interpolation (note only 4d here, 2d/3d interpolations are in interpol.h)
+/**************************************************************************/
+
+#define BUILD_INDEX_4D \
+ Real px=pos.x-0.5f, py=pos.y-0.5f, pz=pos.z-0.5f, pt=pos.t-0.5f; \
+ int xi = (int)px; \
+ int yi = (int)py; \
+ int zi = (int)pz; \
+ int ti = (int)pt; \
+ Real s1 = px-(Real)xi, s0 = 1.-s1; \
+ Real t1 = py-(Real)yi, t0 = 1.-t1; \
+ Real f1 = pz-(Real)zi, f0 = 1.-f1; \
+ Real g1 = pt-(Real)ti, g0 = 1.-g1; \
+ /* clamp to border */ \
+ if (px < 0.) { xi = 0; s0 = 1.0; s1 = 0.0; } \
+ if (py < 0.) { yi = 0; t0 = 1.0; t1 = 0.0; } \
+ if (pz < 0.) { zi = 0; f0 = 1.0; f1 = 0.0; } \
+ if (pt < 0.) { ti = 0; g0 = 1.0; g1 = 0.0; } \
+ if (xi >= size.x-1) { xi = size.x-2; s0 = 0.0; s1 = 1.0; } \
+ if (yi >= size.y-1) { yi = size.y-2; t0 = 0.0; t1 = 1.0; } \
+ if (zi >= size.z-1) { zi = size.z-2; f0 = 0.0; f1 = 1.0; } \
+ if (ti >= size.t-1) { ti = size.t-2; g0 = 0.0; g1 = 1.0; } \
+ const int sX = 1; \
+ const int sY = size.x;
+
+static inline void checkIndexInterpol4d(const Vec4i& size, int idx) {
+ if (idx<0 || idx > size.x * size.y * size.z * size.t) {
+ std::ostringstream s;
+ s << "Grid interpol4d dim " << size << " : index " << idx << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+template <class T>
+inline T interpol4d(const T* data, const Vec4i& size, const IndexInt sZ, const IndexInt sT, const Vec4& pos) {
+ BUILD_INDEX_4D
+ IndexInt idx = (IndexInt)xi + sY * (IndexInt)yi + sZ * (IndexInt)zi + sT * (IndexInt)ti;
+ DEBUG_ONLY(checkIndexInterpol4d(size,idx));
+ DEBUG_ONLY(checkIndexInterpol4d(size,idx+sX+sY+sZ+sT));
+
+ return( ((data[idx] *t0 + data[idx+sY] *t1) * s0
+ + (data[idx+sX] *t0 + data[idx+sX+sY] *t1) * s1) * f0
+ +((data[idx+sZ] *t0 + data[idx+sY+sZ] *t1) * s0
+ + (data[idx+sX+sZ]*t0 + data[idx+sX+sY+sZ]*t1) * s1) * f1 ) * g0
+ +
+ ( ((data[idx+sT] *t0 + data[idx+sT+sY] *t1) * s0
+ + (data[idx+sT+sX] *t0 + data[idx+sT+sX+sY] *t1) * s1) * f0
+ +((data[idx+sT+sZ] *t0 + data[idx+sT+sY+sZ] *t1) * s0
+ + (data[idx+sT+sX+sZ]*t0 + data[idx+sT+sX+sY+sZ]*t1) * s1) * f1 ) * g1 ;
+}
+
+}; // namespace
+
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/vectorbase.cpp b/intern/mantaflow/intern/manta_develop/helper/util/vectorbase.cpp
new file mode 100644
index 00000000000..078a64b81b3
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/vectorbase.cpp
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Basic vector class
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+
+using namespace std;
+
+namespace Manta {
+
+#if (_MSC_VER >= 1910)
+ // already defined in header
+#else
+ template<> const Vector3D<int> Vector3D<int>::Zero(0, 0, 0);
+ template<> const Vector3D<float> Vector3D<float>::Zero(0.f, 0.f, 0.f);
+ template<> const Vector3D<double> Vector3D<double>::Zero(0., 0., 0.);
+ template<> const Vector3D<float> Vector3D<float>::Invalid(numeric_limits<float>::quiet_NaN(), numeric_limits<float>::quiet_NaN(), numeric_limits<float>::quiet_NaN());
+ template<> const Vector3D<double> Vector3D<double>::Invalid(numeric_limits<double>::quiet_NaN(), numeric_limits<double>::quiet_NaN(), numeric_limits<double>::quiet_NaN());
+#endif
+
+template<> bool Vector3D<float>::isValid() const { return !c_isnan(x) && !c_isnan(y) && !c_isnan(z); }
+template<> bool Vector3D<double>::isValid() const { return !c_isnan(x) && !c_isnan(y) && !c_isnan(z); }
+
+//! Specialization for readable ints
+template<> std::string Vector3D<int>::toString() const {
+ char buf[256];
+ snprintf ( buf,256,"[%d,%d,%d]", ( *this ) [0], ( *this ) [1], ( *this ) [2] );
+ return std::string ( buf );
+}
+
+}
diff --git a/intern/mantaflow/intern/manta_develop/helper/util/vectorbase.h b/intern/mantaflow/intern/manta_develop/helper/util/vectorbase.h
new file mode 100644
index 00000000000..a10091fa3ec
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/helper/util/vectorbase.h
@@ -0,0 +1,619 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Basic vector class
+ *
+ ******************************************************************************/
+
+#ifndef _VECTORBASE_H
+#define _VECTORBASE_H
+
+// get rid of windos min/max defines
+#if defined(WIN32) || defined(_WIN32)
+# define NOMINMAX
+#endif
+
+#include <stdio.h>
+#include <string>
+#include <limits>
+#include <iostream>
+#include "general.h"
+
+// if min/max are still around...
+#if defined(WIN32) || defined(_WIN32)
+# undef min
+# undef max
+#endif
+
+// redefine usage of some windows functions
+#if defined(WIN32) || defined(_WIN32)
+# ifndef snprintf
+# define snprintf _snprintf
+# endif
+#endif
+
+// use which fp-precision? 1=float, 2=double
+#ifndef FLOATINGPOINT_PRECISION
+# define FLOATINGPOINT_PRECISION 1
+#endif
+
+// VECTOR_EPSILON is the minimal vector length
+// In order to be able to discriminate floating point values near zero, and
+// to be sure not to fail a comparison because of roundoff errors, use this
+// value as a threshold.
+#if FLOATINGPOINT_PRECISION==1
+ typedef float Real;
+# define VECTOR_EPSILON (1e-6f)
+#else
+ typedef double Real;
+# define VECTOR_EPSILON (1e-10)
+#endif
+
+#ifndef M_PI
+# define M_PI 3.1415926536
+#endif
+#ifndef M_E
+# define M_E 2.7182818284
+#endif
+
+namespace Manta
+{
+
+//! Basic inlined vector class
+template<class S>
+class Vector3D
+{
+public:
+ //! Constructor
+ inline Vector3D() : x(0),y(0),z(0) {}
+
+ //! Copy-Constructor
+ inline Vector3D ( const Vector3D<S> &v ) : x(v.x), y(v.y), z(v.z) {}
+
+ //! Copy-Constructor
+ inline Vector3D ( const int * v) : x((S)v[0]), y((S)v[1]), z((S)v[2]) {}
+
+ //! Copy-Constructor
+ inline Vector3D ( const float * v) : x((S)v[0]), y((S)v[1]), z((S)v[2]) {}
+
+ //! Copy-Constructor
+ inline Vector3D ( const double * v) : x((S)v[0]), y((S)v[1]), z((S)v[2]) {}
+
+ //! Construct a vector from one S
+ inline Vector3D ( S v) : x(v), y(v), z(v) {}
+
+ //! Construct a vector from three Ss
+ inline Vector3D ( S vx, S vy, S vz) : x(vx), y(vy), z(vz) {}
+
+ // Operators
+
+ //! Assignment operator
+ inline const Vector3D<S>& operator= ( const Vector3D<S>& v ) {
+ x = v.x;
+ y = v.y;
+ z = v.z;
+ return *this;
+ }
+ //! Assignment operator
+ inline const Vector3D<S>& operator= ( S s ) {
+ x = y = z = s;
+ return *this;
+ }
+ //! Assign and add operator
+ inline const Vector3D<S>& operator+= ( const Vector3D<S>& v ) {
+ x += v.x;
+ y += v.y;
+ z += v.z;
+ return *this;
+ }
+ //! Assign and add operator
+ inline const Vector3D<S>& operator+= ( S s ) {
+ x += s;
+ y += s;
+ z += s;
+ return *this;
+ }
+ //! Assign and sub operator
+ inline const Vector3D<S>& operator-= ( const Vector3D<S>& v ) {
+ x -= v.x;
+ y -= v.y;
+ z -= v.z;
+ return *this;
+ }
+ //! Assign and sub operator
+ inline const Vector3D<S>& operator-= ( S s ) {
+ x -= s;
+ y -= s;
+ z -= s;
+ return *this;
+ }
+ //! Assign and mult operator
+ inline const Vector3D<S>& operator*= ( const Vector3D<S>& v ) {
+ x *= v.x;
+ y *= v.y;
+ z *= v.z;
+ return *this;
+ }
+ //! Assign and mult operator
+ inline const Vector3D<S>& operator*= ( S s ) {
+ x *= s;
+ y *= s;
+ z *= s;
+ return *this;
+ }
+ //! Assign and div operator
+ inline const Vector3D<S>& operator/= ( const Vector3D<S>& v ) {
+ x /= v.x;
+ y /= v.y;
+ z /= v.z;
+ return *this;
+ }
+ //! Assign and div operator
+ inline const Vector3D<S>& operator/= ( S s ) {
+ x /= s;
+ y /= s;
+ z /= s;
+ return *this;
+ }
+ //! Negation operator
+ inline Vector3D<S> operator- () const {
+ return Vector3D<S> (-x, -y, -z);
+ }
+
+ //! Get smallest component
+ inline S min() const {
+ return ( x<y ) ? ( ( x<z ) ? x:z ) : ( ( y<z ) ? y:z );
+ }
+ //! Get biggest component
+ inline S max() const {
+ return ( x>y ) ? ( ( x>z ) ? x:z ) : ( ( y>z ) ? y:z );
+ }
+
+ //! Test if all components are zero
+ inline bool empty() {
+ return x==0 && y==0 && z==0;
+ }
+
+ //! access operator
+ inline S& operator[] ( unsigned int i ) {
+ return value[i];
+ }
+ //! constant access operator
+ inline const S& operator[] ( unsigned int i ) const {
+ return value[i];
+ }
+
+ //! debug output vector to a string
+ std::string toString() const;
+
+ //! test if nans are present
+ bool isValid() const;
+
+ //! actual values
+ union {
+ S value[3];
+ struct {
+ S x;
+ S y;
+ S z;
+ };
+ struct {
+ S X;
+ S Y;
+ S Z;
+ };
+ };
+
+ //! zero element
+ static const Vector3D<S> Zero, Invalid;
+
+ //! For compatibility with 4d vectors (discards 4th comp)
+ inline Vector3D ( S vx, S vy, S vz, S vDummy) : x(vx), y(vy), z(vz) {}
+
+protected:
+
+};
+
+//! helper to check whether float/double value is non-zero
+inline bool notZero(Real f) {
+ if( std::abs(f) > VECTOR_EPSILON ) return true;
+ return false;
+}
+
+//************************************************************************
+// Additional operators
+//************************************************************************
+
+//! Addition operator
+template<class S>
+inline Vector3D<S> operator+ ( const Vector3D<S> &v1, const Vector3D<S> &v2 ) {
+ return Vector3D<S> ( v1.x+v2.x, v1.y+v2.y, v1.z+v2.z );
+}
+//! Addition operator
+template<class S, class S2>
+inline Vector3D<S> operator+ ( const Vector3D<S>& v, S2 s ) {
+ return Vector3D<S> ( v.x+s, v.y+s, v.z+s );
+}
+//! Addition operator
+template<class S, class S2>
+inline Vector3D<S> operator+ ( S2 s, const Vector3D<S>& v ) {
+ return Vector3D<S> ( v.x+s, v.y+s, v.z+s );
+}
+
+//! Subtraction operator
+template<class S>
+inline Vector3D<S> operator- ( const Vector3D<S> &v1, const Vector3D<S> &v2 ) {
+ return Vector3D<S> ( v1.x-v2.x, v1.y-v2.y, v1.z-v2.z );
+}
+//! Subtraction operator
+template<class S, class S2>
+inline Vector3D<S> operator- ( const Vector3D<S>& v, S2 s ) {
+ return Vector3D<S> ( v.x-s, v.y-s, v.z-s );
+}
+//! Subtraction operator
+template<class S, class S2>
+inline Vector3D<S> operator- ( S2 s, const Vector3D<S>& v ) {
+ return Vector3D<S> ( s-v.x, s-v.y, s-v.z );
+}
+
+//! Multiplication operator
+template<class S>
+inline Vector3D<S> operator* ( const Vector3D<S> &v1, const Vector3D<S> &v2 ) {
+ return Vector3D<S> ( v1.x*v2.x, v1.y*v2.y, v1.z*v2.z );
+}
+//! Multiplication operator
+template<class S, class S2>
+inline Vector3D<S> operator* ( const Vector3D<S>& v, S2 s ) {
+ return Vector3D<S> ( v.x*s, v.y*s, v.z*s );
+}
+//! Multiplication operator
+template<class S, class S2>
+inline Vector3D<S> operator* ( S2 s, const Vector3D<S>& v ) {
+ return Vector3D<S> ( s*v.x, s*v.y, s*v.z );
+}
+
+//! Division operator
+template<class S>
+inline Vector3D<S> operator/ ( const Vector3D<S> &v1, const Vector3D<S> &v2 ) {
+ return Vector3D<S> ( v1.x/v2.x, v1.y/v2.y, v1.z/v2.z );
+}
+//! Division operator
+template<class S, class S2>
+inline Vector3D<S> operator/ ( const Vector3D<S>& v, S2 s ) {
+ return Vector3D<S> ( v.x/s, v.y/s, v.z/s );
+}
+//! Division operator
+template<class S, class S2>
+inline Vector3D<S> operator/ ( S2 s, const Vector3D<S>& v ) {
+ return Vector3D<S> ( s/v.x, s/v.y, s/v.z );
+}
+
+//! Comparison operator
+template<class S>
+inline bool operator== (const Vector3D<S>& s1, const Vector3D<S>& s2) {
+ return s1.x == s2.x && s1.y == s2.y && s1.z == s2.z;
+}
+
+//! Comparison operator
+template<class S>
+inline bool operator!= (const Vector3D<S>& s1, const Vector3D<S>& s2) {
+ return s1.x != s2.x || s1.y != s2.y || s1.z != s2.z;
+}
+
+//************************************************************************
+// External functions
+//************************************************************************
+
+//! Min operator
+template<class S>
+inline Vector3D<S> vmin (const Vector3D<S>& s1, const Vector3D<S>& s2) {
+ return Vector3D<S>(std::min(s1.x,s2.x), std::min(s1.y,s2.y), std::min(s1.z,s2.z));
+}
+
+//! Min operator
+template<class S, class S2>
+inline Vector3D<S> vmin (const Vector3D<S>& s1, S2 s2) {
+ return Vector3D<S>(std::min(s1.x,s2), std::min(s1.y,s2), std::min(s1.z,s2));
+}
+
+//! Min operator
+template<class S1, class S>
+inline Vector3D<S> vmin (S1 s1, const Vector3D<S>& s2) {
+ return Vector3D<S>(std::min(s1,s2.x), std::min(s1,s2.y), std::min(s1,s2.z));
+}
+
+//! Max operator
+template<class S>
+inline Vector3D<S> vmax (const Vector3D<S>& s1, const Vector3D<S>& s2) {
+ return Vector3D<S>(std::max(s1.x,s2.x), std::max(s1.y,s2.y), std::max(s1.z,s2.z));
+}
+
+//! Max operator
+template<class S, class S2>
+inline Vector3D<S> vmax (const Vector3D<S>& s1, S2 s2) {
+ return Vector3D<S>(std::max(s1.x,s2), std::max(s1.y,s2), std::max(s1.z,s2));
+}
+
+//! Max operator
+template<class S1, class S>
+inline Vector3D<S> vmax (S1 s1, const Vector3D<S>& s2) {
+ return Vector3D<S>(std::max(s1,s2.x), std::max(s1,s2.y), std::max(s1,s2.z));
+}
+
+//! Dot product
+template<class S>
+inline S dot ( const Vector3D<S> &t, const Vector3D<S> &v ) {
+ return t.x*v.x + t.y*v.y + t.z*v.z;
+}
+
+//! Cross product
+template<class S>
+inline Vector3D<S> cross ( const Vector3D<S> &t, const Vector3D<S> &v ) {
+ Vector3D<S> cp (
+ ( ( t.y*v.z ) - ( t.z*v.y ) ),
+ ( ( t.z*v.x ) - ( t.x*v.z ) ),
+ ( ( t.x*v.y ) - ( t.y*v.x ) ) );
+ return cp;
+}
+
+//! Project a vector into a plane, defined by its normal
+/*! Projects a vector into a plane normal to the given vector, which must
+ have unit length. Self is modified.
+ \param v The vector to project
+ \param n The plane normal
+ \return The projected vector */
+template<class S>
+inline const Vector3D<S>& projectNormalTo ( const Vector3D<S>& v, const Vector3D<S> &n) {
+ S sprod = dot (v, n);
+ return v - n * dot(v, n);
+}
+
+//! Compute the magnitude (length) of the vector
+//! (clamps to 0 and 1 with VECTOR_EPSILON)
+template<class S>
+inline S norm ( const Vector3D<S>& v ) {
+ S l = v.x*v.x + v.y*v.y + v.z*v.z;
+ if ( l <= VECTOR_EPSILON*VECTOR_EPSILON ) return(0.);
+ return ( fabs ( l-1. ) < VECTOR_EPSILON*VECTOR_EPSILON ) ? 1. : sqrt ( l );
+}
+
+//! Compute squared magnitude
+template<class S>
+inline S normSquare ( const Vector3D<S>& v ) {
+ return v.x*v.x + v.y*v.y + v.z*v.z;
+}
+
+//! compatibility, allow use of int, Real and Vec inputs with norm/normSquare
+inline Real norm(const Real v) { return fabs(v); }
+inline Real normSquare(const Real v) { return square(v); }
+inline Real norm(const int v) { return abs(v); }
+inline Real normSquare(const int v) { return square(v); }
+
+//! Returns a normalized vector
+template<class S>
+inline Vector3D<S> getNormalized ( const Vector3D<S>& v ) {
+ S l = v.x*v.x + v.y*v.y + v.z*v.z;
+ if ( fabs ( l-1. ) < VECTOR_EPSILON*VECTOR_EPSILON )
+ return v; /* normalized "enough"... */
+ else if ( l > VECTOR_EPSILON*VECTOR_EPSILON )
+ {
+ S fac = 1./sqrt ( l );
+ return Vector3D<S> ( v.x*fac, v.y*fac, v.z*fac );
+ }
+ else
+ return Vector3D<S> ( ( S ) 0 );
+}
+
+//! Compute the norm of the vector and normalize it.
+/*! \return The value of the norm */
+template<class S>
+inline S normalize ( Vector3D<S> &v ) {
+ S norm;
+ S l = v.x*v.x + v.y*v.y + v.z*v.z;
+ if ( fabs ( l-1. ) < VECTOR_EPSILON*VECTOR_EPSILON ) {
+ norm = 1.;
+ } else if ( l > VECTOR_EPSILON*VECTOR_EPSILON ) {
+ norm = sqrt ( l );
+ v *= 1./norm;
+ } else {
+ v = Vector3D<S>::Zero;
+ norm = 0.;
+ }
+ return ( S ) norm;
+}
+
+//! Obtain an orthogonal vector
+/*! Compute a vector that is orthonormal to the given vector.
+ * Nothing else can be assumed for the direction of the new vector.
+ * \return The orthonormal vector */
+template<class S>
+Vector3D<S> getOrthogonalVector(const Vector3D<S>& v) {
+ // Determine the component with max. absolute value
+ int maxIndex= ( fabs ( v.x ) > fabs ( v.y ) ) ? 0 : 1;
+ maxIndex= ( fabs ( v[maxIndex] ) > fabs ( v.z ) ) ? maxIndex : 2;
+
+ // Choose another axis than the one with max. component and project
+ // orthogonal to self
+ Vector3D<S> o ( 0.0 );
+ o[ ( maxIndex+1 ) %3]= 1;
+
+ Vector3D<S> c = cross(v, o);
+ normalize(c);
+ return c;
+}
+
+//! Convert vector to polar coordinates
+/*! Stable vector to angle conversion
+ *\param v vector to convert
+ \param phi unique angle [0,2PI]
+ \param theta unique angle [0,PI]
+ */
+template<class S>
+inline void vecToAngle ( const Vector3D<S>& v, S& phi, S& theta )
+{
+ if ( fabs ( v.y ) < VECTOR_EPSILON )
+ theta = M_PI/2;
+ else if ( fabs ( v.x ) < VECTOR_EPSILON && fabs ( v.z ) < VECTOR_EPSILON )
+ theta = ( v.y>=0 ) ? 0:M_PI;
+ else
+ theta = atan ( sqrt ( v.x*v.x+v.z*v.z ) /v.y );
+ if ( theta<0 ) theta+=M_PI;
+
+ if ( fabs ( v.x ) < VECTOR_EPSILON )
+ phi = M_PI/2;
+ else
+ phi = atan ( v.z/v.x );
+ if ( phi<0 ) phi+=M_PI;
+ if ( fabs ( v.z ) < VECTOR_EPSILON )
+ phi = ( v.x>=0 ) ? 0 : M_PI;
+ else if ( v.z < 0 )
+ phi += M_PI;
+}
+
+//! Compute vector reflected at a surface
+/*! Compute a vector, that is self (as an incoming vector)
+ * reflected at a surface with a distinct normal vector.
+ * Note that the normal is reversed, if the scalar product with it is positive.
+ \param t The incoming vector
+ \param n The surface normal
+ \return The new reflected vector
+ */
+template<class S>
+inline Vector3D<S> reflectVector ( const Vector3D<S>& t, const Vector3D<S>& n ) {
+ Vector3D<S> nn= ( dot ( t, n ) > 0.0 ) ? ( n*-1.0 ) : n;
+ return ( t - nn * ( 2.0 * dot ( nn, t ) ) );
+}
+
+//! Compute vector refracted at a surface
+/*! \param t The incoming vector
+ * \param n The surface normal
+ * \param nt The "inside" refraction index
+ * \param nair The "outside" refraction index
+ * \param refRefl Set to 1 on total reflection
+ * \return The refracted vector
+*/
+template<class S>
+inline Vector3D<S> refractVector ( const Vector3D<S> &t, const Vector3D<S> &normal, S nt, S nair, int &refRefl ) {
+ // from Glassner's book, section 5.2 (Heckberts method)
+ S eta = nair / nt;
+ S n = -dot ( t, normal );
+ S tt = 1.0 + eta*eta* ( n*n-1.0 );
+ if ( tt<0.0 ) {
+ // we have total reflection!
+ refRefl = 1;
+ } else {
+ // normal reflection
+ tt = eta*n - sqrt ( tt );
+ return ( t*eta + normal*tt );
+ }
+ return t;
+}
+
+//! Outputs the object in human readable form as string
+template<class S> std::string Vector3D<S>::toString() const {
+ char buf[256];
+ snprintf ( buf,256,"[%+4.6f,%+4.6f,%+4.6f]", ( double ) ( *this ) [0], ( double ) ( *this ) [1], ( double ) ( *this ) [2] );
+ // for debugging, optionally increase precision:
+ //snprintf ( buf,256,"[%+4.16f,%+4.16f,%+4.16f]", ( double ) ( *this ) [0], ( double ) ( *this ) [1], ( double ) ( *this ) [2] );
+ return std::string ( buf );
+}
+
+template<> std::string Vector3D<int>::toString() const;
+
+
+//! Outputs the object in human readable form to stream
+/*! Output format [x,y,z] */
+template<class S>
+std::ostream& operator<< ( std::ostream& os, const Vector3D<S>& i ) {
+ os << i.toString();
+ return os;
+}
+
+//! Reads the contents of the object from a stream
+/*! Input format [x,y,z] */
+template<class S>
+std::istream& operator>> ( std::istream& is, Vector3D<S>& i ) {
+ char c;
+ char dummy[3];
+ is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c;
+ return is;
+}
+
+/**************************************************************************/
+// Define default vector alias
+/**************************************************************************/
+
+//! 3D vector class of type Real (typically float)
+typedef Vector3D<Real> Vec3;
+
+//! 3D vector class of type int
+typedef Vector3D<int> Vec3i;
+
+//! convert to Real Vector
+template<class T> inline Vec3 toVec3 ( T v ) {
+ return Vec3 ( v[0],v[1],v[2] );
+}
+
+//! convert to int Vector
+template<class T> inline Vec3i toVec3i ( T v ) {
+ return Vec3i ( ( int ) v[0], ( int ) v[1], ( int ) v[2] );
+}
+
+//! convert to int Vector
+template<class T> inline Vec3i toVec3i ( T v0, T v1, T v2 ) {
+ return Vec3i ( ( int ) v0, ( int ) v1, ( int ) v2 );
+}
+
+//! round, and convert to int Vector
+template<class T> inline Vec3i toVec3iRound ( T v ) {
+ return Vec3i ( ( int ) round ( v[0] ), ( int ) round ( v[1] ), ( int ) round ( v[2] ) );
+}
+
+//! convert to int Vector if values are close enough to an int
+template<class T> inline Vec3i toVec3iChecked ( T v ) {
+ Vec3i ret;
+ for (size_t i=0; i<3; i++) {
+ Real a = v[i];
+ if (fabs(a-floor(a+0.5)) > 1e-5)
+ errMsg("argument is not an int, cannot convert");
+ ret[i] = (int) (a+0.5);
+ }
+ return ret;
+}
+
+//! convert to double Vector
+template<class T> inline Vector3D<double> toVec3d ( T v ) {
+ return Vector3D<double> ( v[0], v[1], v[2] );
+}
+
+//! convert to float Vector
+template<class T> inline Vector3D<float> toVec3f ( T v ) {
+ return Vector3D<float> ( v[0], v[1], v[2] );
+}
+
+
+/**************************************************************************/
+// Specializations for common math functions
+/**************************************************************************/
+
+template<> inline Vec3 clamp<Vec3>(const Vec3& a, const Vec3& b, const Vec3& c) {
+ return Vec3 ( clamp(a.x, b.x, c.x),
+ clamp(a.y, b.y, c.y),
+ clamp(a.z, b.z, c.z) );
+}
+template<> inline Vec3 safeDivide<Vec3>(const Vec3 &a, const Vec3& b) {
+ return Vec3(safeDivide(a.x,b.x), safeDivide(a.y,b.y), safeDivide(a.z,b.z));
+}
+template<> inline Vec3 nmod<Vec3>(const Vec3& a, const Vec3& b) {
+ return Vec3(nmod(a.x,b.x),nmod(a.y,b.y),nmod(a.z,b.z));
+}
+
+}; // namespace
+
+#endif
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h
new file mode 100644
index 00000000000..69cf5b5e4cf
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h
@@ -0,0 +1,736 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Common grid kernels
+ *
+ ******************************************************************************/
+
+#ifndef _COMMONKERNELS_H
+#define _COMMONKERNELS_H
+
+#include "general.h"
+#include "kernel.h"
+#include "grid.h"
+
+namespace Manta {
+
+//! Kernel: Invert real values, if positive and fluid
+
+
+ struct InvertCheckFluid : public KernelBase {
+ InvertCheckFluid(const FlagGrid& flags, Grid<Real>& grid) : KernelBase(&flags,0) ,flags(flags),grid(grid) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags, Grid<Real>& grid ) {
+ if (flags.isFluid(idx) && grid[idx] > 0)
+ grid[idx] = 1.0 / grid[idx];
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel InvertCheckFluid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,flags,grid); }
+ }
+ const FlagGrid& flags; Grid<Real>& grid; }
+;
+
+//! Kernel: Squared sum over grid
+
+ struct GridSumSqr : public KernelBase {
+ GridSumSqr(const Grid<Real>& grid) : KernelBase(&grid,0) ,grid(grid) ,sum(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& grid ,double& sum) {
+ sum += square((double)grid[idx]);
+} inline operator double () {
+ return sum; }
+ inline double & getRet() {
+ return sum; }
+ inline const Grid<Real>& getArg0() {
+ return grid; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel GridSumSqr ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ double sum = 0;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,grid,sum);
+#pragma omp critical
+{this->sum += sum; } }
+ }
+ const Grid<Real>& grid; double sum; }
+;
+
+//! Kernel: rotation operator \nabla x v for centered vector fields
+
+ struct CurlOp : public KernelBase {
+ CurlOp(const Grid<Vec3>& grid, Grid<Vec3>& dst) : KernelBase(&grid,1) ,grid(grid),dst(dst) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Vec3>& grid, Grid<Vec3>& dst ) {
+ Vec3 v = Vec3(0. , 0. ,
+ 0.5*((grid(i+1,j,k).y - grid(i-1,j,k).y) - (grid(i,j+1,k).x - grid(i,j-1,k).x)) );
+ if(dst.is3D()) {
+ v[0] = 0.5*((grid(i,j+1,k).z - grid(i,j-1,k).z) - (grid(i,j,k+1).y - grid(i,j,k-1).y));
+ v[1] = 0.5*((grid(i,j,k+1).x - grid(i,j,k-1).x) - (grid(i+1,j,k).z - grid(i-1,j,k).z));
+ }
+ dst(i,j,k) = v;
+} inline const Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Grid<Vec3>& getArg1() {
+ return dst; }
+ typedef Grid<Vec3> type1; void runMessage() { debMsg("Executing kernel CurlOp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,grid,dst); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,grid,dst); }
+ }
+ }
+ const Grid<Vec3>& grid; Grid<Vec3>& dst; }
+;;
+
+//! Kernel: divergence operator (from MAC grid)
+
+ struct DivergenceOpMAC : public KernelBase {
+ DivergenceOpMAC(Grid<Real>& div, const MACGrid& grid) : KernelBase(&div,1) ,div(div),grid(grid) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& div, const MACGrid& grid ) {
+ Vec3 del = Vec3(grid(i+1,j,k).x, grid(i,j+1,k).y, 0.) - grid(i,j,k);
+ if(grid.is3D()) del[2] += grid(i,j,k+1).z;
+ else del[2] = 0.;
+ div(i,j,k) = del.x + del.y + del.z;
+} inline Grid<Real>& getArg0() {
+ return div; }
+ typedef Grid<Real> type0;inline const MACGrid& getArg1() {
+ return grid; }
+ typedef MACGrid type1; void runMessage() { debMsg("Executing kernel DivergenceOpMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,div,grid); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,div,grid); }
+ }
+ }
+ Grid<Real>& div; const MACGrid& grid; }
+;
+
+//! Kernel: gradient operator for MAC grid
+ struct GradientOpMAC : public KernelBase {
+ GradientOpMAC(MACGrid& gradient, const Grid<Real>& grid) : KernelBase(&gradient,1) ,gradient(gradient),grid(grid) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& gradient, const Grid<Real>& grid ) {
+ Vec3 grad = (Vec3(grid(i,j,k)) - Vec3(grid(i-1,j,k), grid(i,j-1,k), 0. ));
+ if(grid.is3D()) grad[2] -= grid(i,j,k-1);
+ else grad[2] = 0.;
+ gradient(i,j,k) = grad;
+} inline MACGrid& getArg0() {
+ return gradient; }
+ typedef MACGrid type0;inline const Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel GradientOpMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,gradient,grid); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,gradient,grid); }
+ }
+ }
+ MACGrid& gradient; const Grid<Real>& grid; }
+;
+
+//! Kernel: centered gradient operator
+ struct GradientOp : public KernelBase {
+ GradientOp(Grid<Vec3>& gradient, const Grid<Real>& grid) : KernelBase(&gradient,1) ,gradient(gradient),grid(grid) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& gradient, const Grid<Real>& grid ) {
+ Vec3 grad = 0.5 * Vec3( grid(i+1,j,k)-grid(i-1,j,k),
+ grid(i,j+1,k)-grid(i,j-1,k), 0.);
+ if(grid.is3D()) grad[2]= 0.5*( grid(i,j,k+1)-grid(i,j,k-1) );
+ gradient(i,j,k) = grad;
+} inline Grid<Vec3>& getArg0() {
+ return gradient; }
+ typedef Grid<Vec3> type0;inline const Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel GradientOp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,gradient,grid); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,gradient,grid); }
+ }
+ }
+ Grid<Vec3>& gradient; const Grid<Real>& grid; }
+;
+
+//! Kernel: Laplace operator
+ struct LaplaceOp : public KernelBase {
+ LaplaceOp(Grid<Real>& laplace, const Grid<Real>& grid) : KernelBase(&laplace,1) ,laplace(laplace),grid(grid) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& laplace, const Grid<Real>& grid ) {
+ laplace(i, j, k) = grid(i+1, j, k) - 2.0*grid(i, j, k) + grid(i-1, j, k);
+ laplace(i, j, k) += grid(i, j+1, k) - 2.0*grid(i, j, k) + grid(i, j-1, k);
+ if(grid.is3D()) {
+ laplace(i, j, k) += grid(i, j, k+1) - 2.0*grid(i, j, k) + grid(i, j, k-1); }
+} inline Grid<Real>& getArg0() {
+ return laplace; }
+ typedef Grid<Real> type0;inline const Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel LaplaceOp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,laplace,grid); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,laplace,grid); }
+ }
+ }
+ Grid<Real>& laplace; const Grid<Real>& grid; }
+;
+
+//! Kernel: Curvature operator
+ struct CurvatureOp : public KernelBase {
+ CurvatureOp(Grid<Real>& curv, const Grid<Real>& grid, const Real h) : KernelBase(&curv,1) ,curv(curv),grid(grid),h(h) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& curv, const Grid<Real>& grid, const Real h ) {
+ const Real over_h = 1.0/h;
+ const Real x = 0.5*(grid(i+1, j, k) - grid(i-1, j, k))*over_h;
+ const Real y = 0.5*(grid(i, j+1, k) - grid(i, j-1, k))*over_h;
+ const Real xx = (grid(i+1, j, k) - 2.0*grid(i, j, k) + grid(i-1, j, k))*over_h*over_h;
+ const Real yy = (grid(i, j+1, k) - 2.0*grid(i, j, k) + grid(i, j-1, k))*over_h*over_h;
+ const Real xy = 0.25*(grid(i+1, j+1, k)+grid(i-1, j-1, k)-grid(i-1, j+1, k)-grid(i+1, j-1, k))*over_h*over_h;
+ curv(i, j, k) = x*x*yy + y*y*xx - 2.0*x*y*xy;
+ Real denom = x*x + y*y;
+ if(grid.is3D()) {
+ const Real z = 0.5*(grid(i, j, k+1) - grid(i, j, k-1))*over_h;
+ const Real zz = (grid(i, j, k+1) - 2.0*grid(i, j, k) + grid(i, j, k-1))*over_h*over_h;
+ const Real xz = 0.25*(grid(i+1, j, k+1)+grid(i-1, j, k-1)-grid(i-1, j, k+1)-grid(i+1, j, k-1))*over_h*over_h;
+ const Real yz = 0.25*(grid(i, j+1, k+1)+grid(i, j-1, k-1)-grid(i, j+1, k-1)-grid(i, j-1, k+1))*over_h*over_h;
+ curv(i, j, k) += x*x*zz + z*z*xx + y*y*zz + z*z*yy - 2.0*(x*z*xz + y*z*yz);
+ denom += z*z;
+ }
+ curv(i, j, k) /= std::pow(std::max(denom, VECTOR_EPSILON), 1.5);
+} inline Grid<Real>& getArg0() {
+ return curv; }
+ typedef Grid<Real> type0;inline const Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1;inline const Real& getArg2() {
+ return h; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel CurvatureOp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,curv,grid,h); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,curv,grid,h); }
+ }
+ }
+ Grid<Real>& curv; const Grid<Real>& grid; const Real h; }
+;
+
+//! Kernel: get component at MAC positions
+ struct GetShiftedComponent : public KernelBase {
+ GetShiftedComponent(const Grid<Vec3>& grid, Grid<Real>& comp, int dim) : KernelBase(&grid,1) ,grid(grid),comp(comp),dim(dim) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Vec3>& grid, Grid<Real>& comp, int dim ) {
+ Vec3i ishift(i,j,k);
+ ishift[dim]--;
+ comp(i,j,k) = 0.5*(grid(i,j,k)[dim] + grid(ishift)[dim]);
+} inline const Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Grid<Real>& getArg1() {
+ return comp; }
+ typedef Grid<Real> type1;inline int& getArg2() {
+ return dim; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel GetShiftedComponent ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,grid,comp,dim); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,grid,comp,dim); }
+ }
+ }
+ const Grid<Vec3>& grid; Grid<Real>& comp; int dim; }
+;;
+
+//! Kernel: get component (not shifted)
+ struct GetComponent : public KernelBase {
+ GetComponent(const Grid<Vec3>& grid, Grid<Real>& comp, int dim) : KernelBase(&grid,0) ,grid(grid),comp(comp),dim(dim) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Vec3>& grid, Grid<Real>& comp, int dim ) {
+ comp[idx] = grid[idx][dim];
+} inline const Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Grid<Real>& getArg1() {
+ return comp; }
+ typedef Grid<Real> type1;inline int& getArg2() {
+ return dim; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel GetComponent ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,grid,comp,dim); }
+ }
+ const Grid<Vec3>& grid; Grid<Real>& comp; int dim; }
+;;
+
+//! Kernel: get norm of centered grid
+ struct GridNorm : public KernelBase {
+ GridNorm(Grid<Real>& n, const Grid<Vec3>& grid) : KernelBase(&n,0) ,n(n),grid(grid) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& n, const Grid<Vec3>& grid ) {
+ n[idx] = norm(grid[idx]);
+} inline Grid<Real>& getArg0() {
+ return n; }
+ typedef Grid<Real> type0;inline const Grid<Vec3>& getArg1() {
+ return grid; }
+ typedef Grid<Vec3> type1; void runMessage() { debMsg("Executing kernel GridNorm ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,n,grid); }
+ }
+ Grid<Real>& n; const Grid<Vec3>& grid; }
+;;
+
+//! Kernel: set component (not shifted)
+ struct SetComponent : public KernelBase {
+ SetComponent(Grid<Vec3>& grid, const Grid<Real>& comp, int dim) : KernelBase(&grid,0) ,grid(grid),comp(comp),dim(dim) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Vec3>& grid, const Grid<Real>& comp, int dim ) {
+ grid[idx][dim] = comp[idx];
+} inline Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline const Grid<Real>& getArg1() {
+ return comp; }
+ typedef Grid<Real> type1;inline int& getArg2() {
+ return dim; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel SetComponent ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,grid,comp,dim); }
+ }
+ Grid<Vec3>& grid; const Grid<Real>& comp; int dim; }
+;;
+
+//! Kernel: compute centered velocity field from MAC
+ struct GetCentered : public KernelBase {
+ GetCentered(Grid<Vec3>& center, const MACGrid& vel) : KernelBase(&center,1) ,center(center),vel(vel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& center, const MACGrid& vel ) {
+ Vec3 v = 0.5 * ( vel(i,j,k) + Vec3(vel(i+1,j,k).x, vel(i,j+1,k).y, 0. ) );
+ if(vel.is3D()) v[2] += 0.5 * vel(i,j,k+1).z;
+ else v[2] = 0.;
+ center(i,j,k) = v;
+} inline Grid<Vec3>& getArg0() {
+ return center; }
+ typedef Grid<Vec3> type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1; void runMessage() { debMsg("Executing kernel GetCentered ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,center,vel); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,center,vel); }
+ }
+ }
+ Grid<Vec3>& center; const MACGrid& vel; }
+;;
+
+//! Kernel: compute MAC from centered velocity field
+ struct GetMAC : public KernelBase {
+ GetMAC(MACGrid& vel, const Grid<Vec3>& center) : KernelBase(&vel,1) ,vel(vel),center(center) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& vel, const Grid<Vec3>& center ) {
+ Vec3 v = 0.5*(center(i,j,k) + Vec3(center(i-1,j,k).x, center(i,j-1,k).y, 0. ));
+ if(vel.is3D()) v[2] += 0.5 * center(i,j,k-1).z;
+ else v[2] = 0.;
+ vel(i,j,k) = v;
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const Grid<Vec3>& getArg1() {
+ return center; }
+ typedef Grid<Vec3> type1; void runMessage() { debMsg("Executing kernel GetMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,center); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,center); }
+ }
+ }
+ MACGrid& vel; const Grid<Vec3>& center; }
+;;
+
+//! Fill in the domain boundary cells (i,j,k=0/size-1) from the neighboring cells
+ struct FillInBoundary : public KernelBase {
+ FillInBoundary(Grid<Vec3>& grid, int g) : KernelBase(&grid,0) ,grid(grid),g(g) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& grid, int g ) {
+ if (i==0) grid(i,j,k) = grid(i+1,j,k);
+ if (j==0) grid(i,j,k) = grid(i,j+1,k);
+ if (k==0) grid(i,j,k) = grid(i,j,k+1);
+ if (i==grid.getSizeX()-1) grid(i,j,k) = grid(i-1,j,k);
+ if (j==grid.getSizeY()-1) grid(i,j,k) = grid(i,j-1,k);
+ if (k==grid.getSizeZ()-1) grid(i,j,k) = grid(i,j,k-1);
+} inline Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline int& getArg1() {
+ return g; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel FillInBoundary ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,g); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,g); }
+ }
+ }
+ Grid<Vec3>& grid; int g; }
+;
+
+
+// ****************************************************************************
+
+// helper functions for converting mex data to manta grids and back (for matlab integration)
+
+// MAC grids
+
+ struct kn_conv_mex_in_to_MAC : public KernelBase {
+ kn_conv_mex_in_to_MAC(const double *p_lin_array, MACGrid *p_result) : KernelBase(p_result,0) ,p_lin_array(p_lin_array),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const double *p_lin_array, MACGrid *p_result ) {
+ int ijk = i+j*p_result->getSizeX()+k*p_result->getSizeX()*p_result->getSizeY();
+ const int n = p_result->getSizeX() * p_result->getSizeY()*p_result->getSizeZ();
+
+ p_result->get(i,j,k).x = p_lin_array[ijk];
+ p_result->get(i,j,k).y = p_lin_array[ijk+n];
+ p_result->get(i,j,k).z = p_lin_array[ijk+2*n];
+} inline const double* getArg0() {
+ return p_lin_array; }
+ typedef double type0;inline MACGrid* getArg1() {
+ return p_result; }
+ typedef MACGrid type1; void runMessage() { debMsg("Executing kernel kn_conv_mex_in_to_MAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ }
+ }
+ const double* p_lin_array; MACGrid* p_result; }
+;
+
+
+ struct kn_conv_MAC_to_mex_out : public KernelBase {
+ kn_conv_MAC_to_mex_out(const MACGrid *p_mac, double *p_result) : KernelBase(p_mac,0) ,p_mac(p_mac),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid *p_mac, double *p_result ) {
+ int ijk = i+j*p_mac->getSizeX()+k*p_mac->getSizeX()*p_mac->getSizeY();
+ const int n = p_mac->getSizeX() * p_mac->getSizeY()*p_mac->getSizeZ();
+
+ p_result[ijk] = p_mac->get(i,j,k).x;
+ p_result[ijk+n] = p_mac->get(i,j,k).y;
+ p_result[ijk+2*n] = p_mac->get(i,j,k).z;
+} inline const MACGrid* getArg0() {
+ return p_mac; }
+ typedef MACGrid type0;inline double* getArg1() {
+ return p_result; }
+ typedef double type1; void runMessage() { debMsg("Executing kernel kn_conv_MAC_to_mex_out ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_mac,p_result); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_mac,p_result); }
+ }
+ }
+ const MACGrid* p_mac; double* p_result; }
+;
+
+// Vec3 Grids
+
+ struct kn_conv_mex_in_to_Vec3 : public KernelBase {
+ kn_conv_mex_in_to_Vec3(const double *p_lin_array, Grid<Vec3> *p_result) : KernelBase(p_result,0) ,p_lin_array(p_lin_array),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const double *p_lin_array, Grid<Vec3> *p_result ) {
+ int ijk = i+j*p_result->getSizeX()+k*p_result->getSizeX()*p_result->getSizeY();
+ const int n = p_result->getSizeX() * p_result->getSizeY()*p_result->getSizeZ();
+
+ p_result->get(i,j,k).x = p_lin_array[ijk];
+ p_result->get(i,j,k).y = p_lin_array[ijk+n];
+ p_result->get(i,j,k).z = p_lin_array[ijk+2*n];
+} inline const double* getArg0() {
+ return p_lin_array; }
+ typedef double type0;inline Grid<Vec3> * getArg1() {
+ return p_result; }
+ typedef Grid<Vec3> type1; void runMessage() { debMsg("Executing kernel kn_conv_mex_in_to_Vec3 ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ }
+ }
+ const double* p_lin_array; Grid<Vec3> * p_result; }
+;
+
+
+ struct kn_conv_Vec3_to_mex_out : public KernelBase {
+ kn_conv_Vec3_to_mex_out(const Grid<Vec3> *p_Vec3, double *p_result) : KernelBase(p_Vec3,0) ,p_Vec3(p_Vec3),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Vec3> *p_Vec3, double *p_result ) {
+ int ijk = i+j*p_Vec3->getSizeX()+k*p_Vec3->getSizeX()*p_Vec3->getSizeY();
+ const int n = p_Vec3->getSizeX() * p_Vec3->getSizeY()*p_Vec3->getSizeZ();
+
+ p_result[ijk] = p_Vec3->get(i,j,k).x;
+ p_result[ijk+n] = p_Vec3->get(i,j,k).y;
+ p_result[ijk+2*n] = p_Vec3->get(i,j,k).z;
+} inline const Grid<Vec3> * getArg0() {
+ return p_Vec3; }
+ typedef Grid<Vec3> type0;inline double* getArg1() {
+ return p_result; }
+ typedef double type1; void runMessage() { debMsg("Executing kernel kn_conv_Vec3_to_mex_out ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_Vec3,p_result); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_Vec3,p_result); }
+ }
+ }
+ const Grid<Vec3> * p_Vec3; double* p_result; }
+;
+
+// Real Grids
+
+ struct kn_conv_mex_in_to_Real : public KernelBase {
+ kn_conv_mex_in_to_Real(const double *p_lin_array, Grid<Real> *p_result) : KernelBase(p_result,0) ,p_lin_array(p_lin_array),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const double *p_lin_array, Grid<Real> *p_result ) {
+ int ijk = i+j*p_result->getSizeX()+k*p_result->getSizeX()*p_result->getSizeY();
+
+ p_result->get(i,j,k) = p_lin_array[ijk];
+} inline const double* getArg0() {
+ return p_lin_array; }
+ typedef double type0;inline Grid<Real> * getArg1() {
+ return p_result; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel kn_conv_mex_in_to_Real ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ }
+ }
+ const double* p_lin_array; Grid<Real> * p_result; }
+;
+
+
+ struct kn_conv_Real_to_mex_out : public KernelBase {
+ kn_conv_Real_to_mex_out(const Grid<Real> *p_grid, double *p_result) : KernelBase(p_grid,0) ,p_grid(p_grid),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Real> *p_grid, double *p_result ) {
+ int ijk = i+j*p_grid->getSizeX()+k*p_grid->getSizeX()*p_grid->getSizeY();
+
+ p_result[ijk] = p_grid->get(i,j,k);
+} inline const Grid<Real> * getArg0() {
+ return p_grid; }
+ typedef Grid<Real> type0;inline double* getArg1() {
+ return p_result; }
+ typedef double type1; void runMessage() { debMsg("Executing kernel kn_conv_Real_to_mex_out ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_grid,p_result); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,p_grid,p_result); }
+ }
+ }
+ const Grid<Real> * p_grid; double* p_result; }
+;
+
+
+} // namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h.reg
new file mode 100644
index 00000000000..2609f03504f
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h.reg
@@ -0,0 +1 @@
+#include "commonkernels.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h.reg.cpp
new file mode 100644
index 00000000000..c0487570968
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/commonkernels.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "commonkernels.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_2()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.cpp
new file mode 100644
index 00000000000..6871f2fae44
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.cpp
@@ -0,0 +1,521 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Conjugate gradient solver, for pressure and viscosity
+ *
+ ******************************************************************************/
+
+#include "conjugategrad.h"
+#include "commonkernels.h"
+
+using namespace std;
+namespace Manta {
+
+const int CG_DEBUGLEVEL = 3;
+
+//*****************************************************************************
+// Precondition helpers
+
+//! Preconditioning a la Wavelet Turbulence (needs 4 add. grids)
+void InitPreconditionIncompCholesky(const FlagGrid& flags,
+ Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak,
+ Grid<Real>& orgA0, Grid<Real>& orgAi, Grid<Real>& orgAj, Grid<Real>& orgAk)
+{
+ // compute IC according to Golub and Van Loan
+ A0.copyFrom( orgA0 );
+ Ai.copyFrom( orgAi );
+ Aj.copyFrom( orgAj );
+ Ak.copyFrom( orgAk );
+
+ FOR_IJK(A0) {
+ if (flags.isFluid(i,j,k)) {
+ const IndexInt idx = A0.index(i,j,k);
+ A0[idx] = sqrt(A0[idx]);
+
+ // correct left and top stencil in other entries
+ // for i = k+1:n
+ // if (A(i,k) != 0)
+ // A(i,k) = A(i,k) / A(k,k)
+ Real invDiagonal = 1.0f / A0[idx];
+ Ai[idx] *= invDiagonal;
+ Aj[idx] *= invDiagonal;
+ Ak[idx] *= invDiagonal;
+
+ // correct the right and bottom stencil in other entries
+ // for j = k+1:n
+ // for i = j:n
+ // if (A(i,j) != 0)
+ // A(i,j) = A(i,j) - A(i,k) * A(j,k)
+ A0(i+1,j,k) -= square(Ai[idx]);
+ A0(i,j+1,k) -= square(Aj[idx]);
+ A0(i,j,k+1) -= square(Ak[idx]);
+ }
+ }
+
+ // invert A0 for faster computation later
+ InvertCheckFluid (flags, A0);
+};
+
+//! Preconditioning using modified IC ala Bridson (needs 1 add. grid)
+void InitPreconditionModifiedIncompCholesky2(const FlagGrid& flags,
+ Grid<Real>&Aprecond,
+ Grid<Real>&A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak)
+{
+ // compute IC according to Golub and Van Loan
+ Aprecond.clear();
+
+ FOR_IJK(flags) {
+ if (!flags.isFluid(i,j,k)) continue;
+
+ const Real tau = 0.97;
+ const Real sigma = 0.25;
+
+ // compute modified incomplete cholesky
+ Real e = 0.;
+ e = A0(i,j,k)
+ - square(Ai(i-1,j,k) * Aprecond(i-1,j,k) )
+ - square(Aj(i,j-1,k) * Aprecond(i,j-1,k) )
+ - square(Ak(i,j,k-1) * Aprecond(i,j,k-1) ) ;
+ e -= tau * (
+ Ai(i-1,j,k) * ( Aj(i-1,j,k) + Ak(i-1,j,k) )* square( Aprecond(i-1,j,k) ) +
+ Aj(i,j-1,k) * ( Ai(i,j-1,k) + Ak(i,j-1,k) )* square( Aprecond(i,j-1,k) ) +
+ Ak(i,j,k-1) * ( Ai(i,j,k-1) + Aj(i,j,k-1) )* square( Aprecond(i,j,k-1) ) +
+ 0. );
+
+ // stability cutoff
+ if(e < sigma * A0(i,j,k))
+ e = A0(i,j,k);
+
+ Aprecond(i,j,k) = 1. / sqrt( e );
+ }
+};
+
+//! Preconditioning using multigrid ala Dick et al.
+void InitPreconditionMultigrid(GridMg* MG, Grid<Real>&A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak, Real mAccuracy)
+{
+ // build multigrid hierarchy if necessary
+ if (!MG->isASet()) MG->setA(&A0, &Ai, &Aj, &Ak);
+ MG->setCoarsestLevelAccuracy(mAccuracy * 1E-4);
+ MG->setSmoothing(1,1);
+};
+
+//! Apply WT-style ICP
+void ApplyPreconditionIncompCholesky(Grid<Real>& dst, Grid<Real>& Var1, const FlagGrid& flags,
+ Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak,
+ Grid<Real>& orgA0, Grid<Real>& orgAi, Grid<Real>& orgAj, Grid<Real>& orgAk)
+{
+
+ // forward substitution
+ FOR_IJK(dst) {
+ if (!flags.isFluid(i,j,k)) continue;
+ dst(i,j,k) = A0(i,j,k) * (Var1(i,j,k)
+ - dst(i-1,j,k) * Ai(i-1,j,k)
+ - dst(i,j-1,k) * Aj(i,j-1,k)
+ - dst(i,j,k-1) * Ak(i,j,k-1));
+ }
+
+ // backward substitution
+ FOR_IJK_REVERSE(dst) {
+ const IndexInt idx = A0.index(i,j,k);
+ if (!flags.isFluid(idx)) continue;
+ dst[idx] = A0[idx] * ( dst[idx]
+ - dst(i+1,j,k) * Ai[idx]
+ - dst(i,j+1,k) * Aj[idx]
+ - dst(i,j,k+1) * Ak[idx]);
+ }
+}
+
+//! Apply Bridson-style mICP
+void ApplyPreconditionModifiedIncompCholesky2(Grid<Real>& dst, Grid<Real>& Var1, const FlagGrid& flags,
+ Grid<Real>& Aprecond,
+ Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak)
+{
+ // forward substitution
+ FOR_IJK(dst) {
+ if (!flags.isFluid(i,j,k)) continue;
+ const Real p = Aprecond(i,j,k);
+ dst(i,j,k) = p * (Var1(i,j,k)
+ - dst(i-1,j,k) * Ai(i-1,j,k) * Aprecond(i-1,j,k)
+ - dst(i,j-1,k) * Aj(i,j-1,k) * Aprecond(i,j-1,k)
+ - dst(i,j,k-1) * Ak(i,j,k-1) * Aprecond(i,j,k-1) );
+ }
+
+ // backward substitution
+ FOR_IJK_REVERSE(dst) {
+ const IndexInt idx = A0.index(i,j,k);
+ if (!flags.isFluid(idx)) continue;
+ const Real p = Aprecond[idx];
+ dst[idx] = p * ( dst[idx]
+ - dst(i+1,j,k) * Ai[idx] * p
+ - dst(i,j+1,k) * Aj[idx] * p
+ - dst(i,j,k+1) * Ak[idx] * p);
+ }
+}
+
+//! Perform one Multigrid VCycle
+void ApplyPreconditionMultigrid(GridMg* pMG, Grid<Real>& dst, Grid<Real>& Var1)
+{
+ // one VCycle on "A*dst = Var1" with initial guess dst=0
+ pMG->setRhs(Var1);
+ pMG->doVCycle(dst);
+}
+
+
+//*****************************************************************************
+// Kernels
+
+//! Kernel: Compute the dot product between two Real grids
+/*! Uses double precision internally */
+
+ struct GridDotProduct : public KernelBase {
+ GridDotProduct(const Grid<Real>& a, const Grid<Real>& b) : KernelBase(&a,0) ,a(a),b(b) ,result(0.0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& a, const Grid<Real>& b ,double& result) {
+ result += (a[idx] * b[idx]);
+} inline operator double () {
+ return result; }
+ inline double & getRet() {
+ return result; }
+ inline const Grid<Real>& getArg0() {
+ return a; }
+ typedef Grid<Real> type0;inline const Grid<Real>& getArg1() {
+ return b; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel GridDotProduct ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ double result = 0.0;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,a,b,result);
+#pragma omp critical
+{this->result += result; } }
+ }
+ const Grid<Real>& a; const Grid<Real>& b; double result; }
+;;
+
+//! Kernel: compute residual (init) and add to sigma
+
+
+ struct InitSigma : public KernelBase {
+ InitSigma(const FlagGrid& flags, Grid<Real>& dst, Grid<Real>& rhs, Grid<Real>& temp) : KernelBase(&flags,0) ,flags(flags),dst(dst),rhs(rhs),temp(temp) ,sigma(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags, Grid<Real>& dst, Grid<Real>& rhs, Grid<Real>& temp ,double& sigma) {
+ const double res = rhs[idx] - temp[idx];
+ dst[idx] = (Real)res;
+
+ // only compute residual in fluid region
+ if(flags.isFluid(idx))
+ sigma += res*res;
+} inline operator double () {
+ return sigma; }
+ inline double & getRet() {
+ return sigma; }
+ inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return dst; }
+ typedef Grid<Real> type1;inline Grid<Real>& getArg2() {
+ return rhs; }
+ typedef Grid<Real> type2;inline Grid<Real>& getArg3() {
+ return temp; }
+ typedef Grid<Real> type3; void runMessage() { debMsg("Executing kernel InitSigma ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ double sigma = 0;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,flags,dst,rhs,temp,sigma);
+#pragma omp critical
+{this->sigma += sigma; } }
+ }
+ const FlagGrid& flags; Grid<Real>& dst; Grid<Real>& rhs; Grid<Real>& temp; double sigma; }
+;;
+
+//! Kernel: update search vector
+
+ struct UpdateSearchVec : public KernelBase {
+ UpdateSearchVec(Grid<Real>& dst, Grid<Real>& src, Real factor) : KernelBase(&dst,0) ,dst(dst),src(src),factor(factor) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& dst, Grid<Real>& src, Real factor ) {
+ dst[idx] = src[idx] + factor * dst[idx];
+} inline Grid<Real>& getArg0() {
+ return dst; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return src; }
+ typedef Grid<Real> type1;inline Real& getArg2() {
+ return factor; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel UpdateSearchVec ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,dst,src,factor); }
+ }
+ Grid<Real>& dst; Grid<Real>& src; Real factor; }
+;
+
+//*****************************************************************************
+// CG class
+
+template<class APPLYMAT>
+GridCg<APPLYMAT>::GridCg(Grid<Real>& dst, Grid<Real>& rhs, Grid<Real>& residual, Grid<Real>& search, const FlagGrid& flags, Grid<Real>& tmp,
+ Grid<Real>* pA0, Grid<Real>* pAi, Grid<Real>* pAj, Grid<Real>* pAk) :
+ GridCgInterface(), mInited(false), mIterations(0), mDst(dst), mRhs(rhs), mResidual(residual),
+ mSearch(search), mFlags(flags), mTmp(tmp), mpA0(pA0), mpAi(pAi), mpAj(pAj), mpAk(pAk),
+ mPcMethod(PC_None), mpPCA0(nullptr), mpPCAi(nullptr), mpPCAj(nullptr), mpPCAk(nullptr), mMG(nullptr), mSigma(0.), mAccuracy(VECTOR_EPSILON), mResNorm(1e20)
+{ }
+
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::doInit() {
+ mInited = true;
+ mIterations = 0;
+
+ mDst.clear();
+ mResidual.copyFrom( mRhs ); // p=0, residual = b
+
+ if (mPcMethod == PC_ICP) {
+ assertMsg(mDst.is3D(), "ICP only supports 3D grids so far");
+ InitPreconditionIncompCholesky(mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
+ ApplyPreconditionIncompCholesky(mTmp, mResidual, mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
+ } else if (mPcMethod == PC_mICP) {
+ assertMsg(mDst.is3D(), "mICP only supports 3D grids so far");
+ InitPreconditionModifiedIncompCholesky2(mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
+ ApplyPreconditionModifiedIncompCholesky2(mTmp, mResidual, mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
+ } else if (mPcMethod == PC_MGP) {
+ InitPreconditionMultigrid(mMG, *mpA0, *mpAi, *mpAj, *mpAk, mAccuracy);
+ ApplyPreconditionMultigrid(mMG, mTmp, mResidual);
+ } else {
+ mTmp.copyFrom( mResidual );
+ }
+
+ mSearch.copyFrom( mTmp );
+
+ mSigma = GridDotProduct(mTmp, mResidual);
+}
+
+template<class APPLYMAT>
+bool GridCg<APPLYMAT>::iterate() {
+ if(!mInited) doInit();
+
+ mIterations++;
+
+ // create matrix application operator passed as template argument,
+ // this could reinterpret the mpA pointers (not so clean right now)
+ // tmp = applyMat(search)
+
+ APPLYMAT (mFlags, mTmp, mSearch, *mpA0, *mpAi, *mpAj, *mpAk);
+
+ // alpha = sigma/dot(tmp, search)
+ Real dp = GridDotProduct(mTmp, mSearch);
+ Real alpha = 0.;
+ if(fabs(dp)>0.) alpha = mSigma / (Real)dp;
+
+ gridScaledAdd<Real,Real>(mDst, mSearch, alpha); // dst += search * alpha
+ gridScaledAdd<Real,Real>(mResidual, mTmp, -alpha); // residual += tmp * -alpha
+
+ if (mPcMethod == PC_ICP)
+ ApplyPreconditionIncompCholesky(mTmp, mResidual, mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
+ else if (mPcMethod == PC_mICP)
+ ApplyPreconditionModifiedIncompCholesky2(mTmp, mResidual, mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
+ else if (mPcMethod == PC_MGP)
+ ApplyPreconditionMultigrid(mMG, mTmp, mResidual);
+ else
+ mTmp.copyFrom( mResidual );
+
+ // use the l2 norm of the residual for convergence check? (usually max norm is recommended instead)
+ if(this->mUseL2Norm) {
+ mResNorm = GridSumSqr(mResidual).sum;
+ } else {
+ mResNorm = mResidual.getMaxAbs();
+ }
+
+ // abort here to safe some work...
+ if(mResNorm<mAccuracy) {
+ mSigma = mResNorm; // this will be returned later on to the caller...
+ return false;
+ }
+
+ Real sigmaNew = GridDotProduct(mTmp, mResidual);
+ Real beta = sigmaNew / mSigma;
+
+ // search = tmp + beta * search
+ UpdateSearchVec (mSearch, mTmp, beta);
+
+ debMsg("GridCg::iterate i="<<mIterations<<" sigmaNew="<<sigmaNew<<" sigmaLast="<<mSigma<<" alpha="<<alpha<<" beta="<<beta<<" ", CG_DEBUGLEVEL);
+ mSigma = sigmaNew;
+
+ if(!(mResNorm<1e35)) {
+ if(mPcMethod == PC_MGP) {
+ // diverging solves can be caused by the static multigrid mode, we cannot detect this here, though
+ // only the pressure solve call "knows" whether the MG is static or dynamics...
+ debMsg("GridCg::iterate: Warning - this diverging solve can be caused by the 'static' mode of the MG preconditioner. If the static mode is active, try switching to dynamic.", 1);
+ }
+ errMsg("GridCg::iterate: The CG solver diverged, residual norm > 1e30, stopping.");
+ }
+
+ //debMsg("PB-CG-Norms::p"<<sqrt( GridOpNormNosqrt(mpDst, mpFlags).getValue() ) <<" search"<<sqrt( GridOpNormNosqrt(mpSearch, mpFlags).getValue(), CG_DEBUGLEVEL ) <<" res"<<sqrt( GridOpNormNosqrt(mpResidual, mpFlags).getValue() ) <<" tmp"<<sqrt( GridOpNormNosqrt(mpTmp, mpFlags).getValue() ), CG_DEBUGLEVEL ); // debug
+ return true;
+}
+
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::solve(int maxIter) {
+ for (int iter=0; iter<maxIter; iter++) {
+ if (!iterate()) iter=maxIter;
+ }
+ return;
+}
+
+static bool gPrint2dWarning = true;
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::setICPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) {
+ assertMsg(method==PC_ICP || method==PC_mICP, "GridCg<APPLYMAT>::setICPreconditioner: Invalid method specified.");
+
+ mPcMethod = method;
+ if( (!A0->is3D())) {
+ if(gPrint2dWarning) {
+ debMsg("ICP/mICP pre-conditioning only supported in 3D for now, disabling it.", 1);
+ gPrint2dWarning = false;
+ }
+ mPcMethod=PC_None;
+ }
+ mpPCA0 = A0;
+ mpPCAi = Ai;
+ mpPCAj = Aj;
+ mpPCAk = Ak;
+}
+
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::setMGPreconditioner(PreconditionType method, GridMg* MG) {
+ assertMsg(method==PC_MGP, "GridCg<APPLYMAT>::setMGPreconditioner: Invalid method specified.");
+
+ mPcMethod = method;
+
+ mMG = MG;
+}
+
+// explicit instantiation
+template class GridCg<ApplyMatrix>;
+template class GridCg<ApplyMatrix2D>;
+
+
+
+//*****************************************************************************
+// diffusion for real and vec grids, e.g. for viscosity
+
+
+//! do a CG solve for diffusion; note: diffusion coefficient alpha given in grid space,
+// rescale in python file for discretization independence (or physical correspondence)
+// see lidDrivenCavity.py for an example
+
+
+void cgSolveDiffusion(const FlagGrid& flags, GridBase& grid, Real alpha = 0.25, Real cgMaxIterFac = 1.0, Real cgAccuracy = 1e-4 ) {
+ // reserve temp grids
+ FluidSolver* parent = flags.getParent();
+ Grid<Real> rhs(parent);
+ Grid<Real> residual(parent), search(parent), tmp(parent);
+ Grid<Real> A0(parent), Ai(parent), Aj(parent), Ak(parent);
+
+ // setup matrix and boundaries
+ FlagGrid flagsDummy(parent);
+ flagsDummy.setConst(FlagGrid::TypeFluid);
+ MakeLaplaceMatrix (flagsDummy, A0, Ai, Aj, Ak);
+
+ FOR_IJK(flags) {
+ if(flags.isObstacle(i,j,k)) {
+ Ai(i,j,k) = Aj(i,j,k) = Ak(i,j,k) = 0.0;
+ A0(i,j,k) = 1.0;
+ } else {
+ Ai(i,j,k) *= alpha;
+ Aj(i,j,k) *= alpha;
+ Ak(i,j,k) *= alpha;
+ A0(i,j,k) *= alpha;
+ A0(i,j,k) += 1.;
+ }
+ }
+
+ GridCgInterface *gcg;
+ // note , no preconditioning for now...
+ const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
+
+ if (grid.getType() & GridBase::TypeReal) {
+ Grid<Real>& u = ((Grid<Real>&) grid);
+ rhs.copyFrom(u);
+ if (flags.is3D())
+ gcg = new GridCg<ApplyMatrix >(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+ else
+ gcg = new GridCg<ApplyMatrix2D>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+
+ gcg->setAccuracy( cgAccuracy );
+ gcg->solve(maxIter);
+
+ debMsg("FluidSolver::solveDiffusion iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma(), CG_DEBUGLEVEL);
+ }
+ else
+ if( (grid.getType() & GridBase::TypeVec3) || (grid.getType() & GridBase::TypeVec3) )
+ {
+ Grid<Vec3>& vec = ((Grid<Vec3>&) grid);
+ Grid<Real> u(parent);
+
+ // core solve is same as for a regular real grid
+ if (flags.is3D())
+ gcg = new GridCg<ApplyMatrix >(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+ else
+ gcg = new GridCg<ApplyMatrix2D>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+ gcg->setAccuracy( cgAccuracy );
+
+ // diffuse every component separately
+ for(int component = 0; component< (grid.is3D() ? 3:2); ++component) {
+ getComponent( vec, u, component );
+ gcg->forceReinit();
+
+ rhs.copyFrom(u);
+ gcg->solve(maxIter);
+ debMsg("FluidSolver::solveDiffusion vec3, iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma(), CG_DEBUGLEVEL);
+
+ setComponent( u, vec, component );
+ }
+ } else {
+ errMsg("cgSolveDiffusion: Grid Type is not supported (only Real, Vec3, MAC, or Levelset)");
+ }
+
+ delete gcg;
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "cgSolveDiffusion" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); GridBase& grid = *_args.getPtr<GridBase >("grid",1,&_lock); Real alpha = _args.getOpt<Real >("alpha",2,0.25,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",3,1.0,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",4,1e-4 ,&_lock); _retval = getPyNone(); cgSolveDiffusion(flags,grid,alpha,cgMaxIterFac,cgAccuracy); _args.check(); }
+ pbFinalizePlugin(parent,"cgSolveDiffusion", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("cgSolveDiffusion",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_cgSolveDiffusion ("","cgSolveDiffusion",_W_0);
+extern "C" {
+ void PbRegister_cgSolveDiffusion() {
+ KEEP_UNUSED(_RP_cgSolveDiffusion); }
+ }
+
+
+
+
+
+
+}; // DDF
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h
new file mode 100644
index 00000000000..b6eda119db7
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h
@@ -0,0 +1,293 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Conjugate gradient solver
+ *
+ ******************************************************************************/
+
+#ifndef _CONJUGATEGRADIENT_H
+#define _CONJUGATEGRADIENT_H
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+#include "multigrid.h"
+
+namespace Manta {
+
+static const bool CG_DEBUG = false;
+
+//! Basic CG interface
+class GridCgInterface {
+ public:
+ enum PreconditionType { PC_None=0, PC_ICP, PC_mICP, PC_MGP };
+
+ GridCgInterface() : mUseL2Norm(true) {};
+ virtual ~GridCgInterface() {};
+
+ // solving functions
+ virtual bool iterate() = 0;
+ virtual void solve(int maxIter) = 0;
+
+ // precond
+ virtual void setICPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) = 0;
+ virtual void setMGPreconditioner(PreconditionType method, GridMg* MG) = 0;
+
+ // access
+ virtual Real getSigma() const = 0;
+ virtual Real getIterations() const = 0;
+ virtual Real getResNorm() const = 0;
+ virtual void setAccuracy(Real set) = 0;
+ virtual Real getAccuracy() const = 0;
+
+ //! force reinit upon next iterate() call, can be used for doing multiple solves
+ virtual void forceReinit() = 0;
+
+ void setUseL2Norm(bool set) { mUseL2Norm = set; }
+
+ protected:
+
+ // use l2 norm of residualfor threshold? (otherwise uses max norm)
+ bool mUseL2Norm;
+};
+
+
+//! Run single iteration of the cg solver
+/*! the template argument determines the type of matrix multiplication,
+ typically a ApplyMatrix kernel, another one is needed e.g. for the
+ mesh-based wave equation solver */
+template<class APPLYMAT>
+class GridCg : public GridCgInterface {
+ public:
+ //! constructor
+ GridCg(Grid<Real>& dst, Grid<Real>& rhs, Grid<Real>& residual, Grid<Real>& search, const FlagGrid& flags, Grid<Real>& tmp,
+ Grid<Real>* A0, Grid<Real>* pAi, Grid<Real>* pAj, Grid<Real>* pAk);
+ ~GridCg() {}
+
+ void doInit();
+ bool iterate();
+ void solve(int maxIter);
+ //! init pointers, and copy values from "normal" matrix
+ void setICPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak);
+ void setMGPreconditioner(PreconditionType method, GridMg* MG);
+ void forceReinit() { mInited = false; }
+
+ // Accessors
+ Real getSigma() const { return mSigma; }
+ Real getIterations() const { return mIterations; }
+
+ Real getResNorm() const { return mResNorm; }
+
+ void setAccuracy(Real set) { mAccuracy=set; }
+ Real getAccuracy() const { return mAccuracy; }
+
+ protected:
+ bool mInited;
+ int mIterations;
+ // grids
+ Grid<Real>& mDst;
+ Grid<Real>& mRhs;
+ Grid<Real>& mResidual;
+ Grid<Real>& mSearch;
+ const FlagGrid& mFlags;
+ Grid<Real>& mTmp;
+
+ Grid<Real> *mpA0, *mpAi, *mpAj, *mpAk;
+
+ PreconditionType mPcMethod;
+ //! preconditioning grids
+ Grid<Real> *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk;
+ GridMg* mMG;
+
+ //! sigma / residual
+ Real mSigma;
+ //! accuracy of solver (max. residuum)
+ Real mAccuracy;
+ //! norm of the residual
+ Real mResNorm;
+}; // GridCg
+
+
+//! Kernel: Apply symmetric stored Matrix
+
+
+
+ struct ApplyMatrix : public KernelBase {
+ ApplyMatrix(const FlagGrid& flags, Grid<Real>& dst, const Grid<Real>& src, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak) : KernelBase(&flags,0) ,flags(flags),dst(dst),src(src),A0(A0),Ai(Ai),Aj(Aj),Ak(Ak) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags, Grid<Real>& dst, const Grid<Real>& src, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak ) {
+ if (!flags.isFluid(idx)) {
+ dst[idx] = src[idx]; return;
+ }
+
+ dst[idx] = src[idx] * A0[idx]
+ + src[idx-X] * Ai[idx-X]
+ + src[idx+X] * Ai[idx]
+ + src[idx-Y] * Aj[idx-Y]
+ + src[idx+Y] * Aj[idx]
+ + src[idx-Z] * Ak[idx-Z]
+ + src[idx+Z] * Ak[idx];
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return dst; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return src; }
+ typedef Grid<Real> type2;inline Grid<Real>& getArg3() {
+ return A0; }
+ typedef Grid<Real> type3;inline Grid<Real>& getArg4() {
+ return Ai; }
+ typedef Grid<Real> type4;inline Grid<Real>& getArg5() {
+ return Aj; }
+ typedef Grid<Real> type5;inline Grid<Real>& getArg6() {
+ return Ak; }
+ typedef Grid<Real> type6; void runMessage() { debMsg("Executing kernel ApplyMatrix ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,flags,dst,src,A0,Ai,Aj,Ak); }
+ }
+ const FlagGrid& flags; Grid<Real>& dst; const Grid<Real>& src; Grid<Real>& A0; Grid<Real>& Ai; Grid<Real>& Aj; Grid<Real>& Ak; }
+;
+
+//! Kernel: Apply symmetric stored Matrix. 2D version
+
+
+
+ struct ApplyMatrix2D : public KernelBase {
+ ApplyMatrix2D(const FlagGrid& flags, Grid<Real>& dst, const Grid<Real>& src, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak) : KernelBase(&flags,0) ,flags(flags),dst(dst),src(src),A0(A0),Ai(Ai),Aj(Aj),Ak(Ak) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags, Grid<Real>& dst, const Grid<Real>& src, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak ) {
+ unusedParameter(Ak); // only there for parameter compatibility with ApplyMatrix
+
+ if (!flags.isFluid(idx)) {
+ dst[idx] = src[idx]; return;
+ }
+
+ dst[idx] = src[idx] * A0[idx]
+ + src[idx-X] * Ai[idx-X]
+ + src[idx+X] * Ai[idx]
+ + src[idx-Y] * Aj[idx-Y]
+ + src[idx+Y] * Aj[idx];
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return dst; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return src; }
+ typedef Grid<Real> type2;inline Grid<Real>& getArg3() {
+ return A0; }
+ typedef Grid<Real> type3;inline Grid<Real>& getArg4() {
+ return Ai; }
+ typedef Grid<Real> type4;inline Grid<Real>& getArg5() {
+ return Aj; }
+ typedef Grid<Real> type5;inline Grid<Real>& getArg6() {
+ return Ak; }
+ typedef Grid<Real> type6; void runMessage() { debMsg("Executing kernel ApplyMatrix2D ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,flags,dst,src,A0,Ai,Aj,Ak); }
+ }
+ const FlagGrid& flags; Grid<Real>& dst; const Grid<Real>& src; Grid<Real>& A0; Grid<Real>& Ai; Grid<Real>& Aj; Grid<Real>& Ak; }
+;
+
+//! Kernel: Construct the matrix for the poisson equation
+
+ struct MakeLaplaceMatrix : public KernelBase {
+ MakeLaplaceMatrix(const FlagGrid& flags, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak, const MACGrid* fractions = 0) : KernelBase(&flags,1) ,flags(flags),A0(A0),Ai(Ai),Aj(Aj),Ak(Ak),fractions(fractions) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak, const MACGrid* fractions = 0 ) {
+ if (!flags.isFluid(i,j,k))
+ return;
+
+ if(!fractions) {
+ // diagonal, A0
+ if (!flags.isObstacle(i-1,j,k)) A0(i,j,k) += 1.;
+ if (!flags.isObstacle(i+1,j,k)) A0(i,j,k) += 1.;
+ if (!flags.isObstacle(i,j-1,k)) A0(i,j,k) += 1.;
+ if (!flags.isObstacle(i,j+1,k)) A0(i,j,k) += 1.;
+ if (flags.is3D() && !flags.isObstacle(i,j,k-1)) A0(i,j,k) += 1.;
+ if (flags.is3D() && !flags.isObstacle(i,j,k+1)) A0(i,j,k) += 1.;
+
+ // off-diagonal entries
+ if (flags.isFluid(i+1,j,k)) Ai(i,j,k) = -1.;
+ if (flags.isFluid(i,j+1,k)) Aj(i,j,k) = -1.;
+ if (flags.is3D() && flags.isFluid(i,j,k+1)) Ak(i,j,k) = -1.;
+ } else {
+ // diagonal
+ A0(i,j,k) += fractions->get(i ,j,k).x;
+ A0(i,j,k) += fractions->get(i+1,j,k).x;
+ A0(i,j,k) += fractions->get(i,j ,k).y;
+ A0(i,j,k) += fractions->get(i,j+1,k).y;
+ if (flags.is3D()) A0(i,j,k) += fractions->get(i,j,k ).z;
+ if (flags.is3D()) A0(i,j,k) += fractions->get(i,j,k+1).z;
+
+ // off-diagonal entries
+ if (flags.isFluid(i+1,j,k)) Ai(i,j,k) = -fractions->get(i+1,j,k).x;
+ if (flags.isFluid(i,j+1,k)) Aj(i,j,k) = -fractions->get(i,j+1,k).y;
+ if (flags.is3D() && flags.isFluid(i,j,k+1)) Ak(i,j,k) = -fractions->get(i,j,k+1).z;
+ }
+
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return A0; }
+ typedef Grid<Real> type1;inline Grid<Real>& getArg2() {
+ return Ai; }
+ typedef Grid<Real> type2;inline Grid<Real>& getArg3() {
+ return Aj; }
+ typedef Grid<Real> type3;inline Grid<Real>& getArg4() {
+ return Ak; }
+ typedef Grid<Real> type4;inline const MACGrid* getArg5() {
+ return fractions; }
+ typedef MACGrid type5; void runMessage() { debMsg("Executing kernel MakeLaplaceMatrix ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,A0,Ai,Aj,Ak,fractions); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,A0,Ai,Aj,Ak,fractions); }
+ }
+ }
+ const FlagGrid& flags; Grid<Real>& A0; Grid<Real>& Ai; Grid<Real>& Aj; Grid<Real>& Ak; const MACGrid* fractions; }
+;
+
+
+
+
+} // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h.reg
new file mode 100644
index 00000000000..90e55a88da4
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h.reg
@@ -0,0 +1 @@
+#include "conjugategrad.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h.reg.cpp
new file mode 100644
index 00000000000..1f7a40cc672
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/conjugategrad.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "conjugategrad.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_3()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.cpp
new file mode 100644
index 00000000000..cef9a155e1e
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.cpp
@@ -0,0 +1,679 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Mesh edge collapse and subdivision
+ *
+ ******************************************************************************/
+
+/******************************************************************************/
+// Copyright note:
+//
+// These functions (C) Chris Wojtan
+// Long-term goal is to unify with his split&merge codebase
+//
+/******************************************************************************/
+
+#include "edgecollapse.h"
+#include <queue>
+
+using namespace std;
+
+namespace Manta {
+
+// 8-point butterfly subdivision scheme (as described by Brochu&Bridson 2009)
+Vec3 ButterflySubdivision(Mesh& m, const Corner &ca, const Corner &cb)
+{
+ Vec3 p = m.nodes(m.corners(ca.prev).node).pos + m.nodes(m.corners(ca.next).node).pos;
+ Vec3 q = m.nodes(ca.node).pos + m.nodes(cb.node).pos;
+ Vec3 r = m.nodes(m.corners(m.corners(ca.next).opposite).node).pos
+ + m.nodes(m.corners(m.corners(ca.prev).opposite).node).pos
+ + m.nodes(m.corners(m.corners(cb.next).opposite).node).pos
+ + m.nodes(m.corners(m.corners(cb.prev).opposite).node).pos;
+ return ( 8*p + 2*q - r)/16.0;
+}
+
+// Modified Butterfly Subdivision Scheme from:
+// Interpolating Subdivision for Meshes with Arbitrary Topology
+// Denis Zorin, Peter Schroder, and Wim Sweldens
+// input the Corner that satisfies the following:
+// c.prev.node is the extraordinary vertex,
+// and c.next.node is the other vertex involved in the subdivision
+Vec3 OneSidedButterflySubdivision(Mesh& m, const int valence, const Corner &c) {
+ Vec3 out;
+ Vec3 p0 = m.nodes(m.corners(c.prev).node).pos;
+ Vec3 p1 = m.nodes(m.corners(c.next).node).pos;
+
+ if(valence==3) {
+ Vec3 p2 = m.nodes(c.node).pos;
+ Vec3 p3 = m.nodes(m.corners(m.corners(c.next).opposite).node).pos;
+ out = (5.0/12.0)*p1 - (1.0/12.0)*(p2+p3) + 0.75*p0;
+ }
+ else if(valence==4) {
+ Vec3 p2 = m.nodes(m.corners(m.corners(c.next).opposite).node).pos;
+ out = 0.375*p1 - 0.125*p2 + 0.75*p0;
+ }
+ else {
+ // rotate around extraordinary vertex,
+ // calculate subdivision weights,
+ // and interpolate vertex position
+ double rv = 1.0/(double)valence;
+ out = 0.0;
+ int current = c.prev;
+ for(int j=0; j<valence; j++) {
+ double s = (0.25 + cos(2*M_PI*j*rv) + 0.5*cos(4*M_PI*j*rv))*rv;
+ Vec3 p = m.nodes(m.corners(m.corners(current).prev).node).pos;
+
+ out += s*p;
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ }
+ out += 0.75* m.nodes(m.corners(c.prev).node).pos;
+ }
+ return out;
+}
+
+// Modified Butterfly Subdivision Scheme from:
+// Interpolating Subdivision for Meshes with Arbitrary Topology
+// Denis Zorin, Peter Schroder, and Wim Sweldens
+Vec3 ModifiedButterflySubdivision(Mesh& m, const Corner &ca, const Corner &cb, const Vec3& fallback)
+{
+ // calculate the valence of the two parent vertices
+ int start = ca.prev;
+ int current = start;
+ int valenceA = 0;
+ do {
+ valenceA++;
+ int op = m.corners(m.corners(current).next).opposite;
+ if (op < 0) return fallback;
+ current = m.corners(op).next;
+ }
+ while(current != start);
+ start = ca.next;
+ current = start;
+ int valenceB = 0;
+ do {
+ valenceB++;
+ int op = m.corners(m.corners(current).next).opposite;
+ if (op < 0) return fallback;
+ current = m.corners(op).next;
+ }
+ while(current != start);
+
+ // if both vertices have valence 6, use butterfly subdivision
+ if(valenceA==6 && valenceB==6) {
+ return ButterflySubdivision(m, ca,cb);
+ }
+ else if(valenceA==6) // use a one-sided scheme
+ {
+ return OneSidedButterflySubdivision(m, valenceB,cb);
+ }
+ else if(valenceB==6) // use a one-sided scheme
+ {
+ return OneSidedButterflySubdivision(m, valenceA,ca);
+ }
+ else // average the results from two one-sided schemes
+ {
+ return 0.5*( OneSidedButterflySubdivision(m, valenceA,ca)
+ + OneSidedButterflySubdivision(m, valenceB,cb) );
+ }
+}
+
+bool gAbort = false;
+
+// collapse an edge on triangle "trinum".
+// "which" is 0,1, or 2,
+// where which==0 is the triangle edge from p0 to p1,
+// which==1 is the triangle edge from p1 to p2,
+// and which==2 is the triangle edge from p2 to p0,
+void CollapseEdge(Mesh& m, const int trinum, const int which, const Vec3 &edgevect, const Vec3 &endpoint,
+ vector<int> &deletedNodes, std::map<int,bool> &taintedTris, int &numCollapses, bool doTubeCutting)
+{
+ if (gAbort) return;
+ // I wanted to draw a pretty picture of an edge collapse,
+ // but I don't know how to make wacky angled lines in ASCII.
+ // Instead, I will show the before case and tell you what needs to be done.
+
+ // BEFORE:
+ // *
+ // / \.
+ // /C0 \.
+ // / \.
+ // / \.
+ // / B \.
+ // / \.
+ // /C1 C2 \.
+ // P0 *---------------* P1
+ // \C2 C1 /
+ // \ /
+ // \ A /
+ // \ /
+ // \ /
+ // \C0 /
+ // \ /
+ // *
+ //
+ // We are going to collapse the edge between P0 and P1
+ // by deleting P1,
+ // and taking all references to P1,
+ // and rerouting them to P0 instead
+ //
+ // What we need to do:
+ // Move position of P0
+ // Preserve connectivity in both triangles:
+ // (C1.opposite).opposite = C2.o
+ // (C2.opposite).opposite = C1.o
+ // Delete references to Corners of deleted triangles in both P0 and P1's Corner list
+ // Reassign references to P1:
+ // loop through P1 triangles:
+ // rename P1 references to P0 in p lists.
+ // rename Corner.v references
+ // Copy P1's list of Corners over to P0's list of Corners
+ // Delete P1
+
+ Corner ca_old[3], cb_old[3];
+ ca_old[0] = m.corners(trinum, which);
+ ca_old[1] = m.corners(ca_old[0].next);
+ ca_old[2] = m.corners(ca_old[0].prev);
+ bool haveB = false;
+ if (ca_old[0].opposite>=0) {
+ cb_old[0] = m.corners(ca_old[0].opposite);
+ cb_old[1] = m.corners(cb_old[0].next);
+ cb_old[2] = m.corners(cb_old[0].prev);
+ haveB = true;
+ }
+ if (!haveB) {
+ // for now, don't collapse
+ return;
+ }
+
+ int P0 = ca_old[2].node;
+ int P1 = ca_old[1].node;
+
+ ///////////////
+ // avoid creating nonmanifold edges
+ bool nonmanifold = false;
+ bool nonmanifold2 = false;
+
+ set<int>& ring0 = m.get1Ring(P0).nodes;
+ set<int>& ring1 = m.get1Ring(P1).nodes;
+
+ // check for intersections of the 1-rings of P0,P1
+ int cl=0, commonVert=-1;
+ for(set<int>::iterator it=ring1.begin(); it != ring1.end(); ++it)
+ if (ring0.find(*it) != ring0.end()) {
+ cl++;
+ if (*it != ca_old[0].node && *it != cb_old[0].node) commonVert = *it;
+ }
+
+ nonmanifold = cl>2;
+ nonmanifold2 = cl>3;
+
+ if(nonmanifold &&
+ ca_old[1].opposite>=0 && cb_old[1].opposite>=0 &&
+ ca_old[2].opposite>=0 && cb_old[2].opposite>=0 ) // collapsing this edge would create a non-manifold edge
+ {
+ if(nonmanifold2)
+ return;
+
+ bool topTet = false;
+ bool botTet = false;
+ // check if collapsing this edge will collapse a tet.
+ if(m.corners(ca_old[1].opposite).node == m.corners(ca_old[2].opposite).node)
+ botTet = true;
+
+ if(m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node)
+ topTet = true;
+
+ if(topTet^botTet) {
+
+ // safe pyramid case.
+ // collapse the whole tet!
+ // First collapse the top of the pyramid,
+ // then carry on collapsing the original verts.
+ Corner cc_old[3],cd_old[3];
+ if(botTet)
+ cc_old[0] = m.corners(ca_old[1].opposite);
+ else // topTet
+ cc_old[0] = cb_old[2];
+ cc_old[1] = m.corners(cc_old[0].next);
+ cc_old[2] = m.corners(cc_old[0].prev);
+ if (cc_old[0].opposite<0) return;
+ cd_old[0] = m.corners(cc_old[0].opposite);
+ cd_old[1] = m.corners(cd_old[0].next);
+ cd_old[2] = m.corners(cd_old[0].prev);
+ int P2 = cc_old[2].node;
+ int P3 = cc_old[1].node;
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ for (int i=0; i<m.numTriChannels(); i++)
+ {};//TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]);
+
+ m.mergeNode(P2, P3);
+
+ // Preserve connectivity in both triangles
+ if (cc_old[1].opposite>=0)
+ m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite;
+ if (cc_old[2].opposite>=0)
+ m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite;
+ if (cd_old[1].opposite>=0)
+ m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite;
+ if (cd_old[2].opposite>=0)
+ m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ int tmpTrinum = cc_old[0].tri;
+ int tmpOthertri = cd_old[0].tri;
+ m.removeTriFromLookup(tmpTrinum);
+ m.removeTriFromLookup(tmpOthertri);
+ taintedTris[tmpTrinum] = true;
+ taintedTris[tmpOthertri] = true;
+ deletedNodes.push_back(P3);
+
+ numCollapses++;
+
+ // recompute Corners for triangles A and B
+ if(botTet)
+ ca_old[0] = m.corners(ca_old[2].opposite);
+ else
+ ca_old[0] = m.corners(ca_old[1].prev);
+ ca_old[1] = m.corners(ca_old[0].next);
+ ca_old[2] = m.corners(ca_old[0].prev);
+ cb_old[0] = m.corners(ca_old[0].opposite);
+ cb_old[1] = m.corners(cb_old[0].next);
+ cb_old[2] = m.corners(cb_old[0].prev);
+
+ ///////////////
+ // avoid creating nonmanifold edges... again
+ ring0 = m.get1Ring(ca_old[2].node).nodes;
+ ring1 = m.get1Ring(ca_old[1].node).nodes;
+
+ // check for intersections of the 1-rings of P0,P1
+ cl=0;
+ for(set<int>::iterator it=ring1.begin(); it != ring1.end(); ++it)
+ if (*it != ca_old[0].node && ring0.find(*it) != ring0.end())
+ cl++;
+
+ if(cl>2) { // nonmanifold
+ // this can happen if collapsing the first tet leads to another similar collapse that requires the collapse of a tet.
+ // for now, just move on and pick this up later.
+
+ // if the original component was very small, this first collapse could have led to a tiny piece of nonmanifold geometry.
+ // in this case, just delete everything that remains.
+ if(m.corners(ca_old[0].opposite).tri==cb_old[0].tri && m.corners(ca_old[1].opposite).tri==cb_old[0].tri && m.corners(ca_old[2].opposite).tri==cb_old[0].tri) {
+ taintedTris[ca_old[0].tri] = true;
+ taintedTris[cb_old[0].tri] = true;
+ m.removeTriFromLookup(ca_old[0].tri);
+ m.removeTriFromLookup(cb_old[0].tri);
+ deletedNodes.push_back(ca_old[0].node);
+ deletedNodes.push_back(ca_old[1].node);
+ deletedNodes.push_back(ca_old[2].node);
+ }
+ return;
+ }
+ } else if(topTet && botTet && ca_old[1].opposite>=0 && ca_old[2].opposite>=0 && cb_old[1].opposite>=0 && cb_old[2].opposite>=0)
+ {
+ if(!(m.corners(ca_old[1].opposite).node == m.corners(ca_old[2].opposite).node &&
+ m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node &&
+ (m.corners(ca_old[1].opposite).node == m.corners(cb_old[1].opposite).node ||
+ (m.corners(ca_old[1].opposite).node == cb_old[0].node &&
+ m.corners(cb_old[1].opposite).node == ca_old[0].node) )))
+ {
+ // just collapse one for now.
+
+ // collapse the whole tet!
+ // First collapse the top of the pyramid,
+ // then carry on collapsing the original verts.
+ Corner cc_old[3],cd_old[3];
+
+ // collapse top
+ {
+ cc_old[0] = m.corners(ca_old[1].opposite);
+ cc_old[1] = m.corners(cc_old[0].next);
+ cc_old[2] = m.corners(cc_old[0].prev);
+ if (cc_old[0].opposite<0) return;
+ cd_old[0] = m.corners(cc_old[0].opposite);
+ cd_old[1] = m.corners(cd_old[0].next);
+ cd_old[2] = m.corners(cd_old[0].prev);
+ int P2 = cc_old[2].node;
+ int P3 = cc_old[1].node;
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ // TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]);
+
+ m.mergeNode(P2, P3);
+
+ // Preserve connectivity in both triangles
+ if (cc_old[1].opposite>=0)
+ m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite;
+ if (cc_old[2].opposite>=0)
+ m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite;
+ if (cd_old[1].opposite>=0)
+ m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite;
+ if (cd_old[2].opposite>=0)
+ m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ int tmpTrinum = cc_old[0].tri;
+ int tmpOthertri = cd_old[0].tri;
+ taintedTris[tmpTrinum] = true;
+ taintedTris[tmpOthertri] = true;
+ m.removeTriFromLookup(tmpTrinum);
+ m.removeTriFromLookup(tmpOthertri);
+ deletedNodes.push_back(P3);
+
+ numCollapses++;
+ }
+ // then collapse bottom
+ {
+ //cc_old[0] = [ca_old[1].opposite;
+ cc_old[0] = cb_old[2];
+ cc_old[1] = m.corners(cc_old[0].next);
+ cc_old[2] = m.corners(cc_old[0].prev);
+ if (cc_old[0].opposite<0) return;
+ cd_old[0] = m.corners(cc_old[0].opposite);
+ cd_old[1] = m.corners(cd_old[0].next);
+ cd_old[2] = m.corners(cd_old[0].prev);
+ int P2 = cc_old[2].node;
+ int P3 = cc_old[1].node;
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ // TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]);
+
+ m.mergeNode(P2, P3);
+
+ // Preserve connectivity in both triangles
+ if (cc_old[1].opposite>=0)
+ m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite;
+ if (cc_old[2].opposite>=0)
+ m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite;
+ if (cd_old[1].opposite>=0)
+ m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite;
+ if (cd_old[2].opposite>=0)
+ m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ int tmpTrinum = cc_old[0].tri;
+ int tmpOthertri = cd_old[0].tri;
+ taintedTris[tmpTrinum] = true;
+ taintedTris[tmpOthertri] = true;
+ deletedNodes.push_back(P3);
+
+ numCollapses++;
+ }
+
+ // Though we've collapsed a lot of stuff, we still haven't collapsed the original edge.
+ // At this point we still haven't guaranteed that this original collapse weill be safe.
+ // quit for now, and we'll catch the remaining short edges the next time this function is called.
+ return;
+ }
+ }
+ else if (doTubeCutting)
+ {
+ // tube case
+ //cout<<"CollapseEdge:tube case" << endl;
+
+ // find the edges that touch the common vert
+ int P2 = commonVert;
+ int P1P2=-1, P2P1, P2P0=-1, P0P2=-1; // corners across from the cutting seam
+ int start = ca_old[0].next;
+ int end = cb_old[0].prev;
+ int current = start;
+ do {
+ // rotate around vertex P1 counter-clockwise
+ int op = m.corners(m.corners(current).next).opposite;
+ if (op < 0) errMsg("tube cutting failed, no opposite");
+ current = m.corners(op).next;
+
+ if(m.corners(m.corners(current).prev).node==commonVert)
+ P1P2 = m.corners(current).next;
+ }
+ while(current != end);
+
+ start = ca_old[0].prev;
+ end = cb_old[0].next;
+ current = start;
+ do {
+ // rotate around vertex P0 clockwise
+ int op = m.corners(m.corners(current).prev).opposite;
+ if (op < 0) errMsg("tube cutting failed, no opposite");
+
+ current = m.corners(op).prev;
+ if(m.corners(m.corners(current).next).node==commonVert)
+ P2P0 = m.corners(current).prev;
+ } while(current != end);
+
+ if (P1P2 < 0 || P2P0 < 0)
+ errMsg("tube cutting failed, ill geometry");
+
+ P2P1 = m.corners(P1P2).opposite;
+ P0P2 = m.corners(P2P0).opposite;
+
+ // duplicate vertices on the top half of the cut,
+ // and use them to split the tube at this seam
+ int P0b = m.addNode(Node(m.nodes(P0).pos));
+ int P1b = m.addNode(Node(m.nodes(P1).pos));
+ int P2b = m.addNode(Node(m.nodes(P2).pos));
+ for (int i=0; i<m.numNodeChannels(); i++) {
+ m.nodeChannel(i)->addInterpol(P0, P0, 0.5);
+ m.nodeChannel(i)->addInterpol(P1, P1, 0.5);
+ m.nodeChannel(i)->addInterpol(P2, P2, 0.5);
+ }
+
+ // offset the verts in the normal directions to avoid self intersections
+ Vec3 offsetVec = cross(m.nodes(P1).pos-m.nodes(P0).pos, m.nodes(P2).pos-m.nodes(P0).pos);
+ normalize(offsetVec);
+ offsetVec *= 0.01; // HACK:
+ m.nodes(P0).pos -= offsetVec;
+ m.nodes(P1).pos -= offsetVec;
+ m.nodes(P2).pos -= offsetVec;
+ m.nodes(P0b).pos += offsetVec;
+ m.nodes(P1b).pos += offsetVec;
+ m.nodes(P2b).pos += offsetVec;
+
+ // create a list of all triangles which touch P0, P1, and P2 from the top,
+ map<int,bool> topTris;
+ start = cb_old[0].next;
+ end = m.corners(P0P2).prev;
+ current = start;
+ topTris[start/3]=true;
+ do {
+ // rotate around vertex P0 counter-clockwise
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ topTris[current/3]=true;
+ } while(current != end);
+ start = m.corners(P0P2).next;
+ end = m.corners(P2P1).prev;
+ current = start;
+ topTris[start/3]=true;
+ do {
+ // rotate around vertex P0 counter-clockwise
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ topTris[current/3]=true;
+ } while(current != end);
+ start = m.corners(P2P1).next;
+ end = cb_old[0].prev;
+ current = start;
+ topTris[start/3]=true;
+ do {
+ // rotate around vertex P0 counter-clockwise
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ topTris[current/3]=true;
+ } while(current != end);
+
+ // create two new triangles,
+ int Ta = m.addTri(Triangle(P0,P1,P2));
+ int Tb = m.addTri(Triangle(P1b,P0b,P2b));
+ for (int i=0; i<m.numTriChannels(); i++) {
+ m.triChannel(i)->addNew();
+ m.triChannel(i)->addNew();
+ }
+
+ // sew the tris to close the cut on each side
+ for(int c=0; c<3; c++) m.addCorner(Corner(Ta, m.tris(Ta).c[c]));
+ for(int c=0; c<3; c++) m.addCorner(Corner(Tb, m.tris(Tb).c[c]));
+ for(int c=0; c<3; c++) {
+ m.corners(Ta,c).next = 3*Ta+((c+1)%3);
+ m.corners(Ta,c).prev = 3*Ta+((c+2)%3);
+ m.corners(Tb,c).next = 3*Tb+((c+1)%3);
+ m.corners(Tb,c).prev = 3*Tb+((c+2)%3);
+ }
+ m.corners(Ta,0).opposite = P1P2;
+ m.corners(Ta,1).opposite = P2P0;
+ m.corners(Ta,2).opposite = ca_old[1].prev;
+ m.corners(Tb,0).opposite = P0P2;
+ m.corners(Tb,1).opposite = P2P1;
+ m.corners(Tb,2).opposite = cb_old[1].prev;
+ for (int c=0; c<3; c++) {
+ m.corners(m.corners(Ta,c).opposite).opposite = 3*Ta+c;
+ m.corners(m.corners(Tb,c).opposite).opposite = 3*Tb+c;
+ }
+ // replace P0,P1,P2 on the top with P0b,P1b,P2b.
+ for(map<int,bool>::iterator tti=topTris.begin(); tti!=topTris.end(); tti++) {
+ //cout << "H " << tti->first << " : " << m.tris(tti->first).c[0] << " " << m.tris(tti->first).c[1] << " " << m.tris(tti->first).c[2] << " " << endl;
+ for(int i=0; i<3; i++) {
+ int cn = m.tris(tti->first).c[i];
+ set<int>& ring = m.get1Ring(cn).nodes;
+
+ if (ring.find(P0) != ring.end() && cn!=P0 && cn!=P1 && cn!=P2 && cn!=P0b && cn!=P1b && cn!=P2b) {
+ ring.erase(P0);
+ ring.insert(P0b);
+ m.get1Ring(P0).nodes.erase(cn);
+ m.get1Ring(P0b).nodes.insert(cn);
+ }
+ if (ring.find(P1) != ring.end() && cn!=P0 && cn!=P1 && cn!=P2 && cn!=P0b && cn!=P1b && cn!=P2b) {
+ ring.erase(P1);
+ ring.insert(P1b);
+ m.get1Ring(P1).nodes.erase(cn);
+ m.get1Ring(P1b).nodes.insert(cn);
+ }
+ if (ring.find(P2) != ring.end() && cn!=P0 && cn!=P1 && cn!=P2 && cn!=P0b && cn!=P1b && cn!=P2b) {
+ ring.erase(P2);
+ ring.insert(P2b);
+ m.get1Ring(P2).nodes.erase(cn);
+ m.get1Ring(P2b).nodes.insert(cn);
+ }
+ if(cn==P0) {
+ m.tris(tti->first).c[i]=P0b;
+ m.corners(tti->first,i).node = P0b;
+ m.get1Ring(P0).tris.erase(tti->first);
+ m.get1Ring(P0b).tris.insert(tti->first);
+ }
+ else if(cn==P1) {
+ m.tris(tti->first).c[i]=P1b;
+ m.corners(tti->first,i).node = P1b;
+ m.get1Ring(P1).tris.erase(tti->first);
+ m.get1Ring(P1b).tris.insert(tti->first);
+ }
+ else if(cn==P2) {
+ m.tris(tti->first).c[i]=P2b;
+ m.corners(tti->first,i).node = P2b;
+ m.get1Ring(P2).tris.erase(tti->first);
+ m.get1Ring(P2b).tris.insert(tti->first);
+ }
+ }
+ }
+
+ //m.sanityCheck(true, &deletedNodes, &taintedTris);
+
+ return;
+ }
+ return;
+ }
+ if(ca_old[1].opposite>=0 && ca_old[2].opposite>=0 && cb_old[1].opposite>=0 && cb_old[2].opposite>=0 && ca_old[0].opposite>=0 && cb_old[0].opposite>=0 &&
+ ((m.corners(ca_old[1].opposite).node == m.corners(ca_old[2].opposite).node && // two-pyramid tubey case (6 tris, 5 verts)
+ m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node &&
+ (m.corners(ca_old[1].opposite).node == m.corners(cb_old[1].opposite).node ||
+ (m.corners(ca_old[1].opposite).node==cb_old[0].node && // single tetrahedron case
+ m.corners(cb_old[1].opposite).node==ca_old[0].node) ))
+ ||
+ (m.corners(ca_old[0].opposite).tri==m.corners(cb_old[0].opposite).tri && m.corners(ca_old[1].opposite).tri==m.corners(cb_old[0].opposite).tri && m.corners(ca_old[2].opposite).tri==m.corners(cb_old[0].opposite).tri // nonmanifold: 2 tris, 3 verts
+ && m.corners(cb_old[0].opposite).tri==m.corners(ca_old[0].opposite).tri && m.corners(cb_old[1].opposite).tri==m.corners(ca_old[0].opposite).tri && m.corners(cb_old[2].opposite).tri==m.corners(ca_old[0].opposite).tri)
+ ))
+ {
+ // both top and bottom are closed pyramid caps, or it is a single tet
+ // delete the whole component!
+ // flood fill to mark all triangles in the component
+ map<int,bool> markedTris;
+ queue<int> triQ;
+ triQ.push(trinum);
+ markedTris[trinum] = true;
+ int iters = 0;
+ while(!triQ.empty()) {
+ int trival = triQ.front();
+ triQ.pop();
+ for(int i=0; i<3; i++) {
+ int newtri = m.corners(m.corners(trival,i).opposite).tri;
+ if(markedTris.find(newtri)==markedTris.end()) {
+ triQ.push(newtri);
+ markedTris[newtri] = true;
+ }
+ }
+ iters++;
+ }
+ map<int,bool> markedverts;
+ for(map<int,bool>::iterator mit=markedTris.begin(); mit!=markedTris.end(); mit++) {
+ taintedTris[mit->first] = true;
+ markedverts[m.tris(mit->first).c[0]] = true;
+ markedverts[m.tris(mit->first).c[1]] = true;
+ markedverts[m.tris(mit->first).c[2]] = true;
+ }
+ for(map<int,bool>::iterator mit=markedverts.begin(); mit!=markedverts.end(); mit++)
+ deletedNodes.push_back(mit->first);
+ return;
+ }
+
+ //////////////////////////
+ // begin original edge collapse
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ // TODO: handleTriPropertyEdgeCollapse(trinum, P0,P1, ca_old[0], cb_old[0]);
+
+ m.mergeNode(P0, P1);
+
+ // Move position of P0
+ m.nodes(P0).pos = endpoint + 0.5*edgevect;
+
+ // Preserve connectivity in both triangles
+ if (ca_old[1].opposite>=0)
+ m.corners(ca_old[1].opposite).opposite = ca_old[2].opposite;
+ if (ca_old[2].opposite>=0)
+ m.corners(ca_old[2].opposite).opposite = ca_old[1].opposite;
+ if (haveB && cb_old[1].opposite>=0)
+ m.corners(cb_old[1].opposite).opposite = cb_old[2].opposite;
+ if (haveB && cb_old[2].opposite>=0)
+ m.corners(cb_old[2].opposite).opposite = cb_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ taintedTris[ca_old[0].tri] = true;
+ m.removeTriFromLookup(ca_old[0].tri);
+ if (haveB) {
+ taintedTris[cb_old[0].tri] = true;
+ m.removeTriFromLookup(cb_old[0].tri);
+ }
+ deletedNodes.push_back(P1);
+ numCollapses++;
+}
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h
new file mode 100644
index 00000000000..9e831d3a630
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h
@@ -0,0 +1,48 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Mesh edge collapse and subdivision
+ *
+ ******************************************************************************/
+
+/******************************************************************************/
+// Copyright note:
+//
+// These functions (C) Chris Wojtan
+// Long-term goal is to unify with his split&merge codebase
+//
+/******************************************************************************/
+
+#ifndef _EDGECOLLAPSE_H
+#define _EDGECOLLAPSE_H
+
+#include "mesh.h"
+
+namespace Manta {
+
+void CollapseEdge(Mesh& mesh, const int trinum, const int which, const Vec3 &edgevect, const Vec3 &endpoint,
+ std::vector<int> &deletedNodes, std::map<int,bool> &taintedTris, int &numCollapses, bool doTubeCutting);
+
+Vec3 ModifiedButterflySubdivision(Mesh& mesh, const Corner& ca, const Corner& cb, const Vec3& fallback);
+
+}
+
+#endif
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h.reg
new file mode 100644
index 00000000000..9869b6a5c7d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h.reg
@@ -0,0 +1 @@
+#include "edgecollapse.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h.reg.cpp
new file mode 100644
index 00000000000..9c63706d623
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/edgecollapse.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "edgecollapse.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_19()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.cpp
new file mode 100644
index 00000000000..db0ad64bdaa
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.cpp
@@ -0,0 +1,807 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Fast marching and extrapolation
+ *
+ ******************************************************************************/
+
+#include "fastmarch.h"
+#include "levelset.h"
+#include "kernel.h"
+#include <algorithm>
+
+using namespace std;
+
+namespace Manta {
+
+template<class COMP, int TDIR>
+FastMarch<COMP,TDIR>::FastMarch(const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& levelset, Real maxTime, MACGrid* velTransport )
+ : mLevelset(levelset), mFlags(flags), mFmFlags(fmFlags)
+{
+ if (velTransport)
+ mVelTransport.initMarching(velTransport, &flags);
+
+ mMaxTime = maxTime * TDIR;
+}
+
+// helper for individual components to calculateDistance
+template<class COMP, int TDIR> template<int C>
+Real FastMarch<COMP,TDIR>::calcWeights(int& okcnt, int& invcnt, Real* v, const Vec3i& idx) {
+ Real val = 0.;
+ Vec3i idxPlus(idx), idxMinus(idx);
+ idxPlus[C]++;
+ idxMinus[C]--;
+
+ mWeights[C*2] = mWeights[C*2+1] = 0.;
+ if (mFmFlags(idxPlus)==FlagInited) {
+ // somewhat arbitrary - choose +1 value over -1 ...
+ val = mLevelset(idxPlus);
+ v[okcnt] = val; okcnt++;
+ mWeights[C*2] = 1.;
+ } else if (mFmFlags(idxMinus)==FlagInited) {
+ val = mLevelset(idxMinus);
+ v[okcnt] = val; okcnt++;
+ mWeights[C*2+1] = 1.;
+ }
+ else {
+ invcnt++;
+ }
+ return val;
+}
+
+template<class COMP, int TDIR>
+inline Real FastMarch<COMP,TDIR>::calculateDistance(const Vec3i& idx) {
+ //int invflag = 0;
+ int invcnt = 0;
+ Real v[3];
+ int okcnt = 0;
+
+ Real aVal = calcWeights<0>(okcnt, invcnt, v, idx);
+ Real bVal = calcWeights<1>(okcnt, invcnt, v, idx);
+ Real cVal = 0.;
+ if (mLevelset.is3D()) cVal = calcWeights<2>(okcnt, invcnt, v, idx);
+ else { invcnt++; mWeights[4] = mWeights[5] = 0.; }
+
+ Real ret = InvalidTime();
+ switch(invcnt) {
+ case 0: {
+ // take all values
+ const Real ca=v[0], cb=v[1], cc=v[2];
+ const Real csqrt = max(0. ,
+ -2.*(ca*ca+cb*cb- cb*cc + cc*cc - ca*(cb+cc)) + 3 );
+ // clamp to make sure the sqrt is valid
+ ret = 0.333333*( ca+cb+cc+ TDIR*sqrt(csqrt) );
+
+ // weights needed for transport (transpTouch)
+ mWeights[0] *= fabs(ret-ca);
+ mWeights[1] *= fabs(ret-ca);
+ mWeights[2] *= fabs(ret-cb);
+ mWeights[3] *= fabs(ret-cb);
+ mWeights[4] *= fabs(ret-cc);
+ mWeights[5] *= fabs(ret-cc);
+
+ Real norm = 0.0; // try to force normalization
+ for(int i=0;i<6;i++) {
+ norm += mWeights[i];
+ }
+ norm = 1.0/norm;
+ for(int i=0;i<6;i++) { mWeights[i] *= norm; }
+
+ } break;
+ case 1: {
+ // take just the 2 ok values
+ // t=0.5*( a+b+ (2*g*g-(b-a)*(b-a))^0.5)
+ const Real csqrt = max(0. , 2.-(v[1]-v[0])*(v[1]-v[0]) );
+ // clamp to make sure the sqrt is valid
+ ret = 0.5*( v[0]+v[1]+ TDIR*sqrt(csqrt) );
+
+ // weights needed for transport (transpTouch)
+ mWeights[0] *= fabs(ret-aVal);
+ mWeights[1] *= fabs(ret-aVal);
+ mWeights[2] *= fabs(ret-bVal);
+ mWeights[3] *= fabs(ret-bVal);
+ mWeights[4] *= fabs(ret-cVal);
+ mWeights[5] *= fabs(ret-cVal);
+
+ Real norm = 0.0; // try to force normalization
+ for(int i=0;i<6;i++) {
+ norm += mWeights[i];
+ }
+ norm = 1.0/norm;
+ for(int i=0;i<6;i++) { mWeights[i] *= norm; }
+ // */
+
+ } break;
+ case 2: {
+ // just use the one remaining value
+ ret = v[0]+ (Real)(TDIR) ; // direction = +- 1
+ } break;
+ default:
+ errMsg("FastMarch :: Invalid invcnt");
+ break;
+ }
+ return ret;
+}
+
+template<class COMP, int TDIR>
+void FastMarch<COMP,TDIR>::addToList(const Vec3i& p, const Vec3i& src) {
+ if (!mLevelset.isInBounds(p,1)) return;
+ const IndexInt idx = mLevelset.index(p);
+
+ // already known value, value alreay set to valid value? skip cell...
+ if(mFmFlags[idx] == FlagInited) return;
+
+ // discard by source time now , TODO do instead before calling all addtolists?
+ Real srct = mLevelset(src);
+ if(COMP::compare(srct, mMaxTime)) return;
+
+ Real ttime = calculateDistance(p);
+
+ // remove old entry if larger
+ bool found=false;
+
+ Real oldt = mLevelset[idx];
+ if (mFmFlags[idx] == FlagIsOnHeap) {
+ found = true;
+ // is old time better?
+ if(COMP::compare(ttime,oldt)) return;
+ }
+
+ // update field
+ mFmFlags[idx] = FlagIsOnHeap;
+ mLevelset[idx] = ttime;
+ // debug info std::cout<<"set "<< idx <<","<< ttime <<"\n";
+
+ if (mVelTransport.isInitialized())
+ mVelTransport.transpTouch(p.x, p.y, p.z, mWeights, ttime);
+
+ // the following adds entries to the heap of active cells
+ // current: (!found) , previous: always add, might lead to duplicate
+ // entries, but the earlier will be handled earlier, the second one will skip to the FlagInited check above
+ if(!found)
+ {
+ // add list entry with source value
+ COMP entry;
+ entry.p = p;
+ entry.time = mLevelset[idx];
+
+ mHeap.push( entry );
+ // debug info std::cout<<"push "<< entry.p <<","<< entry.time <<"\n";
+ }
+
+}
+
+//! Enforce delta_phi = 0 on boundaries
+
+ struct SetLevelsetBoundaries : public KernelBase {
+ SetLevelsetBoundaries(Grid<Real>& phi) : KernelBase(&phi,0) ,phi(phi) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& phi ) {
+ if (i==0) phi(i,j,k) = phi(1,j,k);
+ if (i==maxX-1) phi(i,j,k) = phi(i-1,j,k);
+
+ if (j==0) phi(i,j,k) = phi(i,1,k);
+ if (j==maxY-1) phi(i,j,k) = phi(i,j-1,k);
+
+ if(phi.is3D()) {
+ if (k==0) phi(i,j,k) = phi(i,j,1);
+ if (k==maxZ-1) phi(i,j,k) = phi(i,j,k-1);
+ }
+} inline Grid<Real>& getArg0() {
+ return phi; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel SetLevelsetBoundaries ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=0; j< _maxY; j++) for (int i=0; i< _maxX; i++) op(i,j,k, phi); }
+ Grid<Real>& phi; }
+;
+
+/*****************************************************************************/
+//! Walk...
+template<class COMP, int TDIR>
+void FastMarch<COMP,TDIR>::performMarching() {
+ mReheapVal = 0.0;
+ while(mHeap.size() > 0) {
+
+ const COMP& ce = mHeap.top();
+ Vec3i p = ce.p;
+ mFmFlags(p) = FlagInited;
+ mHeap.pop();
+ // debug info std::cout<<"pop "<< ce.p <<","<< ce.time <<"\n";
+
+ addToList(Vec3i(p.x-1,p.y,p.z), p);
+ addToList(Vec3i(p.x+1,p.y,p.z), p);
+ addToList(Vec3i(p.x,p.y-1,p.z), p);
+ addToList(Vec3i(p.x,p.y+1,p.z), p);
+ if(mLevelset.is3D()) {
+ addToList(Vec3i(p.x,p.y,p.z-1), p);
+ addToList(Vec3i(p.x,p.y,p.z+1), p);
+ }
+ }
+
+ // set boundary for plain array
+ SetLevelsetBoundaries setls(mLevelset);
+ setls.getArg0(); // get rid of compiler warning...
+}
+
+// explicit instantiation
+template class FastMarch<FmHeapEntryIn, -1>;
+template class FastMarch<FmHeapEntryOut, +1>;
+
+
+/*****************************************************************************/
+// simpler extrapolation functions (primarily for FLIP)
+
+
+
+ struct knExtrapolateMACSimple : public KernelBase {
+ knExtrapolateMACSimple(MACGrid& vel, int distance , Grid<int>& tmp , const int d , const int c ) : KernelBase(&vel,1) ,vel(vel),distance(distance),tmp(tmp),d(d),c(c) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& vel, int distance , Grid<int>& tmp , const int d , const int c ) {
+ static const Vec3i nb[6] = {
+ Vec3i(1 ,0,0), Vec3i(-1,0,0),
+ Vec3i(0,1 ,0), Vec3i(0,-1,0),
+ Vec3i(0,0,1 ), Vec3i(0,0,-1) };
+ const int dim = (vel.is3D() ? 3:2);
+
+ if (tmp(i,j,k) != 0) return;
+
+ // copy from initialized neighbors
+ Vec3i p(i,j,k);
+ int nbs = 0;
+ Real avgVel = 0.;
+ for (int n=0; n<2*dim; ++n) {
+ if (tmp(p+nb[n]) == d) {
+ //vel(p)[c] = (c+1.)*0.1;
+ avgVel += vel(p+nb[n])[c];
+ nbs++;
+ }
+ }
+
+ if(nbs>0) {
+ tmp(p) = d+1;
+ vel(p)[c] = avgVel / nbs;
+ }
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline int& getArg1() {
+ return distance; }
+ typedef int type1;inline Grid<int>& getArg2() {
+ return tmp; }
+ typedef Grid<int> type2;inline const int& getArg3() {
+ return d; }
+ typedef int type3;inline const int& getArg4() {
+ return c; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel knExtrapolateMACSimple ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,distance,tmp,d,c); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,distance,tmp,d,c); }
+ }
+ }
+ MACGrid& vel; int distance; Grid<int>& tmp; const int d; const int c; }
+;
+//! copy velocity into domain side, note - don't read & write same grid, hence velTmp copy
+
+
+ struct knExtrapolateIntoBnd : public KernelBase {
+ knExtrapolateIntoBnd(FlagGrid& flags, MACGrid& vel, const MACGrid& velTmp) : KernelBase(&flags,0) ,flags(flags),vel(vel),velTmp(velTmp) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, const MACGrid& velTmp ) {
+ int c=0;
+ Vec3 v(0,0,0);
+ const bool isObs = flags.isObstacle(i,j,k);
+ if( i==0 ) {
+ v = velTmp(i+1,j,k);
+ if(isObs && v[0] < 0.) v[0] = 0.;
+ c++;
+ }
+ else if( i==(flags.getSizeX()-1) ) {
+ v = velTmp(i-1,j,k);
+ if(isObs && v[0] > 0.) v[0] = 0.;
+ c++;
+ }
+ if( j==0 ) {
+ v = velTmp(i,j+1,k);
+ if(isObs && v[1] < 0.) v[1] = 0.;
+ c++;
+ }
+ else if( j==(flags.getSizeY()-1) ) {
+ v = velTmp(i,j-1,k);
+ if(isObs && v[1] > 0.) v[1] = 0.;
+ c++;
+ }
+ if(flags.is3D()) {
+ if( k==0 ) {
+ v = velTmp(i,j,k+1);
+ if(isObs && v[2] < 0.) v[2] = 0.;
+ c++;
+ }
+ else if( k==(flags.getSizeZ()-1) ) {
+ v = velTmp(i,j,k-1);
+ if(isObs && v[2] > 0.) v[2] = 0.;
+ c++;
+ } }
+ if(c>0) {
+ vel(i,j,k) = v/(Real)c;
+ }
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const MACGrid& getArg2() {
+ return velTmp; }
+ typedef MACGrid type2; void runMessage() { debMsg("Executing kernel knExtrapolateIntoBnd ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,vel,velTmp); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,vel,velTmp); }
+ }
+ }
+ FlagGrid& flags; MACGrid& vel; const MACGrid& velTmp; }
+;
+
+// todo - use getGradient instead?
+inline Vec3 getNormal(const Grid<Real>& data, int i, int j, int k) {
+ if (i > data.getSizeX()-2) i= data.getSizeX()-2;
+ if (i < 1) i = 1;
+ if (j > data.getSizeY()-2) j= data.getSizeY()-2;
+ if (j < 1) j = 1;
+
+ int kd = 1;
+ if(data.is3D()) {
+ if (k > data.getSizeZ()-2) k= data.getSizeZ()-2;
+ if (k < 1) k = 1;
+ } else { kd=0; }
+
+ return Vec3( data(i+1,j ,k ) - data(i-1,j ,k ) ,
+ data(i ,j+1,k ) - data(i ,j-1,k ) ,
+ data(i ,j ,k+kd) - data(i ,j ,k-kd) );
+}
+
+
+ struct knUnprojectNormalComp : public KernelBase {
+ knUnprojectNormalComp(FlagGrid& flags, MACGrid& vel, Grid<Real>& phi, Real maxDist) : KernelBase(&flags,1) ,flags(flags),vel(vel),phi(phi),maxDist(maxDist) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, Grid<Real>& phi, Real maxDist ) {
+ // apply inside, within range near obstacle surface
+ if(phi(i,j,k)>0. || phi(i,j,k)<-maxDist) return;
+
+ Vec3 n = getNormal(phi, i,j,k);
+ Vec3 v = vel(i,j,k);
+ if(dot(n,v) < 0.) {
+ normalize(n);
+ Real l = dot(n,v);
+ vel(i,j,k) -= n*l;
+ }
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline Grid<Real>& getArg2() {
+ return phi; }
+ typedef Grid<Real> type2;inline Real& getArg3() {
+ return maxDist; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel knUnprojectNormalComp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,phi,maxDist); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,phi,maxDist); }
+ }
+ }
+ FlagGrid& flags; MACGrid& vel; Grid<Real>& phi; Real maxDist; }
+;
+// a simple extrapolation step , used for cases where there's no levelset
+// (note, less accurate than fast marching extrapolation.)
+// into obstacle is a special mode for second order obstable boundaries (extrapolating
+// only fluid velocities, not those at obstacles)
+
+
+void extrapolateMACSimple(FlagGrid& flags, MACGrid& vel, int distance = 4, LevelsetGrid* phiObs=NULL , bool intoObs = false ) {
+ Grid<int> tmp( flags.getParent() );
+ int dim = (flags.is3D() ? 3:2);
+
+ for(int c=0; c<dim; ++c) {
+ Vec3i dir = 0;
+ dir[c] = 1;
+ tmp.clear();
+
+ // remove all fluid cells (not touching obstacles)
+ FOR_IJK_BND(flags,1) {
+ Vec3i p(i,j,k);
+ bool mark = false;
+ if(!intoObs) {
+ if( flags.isFluid(p) || flags.isFluid(p-dir) ) mark = true;
+ } else {
+ if( (flags.isFluid(p) || flags.isFluid(p-dir) ) &&
+ (!flags.isObstacle(p)) && (!flags.isObstacle(p-dir)) ) mark = true;
+ }
+
+ if(mark) tmp(p) = 1;
+ }
+
+ // extrapolate for distance
+ for(int d=1; d<1+distance; ++d) {
+ knExtrapolateMACSimple(vel, distance, tmp, d, c);
+ } // d
+ }
+
+ if(phiObs) {
+ knUnprojectNormalComp( flags, vel, *phiObs, distance );
+ }
+
+ // copy tangential values into sides of domain
+ MACGrid velTmp( flags.getParent() ); velTmp.copyFrom(vel);
+ knExtrapolateIntoBnd(flags, vel, velTmp);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "extrapolateMACSimple" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); int distance = _args.getOpt<int >("distance",2,4,&_lock); LevelsetGrid* phiObs = _args.getPtrOpt<LevelsetGrid >("phiObs",3,NULL ,&_lock); bool intoObs = _args.getOpt<bool >("intoObs",4,false ,&_lock); _retval = getPyNone(); extrapolateMACSimple(flags,vel,distance,phiObs,intoObs); _args.check(); }
+ pbFinalizePlugin(parent,"extrapolateMACSimple", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("extrapolateMACSimple",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_extrapolateMACSimple ("","extrapolateMACSimple",_W_0);
+extern "C" {
+ void PbRegister_extrapolateMACSimple() {
+ KEEP_UNUSED(_RP_extrapolateMACSimple); }
+ }
+
+
+
+
+
+ struct knExtrapolateMACFromWeight : public KernelBase {
+ knExtrapolateMACFromWeight( MACGrid& vel, Grid<Vec3>& weight, int distance , const int d, const int c ) : KernelBase(&vel,1) ,vel(vel),weight(weight),distance(distance),d(d),c(c) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& vel, Grid<Vec3>& weight, int distance , const int d, const int c ) {
+ static const Vec3i nb[6] = {
+ Vec3i(1 ,0,0), Vec3i(-1,0,0),
+ Vec3i(0,1 ,0), Vec3i(0,-1,0),
+ Vec3i(0,0,1 ), Vec3i(0,0,-1) };
+ const int dim = (vel.is3D() ? 3:2);
+
+ if (weight(i,j,k)[c] != 0) return;
+
+ // copy from initialized neighbors
+ Vec3i p(i,j,k);
+ int nbs = 0;
+ Real avgVel = 0.;
+ for (int n=0; n<2*dim; ++n) {
+ if (weight(p+nb[n])[c] == d) {
+ avgVel += vel(p+nb[n])[c];
+ nbs++;
+ }
+ }
+
+ if(nbs>0) {
+ weight(p)[c] = d+1;
+ vel(p)[c] = avgVel / nbs;
+ }
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline Grid<Vec3>& getArg1() {
+ return weight; }
+ typedef Grid<Vec3> type1;inline int& getArg2() {
+ return distance; }
+ typedef int type2;inline const int& getArg3() {
+ return d; }
+ typedef int type3;inline const int& getArg4() {
+ return c; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel knExtrapolateMACFromWeight ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,weight,distance,d,c); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,weight,distance,d,c); }
+ }
+ }
+ MACGrid& vel; Grid<Vec3>& weight; int distance; const int d; const int c; }
+;
+
+// same as extrapolateMACSimple, but uses weight vec3 grid instead of flags to check
+// for valid values (to be used in combination with mapPartsToMAC)
+// note - the weight grid values are destroyed! the function is necessary due to discrepancies
+// between velocity mapping on surface-levelset / fluid-flag creation. With this
+// extrapolation we make sure the fluid region is covered by initial velocities
+
+void extrapolateMACFromWeight( MACGrid& vel, Grid<Vec3>& weight, int distance = 2) {
+ const int dim = (vel.is3D() ? 3:2);
+
+ for(int c=0; c<dim; ++c) {
+ Vec3i dir = 0;
+ dir[c] = 1;
+
+ // reset weight values to 0 (uninitialized), and 1 (initialized inner values)
+ FOR_IJK_BND(vel,1) {
+ Vec3i p(i,j,k);
+ if(weight(p)[c]>0.) weight(p)[c] = 1.0;
+ }
+
+ // extrapolate for distance
+ for(int d=1; d<1+distance; ++d) {
+ knExtrapolateMACFromWeight(vel, weight, distance, d, c);
+ } // d
+
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "extrapolateMACFromWeight" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Vec3>& weight = *_args.getPtr<Grid<Vec3> >("weight",1,&_lock); int distance = _args.getOpt<int >("distance",2,2,&_lock); _retval = getPyNone(); extrapolateMACFromWeight(vel,weight,distance); _args.check(); }
+ pbFinalizePlugin(parent,"extrapolateMACFromWeight", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("extrapolateMACFromWeight",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_extrapolateMACFromWeight ("","extrapolateMACFromWeight",_W_1);
+extern "C" {
+ void PbRegister_extrapolateMACFromWeight() {
+ KEEP_UNUSED(_RP_extrapolateMACFromWeight); }
+ }
+
+
+
+// simple extrapolation functions for levelsets
+
+static const Vec3i nb[6] = {
+ Vec3i(1 ,0,0), Vec3i(-1,0,0),
+ Vec3i(0,1 ,0), Vec3i(0,-1,0),
+ Vec3i(0,0,1 ), Vec3i(0,0,-1) };
+
+
+
+template <class S> struct knExtrapolateLsSimple : public KernelBase {
+ knExtrapolateLsSimple(Grid<S>& val, int distance , Grid<int>& tmp , const int d , S direction ) : KernelBase(&val,1) ,val(val),distance(distance),tmp(tmp),d(d),direction(direction) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<S>& val, int distance , Grid<int>& tmp , const int d , S direction ) {
+ const int dim = (val.is3D() ? 3:2);
+ if (tmp(i,j,k) != 0) return;
+
+ // copy from initialized neighbors
+ Vec3i p(i,j,k);
+ int nbs = 0;
+ S avg(0.);
+ for (int n=0; n<2*dim; ++n) {
+ if (tmp(p+nb[n]) == d) {
+ avg += val(p+nb[n]);
+ nbs++;
+ }
+ }
+
+ if(nbs>0) {
+ tmp(p) = d+1;
+ val(p) = avg / nbs + direction;
+ }
+} inline Grid<S>& getArg0() {
+ return val; }
+ typedef Grid<S> type0;inline int& getArg1() {
+ return distance; }
+ typedef int type1;inline Grid<int>& getArg2() {
+ return tmp; }
+ typedef Grid<int> type2;inline const int& getArg3() {
+ return d; }
+ typedef int type3;inline S& getArg4() {
+ return direction; }
+ typedef S type4; void runMessage() { debMsg("Executing kernel knExtrapolateLsSimple ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,val,distance,tmp,d,direction); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,val,distance,tmp,d,direction); }
+ }
+ }
+ Grid<S>& val; int distance; Grid<int>& tmp; const int d; S direction; }
+;
+
+
+
+
+template <class S> struct knSetRemaining : public KernelBase {
+ knSetRemaining(Grid<S>& phi, Grid<int>& tmp, S distance ) : KernelBase(&phi,1) ,phi(phi),tmp(tmp),distance(distance) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<S>& phi, Grid<int>& tmp, S distance ) {
+ if (tmp(i,j,k) != 0) return;
+ phi(i,j,k) = distance;
+} inline Grid<S>& getArg0() {
+ return phi; }
+ typedef Grid<S> type0;inline Grid<int>& getArg1() {
+ return tmp; }
+ typedef Grid<int> type1;inline S& getArg2() {
+ return distance; }
+ typedef S type2; void runMessage() { debMsg("Executing kernel knSetRemaining ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,phi,tmp,distance); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,phi,tmp,distance); }
+ }
+ }
+ Grid<S>& phi; Grid<int>& tmp; S distance; }
+;
+
+
+void extrapolateLsSimple(Grid<Real>& phi, int distance = 4, bool inside=false ) {
+ Grid<int> tmp( phi.getParent() );
+ tmp.clear();
+ const int dim = (phi.is3D() ? 3:2);
+
+ // by default, march outside
+ Real direction = 1.;
+ if(!inside) {
+ // mark all inside
+ FOR_IJK_BND(phi,1) {
+ if ( phi(i,j,k) < 0. ) { tmp(i,j,k) = 1; }
+ }
+ } else {
+ direction = -1.;
+ FOR_IJK_BND(phi,1) {
+ if ( phi(i,j,k) > 0. ) { tmp(i,j,k) = 1; }
+ }
+ }
+ // + first layer around
+ FOR_IJK_BND(phi,1) {
+ Vec3i p(i,j,k);
+ if ( tmp(p) ) continue;
+ for (int n=0; n<2*dim; ++n) {
+ if (tmp(p+nb[n])==1) {
+ tmp(i,j,k) = 2; n=2*dim;
+ }
+ }
+ }
+
+ // extrapolate for distance
+ for(int d=2; d<1+distance; ++d) {
+ knExtrapolateLsSimple<Real>(phi, distance, tmp, d, direction );
+ }
+
+ // set all remaining cells to max
+ knSetRemaining<Real>(phi, tmp, Real(direction * (distance+2)) );
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "extrapolateLsSimple" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& phi = *_args.getPtr<Grid<Real> >("phi",0,&_lock); int distance = _args.getOpt<int >("distance",1,4,&_lock); bool inside = _args.getOpt<bool >("inside",2,false ,&_lock); _retval = getPyNone(); extrapolateLsSimple(phi,distance,inside); _args.check(); }
+ pbFinalizePlugin(parent,"extrapolateLsSimple", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("extrapolateLsSimple",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_extrapolateLsSimple ("","extrapolateLsSimple",_W_2);
+extern "C" {
+ void PbRegister_extrapolateLsSimple() {
+ KEEP_UNUSED(_RP_extrapolateLsSimple); }
+ }
+
+
+
+// extrapolate centered vec3 values from marked fluid cells
+
+void extrapolateVec3Simple(Grid<Vec3>& vel, Grid<Real>& phi, int distance = 4, bool inside=false) {
+ Grid<int> tmp( vel.getParent() );
+ tmp.clear();
+ const int dim = (vel.is3D() ? 3:2);
+
+ // mark initial cells, by default, march outside
+ if(!inside) {
+ // mark all inside
+ FOR_IJK_BND(phi,1) {
+ if ( phi(i,j,k) < 0. ) { tmp(i,j,k) = 1; }
+ }
+ } else {
+ FOR_IJK_BND(phi,1) {
+ if ( phi(i,j,k) > 0. ) { tmp(i,j,k) = 1; }
+ }
+ }
+ // + first layer next to initial cells
+ FOR_IJK_BND(vel,1) {
+ Vec3i p(i,j,k);
+ if ( tmp(p) ) continue;
+ for (int n=0; n<2*dim; ++n) {
+ if (tmp(p+nb[n])==1) {
+ tmp(i,j,k) = 2; n=2*dim;
+ }
+ }
+ }
+
+ for(int d=2; d<1+distance; ++d) {
+ knExtrapolateLsSimple<Vec3>(vel, distance, tmp, d, Vec3(0.) );
+ }
+ knSetRemaining<Vec3>(vel, tmp, Vec3(0.) );
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "extrapolateVec3Simple" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& vel = *_args.getPtr<Grid<Vec3> >("vel",0,&_lock); Grid<Real>& phi = *_args.getPtr<Grid<Real> >("phi",1,&_lock); int distance = _args.getOpt<int >("distance",2,4,&_lock); bool inside = _args.getOpt<bool >("inside",3,false,&_lock); _retval = getPyNone(); extrapolateVec3Simple(vel,phi,distance,inside); _args.check(); }
+ pbFinalizePlugin(parent,"extrapolateVec3Simple", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("extrapolateVec3Simple",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_extrapolateVec3Simple ("","extrapolateVec3Simple",_W_3);
+extern "C" {
+ void PbRegister_extrapolateVec3Simple() {
+ KEEP_UNUSED(_RP_extrapolateVec3Simple); }
+ }
+
+
+
+
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h
new file mode 100644
index 00000000000..b82a8947f31
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h
@@ -0,0 +1,195 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Fast marching
+ *
+ ******************************************************************************/
+
+#ifndef _FASTMARCH_H
+#define _FASTMARCH_H
+
+#include <queue>
+#include "levelset.h"
+
+namespace Manta {
+
+//! Fast marching. Transport certain values
+// This class exists in two versions: for scalar, and for vector values - the only difference are
+// flag checks i transpTouch (for simplicity in separate classes)
+
+template<class GRID, class T>
+inline T fmInterpolateNeighbors(GRID* mpVal, int x,int y,int z, Real *weights) {
+ T val(0.);
+ if(weights[0]>0.0) val += mpVal->get(x+1, y+0, z+0) * weights[0];
+ if(weights[1]>0.0) val += mpVal->get(x-1, y+0, z+0) * weights[1];
+ if(weights[2]>0.0) val += mpVal->get(x+0, y+1, z+0) * weights[2];
+ if(weights[3]>0.0) val += mpVal->get(x+0, y-1, z+0) * weights[3];
+ if(mpVal->is3D()) {
+ if(weights[4]>0.0) val += mpVal->get(x+0, y+0, z+1) * weights[4];
+ if(weights[5]>0.0) val += mpVal->get(x+0, y+0, z-1) * weights[5];
+ }
+ return val;
+}
+
+template<class GRID, class T>
+class FmValueTransportScalar {
+public:
+ FmValueTransportScalar() : mpVal(0),mpFlags(0) { };
+ ~FmValueTransportScalar() { };
+ void initMarching(GRID* val, FlagGrid* flags) {
+ mpVal = val;
+ mpFlags = flags;
+ }
+ inline bool isInitialized() { return mpVal != 0; }
+
+ //! cell is touched by marching from source cell
+ inline void transpTouch(int x,int y,int z, Real *weights, Real time) {
+ if(!mpVal || !mpFlags->isEmpty(x,y,z)) return;
+ T val = fmInterpolateNeighbors<GRID,T>(mpVal,x,y,z,weights);
+ (*mpVal)(x,y,z) = val;
+ };
+protected:
+ GRID* mpVal;
+ FlagGrid* mpFlags;
+};
+
+template<class GRID, class T>
+class FmValueTransportVec3 {
+public:
+ FmValueTransportVec3() : mpVal(0), mpFlags(0) { };
+ ~FmValueTransportVec3() { };
+ inline bool isInitialized() { return mpVal != 0; }
+ void initMarching(GRID* val, const FlagGrid* flags) {
+ mpVal = val;
+ mpFlags = flags;
+ }
+
+ //! cell is touched by marching from source cell
+ inline void transpTouch(int x,int y,int z, Real *weights, Real time) {
+ if(!mpVal || !mpFlags->isEmpty(x,y,z)) return;
+
+ T val = fmInterpolateNeighbors<GRID,T>(mpVal,x,y,z,weights);
+
+ // set velocity components if adjacent is empty
+ if (mpFlags->isEmpty(x-1,y,z)) (*mpVal)(x,y,z).x = val.x;
+ if (mpFlags->isEmpty(x,y-1,z)) (*mpVal)(x,y,z).y = val.y;
+ if(mpVal->is3D()) { if (mpFlags->isEmpty(x,y,z-1)) (*mpVal)(x,y,z).z = val.z; }
+ };
+
+protected:
+ GRID* mpVal;
+ const FlagGrid* mpFlags;
+};
+
+class FmHeapEntryOut {
+public:
+ Vec3i p;
+ // quick time access for sorting
+ Real time;
+ static inline bool compare(const Real x, const Real y) {
+ return x > y;
+ }
+
+ inline bool operator< (const FmHeapEntryOut& o) const {
+ const Real d = fabs((time) - ((o.time)));
+ if (d > 0.) return (time) > ((o.time));
+ if (p.z != o.p.z) return p.z > o.p.z;
+ if (p.y != o.p.y) return p.y > o.p.y;
+ return p.x > o.p.x;
+ };
+
+};
+
+class FmHeapEntryIn {
+public:
+ Vec3i p;
+ // quick time access for sorting
+ Real time;
+ static inline bool compare(const Real x, const Real y) {
+ return x < y;
+ }
+
+ inline bool operator< (const FmHeapEntryIn& o) const {
+ const Real d = fabs((time) - ((o.time)));
+ if (d > 0.) return (time) < ((o.time));
+ if (p.z != o.p.z) return p.z < o.p.z;
+ if (p.y != o.p.y) return p.y < o.p.y;
+ return p.x < o.p.x;
+ };
+};
+
+
+//! fast marching algorithm wrapper class
+template<class T, int TDIR>
+class FastMarch {
+
+public:
+ // MSVC doesn't allow static const variables in template classes
+ static inline Real InvalidTime() { return -1000; }
+ static inline Real InvtOffset() { return 500; }
+
+ enum SpecialValues { FlagInited = 1, FlagIsOnHeap = 2};
+
+ FastMarch(const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& levelset, Real maxTime, MACGrid* velTransport = NULL);
+ ~FastMarch() {}
+
+ //! advect level set function with given velocity */
+ void performMarching();
+
+ //! test value for invalidity
+ inline bool isInvalid(Real v) const { return (v <= InvalidTime()); }
+
+ void addToList(const Vec3i& p, const Vec3i& src);
+
+ //! convert phi to time value
+ inline Real phi2time(Real phival) { return (phival-InvalidTime()+ InvtOffset()) * -1.0; }
+
+ //! ... and back
+ inline Real time2phi(Real tval) { return (InvalidTime() - InvtOffset() - tval); }
+
+ inline Real _phi(int i, int j, int k) { return mLevelset(i,j,k); }
+protected:
+ Grid<Real>& mLevelset;
+ const FlagGrid& mFlags;
+ Grid<int>& mFmFlags;
+
+ //! velocity extrpolation
+ FmValueTransportVec3<MACGrid , Vec3> mVelTransport;
+
+ //! maximal time to march for
+ Real mMaxTime;
+
+ //! fast marching list
+ std::priority_queue<T, std::vector<T>, std::less<T> > mHeap;
+ Real mReheapVal;
+
+ //! weights for touching points
+ Real mWeights[6];
+
+ template<int C> inline Real calcWeights(int& okCnt, int& invcnt, Real* v, const Vec3i& idx);
+
+ inline Real calculateDistance(const Vec3i& pos);
+};
+
+} // namespace
+#endif
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h.reg
new file mode 100644
index 00000000000..7b9296f3580
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h.reg
@@ -0,0 +1 @@
+#include "fastmarch.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h.reg.cpp
new file mode 100644
index 00000000000..919d0fe6c82
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fastmarch.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "fastmarch.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_5()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/iogrids.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/iogrids.cpp
new file mode 100644
index 00000000000..e9a877dae41
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/iogrids.cpp
@@ -0,0 +1,1237 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <cstring>
+
+#if NO_ZLIB!=1
+extern "C" {
+#include <zlib.h>
+}
+#endif
+
+#if OPENVDB==1
+#include "openvdb/openvdb.h"
+#endif
+
+#include "cnpy.h"
+#include "mantaio.h"
+#include "grid.h"
+#include "vector4d.h"
+#include "grid4d.h"
+
+using namespace std;
+
+namespace Manta {
+
+static const int STR_LEN_GRID = 252;
+
+//! uni file header, v4
+typedef struct {
+ int dimX, dimY, dimZ; // grid size
+ int gridType, elementType, bytesPerElement; // data type info
+ char info[STR_LEN_GRID]; // mantaflow build information
+ int dimT; // optionally store forth dimension for 4d grids
+ unsigned long long timestamp; // creation time
+} UniHeader;
+
+// note: header v4 only uses 4 bytes of the info string to store the fourth dimension, not needed for pdata
+
+
+//*****************************************************************************
+// conversion functions for double precision
+// (note - uni files always store single prec. values)
+//*****************************************************************************
+
+#if NO_ZLIB!=1
+template <class GRIDT>
+void gridConvertWrite(gzFile& gzf, GRIDT& grid, void* ptr, UniHeader& head) {
+ errMsg("gridConvertWrite: unknown type, not yet supported");
+}
+
+template <>
+void gridConvertWrite(gzFile& gzf, Grid<int>& grid, void* ptr, UniHeader& head) {
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, &grid[0], sizeof(int)*head.dimX*head.dimY*head.dimZ);
+}
+template <>
+void gridConvertWrite(gzFile& gzf, Grid<double>& grid, void* ptr, UniHeader& head) {
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i,++ptrf) {
+ *ptrf = (float)grid[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float)* head.dimX*head.dimY*head.dimZ);
+}
+template <>
+void gridConvertWrite(gzFile& gzf, Grid<Vector3D<double> >& grid, void* ptr, UniHeader& head) {
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i) {
+ for(int c=0; c<3; ++c) { *ptrf = (float)grid[i][c]; ptrf++; }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) *head.dimX*head.dimY*head.dimZ);
+}
+
+template <>
+void gridConvertWrite(gzFile& gzf, Grid4d<int>& grid, void* ptr, UniHeader& head) {
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, &grid[0], sizeof(int)*head.dimX*head.dimY*head.dimZ*head.dimT);
+}
+template <>
+void gridConvertWrite(gzFile& gzf, Grid4d<double>& grid, void* ptr, UniHeader& head) {
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float* ptrf = (float*)ptr;
+ IndexInt s = grid.getStrideT()*grid.getSizeT();
+ for(IndexInt i=0; i<s; ++i,++ptrf) {
+ *ptrf = (float)grid[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float)* s );
+}
+template <>
+void gridConvertWrite(gzFile& gzf, Grid4d<Vector3D<double> >& grid, void* ptr, UniHeader& head) {
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float* ptrf = (float*)ptr;
+ IndexInt s = grid.getStrideT()*grid.getSizeT();
+ for(IndexInt i=0; i<s; ++i) {
+ for(int c=0; c<3; ++c) { *ptrf = (float)grid[i][c]; ptrf++; }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) *s);
+}
+template <>
+void gridConvertWrite(gzFile& gzf, Grid4d<Vector4D<double> >& grid, void* ptr, UniHeader& head) {
+ head.bytesPerElement = sizeof(Vector4D<float>);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float* ptrf = (float*)ptr;
+ IndexInt s = grid.getStrideT()*grid.getSizeT();
+ for(IndexInt i=0; i<s; ++i) {
+ for(int c=0; c<4; ++c) { *ptrf = (float)grid[i][c]; ptrf++; }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector4D<float>) *s);
+}
+
+template <class T>
+void gridReadConvert(gzFile& gzf, Grid<T>& grid, void* ptr, int bytesPerElement) {
+ errMsg("gridReadConvert: unknown type, not yet supported");
+}
+
+template <>
+void gridReadConvert<int>(gzFile& gzf, Grid<int>& grid, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(int)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ assertMsg (bytesPerElement == sizeof(int), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(int) );
+ // easy, nothing to do for ints
+ memcpy(&(grid[0]), ptr, sizeof(int) * grid.getSizeX()*grid.getSizeY()*grid.getSizeZ() );
+}
+
+template <>
+void gridReadConvert<double>(gzFile& gzf, Grid<double>& grid, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(float)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ assertMsg (bytesPerElement == sizeof(float), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i,++ptrf) {
+ grid[i] = (double)(*ptrf);
+ }
+}
+
+template <>
+void gridReadConvert<Vec3>(gzFile& gzf, Grid<Vec3>& grid, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(Vector3D<float>)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ assertMsg (bytesPerElement == sizeof(Vector3D<float>), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(Vector3D<float>) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i) {
+ Vec3 v;
+ for(int c=0; c<3; ++c) { v[c] = double(*ptrf); ptrf++; }
+ grid[i] = v;
+ }
+}
+
+template <class T>
+void gridReadConvert4d(gzFile& gzf, Grid4d<T>& grid, void* ptr, int bytesPerElement, int t) {
+ errMsg("gridReadConvert4d: unknown type, not yet supported");
+}
+
+template <>
+void gridReadConvert4d<int>(gzFile& gzf, Grid4d<int>& grid, void* ptr, int bytesPerElement, int t) {
+ gzread(gzf, ptr, sizeof(int)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ() );
+ assertMsg (bytesPerElement == sizeof(int), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(int) );
+ // nothing to do for ints
+ memcpy(&(grid[grid.getSizeX()*grid.getSizeY()*grid.getSizeZ() *t]), ptr, sizeof(int) * grid.getSizeX()*grid.getSizeY()*grid.getSizeZ() );
+}
+
+template <>
+void gridReadConvert4d<double>(gzFile& gzf, Grid4d<double>& grid, void* ptr, int bytesPerElement, int t) {
+ assertMsg (bytesPerElement == sizeof(float), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+
+ float* ptrf = (float*)ptr;
+ gzread(gzf, ptr, sizeof(float)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ for(IndexInt i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i , ++ptrf ) {
+ grid[ grid.getSizeX()*grid.getSizeY()*grid.getSizeZ()*t + i] = (double)(*ptrf);
+ }
+}
+
+template <>
+void gridReadConvert4d<Vec3>(gzFile& gzf, Grid4d<Vec3>& grid, void* ptr, int bytesPerElement, int t) {
+ assertMsg (bytesPerElement == sizeof(Vector3D<float>), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+
+ gzread(gzf, ptr, sizeof(Vector3D<float>)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ float* ptrf = (float*)ptr;
+ for(IndexInt i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i) {
+ Vec3 v;
+ for(int c=0; c<3; ++c) { v[c] = double(*ptrf); ptrf++; }
+ grid[grid.getSizeX()*grid.getSizeY()*grid.getSizeZ()*t + i] = v;
+ }
+}
+
+template <>
+void gridReadConvert4d<Vec4>(gzFile& gzf, Grid4d<Vec4>& grid, void* ptr, int bytesPerElement, int t) {
+ assertMsg (bytesPerElement == sizeof(Vector4D<float>), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+
+ gzread(gzf, ptr, sizeof(Vector4D<float>)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ float* ptrf = (float*)ptr;
+ for(IndexInt i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i) {
+ Vec4 v;
+ for(int c=0; c<4; ++c) { v[c] = double(*ptrf); ptrf++; }
+ grid[grid.getSizeX()*grid.getSizeY()*grid.getSizeZ()*t + i] = v;
+ }
+}
+
+
+
+// make sure compatible grid types dont lead to errors...
+static int unifyGridType(int type) {
+ // real <> levelset
+ if(type & GridBase::TypeReal) type |= GridBase::TypeLevelset;
+ if(type & GridBase::TypeLevelset) type |= GridBase::TypeReal;
+ // vec3 <> mac
+ if(type & GridBase::TypeVec3) type |= GridBase::TypeMAC;
+ if(type & GridBase::TypeMAC) type |= GridBase::TypeVec3;
+ return type;
+}
+
+#endif // NO_ZLIB!=1
+
+//*****************************************************************************
+// grid data
+//*****************************************************************************
+
+template<class T>
+void writeGridTxt(const string& name, Grid<T>* grid) {
+ debMsg( "writing grid " << grid->getName() << " to text file " << name ,1);
+
+ ofstream ofs(name.c_str());
+ if (!ofs.good())
+ errMsg("writeGridTxt: can't open file " << name);
+ FOR_IJK(*grid) {
+ ofs << Vec3i(i,j,k) <<" = "<< (*grid)(i,j,k) <<"\n";
+ }
+ ofs.close();
+}
+
+template<class T>
+void writeGridRaw(const string& name, Grid<T>* grid) {
+ debMsg( "writing grid " << grid->getName() << " to raw file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("writeGridRaw: can't open file " << name);
+ gzwrite(gzf, &((*grid)[0]), sizeof(T)*grid->getSizeX()*grid->getSizeY()*grid->getSizeZ());
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+template<class T>
+void readGridRaw(const string& name, Grid<T>* grid) {
+ debMsg( "reading grid " << grid->getName() << " from raw file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("readGridRaw: can't open file " << name);
+
+ IndexInt bytes = sizeof(T)*grid->getSizeX()*grid->getSizeY()*grid->getSizeZ();
+ IndexInt readBytes = gzread(gzf, &((*grid)[0]), bytes);
+ assertMsg(bytes==readBytes, "can't read raw file, stream length does not match, "<<bytes<<" vs "<<readBytes);
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+//! legacy headers for reading old files
+typedef struct {
+ int dimX, dimY, dimZ;
+ int frames, elements, elementType, bytesPerElement, bytesPerFrame;
+} UniLegacyHeader;
+
+typedef struct {
+ int dimX, dimY, dimZ;
+ int gridType, elementType, bytesPerElement;
+} UniLegacyHeader2;
+
+typedef struct {
+ int dimX, dimY, dimZ;
+ int gridType, elementType, bytesPerElement;
+ char info[256];
+ unsigned long long timestamp;
+} UniLegacyHeader3;
+
+//! for auto-init & check of results of test runs , optionally returns info string of header
+void getUniFileSize(const string& name, int& x, int& y, int& z, int* t, std::string* info) {
+ x = y = z = 0;
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (gzf) {
+ char ID[5]={0,0,0,0,0};
+ gzread(gzf, ID, 4);
+
+ // v3
+ if ( (!strcmp(ID, "MNT2")) || (!strcmp(ID, "M4T2")) ) {
+ UniLegacyHeader3 head;
+ assertMsg (gzread(gzf, &head, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3), "can't read file, no header present");
+ x = head.dimX;
+ y = head.dimY;
+ z = head.dimZ;
+
+ // optionally , read fourth dim
+ if ((!strcmp(ID, "M4T2")) && t) {
+ int dimT = 0;
+ gzread(gzf, &dimT, sizeof(int) );
+ (*t) = dimT;
+ }
+ }
+
+ // v4
+ if ( (!strcmp(ID, "MNT3")) || (!strcmp(ID, "M4T3")) ) {
+ UniHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader), "can't read file, no header present");
+ x = head.dimX;
+ y = head.dimY;
+ z = head.dimZ;
+ if(t) (*t) = head.dimT;
+ }
+
+ gzclose(gzf);
+ }
+# endif
+ if(info) {
+ std::ostringstream out;
+ out << x <<","<< y <<","<< z ;
+ if(t && (*t)>0 ) out << ","<< (*t);
+ *info = out.str();
+ }
+}
+Vec3 getUniFileSize(const string& name) {
+ int x,y,z;
+ getUniFileSize(name, x,y,z);
+ return Vec3( Real(x), Real(y), Real(z) );
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getUniFileSize" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const string& name = _args.get<string >("name",0,&_lock); _retval = toPy(getUniFileSize(name)); _args.check(); }
+ pbFinalizePlugin(parent,"getUniFileSize", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getUniFileSize",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getUniFileSize ("","getUniFileSize",_W_0);
+extern "C" {
+ void PbRegister_getUniFileSize() {
+ KEEP_UNUSED(_RP_getUniFileSize); }
+ }
+
+
+
+//! for test run debugging
+void printUniFileInfoString(const string& name) {
+ std::string info("<file not found>");
+ int x=-1,y=-1,z=-1,t=-1;
+ // use getUniFileSize to parse the different headers
+ getUniFileSize(name, x,y,z,&t, &info);
+ debMsg("File '"<<name<<"' info: "<< info ,1);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "printUniFileInfoString" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const string& name = _args.get<string >("name",0,&_lock); _retval = getPyNone(); printUniFileInfoString(name); _args.check(); }
+ pbFinalizePlugin(parent,"printUniFileInfoString", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("printUniFileInfoString",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_printUniFileInfoString ("","printUniFileInfoString",_W_1);
+extern "C" {
+ void PbRegister_printUniFileInfoString() {
+ KEEP_UNUSED(_RP_printUniFileInfoString); }
+ }
+
+
+
+
+// actual read/write functions
+
+template <class T>
+void writeGridUni(const string& name, Grid<T>* grid) {
+ debMsg( "Writing grid " << grid->getName() << " to uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ char ID[5] = "MNT3";
+ UniHeader head;
+ head.dimX = grid->getSizeX();
+ head.dimY = grid->getSizeY();
+ head.dimZ = grid->getSizeZ();
+ head.dimT = 0;
+ head.gridType = grid->getType();
+ head.bytesPerElement = sizeof(T);
+ snprintf( head.info, STR_LEN_GRID, "%s", buildInfoString().c_str() );
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ if (grid->getType() & GridBase::TypeInt)
+ head.elementType = 0;
+ else if (grid->getType() & GridBase::TypeReal)
+ head.elementType = 1;
+ else if (grid->getType() & GridBase::TypeVec3)
+ head.elementType = 2;
+ else
+ errMsg("writeGridUni: unknown element type");
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("writeGridUni: can't open file " << name);
+
+ gzwrite(gzf, ID, 4);
+# if FLOATINGPOINT_PRECISION!=1
+ // always write float values, even if compiled with double precision...
+ Grid<T> temp(grid->getParent());
+ // "misuse" temp grid as storage for floating point values (we have double, so it will always fit)
+ gridConvertWrite( gzf, *grid, &(temp[0]), head);
+# else
+ void* ptr = &((*grid)[0]);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, ptr, sizeof(T)*head.dimX*head.dimY*head.dimZ);
+# endif
+ gzclose(gzf);
+
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+
+template <class T>
+void readGridUni(const string& name, Grid<T>* grid) {
+ debMsg( "Reading grid " << grid->getName() << " from uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("readGridUni: can't open file " << name);
+
+ char ID[5]={0,0,0,0,0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "DDF2")) {
+ // legacy file format
+ UniLegacyHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniLegacyHeader)) == sizeof(UniLegacyHeader), "can't read file, no header present");
+ assertMsg (head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() && head.dimZ == grid->getSizeZ(), "grid dim doesn't match");
+ assertMsg (head.bytesPerElement * head.elements == sizeof(T), "grid type doesn't match");
+ // skip flags
+ int numEl = head.dimX*head.dimY*head.dimZ;
+ gzseek(gzf, numEl, SEEK_CUR);
+ // actual grid read
+ gzread(gzf, &((*grid)[0]), sizeof(T)*numEl);
+ }
+ else if (!strcmp(ID, "MNT1")) {
+ // legacy file format 2
+ UniLegacyHeader2 head;
+ assertMsg (gzread(gzf, &head, sizeof(UniLegacyHeader2)) == sizeof(UniLegacyHeader2), "can't read file, no header present");
+ assertMsg (head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() && head.dimZ == grid->getSizeZ(), "grid dim doesn't match, "<< Vec3(head.dimX,head.dimY,head.dimZ)<<" vs "<< grid->getSize() );
+ assertMsg (head.gridType == grid->getType(), "grid type doesn't match "<< head.gridType<<" vs "<< grid->getType() );
+ assertMsg (head.bytesPerElement == sizeof(T), "grid element size doesn't match "<< head.bytesPerElement <<" vs "<< sizeof(T) );
+ gzread(gzf, &((*grid)[0]), sizeof(T)*head.dimX*head.dimY*head.dimZ);
+ }
+ else if (!strcmp(ID, "MNT2")) {
+ // a bit ugly, almost identical to MNT3
+ UniLegacyHeader3 head;
+ assertMsg (gzread(gzf, &head, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3), "can't read file, no header present");
+ assertMsg (head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() && head.dimZ == grid->getSizeZ(), "grid dim doesn't match, "<< Vec3(head.dimX,head.dimY,head.dimZ)<<" vs "<< grid->getSize() );
+ assertMsg (unifyGridType(head.gridType)==unifyGridType(grid->getType()) , "grid type doesn't match "<< head.gridType<<" vs "<< grid->getType() );
+# if FLOATINGPOINT_PRECISION!=1
+ Grid<T> temp(grid->getParent());
+ void* ptr = &(temp[0]);
+ gridReadConvert<T>(gzf, *grid, ptr, head.bytesPerElement);
+# else
+ assertMsg (head.bytesPerElement == sizeof(T), "grid element size doesn't match "<< head.bytesPerElement <<" vs "<< sizeof(T) );
+ gzread(gzf, &((*grid)[0]), sizeof(T)*head.dimX*head.dimY*head.dimZ);
+# endif
+ }
+ else if (!strcmp(ID, "MNT3")) {
+ // current file format
+ UniHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader), "can't read file, no header present");
+ assertMsg (head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() && head.dimZ == grid->getSizeZ(), "grid dim doesn't match, "<< Vec3(head.dimX,head.dimY,head.dimZ)<<" vs "<< grid->getSize() );
+ assertMsg (unifyGridType(head.gridType)==unifyGridType(grid->getType()) , "grid type doesn't match "<< head.gridType<<" vs "<< grid->getType() );
+# if FLOATINGPOINT_PRECISION!=1
+ // convert float to double
+ Grid<T> temp(grid->getParent());
+ void* ptr = &(temp[0]);
+ gridReadConvert<T>(gzf, *grid, ptr, head.bytesPerElement);
+# else
+ assertMsg (head.bytesPerElement == sizeof(T), "grid element size doesn't match "<< head.bytesPerElement <<" vs "<< sizeof(T) );
+ gzread(gzf, &((*grid)[0]), sizeof(T)*head.dimX*head.dimY*head.dimZ);
+# endif
+ } else {
+ errMsg( "readGridUni: Unknown header '"<<ID<<"' " );
+ }
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+template <class T>
+void writeGridVol(const string& name, Grid<T>* grid) {
+ debMsg( "writing grid " << grid->getName() << " to vol file " << name ,1);
+ errMsg("writeGridVol: Type not yet supported!");
+}
+
+struct volHeader {
+ char ID[3];
+ char version;
+ int encoding;
+ int dimX, dimY, dimZ;
+ int channels;
+ Vec3 bboxMin, bboxMax;
+};
+
+template <>
+void writeGridVol<Real>(const string& name, Grid<Real>* grid) {
+ debMsg( "writing real grid " << grid->getName() << " to vol file " << name ,1);
+
+ volHeader header;
+ header.ID[0] = 'V';
+ header.ID[1] = 'O';
+ header.ID[2] = 'L';
+ header.version = 3;
+ header.encoding = 1; // float32 precision
+ header.dimX = grid->getSizeX();
+ header.dimY = grid->getSizeY();
+ header.dimZ = grid->getSizeZ();
+ header.channels = 1; // only 1 channel
+ header.bboxMin = Vec3(-0.5);
+ header.bboxMax = Vec3( 0.5);
+
+ FILE* fp = fopen( name.c_str(), "wb" );
+ if (fp == NULL) {
+ errMsg("writeGridVol: Cannot open '" << name << "'");
+ return;
+ }
+
+ fwrite( &header, sizeof(volHeader), 1, fp );
+
+# if FLOATINGPOINT_PRECISION==1
+ // for float, write one big chunk
+ fwrite( &(*grid)[0], sizeof(float), grid->getSizeX()*grid->getSizeY()*grid->getSizeZ(), fp );
+# else
+ // explicitly convert each entry to float - we might have double precision in mantaflow
+ FOR_IDX(*grid) {
+ float value = (*grid)[idx];
+ fwrite( &value, sizeof(float), 1, fp );
+ }
+# endif
+
+ fclose(fp);
+};
+
+
+template <class T>
+void readGridVol(const string& name, Grid<T>* grid) {
+ debMsg( "writing grid " << grid->getName() << " to vol file " << name ,1);
+ errMsg("readGridVol: Type not yet supported!");
+}
+
+template <>
+void readGridVol<Real>(const string& name, Grid<Real>* grid) {
+ debMsg( "reading real grid " << grid->getName() << " from vol file " << name ,1);
+
+ volHeader header;
+ FILE* fp = fopen( name.c_str(), "rb" );
+ if (fp == NULL) {
+ errMsg("readGridVol: Cannot open '" << name << "'");
+ return;
+ }
+
+ // note, only very basic file format checks here!
+ assertMsg( fread( &header, 1, sizeof(volHeader) , fp) == sizeof(volHeader), "can't read file, no header present");
+ if( header.dimX != grid->getSizeX() || header.dimY != grid->getSizeY() || header.dimZ != grid->getSizeZ()) errMsg( "grid dim doesn't match, "<< Vec3(header.dimX,header.dimY,header.dimZ)<<" vs "<< grid->getSize() );
+# if FLOATINGPOINT_PRECISION!=1
+ errMsg("readGridVol: Double precision not yet supported");
+# else
+ const unsigned int s = sizeof(float)*header.dimX*header.dimY*header.dimZ;
+ assertMsg( fread( &((*grid)[0]), 1, s, fp) == s, "can't read file, no / not enough data");
+# endif
+
+ fclose(fp);
+};
+
+// 4d grids IO
+
+template <class T>
+void writeGrid4dUni(const string& name, Grid4d<T>* grid) {
+ debMsg( "writing grid4d " << grid->getName() << " to uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ char ID[5] = "M4T3";
+ UniHeader head;
+ head.dimX = grid->getSizeX();
+ head.dimY = grid->getSizeY();
+ head.dimZ = grid->getSizeZ();
+ head.dimT = grid->getSizeT();
+ head.gridType = grid->getType();
+ head.bytesPerElement = sizeof(T);
+ snprintf( head.info, STR_LEN_GRID, "%s", buildInfoString().c_str() );
+ MuTime stamp; stamp.get();
+ head.timestamp = stamp.time;
+
+ if (grid->getType() & Grid4dBase::TypeInt)
+ head.elementType = 0;
+ else if (grid->getType() & Grid4dBase::TypeReal)
+ head.elementType = 1;
+ else if (grid->getType() & Grid4dBase::TypeVec3)
+ head.elementType = 2;
+ else if (grid->getType() & Grid4dBase::TypeVec4)
+ head.elementType = 2;
+ else
+ errMsg("writeGrid4dUni: unknown element type");
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("writeGrid4dUni: can't open file " << name);
+
+ gzwrite(gzf, ID, 4);
+# if FLOATINGPOINT_PRECISION!=1
+ Grid4d<T> temp(grid->getParent());
+ gridConvertWrite< Grid4d<T> >( gzf, *grid, &(temp[0]), head);
+# else
+ gzwrite(gzf, &head, sizeof(UniHeader));
+
+ // can be too large - write in chunks
+ for(int t=0; t<head.dimT; ++t) {
+ void* ptr = &((*grid)[ head.dimX*head.dimY*head.dimZ* t ]);
+ gzwrite(gzf, ptr, sizeof(T)*head.dimX*head.dimY*head.dimZ* 1);
+ }
+# endif
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+//! note, reading 4d uni grids is slightly more complicated than 3d ones
+//! as it optionally supports sliced reading
+template <class T>
+void readGrid4dUni(const string& name, Grid4d<T>* grid, int readTslice, Grid4d<T>* slice, void** fileHandle )
+{
+ if(grid) debMsg( "reading grid " << grid->getName() << " from uni file " << name ,1);
+ if(slice) debMsg( "reading slice " << slice->getName() << ",t="<<readTslice<<" from uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = NULL;
+ char ID[5]={0,0,0,0,0};
+
+ // optionally - reuse file handle, if valid one is passed in fileHandle pointer...
+ if( (!fileHandle) || (fileHandle && (*fileHandle == NULL)) ) {
+ gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("readGrid4dUni: can't open file "<<name);
+
+ gzread(gzf, ID, 4);
+ if( fileHandle) { *fileHandle = gzf; }
+ } else {
+ // optimized read - reduced sanity checks
+ gzf = (gzFile)(*fileHandle);
+ void* ptr = &( (*slice)[ 0 ] );
+ gzread(gzf, ptr, sizeof(T)* slice->getStrideT()* 1); // quick and dirty...
+ return;
+ }
+
+ if( (!strcmp(ID, "M4T2")) || (!strcmp(ID, "M4T3")) ) {
+ int headerSize = -1;
+
+ // current file format
+ UniHeader head;
+ if(!strcmp(ID, "M4T3")) {
+ headerSize = sizeof(UniHeader);
+ assertMsg (gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader), "can't read file, no 4d header present");
+ if(FLOATINGPOINT_PRECISION==1) assertMsg (head.bytesPerElement == sizeof(T), "4d grid element size doesn't match "<< head.bytesPerElement <<" vs "<< sizeof(T) );
+ }
+ // old header
+ if(!strcmp(ID, "M4T2")) {
+ UniLegacyHeader3 lhead;
+ headerSize = sizeof(UniLegacyHeader3) + sizeof(int);
+ assertMsg (gzread(gzf, &lhead, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3), "can't read file, no 4dl header present");
+ if(FLOATINGPOINT_PRECISION==1) assertMsg (lhead.bytesPerElement == sizeof(T), "4d grid element size doesn't match "<< lhead.bytesPerElement <<" vs "<< sizeof(T) );
+
+ int fourthDim = 0;
+ gzread(gzf, &fourthDim, sizeof(fourthDim));
+
+ head.dimX = lhead.dimX;
+ head.dimY = lhead.dimY;
+ head.dimZ = lhead.dimZ;
+ head.dimT = fourthDim;
+ head.gridType = lhead.gridType;
+ }
+
+ if(readTslice<0) {
+ assertMsg (head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() && head.dimZ == grid->getSizeZ(), "grid dim doesn't match, "<< Vec3(head.dimX,head.dimY,head.dimZ)<<" vs "<< grid->getSize() );
+ assertMsg ( unifyGridType(head.gridType)==unifyGridType(grid->getType()) , "grid type doesn't match "<< head.gridType<<" vs "<< grid->getType() );
+
+ // read full 4d grid
+ assertMsg (head.dimT == grid->getSizeT(), "grid dim4 doesn't match, "<< head.dimT <<" vs "<< grid->getSize() );
+
+ // can be too large - read in chunks
+# if FLOATINGPOINT_PRECISION!=1
+ Grid4d<T> temp(grid->getParent());
+ void* ptr = &(temp[0]);
+ for(int t=0; t<head.dimT; ++t) {
+ gridReadConvert4d<T>(gzf, *grid, ptr, head.bytesPerElement, t);
+ }
+# else
+ for(int t=0; t<head.dimT; ++t) {
+ void* ptr = &((*grid)[ head.dimX*head.dimY*head.dimZ* t ] );
+ gzread(gzf, ptr, sizeof(T)* head.dimX*head.dimY*head.dimZ* 1);
+ }
+# endif
+ } else {
+ // read chosen slice only
+ assertMsg (head.dimX == slice->getSizeX() && head.dimY == slice->getSizeY() && head.dimZ == slice->getSizeZ(), "grid dim doesn't match, "<< Vec3(head.dimX,head.dimY,head.dimZ)<<" vs "<< slice->getSize() );
+ assertMsg ( unifyGridType(head.gridType)==unifyGridType(slice->getType()) , "grid type doesn't match "<< head.gridType<<" vs "<< slice->getType() );
+
+# if FLOATINGPOINT_PRECISION!=1
+ errMsg( "readGrid4dUni: NYI (2)" ); // slice read not yet supported for double
+# else
+ assertMsg( slice, "No 3d slice grid data given" );
+ assertMsg (readTslice < head.dimT, "grid dim4 slice too large "<< readTslice <<" vs "<< head.dimT );
+ void* ptr = &( (*slice)[ 0 ] );
+ gzseek(gzf, sizeof(T)*head.dimX*head.dimY*head.dimZ* readTslice + headerSize + 4 , SEEK_SET );
+ gzread(gzf, ptr, sizeof(T)*head.dimX*head.dimY*head.dimZ* 1);
+# endif
+ }
+ } else {
+ debMsg( "Unknown header!" ,1);
+ }
+
+ if( !fileHandle) {
+ gzclose(gzf);
+ }
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+void readGrid4dUniCleanup(void** fileHandle) {
+ gzFile gzf = NULL;
+ if( fileHandle) {
+ gzf = (gzFile)(*fileHandle);
+ gzclose(gzf);
+ *fileHandle = NULL;
+ }
+}
+
+template<class T>
+void writeGrid4dRaw(const string& name, Grid4d<T>* grid) {
+ debMsg( "writing grid4d " << grid->getName() << " to raw file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("writeGrid4dRaw: can't open file " << name);
+ gzwrite(gzf, &((*grid)[0]), sizeof(T)*grid->getSizeX()*grid->getSizeY()*grid->getSizeZ()*grid->getSizeT());
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+template<class T>
+void readGrid4dRaw(const string& name, Grid4d<T>* grid) {
+ debMsg( "reading grid4d " << grid->getName() << " from raw file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("readGrid4dRaw: can't open file " << name);
+
+ IndexInt bytes = sizeof(T)*grid->getSizeX()*grid->getSizeY()*grid->getSizeZ()*grid->getSizeT();
+ IndexInt readBytes = gzread(gzf, &((*grid)[0]), bytes);
+ assertMsg(bytes==readBytes, "can't read raw file, stream length does not match, "<<bytes<<" vs "<<readBytes);
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+
+//*****************************************************************************
+// optional openvdb export
+
+#if OPENVDB==1
+
+template <class T>
+void writeGridVDB(const string& name, Grid<T>* grid) {
+ debMsg("Writing grid " << grid->getName() << " to vdb file " << name << " not yet supported!", 1);
+}
+
+template <class T>
+void readGridVDB(const string& name, Grid<T>* grid) {
+ debMsg("Reading grid " << grid->getName() << " from vdb file " << name << " not yet supported!", 1);
+}
+
+template <>
+void writeGridVDB(const string& name, Grid<Real>* grid) {
+ debMsg("Writing real grid " << grid->getName() << " to vdb file " << name, 1);
+
+ // Create an empty floating-point grid with background value 0.
+ openvdb::initialize();
+ openvdb::FloatGrid::Ptr gridVDB = openvdb::FloatGrid::create();
+ gridVDB->setTransform( openvdb::math::Transform::createLinearTransform( 1./grid->getSizeX() )); //voxel size
+
+ // Get an accessor for coordinate-based access to voxels.
+ openvdb::FloatGrid::Accessor accessor = gridVDB->getAccessor();
+
+ // Identify the grid as a level set.
+ gridVDB->setGridClass(openvdb::GRID_FOG_VOLUME);
+
+ // Name the grid "density".
+ gridVDB->setName( grid->getName() );
+
+ openvdb::io::File file(name);
+
+ FOR_IJK(*grid) {
+ openvdb::Coord xyz(i, j, k);
+ accessor.setValue(xyz, (*grid)(i, j, k));
+ }
+
+ // Add the grid pointer to a container.
+ openvdb::GridPtrVec gridsVDB;
+ gridsVDB.push_back(gridVDB);
+
+ // Write out the contents of the container.
+ file.write(gridsVDB);
+ file.close();
+};
+
+template <>
+void readGridVDB(const string& name, Grid<Real>* grid) {
+ debMsg("Reading real grid " << grid->getName() << " from vdb file " << name, 1);
+
+ openvdb::initialize();
+ openvdb::io::File file(name);
+ file.open();
+
+ openvdb::GridBase::Ptr baseGrid;
+ for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName(); ++nameIter)
+ {
+ #ifndef BLENDER
+ // Read in only the grid we are interested in.
+ if (nameIter.gridName() == grid->getName()) {
+ baseGrid = file.readGrid(nameIter.gridName());
+ } else {
+ debMsg("skipping grid " << nameIter.gridName(), 1);
+ }
+ #else
+ // For Blender, skip name check and pick first grid from loop
+ baseGrid = file.readGrid(nameIter.gridName());
+ break;
+ #endif
+ }
+ file.close();
+ openvdb::FloatGrid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::FloatGrid>(baseGrid);
+
+ openvdb::FloatGrid::Accessor accessor = gridVDB->getAccessor();
+
+ FOR_IJK(*grid) {
+ openvdb::Coord xyz(i, j, k);
+ float v = accessor.getValue(xyz);
+ (*grid)(i, j, k) = v;
+ }
+};
+
+template <>
+void writeGridVDB(const string& name, Grid<Vec3>* grid) {
+ debMsg("Writing vec3 grid " << grid->getName() << " to vdb file " << name, 1);
+
+ openvdb::initialize();
+ openvdb::Vec3SGrid::Ptr gridVDB = openvdb::Vec3SGrid::create();
+ // note , warning - velocity content currently not scaled...
+ gridVDB->setTransform( openvdb::math::Transform::createLinearTransform( 1./grid->getSizeX() )); //voxel size
+ openvdb::Vec3SGrid::Accessor accessor = gridVDB->getAccessor();
+
+ // MAC or regular vec grid?
+ if(grid->getType() & GridBase::TypeMAC) gridVDB->setGridClass(openvdb::GRID_STAGGERED);
+ else gridVDB->setGridClass(openvdb::GRID_UNKNOWN);
+
+ gridVDB->setName( grid->getName() );
+
+ openvdb::io::File file(name);
+ FOR_IJK(*grid) {
+ openvdb::Coord xyz(i, j, k);
+ Vec3 v = (*grid)(i, j, k);
+ openvdb::Vec3f vo( (float)v[0] , (float)v[1] , (float)v[2] );
+ accessor.setValue(xyz, vo);
+ }
+
+ openvdb::GridPtrVec gridsVDB;
+ gridsVDB.push_back(gridVDB);
+
+ file.write(gridsVDB);
+ file.close();
+};
+
+template <>
+void readGridVDB(const string& name, Grid<Vec3>* grid) {
+ debMsg("Reading vec3 grid " << grid->getName() << " from vdb file " << name, 1);
+
+ openvdb::initialize();
+ openvdb::io::File file(name);
+ file.open();
+
+ openvdb::GridBase::Ptr baseGrid;
+ for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName(); ++nameIter)
+ {
+ #ifndef BLENDER
+ // Read in only the grid we are interested in.
+ if (nameIter.gridName() == grid->getName()) {
+ baseGrid = file.readGrid(nameIter.gridName());
+ } else {
+ debMsg("skipping grid " << nameIter.gridName(), 1);
+ }
+ #else
+ // For Blender, skip name check and pick first grid from loop
+ baseGrid = file.readGrid(nameIter.gridName());
+ break;
+ #endif
+ }
+ file.close();
+ openvdb::Vec3SGrid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::Vec3SGrid>(baseGrid);
+
+ openvdb::Vec3SGrid::Accessor accessor = gridVDB->getAccessor();
+
+ FOR_IJK(*grid) {
+ openvdb::Coord xyz(i, j, k);
+ openvdb::Vec3f v = accessor.getValue(xyz);
+ (*grid)(i, j, k).x = (float)v[0];
+ (*grid)(i, j, k).y = (float)v[1];
+ (*grid)(i, j, k).z = (float)v[2];
+ }
+};
+
+#endif // OPENVDB==1
+
+
+//*****************************************************************************
+// npz file support (warning - read works, but write generates uncompressed npz; i.e. not recommended for large volumes)
+
+template <class T>
+void writeGridNumpy(const string& name, Grid<T>* grid) {
+# if NO_ZLIB==1
+ debMsg( "file format not supported without zlib" ,1);
+ return;
+# endif
+# if FLOATINGPOINT_PRECISION!=1
+ errMsg("writeGridNumpy: Double precision not yet supported");
+# endif
+
+ // find suffix to differentiate between npy <-> npz , TODO: check for actual "npy" string
+ std::string::size_type idx;
+ bool bUseNpz = false;
+ idx = name.rfind('.');
+ if(idx != std::string::npos) {
+ bUseNpz = name.substr(idx+1) == "npz";
+ debMsg( "Writing grid " << grid->getName() << " to npz file " << name ,1);
+ } else {
+ debMsg( "Writing grid " << grid->getName() << " to npy file " << name ,1);
+ }
+
+ // storage code
+ size_t uDim = 1;
+ if (grid->getType() & GridBase::TypeInt || grid->getType() & GridBase::TypeReal || grid->getType() & GridBase::TypeLevelset)
+ uDim = 1;
+ else if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC)
+ uDim = 3;
+ else
+ errMsg("writeGridNumpy: unknown element type");
+
+ const std::vector<size_t> shape = {static_cast<size_t>(grid->getSizeZ()), static_cast<size_t>(grid->getSizeY()), static_cast<size_t>(grid->getSizeX()), uDim};
+
+ if(bUseNpz){
+ // note, the following generates a zip file without compression
+ if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC) {
+ // cast to float* for export!
+ float* ptr = (float*)&((*grid)[0]);
+ cnpy::npz_save(name, "arr_0", ptr, shape, "w");
+ } else {
+ T* ptr = &((*grid)[0]);
+ cnpy::npz_save(name, "arr_0", ptr, shape, "w");
+ }
+ } else {
+ cnpy::npy_save(name, &grid[0], shape, "w");
+ }
+};
+
+template <class T>
+void readGridNumpy(const string& name, Grid<T>* grid) {
+# if NO_ZLIB==1
+ debMsg( "file format not supported without zlib" ,1);
+ return;
+# endif
+# if FLOATINGPOINT_PRECISION!=1
+ errMsg("readGridNumpy: Double precision not yet supported");
+# endif
+
+ // find suffix to differentiate between npy <-> npz
+ std::string::size_type idx;
+ bool bUseNpz = false;
+ idx = name.rfind('.');
+ if(idx != std::string::npos) {
+ bUseNpz = name.substr(idx+1) == "npz";
+ debMsg( "Reading grid " << grid->getName() << " as npz file " << name ,1);
+ } else {
+ debMsg( "Reading grid " << grid->getName() << " as npy file " << name ,1);
+ }
+
+ cnpy::NpyArray gridArr;
+ if(bUseNpz) {
+ cnpy::npz_t fNpz = cnpy::npz_load(name);
+ gridArr = fNpz["arr_0"];
+ } else {
+ gridArr = cnpy::npy_load(name);
+ }
+
+ // Check the file meta information
+ assertMsg (gridArr.shape[2] == grid->getSizeX() && gridArr.shape[1] == grid->getSizeY() && gridArr.shape[0] == grid->getSizeZ(), "grid dim doesn't match, " << Vec3(gridArr.shape[2], gridArr.shape[1], gridArr.shape[0]) << " vs " << grid->getSize() );
+ size_t uDim = 1;
+ if (grid->getType() & GridBase::TypeInt || grid->getType() & GridBase::TypeReal || grid->getType() & GridBase::TypeLevelset)
+ uDim = 1;
+ else if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC)
+ uDim = 3;
+ else
+ errMsg("readGridNumpy: unknown element type");
+ assertMsg (gridArr.shape[3] == uDim, "grid data dim doesn't match, " << gridArr.shape[3] << " vs " << uDim );
+
+ if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC) {
+ // treated as float* for export , thus consider 3 elements
+ assertMsg (3*gridArr.word_size == sizeof(T), "vec3 grid data size doesn't match, " << 3*gridArr.word_size << " vs " << sizeof(T));
+ } else {
+ assertMsg (gridArr.word_size == sizeof(T), "grid data size doesn't match, " << gridArr.word_size << " vs " << sizeof(T));
+ }
+
+ // copy back, TODO: beautify...
+ memcpy(&((*grid)[0]), gridArr.data<T>(), sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ() );
+};
+
+// adopted from getUniFileSize
+void getNpzFileSize(const string& name, int& x, int& y, int& z, int* t = NULL, std::string* info = NULL) {
+ x = y = z = 0;
+# if NO_ZLIB!=1
+ debMsg( "file format not supported without zlib" ,1);
+ return;
+# endif
+# if FLOATINGPOINT_PRECISION!=1
+ errMsg("getNpzFileSize: Double precision not yet supported");
+# endif
+ // find suffix to differentiate between npy <-> npz
+ cnpy::NpyArray gridArr;
+ cnpy::npz_t fNpz = cnpy::npz_load(name);
+ gridArr = fNpz["arr_0"];
+
+ z = gridArr.shape[0];
+ y = gridArr.shape[1];
+ x = gridArr.shape[2];
+ if(t) (*t) = 0; // unused for now
+}
+Vec3 getNpzFileSize(const string& name) {
+ int x,y,z;
+ getNpzFileSize(name, x,y,z);
+ return Vec3( Real(x), Real(y), Real(z) );
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getNpzFileSize" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const string& name = _args.get<string >("name",0,&_lock); _retval = toPy(getNpzFileSize(name)); _args.check(); }
+ pbFinalizePlugin(parent,"getNpzFileSize", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getNpzFileSize",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getNpzFileSize ("","getNpzFileSize",_W_2);
+extern "C" {
+ void PbRegister_getNpzFileSize() {
+ KEEP_UNUSED(_RP_getNpzFileSize); }
+ }
+
+
+
+
+//*****************************************************************************
+// helper functions
+
+
+void quantizeReal(Real& v, const Real step) {
+ int q = int(v / step + step*0.5);
+ double qd = q * (double)step;
+ v = (Real)qd;
+}
+ struct knQuantize : public KernelBase {
+ knQuantize(Grid<Real>& grid, Real step) : KernelBase(&grid,0) ,grid(grid),step(step) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& grid, Real step ) {
+ quantizeReal( grid(idx), step );
+} inline Grid<Real>& getArg0() {
+ return grid; }
+ typedef Grid<Real> type0;inline Real& getArg1() {
+ return step; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knQuantize ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,grid,step); }
+ }
+ Grid<Real>& grid; Real step; }
+;
+void quantizeGrid(Grid<Real>& grid, Real step) { knQuantize(grid,step); } static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "quantizeGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& grid = *_args.getPtr<Grid<Real> >("grid",0,&_lock); Real step = _args.get<Real >("step",1,&_lock); _retval = getPyNone(); quantizeGrid(grid,step); _args.check(); }
+ pbFinalizePlugin(parent,"quantizeGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("quantizeGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_quantizeGrid ("","quantizeGrid",_W_3);
+extern "C" {
+ void PbRegister_quantizeGrid() {
+ KEEP_UNUSED(_RP_quantizeGrid); }
+ }
+
+
+
+ struct knQuantizeVec3 : public KernelBase {
+ knQuantizeVec3(Grid<Vec3>& grid, Real step) : KernelBase(&grid,0) ,grid(grid),step(step) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Vec3>& grid, Real step ) {
+ for(int c=0; c<3; ++c) quantizeReal( grid(idx)[c], step );
+} inline Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Real& getArg1() {
+ return step; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knQuantizeVec3 ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,grid,step); }
+ }
+ Grid<Vec3>& grid; Real step; }
+;
+void quantizeGridVec3(Grid<Vec3>& grid, Real step) { knQuantizeVec3(grid,step); } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "quantizeGridVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& grid = *_args.getPtr<Grid<Vec3> >("grid",0,&_lock); Real step = _args.get<Real >("step",1,&_lock); _retval = getPyNone(); quantizeGridVec3(grid,step); _args.check(); }
+ pbFinalizePlugin(parent,"quantizeGridVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("quantizeGridVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_quantizeGridVec3 ("","quantizeGridVec3",_W_4);
+extern "C" {
+ void PbRegister_quantizeGridVec3() {
+ KEEP_UNUSED(_RP_quantizeGridVec3); }
+ }
+
+
+
+
+
+// explicit instantiation
+template void writeGridRaw<int> (const string& name, Grid<int>* grid);
+template void writeGridRaw<Real>(const string& name, Grid<Real>* grid);
+template void writeGridRaw<Vec3>(const string& name, Grid<Vec3>* grid);
+template void writeGridUni<int> (const string& name, Grid<int>* grid);
+template void writeGridUni<Real>(const string& name, Grid<Real>* grid);
+template void writeGridUni<Vec3>(const string& name, Grid<Vec3>* grid);
+template void writeGridVol<int> (const string& name, Grid<int>* grid);
+template void writeGridVol<Vec3>(const string& name, Grid<Vec3>* grid);
+template void writeGridTxt<int> (const string& name, Grid<int>* grid);
+template void writeGridTxt<Real>(const string& name, Grid<Real>* grid);
+template void writeGridTxt<Vec3>(const string& name, Grid<Vec3>* grid);
+
+template void readGridRaw<int> (const string& name, Grid<int>* grid);
+template void readGridRaw<Real> (const string& name, Grid<Real>* grid);
+template void readGridRaw<Vec3> (const string& name, Grid<Vec3>* grid);
+template void readGridUni<int> (const string& name, Grid<int>* grid);
+template void readGridUni<Real> (const string& name, Grid<Real>* grid);
+template void readGridUni<Vec3> (const string& name, Grid<Vec3>* grid);
+template void readGridVol<int> (const string& name, Grid<int>* grid);
+template void readGridVol<Vec3> (const string& name, Grid<Vec3>* grid);
+
+template void readGrid4dUni<int> (const string& name, Grid4d<int>* grid, int readTslice, Grid4d<int>* slice, void** fileHandle);
+template void readGrid4dUni<Real> (const string& name, Grid4d<Real>* grid, int readTslice, Grid4d<Real>* slice, void** fileHandle);
+template void readGrid4dUni<Vec3> (const string& name, Grid4d<Vec3>* grid, int readTslice, Grid4d<Vec3>* slice, void** fileHandle);
+template void readGrid4dUni<Vec4> (const string& name, Grid4d<Vec4>* grid, int readTslice, Grid4d<Vec4>* slice, void** fileHandle);
+template void writeGrid4dUni<int> (const string& name, Grid4d<int>* grid);
+template void writeGrid4dUni<Real>(const string& name, Grid4d<Real>* grid);
+template void writeGrid4dUni<Vec3>(const string& name, Grid4d<Vec3>* grid);
+template void writeGrid4dUni<Vec4>(const string& name, Grid4d<Vec4>* grid);
+
+template void readGrid4dRaw<int> (const string& name, Grid4d<int>* grid);
+template void readGrid4dRaw<Real> (const string& name, Grid4d<Real>* grid);
+template void readGrid4dRaw<Vec3> (const string& name, Grid4d<Vec3>* grid);
+template void readGrid4dRaw<Vec4> (const string& name, Grid4d<Vec4>* grid);
+template void writeGrid4dRaw<int> (const string& name, Grid4d<int>* grid);
+template void writeGrid4dRaw<Real>(const string& name, Grid4d<Real>* grid);
+template void writeGrid4dRaw<Vec3>(const string& name, Grid4d<Vec3>* grid);
+template void writeGrid4dRaw<Vec4>(const string& name, Grid4d<Vec4>* grid);
+
+template void writeGridNumpy<int> (const string& name, Grid<int>* grid);
+template void writeGridNumpy<Real>(const string& name, Grid<Real>* grid);
+template void writeGridNumpy<Vec3>(const string& name, Grid<Vec3>* grid);
+template void readGridNumpy<int> (const string& name, Grid<int>* grid);
+template void readGridNumpy<Real> (const string& name, Grid<Real>* grid);
+template void readGridNumpy<Vec3> (const string& name, Grid<Vec3>* grid);
+
+#if OPENVDB==1
+template void writeGridVDB<int>(const string& name, Grid<int>* grid);
+template void writeGridVDB<Vec3>(const string& name, Grid<Vec3>* grid);
+template void writeGridVDB<Real>(const string& name, Grid<Real>* grid);
+
+template void readGridVDB<int>(const string& name, Grid<int>* grid);
+template void readGridVDB<Vec3>(const string& name, Grid<Vec3>* grid);
+template void readGridVDB<Real>(const string& name, Grid<Real>* grid);
+#endif // OPENVDB==1
+
+} //namespace
+
+namespace Manta {
+
+}
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/iomeshes.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/iomeshes.cpp
new file mode 100644
index 00000000000..4bd336c8d48
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/iomeshes.cpp
@@ -0,0 +1,459 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#if NO_ZLIB!=1
+extern "C" {
+#include <zlib.h>
+}
+#endif
+
+#include "mantaio.h"
+#include "grid.h"
+#include "mesh.h"
+#include "vortexsheet.h"
+#include <cstring>
+
+using namespace std;
+
+namespace Manta {
+
+static const int STR_LEN_PDATA = 256;
+
+//! mdata uni header, v3 (similar to grid header and mdata header)
+typedef struct {
+ int dim; // number of vertices
+ int dimX, dimY, dimZ; // underlying solver resolution (all data in local coordinates!)
+ int elementType, bytesPerElement; // type id and byte size
+ char info[STR_LEN_PDATA]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+} UniMeshHeader;
+
+//*****************************************************************************
+// conversion functions for double precision
+// (note - uni files always store single prec. values)
+//*****************************************************************************
+
+#if NO_ZLIB!=1
+
+template <class T>
+void mdataConvertWrite( gzFile& gzf, MeshDataImpl<T>& mdata, void* ptr, UniMeshHeader& head) {
+ errMsg("mdataConvertWrite: unknown type, not yet supported");
+}
+
+template <>
+void mdataConvertWrite( gzFile& gzf, MeshDataImpl<int>& mdata, void* ptr, UniMeshHeader& head) {
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ gzwrite(gzf, &mdata[0], sizeof(int)*head.dim);
+}
+template <>
+void mdataConvertWrite( gzFile& gzf, MeshDataImpl<double>& mdata, void* ptr, UniMeshHeader& head) {
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<mdata.size(); ++i,++ptrf) {
+ *ptrf = (float)mdata[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float)* head.dim);
+}
+template <>
+void mdataConvertWrite( gzFile& gzf, MeshDataImpl<Vec3>& mdata, void* ptr, UniMeshHeader& head) {
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<mdata.size(); ++i) {
+ for(int c=0; c<3; ++c) { *ptrf = (float)mdata[i][c]; ptrf++; }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) *head.dim);
+}
+
+
+template <class T>
+void mdataReadConvert(gzFile& gzf, MeshDataImpl<T>& grid, void* ptr, int bytesPerElement) {
+ errMsg("mdataReadConvert: unknown mdata type, not yet supported");
+}
+
+template <>
+void mdataReadConvert<int>(gzFile& gzf, MeshDataImpl<int>& mdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(int)*mdata.size());
+ assertMsg (bytesPerElement == sizeof(int), "mdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(int) );
+ // int dont change in double precision mode - copy over
+ memcpy(&(mdata[0]), ptr, sizeof(int) * mdata.size() );
+}
+
+template <>
+void mdataReadConvert<double>(gzFile& gzf, MeshDataImpl<double>& mdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(float)*mdata.size());
+ assertMsg (bytesPerElement == sizeof(float), "mdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<mdata.size(); ++i,++ptrf) {
+ mdata[i] = double(*ptrf);
+ }
+}
+
+template <>
+void mdataReadConvert<Vec3>(gzFile& gzf, MeshDataImpl<Vec3>& mdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(Vector3D<float>)*mdata.size());
+ assertMsg (bytesPerElement == sizeof(Vector3D<float>), "mdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(Vector3D<float>) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<mdata.size(); ++i) {
+ Vec3 v;
+ for(int c=0; c<3; ++c) { v[c] = double(*ptrf); ptrf++; }
+ mdata[i] = v;
+ }
+}
+
+
+#endif // NO_ZLIB!=1
+
+//*****************************************************************************
+// mesh data
+//*****************************************************************************
+
+void readBobjFile(const string& name, Mesh* mesh, bool append) {
+ debMsg( "reading mesh file " << name ,1);
+ if (!append)
+ mesh->clear();
+ else
+ errMsg("readBobj: append not yet implemented!");
+
+# if NO_ZLIB!=1
+ const Real dx = mesh->getParent()->getDx();
+ const Vec3 gs = toVec3( mesh->getParent()->getGridSize() );
+
+ gzFile gzf = gzopen(name.c_str(), "rb1"); // do some compression
+ if (!gzf)
+ errMsg("readBobj: unable to open file");
+
+ // read vertices
+ int num = 0;
+ gzread(gzf, &num, sizeof(int));
+ mesh->resizeNodes(num);
+ debMsg( "read mesh , verts "<<num,1);
+ for (int i=0; i<num; i++) {
+ Vector3D<float> pos;
+ gzread(gzf, &pos.value[0], sizeof(float)*3);
+ mesh->nodes(i).pos = toVec3(pos);
+
+ // convert to grid space
+ mesh->nodes(i).pos /= dx;
+ mesh->nodes(i).pos += gs*0.5;
+ }
+
+ // normals
+ num = 0;
+ gzread(gzf, &num, sizeof(int));
+ for (int i=0; i<num; i++) {
+ Vector3D<float> pos;
+ gzread(gzf, &pos.value[0], sizeof(float)*3);
+ mesh->nodes(i).normal = toVec3(pos);
+ }
+
+ // read tris
+ num = 0;
+ gzread(gzf, &num, sizeof(int));
+ mesh->resizeTris( num );
+ for(int t=0; t<num; t++) {
+ for(int j=0; j<3; j++) {
+ int trip = 0;
+ gzread(gzf, &trip, sizeof(int));
+ mesh->tris(t).c[j] = trip;
+ }
+ }
+ // note - vortex sheet info ignored for now... (see writeBobj)
+ gzclose( gzf );
+ debMsg( "read mesh , triangles "<<mesh->numTris()<<", vertices "<<mesh->numNodes()<<" ",1 );
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+void writeBobjFile(const string& name, Mesh* mesh) {
+ debMsg( "writing mesh file " << name ,1);
+# if NO_ZLIB!=1
+ const Real dx = mesh->getParent()->getDx();
+ const Vec3i gs = mesh->getParent()->getGridSize();
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf)
+ errMsg("writeBobj: unable to open file");
+
+ // write vertices
+ int numVerts = mesh->numNodes();
+ gzwrite(gzf, &numVerts, sizeof(int));
+ for (int i=0; i<numVerts; i++) {
+ Vector3D<float> pos = toVec3f(mesh->nodes(i).pos);
+ // normalize to unit cube around 0
+ pos -= toVec3f(gs)*0.5;
+ pos *= dx;
+ gzwrite(gzf, &pos.value[0], sizeof(float)*3);
+ }
+
+ // normals
+ mesh->computeVertexNormals();
+ gzwrite(gzf, &numVerts, sizeof(int));
+ for (int i=0; i<numVerts; i++) {
+ Vector3D<float> pos = toVec3f(mesh->nodes(i).normal);
+ gzwrite(gzf, &pos.value[0], sizeof(float)*3);
+ }
+
+ // write tris
+ int numTris = mesh->numTris();
+ gzwrite(gzf, &numTris, sizeof(int));
+ for(int t=0; t<numTris; t++) {
+ for(int j=0; j<3; j++) {
+ int trip = mesh->tris(t).c[j];
+ gzwrite(gzf, &trip, sizeof(int));
+ }
+ }
+
+ // per vertex smoke densities
+ if (mesh->getType() == Mesh::TypeVortexSheet) {
+ VortexSheetMesh* vmesh = (VortexSheetMesh*) mesh;
+ int densId[4] = {0, 'v','d','e'};
+ gzwrite(gzf, &densId[0], sizeof(int) * 4);
+
+ // compute densities
+ vector<float> triDensity(numTris);
+ for (int tri=0; tri < numTris; tri++) {
+ Real area = vmesh->getFaceArea(tri);
+ if (area>0)
+ triDensity[tri] = vmesh->sheet(tri).smokeAmount;
+ }
+
+ // project triangle data to vertex
+ vector<int> triPerVertex(numVerts);
+ vector<float> density(numVerts);
+ for (int tri=0; tri < numTris; tri++) {
+ for (int c=0; c<3; c++) {
+ int vertex = mesh->tris(tri).c[c];
+ density[vertex] += triDensity[tri];
+ triPerVertex[vertex]++;
+ }
+ }
+
+ // averaged smoke densities
+ for(int point=0; point<numVerts; point++) {
+ float dens = 0;
+ if (triPerVertex[point]>0)
+ dens = density[point] / triPerVertex[point];
+ gzwrite(gzf, &dens, sizeof(float));
+ }
+ }
+
+ // vertex flags
+ if (mesh->getType() == Mesh::TypeVortexSheet) {
+ int Id[4] = {0, 'v','x','f'};
+ gzwrite(gzf, &Id[0], sizeof(int) * 4);
+
+ // averaged smoke densities
+ for(int point=0; point<numVerts; point++) {
+ float alpha = (mesh->nodes(point).flags & Mesh::NfMarked) ? 1: 0;
+ gzwrite(gzf, &alpha, sizeof(float));
+ }
+ }
+
+ gzclose( gzf );
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+void readObjFile(const std::string& name, Mesh* mesh, bool append) {
+ ifstream ifs (name.c_str());
+
+ if (!ifs.good())
+ errMsg("can't open file '" + name + "'");
+
+ if (!append)
+ mesh->clear();
+ int nodebase = mesh->numNodes();
+ int cnt = nodebase;
+ while(ifs.good() && !ifs.eof()) {
+ string id;
+ ifs >> id;
+
+ if (id[0] == '#') {
+ // comment
+ getline(ifs, id);
+ continue;
+ }
+ if (id == "vt") {
+ // tex coord, ignore
+ } else if (id == "vn") {
+ // normals
+ if (!mesh->numNodes())
+ errMsg("invalid amount of nodes");
+ Node n = mesh->nodes(cnt);
+ ifs >> n.normal.x >> n.normal.y >> n.normal.z;
+ cnt++;
+ } else if (id == "v") {
+ // vertex
+ Node n;
+ ifs >> n.pos.x >> n.pos.y >> n.pos.z;
+ mesh->addNode(n);
+ } else if (id == "g") {
+ // group
+ string group;
+ ifs >> group;
+ } else if (id == "f") {
+ // face
+ string face;
+ Triangle t;
+ for (int i=0; i<3; i++) {
+ ifs >> face;
+ if (face.find('/') != string::npos)
+ face = face.substr(0, face.find('/')); // ignore other indices
+ int idx = atoi(face.c_str()) - 1;
+ if (idx < 0)
+ errMsg("invalid face encountered");
+ idx += nodebase;
+ t.c[i] = idx;
+ }
+ mesh->addTri(t);
+ } else {
+ // whatever, ignore
+ }
+ // kill rest of line
+ getline(ifs, id);
+ }
+ ifs.close();
+}
+
+// write regular .obj file, in line with bobj.gz output (but only verts & tris for now)
+void writeObjFile(const string& name, Mesh* mesh) {
+ const Real dx = mesh->getParent()->getDx();
+ const Vec3i gs = mesh->getParent()->getGridSize();
+
+ ofstream ofs(name.c_str());
+ if (!ofs.good())
+ errMsg("writeObjFile: can't open file " << name);
+
+ ofs << "o MantaMesh\n";
+
+ // write vertices
+ int numVerts = mesh->numNodes();
+ for (int i=0; i<numVerts; i++) {
+ Vector3D<float> pos = toVec3f(mesh->nodes(i).pos);
+ // normalize to unit cube around 0
+ pos -= toVec3f(gs)*0.5;
+ pos *= dx;
+ ofs << "v "<< pos.value[0] <<" "<< pos.value[1] <<" "<< pos.value[2] <<" "<< "\n";
+ }
+
+ // write normals
+ for (int i=0; i<numVerts; i++) {
+ Vector3D<float> n = toVec3f(mesh->nodes(i).normal);
+ // normalize to unit cube around 0
+ ofs << "vn "<< n.value[0] <<" "<< n.value[1] <<" "<< n.value[2] <<" "<< "\n";
+ }
+
+ // write tris
+ int numTris = mesh->numTris();
+ for(int t=0; t<numTris; t++) {
+ ofs << "f "<< (mesh->tris(t).c[0]+1) <<" "<< (mesh->tris(t).c[1]+1) <<" "<< (mesh->tris(t).c[2]+1) <<" "<< "\n";
+ }
+
+ ofs.close();
+}
+
+template <class T>
+void readMdataUni(const std::string& name, MeshDataImpl<T>* mdata ) {
+ debMsg( "reading mesh data " << mdata->getName() << " from uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("can't open file " << name );
+
+ char ID[5]={0,0,0,0,0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "MD01")) {
+ UniMeshHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniMeshHeader)) == sizeof(UniMeshHeader), "can't read file, no header present");
+ assertMsg (head.dim == mdata->size() , "mdata size doesn't match");
+# if FLOATINGPOINT_PRECISION!=1
+ MeshDataImpl<T> temp(mdata->getParent());
+ temp.resize( mdata->size() );
+ mdataReadConvert<T>(gzf, *mdata, &(temp[0]), head.bytesPerElement);
+# else
+ assertMsg ( ((head.bytesPerElement == sizeof(T)) && (head.elementType==1) ), "mdata type doesn't match");
+ IndexInt bytes = sizeof(T)*head.dim;
+ IndexInt readBytes = gzread(gzf, &(mdata->get(0)), sizeof(T)*head.dim);
+ assertMsg(bytes==readBytes, "can't read uni file, stream length does not match, "<<bytes<<" vs "<<readBytes );
+# endif
+ }
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+template <class T>
+void writeMdataUni(const std::string& name, MeshDataImpl<T>* mdata ) {
+ debMsg( "writing mesh data " << mdata->getName() << " to uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ char ID[5] = "MD01";
+ UniMeshHeader head;
+ head.dim = mdata->size();
+ head.bytesPerElement = sizeof(T);
+ head.elementType = 1; // 1 for mesh data, todo - add sub types?
+ snprintf( head.info, STR_LEN_PDATA, "%s", buildInfoString().c_str() );
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file " << name);
+ gzwrite(gzf, ID, 4);
+
+# if FLOATINGPOINT_PRECISION!=1
+ // always write float values, even if compiled with double precision (as for grids)
+ MeshDataImpl<T> temp(mdata->getParent());
+ temp.resize( mdata->size() );
+ mdataConvertWrite( gzf, *mdata, &(temp[0]), head);
+# else
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ gzwrite(gzf, &(mdata->get(0)), sizeof(T)*head.dim);
+# endif
+ gzclose(gzf);
+
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+// explicit instantiation
+template void writeMdataUni<int> (const std::string& name, MeshDataImpl<int>* mdata );
+template void writeMdataUni<Real>(const std::string& name, MeshDataImpl<Real>* mdata );
+template void writeMdataUni<Vec3>(const std::string& name, MeshDataImpl<Vec3>* mdata );
+template void readMdataUni<int> (const std::string& name, MeshDataImpl<int>* mdata );
+template void readMdataUni<Real> (const std::string& name, MeshDataImpl<Real>* mdata );
+template void readMdataUni<Vec3> (const std::string& name, MeshDataImpl<Vec3>* mdata );
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/ioparticles.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/ioparticles.cpp
new file mode 100644
index 00000000000..20c89aabe90
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/ioparticles.cpp
@@ -0,0 +1,310 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <cstring>
+#if NO_ZLIB!=1
+extern "C" {
+#include <zlib.h>
+}
+#endif
+
+#include "mantaio.h"
+#include "grid.h"
+#include "particle.h"
+#include "vector4d.h"
+#include "grid4d.h"
+
+using namespace std;
+
+namespace Manta {
+
+static const int STR_LEN_PDATA = 256;
+
+//! pdata uni header, v3 (similar to grid header)
+typedef struct {
+ int dim; // number of partilces
+ int dimX, dimY, dimZ; // underlying solver resolution (all data in local coordinates!)
+ int elementType, bytesPerElement; // type id and byte size
+ char info[STR_LEN_PDATA]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+} UniPartHeader;
+
+
+//*****************************************************************************
+// conversion functions for double precision
+// (note - uni files always store single prec. values)
+//*****************************************************************************
+
+#if NO_ZLIB!=1
+
+template <class T>
+void pdataConvertWrite( gzFile& gzf, ParticleDataImpl<T>& pdata, void* ptr, UniPartHeader& head) {
+ errMsg("pdataConvertWrite: unknown type, not yet supported");
+}
+
+template <>
+void pdataConvertWrite( gzFile& gzf, ParticleDataImpl<int>& pdata, void* ptr, UniPartHeader& head) {
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &pdata[0], sizeof(int)*head.dim);
+}
+template <>
+void pdataConvertWrite( gzFile& gzf, ParticleDataImpl<double>& pdata, void* ptr, UniPartHeader& head) {
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<pdata.size(); ++i,++ptrf) {
+ *ptrf = (float)pdata[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float)* head.dim);
+}
+template <>
+void pdataConvertWrite( gzFile& gzf, ParticleDataImpl<Vec3>& pdata, void* ptr, UniPartHeader& head) {
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<pdata.size(); ++i) {
+ for(int c=0; c<3; ++c) { *ptrf = (float)pdata[i][c]; ptrf++; }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) *head.dim);
+}
+
+
+template <class T>
+void pdataReadConvert(gzFile& gzf, ParticleDataImpl<T>& grid, void* ptr, int bytesPerElement) {
+ errMsg("pdataReadConvert: unknown pdata type, not yet supported");
+}
+
+template <>
+void pdataReadConvert<int>(gzFile& gzf, ParticleDataImpl<int>& pdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(int)*pdata.size());
+ assertMsg (bytesPerElement == sizeof(int), "pdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(int) );
+ // int dont change in double precision mode - copy over
+ memcpy(&(pdata[0]), ptr, sizeof(int) * pdata.size() );
+}
+
+template <>
+void pdataReadConvert<double>(gzFile& gzf, ParticleDataImpl<double>& pdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(float)*pdata.size());
+ assertMsg (bytesPerElement == sizeof(float), "pdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<pdata.size(); ++i,++ptrf) {
+ pdata[i] = double(*ptrf);
+ }
+}
+
+template <>
+void pdataReadConvert<Vec3>(gzFile& gzf, ParticleDataImpl<Vec3>& pdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(Vector3D<float>)*pdata.size());
+ assertMsg (bytesPerElement == sizeof(Vector3D<float>), "pdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(Vector3D<float>) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<pdata.size(); ++i) {
+ Vec3 v;
+ for(int c=0; c<3; ++c) { v[c] = double(*ptrf); ptrf++; }
+ pdata[i] = v;
+ }
+}
+
+
+#endif // NO_ZLIB!=1
+
+
+//*****************************************************************************
+// particles and particle data
+//*****************************************************************************
+
+static const int PartSysSize = sizeof(Vector3D<float>)+sizeof(int);
+
+void writeParticlesUni(const std::string& name, const BasicParticleSystem* parts ) {
+ debMsg( "writing particles " << parts->getName() << " to uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ char ID[5] = "PB02";
+ UniPartHeader head;
+ head.dim = parts->size();
+ Vec3i gridSize = parts->getParent()->getGridSize();
+ head.dimX = gridSize.x;
+ head.dimY = gridSize.y;
+ head.dimZ = gridSize.z;
+ head.bytesPerElement = PartSysSize;
+ head.elementType = 0; // 0 for base data
+ snprintf( head.info, STR_LEN_PDATA, "%s", buildInfoString().c_str() );
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file " << name);
+
+ gzwrite(gzf, ID, 4);
+# if FLOATINGPOINT_PRECISION!=1
+ // warning - hard coded conversion of byte size here...
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ for(int i=0; i<parts->size(); ++i) {
+ Vector3D<float> pos = toVec3f( (*parts)[i].pos );
+ int flag = (*parts)[i].flag;
+ gzwrite(gzf, &pos , sizeof(Vector3D<float>) );
+ gzwrite(gzf, &flag, sizeof(int) );
+ }
+# else
+ assertMsg( sizeof(BasicParticleData) == PartSysSize, "particle data size doesn't match" );
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &((*parts)[0]), PartSysSize*head.dim);
+# endif
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+void readParticlesUni(const std::string& name, BasicParticleSystem* parts ) {
+ debMsg( "reading particles " << parts->getName() << " from uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("can't open file " << name);
+
+ char ID[5]={0,0,0,0,0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "PB01")) {
+ errMsg("particle uni file format v01 not supported anymore");
+ } else if (!strcmp(ID, "PB02")) {
+ // current file format
+ UniPartHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniPartHeader)) == sizeof(UniPartHeader), "can't read file, no header present");
+ assertMsg ( ((head.bytesPerElement == PartSysSize) && (head.elementType==0) ), "particle type doesn't match");
+
+ // re-allocate all data
+ parts->resizeAll( head.dim );
+
+ assertMsg (head.dim == parts->size() , "particle size doesn't match");
+# if FLOATINGPOINT_PRECISION!=1
+ for(int i=0; i<parts->size(); ++i) {
+ Vector3D<float> pos; int flag;
+ gzread(gzf, &pos , sizeof(Vector3D<float>) );
+ gzread(gzf, &flag, sizeof(int) );
+ (*parts)[i].pos = toVec3d(pos);
+ (*parts)[i].flag = flag;
+ }
+# else
+ assertMsg( sizeof(BasicParticleData) == PartSysSize, "particle data size doesn't match" );
+ IndexInt bytes = PartSysSize*head.dim;
+ IndexInt readBytes = gzread(gzf, &(parts->getData()[0]), bytes);
+ assertMsg( bytes==readBytes, "can't read uni file, stream length does not match, "<<bytes<<" vs "<<readBytes );
+# endif
+
+ parts->transformPositions( Vec3i(head.dimX,head.dimY,head.dimZ), parts->getParent()->getGridSize() );
+ }
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+template <class T>
+void writePdataUni(const std::string& name, ParticleDataImpl<T>* pdata ) {
+ debMsg( "writing particle data " << pdata->getName() << " to uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ char ID[5] = "PD01";
+ UniPartHeader head;
+ head.dim = pdata->size();
+ Vec3i gridSize = pdata->getParent()->getGridSize();
+ head.dimX = gridSize.x;
+ head.dimY = gridSize.y;
+ head.dimZ = gridSize.z;
+ head.bytesPerElement = sizeof(T);
+ head.elementType = 1; // 1 for particle data, todo - add sub types?
+ snprintf( head.info, STR_LEN_PDATA, "%s", buildInfoString().c_str() );
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file " << name);
+ gzwrite(gzf, ID, 4);
+
+# if FLOATINGPOINT_PRECISION!=1
+ // always write float values, even if compiled with double precision (as for grids)
+ ParticleDataImpl<T> temp(pdata->getParent());
+ temp.resize( pdata->size() );
+ pdataConvertWrite( gzf, *pdata, &(temp[0]), head);
+# else
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &(pdata->get(0)), sizeof(T)*head.dim);
+# endif
+ gzclose(gzf);
+
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+template <class T>
+void readPdataUni(const std::string& name, ParticleDataImpl<T>* pdata ) {
+ debMsg( "reading particle data " << pdata->getName() << " from uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("can't open file " << name );
+
+ char ID[5]={0,0,0,0,0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "PD01")) {
+ UniPartHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniPartHeader)) == sizeof(UniPartHeader), "can't read file, no header present");
+ assertMsg (head.dim == pdata->size() , "pdata size doesn't match");
+# if FLOATINGPOINT_PRECISION!=1
+ ParticleDataImpl<T> temp(pdata->getParent());
+ temp.resize( pdata->size() );
+ pdataReadConvert<T>(gzf, *pdata, &(temp[0]), head.bytesPerElement);
+# else
+ assertMsg ( ((head.bytesPerElement == sizeof(T)) && (head.elementType==1) ), "pdata type doesn't match");
+ IndexInt bytes = sizeof(T)*head.dim;
+ IndexInt readBytes = gzread(gzf, &(pdata->get(0)), sizeof(T)*head.dim);
+ assertMsg(bytes==readBytes, "can't read uni file, stream length does not match, "<<bytes<<" vs "<<readBytes );
+# endif
+ }
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+
+
+
+// explicit instantiation
+template void writePdataUni<int> (const std::string& name, ParticleDataImpl<int>* pdata );
+template void writePdataUni<Real>(const std::string& name, ParticleDataImpl<Real>* pdata );
+template void writePdataUni<Vec3>(const std::string& name, ParticleDataImpl<Vec3>* pdata );
+template void readPdataUni<int> (const std::string& name, ParticleDataImpl<int>* pdata );
+template void readPdataUni<Real> (const std::string& name, ParticleDataImpl<Real>* pdata );
+template void readPdataUni<Vec3> (const std::string& name, ParticleDataImpl<Vec3>* pdata );
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h
new file mode 100644
index 00000000000..bac0c46e948
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h
@@ -0,0 +1,83 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#ifndef _FILEIO_H
+#define _FILEIO_H
+
+#include <string>
+
+namespace Manta {
+
+// forward decl.
+class Mesh;
+class FlagGrid;
+template<class T> class Grid;
+template<class T> class Grid4d;
+class BasicParticleSystem;
+template<class T> class ParticleDataImpl;
+template<class T> class MeshDataImpl;
+
+void writeObjFile(const std::string& name, Mesh* mesh);
+void writeBobjFile(const std::string& name, Mesh* mesh);
+void readObjFile(const std::string& name, Mesh* mesh, bool append);
+void readBobjFile(const std::string& name, Mesh* mesh, bool append);
+
+template<class T> void writeGridRaw(const std::string& name, Grid<T>* grid);
+template<class T> void writeGridUni(const std::string& name, Grid<T>* grid);
+template<class T> void writeGridVol(const std::string& name, Grid<T>* grid);
+template<class T> void writeGridTxt(const std::string& name, Grid<T>* grid);
+
+#if OPENVDB==1
+template<class T> void writeGridVDB(const std::string& name, Grid<T>* grid);
+template<class T> void readGridVDB(const std::string& name, Grid<T>* grid);
+#endif // OPENVDB==1
+template<class T> void writeGridNumpy(const std::string& name, Grid<T>* grid);
+template<class T> void readGridNumpy (const std::string& name, Grid<T>* grid);
+
+template<class T> void readGridUni (const std::string& name, Grid<T>* grid);
+template<class T> void readGridRaw (const std::string& name, Grid<T>* grid);
+template<class T> void readGridVol (const std::string& name, Grid<T>* grid);
+
+template<class T> void writeGrid4dUni(const std::string& name, Grid4d<T>* grid);
+template<class T> void readGrid4dUni (const std::string& name, Grid4d<T>* grid, int readTslice=-1, Grid4d<T>* slice=NULL, void** fileHandle=NULL);
+void readGrid4dUniCleanup(void** fileHandle);
+template<class T> void writeGrid4dRaw(const std::string& name, Grid4d<T>* grid);
+template<class T> void readGrid4dRaw (const std::string& name, Grid4d<T>* grid);
+
+void writeParticlesUni(const std::string& name, const BasicParticleSystem* parts );
+void readParticlesUni (const std::string& name, BasicParticleSystem* parts );
+
+template <class T> void writePdataUni(const std::string& name, ParticleDataImpl<T>* pdata );
+template <class T> void readPdataUni (const std::string& name, ParticleDataImpl<T>* pdata );
+
+template <class T> void writeMdataUni(const std::string& name, MeshDataImpl<T>* mdata );
+template <class T> void readMdataUni (const std::string& name, MeshDataImpl<T>* mdata );
+
+void getUniFileSize(const std::string& name, int& x, int& y, int& z, int* t = NULL, std::string* info = NULL);
+
+} // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h.reg
new file mode 100644
index 00000000000..874b2834685
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h.reg
@@ -0,0 +1 @@
+#include "fileio/mantaio.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h.reg.cpp
new file mode 100644
index 00000000000..b87835606f7
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fileio/mantaio.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "fileio/mantaio.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_18()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.cpp
new file mode 100644
index 00000000000..aae4a03196d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.cpp
@@ -0,0 +1,296 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Main class for the fluid solver
+ *
+ ******************************************************************************/
+
+#include "fluidsolver.h"
+#include "grid.h"
+#include <sstream>
+#include <fstream>
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// Gridstorage-related members
+
+template<class T>
+void FluidSolver::GridStorage<T>::free() {
+ if (used != 0)
+ errMsg("can't clean grid cache, some grids are still in use");
+ for(size_t i = 0; i<grids.size(); i++)
+ delete[] grids[i];
+ grids.clear();
+}
+template<class T>
+T* FluidSolver::GridStorage<T>::get(Vec3i size) {
+ if ((int)grids.size() <= used) {
+ debMsg("FluidSolver::GridStorage::get Allocating new "<<size.x<<","<<size.y<<","<<size.z<<" ",3);
+ grids.push_back( new T[(long long)(size.x) * size.y * size.z] );
+ }
+ if (used > 200)
+ errMsg("too many temp grids used -- are they released properly ?");
+ return grids[used++];
+}
+template<class T>
+void FluidSolver::GridStorage<T>::release(T* ptr) {
+ // rewrite pointer, as it may have changed due to swap operations
+ used--;
+ if (used < 0)
+ errMsg("temp grid inconsistency");
+ grids[used] = ptr;
+}
+
+template<> int* FluidSolver::getGridPointer<int>() {
+ return mGridsInt.get(mGridSize);
+}
+template<> Real* FluidSolver::getGridPointer<Real>() {
+ return mGridsReal.get(mGridSize);
+}
+template<> Vec3* FluidSolver::getGridPointer<Vec3>() {
+ return mGridsVec.get(mGridSize);
+}
+template<> Vec4* FluidSolver::getGridPointer<Vec4>() {
+ return mGridsVec4.get(mGridSize);
+}
+template<> void FluidSolver::freeGridPointer<int>(int *ptr) {
+ mGridsInt.release(ptr);
+}
+template<> void FluidSolver::freeGridPointer<Real>(Real* ptr) {
+ mGridsReal.release(ptr);
+}
+template<> void FluidSolver::freeGridPointer<Vec3>(Vec3* ptr) {
+ mGridsVec.release(ptr);
+}
+template<> void FluidSolver::freeGridPointer<Vec4>(Vec4* ptr) {
+ mGridsVec4.release(ptr);
+}
+
+// 4d data (work around for now, convert to 1d length)
+
+template<> int* FluidSolver::getGrid4dPointer<int>() {
+ return mGrids4dInt.get( Vec3i(mGridSize[0]*mGridSize[1],mGridSize[2],mFourthDim) );
+}
+template<> Real* FluidSolver::getGrid4dPointer<Real>() {
+ return mGrids4dReal.get( Vec3i(mGridSize[0]*mGridSize[1],mGridSize[2],mFourthDim) );
+}
+template<> Vec3* FluidSolver::getGrid4dPointer<Vec3>() {
+ return mGrids4dVec.get( Vec3i(mGridSize[0]*mGridSize[1],mGridSize[2],mFourthDim) );
+}
+template<> Vec4* FluidSolver::getGrid4dPointer<Vec4>() {
+ return mGrids4dVec4.get( Vec3i(mGridSize[0]*mGridSize[1],mGridSize[2],mFourthDim) );
+}
+template<> void FluidSolver::freeGrid4dPointer<int>(int *ptr) {
+ mGrids4dInt.release(ptr);
+}
+template<> void FluidSolver::freeGrid4dPointer<Real>(Real* ptr) {
+ mGrids4dReal.release(ptr);
+}
+template<> void FluidSolver::freeGrid4dPointer<Vec3>(Vec3* ptr) {
+ mGrids4dVec.release(ptr);
+}
+template<> void FluidSolver::freeGrid4dPointer<Vec4>(Vec4* ptr) {
+ mGrids4dVec4.release(ptr);
+}
+
+//******************************************************************************
+// FluidSolver members
+
+FluidSolver::FluidSolver(Vec3i gridsize, int dim, int fourthDim)
+ : PbClass(this), mDt(1.0), mTimeTotal(0.), mFrame(0),
+ mCflCond(1000), mDtMin(1.), mDtMax(1.), mFrameLength(1.),
+ mGridSize(gridsize), mDim(dim) , mTimePerFrame(0.), mLockDt(false), mFourthDim(fourthDim)
+{
+ if(dim==4 && mFourthDim>0) errMsg("Don't create 4D solvers, use 3D with fourth-dim parameter >0 instead.");
+ assertMsg(dim==2 || dim==3, "Only 2D and 3D solvers allowed.");
+ assertMsg(dim!=2 || gridsize.z == 1, "Trying to create 2D solver with size.z != 1");
+}
+
+FluidSolver::~FluidSolver() {
+ mGridsInt.free();
+ mGridsReal.free();
+ mGridsVec.free();
+ mGridsVec4.free();
+
+ mGrids4dInt.free();
+ mGrids4dReal.free();
+ mGrids4dVec.free();
+ mGrids4dVec4.free();
+}
+
+PbClass* FluidSolver::create(PbType t, PbTypeVec T, const string& name) {
+# if NOPYTHON!=1
+ _args.add("nocheck",true);
+ if (t.str() == "")
+ errMsg("Need to specify object type. Use e.g. Solver.create(FlagGrid, ...) or Solver.create(type=FlagGrid, ...)");
+
+ PbClass* ret = PbClass::createPyObject(t.str() + T.str(), name, _args, this);
+# else
+ PbClass* ret = NULL;
+# endif
+ return ret;
+}
+
+void FluidSolver::step() {
+ // update simulation time with adaptive time stepping
+ // (use eps value to prevent roundoff errors)
+ mTimePerFrame += mDt;
+ mTimeTotal += mDt;
+
+ if( (mTimePerFrame+VECTOR_EPSILON) >mFrameLength) {
+ mFrame++;
+
+ // re-calc total time, prevent drift...
+ mTimeTotal = (double)mFrame * mFrameLength;
+ mTimePerFrame = 0.;
+ mLockDt = false;
+ }
+
+ updateQtGui(true, mFrame,mTimeTotal, "FluidSolver::step");
+}
+
+void FluidSolver::printMemInfo() {
+ std::ostringstream msg;
+ msg << "Allocated grids: int " << mGridsInt.used <<"/"<< mGridsInt.grids.size() <<", ";
+ msg << " real "<< mGridsReal.used <<"/"<< mGridsReal.grids.size() <<", ";
+ msg << " vec3 "<< mGridsVec.used <<"/"<< mGridsVec.grids.size() <<". ";
+ msg << " vec4 "<< mGridsVec4.used <<"/"<< mGridsVec4.grids.size() <<". ";
+ if( supports4D() ) {
+ msg << "Allocated 4d grids: int " << mGrids4dInt.used <<"/"<< mGrids4dInt.grids.size() <<", ";
+ msg << " real "<< mGrids4dReal.used <<"/"<< mGrids4dReal.grids.size() <<", ";
+ msg << " vec3 "<< mGrids4dVec.used <<"/"<< mGrids4dVec.grids.size() <<". ";
+ msg << " vec4 "<< mGrids4dVec4.used <<"/"<< mGrids4dVec4.grids.size() <<". "; }
+ printf("%s\n", msg.str().c_str() );
+}
+
+//! warning, uses 10^-4 epsilon values, thus only use around "regular" FPS time scales, e.g. 30 frames per time unit
+//! pass max magnitude of current velocity as maxvel, not yet scaled by dt!
+void FluidSolver::adaptTimestep(Real maxVel)
+{
+ const Real mvt = maxVel * mDt;
+ if (!mLockDt) {
+ // calculate current timestep from maxvel, clamp range
+ mDt = std::max( std::min( mDt * (Real)(mCflCond/(mvt+1e-05)), mDtMax) , mDtMin );
+ if( (mTimePerFrame+mDt*1.05) > mFrameLength ) {
+ // within 5% of full step? add epsilon to prevent roundoff errors...
+ mDt = ( mFrameLength - mTimePerFrame ) + 1e-04;
+ }
+ else if ( (mTimePerFrame+mDt + mDtMin) > mFrameLength || (mTimePerFrame+(mDt*1.25)) > mFrameLength ) {
+ // avoid tiny timesteps and strongly varying ones, do 2 medium size ones if necessary...
+ mDt = (mFrameLength-mTimePerFrame+ 1e-04)*0.5;
+ mLockDt = true;
+ }
+ }
+ debMsg( "Frame "<<mFrame<<", max vel per step: "<<mvt<<" , dt: "<<mDt<<", frame time "<<mTimePerFrame<<"/"<<mFrameLength<<"; lock:"<<mLockDt , 2);
+
+ // sanity check
+ assertMsg( (mDt > (mDtMin/2.) ) , "Invalid dt encountered! Shouldnt happen..." );
+}
+
+//******************************************************************************
+// Generic helpers (no PYTHON funcs in general.cpp, thus they're here...)
+
+//! helper to unify printing from python scripts and printing internal messages (optionally pass debug level to control amount of output)
+void mantaMsg(const std::string& out, int level=1) {
+ debMsg( out, level );
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mantaMsg" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string& out = _args.get<std::string >("out",0,&_lock); int level = _args.getOpt<int >("level",1,1,&_lock); _retval = getPyNone(); mantaMsg(out,level); _args.check(); }
+ pbFinalizePlugin(parent,"mantaMsg", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mantaMsg",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mantaMsg ("","mantaMsg",_W_0);
+extern "C" {
+ void PbRegister_mantaMsg() {
+ KEEP_UNUSED(_RP_mantaMsg); }
+ }
+
+
+
+std::string printBuildInfo() {
+ string infoString = buildInfoString();
+ debMsg( "Build info: "<<infoString.c_str()<<" ",1);
+ return infoString;
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "printBuildInfo" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; _retval = toPy(printBuildInfo()); _args.check(); }
+ pbFinalizePlugin(parent,"printBuildInfo", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("printBuildInfo",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_printBuildInfo ("","printBuildInfo",_W_1);
+extern "C" {
+ void PbRegister_printBuildInfo() {
+ KEEP_UNUSED(_RP_printBuildInfo); }
+ }
+
+
+
+//! set debug level for messages (0 off, 1 regular, higher = more, up to 10)
+void setDebugLevel(int level=1) {
+ gDebugLevel = level;
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setDebugLevel" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; int level = _args.getOpt<int >("level",0,1,&_lock); _retval = getPyNone(); setDebugLevel(level); _args.check(); }
+ pbFinalizePlugin(parent,"setDebugLevel", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setDebugLevel",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setDebugLevel ("","setDebugLevel",_W_2);
+extern "C" {
+ void PbRegister_setDebugLevel() {
+ KEEP_UNUSED(_RP_setDebugLevel); }
+ }
+
+
+
+//! helper function to check for numpy compilation
+void assertNumpy() {
+#if NUMPY==1
+ // all good, nothing to do...
+#else
+ errMsg("This scene requires numpy support. Enable compilation in cmake with \"-DNUMPY=1\" ");
+#endif
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "assertNumpy" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; _retval = getPyNone(); assertNumpy(); _args.check(); }
+ pbFinalizePlugin(parent,"assertNumpy", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("assertNumpy",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_assertNumpy ("","assertNumpy",_W_3);
+extern "C" {
+ void PbRegister_assertNumpy() {
+ KEEP_UNUSED(_RP_assertNumpy); }
+ }
+
+
+
+} // manta
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h
new file mode 100644
index 00000000000..a89a3ed5ccf
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h
@@ -0,0 +1,220 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Main class for the fluid solver
+ *
+ ******************************************************************************/
+
+#ifndef _FLUIDSOLVER_H
+#define _FLUIDSOLVER_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "vector4d.h"
+#include <vector>
+#include <map>
+
+namespace Manta {
+
+//! Encodes grid size, timstep etc.
+
+class FluidSolver : public PbClass {public:
+ FluidSolver(Vec3i gridSize, int dim=3, int fourthDim=-1); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "FluidSolver::FluidSolver" , !noTiming ); {
+ ArgLocker _lock; Vec3i gridSize = _args.get<Vec3i >("gridSize",0,&_lock); int dim = _args.getOpt<int >("dim",1,3,&_lock); int fourthDim = _args.getOpt<int >("fourthDim",2,-1,&_lock); obj = new FluidSolver(gridSize,dim,fourthDim); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"FluidSolver::FluidSolver" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::FluidSolver",e.what()); return -1; }
+ }
+
+ virtual ~FluidSolver();
+
+ // accessors
+ Vec3i getGridSize() { return mGridSize; } static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FluidSolver::getGridSize" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getGridSize()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FluidSolver::getGridSize" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::getGridSize",e.what()); return 0; }
+ }
+
+ inline Real getDt() { return mDt; }
+ inline Real getDx() { return 1.0 / mGridSize.max(); }
+ inline Real getTime() { return mTimeTotal; }
+ inline Real getFrameLength() { return mFrameLength; }
+
+ //! Check dimensionality
+ inline bool is2D() const { return mDim==2; }
+ //! Check dimensionality (3d or above)
+ inline bool is3D() const { return mDim==3; }
+
+ void printMemInfo(); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FluidSolver::printMemInfo" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->printMemInfo(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FluidSolver::printMemInfo" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::printMemInfo",e.what()); return 0; }
+ }
+
+
+ //! Advance the solver one timestep, update GUI if present
+ void step(); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FluidSolver::step" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->step(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FluidSolver::step" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::step",e.what()); return 0; }
+ }
+
+
+ //! Update the timestep size based on given maximal velocity magnitude
+ void adaptTimestep(Real maxVel); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FluidSolver::adaptTimestep" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real maxVel = _args.get<Real >("maxVel",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->adaptTimestep(maxVel); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FluidSolver::adaptTimestep" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::adaptTimestep",e.what()); return 0; }
+ }
+
+
+ //! create a object with the solver as its parent
+ PbClass* create(PbType type, PbTypeVec T=PbTypeVec(),const std::string& name = ""); static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FluidSolver::create" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; PbType type = _args.get<PbType >("type",0,&_lock); PbTypeVec T = _args.getOpt<PbTypeVec >("T",1,PbTypeVec(),&_lock); const std::string& name = _args.getOpt<std::string >("name",2,"",&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->create(type,T,name)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FluidSolver::create" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::create",e.what()); return 0; }
+ }
+
+
+ // temp grid and plugin functions: you shouldn't call this manually
+ template<class T> T* getGridPointer();
+ template<class T> void freeGridPointer(T* ptr);
+
+ //! expose animation time to python
+ Real mDt;static PyObject* _GET_mDt(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mDt); }
+ static int _SET_mDt(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mDt = fromPy<Real >(val); return 0; }
+
+ Real mTimeTotal;static PyObject* _GET_mTimeTotal(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mTimeTotal); }
+ static int _SET_mTimeTotal(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mTimeTotal = fromPy<Real >(val); return 0; }
+
+ int mFrame;static PyObject* _GET_mFrame(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mFrame); }
+ static int _SET_mFrame(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mFrame = fromPy<int >(val); return 0; }
+
+ //! parameters for adaptive time stepping
+ Real mCflCond;static PyObject* _GET_mCflCond(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mCflCond); }
+ static int _SET_mCflCond(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mCflCond = fromPy<Real >(val); return 0; }
+
+ Real mDtMin;static PyObject* _GET_mDtMin(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mDtMin); }
+ static int _SET_mDtMin(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mDtMin = fromPy<Real >(val); return 0; }
+
+ Real mDtMax;static PyObject* _GET_mDtMax(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mDtMax); }
+ static int _SET_mDtMax(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mDtMax = fromPy<Real >(val); return 0; }
+
+ Real mFrameLength;static PyObject* _GET_mFrameLength(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mFrameLength); }
+ static int _SET_mFrameLength(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mFrameLength = fromPy<Real >(val); return 0; }
+
+#ifdef BLENDER
+ //! Blender needs access in order to restore value in new solver object
+ Real mTimePerFrame;static PyObject* _GET_mTimePerFrame(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mTimePerFrame); }
+ static int _SET_mTimePerFrame(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mTimePerFrame = fromPy<Real >(val); return 0; }
+
+#endif
+
+protected:
+ Vec3i mGridSize;
+ const int mDim;
+ bool mLockDt;
+#ifndef BLENDER
+ //! Blender needs public access to this field, see above
+ Real mTimePerFrame;
+#endif
+
+ //! subclass for managing grid memory
+ //! stored as a stack to allow fast allocation
+ template<class T> struct GridStorage {
+ GridStorage() : used(0) {}
+ T* get(Vec3i size);
+ void free();
+ void release(T* ptr);
+
+ std::vector<T*> grids;
+ int used;
+ };
+
+ //! memory for regular (3d) grids
+ GridStorage<int> mGridsInt;
+ GridStorage<Real> mGridsReal;
+ GridStorage<Vec3> mGridsVec;
+
+
+ //! 4d data section, only required for simulations working with space-time data
+
+public:
+ //! 4D enabled? note, there's intentionally no "is4D" function, there are only 3D solvers that also support 4D of a certain size
+ inline bool supports4D() const { return mFourthDim>0; }
+ //! fourth dimension size
+ inline int getFourthDim() const { return mFourthDim; }
+ //! 4d data allocation
+ template<class T> T* getGrid4dPointer();
+ template<class T> void freeGrid4dPointer(T* ptr);
+
+protected:
+
+ //! 4d size. Note - 4d is not treated like going from 2d to 3d! 4D grids are a separate data type. Normally all
+ //! grids are forced to have the same size. In contrast, a solver can create and work with 3D as
+ //! well as 4D grids, when fourth-dim is >0.
+ int mFourthDim;
+
+ //! 4d grid storage
+ GridStorage<Vec4> mGridsVec4;
+ GridStorage<int> mGrids4dInt;
+ GridStorage<Real> mGrids4dReal;
+ GridStorage<Vec3> mGrids4dVec; GridStorage<Vec4> mGrids4dVec4; public: PbArgs _args; }
+#define _C_FluidSolver
+;
+
+}
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h.reg
new file mode 100644
index 00000000000..68ed956e40d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h.reg
@@ -0,0 +1,17 @@
+#include "fluidsolver.h"
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","Solver","PbClass"); template<> const char* Namify<FluidSolver >::S = "FluidSolver";
+>FluidSolver^
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","FluidSolver",FluidSolver::_W_0);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","getGridSize",FluidSolver::_W_1);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","printMemInfo",FluidSolver::_W_2);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","step",FluidSolver::_W_3);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","adaptTimestep",FluidSolver::_W_4);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","create",FluidSolver::_W_5);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","timestep",FluidSolver::_GET_mDt,FluidSolver::_SET_mDt);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","timeTotal",FluidSolver::_GET_mTimeTotal,FluidSolver::_SET_mTimeTotal);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","frame",FluidSolver::_GET_mFrame,FluidSolver::_SET_mFrame);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","cfl",FluidSolver::_GET_mCflCond,FluidSolver::_SET_mCflCond);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","timestepMin",FluidSolver::_GET_mDtMin,FluidSolver::_SET_mDtMin);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","timestepMax",FluidSolver::_GET_mDtMax,FluidSolver::_SET_mDtMax);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","frameLength",FluidSolver::_GET_mFrameLength,FluidSolver::_SET_mFrameLength);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","timePerFrame",FluidSolver::_GET_mTimePerFrame,FluidSolver::_SET_mTimePerFrame);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h.reg.cpp
new file mode 100644
index 00000000000..9ad461fb974
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/fluidsolver.h.reg.cpp
@@ -0,0 +1,50 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "fluidsolver.h"
+namespace Manta {
+#ifdef _C_FluidSolver
+ static const Pb::Register _R_6 ("FluidSolver","Solver","PbClass"); template<> const char* Namify<FluidSolver >::S = "FluidSolver";
+ static const Pb::Register _R_7 ("FluidSolver","FluidSolver",FluidSolver::_W_0);
+ static const Pb::Register _R_8 ("FluidSolver","getGridSize",FluidSolver::_W_1);
+ static const Pb::Register _R_9 ("FluidSolver","printMemInfo",FluidSolver::_W_2);
+ static const Pb::Register _R_10 ("FluidSolver","step",FluidSolver::_W_3);
+ static const Pb::Register _R_11 ("FluidSolver","adaptTimestep",FluidSolver::_W_4);
+ static const Pb::Register _R_12 ("FluidSolver","create",FluidSolver::_W_5);
+ static const Pb::Register _R_13 ("FluidSolver","timestep",FluidSolver::_GET_mDt,FluidSolver::_SET_mDt);
+ static const Pb::Register _R_14 ("FluidSolver","timeTotal",FluidSolver::_GET_mTimeTotal,FluidSolver::_SET_mTimeTotal);
+ static const Pb::Register _R_15 ("FluidSolver","frame",FluidSolver::_GET_mFrame,FluidSolver::_SET_mFrame);
+ static const Pb::Register _R_16 ("FluidSolver","cfl",FluidSolver::_GET_mCflCond,FluidSolver::_SET_mCflCond);
+ static const Pb::Register _R_17 ("FluidSolver","timestepMin",FluidSolver::_GET_mDtMin,FluidSolver::_SET_mDtMin);
+ static const Pb::Register _R_18 ("FluidSolver","timestepMax",FluidSolver::_GET_mDtMax,FluidSolver::_SET_mDtMax);
+ static const Pb::Register _R_19 ("FluidSolver","frameLength",FluidSolver::_GET_mFrameLength,FluidSolver::_SET_mFrameLength);
+ static const Pb::Register _R_20 ("FluidSolver","timePerFrame",FluidSolver::_GET_mTimePerFrame,FluidSolver::_SET_mTimePerFrame);
+#endif
+extern "C" {
+void PbRegister_file_6()
+{
+ KEEP_UNUSED(_R_6);
+ KEEP_UNUSED(_R_7);
+ KEEP_UNUSED(_R_8);
+ KEEP_UNUSED(_R_9);
+ KEEP_UNUSED(_R_10);
+ KEEP_UNUSED(_R_11);
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.cpp
new file mode 100644
index 00000000000..c165533c898
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.cpp
@@ -0,0 +1,165 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Globally used macros and functions (e.g. time measurements),
+ * and doxygen documentation collection.
+ *
+ ******************************************************************************/
+
+
+/*! \mainpage Welcome to mantaflow!
+ *
+ * Here you can find the auto-generated documentation of the mantaflow framework.
+ *
+ * One of the most useful parts is probably the list of python functions, classes and the C++ kernels.
+ * Those can be found found in the ''Modules'' section. For python functions the parameters (e.g. Grids, Real or int values)
+ * are automatically transferred to and from python. Thus, this list is a good reference how to call the functions used in the
+ * example scenes.
+ *
+ */
+
+// Define plugin documentation group
+// all kernels, plugin functions and classes will automatically be added to this group
+//! @defgroup Plugins Functions callable from Python
+//! @defgroup PyClasses Classes exposed to Python
+//! @defgroup Kernels Computation Kernels
+
+#include "general.h"
+#if defined(WIN32) || defined(_WIN32)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+# undef NOMINMAX
+#else
+# include <sys/time.h>
+# include "gitinfo.h"
+#endif
+
+using namespace std;
+
+namespace Manta {
+
+int gDebugLevel = 1;
+
+void MuTime::get() {
+#if defined(WIN32) || defined(_WIN32)
+ LARGE_INTEGER liTimerFrequency;
+ QueryPerformanceFrequency(&liTimerFrequency);
+ LARGE_INTEGER liLastTime;
+ QueryPerformanceCounter(&liLastTime);
+ time = (INT)( ((double)liLastTime.QuadPart / liTimerFrequency.QuadPart)*1000 );
+#else
+ struct timeval tv;
+ struct timezone tz;
+ tz.tz_minuteswest = 0;
+ tz.tz_dsttime = 0;
+ gettimeofday(&tv,&tz);
+ time = (tv.tv_sec*1000)+(tv.tv_usec/1000);
+#endif
+}
+
+MuTime MuTime::update() {
+ MuTime o = *this;
+ get();
+ return *this - o;
+}
+
+string MuTime::toString() {
+ stringstream ss;
+ ss << *this;
+ return ss.str();
+}
+
+ostream& operator<<(ostream& os, const MuTime& t) {
+ unsigned long ms = (unsigned long)( (double)t.time / (60.0*1000.0) );
+ unsigned long ss = (unsigned long)( ((double)t.time / 1000.0) - ((double)ms*60.0) );
+ int ps = (int)( ((double)t.time - (double)ss*1000.0)/1.0 );
+
+ if(ms>0) {
+ os << ms<<"m"<< ss<<"s" ;
+ } else {
+ if(ps>0) {
+ os << ss<<".";
+ if(ps<10) { os <<"0"; }
+ if(ps<100) { os <<"0"; }
+ os <<ps<<"s" ;
+ } else {
+ os << ss<<"s" ;
+ }
+ }
+ return os;
+}
+
+//! print info about this mantaflow build, used eg by printBuildInfo in fluidsolver.cpp
+std::string buildInfoString() {
+ std::ostringstream infoStr;
+# ifndef MANTAVERSION
+# define MANTAVERSION "<unknown-version>"
+# endif
+ infoStr << "mantaflow " << MANTAVERSION;
+
+ // os
+#if defined(WIN32) || defined(_WIN32)
+ infoStr << " win";
+# endif
+# ifdef __APPLE__
+ infoStr << " mac";
+# endif
+# ifdef LINUX
+ infoStr << " linux";
+# endif
+
+ // 32/64 bit
+ if (sizeof(size_t) == 8)
+ infoStr << " 64bit";
+ else
+ infoStr << " 32bit";
+
+ // fp precision
+# if FLOATINGPOINT_PRECISION==2
+ infoStr << " fp2";
+# else
+ infoStr << " fp1";
+# endif
+
+ // other compile switches
+# ifdef DEBUG
+ infoStr << " debug";
+# endif
+# ifdef OPENMP
+ infoStr << " omp";
+# endif
+
+ // repository info (git commit id)
+# ifndef MANTA_GIT_VERSION
+# define MANTA_GIT_VERSION "<unknown-commit>"
+# endif
+ infoStr << " "<< MANTA_GIT_VERSION;
+
+ infoStr << " from "<< __DATE__<<", "<<__TIME__;
+ return infoStr.str();
+}
+
+//! note - generic PYTHON helpers in fluidsolver.cpp , no python bindings here
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h
new file mode 100644
index 00000000000..71f453a6128
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h
@@ -0,0 +1,173 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Globally used macros and functions
+ *
+ ******************************************************************************/
+
+#ifndef _GENERAL_H
+#define _GENERAL_H
+
+#include <iostream>
+#include <sstream>
+#include <cmath>
+#include <algorithm>
+
+namespace Manta {
+
+// ui data exchange
+#ifdef GUI
+ // defined in qtmain.cpp
+ extern void updateQtGui(bool full, int frame, float time, const std::string& curPlugin);
+#else
+ // dummy function if GUI is not enabled
+ inline void updateQtGui(bool full, int frame, float time, const std::string& curPlugin) {}
+#endif
+
+
+// activate debug mode if _DEBUG is defined (eg for windows)
+#ifndef DEBUG
+#ifdef _DEBUG
+#define DEBUG 1
+#endif // _DEBUG
+#endif // DEBUG
+
+// Standard exception
+class Error : public std::exception
+{
+public:
+ Error(const std::string& s) : mS(s) {
+# ifdef DEBUG
+ // print error
+ std::cerr << "Aborting: "<< s <<" \n";
+ // then force immedieate crash in debug mode
+ *(volatile int*)(0) = 1;
+# endif
+ }
+ virtual ~Error() throw() {}
+ virtual const char* what() const throw() { return mS.c_str(); }
+private:
+ std::string mS;
+};
+
+// mark unused parameter variables
+#define unusedParameter(x) ((void)x)
+
+// Debug output functions and macros
+extern int gDebugLevel;
+
+#define MSGSTREAM std::ostringstream msg; msg.precision(7); msg.width(9);
+#define debMsg(mStr, level) if (_chklevel(level)) { MSGSTREAM; msg << mStr; std::cout << msg.str() << std::endl; }
+inline bool _chklevel(int level=0) { return gDebugLevel >= level; }
+
+// error and assertation macros
+#ifdef DEBUG
+# define DEBUG_ONLY(a) a
+#else
+# define DEBUG_ONLY(a)
+#endif
+#define throwError(msg) { std::ostringstream __s; __s << msg << std::endl << "Error raised in " << __FILE__ << ":" << __LINE__; throw Manta::Error(__s.str()); }
+#define errMsg(msg) throwError(msg);
+#define assertMsg(cond,msg) if(!(cond)) throwError(msg)
+#define assertDeb(cond,msg) DEBUG_ONLY( assertMsg(cond,msg) )
+
+// for compatibility with blender, blender only defines WITH_MANTA, make sure we have "BLENDER"
+#ifndef BLENDER
+#ifdef WITH_MANTA
+#define BLENDER 1
+#endif
+#endif
+
+// common type for indexing large grids
+typedef long long IndexInt;
+
+// template tricks
+template<typename T>
+struct remove_pointers {
+ typedef T type;
+};
+
+template<typename T>
+struct remove_pointers<T*> {
+ typedef T type;
+};
+
+template<typename T>
+struct remove_pointers<T&> {
+ typedef T type;
+};
+
+// Commonly used enums and types
+//! Timing class for preformance measuring
+struct MuTime {
+ MuTime() { get(); }
+ MuTime operator-(const MuTime& a) { MuTime b; b.time = time - a.time; return b; };
+ MuTime operator+(const MuTime& a) { MuTime b; b.time = time + a.time; return b; };
+ MuTime operator/(unsigned long a) { MuTime b; b.time = time / a; return b; };
+ MuTime& operator+=(const MuTime& a) { time += a.time; return *this; }
+ MuTime& operator-=(const MuTime& a) { time -= a.time; return *this; }
+ MuTime& operator/=(unsigned long a) { time /= a; return *this; }
+ std::string toString();
+
+ void clear() { time = 0; }
+ void get();
+ MuTime update();
+
+ unsigned long time;
+};
+std::ostream& operator<< (std::ostream& os, const MuTime& t);
+
+//! generate a string with infos about the current mantaflow build
+std::string buildInfoString();
+
+// Some commonly used math helpers
+template<class T> inline T square(T a) {
+ return a*a;
+}
+template<class T> inline T cubed(T a) {
+ return a*a*a;
+}
+
+template<class T> inline T clamp(const T& val, const T& vmin, const T& vmax) {
+ if (val < vmin) return vmin;
+ if (val > vmax) return vmax;
+ return val;
+}
+
+template<class T> inline T nmod(const T& a, const T& b);
+template<> inline int nmod(const int& a, const int& b) { int c=a%b; return (c<0) ? (c+b) : c; }
+template<> inline float nmod(const float& a, const float& b) { float c=std::fmod(a,b); return (c<0) ? (c+b) : c; }
+template<> inline double nmod(const double& a, const double& b) { double c=std::fmod(a,b); return (c<0) ? (c+b) : c; }
+
+template<class T> inline T safeDivide(const T& a, const T& b);
+template<> inline int safeDivide<int>(const int &a, const int& b) { return (b) ? (a/b) : a; }
+template<> inline float safeDivide<float>(const float &a, const float& b) { return (b) ? (a/b) : a; }
+template<> inline double safeDivide<double>(const double &a, const double& b) { return (b) ? (a/b) : a; }
+
+inline bool c_isnan(float c) {
+ volatile float d=c;
+ return d != d;
+}
+
+} // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h.reg
new file mode 100644
index 00000000000..65a276295d5
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h.reg
@@ -0,0 +1 @@
+#include "general.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h.reg.cpp
new file mode 100644
index 00000000000..44b2155020f
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/general.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "general.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_1()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/gitinfo.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/gitinfo.h
new file mode 100644
index 00000000000..b696431ac9e
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/gitinfo.h
@@ -0,0 +1,4 @@
+
+
+#define MANTA_GIT_VERSION "commit 0793c3c5f60deedee26289afcc135a0c15de96a3"
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.cpp
new file mode 100644
index 00000000000..f447a1d8aa5
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.cpp
@@ -0,0 +1,1634 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#include "grid.h"
+#include "levelset.h"
+#include "kernel.h"
+#include "mantaio.h"
+#include <limits>
+#include <sstream>
+#include <cstring>
+
+#include "commonkernels.h"
+
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// GridBase members
+
+GridBase::GridBase (FluidSolver* parent)
+ : PbClass(parent), mType(TypeNone)
+{
+ checkParent();
+ m3D = getParent()->is3D();
+}
+
+//******************************************************************************
+// Grid<T> members
+
+// helpers to set type
+template<class T> inline GridBase::GridType typeList() { return GridBase::TypeNone; }
+template<> inline GridBase::GridType typeList<Real>() { return GridBase::TypeReal; }
+template<> inline GridBase::GridType typeList<int>() { return GridBase::TypeInt; }
+template<> inline GridBase::GridType typeList<Vec3>() { return GridBase::TypeVec3; }
+
+template<class T>
+Grid<T>::Grid(FluidSolver* parent, bool show)
+ : GridBase(parent), externalData(false)
+{
+ mType = typeList<T>();
+ mSize = parent->getGridSize();
+ mData = parent->getGridPointer<T>();
+
+ mStrideZ = parent->is2D() ? 0 : (mSize.x * mSize.y);
+ mDx = 1.0 / mSize.max();
+ clear();
+ setHidden(!show);
+}
+
+template<class T>
+Grid<T>::Grid(FluidSolver* parent, T* data, bool show)
+ : GridBase(parent), mData(data), externalData(true)
+{
+ mType = typeList<T>();
+ mSize = parent->getGridSize();
+
+ mStrideZ = parent->is2D() ? 0 : (mSize.x * mSize.y);
+ mDx = 1.0 / mSize.max();
+
+ setHidden(!show);
+}
+
+template<class T>
+Grid<T>::Grid(const Grid<T>& a)
+ : GridBase(a.getParent()), externalData(false) {
+ mSize = a.mSize;
+ mType = a.mType;
+ mStrideZ = a.mStrideZ;
+ mDx = a.mDx;
+ FluidSolver *gp = a.getParent();
+ mData = gp->getGridPointer<T>();
+ memcpy(mData, a.mData, sizeof(T) * a.mSize.x * a.mSize.y * a.mSize.z);
+}
+
+template<class T>
+Grid<T>::~Grid() {
+ if(!externalData) {
+ mParent->freeGridPointer<T>(mData);
+ }
+}
+
+template<class T>
+void Grid<T>::clear() {
+ memset(mData, 0, sizeof(T) * mSize.x * mSize.y * mSize.z);
+}
+
+template<class T>
+void Grid<T>::swap(Grid<T>& other) {
+ if (other.getSizeX() != getSizeX() || other.getSizeY() != getSizeY() || other.getSizeZ() != getSizeZ())
+ errMsg("Grid::swap(): Grid dimensions mismatch.");
+
+ if(externalData || other.externalData)
+ errMsg("Grid::swap(): Cannot swap if one grid stores externalData.");
+
+ T* dswap = other.mData;
+ other.mData = mData;
+ mData = dswap;
+
+}
+
+template<class T>
+void Grid<T>::load(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".raw")
+ readGridRaw(name, this);
+ else if (ext == ".uni")
+ readGridUni(name, this);
+ else if (ext == ".vol")
+ readGridVol(name, this);
+ else if (ext == ".npz")
+ readGridNumpy(name, this);
+# if OPENVDB==1
+ else if (ext == ".vdb")
+ readGridVDB(name, this);
+# endif // OPENVDB==1
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+template<class T>
+void Grid<T>::save(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".raw")
+ writeGridRaw(name, this);
+ else if (ext == ".uni")
+ writeGridUni(name, this);
+ else if (ext == ".vol")
+ writeGridVol(name, this);
+# if OPENVDB==1
+ else if (ext == ".vdb")
+ writeGridVDB(name, this);
+# endif // OPENVDB==1
+ else if (ext == ".npz")
+ writeGridNumpy(name, this);
+ else if (ext == ".txt")
+ writeGridTxt(name, this);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+//******************************************************************************
+// Grid<T> operators
+
+//! Kernel: Compute min value of Real grid
+
+ struct CompMinReal : public KernelBase {
+ CompMinReal(const Grid<Real>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& val ,Real& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const Grid<Real>& getArg0() {
+ return val; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel CompMinReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real minVal = std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,minVal);
+#pragma omp critical
+{this->minVal = min(minVal, this->minVal); } }
+ }
+ const Grid<Real>& val; Real minVal; }
+;
+
+//! Kernel: Compute max value of Real grid
+
+ struct CompMaxReal : public KernelBase {
+ CompMaxReal(const Grid<Real>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& val ,Real& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const Grid<Real>& getArg0() {
+ return val; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel CompMaxReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real maxVal = -std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,maxVal);
+#pragma omp critical
+{this->maxVal = max(maxVal, this->maxVal); } }
+ }
+ const Grid<Real>& val; Real maxVal; }
+;
+
+//! Kernel: Compute min value of int grid
+
+ struct CompMinInt : public KernelBase {
+ CompMinInt(const Grid<int>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<int>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<int>& val ,int& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator int () {
+ return minVal; }
+ inline int & getRet() {
+ return minVal; }
+ inline const Grid<int>& getArg0() {
+ return val; }
+ typedef Grid<int> type0; void runMessage() { debMsg("Executing kernel CompMinInt ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ int minVal = std::numeric_limits<int>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,minVal);
+#pragma omp critical
+{this->minVal = min(minVal, this->minVal); } }
+ }
+ const Grid<int>& val; int minVal; }
+;
+
+//! Kernel: Compute max value of int grid
+
+ struct CompMaxInt : public KernelBase {
+ CompMaxInt(const Grid<int>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<int>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<int>& val ,int& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator int () {
+ return maxVal; }
+ inline int & getRet() {
+ return maxVal; }
+ inline const Grid<int>& getArg0() {
+ return val; }
+ typedef Grid<int> type0; void runMessage() { debMsg("Executing kernel CompMaxInt ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ int maxVal = -std::numeric_limits<int>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,maxVal);
+#pragma omp critical
+{this->maxVal = max(maxVal, this->maxVal); } }
+ }
+ const Grid<int>& val; int maxVal; }
+;
+
+//! Kernel: Compute min norm of vec grid
+
+ struct CompMinVec : public KernelBase {
+ CompMinVec(const Grid<Vec3>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Vec3>& val ,Real& minVal) {
+ const Real s = normSquare(val[idx]);
+ if (s < minVal)
+ minVal = s;
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const Grid<Vec3>& getArg0() {
+ return val; }
+ typedef Grid<Vec3> type0; void runMessage() { debMsg("Executing kernel CompMinVec ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real minVal = std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,minVal);
+#pragma omp critical
+{this->minVal = min(minVal, this->minVal); } }
+ }
+ const Grid<Vec3>& val; Real minVal; }
+;
+
+//! Kernel: Compute max norm of vec grid
+
+ struct CompMaxVec : public KernelBase {
+ CompMaxVec(const Grid<Vec3>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Vec3>& val ,Real& maxVal) {
+ const Real s = normSquare(val[idx]);
+ if (s > maxVal)
+ maxVal = s;
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const Grid<Vec3>& getArg0() {
+ return val; }
+ typedef Grid<Vec3> type0; void runMessage() { debMsg("Executing kernel CompMaxVec ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real maxVal = -std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,maxVal);
+#pragma omp critical
+{this->maxVal = max(maxVal, this->maxVal); } }
+ }
+ const Grid<Vec3>& val; Real maxVal; }
+;
+
+template<class T> Grid<T>& Grid<T>::copyFrom (const Grid<T>& a, bool copyType ) {
+ assertMsg (a.mSize.x == mSize.x && a.mSize.y == mSize.y && a.mSize.z == mSize.z, "different grid resolutions "<<a.mSize<<" vs "<<this->mSize );
+ memcpy(mData, a.mData, sizeof(T) * mSize.x * mSize.y * mSize.z);
+ if(copyType) mType = a.mType; // copy type marker
+ return *this;
+}
+/*template<class T> Grid<T>& Grid<T>::operator= (const Grid<T>& a) {
+ note: do not use , use copyFrom instead
+}*/
+
+template <class T> struct knGridSetConstReal : public KernelBase {
+ knGridSetConstReal(Grid<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, T val ) { me[idx] = val; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knGridSetConstReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,val); }
+ }
+ Grid<T>& me; T val; }
+;
+template <class T> struct knGridAddConstReal : public KernelBase {
+ knGridAddConstReal(Grid<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, T val ) { me[idx] += val; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knGridAddConstReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,val); }
+ }
+ Grid<T>& me; T val; }
+;
+template <class T> struct knGridMultConst : public KernelBase {
+ knGridMultConst(Grid<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, T val ) { me[idx] *= val; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knGridMultConst ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,val); }
+ }
+ Grid<T>& me; T val; }
+;
+
+template <class T> struct knGridSafeDiv : public KernelBase {
+ knGridSafeDiv(Grid<T>& me, const Grid<T>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<T>& other ) { me[idx] = safeDivide(me[idx], other[idx]); } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<T>& getArg1() {
+ return other; }
+ typedef Grid<T> type1; void runMessage() { debMsg("Executing kernel knGridSafeDiv ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid<T>& me; const Grid<T>& other; }
+;
+//KERNEL(idx) template<class T> void gridSafeDiv (Grid<T>& me, const Grid<T>& other) { me[idx] = safeDivide(me[idx], other[idx]); }
+
+template <class T> struct knGridClamp : public KernelBase {
+ knGridClamp(Grid<T>& me, const T& min, const T& max) : KernelBase(&me,0) ,me(me),min(min),max(max) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const T& min, const T& max ) { me[idx] = clamp(me[idx], min, max); } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const T& getArg1() {
+ return min; }
+ typedef T type1;inline const T& getArg2() {
+ return max; }
+ typedef T type2; void runMessage() { debMsg("Executing kernel knGridClamp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,min,max); }
+ }
+ Grid<T>& me; const T& min; const T& max; }
+;
+
+template<typename T> inline void stomp(T &v, const T &th) { if(v<th) v=0; }
+template<> inline void stomp<Vec3>(Vec3 &v, const Vec3 &th) { if(v[0]<th[0]) v[0]=0; if(v[1]<th[1]) v[1]=0; if(v[2]<th[2]) v[2]=0; }
+template <class T> struct knGridStomp : public KernelBase {
+ knGridStomp(Grid<T>& me, const T& threshold) : KernelBase(&me,0) ,me(me),threshold(threshold) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const T& threshold ) { stomp(me[idx], threshold); } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const T& getArg1() {
+ return threshold; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knGridStomp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,threshold); }
+ }
+ Grid<T>& me; const T& threshold; }
+;
+
+template<class T> Grid<T>& Grid<T>::safeDivide (const Grid<T>& a) {
+ knGridSafeDiv<T> (*this, a);
+ return *this;
+}
+
+template<class T> int Grid<T>::getGridType() {
+ return static_cast<int>(mType);
+}
+
+template<class T> void Grid<T>::add(const Grid<T>& a) {
+ gridAdd<T,T>(*this, a);
+}
+template<class T> void Grid<T>::sub(const Grid<T>& a) {
+ gridSub<T,T>(*this, a);
+}
+template<class T> void Grid<T>::addScaled(const Grid<T>& a, const T& factor) {
+ gridScaledAdd<T,T> (*this, a, factor);
+}
+template<class T> void Grid<T>::setConst(T a) {
+ knGridSetConstReal<T>( *this, T(a) );
+}
+template<class T> void Grid<T>::addConst(T a) {
+ knGridAddConstReal<T>( *this, T(a) );
+}
+template<class T> void Grid<T>::multConst(T a) {
+ knGridMultConst<T>( *this, a );
+}
+
+template<class T> void Grid<T>::mult(const Grid<T>& a) {
+ gridMult<T,T> (*this, a);
+}
+
+template<class T> void Grid<T>::clamp(Real min, Real max) {
+ knGridClamp<T> (*this, T(min), T(max) );
+}
+template<class T> void Grid<T>::stomp(const T& threshold) {
+ knGridStomp<T>(*this, threshold);
+}
+
+template<> Real Grid<Real>::getMax() const {
+ return CompMaxReal (*this);
+}
+template<> Real Grid<Real>::getMin() const {
+ return CompMinReal (*this);
+}
+template<> Real Grid<Real>::getMaxAbs() const {
+ Real amin = CompMinReal (*this);
+ Real amax = CompMaxReal (*this);
+ return max( fabs(amin), fabs(amax));
+}
+template<> Real Grid<Vec3>::getMax() const {
+ return sqrt(CompMaxVec (*this));
+}
+template<> Real Grid<Vec3>::getMin() const {
+ return sqrt(CompMinVec (*this));
+}
+template<> Real Grid<Vec3>::getMaxAbs() const {
+ return sqrt(CompMaxVec (*this));
+}
+template<> Real Grid<int>::getMax() const {
+ return (Real) CompMaxInt (*this);
+}
+template<> Real Grid<int>::getMin() const {
+ return (Real) CompMinInt (*this);
+}
+template<> Real Grid<int>::getMaxAbs() const {
+ int amin = CompMinInt (*this);
+ int amax = CompMaxInt (*this);
+ return max( fabs((Real)amin), fabs((Real)amax));
+}
+template<class T> std::string Grid<T>::getDataPointer() {
+ std::ostringstream out;
+ out << mData ;
+ return out.str();
+}
+
+// L1 / L2 functions
+
+//! calculate L1 norm for whole grid with non-parallelized loop
+template<class GRID>
+Real loop_calcL1Grid (const GRID &grid, int bnd)
+{
+ double accu = 0.;
+ FOR_IJKT_BND(grid, bnd) { accu += norm(grid(i,j,k,t)); }
+ return (Real)accu;
+}
+
+//! calculate L2 norm for whole grid with non-parallelized loop
+// note - kernels "could" be used here, but they can't be templated at the moment (also, that would
+// mean the bnd parameter is fixed)
+template<class GRID>
+Real loop_calcL2Grid(const GRID &grid, int bnd)
+{
+ double accu = 0.;
+ FOR_IJKT_BND(grid, bnd) {
+ accu += normSquare(grid(i,j,k,t)); // supported for real and vec3,4 types
+ }
+ return (Real)sqrt(accu);
+}
+
+//! compute L1 norm of whole grid content (note, not parallel at the moment)
+template<class T> Real Grid<T>::getL1(int bnd) {
+ return loop_calcL1Grid<Grid<T> >(*this, bnd);
+}
+//! compute L2 norm of whole grid content (note, not parallel at the moment)
+template<class T> Real Grid<T>::getL2(int bnd) {
+ return loop_calcL2Grid<Grid<T> >(*this, bnd);
+}
+
+
+ struct knCountCells : public KernelBase {
+ knCountCells(const FlagGrid& flags, int flag, int bnd, Grid<Real>* mask) : KernelBase(&flags,0) ,flags(flags),flag(flag),bnd(bnd),mask(mask) ,cnt(0) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, int flag, int bnd, Grid<Real>* mask ,int& cnt) {
+ if(mask) (*mask)(i,j,k) = 0.;
+ if( bnd>0 && (!flags.isInBounds(Vec3i(i,j,k))) ) return;
+ if (flags(i,j,k) & flag ) {
+ cnt++;
+ if(mask) (*mask)(i,j,k) = 1.;
+ }
+} inline operator int () {
+ return cnt; }
+ inline int & getRet() {
+ return cnt; }
+ inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline int& getArg1() {
+ return flag; }
+ typedef int type1;inline int& getArg2() {
+ return bnd; }
+ typedef int type2;inline Grid<Real>* getArg3() {
+ return mask; }
+ typedef Grid<Real> type3; void runMessage() { debMsg("Executing kernel knCountCells ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+ int cnt = 0;
+#pragma omp for nowait
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,flag,bnd,mask,cnt);
+#pragma omp critical
+{this->cnt += cnt; } }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+ int cnt = 0;
+#pragma omp for nowait
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,flag,bnd,mask,cnt);
+#pragma omp critical
+{this->cnt += cnt; } }
+ }
+ }
+ const FlagGrid& flags; int flag; int bnd; Grid<Real>* mask; int cnt; }
+;
+
+//! count number of cells of a certain type flag (can contain multiple bits, checks if any one of them is set - not all!)
+int FlagGrid::countCells(int flag, int bnd, Grid<Real>* mask) {
+ return knCountCells(*this, flag, bnd, mask);
+}
+
+// compute maximal diference of two cells in the grid
+// used for testing system
+
+Real gridMaxDiff(Grid<Real>& g1, Grid<Real>& g2) {
+ double maxVal = 0.;
+ FOR_IJK(g1) {
+ maxVal = std::max(maxVal, (double)fabs(g1(i, j, k) - g2(i, j, k)));
+ }
+ return maxVal;
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "gridMaxDiff" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& g1 = *_args.getPtr<Grid<Real> >("g1",0,&_lock); Grid<Real>& g2 = *_args.getPtr<Grid<Real> >("g2",1,&_lock); _retval = toPy(gridMaxDiff(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"gridMaxDiff", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("gridMaxDiff",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_gridMaxDiff ("","gridMaxDiff",_W_0);
+extern "C" {
+ void PbRegister_gridMaxDiff() {
+ KEEP_UNUSED(_RP_gridMaxDiff); }
+ }
+
+
+
+Real gridMaxDiffInt(Grid<int>& g1, Grid<int>& g2) {
+ double maxVal = 0.;
+ FOR_IJK(g1) {
+ maxVal = std::max(maxVal, (double)fabs((double)g1(i, j, k) - g2(i, j, k)));
+ }
+ return maxVal;
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "gridMaxDiffInt" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<int>& g1 = *_args.getPtr<Grid<int> >("g1",0,&_lock); Grid<int>& g2 = *_args.getPtr<Grid<int> >("g2",1,&_lock); _retval = toPy(gridMaxDiffInt(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"gridMaxDiffInt", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("gridMaxDiffInt",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_gridMaxDiffInt ("","gridMaxDiffInt",_W_1);
+extern "C" {
+ void PbRegister_gridMaxDiffInt() {
+ KEEP_UNUSED(_RP_gridMaxDiffInt); }
+ }
+
+
+
+Real gridMaxDiffVec3(Grid<Vec3>& g1, Grid<Vec3>& g2) {
+ double maxVal = 0.;
+ FOR_IJK(g1) {
+ // accumulate differences with double precision
+ // note - don't use norm here! should be as precise as possible...
+ double d = 0.;
+ for (int c = 0; c<3; ++c) {
+ d += fabs((double)g1(i, j, k)[c] - (double)g2(i, j, k)[c]);
+ }
+ maxVal = std::max(maxVal, d);
+ //maxVal = std::max(maxVal, (double)fabs( norm(g1(i,j,k)-g2(i,j,k)) ));
+ }
+ return maxVal;
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "gridMaxDiffVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& g1 = *_args.getPtr<Grid<Vec3> >("g1",0,&_lock); Grid<Vec3>& g2 = *_args.getPtr<Grid<Vec3> >("g2",1,&_lock); _retval = toPy(gridMaxDiffVec3(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"gridMaxDiffVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("gridMaxDiffVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_gridMaxDiffVec3 ("","gridMaxDiffVec3",_W_2);
+extern "C" {
+ void PbRegister_gridMaxDiffVec3() {
+ KEEP_UNUSED(_RP_gridMaxDiffVec3); }
+ }
+
+
+
+// simple helper functions to copy (convert) mac to vec3 , and levelset to real grids
+// (are assumed to be the same for running the test cases - in general they're not!)
+
+void copyMacToVec3(MACGrid &source, Grid<Vec3>& target) {
+ FOR_IJK(target) {
+ target(i,j,k) = source(i,j,k);
+ }
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "copyMacToVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& source = *_args.getPtr<MACGrid >("source",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); _retval = getPyNone(); copyMacToVec3(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"copyMacToVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("copyMacToVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_copyMacToVec3 ("","copyMacToVec3",_W_3);
+extern "C" {
+ void PbRegister_copyMacToVec3() {
+ KEEP_UNUSED(_RP_copyMacToVec3); }
+ }
+
+
+
+void convertMacToVec3(MACGrid &source , Grid<Vec3> &target) { debMsg("Deprecated - do not use convertMacToVec3... use copyMacToVec3 instead",1); copyMacToVec3(source,target); } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "convertMacToVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& source = *_args.getPtr<MACGrid >("source",0,&_lock); Grid<Vec3> & target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); _retval = getPyNone(); convertMacToVec3(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"convertMacToVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("convertMacToVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_convertMacToVec3 ("","convertMacToVec3",_W_4);
+extern "C" {
+ void PbRegister_convertMacToVec3() {
+ KEEP_UNUSED(_RP_convertMacToVec3); }
+ }
+
+
+
+//! vec3->mac grid conversion , but with full resampling
+void resampleVec3ToMac(Grid<Vec3>& source, MACGrid &target ) {
+ FOR_IJK_BND(target,1) {
+ target(i,j,k)[0] = 0.5*(source(i-1,j,k)[0]+source(i,j,k))[0];
+ target(i,j,k)[1] = 0.5*(source(i,j-1,k)[1]+source(i,j,k))[1];
+ if(target.is3D()) {
+ target(i,j,k)[2] = 0.5*(source(i,j,k-1)[2]+source(i,j,k))[2]; }
+ }
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "resampleVec3ToMac" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& source = *_args.getPtr<Grid<Vec3> >("source",0,&_lock); MACGrid& target = *_args.getPtr<MACGrid >("target",1,&_lock); _retval = getPyNone(); resampleVec3ToMac(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"resampleVec3ToMac", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("resampleVec3ToMac",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_resampleVec3ToMac ("","resampleVec3ToMac",_W_5);
+extern "C" {
+ void PbRegister_resampleVec3ToMac() {
+ KEEP_UNUSED(_RP_resampleVec3ToMac); }
+ }
+
+
+//! mac->vec3 grid conversion , with full resampling
+void resampleMacToVec3(MACGrid &source, Grid<Vec3>& target ) {
+ FOR_IJK_BND(target,1) {
+ target(i,j,k) = source.getCentered(i,j,k);
+ }
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "resampleMacToVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& source = *_args.getPtr<MACGrid >("source",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); _retval = getPyNone(); resampleMacToVec3(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"resampleMacToVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("resampleMacToVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_resampleMacToVec3 ("","resampleMacToVec3",_W_6);
+extern "C" {
+ void PbRegister_resampleMacToVec3() {
+ KEEP_UNUSED(_RP_resampleMacToVec3); }
+ }
+
+
+
+
+void copyLevelsetToReal(LevelsetGrid &source , Grid<Real> &target) {
+ FOR_IJK(target) {
+ target(i,j,k) = source(i,j,k);
+ }
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "copyLevelsetToReal" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; LevelsetGrid& source = *_args.getPtr<LevelsetGrid >("source",0,&_lock); Grid<Real> & target = *_args.getPtr<Grid<Real> >("target",1,&_lock); _retval = getPyNone(); copyLevelsetToReal(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"copyLevelsetToReal", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("copyLevelsetToReal",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_copyLevelsetToReal ("","copyLevelsetToReal",_W_7);
+extern "C" {
+ void PbRegister_copyLevelsetToReal() {
+ KEEP_UNUSED(_RP_copyLevelsetToReal); }
+ }
+
+
+
+void copyVec3ToReal(Grid<Vec3> &source, Grid<Real> &targetX, Grid<Real> &targetY, Grid<Real> &targetZ) {
+ FOR_IJK(source) {
+ targetX(i,j,k) = source(i,j,k).x;
+ targetY(i,j,k) = source(i,j,k).y;
+ targetZ(i,j,k) = source(i,j,k).z;
+ }
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "copyVec3ToReal" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3> & source = *_args.getPtr<Grid<Vec3> >("source",0,&_lock); Grid<Real> & targetX = *_args.getPtr<Grid<Real> >("targetX",1,&_lock); Grid<Real> & targetY = *_args.getPtr<Grid<Real> >("targetY",2,&_lock); Grid<Real> & targetZ = *_args.getPtr<Grid<Real> >("targetZ",3,&_lock); _retval = getPyNone(); copyVec3ToReal(source,targetX,targetY,targetZ); _args.check(); }
+ pbFinalizePlugin(parent,"copyVec3ToReal", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("copyVec3ToReal",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_copyVec3ToReal ("","copyVec3ToReal",_W_8);
+extern "C" {
+ void PbRegister_copyVec3ToReal() {
+ KEEP_UNUSED(_RP_copyVec3ToReal); }
+ }
+
+
+
+
+void copyRealToVec3(Grid<Real> &sourceX, Grid<Real> &sourceY, Grid<Real> &sourceZ, Grid<Vec3> &target) {
+ FOR_IJK(target) {
+ target(i,j,k).x = sourceX(i,j,k);
+ target(i,j,k).y = sourceY(i,j,k);
+ target(i,j,k).z = sourceZ(i,j,k);
+ }
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "copyRealToVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & sourceX = *_args.getPtr<Grid<Real> >("sourceX",0,&_lock); Grid<Real> & sourceY = *_args.getPtr<Grid<Real> >("sourceY",1,&_lock); Grid<Real> & sourceZ = *_args.getPtr<Grid<Real> >("sourceZ",2,&_lock); Grid<Vec3> & target = *_args.getPtr<Grid<Vec3> >("target",3,&_lock); _retval = getPyNone(); copyRealToVec3(sourceX,sourceY,sourceZ,target); _args.check(); }
+ pbFinalizePlugin(parent,"copyRealToVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("copyRealToVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_copyRealToVec3 ("","copyRealToVec3",_W_9);
+extern "C" {
+ void PbRegister_copyRealToVec3() {
+ KEEP_UNUSED(_RP_copyRealToVec3); }
+ }
+
+
+void convertLevelsetToReal(LevelsetGrid &source , Grid<Real> &target) { debMsg("Deprecated - do not use convertLevelsetToReal... use copyLevelsetToReal instead",1); copyLevelsetToReal(source,target); } static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "convertLevelsetToReal" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; LevelsetGrid& source = *_args.getPtr<LevelsetGrid >("source",0,&_lock); Grid<Real> & target = *_args.getPtr<Grid<Real> >("target",1,&_lock); _retval = getPyNone(); convertLevelsetToReal(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"convertLevelsetToReal", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("convertLevelsetToReal",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_convertLevelsetToReal ("","convertLevelsetToReal",_W_10);
+extern "C" {
+ void PbRegister_convertLevelsetToReal() {
+ KEEP_UNUSED(_RP_convertLevelsetToReal); }
+ }
+
+
+
+template<class T> void Grid<T>::printGrid(int zSlice, bool printIndex, int bnd) {
+ std::ostringstream out;
+ out << std::endl;
+ FOR_IJK_BND(*this,bnd) {
+ IndexInt idx = (*this).index(i,j,k);
+ if((zSlice>=0 && k==zSlice) || (zSlice<0)) {
+ out << " ";
+ if(printIndex && this->is3D()) out << " "<<i<<","<<j<<","<<k <<":";
+ if(printIndex && !this->is3D()) out << " "<<i<<","<<j<<":";
+ out << (*this)[idx];
+ if(i==(*this).getSizeX()-1 -bnd) out << std::endl;
+ }
+ }
+ out << endl; debMsg("Printing " << this->getName() << out.str().c_str() , 1);
+}
+
+//! helper to swap components of a grid (eg for data import)
+void swapComponents(Grid<Vec3>& vel, int c1=0, int c2=1, int c3=2) {
+ FOR_IJK(vel) {
+ Vec3 v = vel(i,j,k);
+ vel(i,j,k)[0] = v[c1];
+ vel(i,j,k)[1] = v[c2];
+ vel(i,j,k)[2] = v[c3];
+ }
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "swapComponents" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& vel = *_args.getPtr<Grid<Vec3> >("vel",0,&_lock); int c1 = _args.getOpt<int >("c1",1,0,&_lock); int c2 = _args.getOpt<int >("c2",2,1,&_lock); int c3 = _args.getOpt<int >("c3",3,2,&_lock); _retval = getPyNone(); swapComponents(vel,c1,c2,c3); _args.check(); }
+ pbFinalizePlugin(parent,"swapComponents", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("swapComponents",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_swapComponents ("","swapComponents",_W_11);
+extern "C" {
+ void PbRegister_swapComponents() {
+ KEEP_UNUSED(_RP_swapComponents); }
+ }
+
+
+
+// helper functions for UV grid data (stored grid coordinates as Vec3 values, and uv weight in entry zero)
+
+// make uv weight accesible in python
+Real getUvWeight(Grid<Vec3> &uv) { return uv[0][0]; } static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getUvWeight" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3> & uv = *_args.getPtr<Grid<Vec3> >("uv",0,&_lock); _retval = toPy(getUvWeight(uv)); _args.check(); }
+ pbFinalizePlugin(parent,"getUvWeight", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getUvWeight",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getUvWeight ("","getUvWeight",_W_12);
+extern "C" {
+ void PbRegister_getUvWeight() {
+ KEEP_UNUSED(_RP_getUvWeight); }
+ }
+
+
+
+// note - right now the UV grids have 0 values at the border after advection... could be fixed with an extrapolation step...
+
+// compute normalized modulo interval
+static inline Real computeUvGridTime(Real t, Real resetTime) {
+ return fmod( (t / resetTime), (Real)1. );
+}
+// create ramp function in 0..1 range with half frequency
+static inline Real computeUvRamp(Real t) {
+ Real uvWeight = 2. * t;
+ if (uvWeight>1.) uvWeight=2.-uvWeight;
+ return uvWeight;
+}
+
+ struct knResetUvGrid : public KernelBase {
+ knResetUvGrid(Grid<Vec3>& target, const Vec3* offset) : KernelBase(&target,0) ,target(target),offset(offset) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& target, const Vec3* offset ) {
+ Vec3 coord = Vec3((Real)i,(Real)j,(Real)k);
+ if (offset) coord += (*offset);
+ target(i,j,k) = coord;
+} inline Grid<Vec3>& getArg0() {
+ return target; }
+ typedef Grid<Vec3> type0;inline const Vec3* getArg1() {
+ return offset; }
+ typedef Vec3 type1; void runMessage() { debMsg("Executing kernel knResetUvGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,target,offset); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,target,offset); }
+ }
+ }
+ Grid<Vec3>& target; const Vec3* offset; }
+;
+
+
+void resetUvGrid(Grid<Vec3> &target, const Vec3* offset=NULL) {
+ knResetUvGrid reset(target, offset); // note, llvm complains about anonymous declaration here... ?
+} static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "resetUvGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3> & target = *_args.getPtr<Grid<Vec3> >("target",0,&_lock); const Vec3* offset = _args.getPtrOpt<Vec3 >("offset",1,NULL,&_lock); _retval = getPyNone(); resetUvGrid(target,offset); _args.check(); }
+ pbFinalizePlugin(parent,"resetUvGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("resetUvGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_resetUvGrid ("","resetUvGrid",_W_13);
+extern "C" {
+ void PbRegister_resetUvGrid() {
+ KEEP_UNUSED(_RP_resetUvGrid); }
+ }
+
+
+
+void updateUvWeight(Real resetTime, int index, int numUvs, Grid<Vec3> &uv, const Vec3* offset=NULL) {
+ const Real t = uv.getParent()->getTime();
+ Real timeOff = resetTime/(Real)numUvs;
+
+ Real lastt = computeUvGridTime(t +(Real)index*timeOff - uv.getParent()->getDt(), resetTime);
+ Real currt = computeUvGridTime(t +(Real)index*timeOff , resetTime);
+ Real uvWeight = computeUvRamp(currt);
+
+ // normalize the uvw weights , note: this is a bit wasteful...
+ Real uvWTotal = 0.;
+ for(int i=0; i<numUvs; ++i) {
+ uvWTotal += computeUvRamp( computeUvGridTime(t +(Real)i*timeOff , resetTime) );
+ }
+ if(uvWTotal<=VECTOR_EPSILON) { uvWeight = uvWTotal = 1.; }
+ else uvWeight /= uvWTotal;
+
+ // check for reset
+ if( currt < lastt )
+ knResetUvGrid reset(uv, offset);
+
+ // write new weight value to grid
+ uv[0] = Vec3( uvWeight, 0.,0.);
+
+ // print info about uv weights?
+ debMsg("Uv grid "<<index<<"/"<<numUvs<< " t="<<currt<<" w="<<uvWeight<<", reset:"<<(int)(currt<lastt) , 2);
+} static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "updateUvWeight" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Real resetTime = _args.get<Real >("resetTime",0,&_lock); int index = _args.get<int >("index",1,&_lock); int numUvs = _args.get<int >("numUvs",2,&_lock); Grid<Vec3> & uv = *_args.getPtr<Grid<Vec3> >("uv",3,&_lock); const Vec3* offset = _args.getPtrOpt<Vec3 >("offset",4,NULL,&_lock); _retval = getPyNone(); updateUvWeight(resetTime,index,numUvs,uv,offset); _args.check(); }
+ pbFinalizePlugin(parent,"updateUvWeight", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("updateUvWeight",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_updateUvWeight ("","updateUvWeight",_W_14);
+extern "C" {
+ void PbRegister_updateUvWeight() {
+ KEEP_UNUSED(_RP_updateUvWeight); }
+ }
+
+
+
+template <class T> struct knSetBoundary : public KernelBase {
+ knSetBoundary(Grid<T>& grid, T value, int w) : KernelBase(&grid,0) ,grid(grid),value(value),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>& grid, T value, int w ) {
+ bool bnd = (i<=w || i>=grid.getSizeX()-1-w || j<=w || j>=grid.getSizeY()-1-w || (grid.is3D() && (k<=w || k>=grid.getSizeZ()-1-w)));
+ if (bnd)
+ grid(i,j,k) = value;
+} inline Grid<T>& getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1;inline int& getArg2() {
+ return w; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetBoundary ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,value,w); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,value,w); }
+ }
+ }
+ Grid<T>& grid; T value; int w; }
+;
+
+template<class T> void Grid<T>::setBound(T value, int boundaryWidth) {
+ knSetBoundary<T>( *this, value, boundaryWidth );
+}
+
+
+template <class T> struct knSetBoundaryNeumann : public KernelBase {
+ knSetBoundaryNeumann(Grid<T>& grid, int w) : KernelBase(&grid,0) ,grid(grid),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>& grid, int w ) {
+ bool set = false;
+ int si=i, sj=j, sk=k;
+ if( i<=w) {
+ si = w+1; set=true;
+ }
+ if( i>=grid.getSizeX()-1-w){
+ si = grid.getSizeX()-1-w-1; set=true;
+ }
+ if( j<=w){
+ sj = w+1; set=true;
+ }
+ if( j>=grid.getSizeY()-1-w){
+ sj = grid.getSizeY()-1-w-1; set=true;
+ }
+ if( grid.is3D() ){
+ if( k<=w ) {
+ sk = w+1; set=true;
+ }
+ if( k>=grid.getSizeZ()-1-w ) {
+ sk = grid.getSizeZ()-1-w-1; set=true;
+ }
+ }
+ if(set)
+ grid(i,j,k) = grid(si, sj, sk);
+} inline Grid<T>& getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline int& getArg1() {
+ return w; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel knSetBoundaryNeumann ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,w); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,w); }
+ }
+ }
+ Grid<T>& grid; int w; }
+;
+
+template<class T> void Grid<T>::setBoundNeumann(int boundaryWidth) {
+ knSetBoundaryNeumann<T>( *this, boundaryWidth );
+}
+
+//! kernel to set velocity components of mac grid to value for a boundary of w cells
+ struct knSetBoundaryMAC : public KernelBase {
+ knSetBoundaryMAC(Grid<Vec3>& grid, Vec3 value, int w) : KernelBase(&grid,0) ,grid(grid),value(value),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& grid, Vec3 value, int w ) {
+ if (i<=w || i>=grid.getSizeX() -w || j<=w-1 || j>=grid.getSizeY()-1-w || (grid.is3D() && (k<=w-1 || k>=grid.getSizeZ()-1-w)))
+ grid(i,j,k).x = value.x;
+ if (i<=w-1 || i>=grid.getSizeX()-1-w || j<=w || j>=grid.getSizeY() -w || (grid.is3D() && (k<=w-1 || k>=grid.getSizeZ()-1-w)))
+ grid(i,j,k).y = value.y;
+ if (i<=w-1 || i>=grid.getSizeX()-1-w || j<=w-1 || j>=grid.getSizeY()-1-w || (grid.is3D() && (k<=w || k>=grid.getSizeZ() -w)))
+ grid(i,j,k).z = value.z;
+} inline Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Vec3& getArg1() {
+ return value; }
+ typedef Vec3 type1;inline int& getArg2() {
+ return w; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetBoundaryMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,value,w); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,value,w); }
+ }
+ }
+ Grid<Vec3>& grid; Vec3 value; int w; }
+;
+
+//! only set normal velocity components of mac grid to value for a boundary of w cells
+ struct knSetBoundaryMACNorm : public KernelBase {
+ knSetBoundaryMACNorm(Grid<Vec3>& grid, Vec3 value, int w) : KernelBase(&grid,0) ,grid(grid),value(value),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& grid, Vec3 value, int w ) {
+ if (i<=w || i>=grid.getSizeX() -w ) grid(i,j,k).x = value.x;
+ if (j<=w || j>=grid.getSizeY() -w ) grid(i,j,k).y = value.y;
+ if ( (grid.is3D() && (k<=w || k>=grid.getSizeZ() -w))) grid(i,j,k).z = value.z;
+} inline Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Vec3& getArg1() {
+ return value; }
+ typedef Vec3 type1;inline int& getArg2() {
+ return w; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetBoundaryMACNorm ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,value,w); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,value,w); }
+ }
+ }
+ Grid<Vec3>& grid; Vec3 value; int w; }
+;
+
+//! set velocity components of mac grid to value for a boundary of w cells (optionally only normal values)
+void MACGrid::setBoundMAC(Vec3 value, int boundaryWidth, bool normalOnly) {
+ if(!normalOnly) knSetBoundaryMAC ( *this, value, boundaryWidth );
+ else knSetBoundaryMACNorm( *this, value, boundaryWidth );
+}
+
+
+//! helper kernels for getGridAvg
+
+ struct knGridTotalSum : public KernelBase {
+ knGridTotalSum(const Grid<Real>& a, FlagGrid* flags) : KernelBase(&a,0) ,a(a),flags(flags) ,result(0.0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& a, FlagGrid* flags ,double& result) {
+ if(flags) { if(flags->isFluid(idx)) result += a[idx]; }
+ else { result += a[idx]; }
+} inline operator double () {
+ return result; }
+ inline double & getRet() {
+ return result; }
+ inline const Grid<Real>& getArg0() {
+ return a; }
+ typedef Grid<Real> type0;inline FlagGrid* getArg1() {
+ return flags; }
+ typedef FlagGrid type1; void runMessage() { debMsg("Executing kernel knGridTotalSum ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ double result = 0.0;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,a,flags,result);
+#pragma omp critical
+{this->result += result; } }
+ }
+ const Grid<Real>& a; FlagGrid* flags; double result; }
+;
+
+
+ struct knCountFluidCells : public KernelBase {
+ knCountFluidCells(FlagGrid& flags) : KernelBase(&flags,0) ,flags(flags) ,numEmpty(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, FlagGrid& flags ,int& numEmpty) { if (flags.isFluid(idx) ) numEmpty++; } inline operator int () {
+ return numEmpty; }
+ inline int & getRet() {
+ return numEmpty; }
+ inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0; void runMessage() { debMsg("Executing kernel knCountFluidCells ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ int numEmpty = 0;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,flags,numEmpty);
+#pragma omp critical
+{this->numEmpty += numEmpty; } }
+ }
+ FlagGrid& flags; int numEmpty; }
+;
+
+//! averaged value for all cells (if flags are given, only for fluid cells)
+
+Real getGridAvg(Grid<Real>& source, FlagGrid* flags=NULL) {
+ double sum = knGridTotalSum(source, flags);
+
+ double cells;
+ if(flags) { cells = knCountFluidCells(*flags); }
+ else { cells = source.getSizeX()*source.getSizeY()*source.getSizeZ(); }
+
+ if(cells>0.) sum *= 1./cells;
+ else sum = -1.;
+ return sum;
+} static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getGridAvg" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",0,&_lock); FlagGrid* flags = _args.getPtrOpt<FlagGrid >("flags",1,NULL,&_lock); _retval = toPy(getGridAvg(source,flags)); _args.check(); }
+ pbFinalizePlugin(parent,"getGridAvg", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getGridAvg",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getGridAvg ("","getGridAvg",_W_15);
+extern "C" {
+ void PbRegister_getGridAvg() {
+ KEEP_UNUSED(_RP_getGridAvg); }
+ }
+
+
+
+//! transfer data between real and vec3 grids
+
+ struct knGetComponent : public KernelBase {
+ knGetComponent(const Grid<Vec3>& source, Grid<Real>& target, int component) : KernelBase(&source,0) ,source(source),target(target),component(component) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Vec3>& source, Grid<Real>& target, int component ) {
+ target[idx] = source[idx][component];
+} inline const Grid<Vec3>& getArg0() {
+ return source; }
+ typedef Grid<Vec3> type0;inline Grid<Real>& getArg1() {
+ return target; }
+ typedef Grid<Real> type1;inline int& getArg2() {
+ return component; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knGetComponent ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,source,target,component); }
+ }
+ const Grid<Vec3>& source; Grid<Real>& target; int component; }
+;
+void getComponent(const Grid<Vec3>& source, Grid<Real>& target, int component) { knGetComponent(source, target, component); } static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getComponent" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Vec3>& source = *_args.getPtr<Grid<Vec3> >("source",0,&_lock); Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",1,&_lock); int component = _args.get<int >("component",2,&_lock); _retval = getPyNone(); getComponent(source,target,component); _args.check(); }
+ pbFinalizePlugin(parent,"getComponent", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getComponent",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getComponent ("","getComponent",_W_16);
+extern "C" {
+ void PbRegister_getComponent() {
+ KEEP_UNUSED(_RP_getComponent); }
+ }
+
+
+
+ struct knSetComponent : public KernelBase {
+ knSetComponent(const Grid<Real>& source, Grid<Vec3>& target, int component) : KernelBase(&source,0) ,source(source),target(target),component(component) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& source, Grid<Vec3>& target, int component ) {
+ target[idx][component] = source[idx];
+} inline const Grid<Real>& getArg0() {
+ return source; }
+ typedef Grid<Real> type0;inline Grid<Vec3>& getArg1() {
+ return target; }
+ typedef Grid<Vec3> type1;inline int& getArg2() {
+ return component; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetComponent ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,source,target,component); }
+ }
+ const Grid<Real>& source; Grid<Vec3>& target; int component; }
+;
+void setComponent(const Grid<Real>& source, Grid<Vec3>& target, int component) { knSetComponent(source, target, component); } static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setComponent" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); int component = _args.get<int >("component",2,&_lock); _retval = getPyNone(); setComponent(source,target,component); _args.check(); }
+ pbFinalizePlugin(parent,"setComponent", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setComponent",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setComponent ("","setComponent",_W_17);
+extern "C" {
+ void PbRegister_setComponent() {
+ KEEP_UNUSED(_RP_setComponent); }
+ }
+
+
+
+//******************************************************************************
+// Specialization classes
+
+void FlagGrid::InitMinXWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(i - w - .5, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::InitMaxXWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(mSize.x-i-1.5-w, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::InitMinYWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(j - w - .5, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::InitMaxYWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(mSize.y-j-1.5-w, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::InitMinZWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(k - w - .5, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::InitMaxZWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(mSize.z-k-1.5-w, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::initDomain( const int &boundaryWidth
+ , const string &wallIn
+ , const string &openIn
+ , const string &inflowIn
+ , const string &outflowIn
+ , Grid<Real>* phiWalls ) {
+
+ int types[6] = {0};
+ bool set [6] = {false};
+ // make sure we have at least 6 entries
+ string wall = wallIn; wall.append(" ");
+ string open = openIn; open.append(" ");
+ string inflow = inflowIn; inflow.append(" ");
+ string outflow = outflowIn; outflow.append(" ");
+
+ if(phiWalls) phiWalls->setConst(1000000000);
+
+ for (int i = 0; i<6; ++i) {
+ //min x-direction
+ if(!set[0]) {
+ if(open[i]=='x') {types[0] = TypeOpen;set[0] = true;}
+ else if(inflow[i]=='x') {types[0] = TypeInflow;set[0] = true;}
+ else if(outflow[i]=='x') {types[0] = TypeOutflow;set[0] = true;}
+ else if(wall[i]=='x') {
+ types[0] = TypeObstacle;
+ if(phiWalls) InitMinXWall(boundaryWidth, *phiWalls);
+ set[0] = true;
+ }
+ }
+ //max x-direction
+ if(!set[1]) {
+ if(open[i]=='X') {types[1] = TypeOpen;set[1] = true;}
+ else if(inflow[i]=='X') {types[1] = TypeInflow;set[1] = true;}
+ else if(outflow[i]=='X') {types[1] = TypeOutflow;set[1] = true;}
+ else if(wall[i]=='X') {
+ types[1] = TypeObstacle;
+ if(phiWalls) InitMaxXWall(boundaryWidth, *phiWalls);
+ set[1] = true;
+ }
+ }
+ //min y-direction
+ if(!set[2]) {
+ if(open[i]=='y') {types[2] = TypeOpen;set[2] = true;}
+ else if(inflow[i]=='y') {types[2] = TypeInflow;set[2] = true;}
+ else if(outflow[i]=='y') {types[2] = TypeOutflow;set[2] = true;}
+ else if(wall[i]=='y') {
+ types[2] = TypeObstacle;
+ if(phiWalls) InitMinYWall(boundaryWidth, *phiWalls);
+ set[2] = true;
+ }
+ }
+ //max y-direction
+ if(!set[3]) {
+ if(open[i]=='Y') {types[3] = TypeOpen;set[3] = true;}
+ else if(inflow[i]=='Y') {types[3] = TypeInflow;set[3] = true;}
+ else if(outflow[i]=='Y') {types[3] = TypeOutflow;set[3] = true;}
+ else if(wall[i]=='Y') {
+ types[3] = TypeObstacle;
+ if(phiWalls) InitMaxYWall(boundaryWidth, *phiWalls);
+ set[3] = true;
+ }
+ }
+ if(this->is3D()) {
+ //min z-direction
+ if(!set[4]) {
+ if(open[i]=='z') {types[4] = TypeOpen;set[4] = true;}
+ else if(inflow[i]=='z') {types[4] = TypeInflow;set[4] = true;}
+ else if(outflow[i]=='z') {types[4] = TypeOutflow;set[4] = true;}
+ else if(wall[i]=='z') {
+ types[4] = TypeObstacle;
+ if(phiWalls) InitMinZWall(boundaryWidth, *phiWalls);
+ set[4] = true;
+ }
+ }
+ //max z-direction
+ if(!set[5]) {
+ if(open[i]=='Z') {types[5] = TypeOpen;set[5] = true;}
+ else if(inflow[i]=='Z') {types[5] = TypeInflow;set[5] = true;}
+ else if(outflow[i]=='Z') {types[5] = TypeOutflow;set[5] = true;}
+ else if(wall[i]=='Z') {
+ types[5] = TypeObstacle;
+ if(phiWalls) InitMaxZWall(boundaryWidth, *phiWalls);
+ set[5] = true;
+ }
+ }
+ }
+ }
+
+ setConst(TypeEmpty);
+ initBoundaries(boundaryWidth, types);
+}
+
+void FlagGrid::initBoundaries(const int &boundaryWidth, const int *types) {
+ const int w = boundaryWidth;
+ FOR_IJK(*this) {
+ bool bnd = (i <= w);
+ if (bnd) mData[index(i,j,k)] = types[0];
+ bnd = (i >= mSize.x-1-w);
+ if (bnd) mData[index(i,j,k)] = types[1];
+ bnd = (j <= w);
+ if (bnd) mData[index(i,j,k)] = types[2];
+ bnd = (j >= mSize.y-1-w);
+ if (bnd) mData[index(i,j,k)] = types[3];
+ if(is3D()) {
+ bnd = (k <= w);
+ if (bnd) mData[index(i,j,k)] = types[4];
+ bnd = (k >= mSize.z-1-w);
+ if (bnd) mData[index(i,j,k)] = types[5];
+ }
+ }
+}
+
+void FlagGrid::updateFromLevelset(LevelsetGrid& levelset, LevelsetGrid* obsLevelset) {
+ FOR_IDX(*this) {
+ if (!isObstacle(idx) && !isOutflow(idx)) {
+ const Real phi = levelset[idx];
+ if (phi <= levelset.invalidTimeValue()) continue;
+
+ mData[idx] &= ~(TypeEmpty | TypeFluid); // clear empty/fluid flags
+ mData[idx] |= (phi <= 0) ? TypeFluid : TypeEmpty; // set resepctive flag
+ }
+ if (obsLevelset && isOutflow(idx)) {
+ const Real phiObs = (*obsLevelset)[idx];
+ if (phiObs <= 0) mData[idx] = TypeObstacle; // enforce obstacle flag
+ }
+ }
+}
+
+void FlagGrid::fillGrid(int type) {
+ FOR_IDX(*this) {
+ if ((mData[idx] & TypeObstacle)==0 && (mData[idx] & TypeInflow)==0&& (mData[idx] & TypeOutflow)==0&& (mData[idx] & TypeOpen)==0)
+ mData[idx] = (mData[idx] & ~(TypeEmpty | TypeFluid)) | type;
+ }
+}
+
+// flag grid helper
+
+bool isIsolatedFluidCell(const IndexInt idx, const FlagGrid &flags)
+{
+ if(!flags.isFluid(idx)) return false;
+ if(flags.isFluid(idx-flags.getStrideX())) return false;
+ if(flags.isFluid(idx+flags.getStrideX())) return false;
+ if(flags.isFluid(idx-flags.getStrideY())) return false;
+ if(flags.isFluid(idx+flags.getStrideY())) return false;
+ if(!flags.is3D()) return true;
+ if(flags.isFluid(idx-flags.getStrideZ())) return false;
+ if(flags.isFluid(idx+flags.getStrideZ())) return false;
+ return true;
+}
+
+
+
+ struct knMarkIsolatedFluidCell : public KernelBase {
+ knMarkIsolatedFluidCell(FlagGrid &flags, const int mark) : KernelBase(&flags,0) ,flags(flags),mark(mark) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, FlagGrid &flags, const int mark ) {
+ if(isIsolatedFluidCell(idx, flags)) flags[idx] = mark;
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const int& getArg1() {
+ return mark; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel knMarkIsolatedFluidCell ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,flags,mark); }
+ }
+ FlagGrid& flags; const int mark; }
+;
+
+
+
+void markIsolatedFluidCell(FlagGrid &flags, const int mark) {
+ knMarkIsolatedFluidCell(flags, mark);
+} static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "markIsolatedFluidCell" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const int mark = _args.get<int >("mark",1,&_lock); _retval = getPyNone(); markIsolatedFluidCell(flags,mark); _args.check(); }
+ pbFinalizePlugin(parent,"markIsolatedFluidCell", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("markIsolatedFluidCell",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_markIsolatedFluidCell ("","markIsolatedFluidCell",_W_18);
+extern "C" {
+ void PbRegister_markIsolatedFluidCell() {
+ KEEP_UNUSED(_RP_markIsolatedFluidCell); }
+ }
+
+
+
+
+
+void copyMACData(const MACGrid &source, MACGrid &target, const FlagGrid& flags, const int flag, const int bnd) {
+ assertMsg (source.getSize().x == target.getSize().x && source.getSize().y == target.getSize().y && source.getSize().z == target.getSize().z, "different grid resolutions " << source.getSize() << " vs " << target.getSize() );
+
+ // Grid<Real> divGrid(target.getParent());
+ // DivergenceOpMAC(divGrid, target);
+ // Real fDivOrig = GridSumSqr(divGrid);
+
+ FOR_IJK_BND(target, bnd)
+ {
+ if(flags.get(i,j,k) & flag)
+ {
+ target(i,j,k) = source(i,j,k);
+ }
+ }
+
+ // DivergenceOpMAC(divGrid, target);
+ // Real fDivTransfer = GridSumSqr(divGrid);
+ // std::cout << "Divergence: " << fDivOrig << " -> " << fDivTransfer << std::endl;
+} static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "copyMACData" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const MACGrid& source = *_args.getPtr<MACGrid >("source",0,&_lock); MACGrid& target = *_args.getPtr<MACGrid >("target",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); const int flag = _args.get<int >("flag",3,&_lock); const int bnd = _args.get<int >("bnd",4,&_lock); _retval = getPyNone(); copyMACData(source,target,flags,flag,bnd); _args.check(); }
+ pbFinalizePlugin(parent,"copyMACData", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("copyMACData",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_copyMACData ("","copyMACData",_W_19);
+extern "C" {
+ void PbRegister_copyMACData() {
+ KEEP_UNUSED(_RP_copyMACData); }
+ }
+
+
+
+
+// explicit instantiation
+template class Grid<int>;
+template class Grid<Real>;
+template class Grid<Vec3>;
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h
new file mode 100644
index 00000000000..a1283db5eee
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h
@@ -0,0 +1,1025 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#ifndef _GRID_H
+#define _GRID_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "interpol.h"
+#include "interpolHigh.h"
+#include "kernel.h"
+
+namespace Manta {
+class LevelsetGrid;
+
+//! Base class for all grids
+class GridBase : public PbClass {public:
+ enum GridType {TypeNone=0,TypeReal=1,TypeInt=2,TypeVec3=4,TypeMAC=8,TypeLevelset=16,TypeFlags=32}
+;
+
+ GridBase(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "GridBase::GridBase" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new GridBase(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"GridBase::GridBase" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::GridBase",e.what()); return -1; }
+ }
+
+
+ //! Get the grids X dimension
+ inline int getSizeX() const { return mSize.x; } static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getSizeX" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeX()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getSizeX" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getSizeX",e.what()); return 0; }
+ }
+
+ //! Get the grids Y dimension
+ inline int getSizeY() const { return mSize.y; } static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getSizeY" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeY()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getSizeY" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getSizeY",e.what()); return 0; }
+ }
+
+ //! Get the grids Z dimension
+ inline int getSizeZ() const { return mSize.z; } static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getSizeZ" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeZ()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getSizeZ" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getSizeZ",e.what()); return 0; }
+ }
+
+ //! Get the grids dimensions
+ inline Vec3i getSize() const { return mSize; } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getSize" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSize()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getSize" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getSize",e.what()); return 0; }
+ }
+
+
+ //! Get Stride in X dimension
+ inline IndexInt getStrideX() const { return 1; }
+ //! Get Stride in Y dimension
+ inline IndexInt getStrideY() const { return mSize.x; }
+ //! Get Stride in Z dimension
+ inline IndexInt getStrideZ() const { return mStrideZ; }
+
+ inline Real getDx() const { return mDx; }
+
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(int i, int j, int k) const;
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(IndexInt idx) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec3i& p, int bnd) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec3i& p) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec3& p, int bnd = 0) const { return isInBounds(toVec3i(p), bnd); }
+ //! Check if linear index is in the range of the array
+ inline bool isInBounds(IndexInt idx) const;
+
+ //! Get the type of grid
+ inline GridType getType() const { return mType; }
+ //! Check dimensionality
+ inline bool is3D() const { return m3D; } static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::is3D" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->is3D()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::is3D" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::is3D",e.what()); return 0; }
+ }
+
+
+ //! Get index into the data
+ inline IndexInt index(int i, int j, int k) const { DEBUG_ONLY(checkIndex(i,j,k)); return (IndexInt)i + (IndexInt)mSize.x * j + (IndexInt)mStrideZ * k; }
+ //! Get index into the data
+ inline IndexInt index(const Vec3i& pos) const { DEBUG_ONLY(checkIndex(pos.x,pos.y,pos.z)); return (IndexInt)pos.x + (IndexInt)mSize.x * pos.y + (IndexInt)mStrideZ * pos.z; }
+
+ //! grid4d compatibility functions
+ inline bool is4D() const { return false; } static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::is4D" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->is4D()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::is4D" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::is4D",e.what()); return 0; }
+ }
+
+ inline int getSizeT() const { return 1; } static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getSizeT" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeT()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getSizeT" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getSizeT",e.what()); return 0; }
+ }
+
+ inline int getStrideT() const { return 0; } static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getStrideT" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getStrideT()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getStrideT" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getStrideT",e.what()); return 0; }
+ }
+
+ inline int index(int i, int j, int k, int unused) const { return index(i,j,k); }
+ inline bool isInBounds(int i,int j, int k, int t, int bnd) const { if(t!=0) return false; return isInBounds( Vec3i(i,j,k), bnd ); }
+
+protected:
+
+ GridType mType;
+ Vec3i mSize;
+ Real mDx;
+ bool m3D; // precomputed Z shift: to ensure 2D compatibility, always use this instead of sx*sy !
+ IndexInt mStrideZ; public: PbArgs _args; }
+#define _C_GridBase
+;
+
+//! Grid class
+
+template<class T> class Grid : public GridBase {public:
+ //! init new grid, values are set to zero
+ Grid(FluidSolver* parent, bool show = true); static int _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Grid::Grid" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); bool show = _args.getOpt<bool >("show",1,true,&_lock); obj = new Grid(parent,show); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Grid::Grid" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Grid::Grid",e.what()); return -1; }
+ }
+
+ //! init new grid with an existing array
+ Grid(FluidSolver* parent, T* data, bool show = true);
+ //! create new & copy content from another grid
+ Grid(const Grid<T>& a);
+ //! return memory to solver
+ virtual ~Grid();
+
+ typedef T BASETYPE;
+ typedef GridBase BASETYPE_GRID;
+
+ void save(std::string name); static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::save",e.what()); return 0; }
+ }
+
+ void load(std::string name); static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::load",e.what()); return 0; }
+ }
+
+
+ //! set all cells to zero
+ void clear(); static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::clear",e.what()); return 0; }
+ }
+
+
+ //! all kinds of access functions, use grid(), grid[] or grid.get()
+ //! access data
+ inline T get(int i,int j, int k) const { return mData[index(i,j,k)]; }
+ //! access data
+ inline T& get(int i,int j, int k) { return mData[index(i,j,k)]; }
+ //! access data
+ inline T get(IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T get(const Vec3i& pos) const { return mData[index(pos)]; }
+ //! access data
+ inline T& operator()(int i, int j, int k) { return mData[index(i, j, k)]; }
+ //! access data
+ inline T operator()(int i, int j, int k) const { return mData[index(i, j, k)]; }
+ //! access data
+ inline T& operator()(IndexInt idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T operator()(IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T& operator()(const Vec3i& pos) { return mData[index(pos)]; }
+ //! access data
+ inline T operator()(const Vec3i& pos) const { return mData[index(pos)]; }
+ //! access data
+ inline T& operator[](IndexInt idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline const T operator[](IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+
+ // interpolated access
+ inline T getInterpolated(const Vec3& pos) const { return interpol<T>(mData, mSize, mStrideZ, pos); }
+ inline void setInterpolated(const Vec3& pos, const T& val, Grid<Real>& sumBuffer) const { setInterpol<T>(mData, mSize, mStrideZ, pos, val, &sumBuffer[0]); }
+ // higher order interpolation (1=linear, 2=cubic)
+ inline T getInterpolatedHi(const Vec3& pos, int order) const {
+ switch(order) {
+ case 1: return interpol <T>(mData, mSize, mStrideZ, pos);
+ case 2: return interpolCubic<T>(mData, mSize, mStrideZ, pos);
+ default: assertMsg(false, "Unknown interpolation order "<<order); }
+ return T(0.); // should never be reached, just to prevent compiler warnings
+ }
+
+ // assignment / copy
+
+ //! warning - do not use "=" for grids in python, this copies the reference! not the grid content...
+ //Grid<T>& operator=(const Grid<T>& a);
+ //! copy content from other grid (use this one instead of operator= !)
+ Grid<T>& copyFrom(const Grid<T>& a, bool copyType=true ); static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::copyFrom" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<T>& a = *_args.getPtr<Grid<T> >("a",0,&_lock); bool copyType = _args.getOpt<bool >("copyType",1,true ,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->copyFrom(a,copyType)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::copyFrom" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::copyFrom",e.what()); return 0; }
+ }
+ // old: { *this = a; }
+
+ // helper functions to work with grids in scene files
+
+ //! get grid type
+ int getGridType(); static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getGridType" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getGridType()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getGridType" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getGridType",e.what()); return 0; }
+ }
+
+
+ //! add/subtract other grid
+ void add(const Grid<T>& a); static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::add" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<T>& a = *_args.getPtr<Grid<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->add(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::add" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::add",e.what()); return 0; }
+ }
+
+ void sub(const Grid<T>& a); static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::sub" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<T>& a = *_args.getPtr<Grid<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->sub(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::sub" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::sub",e.what()); return 0; }
+ }
+
+ //! set all cells to constant value
+ void setConst(T s); static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::setConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::setConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::setConst",e.what()); return 0; }
+ }
+
+ //! add constant to all grid cells
+ void addConst(T s); static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::addConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::addConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::addConst",e.what()); return 0; }
+ }
+
+ //! add scaled other grid to current one (note, only "Real" factor, "T" type not supported here!)
+ void addScaled(const Grid<T>& a, const T& factor); static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::addScaled" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<T>& a = *_args.getPtr<Grid<T> >("a",0,&_lock); const T& factor = *_args.getPtr<T >("factor",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addScaled(a,factor); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::addScaled" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::addScaled",e.what()); return 0; }
+ }
+
+ //! multiply contents of grid
+ void mult( const Grid<T>& a); static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::mult" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<T>& a = *_args.getPtr<Grid<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->mult(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::mult" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::mult",e.what()); return 0; }
+ }
+
+ //! multiply each cell by a constant scalar value
+ void multConst(T s); static PyObject* _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::multConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->multConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::multConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::multConst",e.what()); return 0; }
+ }
+
+ //! clamp content to range (for vec3, clamps each component separately)
+ void clamp(Real min, Real max); static PyObject* _W_22 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::clamp" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real min = _args.get<Real >("min",0,&_lock); Real max = _args.get<Real >("max",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clamp(min,max); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::clamp" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::clamp",e.what()); return 0; }
+ }
+
+ //! reduce small values to zero
+ void stomp(const T& threshold); static PyObject* _W_23 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::stomp" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& threshold = *_args.getPtr<T >("threshold",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->stomp(threshold); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::stomp" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::stomp",e.what()); return 0; }
+ }
+
+
+ // common compound operators
+ //! get absolute max value in grid
+ Real getMaxAbs() const ; static PyObject* _W_24 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getMaxAbs" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxAbs()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getMaxAbs" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getMaxAbs",e.what()); return 0; }
+ }
+
+ //! get max value in grid
+ Real getMax() const ; static PyObject* _W_25 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMax()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getMax",e.what()); return 0; }
+ }
+
+ //! get min value in grid
+ Real getMin() const ; static PyObject* _W_26 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMin()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getMin",e.what()); return 0; }
+ }
+
+ //! calculate L1 norm of grid content
+ Real getL1(int bnd=0); static PyObject* _W_27 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getL1" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int bnd = _args.getOpt<int >("bnd",0,0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->getL1(bnd)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getL1" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getL1",e.what()); return 0; }
+ }
+
+ //! calculate L2 norm of grid content
+ Real getL2(int bnd=0); static PyObject* _W_28 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getL2" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int bnd = _args.getOpt<int >("bnd",0,0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->getL2(bnd)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getL2" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getL2",e.what()); return 0; }
+ }
+
+
+ //! set all boundary cells to constant value (Dirichlet)
+ void setBound(T value, int boundaryWidth=1); static PyObject* _W_29 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::setBound" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T value = _args.get<T >("value",0,&_lock); int boundaryWidth = _args.getOpt<int >("boundaryWidth",1,1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setBound(value,boundaryWidth); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::setBound" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::setBound",e.what()); return 0; }
+ }
+
+ //! set all boundary cells to last inner value (Neumann)
+ void setBoundNeumann(int boundaryWidth=1); static PyObject* _W_30 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::setBoundNeumann" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int boundaryWidth = _args.getOpt<int >("boundaryWidth",0,1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setBoundNeumann(boundaryWidth); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::setBoundNeumann" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::setBoundNeumann",e.what()); return 0; }
+ }
+
+
+ //! get data pointer of grid
+ std::string getDataPointer(); static PyObject* _W_31 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getDataPointer",e.what()); return 0; }
+ }
+
+
+ //! debugging helper, print grid from python. skip boundary of width bnd
+ void printGrid(int zSlice=-1, bool printIndex=false, int bnd=1); static PyObject* _W_32 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::printGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int zSlice = _args.getOpt<int >("zSlice",0,-1,&_lock); bool printIndex = _args.getOpt<bool >("printIndex",1,false,&_lock); int bnd = _args.getOpt<int >("bnd",2,1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->printGrid(zSlice,printIndex,bnd); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::printGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::printGrid",e.what()); return 0; }
+ }
+
+
+ // c++ only operators
+ template<class S> Grid<T>& operator+=(const Grid<S>& a);
+ template<class S> Grid<T>& operator+=(const S& a);
+ template<class S> Grid<T>& operator-=(const Grid<S>& a);
+ template<class S> Grid<T>& operator-=(const S& a);
+ template<class S> Grid<T>& operator*=(const Grid<S>& a);
+ template<class S> Grid<T>& operator*=(const S& a);
+ template<class S> Grid<T>& operator/=(const Grid<S>& a);
+ template<class S> Grid<T>& operator/=(const S& a);
+ Grid<T>& safeDivide(const Grid<T>& a);
+
+ //! Swap data with another grid (no actual data is moved)
+ void swap(Grid<T>& other);
+
+ //! grid4d compatibility functions
+ inline T& operator()(int i, int j, int k, int unused) { return mData[index(i, j, k)]; }
+ inline T operator() (int i, int j, int k, int unused) const { return mData[index(i, j, k)]; }
+
+protected: T* mData; bool externalData; // True if mData is managed outside of the Fluidsolver
+public: PbArgs _args; }
+#define _C_Grid
+;
+
+// Python doesn't know about templates: explicit aliases needed
+
+
+
+
+//! Special function for staggered grids
+class MACGrid : public Grid<Vec3> {public:
+ MACGrid(FluidSolver* parent, bool show=true) :Grid<Vec3>(parent,show){
+ mType = (GridType)(TypeMAC | TypeVec3); } static int _W_33 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "MACGrid::MACGrid" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); bool show = _args.getOpt<bool >("show",1,true,&_lock); obj = new MACGrid(parent,show); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"MACGrid::MACGrid" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("MACGrid::MACGrid",e.what()); return -1; }
+ }
+
+ MACGrid(FluidSolver* parent, Vec3* data, bool show=true) : Grid<Vec3>(parent, data, show) {
+ mType = (GridType)(TypeMAC | TypeVec3); }
+
+ // specialized functions for interpolating MAC information
+ inline Vec3 getCentered(int i, int j, int k) const;
+ inline Vec3 getCentered(const Vec3i& pos) const { return getCentered(pos.x, pos.y, pos.z); }
+ inline Vec3 getAtMACX(int i, int j, int k) const;
+ inline Vec3 getAtMACY(int i, int j, int k) const;
+ inline Vec3 getAtMACZ(int i, int j, int k) const;
+ // interpolation
+ inline Vec3 getInterpolated(const Vec3& pos) const { return interpolMAC(mData, mSize, mStrideZ, pos); }
+ inline void setInterpolated(const Vec3& pos, const Vec3& val, Vec3* tmp) const { return setInterpolMAC(mData, mSize, mStrideZ, pos, val, tmp); }
+ inline Vec3 getInterpolatedHi(const Vec3& pos, int order) const {
+ switch(order) {
+ case 1: return interpolMAC (mData, mSize, mStrideZ, pos);
+ case 2: return interpolCubicMAC(mData, mSize, mStrideZ, pos);
+ default: assertMsg(false, "Unknown interpolation order "<<order); }
+ return Vec3(0.); // should never be reached, just to prevent compiler warnings
+ }
+ // specials for mac grid:
+ template<int comp> inline Real getInterpolatedComponent(Vec3 pos) const { return interpolComponent<comp>(mData, mSize, mStrideZ, pos); }
+ template<int comp> inline Real getInterpolatedComponentHi(const Vec3& pos, int order) const {
+ switch(order) {
+ case 1: return interpolComponent<comp>(mData, mSize, mStrideZ, pos);
+ case 2: return interpolCubicMAC(mData, mSize, mStrideZ, pos)[comp]; // warning - not yet optimized
+ default: assertMsg(false, "Unknown interpolation order "<<order); }
+ return 0.; // should never be reached, just to prevent compiler warnings
+ }
+
+ //! set all boundary cells of a MAC grid to certain value (Dirchlet). Respects staggered grid locations
+ //! optionally, only set normal components
+ void setBoundMAC(Vec3 value, int boundaryWidth, bool normalOnly=false); static PyObject* _W_34 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MACGrid* pbo = dynamic_cast<MACGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MACGrid::setBoundMAC" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 value = _args.get<Vec3 >("value",0,&_lock); int boundaryWidth = _args.get<int >("boundaryWidth",1,&_lock); bool normalOnly = _args.getOpt<bool >("normalOnly",2,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setBoundMAC(value,boundaryWidth,normalOnly); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MACGrid::setBoundMAC" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MACGrid::setBoundMAC",e.what()); return 0; }
+ }
+
+ protected: public: PbArgs _args; }
+#define _C_MACGrid
+;
+
+//! Special functions for FlagGrid
+class FlagGrid : public Grid<int> {public:
+ FlagGrid(FluidSolver* parent, int dim=3, bool show=true) :Grid<int>(parent,show){
+ mType = (GridType)(TypeFlags | TypeInt); } static int _W_35 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "FlagGrid::FlagGrid" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); int dim = _args.getOpt<int >("dim",1,3,&_lock); bool show = _args.getOpt<bool >("show",2,true,&_lock); obj = new FlagGrid(parent,dim,show); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"FlagGrid::FlagGrid" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("FlagGrid::FlagGrid",e.what()); return -1; }
+ }
+
+ FlagGrid(FluidSolver* parent, int* data, int dim = 3, bool show=true) : Grid<int>(parent, data, show) {
+ mType = (GridType)(TypeFlags | TypeInt); }
+
+ //! types of cells, in/outflow can be combined, e.g., TypeFluid|TypeInflow
+ enum CellType {TypeNone=0,TypeFluid=1,TypeObstacle=2,TypeEmpty=4,TypeInflow=8,TypeOutflow=16,TypeOpen=32,TypeStick=64,TypeReserved=256}
+;
+
+ //! access for particles
+ inline int getAt(const Vec3& pos) const { return mData[index((int)pos.x, (int)pos.y, (int)pos.z)]; }
+
+ //! check for different flag types
+ inline bool isObstacle(IndexInt idx) const { return get(idx) & TypeObstacle; }
+ inline bool isObstacle(int i, int j, int k) const { return get(i,j,k) & TypeObstacle; }
+ inline bool isObstacle(const Vec3i& pos) const { return get(pos) & TypeObstacle; }
+ inline bool isObstacle(const Vec3& pos) const { return getAt(pos) & TypeObstacle; }
+ inline bool isFluid(IndexInt idx) const { return get(idx) & TypeFluid; }
+ inline bool isFluid(int i, int j, int k) const { return get(i,j,k) & TypeFluid; }
+ inline bool isFluid(const Vec3i& pos) const { return get(pos) & TypeFluid; }
+ inline bool isFluid(const Vec3& pos) const { return getAt(pos) & TypeFluid; }
+ inline bool isInflow(IndexInt idx) const { return get(idx) & TypeInflow; }
+ inline bool isInflow(int i, int j, int k) const { return get(i,j,k) & TypeInflow; }
+ inline bool isInflow(const Vec3i& pos) const { return get(pos) & TypeInflow; }
+ inline bool isInflow(const Vec3& pos) const { return getAt(pos) & TypeInflow; }
+ inline bool isEmpty(IndexInt idx) const { return get(idx) & TypeEmpty; }
+ inline bool isEmpty(int i, int j, int k) const { return get(i,j,k) & TypeEmpty; }
+ inline bool isEmpty(const Vec3i& pos) const { return get(pos) & TypeEmpty; }
+ inline bool isEmpty(const Vec3& pos) const { return getAt(pos) & TypeEmpty; }
+ inline bool isOutflow(IndexInt idx) const { return get(idx) & TypeOutflow; }
+ inline bool isOutflow(int i, int j, int k) const { return get(i, j, k) & TypeOutflow; }
+ inline bool isOutflow(const Vec3i& pos) const { return get(pos) & TypeOutflow; }
+ inline bool isOutflow(const Vec3& pos) const { return getAt(pos) & TypeOutflow; }
+ inline bool isOpen(IndexInt idx) const { return get(idx) & TypeOpen; }
+ inline bool isOpen(int i, int j, int k) const { return get(i, j, k) & TypeOpen; }
+ inline bool isOpen(const Vec3i& pos) const { return get(pos) & TypeOpen; }
+ inline bool isOpen(const Vec3& pos) const { return getAt(pos) & TypeOpen; }
+ inline bool isStick(IndexInt idx) const { return get(idx) & TypeStick; }
+ inline bool isStick(int i, int j, int k) const { return get(i,j,k) & TypeStick; }
+ inline bool isStick(const Vec3i& pos) const { return get(pos) & TypeStick; }
+ inline bool isStick(const Vec3& pos) const { return getAt(pos) & TypeStick; }
+
+
+ void InitMinXWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ void InitMaxXWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ void InitMinYWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ void InitMaxYWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ void InitMinZWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ void InitMaxZWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ // Python callables
+
+
+
+
+
+void initDomain( const int &boundaryWidth = 0 , const std::string &wall = "xXyYzZ" , const std::string &open = " " , const std::string &inflow = " " , const std::string &outflow = " " , Grid<Real>* phiWalls = 0x00 ); static PyObject* _W_36 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FlagGrid::initDomain" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const int& boundaryWidth = _args.getOpt<int >("boundaryWidth",0,0 ,&_lock); const std::string& wall = _args.getOpt<std::string >("wall",1,"xXyYzZ" ,&_lock); const std::string& open = _args.getOpt<std::string >("open",2," " ,&_lock); const std::string& inflow = _args.getOpt<std::string >("inflow",3," " ,&_lock); const std::string& outflow = _args.getOpt<std::string >("outflow",4," " ,&_lock); Grid<Real>* phiWalls = _args.getPtrOpt<Grid<Real> >("phiWalls",5,0x00 ,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->initDomain(boundaryWidth,wall,open,inflow,outflow,phiWalls); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FlagGrid::initDomain" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FlagGrid::initDomain",e.what()); return 0; }
+ }
+
+
+ void initBoundaries( const int &boundaryWidth, const int *types );
+
+ //! set fluid flags inside levelset (liquids)
+ void updateFromLevelset(LevelsetGrid& levelset, LevelsetGrid* obsLevelset=NULL); static PyObject* _W_37 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FlagGrid::updateFromLevelset" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; LevelsetGrid& levelset = *_args.getPtr<LevelsetGrid >("levelset",0,&_lock); LevelsetGrid* obsLevelset = _args.getPtrOpt<LevelsetGrid >("obsLevelset",1,NULL,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->updateFromLevelset(levelset,obsLevelset); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FlagGrid::updateFromLevelset" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FlagGrid::updateFromLevelset",e.what()); return 0; }
+ }
+
+ //! set all cells (except obs/in/outflow) to type (fluid by default)
+ void fillGrid(int type=TypeFluid); static PyObject* _W_38 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FlagGrid::fillGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int type = _args.getOpt<int >("type",0,TypeFluid,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->fillGrid(type); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FlagGrid::fillGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FlagGrid::fillGrid",e.what()); return 0; }
+ }
+
+ //! count no. of cells matching flags via "AND"
+ //! warning for large grids! only regular int returned (due to python interface)
+ //! optionally creates mask in RealGrid (1 where flag matches, 0 otherwise)
+ int countCells(int flag, int bnd=0, Grid<Real>* mask=NULL); static PyObject* _W_39 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FlagGrid::countCells" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int flag = _args.get<int >("flag",0,&_lock); int bnd = _args.getOpt<int >("bnd",1,0,&_lock); Grid<Real>* mask = _args.getPtrOpt<Grid<Real> >("mask",2,NULL,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->countCells(flag,bnd,mask)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FlagGrid::countCells" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FlagGrid::countCells",e.what()); return 0; }
+ }
+ public: PbArgs _args; }
+#define _C_FlagGrid
+;
+
+//! helper to compute grid conversion factor between local coordinates of two grids
+inline Vec3 calcGridSizeFactor(Vec3i s1, Vec3i s2) {
+ return Vec3( Real(s1[0])/s2[0], Real(s1[1])/s2[1], Real(s1[2])/s2[2] );
+}
+
+// prototypes for grid plugins
+void copyMacToVec3(MACGrid &source, Grid<Vec3>& target);
+void convertMacToVec3(MACGrid &source, Grid<Vec3>& target);
+void resampleVec3ToMac(Grid<Vec3>& source, MACGrid &target);
+void resampleMacToVec3 (MACGrid &source, Grid<Vec3>& target );
+
+void getComponent(const Grid<Vec3>& source, Grid<Real>& target, int component);
+void setComponent(const Grid<Real>& source, Grid<Vec3>& target, int component);
+
+
+
+
+//******************************************************************************
+// Implementation of inline functions
+
+inline void GridBase::checkIndex(int i, int j, int k) const {
+ if (i<0 || j<0 || k<0 || i>=mSize.x || j>=mSize.y || k>=mSize.z) {
+ std::ostringstream s;
+ s << "Grid " << mName << " dim " << mSize << " : index " << i << "," << j << "," << k << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+inline void GridBase::checkIndex(IndexInt idx) const {
+ if (idx<0 || idx >= mSize.x * mSize.y * mSize.z) {
+ std::ostringstream s;
+ s << "Grid " << mName << " dim " << mSize << " : index " << idx << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+bool GridBase::isInBounds(const Vec3i& p) const {
+ return (p.x >= 0 && p.y >= 0 && p.z >= 0 && p.x < mSize.x && p.y < mSize.y && p.z < mSize.z);
+}
+
+bool GridBase::isInBounds(const Vec3i& p, int bnd) const {
+ bool ret = (p.x >= bnd && p.y >= bnd && p.x < mSize.x-bnd && p.y < mSize.y-bnd);
+ if(this->is3D()) {
+ ret &= (p.z >= bnd && p.z < mSize.z-bnd);
+ } else {
+ ret &= (p.z == 0);
+ }
+ return ret;
+}
+//! Check if linear index is in the range of the array
+bool GridBase::isInBounds(IndexInt idx) const {
+ if (idx<0 || idx >= mSize.x * mSize.y * mSize.z) {
+ return false;
+ }
+ return true;
+}
+
+inline Vec3 MACGrid::getCentered(int i, int j, int k) const {
+ DEBUG_ONLY(checkIndex(i+1,j+1,k));
+ const IndexInt idx = index(i,j,k);
+ Vec3 v = Vec3(0.5* (mData[idx].x + mData[idx+1].x),
+ 0.5* (mData[idx].y + mData[idx+mSize.x].y),
+ 0.);
+ if( this->is3D() ) {
+ DEBUG_ONLY(checkIndex(idx+mStrideZ));
+ v[2] = 0.5* (mData[idx].z + mData[idx+mStrideZ].z);
+ }
+ return v;
+}
+
+inline Vec3 MACGrid::getAtMACX(int i, int j, int k) const {
+ DEBUG_ONLY(checkIndex(i-1,j+1,k));
+ const IndexInt idx = index(i,j,k);
+ Vec3 v = Vec3( (mData[idx].x),
+ 0.25* (mData[idx].y + mData[idx-1].y + mData[idx+mSize.x].y + mData[idx+mSize.x-1].y),
+ 0.);
+ if( this->is3D() ) {
+ DEBUG_ONLY(checkIndex(idx+mStrideZ-1));
+ v[2] = 0.25* (mData[idx].z + mData[idx-1].z + mData[idx+mStrideZ].z + mData[idx+mStrideZ-1].z);
+ }
+ return v;
+}
+
+inline Vec3 MACGrid::getAtMACY(int i, int j, int k) const {
+ DEBUG_ONLY(checkIndex(i+1,j-1,k));
+ const IndexInt idx = index(i,j,k);
+ Vec3 v = Vec3(0.25* (mData[idx].x + mData[idx-mSize.x].x + mData[idx+1].x + mData[idx+1-mSize.x].x),
+ (mData[idx].y), 0. );
+ if( this->is3D() ) {
+ DEBUG_ONLY(checkIndex(idx+mStrideZ-mSize.x));
+ v[2] = 0.25* (mData[idx].z + mData[idx-mSize.x].z + mData[idx+mStrideZ].z + mData[idx+mStrideZ-mSize.x].z);
+ }
+ return v;
+}
+
+inline Vec3 MACGrid::getAtMACZ(int i, int j, int k) const {
+ const IndexInt idx = index(i,j,k);
+ DEBUG_ONLY(checkIndex(idx-mStrideZ));
+ DEBUG_ONLY(checkIndex(idx+mSize.x-mStrideZ));
+ Vec3 v = Vec3(0.25* (mData[idx].x + mData[idx-mStrideZ].x + mData[idx+1].x + mData[idx+1-mStrideZ].x),
+ 0.25* (mData[idx].y + mData[idx-mStrideZ].y + mData[idx+mSize.x].y + mData[idx+mSize.x-mStrideZ].y),
+ (mData[idx].z) );
+ return v;
+}
+
+template <class T, class S> struct gridAdd : public KernelBase {
+ gridAdd(Grid<T>& me, const Grid<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<S>& other ) { me[idx] += other[idx]; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<S>& getArg1() {
+ return other; }
+ typedef Grid<S> type1; void runMessage() { debMsg("Executing kernel gridAdd ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid<T>& me; const Grid<S>& other; }
+;
+template <class T, class S> struct gridSub : public KernelBase {
+ gridSub(Grid<T>& me, const Grid<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<S>& other ) { me[idx] -= other[idx]; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<S>& getArg1() {
+ return other; }
+ typedef Grid<S> type1; void runMessage() { debMsg("Executing kernel gridSub ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid<T>& me; const Grid<S>& other; }
+;
+template <class T, class S> struct gridMult : public KernelBase {
+ gridMult(Grid<T>& me, const Grid<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<S>& other ) { me[idx] *= other[idx]; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<S>& getArg1() {
+ return other; }
+ typedef Grid<S> type1; void runMessage() { debMsg("Executing kernel gridMult ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid<T>& me; const Grid<S>& other; }
+;
+template <class T, class S> struct gridDiv : public KernelBase {
+ gridDiv(Grid<T>& me, const Grid<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<S>& other ) { me[idx] /= other[idx]; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<S>& getArg1() {
+ return other; }
+ typedef Grid<S> type1; void runMessage() { debMsg("Executing kernel gridDiv ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid<T>& me; const Grid<S>& other; }
+;
+template <class T, class S> struct gridAddScalar : public KernelBase {
+ gridAddScalar(Grid<T>& me, const S& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const S& other ) { me[idx] += other; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel gridAddScalar ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid<T>& me; const S& other; }
+;
+template <class T, class S> struct gridMultScalar : public KernelBase {
+ gridMultScalar(Grid<T>& me, const S& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const S& other ) { me[idx] *= other; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel gridMultScalar ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid<T>& me; const S& other; }
+;
+template <class T, class S> struct gridScaledAdd : public KernelBase {
+ gridScaledAdd(Grid<T>& me, const Grid<T>& other, const S& factor) : KernelBase(&me,0) ,me(me),other(other),factor(factor) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<T>& other, const S& factor ) { me[idx] += factor * other[idx]; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<T>& getArg1() {
+ return other; }
+ typedef Grid<T> type1;inline const S& getArg2() {
+ return factor; }
+ typedef S type2; void runMessage() { debMsg("Executing kernel gridScaledAdd ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other,factor); }
+ }
+ Grid<T>& me; const Grid<T>& other; const S& factor; }
+;
+
+template <class T> struct gridSetConst : public KernelBase {
+ gridSetConst(Grid<T>& grid, T value) : KernelBase(&grid,0) ,grid(grid),value(value) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& grid, T value ) { grid[idx] = value; } inline Grid<T>& getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel gridSetConst ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,grid,value); }
+ }
+ Grid<T>& grid; T value; }
+;
+
+template<class T> template<class S> Grid<T>& Grid<T>::operator+= (const Grid<S>& a) {
+ gridAdd<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator+= (const S& a) {
+ gridAddScalar<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator-= (const Grid<S>& a) {
+ gridSub<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator-= (const S& a) {
+ gridAddScalar<T,S> (*this, -a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator*= (const Grid<S>& a) {
+ gridMult<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator*= (const S& a) {
+ gridMultScalar<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator/= (const Grid<S>& a) {
+ gridDiv<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator/= (const S& a) {
+ S rez((S)1.0 / a);
+ gridMultScalar<T,S> (*this, rez);
+ return *this;
+}
+
+//******************************************************************************
+// Other helper functions
+
+// compute gradient of a scalar grid
+inline Vec3 getGradient(const Grid<Real>& data, int i, int j, int k) {
+ Vec3 v;
+
+ if (i > data.getSizeX()-2) i= data.getSizeX()-2;
+ if (j > data.getSizeY()-2) j= data.getSizeY()-2;
+ if (i < 1) i = 1;
+ if (j < 1) j = 1;
+ v = Vec3( data(i+1,j ,k ) - data(i-1,j ,k ) ,
+ data(i ,j+1,k ) - data(i ,j-1,k ) , 0. );
+
+ if(data.is3D()) {
+ if (k > data.getSizeZ()-2) k= data.getSizeZ()-2;
+ if (k < 1) k = 1;
+ v[2]= data(i ,j ,k+1) - data(i ,j ,k-1);
+ }
+
+ return v;
+}
+
+// interpolate grid from one size to another size
+
+template <class S> struct knInterpolateGridTempl : public KernelBase {
+ knInterpolateGridTempl(Grid<S>& target, const Grid<S>& source, const Vec3& sourceFactor , Vec3 offset, int orderSpace=1 ) : KernelBase(&target,0) ,target(target),source(source),sourceFactor(sourceFactor),offset(offset),orderSpace(orderSpace) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<S>& target, const Grid<S>& source, const Vec3& sourceFactor , Vec3 offset, int orderSpace=1 ) {
+ Vec3 pos = Vec3(i,j,k) * sourceFactor + offset;
+ if(!source.is3D()) pos[2] = 0; // allow 2d -> 3d
+ target(i,j,k) = source.getInterpolatedHi(pos, orderSpace);
+} inline Grid<S>& getArg0() {
+ return target; }
+ typedef Grid<S> type0;inline const Grid<S>& getArg1() {
+ return source; }
+ typedef Grid<S> type1;inline const Vec3& getArg2() {
+ return sourceFactor; }
+ typedef Vec3 type2;inline Vec3& getArg3() {
+ return offset; }
+ typedef Vec3 type3;inline int& getArg4() {
+ return orderSpace; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel knInterpolateGridTempl ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,target,source,sourceFactor,offset,orderSpace); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,target,source,sourceFactor,offset,orderSpace); }
+ }
+ }
+ Grid<S>& target; const Grid<S>& source; const Vec3& sourceFactor; Vec3 offset; int orderSpace; }
+;
+// template glue code - choose interpolation based on template arguments
+template<class GRID>
+void interpolGridTempl( GRID& target, GRID& source ) {
+ errMsg("interpolGridTempl - Only valid for specific instantiations");
+}
+
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h.reg
new file mode 100644
index 00000000000..85eade2f2d9
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h.reg
@@ -0,0 +1,72 @@
+#include "grid.h"
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","GridBase","PbClass"); template<> const char* Namify<GridBase >::S = "GridBase";
+>GridBase^
+&static const Pb::Register _R_$IDX$ ("GridType_TypeNone",0);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeReal",1);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeInt",2);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeVec3",4);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeMAC",8);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeLevelset",16);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeFlags",32);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","GridBase",GridBase::_W_0);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getSizeX",GridBase::_W_1);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getSizeY",GridBase::_W_2);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getSizeZ",GridBase::_W_3);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getSize",GridBase::_W_4);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","is3D",GridBase::_W_5);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","is4D",GridBase::_W_6);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getSizeT",GridBase::_W_7);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getStrideT",GridBase::_W_8);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","Grid<$CT$>","GridBase"); template<> const char* Namify<Grid<$CT$> >::S = "Grid<$CT$>";
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","Grid",Grid<$CT$>::_W_9);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","save",Grid<$CT$>::_W_10);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","load",Grid<$CT$>::_W_11);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","clear",Grid<$CT$>::_W_12);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","copyFrom",Grid<$CT$>::_W_13);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getGridType",Grid<$CT$>::_W_14);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","add",Grid<$CT$>::_W_15);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","sub",Grid<$CT$>::_W_16);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","setConst",Grid<$CT$>::_W_17);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","addConst",Grid<$CT$>::_W_18);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","addScaled",Grid<$CT$>::_W_19);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","mult",Grid<$CT$>::_W_20);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","multConst",Grid<$CT$>::_W_21);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","clamp",Grid<$CT$>::_W_22);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","stomp",Grid<$CT$>::_W_23);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getMaxAbs",Grid<$CT$>::_W_24);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getMax",Grid<$CT$>::_W_25);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getMin",Grid<$CT$>::_W_26);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getL1",Grid<$CT$>::_W_27);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getL2",Grid<$CT$>::_W_28);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","setBound",Grid<$CT$>::_W_29);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","setBoundNeumann",Grid<$CT$>::_W_30);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getDataPointer",Grid<$CT$>::_W_31);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","printGrid",Grid<$CT$>::_W_32);
+>Grid^int
+&static const Pb::Register _R_$IDX$ ("Grid<int>","IntGrid","");
+>Grid^Real
+&static const Pb::Register _R_$IDX$ ("Grid<Real>","RealGrid","");
+>Grid^Vec3
+&static const Pb::Register _R_$IDX$ ("Grid<Vec3>","VecGrid","");
++MACGrid^ static const Pb::Register _R_$IDX$ ("MACGrid","MACGrid","Grid<$BT$>"); template<> const char* Namify<MACGrid >::S = "MACGrid";
+>MACGrid^
+@MACGrid^^Grid^Vec3
++MACGrid^ static const Pb::Register _R_$IDX$ ("MACGrid","MACGrid",MACGrid::_W_33);
++MACGrid^ static const Pb::Register _R_$IDX$ ("MACGrid","setBoundMAC",MACGrid::_W_34);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","FlagGrid","Grid<$BT$>"); template<> const char* Namify<FlagGrid >::S = "FlagGrid";
+>FlagGrid^
+@FlagGrid^^Grid^int
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","FlagGrid",FlagGrid::_W_35);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeNone",0);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeFluid",1);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeObstacle",2);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeEmpty",4);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeInflow",8);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeOutflow",16);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeOpen",32);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeStick",64);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeReserved",256);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","initDomain",FlagGrid::_W_36);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","updateFromLevelset",FlagGrid::_W_37);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","fillGrid",FlagGrid::_W_38);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","countCells",FlagGrid::_W_39);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h.reg.cpp
new file mode 100644
index 00000000000..c4a104fa03a
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid.h.reg.cpp
@@ -0,0 +1,233 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "grid.h"
+namespace Manta {
+#ifdef _C_FlagGrid
+ static const Pb::Register _R_26 ("FlagGrid","FlagGrid","Grid<int>"); template<> const char* Namify<FlagGrid >::S = "FlagGrid";
+ static const Pb::Register _R_27 ("FlagGrid","FlagGrid",FlagGrid::_W_35);
+ static const Pb::Register _R_28 ("FlagGrid","initDomain",FlagGrid::_W_36);
+ static const Pb::Register _R_29 ("FlagGrid","updateFromLevelset",FlagGrid::_W_37);
+ static const Pb::Register _R_30 ("FlagGrid","fillGrid",FlagGrid::_W_38);
+ static const Pb::Register _R_31 ("FlagGrid","countCells",FlagGrid::_W_39);
+#endif
+#ifdef _C_Grid
+ static const Pb::Register _R_32 ("Grid<int>","Grid<int>","GridBase"); template<> const char* Namify<Grid<int> >::S = "Grid<int>";
+ static const Pb::Register _R_33 ("Grid<int>","Grid",Grid<int>::_W_9);
+ static const Pb::Register _R_34 ("Grid<int>","save",Grid<int>::_W_10);
+ static const Pb::Register _R_35 ("Grid<int>","load",Grid<int>::_W_11);
+ static const Pb::Register _R_36 ("Grid<int>","clear",Grid<int>::_W_12);
+ static const Pb::Register _R_37 ("Grid<int>","copyFrom",Grid<int>::_W_13);
+ static const Pb::Register _R_38 ("Grid<int>","getGridType",Grid<int>::_W_14);
+ static const Pb::Register _R_39 ("Grid<int>","add",Grid<int>::_W_15);
+ static const Pb::Register _R_40 ("Grid<int>","sub",Grid<int>::_W_16);
+ static const Pb::Register _R_41 ("Grid<int>","setConst",Grid<int>::_W_17);
+ static const Pb::Register _R_42 ("Grid<int>","addConst",Grid<int>::_W_18);
+ static const Pb::Register _R_43 ("Grid<int>","addScaled",Grid<int>::_W_19);
+ static const Pb::Register _R_44 ("Grid<int>","mult",Grid<int>::_W_20);
+ static const Pb::Register _R_45 ("Grid<int>","multConst",Grid<int>::_W_21);
+ static const Pb::Register _R_46 ("Grid<int>","clamp",Grid<int>::_W_22);
+ static const Pb::Register _R_47 ("Grid<int>","stomp",Grid<int>::_W_23);
+ static const Pb::Register _R_48 ("Grid<int>","getMaxAbs",Grid<int>::_W_24);
+ static const Pb::Register _R_49 ("Grid<int>","getMax",Grid<int>::_W_25);
+ static const Pb::Register _R_50 ("Grid<int>","getMin",Grid<int>::_W_26);
+ static const Pb::Register _R_51 ("Grid<int>","getL1",Grid<int>::_W_27);
+ static const Pb::Register _R_52 ("Grid<int>","getL2",Grid<int>::_W_28);
+ static const Pb::Register _R_53 ("Grid<int>","setBound",Grid<int>::_W_29);
+ static const Pb::Register _R_54 ("Grid<int>","setBoundNeumann",Grid<int>::_W_30);
+ static const Pb::Register _R_55 ("Grid<int>","getDataPointer",Grid<int>::_W_31);
+ static const Pb::Register _R_56 ("Grid<int>","printGrid",Grid<int>::_W_32);
+ static const Pb::Register _R_57 ("Grid<Real>","Grid<Real>","GridBase"); template<> const char* Namify<Grid<Real> >::S = "Grid<Real>";
+ static const Pb::Register _R_58 ("Grid<Real>","Grid",Grid<Real>::_W_9);
+ static const Pb::Register _R_59 ("Grid<Real>","save",Grid<Real>::_W_10);
+ static const Pb::Register _R_60 ("Grid<Real>","load",Grid<Real>::_W_11);
+ static const Pb::Register _R_61 ("Grid<Real>","clear",Grid<Real>::_W_12);
+ static const Pb::Register _R_62 ("Grid<Real>","copyFrom",Grid<Real>::_W_13);
+ static const Pb::Register _R_63 ("Grid<Real>","getGridType",Grid<Real>::_W_14);
+ static const Pb::Register _R_64 ("Grid<Real>","add",Grid<Real>::_W_15);
+ static const Pb::Register _R_65 ("Grid<Real>","sub",Grid<Real>::_W_16);
+ static const Pb::Register _R_66 ("Grid<Real>","setConst",Grid<Real>::_W_17);
+ static const Pb::Register _R_67 ("Grid<Real>","addConst",Grid<Real>::_W_18);
+ static const Pb::Register _R_68 ("Grid<Real>","addScaled",Grid<Real>::_W_19);
+ static const Pb::Register _R_69 ("Grid<Real>","mult",Grid<Real>::_W_20);
+ static const Pb::Register _R_70 ("Grid<Real>","multConst",Grid<Real>::_W_21);
+ static const Pb::Register _R_71 ("Grid<Real>","clamp",Grid<Real>::_W_22);
+ static const Pb::Register _R_72 ("Grid<Real>","stomp",Grid<Real>::_W_23);
+ static const Pb::Register _R_73 ("Grid<Real>","getMaxAbs",Grid<Real>::_W_24);
+ static const Pb::Register _R_74 ("Grid<Real>","getMax",Grid<Real>::_W_25);
+ static const Pb::Register _R_75 ("Grid<Real>","getMin",Grid<Real>::_W_26);
+ static const Pb::Register _R_76 ("Grid<Real>","getL1",Grid<Real>::_W_27);
+ static const Pb::Register _R_77 ("Grid<Real>","getL2",Grid<Real>::_W_28);
+ static const Pb::Register _R_78 ("Grid<Real>","setBound",Grid<Real>::_W_29);
+ static const Pb::Register _R_79 ("Grid<Real>","setBoundNeumann",Grid<Real>::_W_30);
+ static const Pb::Register _R_80 ("Grid<Real>","getDataPointer",Grid<Real>::_W_31);
+ static const Pb::Register _R_81 ("Grid<Real>","printGrid",Grid<Real>::_W_32);
+ static const Pb::Register _R_82 ("Grid<Vec3>","Grid<Vec3>","GridBase"); template<> const char* Namify<Grid<Vec3> >::S = "Grid<Vec3>";
+ static const Pb::Register _R_83 ("Grid<Vec3>","Grid",Grid<Vec3>::_W_9);
+ static const Pb::Register _R_84 ("Grid<Vec3>","save",Grid<Vec3>::_W_10);
+ static const Pb::Register _R_85 ("Grid<Vec3>","load",Grid<Vec3>::_W_11);
+ static const Pb::Register _R_86 ("Grid<Vec3>","clear",Grid<Vec3>::_W_12);
+ static const Pb::Register _R_87 ("Grid<Vec3>","copyFrom",Grid<Vec3>::_W_13);
+ static const Pb::Register _R_88 ("Grid<Vec3>","getGridType",Grid<Vec3>::_W_14);
+ static const Pb::Register _R_89 ("Grid<Vec3>","add",Grid<Vec3>::_W_15);
+ static const Pb::Register _R_90 ("Grid<Vec3>","sub",Grid<Vec3>::_W_16);
+ static const Pb::Register _R_91 ("Grid<Vec3>","setConst",Grid<Vec3>::_W_17);
+ static const Pb::Register _R_92 ("Grid<Vec3>","addConst",Grid<Vec3>::_W_18);
+ static const Pb::Register _R_93 ("Grid<Vec3>","addScaled",Grid<Vec3>::_W_19);
+ static const Pb::Register _R_94 ("Grid<Vec3>","mult",Grid<Vec3>::_W_20);
+ static const Pb::Register _R_95 ("Grid<Vec3>","multConst",Grid<Vec3>::_W_21);
+ static const Pb::Register _R_96 ("Grid<Vec3>","clamp",Grid<Vec3>::_W_22);
+ static const Pb::Register _R_97 ("Grid<Vec3>","stomp",Grid<Vec3>::_W_23);
+ static const Pb::Register _R_98 ("Grid<Vec3>","getMaxAbs",Grid<Vec3>::_W_24);
+ static const Pb::Register _R_99 ("Grid<Vec3>","getMax",Grid<Vec3>::_W_25);
+ static const Pb::Register _R_100 ("Grid<Vec3>","getMin",Grid<Vec3>::_W_26);
+ static const Pb::Register _R_101 ("Grid<Vec3>","getL1",Grid<Vec3>::_W_27);
+ static const Pb::Register _R_102 ("Grid<Vec3>","getL2",Grid<Vec3>::_W_28);
+ static const Pb::Register _R_103 ("Grid<Vec3>","setBound",Grid<Vec3>::_W_29);
+ static const Pb::Register _R_104 ("Grid<Vec3>","setBoundNeumann",Grid<Vec3>::_W_30);
+ static const Pb::Register _R_105 ("Grid<Vec3>","getDataPointer",Grid<Vec3>::_W_31);
+ static const Pb::Register _R_106 ("Grid<Vec3>","printGrid",Grid<Vec3>::_W_32);
+#endif
+#ifdef _C_GridBase
+ static const Pb::Register _R_107 ("GridBase","GridBase","PbClass"); template<> const char* Namify<GridBase >::S = "GridBase";
+ static const Pb::Register _R_108 ("GridBase","GridBase",GridBase::_W_0);
+ static const Pb::Register _R_109 ("GridBase","getSizeX",GridBase::_W_1);
+ static const Pb::Register _R_110 ("GridBase","getSizeY",GridBase::_W_2);
+ static const Pb::Register _R_111 ("GridBase","getSizeZ",GridBase::_W_3);
+ static const Pb::Register _R_112 ("GridBase","getSize",GridBase::_W_4);
+ static const Pb::Register _R_113 ("GridBase","is3D",GridBase::_W_5);
+ static const Pb::Register _R_114 ("GridBase","is4D",GridBase::_W_6);
+ static const Pb::Register _R_115 ("GridBase","getSizeT",GridBase::_W_7);
+ static const Pb::Register _R_116 ("GridBase","getStrideT",GridBase::_W_8);
+#endif
+#ifdef _C_MACGrid
+ static const Pb::Register _R_117 ("MACGrid","MACGrid","Grid<Vec3>"); template<> const char* Namify<MACGrid >::S = "MACGrid";
+ static const Pb::Register _R_118 ("MACGrid","MACGrid",MACGrid::_W_33);
+ static const Pb::Register _R_119 ("MACGrid","setBoundMAC",MACGrid::_W_34);
+#endif
+static const Pb::Register _R_7 ("GridType_TypeNone",0);
+static const Pb::Register _R_8 ("GridType_TypeReal",1);
+static const Pb::Register _R_9 ("GridType_TypeInt",2);
+static const Pb::Register _R_10 ("GridType_TypeVec3",4);
+static const Pb::Register _R_11 ("GridType_TypeMAC",8);
+static const Pb::Register _R_12 ("GridType_TypeLevelset",16);
+static const Pb::Register _R_13 ("GridType_TypeFlags",32);
+static const Pb::Register _R_14 ("Grid<int>","IntGrid","");
+static const Pb::Register _R_15 ("Grid<Real>","RealGrid","");
+static const Pb::Register _R_16 ("Grid<Vec3>","VecGrid","");
+static const Pb::Register _R_17 ("CellType_TypeNone",0);
+static const Pb::Register _R_18 ("CellType_TypeFluid",1);
+static const Pb::Register _R_19 ("CellType_TypeObstacle",2);
+static const Pb::Register _R_20 ("CellType_TypeEmpty",4);
+static const Pb::Register _R_21 ("CellType_TypeInflow",8);
+static const Pb::Register _R_22 ("CellType_TypeOutflow",16);
+static const Pb::Register _R_23 ("CellType_TypeOpen",32);
+static const Pb::Register _R_24 ("CellType_TypeStick",64);
+static const Pb::Register _R_25 ("CellType_TypeReserved",256);
+extern "C" {
+void PbRegister_file_7()
+{
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+ KEEP_UNUSED(_R_101);
+ KEEP_UNUSED(_R_102);
+ KEEP_UNUSED(_R_103);
+ KEEP_UNUSED(_R_104);
+ KEEP_UNUSED(_R_105);
+ KEEP_UNUSED(_R_106);
+ KEEP_UNUSED(_R_107);
+ KEEP_UNUSED(_R_108);
+ KEEP_UNUSED(_R_109);
+ KEEP_UNUSED(_R_110);
+ KEEP_UNUSED(_R_111);
+ KEEP_UNUSED(_R_112);
+ KEEP_UNUSED(_R_113);
+ KEEP_UNUSED(_R_114);
+ KEEP_UNUSED(_R_115);
+ KEEP_UNUSED(_R_116);
+ KEEP_UNUSED(_R_117);
+ KEEP_UNUSED(_R_118);
+ KEEP_UNUSED(_R_119);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.cpp
new file mode 100644
index 00000000000..14f3e6c713f
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.cpp
@@ -0,0 +1,1023 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#include <limits>
+#include <sstream>
+#include <cstring>
+
+#include "grid4d.h"
+#include "levelset.h"
+#include "kernel.h"
+#include "mantaio.h"
+
+using namespace std;
+namespace Manta {
+
+
+//******************************************************************************
+// GridBase members
+
+Grid4dBase::Grid4dBase (FluidSolver* parent)
+ : PbClass(parent), mType(TypeNone)
+{
+ checkParent();
+}
+
+
+//******************************************************************************
+// Grid4d<T> members
+
+// helpers to set type
+template<class T> inline Grid4dBase::Grid4dType typeList() { return Grid4dBase::TypeNone; }
+template<> inline Grid4dBase::Grid4dType typeList<Real>() { return Grid4dBase::TypeReal; }
+template<> inline Grid4dBase::Grid4dType typeList<int>() { return Grid4dBase::TypeInt; }
+template<> inline Grid4dBase::Grid4dType typeList<Vec3>() { return Grid4dBase::TypeVec3; }
+template<> inline Grid4dBase::Grid4dType typeList<Vec4>() { return Grid4dBase::TypeVec4; }
+
+
+template<class T>
+Grid4d<T>::Grid4d(FluidSolver* parent, bool show)
+ : Grid4dBase(parent)
+{
+ assertMsg( parent->is3D() && parent->supports4D(), "To use 4d grids create a 3d solver with fourthDim>0");
+
+ mType = typeList<T>();
+ Vec3i s = parent->getGridSize();
+ mSize = Vec4i(s.x, s.y, s.z, parent->getFourthDim() );
+ mData = parent->getGrid4dPointer<T>();
+ assertMsg( mData, "Couldnt allocate data pointer!");
+
+ mStrideZ = (mSize.x * mSize.y);
+ mStrideT = (mStrideZ * mSize.z);
+
+ Real sizemax = (Real)mSize[0];
+ for(int c=1; c<3; ++c) if(mSize[c]>sizemax) sizemax = mSize[c];
+ // note - the 4d component is ignored for dx! keep same scaling as for 3d...
+ mDx = 1.0 / sizemax;
+
+ clear();
+ setHidden(!show);
+}
+
+template<class T>
+Grid4d<T>::Grid4d(const Grid4d<T>& a) : Grid4dBase(a.getParent()) {
+ mSize = a.mSize;
+ mType = a.mType;
+ mStrideZ = a.mStrideZ;
+ mStrideT = a.mStrideT;
+ mDx = a.mDx;
+ FluidSolver *gp = a.getParent();
+ mData = gp->getGrid4dPointer<T>();
+ assertMsg( mData, "Couldnt allocate data pointer!");
+
+ memcpy(mData, a.mData, sizeof(T) * a.mSize.x * a.mSize.y * a.mSize.z * a.mSize.t);
+}
+
+template<class T>
+Grid4d<T>::~Grid4d() {
+ mParent->freeGrid4dPointer<T>(mData);
+}
+
+template<class T>
+void Grid4d<T>::clear() {
+ memset(mData, 0, sizeof(T) * mSize.x * mSize.y * mSize.z * mSize.t);
+}
+
+template<class T>
+void Grid4d<T>::swap(Grid4d<T>& other) {
+ if (other.getSizeX() != getSizeX() || other.getSizeY() != getSizeY() || other.getSizeZ() != getSizeZ() || other.getSizeT() != getSizeT())
+ errMsg("Grid4d::swap(): Grid4d dimensions mismatch.");
+
+ T* dswap = other.mData;
+ other.mData = mData;
+ mData = dswap;
+}
+
+template<class T>
+void Grid4d<T>::load(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ readGrid4dUni(name, this);
+ else if (ext == ".raw")
+ readGrid4dRaw(name, this);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+template<class T>
+void Grid4d<T>::save(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ writeGrid4dUni(name, this);
+ else if (ext == ".raw")
+ writeGrid4dRaw(name, this);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+//******************************************************************************
+// Grid4d<T> operators
+
+//! Kernel: Compute min value of Real Grid4d
+
+ struct kn4dMinReal : public KernelBase {
+ kn4dMinReal(Grid4d<Real>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<Real>& val ,Real& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline Grid4d<Real>& getArg0() {
+ return val; }
+ typedef Grid4d<Real> type0; void runMessage() { debMsg("Executing kernel kn4dMinReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real minVal = std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,minVal);
+#pragma omp critical
+{this->minVal = min(minVal, this->minVal); } }
+ }
+ Grid4d<Real>& val; Real minVal; }
+;
+
+//! Kernel: Compute max value of Real Grid4d
+
+ struct kn4dMaxReal : public KernelBase {
+ kn4dMaxReal(Grid4d<Real>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<Real>& val ,Real& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline Grid4d<Real>& getArg0() {
+ return val; }
+ typedef Grid4d<Real> type0; void runMessage() { debMsg("Executing kernel kn4dMaxReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real maxVal = -std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,maxVal);
+#pragma omp critical
+{this->maxVal = max(maxVal, this->maxVal); } }
+ }
+ Grid4d<Real>& val; Real maxVal; }
+;
+
+//! Kernel: Compute min value of int Grid4d
+
+ struct kn4dMinInt : public KernelBase {
+ kn4dMinInt(Grid4d<int>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<int>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<int>& val ,int& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator int () {
+ return minVal; }
+ inline int & getRet() {
+ return minVal; }
+ inline Grid4d<int>& getArg0() {
+ return val; }
+ typedef Grid4d<int> type0; void runMessage() { debMsg("Executing kernel kn4dMinInt ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ int minVal = std::numeric_limits<int>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,minVal);
+#pragma omp critical
+{this->minVal = min(minVal, this->minVal); } }
+ }
+ Grid4d<int>& val; int minVal; }
+;
+
+//! Kernel: Compute max value of int Grid4d
+
+ struct kn4dMaxInt : public KernelBase {
+ kn4dMaxInt(Grid4d<int>& val) : KernelBase(&val,0) ,val(val) ,maxVal(std::numeric_limits<int>::min()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<int>& val ,int& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator int () {
+ return maxVal; }
+ inline int & getRet() {
+ return maxVal; }
+ inline Grid4d<int>& getArg0() {
+ return val; }
+ typedef Grid4d<int> type0; void runMessage() { debMsg("Executing kernel kn4dMaxInt ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ int maxVal = std::numeric_limits<int>::min();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,maxVal);
+#pragma omp critical
+{this->maxVal = max(maxVal, this->maxVal); } }
+ }
+ Grid4d<int>& val; int maxVal; }
+;
+
+//! Kernel: Compute min norm of vec Grid4d
+
+template <class VEC> struct kn4dMinVec : public KernelBase {
+ kn4dMinVec(Grid4d<VEC>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<VEC>& val ,Real& minVal) {
+ const Real s = normSquare(val[idx]);
+ if (s < minVal)
+ minVal = s;
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline Grid4d<VEC>& getArg0() {
+ return val; }
+ typedef Grid4d<VEC> type0; void runMessage() { debMsg("Executing kernel kn4dMinVec ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real minVal = std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,minVal);
+#pragma omp critical
+{this->minVal = min(minVal, this->minVal); } }
+ }
+ Grid4d<VEC>& val; Real minVal; }
+;
+
+//! Kernel: Compute max norm of vec Grid4d
+
+template <class VEC> struct kn4dMaxVec : public KernelBase {
+ kn4dMaxVec(Grid4d<VEC>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<VEC>& val ,Real& maxVal) {
+ const Real s = normSquare(val[idx]);
+ if (s > maxVal)
+ maxVal = s;
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline Grid4d<VEC>& getArg0() {
+ return val; }
+ typedef Grid4d<VEC> type0; void runMessage() { debMsg("Executing kernel kn4dMaxVec ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real maxVal = -std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,maxVal);
+#pragma omp critical
+{this->maxVal = max(maxVal, this->maxVal); } }
+ }
+ Grid4d<VEC>& val; Real maxVal; }
+;
+
+
+template<class T> Grid4d<T>& Grid4d<T>::safeDivide (const Grid4d<T>& a) {
+ Grid4dSafeDiv<T> (*this, a);
+ return *this;
+}
+template<class T> Grid4d<T>& Grid4d<T>::copyFrom (const Grid4d<T>& a, bool copyType ) {
+ assertMsg (a.mSize.x == mSize.x && a.mSize.y == mSize.y && a.mSize.z == mSize.z && a.mSize.t == mSize.t, "different Grid4d resolutions "<<a.mSize<<" vs "<<this->mSize );
+ memcpy(mData, a.mData, sizeof(T) * mSize.x * mSize.y * mSize.z * mSize.t);
+ if(copyType) mType = a.mType; // copy type marker
+ return *this;
+}
+/*template<class T> Grid4d<T>& Grid4d<T>::operator= (const Grid4d<T>& a) {
+ note: do not use , use copyFrom instead
+}*/
+
+template <class T> struct kn4dSetConstReal : public KernelBase {
+ kn4dSetConstReal(Grid4d<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, T val ) { me[idx] = val; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel kn4dSetConstReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,val); }
+ }
+ Grid4d<T>& me; T val; }
+;
+template <class T> struct kn4dAddConstReal : public KernelBase {
+ kn4dAddConstReal(Grid4d<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, T val ) { me[idx] += val; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel kn4dAddConstReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,val); }
+ }
+ Grid4d<T>& me; T val; }
+;
+template <class T> struct kn4dMultConst : public KernelBase {
+ kn4dMultConst(Grid4d<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, T val ) { me[idx] *= val; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel kn4dMultConst ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,val); }
+ }
+ Grid4d<T>& me; T val; }
+;
+template <class T> struct kn4dClamp : public KernelBase {
+ kn4dClamp(Grid4d<T>& me, T min, T max) : KernelBase(&me,0) ,me(me),min(min),max(max) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, T min, T max ) { me[idx] = clamp( me[idx], min, max); } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return min; }
+ typedef T type1;inline T& getArg2() {
+ return max; }
+ typedef T type2; void runMessage() { debMsg("Executing kernel kn4dClamp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,min,max); }
+ }
+ Grid4d<T>& me; T min; T max; }
+;
+
+template<class T> void Grid4d<T>::add(const Grid4d<T>& a) {
+ Grid4dAdd<T,T>(*this, a);
+}
+template<class T> void Grid4d<T>::sub(const Grid4d<T>& a) {
+ Grid4dSub<T,T>(*this, a);
+}
+template<class T> void Grid4d<T>::addScaled(const Grid4d<T>& a, const T& factor) {
+ Grid4dScaledAdd<T,T> (*this, a, factor);
+}
+template<class T> void Grid4d<T>::setConst(T a) {
+ kn4dSetConstReal<T>( *this, T(a) );
+}
+template<class T> void Grid4d<T>::addConst(T a) {
+ kn4dAddConstReal<T>( *this, T(a) );
+}
+template<class T> void Grid4d<T>::multConst(T a) {
+ kn4dMultConst<T>( *this, a );
+}
+
+template<class T> void Grid4d<T>::mult(const Grid4d<T>& a) {
+ Grid4dMult<T,T> (*this, a);
+}
+
+template<class T> void Grid4d<T>::clamp(Real min, Real max) {
+ kn4dClamp<T> (*this, T(min), T(max) );
+}
+
+template<> Real Grid4d<Real>::getMax() {
+ return kn4dMaxReal (*this);
+}
+template<> Real Grid4d<Real>::getMin() {
+ return kn4dMinReal (*this);
+}
+template<> Real Grid4d<Real>::getMaxAbs() {
+ Real amin = kn4dMinReal (*this);
+ Real amax = kn4dMaxReal (*this);
+ return max( fabs(amin), fabs(amax));
+}
+template<> Real Grid4d<Vec4>::getMax() {
+ return sqrt(kn4dMaxVec<Vec4> (*this));
+}
+template<> Real Grid4d<Vec4>::getMin() {
+ return sqrt(kn4dMinVec<Vec4> (*this));
+}
+template<> Real Grid4d<Vec4>::getMaxAbs() {
+ return sqrt(kn4dMaxVec<Vec4> (*this));
+}
+template<> Real Grid4d<int>::getMax() {
+ return (Real) kn4dMaxInt (*this);
+}
+template<> Real Grid4d<int>::getMin() {
+ return (Real) kn4dMinInt (*this);
+}
+template<> Real Grid4d<int>::getMaxAbs() {
+ int amin = kn4dMinInt (*this);
+ int amax = kn4dMaxInt (*this);
+ return max( fabs((Real)amin), fabs((Real)amax));
+}
+template<> Real Grid4d<Vec3>::getMax() {
+ return sqrt(kn4dMaxVec<Vec3> (*this));
+}
+template<> Real Grid4d<Vec3>::getMin() {
+ return sqrt(kn4dMinVec<Vec3> (*this));
+}
+template<> Real Grid4d<Vec3>::getMaxAbs() {
+ return sqrt(kn4dMaxVec<Vec3> (*this));
+}
+
+
+template<class T> void Grid4d<T>::printGrid(int zSlice, int tSlice, bool printIndex, int bnd) {
+ std::ostringstream out;
+ out << std::endl;
+ FOR_IJKT_BND(*this,bnd) {
+ IndexInt idx = (*this).index(i,j,k,t);
+ if ( ( (zSlice>=0 && k==zSlice) || (zSlice<0) ) &&
+ ( (tSlice>=0 && t==tSlice) || (tSlice<0) ) ) {
+ out << " ";
+ if(printIndex) out << " "<<i<<","<<j<<","<<k<<","<<t <<":";
+ out << (*this)[idx];
+ if(i==(*this).getSizeX()-1 -bnd) {
+ out << std::endl;
+ if(j==(*this).getSizeY()-1 -bnd) {
+ out << std::endl;
+ if(k==(*this).getSizeZ()-1 -bnd) { out << std::endl; }
+ } }
+ }
+ }
+ out << endl; debMsg("Printing '" << this->getName() <<"' "<< out.str().c_str()<<" " , 1);
+}
+
+
+// helper to set/get components of vec4 Grids
+ struct knGetComp4d : public KernelBase {
+ knGetComp4d(const Grid4d<Vec4>& src, Grid4d<Real>& dst, int c) : KernelBase(&src,0) ,src(src),dst(dst),c(c) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid4d<Vec4>& src, Grid4d<Real>& dst, int c ) { dst[idx] = src[idx][c]; } inline const Grid4d<Vec4>& getArg0() {
+ return src; }
+ typedef Grid4d<Vec4> type0;inline Grid4d<Real>& getArg1() {
+ return dst; }
+ typedef Grid4d<Real> type1;inline int& getArg2() {
+ return c; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knGetComp4d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,src,dst,c); }
+ }
+ const Grid4d<Vec4>& src; Grid4d<Real>& dst; int c; }
+;;
+ struct knSetComp4d : public KernelBase {
+ knSetComp4d(const Grid4d<Real>& src, Grid4d<Vec4>& dst, int c) : KernelBase(&src,0) ,src(src),dst(dst),c(c) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid4d<Real>& src, Grid4d<Vec4>& dst, int c ) { dst[idx][c] = src[idx]; } inline const Grid4d<Real>& getArg0() {
+ return src; }
+ typedef Grid4d<Real> type0;inline Grid4d<Vec4>& getArg1() {
+ return dst; }
+ typedef Grid4d<Vec4> type1;inline int& getArg2() {
+ return c; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetComp4d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,src,dst,c); }
+ }
+ const Grid4d<Real>& src; Grid4d<Vec4>& dst; int c; }
+;;
+void getComp4d(const Grid4d<Vec4>& src, Grid4d<Real>& dst, int c) { knGetComp4d(src,dst,c); } static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getComp4d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<Vec4>& src = *_args.getPtr<Grid4d<Vec4> >("src",0,&_lock); Grid4d<Real>& dst = *_args.getPtr<Grid4d<Real> >("dst",1,&_lock); int c = _args.get<int >("c",2,&_lock); _retval = getPyNone(); getComp4d(src,dst,c); _args.check(); }
+ pbFinalizePlugin(parent,"getComp4d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getComp4d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getComp4d ("","getComp4d",_W_0);
+extern "C" {
+ void PbRegister_getComp4d() {
+ KEEP_UNUSED(_RP_getComp4d); }
+ }
+
+;
+void setComp4d(const Grid4d<Real>& src, Grid4d<Vec4>& dst, int c) { knSetComp4d(src,dst,c); } static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setComp4d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<Real>& src = *_args.getPtr<Grid4d<Real> >("src",0,&_lock); Grid4d<Vec4>& dst = *_args.getPtr<Grid4d<Vec4> >("dst",1,&_lock); int c = _args.get<int >("c",2,&_lock); _retval = getPyNone(); setComp4d(src,dst,c); _args.check(); }
+ pbFinalizePlugin(parent,"setComp4d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setComp4d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setComp4d ("","setComp4d",_W_1);
+extern "C" {
+ void PbRegister_setComp4d() {
+ KEEP_UNUSED(_RP_setComp4d); }
+ }
+
+;
+
+
+template <class T> struct knSetBnd4d : public KernelBase {
+ knSetBnd4d(Grid4d<T>& grid, T value, int w) : KernelBase(&grid,0) ,grid(grid),value(value),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, int t, Grid4d<T>& grid, T value, int w ) {
+ bool bnd =
+ (i<=w || i>=grid.getSizeX()-1-w ||
+ j<=w || j>=grid.getSizeY()-1-w ||
+ k<=w || k>=grid.getSizeZ()-1-w ||
+ t<=w || t>=grid.getSizeT()-1-w );
+ if (bnd)
+ grid(i,j,k,t) = value;
+} inline Grid4d<T>& getArg0() {
+ return grid; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1;inline int& getArg2() {
+ return w; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetBnd4d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " " t "<< minT<<" - "<< maxT , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxT > 1) {
+ const int _maxZ = maxZ;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int t=0; t < maxT; t++) for (int k=0; k < _maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,grid,value,w); }
+ }
+ else if (maxZ > 1) {
+ const int t=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,grid,value,w); }
+ }
+ else {
+ const int t=0; const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,grid,value,w); }
+ }
+ }
+ Grid4d<T>& grid; T value; int w; }
+;
+
+template<class T> void Grid4d<T>::setBound(T value, int boundaryWidth) {
+ knSetBnd4d<T>( *this, value, boundaryWidth );
+}
+
+template <class T> struct knSetBnd4dNeumann : public KernelBase {
+ knSetBnd4dNeumann(Grid4d<T>& grid, int w) : KernelBase(&grid,0) ,grid(grid),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, int t, Grid4d<T>& grid, int w ) {
+ bool set = false;
+ int si=i, sj=j, sk=k, st=t;
+ if( i<=w) {
+ si = w+1; set=true;
+ }
+ if( i>=grid.getSizeX()-1-w){
+ si = grid.getSizeX()-1-w-1; set=true;
+ }
+ if( j<=w){
+ sj = w+1; set=true;
+ }
+ if( j>=grid.getSizeY()-1-w){
+ sj = grid.getSizeY()-1-w-1; set=true;
+ }
+ if( k<=w ) {
+ sk = w+1; set=true;
+ }
+ if( k>=grid.getSizeZ()-1-w ) {
+ sk = grid.getSizeZ()-1-w-1; set=true;
+ }
+ if( t<=w ) {
+ st = w+1; set=true;
+ }
+ if( t>=grid.getSizeT()-1-w ) {
+ st = grid.getSizeT()-1-w-1; set=true;
+ }
+ if(set)
+ grid(i,j,k,t) = grid(si, sj, sk, st);
+} inline Grid4d<T>& getArg0() {
+ return grid; }
+ typedef Grid4d<T> type0;inline int& getArg1() {
+ return w; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel knSetBnd4dNeumann ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " " t "<< minT<<" - "<< maxT , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxT > 1) {
+ const int _maxZ = maxZ;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int t=0; t < maxT; t++) for (int k=0; k < _maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,grid,w); }
+ }
+ else if (maxZ > 1) {
+ const int t=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,grid,w); }
+ }
+ else {
+ const int t=0; const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,grid,w); }
+ }
+ }
+ Grid4d<T>& grid; int w; }
+;
+
+template<class T> void Grid4d<T>::setBoundNeumann(int boundaryWidth) {
+ knSetBnd4dNeumann<T>( *this, boundaryWidth );
+}
+
+//******************************************************************************
+// testing helpers
+
+//! compute maximal diference of two cells in the grid, needed for testing system
+
+Real grid4dMaxDiff(Grid4d<Real>& g1, Grid4d<Real>& g2 ) {
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1,0) {
+ maxVal = std::max(maxVal, (double)fabs( g1(i,j,k,t)-g2(i,j,k,t) ));
+ }
+ return maxVal;
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "grid4dMaxDiff" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Real>& g1 = *_args.getPtr<Grid4d<Real> >("g1",0,&_lock); Grid4d<Real>& g2 = *_args.getPtr<Grid4d<Real> >("g2",1,&_lock); _retval = toPy(grid4dMaxDiff(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"grid4dMaxDiff", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("grid4dMaxDiff",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_grid4dMaxDiff ("","grid4dMaxDiff",_W_2);
+extern "C" {
+ void PbRegister_grid4dMaxDiff() {
+ KEEP_UNUSED(_RP_grid4dMaxDiff); }
+ }
+
+
+
+Real grid4dMaxDiffInt(Grid4d<int>& g1, Grid4d<int>& g2 ) {
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1,0) {
+ maxVal = std::max(maxVal, (double)fabs( (double)g1(i,j,k,t)-g2(i,j,k,t) ));
+ }
+ return maxVal;
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "grid4dMaxDiffInt" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<int>& g1 = *_args.getPtr<Grid4d<int> >("g1",0,&_lock); Grid4d<int>& g2 = *_args.getPtr<Grid4d<int> >("g2",1,&_lock); _retval = toPy(grid4dMaxDiffInt(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"grid4dMaxDiffInt", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("grid4dMaxDiffInt",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_grid4dMaxDiffInt ("","grid4dMaxDiffInt",_W_3);
+extern "C" {
+ void PbRegister_grid4dMaxDiffInt() {
+ KEEP_UNUSED(_RP_grid4dMaxDiffInt); }
+ }
+
+
+
+Real grid4dMaxDiffVec3(Grid4d<Vec3>& g1, Grid4d<Vec3>& g2 ) {
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1,0) {
+ double d = 0.;
+ for(int c=0; c<3; ++c) {
+ d += fabs( (double)g1(i,j,k,t)[c] - (double)g2(i,j,k,t)[c] );
+ }
+ maxVal = std::max(maxVal, d );
+ }
+ return maxVal;
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "grid4dMaxDiffVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Vec3>& g1 = *_args.getPtr<Grid4d<Vec3> >("g1",0,&_lock); Grid4d<Vec3>& g2 = *_args.getPtr<Grid4d<Vec3> >("g2",1,&_lock); _retval = toPy(grid4dMaxDiffVec3(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"grid4dMaxDiffVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("grid4dMaxDiffVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_grid4dMaxDiffVec3 ("","grid4dMaxDiffVec3",_W_4);
+extern "C" {
+ void PbRegister_grid4dMaxDiffVec3() {
+ KEEP_UNUSED(_RP_grid4dMaxDiffVec3); }
+ }
+
+
+
+Real grid4dMaxDiffVec4(Grid4d<Vec4>& g1, Grid4d<Vec4>& g2 ) {
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1,0) {
+ double d = 0.;
+ for(int c=0; c<4; ++c) {
+ d += fabs( (double)g1(i,j,k,t)[c] - (double)g2(i,j,k,t)[c] );
+ }
+ maxVal = std::max(maxVal, d );
+ }
+ return maxVal;
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "grid4dMaxDiffVec4" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Vec4>& g1 = *_args.getPtr<Grid4d<Vec4> >("g1",0,&_lock); Grid4d<Vec4>& g2 = *_args.getPtr<Grid4d<Vec4> >("g2",1,&_lock); _retval = toPy(grid4dMaxDiffVec4(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"grid4dMaxDiffVec4", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("grid4dMaxDiffVec4",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_grid4dMaxDiffVec4 ("","grid4dMaxDiffVec4",_W_5);
+extern "C" {
+ void PbRegister_grid4dMaxDiffVec4() {
+ KEEP_UNUSED(_RP_grid4dMaxDiffVec4); }
+ }
+
+
+
+// set a region to some value
+
+
+template <class S> struct knSetRegion4d : public KernelBase {
+ knSetRegion4d(Grid4d<S>& dst, Vec4 start, Vec4 end, S value ) : KernelBase(&dst,0) ,dst(dst),start(start),end(end),value(value) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, int t, Grid4d<S>& dst, Vec4 start, Vec4 end, S value ) {
+ Vec4 p(i,j,k,t);
+ for(int c=0; c<4; ++c) if(p[c]<start[c] || p[c]>end[c]) return;
+ dst(i,j,k,t) = value;
+} inline Grid4d<S>& getArg0() {
+ return dst; }
+ typedef Grid4d<S> type0;inline Vec4& getArg1() {
+ return start; }
+ typedef Vec4 type1;inline Vec4& getArg2() {
+ return end; }
+ typedef Vec4 type2;inline S& getArg3() {
+ return value; }
+ typedef S type3; void runMessage() { debMsg("Executing kernel knSetRegion4d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " " t "<< minT<<" - "<< maxT , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxT > 1) {
+ const int _maxZ = maxZ;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int t=0; t < maxT; t++) for (int k=0; k < _maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,dst,start,end,value); }
+ }
+ else if (maxZ > 1) {
+ const int t=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,dst,start,end,value); }
+ }
+ else {
+ const int t=0; const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,dst,start,end,value); }
+ }
+ }
+ Grid4d<S>& dst; Vec4 start; Vec4 end; S value; }
+;
+//! simple init functions in 4d
+void setRegion4d(Grid4d<Real>& dst, Vec4 start, Vec4 end, Real value) { knSetRegion4d<Real>(dst,start,end,value); } static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setRegion4d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Real>& dst = *_args.getPtr<Grid4d<Real> >("dst",0,&_lock); Vec4 start = _args.get<Vec4 >("start",1,&_lock); Vec4 end = _args.get<Vec4 >("end",2,&_lock); Real value = _args.get<Real >("value",3,&_lock); _retval = getPyNone(); setRegion4d(dst,start,end,value); _args.check(); }
+ pbFinalizePlugin(parent,"setRegion4d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setRegion4d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setRegion4d ("","setRegion4d",_W_6);
+extern "C" {
+ void PbRegister_setRegion4d() {
+ KEEP_UNUSED(_RP_setRegion4d); }
+ }
+
+
+//! simple init functions in 4d, vec4
+void setRegion4dVec4(Grid4d<Vec4>& dst, Vec4 start, Vec4 end, Vec4 value) { knSetRegion4d<Vec4>(dst,start,end,value); } static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setRegion4dVec4" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Vec4>& dst = *_args.getPtr<Grid4d<Vec4> >("dst",0,&_lock); Vec4 start = _args.get<Vec4 >("start",1,&_lock); Vec4 end = _args.get<Vec4 >("end",2,&_lock); Vec4 value = _args.get<Vec4 >("value",3,&_lock); _retval = getPyNone(); setRegion4dVec4(dst,start,end,value); _args.check(); }
+ pbFinalizePlugin(parent,"setRegion4dVec4", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setRegion4dVec4",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setRegion4dVec4 ("","setRegion4dVec4",_W_7);
+extern "C" {
+ void PbRegister_setRegion4dVec4() {
+ KEEP_UNUSED(_RP_setRegion4dVec4); }
+ }
+
+
+
+//! slow helper to visualize tests, get a 3d slice of a 4d grid
+void getSliceFrom4d(Grid4d<Real>& src, int srct, Grid<Real>& dst) {
+ const int bnd = 0;
+ if(! src.isInBounds(Vec4i(bnd,bnd,bnd,srct)) ) return;
+
+ for(int k=bnd; k<src.getSizeZ()-bnd; k++)
+ for(int j=bnd; j<src.getSizeY()-bnd; j++)
+ for(int i=bnd; i<src.getSizeX()-bnd; i++)
+ {
+ if(!dst.isInBounds(Vec3i(i,j,k))) continue;
+ dst(i,j,k) = src(i,j,k,srct);
+ }
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getSliceFrom4d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Real>& src = *_args.getPtr<Grid4d<Real> >("src",0,&_lock); int srct = _args.get<int >("srct",1,&_lock); Grid<Real>& dst = *_args.getPtr<Grid<Real> >("dst",2,&_lock); _retval = getPyNone(); getSliceFrom4d(src,srct,dst); _args.check(); }
+ pbFinalizePlugin(parent,"getSliceFrom4d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getSliceFrom4d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getSliceFrom4d ("","getSliceFrom4d",_W_8);
+extern "C" {
+ void PbRegister_getSliceFrom4d() {
+ KEEP_UNUSED(_RP_getSliceFrom4d); }
+ }
+
+
+//! slow helper to visualize tests, get a 3d slice of a 4d vec4 grid
+void getSliceFrom4dVec(Grid4d<Vec4>& src, int srct, Grid<Vec3>& dst, Grid<Real>* dstt=NULL) {
+ const int bnd = 0;
+ if(! src.isInBounds(Vec4i(bnd,bnd,bnd,srct)) ) return;
+
+ for(int k=bnd; k<src.getSizeZ()-bnd; k++)
+ for(int j=bnd; j<src.getSizeY()-bnd; j++)
+ for(int i=bnd; i<src.getSizeX()-bnd; i++)
+ {
+ if(!dst.isInBounds(Vec3i(i,j,k))) continue;
+ for(int c=0; c<3; ++c)
+ dst(i,j,k)[c] = src(i,j,k,srct)[c];
+ if(dstt) (*dstt)(i,j,k) = src(i,j,k,srct)[3];
+ }
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getSliceFrom4dVec" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Vec4>& src = *_args.getPtr<Grid4d<Vec4> >("src",0,&_lock); int srct = _args.get<int >("srct",1,&_lock); Grid<Vec3>& dst = *_args.getPtr<Grid<Vec3> >("dst",2,&_lock); Grid<Real>* dstt = _args.getPtrOpt<Grid<Real> >("dstt",3,NULL,&_lock); _retval = getPyNone(); getSliceFrom4dVec(src,srct,dst,dstt); _args.check(); }
+ pbFinalizePlugin(parent,"getSliceFrom4dVec", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getSliceFrom4dVec",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getSliceFrom4dVec ("","getSliceFrom4dVec",_W_9);
+extern "C" {
+ void PbRegister_getSliceFrom4dVec() {
+ KEEP_UNUSED(_RP_getSliceFrom4dVec); }
+ }
+
+
+
+
+//******************************************************************************
+// interpolation
+
+//! same as in grid.h , but takes an additional optional "desired" size
+static inline void gridFactor4d(Vec4 s1, Vec4 s2, Vec4 optSize, Vec4 scale, Vec4& srcFac, Vec4& retOff ) {
+ for(int c=0; c<4; c++) { if(optSize[c] > 0.){ s2[c] = optSize[c]; } }
+ srcFac = calcGridSizeFactor4d( s1, s2) / scale;
+ retOff = -retOff * srcFac + srcFac*0.5;
+}
+
+//! interpolate 4d grid from one size to another size
+// real valued offsets & scale
+
+
+template <class S> struct knInterpol4d : public KernelBase {
+ knInterpol4d(Grid4d<S>& target, Grid4d<S>& source, const Vec4& srcFac, const Vec4& offset) : KernelBase(&target,0) ,target(target),source(source),srcFac(srcFac),offset(offset) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, int t, Grid4d<S>& target, Grid4d<S>& source, const Vec4& srcFac, const Vec4& offset ) {
+ Vec4 pos = Vec4(i,j,k,t) * srcFac + offset;
+ target(i,j,k,t) = source.getInterpolated(pos);
+} inline Grid4d<S>& getArg0() {
+ return target; }
+ typedef Grid4d<S> type0;inline Grid4d<S>& getArg1() {
+ return source; }
+ typedef Grid4d<S> type1;inline const Vec4& getArg2() {
+ return srcFac; }
+ typedef Vec4 type2;inline const Vec4& getArg3() {
+ return offset; }
+ typedef Vec4 type3; void runMessage() { debMsg("Executing kernel knInterpol4d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " " t "<< minT<<" - "<< maxT , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxT > 1) {
+ const int _maxZ = maxZ;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int t=0; t < maxT; t++) for (int k=0; k < _maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,target,source,srcFac,offset); }
+ }
+ else if (maxZ > 1) {
+ const int t=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,target,source,srcFac,offset); }
+ }
+ else {
+ const int t=0; const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,target,source,srcFac,offset); }
+ }
+ }
+ Grid4d<S>& target; Grid4d<S>& source; const Vec4& srcFac; const Vec4& offset; }
+;
+//! linearly interpolate data of a 4d grid
+
+void interpolateGrid4d( Grid4d<Real>& target, Grid4d<Real>& source , Vec4 offset=Vec4(0.), Vec4 scale=Vec4(1.), Vec4 size=Vec4(-1.) ) {
+ Vec4 srcFac(1.), off2 = offset;
+ gridFactor4d( toVec4(source.getSize()), toVec4(target.getSize()), size,scale, srcFac,off2 );
+ knInterpol4d<Real> (target, source, srcFac, off2 );
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "interpolateGrid4d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Real>& target = *_args.getPtr<Grid4d<Real> >("target",0,&_lock); Grid4d<Real>& source = *_args.getPtr<Grid4d<Real> >("source",1,&_lock); Vec4 offset = _args.getOpt<Vec4 >("offset",2,Vec4(0.),&_lock); Vec4 scale = _args.getOpt<Vec4 >("scale",3,Vec4(1.),&_lock); Vec4 size = _args.getOpt<Vec4 >("size",4,Vec4(-1.) ,&_lock); _retval = getPyNone(); interpolateGrid4d(target,source,offset,scale,size); _args.check(); }
+ pbFinalizePlugin(parent,"interpolateGrid4d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("interpolateGrid4d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_interpolateGrid4d ("","interpolateGrid4d",_W_10);
+extern "C" {
+ void PbRegister_interpolateGrid4d() {
+ KEEP_UNUSED(_RP_interpolateGrid4d); }
+ }
+
+
+//! linearly interpolate vec4 data of a 4d grid
+
+void interpolateGrid4dVec( Grid4d<Vec4>& target, Grid4d<Vec4>& source, Vec4 offset=Vec4(0.), Vec4 scale=Vec4(1.), Vec4 size=Vec4(-1.) ) {
+ Vec4 srcFac(1.), off2 = offset;
+ gridFactor4d( toVec4(source.getSize()), toVec4(target.getSize()), size,scale, srcFac,off2 );
+ knInterpol4d<Vec4> (target, source, srcFac, off2 );
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "interpolateGrid4dVec" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Vec4>& target = *_args.getPtr<Grid4d<Vec4> >("target",0,&_lock); Grid4d<Vec4>& source = *_args.getPtr<Grid4d<Vec4> >("source",1,&_lock); Vec4 offset = _args.getOpt<Vec4 >("offset",2,Vec4(0.),&_lock); Vec4 scale = _args.getOpt<Vec4 >("scale",3,Vec4(1.),&_lock); Vec4 size = _args.getOpt<Vec4 >("size",4,Vec4(-1.) ,&_lock); _retval = getPyNone(); interpolateGrid4dVec(target,source,offset,scale,size); _args.check(); }
+ pbFinalizePlugin(parent,"interpolateGrid4dVec", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("interpolateGrid4dVec",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_interpolateGrid4dVec ("","interpolateGrid4dVec",_W_11);
+extern "C" {
+ void PbRegister_interpolateGrid4dVec() {
+ KEEP_UNUSED(_RP_interpolateGrid4dVec); }
+ }
+
+
+
+
+// explicit instantiation
+template class Grid4d<int>;
+template class Grid4d<Real>;
+template class Grid4d<Vec3>;
+template class Grid4d<Vec4>;
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h
new file mode 100644
index 00000000000..636029aaa2c
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h
@@ -0,0 +1,746 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#ifndef _GRID4D_H
+#define _GRID4D_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "vector4d.h"
+#include "kernel.h"
+
+
+namespace Manta {
+
+
+//! Base class for all grids
+class Grid4dBase : public PbClass {public:
+ enum Grid4dType { TypeNone = 0, TypeReal = 1, TypeInt = 2, TypeVec3 = 4, TypeVec4 = 8 };
+
+ Grid4dBase(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Grid4dBase::Grid4dBase" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new Grid4dBase(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Grid4dBase::Grid4dBase" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::Grid4dBase",e.what()); return -1; }
+ }
+
+
+ //! Get the grids X dimension
+ inline int getSizeX() const { return mSize.x; } static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeX" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeX()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::getSizeX" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::getSizeX",e.what()); return 0; }
+ }
+
+ //! Get the grids Y dimension
+ inline int getSizeY() const { return mSize.y; } static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeY" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeY()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::getSizeY" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::getSizeY",e.what()); return 0; }
+ }
+
+ //! Get the grids Z dimension
+ inline int getSizeZ() const { return mSize.z; } static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeZ" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeZ()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::getSizeZ" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::getSizeZ",e.what()); return 0; }
+ }
+
+ //! Get the grids T dimension
+ inline int getSizeT() const { return mSize.t; } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeT" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeT()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::getSizeT" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::getSizeT",e.what()); return 0; }
+ }
+
+ //! Get the grids dimensions
+ inline Vec4i getSize() const { return mSize; } static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSize" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSize()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::getSize" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::getSize",e.what()); return 0; }
+ }
+
+
+ //! Get Stride in X dimension
+ inline IndexInt getStrideX() const { return 1; }
+ //! Get Stride in Y dimension
+ inline IndexInt getStrideY() const { return mSize.x; }
+ //! Get Stride in Z dimension
+ inline IndexInt getStrideZ() const { return mStrideZ; }
+ //! Get Stride in T dimension
+ inline IndexInt getStrideT() const { return mStrideT; }
+
+ inline Real getDx() { return mDx; }
+
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(int i, int j, int k, int t) const;
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(IndexInt idx) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec4i& p, int bnd) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec4i& p) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec4& p, int bnd = 0) const { return isInBounds(toVec4i(p), bnd); }
+ //! Check if linear index is in the range of the array
+ inline bool isInBounds(IndexInt idx) const;
+
+ //! Get the type of grid
+ inline Grid4dType getType() const { return mType; }
+ //! Check dimensionality
+ inline bool is3D() const { return true; } static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::is3D" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->is3D()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::is3D" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::is3D",e.what()); return 0; }
+ }
+
+ inline bool is4D() const { return true; } static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::is4D" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->is4D()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::is4D" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::is4D",e.what()); return 0; }
+ }
+
+
+ //! 3d compatibility
+ inline bool isInBounds(int i,int j, int k, int t, int bnd) const { return isInBounds( Vec4i(i,j,k,t), bnd ); }
+
+ //! Get index into the data
+ inline IndexInt index(int i, int j, int k, int t) const { DEBUG_ONLY(checkIndex(i,j,k,t)); return (IndexInt)i + (IndexInt)mSize.x * j + (IndexInt)mStrideZ * k + (IndexInt)mStrideT * t; }
+ //! Get index into the data
+ inline IndexInt index(const Vec4i& pos) const { DEBUG_ONLY(checkIndex(pos.x,pos.y,pos.z,pos.t)); return (IndexInt)pos.x + (IndexInt)mSize.x * pos.y + (IndexInt)mStrideZ * pos.z + (IndexInt)mStrideT * pos.t; }
+protected:
+
+ Grid4dType mType;
+ Vec4i mSize;
+ Real mDx;
+ // precomputed Z,T shift: to ensure 2D compatibility, always use this instead of sx*sy !
+ IndexInt mStrideZ; IndexInt mStrideT; public: PbArgs _args; }
+#define _C_Grid4dBase
+;
+
+//! Grid class
+
+template<class T> class Grid4d : public Grid4dBase {public:
+ //! init new grid, values are set to zero
+ Grid4d(FluidSolver* parent, bool show = true); static int _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Grid4d::Grid4d" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); bool show = _args.getOpt<bool >("show",1,true,&_lock); obj = new Grid4d(parent,show); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Grid4d::Grid4d" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::Grid4d",e.what()); return -1; }
+ }
+
+ //! create new & copy content from another grid
+ Grid4d(const Grid4d<T>& a);
+ //! return memory to solver
+ virtual ~Grid4d();
+
+ typedef T BASETYPE;
+ typedef Grid4dBase BASETYPE_GRID;
+
+ void save(std::string name); static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::save",e.what()); return 0; }
+ }
+
+ void load(std::string name); static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::load",e.what()); return 0; }
+ }
+
+
+ //! set all cells to zero
+ void clear(); static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::clear",e.what()); return 0; }
+ }
+
+
+ //! all kinds of access functions, use grid(), grid[] or grid.get()
+ //! access data
+ inline T get(int i,int j, int k, int t) const { return mData[index(i,j,k,t)]; }
+ //! access data
+ inline T& get(int i,int j, int k, int t) { return mData[index(i,j,k,t)]; }
+ //! access data
+ inline T get(IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T get(const Vec4i& pos) const { return mData[index(pos)]; }
+ //! access data
+ inline T& operator()(int i, int j, int k, int t) { return mData[index(i, j, k,t)]; }
+ //! access data
+ inline T operator()(int i, int j, int k, int t) const { return mData[index(i, j, k,t)]; }
+ //! access data
+ inline T& operator()(IndexInt idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T operator()(IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T& operator()(const Vec4i& pos) { return mData[index(pos)]; }
+ //! access data
+ inline T operator()(const Vec4i& pos) const { return mData[index(pos)]; }
+ //! access data
+ inline T& operator[](IndexInt idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline const T operator[](IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+
+ // interpolated access
+ inline T getInterpolated(const Vec4& pos) const { return interpol4d<T>(mData, mSize, mStrideZ, mStrideT, pos); }
+
+ // assignment / copy
+
+ //! warning - do not use "=" for grids in python, this copies the reference! not the grid content...
+ //Grid4d<T>& operator=(const Grid4d<T>& a);
+ //! copy content from other grid (use this one instead of operator= !)
+ Grid4d<T>& copyFrom(const Grid4d<T>& a, bool copyType=true ); static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::copyFrom" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<T>& a = *_args.getPtr<Grid4d<T> >("a",0,&_lock); bool copyType = _args.getOpt<bool >("copyType",1,true ,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->copyFrom(a,copyType)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::copyFrom" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::copyFrom",e.what()); return 0; }
+ }
+ // old: { *this = a; }
+
+ // helper functions to work with grids in scene files
+
+ //! add/subtract other grid
+ void add(const Grid4d<T>& a); static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::add" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<T>& a = *_args.getPtr<Grid4d<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->add(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::add" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::add",e.what()); return 0; }
+ }
+
+ void sub(const Grid4d<T>& a); static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::sub" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<T>& a = *_args.getPtr<Grid4d<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->sub(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::sub" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::sub",e.what()); return 0; }
+ }
+
+ //! set all cells to constant value
+ void setConst(T s); static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::setConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::setConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::setConst",e.what()); return 0; }
+ }
+
+ //! add constant to all grid cells
+ void addConst(T s); static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::addConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::addConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::addConst",e.what()); return 0; }
+ }
+
+ //! add scaled other grid to current one (note, only "Real" factor, "T" type not supported here!)
+ void addScaled(const Grid4d<T>& a, const T& factor); static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::addScaled" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<T>& a = *_args.getPtr<Grid4d<T> >("a",0,&_lock); const T& factor = *_args.getPtr<T >("factor",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addScaled(a,factor); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::addScaled" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::addScaled",e.what()); return 0; }
+ }
+
+ //! multiply contents of grid
+ void mult( const Grid4d<T>& a); static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::mult" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<T>& a = *_args.getPtr<Grid4d<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->mult(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::mult" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::mult",e.what()); return 0; }
+ }
+
+ //! multiply each cell by a constant scalar value
+ void multConst(T s); static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::multConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->multConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::multConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::multConst",e.what()); return 0; }
+ }
+
+ //! clamp content to range (for vec3, clamps each component separately)
+ void clamp(Real min, Real max); static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::clamp" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real min = _args.get<Real >("min",0,&_lock); Real max = _args.get<Real >("max",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clamp(min,max); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::clamp" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::clamp",e.what()); return 0; }
+ }
+
+
+ // common compound operators
+ //! get absolute max value in grid
+ Real getMaxAbs(); static PyObject* _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::getMaxAbs" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxAbs()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::getMaxAbs" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::getMaxAbs",e.what()); return 0; }
+ }
+
+ //! get max value in grid
+ Real getMax(); static PyObject* _W_22 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::getMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMax()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::getMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::getMax",e.what()); return 0; }
+ }
+
+ //! get min value in grid
+ Real getMin(); static PyObject* _W_23 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::getMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMin()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::getMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::getMin",e.what()); return 0; }
+ }
+
+ //! set all boundary cells to constant value (Dirichlet)
+ void setBound(T value, int boundaryWidth=1); static PyObject* _W_24 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::setBound" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T value = _args.get<T >("value",0,&_lock); int boundaryWidth = _args.getOpt<int >("boundaryWidth",1,1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setBound(value,boundaryWidth); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::setBound" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::setBound",e.what()); return 0; }
+ }
+
+ //! set all boundary cells to last inner value (Neumann)
+ void setBoundNeumann(int boundaryWidth=1); static PyObject* _W_25 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::setBoundNeumann" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int boundaryWidth = _args.getOpt<int >("boundaryWidth",0,1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setBoundNeumann(boundaryWidth); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::setBoundNeumann" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::setBoundNeumann",e.what()); return 0; }
+ }
+
+
+ //! debugging helper, print grid from Python
+ void printGrid(int zSlice=-1, int tSlice=-1, bool printIndex=false, int bnd=0); static PyObject* _W_26 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::printGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int zSlice = _args.getOpt<int >("zSlice",0,-1,&_lock); int tSlice = _args.getOpt<int >("tSlice",1,-1,&_lock); bool printIndex = _args.getOpt<bool >("printIndex",2,false,&_lock); int bnd = _args.getOpt<int >("bnd",3,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->printGrid(zSlice,tSlice,printIndex,bnd); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::printGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::printGrid",e.what()); return 0; }
+ }
+
+
+ // c++ only operators
+ template<class S> Grid4d<T>& operator+=(const Grid4d<S>& a);
+ template<class S> Grid4d<T>& operator+=(const S& a);
+ template<class S> Grid4d<T>& operator-=(const Grid4d<S>& a);
+ template<class S> Grid4d<T>& operator-=(const S& a);
+ template<class S> Grid4d<T>& operator*=(const Grid4d<S>& a);
+ template<class S> Grid4d<T>& operator*=(const S& a);
+ template<class S> Grid4d<T>& operator/=(const Grid4d<S>& a);
+ template<class S> Grid4d<T>& operator/=(const S& a);
+ Grid4d<T>& safeDivide(const Grid4d<T>& a);
+
+ //! Swap data with another grid (no actual data is moved)
+ void swap(Grid4d<T>& other);
+
+protected: T* mData; public: PbArgs _args; }
+#define _C_Grid4d
+;
+
+// Python doesn't know about templates: explicit aliases needed
+
+
+
+
+
+
+//! helper to compute grid conversion factor between local coordinates of two grids
+inline Vec4 calcGridSizeFactor4d(Vec4i s1, Vec4i s2) {
+ return Vec4( Real(s1[0])/s2[0], Real(s1[1])/s2[1], Real(s1[2])/s2[2] , Real(s1[3])/s2[3] );
+}
+inline Vec4 calcGridSizeFactor4d(Vec4 s1, Vec4 s2) {
+ return Vec4( s1[0]/s2[0], s1[1]/s2[1], s1[2]/s2[2] , s1[3]/s2[3] );
+}
+
+// prototypes for grid plugins
+void getComponent4d(const Grid4d<Vec4>& src, Grid4d<Real>& dst, int c);
+void setComponent4d(const Grid4d<Real>& src, Grid4d<Vec4>& dst, int c);
+
+
+//******************************************************************************
+// Implementation of inline functions
+
+inline void Grid4dBase::checkIndex(int i, int j, int k, int t) const {
+ if ( i<0 || j<0 || i>=mSize.x || j>=mSize.y || k<0|| k>= mSize.z ||
+ t<0|| t>= mSize.t ) {
+ std::ostringstream s;
+ s << "Grid4d " << mName << " dim " << mSize << " : index " << i << "," << j << "," << k << ","<<t<<" out of bound ";
+ errMsg(s.str());
+ }
+}
+
+inline void Grid4dBase::checkIndex(IndexInt idx) const {
+ if (idx<0 || idx >= mSize.x * mSize.y * mSize.z * mSize.t) {
+ std::ostringstream s;
+ s << "Grid4d " << mName << " dim " << mSize << " : index " << idx << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+bool Grid4dBase::isInBounds(const Vec4i& p) const {
+ return (p.x >= 0 && p.y >= 0 && p.z >= 0 && p.t >= 0 &&
+ p.x < mSize.x && p.y < mSize.y && p.z < mSize.z && p.t < mSize.t);
+}
+
+bool Grid4dBase::isInBounds(const Vec4i& p, int bnd) const {
+ bool ret = (p.x >= bnd && p.y >= bnd && p.x < mSize.x-bnd && p.y < mSize.y-bnd);
+ ret &= (p.z >= bnd && p.z < mSize.z-bnd);
+ ret &= (p.t >= bnd && p.t < mSize.t-bnd);
+ return ret;
+}
+//! Check if linear index is in the range of the array
+bool Grid4dBase::isInBounds(IndexInt idx) const {
+ if (idx<0 || idx >= mSize.x * mSize.y * mSize.z * mSize.t) {
+ return false;
+ }
+ return true;
+}
+
+// note - ugly, mostly copied from normal GRID!
+
+template <class T, class S> struct Grid4dAdd : public KernelBase {
+ Grid4dAdd(Grid4d<T>& me, const Grid4d<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<S>& other ) { me[idx] += other[idx]; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<S>& getArg1() {
+ return other; }
+ typedef Grid4d<S> type1; void runMessage() { debMsg("Executing kernel Grid4dAdd ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid4d<T>& me; const Grid4d<S>& other; }
+;
+template <class T, class S> struct Grid4dSub : public KernelBase {
+ Grid4dSub(Grid4d<T>& me, const Grid4d<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<S>& other ) { me[idx] -= other[idx]; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<S>& getArg1() {
+ return other; }
+ typedef Grid4d<S> type1; void runMessage() { debMsg("Executing kernel Grid4dSub ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid4d<T>& me; const Grid4d<S>& other; }
+;
+template <class T, class S> struct Grid4dMult : public KernelBase {
+ Grid4dMult(Grid4d<T>& me, const Grid4d<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<S>& other ) { me[idx] *= other[idx]; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<S>& getArg1() {
+ return other; }
+ typedef Grid4d<S> type1; void runMessage() { debMsg("Executing kernel Grid4dMult ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid4d<T>& me; const Grid4d<S>& other; }
+;
+template <class T, class S> struct Grid4dDiv : public KernelBase {
+ Grid4dDiv(Grid4d<T>& me, const Grid4d<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<S>& other ) { me[idx] /= other[idx]; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<S>& getArg1() {
+ return other; }
+ typedef Grid4d<S> type1; void runMessage() { debMsg("Executing kernel Grid4dDiv ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid4d<T>& me; const Grid4d<S>& other; }
+;
+template <class T, class S> struct Grid4dAddScalar : public KernelBase {
+ Grid4dAddScalar(Grid4d<T>& me, const S& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const S& other ) { me[idx] += other; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel Grid4dAddScalar ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid4d<T>& me; const S& other; }
+;
+template <class T, class S> struct Grid4dMultScalar : public KernelBase {
+ Grid4dMultScalar(Grid4d<T>& me, const S& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const S& other ) { me[idx] *= other; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel Grid4dMultScalar ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid4d<T>& me; const S& other; }
+;
+template <class T, class S> struct Grid4dScaledAdd : public KernelBase {
+ Grid4dScaledAdd(Grid4d<T>& me, const Grid4d<T>& other, const S& factor) : KernelBase(&me,0) ,me(me),other(other),factor(factor) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<T>& other, const S& factor ) { me[idx] += factor * other[idx]; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<T>& getArg1() {
+ return other; }
+ typedef Grid4d<T> type1;inline const S& getArg2() {
+ return factor; }
+ typedef S type2; void runMessage() { debMsg("Executing kernel Grid4dScaledAdd ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other,factor); }
+ }
+ Grid4d<T>& me; const Grid4d<T>& other; const S& factor; }
+;
+
+template <class T> struct Grid4dSafeDiv : public KernelBase {
+ Grid4dSafeDiv(Grid4d<T>& me, const Grid4d<T>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<T>& other ) { me[idx] = safeDivide(me[idx], other[idx]); } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<T>& getArg1() {
+ return other; }
+ typedef Grid4d<T> type1; void runMessage() { debMsg("Executing kernel Grid4dSafeDiv ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ Grid4d<T>& me; const Grid4d<T>& other; }
+;
+template <class T> struct Grid4dSetConst : public KernelBase {
+ Grid4dSetConst(Grid4d<T>& me, T value) : KernelBase(&me,0) ,me(me),value(value) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, T value ) { me[idx] = value; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel Grid4dSetConst ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,value); }
+ }
+ Grid4d<T>& me; T value; }
+;
+
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator+= (const Grid4d<S>& a) {
+ Grid4dAdd<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator+= (const S& a) {
+ Grid4dAddScalar<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator-= (const Grid4d<S>& a) {
+ Grid4dSub<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator-= (const S& a) {
+ Grid4dAddScalar<T,S> (*this, -a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator*= (const Grid4d<S>& a) {
+ Grid4dMult<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator*= (const S& a) {
+ Grid4dMultScalar<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator/= (const Grid4d<S>& a) {
+ Grid4dDiv<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator/= (const S& a) {
+ S rez((S)1.0 / a);
+ Grid4dMultScalar<T,S> (*this, rez);
+ return *this;
+}
+
+
+//******************************************************************************
+// Other helper functions
+
+inline Vec4 getGradient4d(const Grid4d<Real>& data, int i, int j, int k, int t) {
+ Vec4 v;
+ if (i > data.getSizeX()-2) i= data.getSizeX()-2;
+ if (j > data.getSizeY()-2) j= data.getSizeY()-2;
+ if (k > data.getSizeZ()-2) k= data.getSizeZ()-2;
+ if (t > data.getSizeT()-2) t= data.getSizeT()-2;
+ if (i < 1) i = 1;
+ if (j < 1) j = 1;
+ if (k < 1) k = 1;
+ if (t < 1) t = 1;
+ v = Vec4( data(i+1,j ,k ,t ) - data(i-1,j ,k ,t ) ,
+ data(i ,j+1,k ,t ) - data(i ,j-1,k ,t ) ,
+ data(i ,j ,k+1,t ) - data(i ,j ,k-1,t ) ,
+ data(i ,j ,k ,t+1) - data(i ,j ,k ,t-1) );
+ return v;
+}
+
+
+
+template <class S> struct KnInterpolateGrid4dTempl : public KernelBase {
+ KnInterpolateGrid4dTempl(Grid4d<S>& target, Grid4d<S>& source, const Vec4& sourceFactor , Vec4 offset) : KernelBase(&target,0) ,target(target),source(source),sourceFactor(sourceFactor),offset(offset) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, int t, Grid4d<S>& target, Grid4d<S>& source, const Vec4& sourceFactor , Vec4 offset ) {
+ Vec4 pos = Vec4(i,j,k,t) * sourceFactor + offset;
+ if(!source.is3D()) pos[2] = 0.; // allow 2d -> 3d
+ if(!source.is4D()) pos[3] = 0.; // allow 3d -> 4d
+ target(i,j,k,t) = source.getInterpolated(pos);
+} inline Grid4d<S>& getArg0() {
+ return target; }
+ typedef Grid4d<S> type0;inline Grid4d<S>& getArg1() {
+ return source; }
+ typedef Grid4d<S> type1;inline const Vec4& getArg2() {
+ return sourceFactor; }
+ typedef Vec4 type2;inline Vec4& getArg3() {
+ return offset; }
+ typedef Vec4 type3; void runMessage() { debMsg("Executing kernel KnInterpolateGrid4dTempl ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " " t "<< minT<<" - "<< maxT , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxT > 1) {
+ const int _maxZ = maxZ;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int t=0; t < maxT; t++) for (int k=0; k < _maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,target,source,sourceFactor,offset); }
+ }
+ else if (maxZ > 1) {
+ const int t=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,target,source,sourceFactor,offset); }
+ }
+ else {
+ const int t=0; const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,t,target,source,sourceFactor,offset); }
+ }
+ }
+ Grid4d<S>& target; Grid4d<S>& source; const Vec4& sourceFactor; Vec4 offset; }
+;
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h.reg
new file mode 100644
index 00000000000..874c3d6670d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h.reg
@@ -0,0 +1,39 @@
+#include "grid4d.h"
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","Grid4dBase","PbClass"); template<> const char* Namify<Grid4dBase >::S = "Grid4dBase";
+>Grid4dBase^
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","Grid4dBase",Grid4dBase::_W_0);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","getSizeX",Grid4dBase::_W_1);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","getSizeY",Grid4dBase::_W_2);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","getSizeZ",Grid4dBase::_W_3);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","getSizeT",Grid4dBase::_W_4);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","getSize",Grid4dBase::_W_5);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","is3D",Grid4dBase::_W_6);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","is4D",Grid4dBase::_W_7);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","Grid4d<$CT$>","Grid4dBase"); template<> const char* Namify<Grid4d<$CT$> >::S = "Grid4d<$CT$>";
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","Grid4d",Grid4d<$CT$>::_W_8);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","save",Grid4d<$CT$>::_W_9);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","load",Grid4d<$CT$>::_W_10);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","clear",Grid4d<$CT$>::_W_11);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","copyFrom",Grid4d<$CT$>::_W_12);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","add",Grid4d<$CT$>::_W_13);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","sub",Grid4d<$CT$>::_W_14);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","setConst",Grid4d<$CT$>::_W_15);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","addConst",Grid4d<$CT$>::_W_16);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","addScaled",Grid4d<$CT$>::_W_17);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","mult",Grid4d<$CT$>::_W_18);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","multConst",Grid4d<$CT$>::_W_19);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","clamp",Grid4d<$CT$>::_W_20);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","getMaxAbs",Grid4d<$CT$>::_W_21);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","getMax",Grid4d<$CT$>::_W_22);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","getMin",Grid4d<$CT$>::_W_23);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","setBound",Grid4d<$CT$>::_W_24);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","setBoundNeumann",Grid4d<$CT$>::_W_25);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","printGrid",Grid4d<$CT$>::_W_26);
+>Grid4d^int
+&static const Pb::Register _R_$IDX$ ("Grid4d<int>","Grid4Int","");
+>Grid4d^Real
+&static const Pb::Register _R_$IDX$ ("Grid4d<Real>","Grid4Real","");
+>Grid4d^Vec3
+&static const Pb::Register _R_$IDX$ ("Grid4d<Vec3>","Grid4Vec3","");
+>Grid4d^Vec4
+&static const Pb::Register _R_$IDX$ ("Grid4d<Vec4>","Grid4Vec4","");
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h.reg.cpp
new file mode 100644
index 00000000000..9304610a2d1
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/grid4d.h.reg.cpp
@@ -0,0 +1,204 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "grid4d.h"
+namespace Manta {
+#ifdef _C_Grid4d
+ static const Pb::Register _R_12 ("Grid4d<int>","Grid4d<int>","Grid4dBase"); template<> const char* Namify<Grid4d<int> >::S = "Grid4d<int>";
+ static const Pb::Register _R_13 ("Grid4d<int>","Grid4d",Grid4d<int>::_W_8);
+ static const Pb::Register _R_14 ("Grid4d<int>","save",Grid4d<int>::_W_9);
+ static const Pb::Register _R_15 ("Grid4d<int>","load",Grid4d<int>::_W_10);
+ static const Pb::Register _R_16 ("Grid4d<int>","clear",Grid4d<int>::_W_11);
+ static const Pb::Register _R_17 ("Grid4d<int>","copyFrom",Grid4d<int>::_W_12);
+ static const Pb::Register _R_18 ("Grid4d<int>","add",Grid4d<int>::_W_13);
+ static const Pb::Register _R_19 ("Grid4d<int>","sub",Grid4d<int>::_W_14);
+ static const Pb::Register _R_20 ("Grid4d<int>","setConst",Grid4d<int>::_W_15);
+ static const Pb::Register _R_21 ("Grid4d<int>","addConst",Grid4d<int>::_W_16);
+ static const Pb::Register _R_22 ("Grid4d<int>","addScaled",Grid4d<int>::_W_17);
+ static const Pb::Register _R_23 ("Grid4d<int>","mult",Grid4d<int>::_W_18);
+ static const Pb::Register _R_24 ("Grid4d<int>","multConst",Grid4d<int>::_W_19);
+ static const Pb::Register _R_25 ("Grid4d<int>","clamp",Grid4d<int>::_W_20);
+ static const Pb::Register _R_26 ("Grid4d<int>","getMaxAbs",Grid4d<int>::_W_21);
+ static const Pb::Register _R_27 ("Grid4d<int>","getMax",Grid4d<int>::_W_22);
+ static const Pb::Register _R_28 ("Grid4d<int>","getMin",Grid4d<int>::_W_23);
+ static const Pb::Register _R_29 ("Grid4d<int>","setBound",Grid4d<int>::_W_24);
+ static const Pb::Register _R_30 ("Grid4d<int>","setBoundNeumann",Grid4d<int>::_W_25);
+ static const Pb::Register _R_31 ("Grid4d<int>","printGrid",Grid4d<int>::_W_26);
+ static const Pb::Register _R_32 ("Grid4d<Real>","Grid4d<Real>","Grid4dBase"); template<> const char* Namify<Grid4d<Real> >::S = "Grid4d<Real>";
+ static const Pb::Register _R_33 ("Grid4d<Real>","Grid4d",Grid4d<Real>::_W_8);
+ static const Pb::Register _R_34 ("Grid4d<Real>","save",Grid4d<Real>::_W_9);
+ static const Pb::Register _R_35 ("Grid4d<Real>","load",Grid4d<Real>::_W_10);
+ static const Pb::Register _R_36 ("Grid4d<Real>","clear",Grid4d<Real>::_W_11);
+ static const Pb::Register _R_37 ("Grid4d<Real>","copyFrom",Grid4d<Real>::_W_12);
+ static const Pb::Register _R_38 ("Grid4d<Real>","add",Grid4d<Real>::_W_13);
+ static const Pb::Register _R_39 ("Grid4d<Real>","sub",Grid4d<Real>::_W_14);
+ static const Pb::Register _R_40 ("Grid4d<Real>","setConst",Grid4d<Real>::_W_15);
+ static const Pb::Register _R_41 ("Grid4d<Real>","addConst",Grid4d<Real>::_W_16);
+ static const Pb::Register _R_42 ("Grid4d<Real>","addScaled",Grid4d<Real>::_W_17);
+ static const Pb::Register _R_43 ("Grid4d<Real>","mult",Grid4d<Real>::_W_18);
+ static const Pb::Register _R_44 ("Grid4d<Real>","multConst",Grid4d<Real>::_W_19);
+ static const Pb::Register _R_45 ("Grid4d<Real>","clamp",Grid4d<Real>::_W_20);
+ static const Pb::Register _R_46 ("Grid4d<Real>","getMaxAbs",Grid4d<Real>::_W_21);
+ static const Pb::Register _R_47 ("Grid4d<Real>","getMax",Grid4d<Real>::_W_22);
+ static const Pb::Register _R_48 ("Grid4d<Real>","getMin",Grid4d<Real>::_W_23);
+ static const Pb::Register _R_49 ("Grid4d<Real>","setBound",Grid4d<Real>::_W_24);
+ static const Pb::Register _R_50 ("Grid4d<Real>","setBoundNeumann",Grid4d<Real>::_W_25);
+ static const Pb::Register _R_51 ("Grid4d<Real>","printGrid",Grid4d<Real>::_W_26);
+ static const Pb::Register _R_52 ("Grid4d<Vec3>","Grid4d<Vec3>","Grid4dBase"); template<> const char* Namify<Grid4d<Vec3> >::S = "Grid4d<Vec3>";
+ static const Pb::Register _R_53 ("Grid4d<Vec3>","Grid4d",Grid4d<Vec3>::_W_8);
+ static const Pb::Register _R_54 ("Grid4d<Vec3>","save",Grid4d<Vec3>::_W_9);
+ static const Pb::Register _R_55 ("Grid4d<Vec3>","load",Grid4d<Vec3>::_W_10);
+ static const Pb::Register _R_56 ("Grid4d<Vec3>","clear",Grid4d<Vec3>::_W_11);
+ static const Pb::Register _R_57 ("Grid4d<Vec3>","copyFrom",Grid4d<Vec3>::_W_12);
+ static const Pb::Register _R_58 ("Grid4d<Vec3>","add",Grid4d<Vec3>::_W_13);
+ static const Pb::Register _R_59 ("Grid4d<Vec3>","sub",Grid4d<Vec3>::_W_14);
+ static const Pb::Register _R_60 ("Grid4d<Vec3>","setConst",Grid4d<Vec3>::_W_15);
+ static const Pb::Register _R_61 ("Grid4d<Vec3>","addConst",Grid4d<Vec3>::_W_16);
+ static const Pb::Register _R_62 ("Grid4d<Vec3>","addScaled",Grid4d<Vec3>::_W_17);
+ static const Pb::Register _R_63 ("Grid4d<Vec3>","mult",Grid4d<Vec3>::_W_18);
+ static const Pb::Register _R_64 ("Grid4d<Vec3>","multConst",Grid4d<Vec3>::_W_19);
+ static const Pb::Register _R_65 ("Grid4d<Vec3>","clamp",Grid4d<Vec3>::_W_20);
+ static const Pb::Register _R_66 ("Grid4d<Vec3>","getMaxAbs",Grid4d<Vec3>::_W_21);
+ static const Pb::Register _R_67 ("Grid4d<Vec3>","getMax",Grid4d<Vec3>::_W_22);
+ static const Pb::Register _R_68 ("Grid4d<Vec3>","getMin",Grid4d<Vec3>::_W_23);
+ static const Pb::Register _R_69 ("Grid4d<Vec3>","setBound",Grid4d<Vec3>::_W_24);
+ static const Pb::Register _R_70 ("Grid4d<Vec3>","setBoundNeumann",Grid4d<Vec3>::_W_25);
+ static const Pb::Register _R_71 ("Grid4d<Vec3>","printGrid",Grid4d<Vec3>::_W_26);
+ static const Pb::Register _R_72 ("Grid4d<Vec4>","Grid4d<Vec4>","Grid4dBase"); template<> const char* Namify<Grid4d<Vec4> >::S = "Grid4d<Vec4>";
+ static const Pb::Register _R_73 ("Grid4d<Vec4>","Grid4d",Grid4d<Vec4>::_W_8);
+ static const Pb::Register _R_74 ("Grid4d<Vec4>","save",Grid4d<Vec4>::_W_9);
+ static const Pb::Register _R_75 ("Grid4d<Vec4>","load",Grid4d<Vec4>::_W_10);
+ static const Pb::Register _R_76 ("Grid4d<Vec4>","clear",Grid4d<Vec4>::_W_11);
+ static const Pb::Register _R_77 ("Grid4d<Vec4>","copyFrom",Grid4d<Vec4>::_W_12);
+ static const Pb::Register _R_78 ("Grid4d<Vec4>","add",Grid4d<Vec4>::_W_13);
+ static const Pb::Register _R_79 ("Grid4d<Vec4>","sub",Grid4d<Vec4>::_W_14);
+ static const Pb::Register _R_80 ("Grid4d<Vec4>","setConst",Grid4d<Vec4>::_W_15);
+ static const Pb::Register _R_81 ("Grid4d<Vec4>","addConst",Grid4d<Vec4>::_W_16);
+ static const Pb::Register _R_82 ("Grid4d<Vec4>","addScaled",Grid4d<Vec4>::_W_17);
+ static const Pb::Register _R_83 ("Grid4d<Vec4>","mult",Grid4d<Vec4>::_W_18);
+ static const Pb::Register _R_84 ("Grid4d<Vec4>","multConst",Grid4d<Vec4>::_W_19);
+ static const Pb::Register _R_85 ("Grid4d<Vec4>","clamp",Grid4d<Vec4>::_W_20);
+ static const Pb::Register _R_86 ("Grid4d<Vec4>","getMaxAbs",Grid4d<Vec4>::_W_21);
+ static const Pb::Register _R_87 ("Grid4d<Vec4>","getMax",Grid4d<Vec4>::_W_22);
+ static const Pb::Register _R_88 ("Grid4d<Vec4>","getMin",Grid4d<Vec4>::_W_23);
+ static const Pb::Register _R_89 ("Grid4d<Vec4>","setBound",Grid4d<Vec4>::_W_24);
+ static const Pb::Register _R_90 ("Grid4d<Vec4>","setBoundNeumann",Grid4d<Vec4>::_W_25);
+ static const Pb::Register _R_91 ("Grid4d<Vec4>","printGrid",Grid4d<Vec4>::_W_26);
+#endif
+#ifdef _C_Grid4dBase
+ static const Pb::Register _R_92 ("Grid4dBase","Grid4dBase","PbClass"); template<> const char* Namify<Grid4dBase >::S = "Grid4dBase";
+ static const Pb::Register _R_93 ("Grid4dBase","Grid4dBase",Grid4dBase::_W_0);
+ static const Pb::Register _R_94 ("Grid4dBase","getSizeX",Grid4dBase::_W_1);
+ static const Pb::Register _R_95 ("Grid4dBase","getSizeY",Grid4dBase::_W_2);
+ static const Pb::Register _R_96 ("Grid4dBase","getSizeZ",Grid4dBase::_W_3);
+ static const Pb::Register _R_97 ("Grid4dBase","getSizeT",Grid4dBase::_W_4);
+ static const Pb::Register _R_98 ("Grid4dBase","getSize",Grid4dBase::_W_5);
+ static const Pb::Register _R_99 ("Grid4dBase","is3D",Grid4dBase::_W_6);
+ static const Pb::Register _R_100 ("Grid4dBase","is4D",Grid4dBase::_W_7);
+#endif
+static const Pb::Register _R_8 ("Grid4d<int>","Grid4Int","");
+static const Pb::Register _R_9 ("Grid4d<Real>","Grid4Real","");
+static const Pb::Register _R_10 ("Grid4d<Vec3>","Grid4Vec3","");
+static const Pb::Register _R_11 ("Grid4d<Vec4>","Grid4Vec4","");
+extern "C" {
+void PbRegister_file_8()
+{
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.cpp
new file mode 100644
index 00000000000..1418905083a
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.cpp
@@ -0,0 +1,64 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Function and macros for defining compution kernels over grids
+ *
+ ******************************************************************************/
+
+#include "kernel.h"
+#include "grid.h"
+#include "grid4d.h"
+#include "particle.h"
+
+namespace Manta {
+
+KernelBase::KernelBase(const GridBase* base, int bnd) :
+ maxX (base->getSizeX()-bnd),
+ maxY (base->getSizeY()-bnd),
+ maxZ (base->is3D() ? (base->getSizeZ()-bnd) : 1),
+ minZ (base->is3D() ? bnd : 0), maxT(1), minT(0),
+ X (base->getStrideX()),
+ Y (base->getStrideY()),
+ Z (base->getStrideZ()), dimT (0),
+ size (base->getSizeX() * base->getSizeY() * (IndexInt)base->getSizeZ())
+ {}
+
+KernelBase::KernelBase(IndexInt num) :
+ maxX (0), maxY (0), maxZ (0), minZ (0), maxT(0),
+ X (0), Y (0), Z (0), dimT (0),
+ size(num)
+ {}
+
+KernelBase::KernelBase(const Grid4dBase* base, int bnd) :
+ maxX (base->getSizeX()-bnd),
+ maxY (base->getSizeY()-bnd),
+ maxZ (base->getSizeZ()-bnd), minZ (bnd),
+ maxT (base->getSizeT()-bnd), minT (bnd),
+ X (base->getStrideX()),
+ Y (base->getStrideY()),
+ Z (base->getStrideZ()),
+ dimT (base->getStrideT()),
+ size (base->getSizeX() * base->getSizeY() * base->getSizeZ() * (IndexInt)base->getSizeT())
+ {}
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h
new file mode 100644
index 00000000000..98fb2719288
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h
@@ -0,0 +1,102 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Function and macros for defining compution kernels over grids
+ *
+ ******************************************************************************/
+
+#ifndef _KERNEL_H
+#define _KERNEL_H
+
+#if TBB==1
+# include <tbb/blocked_range3d.h>
+# include <tbb/blocked_range.h>
+# include <tbb/parallel_for.h>
+# include <tbb/parallel_reduce.h>
+#endif
+
+#if OPENMP==1
+# include <omp.h>
+#endif
+
+#include "general.h"
+
+namespace Manta {
+
+// fwd decl
+class GridBase;
+class Grid4dBase;
+class ParticleBase;
+
+
+// simple iteration
+#define FOR_IJK_BND(grid, bnd) \
+ for(int k=((grid).is3D() ? bnd : 0),__kmax=((grid).is3D() ? ((grid).getSizeZ()-bnd) : 1); k<__kmax; k++) \
+ for(int j=bnd; j<(grid).getSizeY()-bnd; j++) \
+ for(int i=bnd; i<(grid).getSizeX()-bnd; i++)
+
+#define FOR_IJK_REVERSE(grid) \
+ for(int k=(grid).getSizeZ()-1; k>=0; k--) \
+ for(int j=(grid).getSizeY()-1; j>=0; j--) \
+ for(int i=(grid).getSizeX()-1; i>=0; i--)
+
+#define FOR_IDX(grid) \
+ for(IndexInt idx=0, total=(grid).getSizeX()*(grid).getSizeY()*(grid).getSizeZ(); idx<total; idx++)
+
+#define FOR_IJK(grid) FOR_IJK_BND(grid, 0)
+
+#define FOR_PARTS(parts) \
+ for(IndexInt idx=0, total=(parts).size(); idx<total; idx++)
+
+// simple loop over 4d grids
+#define FOR_IJKT_BND(grid, bnd) \
+ for(int t=((grid).is4D() ? bnd : 0); t<((grid).is4D() ? ((grid).getSizeT()-bnd) : 1); ++t) \
+ for(int k=((grid).is3D() ? bnd : 0); k<((grid).is3D() ? ((grid).getSizeZ()-bnd) : 1); ++k) \
+ for(int j=bnd; j<(grid).getSizeY()-bnd; ++j) \
+ for(int i=bnd; i<(grid).getSizeX()-bnd; ++i)
+
+//! Basic data structure for kernel data, initialized based on kernel type (e.g. single, idx, etc).
+struct KernelBase {
+ int maxX, maxY, maxZ, minZ, maxT, minT;
+ int X, Y, Z, dimT;
+ IndexInt size;
+
+ KernelBase(IndexInt num);
+ KernelBase(const GridBase* base, int bnd);
+ KernelBase(const Grid4dBase* base, int bnd);
+
+ // specify in your derived classes:
+
+ // kernel operators
+ // ijk mode: void operator() (int i, int j, int k)
+ // idx mode: void operator() (IndexInt idx)
+
+ // reduce mode:
+ // void join(classname& other)
+ // void setup()
+};
+
+} // namespace
+
+// all kernels will automatically be added to the "Kernels" group in doxygen
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h.reg
new file mode 100644
index 00000000000..6457157c184
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h.reg
@@ -0,0 +1 @@
+#include "kernel.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h.reg.cpp
new file mode 100644
index 00000000000..195a25409a2
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/kernel.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "kernel.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_15()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.cpp
new file mode 100644
index 00000000000..062535572f9
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.cpp
@@ -0,0 +1,541 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Levelset
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "fastmarch.h"
+#include "kernel.h"
+#include "mcubes.h"
+#include "mesh.h"
+#include <stack>
+
+using namespace std;
+namespace Manta {
+
+//************************************************************************
+// Helper functions and kernels for marching
+
+static const int FlagInited = FastMarch<FmHeapEntryOut, +1>::FlagInited;
+
+// neighbor lookup vectors
+static const Vec3i neighbors[6] = { Vec3i(-1,0,0), Vec3i(1,0,0), Vec3i(0,-1,0), Vec3i(0,1,0), Vec3i(0,0,-1), Vec3i(0,0,1) };
+
+
+ struct InitFmIn : public KernelBase {
+ InitFmIn(const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& phi, bool ignoreWalls, int obstacleType) : KernelBase(&flags,1) ,flags(flags),fmFlags(fmFlags),phi(phi),ignoreWalls(ignoreWalls),obstacleType(obstacleType) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& phi, bool ignoreWalls, int obstacleType ) {
+ const IndexInt idx = flags.index(i,j,k);
+ const Real v = phi[idx];
+ if (ignoreWalls) {
+ if (v>=0. && ((flags[idx] & obstacleType) == 0) )
+ fmFlags[idx] = FlagInited;
+ else
+ fmFlags[idx] = 0;
+ } else {
+ if (v>=0) fmFlags[idx] = FlagInited;
+ else fmFlags[idx] = 0;
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<int>& getArg1() {
+ return fmFlags; }
+ typedef Grid<int> type1;inline Grid<Real>& getArg2() {
+ return phi; }
+ typedef Grid<Real> type2;inline bool& getArg3() {
+ return ignoreWalls; }
+ typedef bool type3;inline int& getArg4() {
+ return obstacleType; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel InitFmIn ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,fmFlags,phi,ignoreWalls,obstacleType); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,fmFlags,phi,ignoreWalls,obstacleType); }
+ }
+ }
+ const FlagGrid& flags; Grid<int>& fmFlags; Grid<Real>& phi; bool ignoreWalls; int obstacleType; }
+;
+
+
+ struct InitFmOut : public KernelBase {
+ InitFmOut(const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& phi, bool ignoreWalls, int obstacleType) : KernelBase(&flags,1) ,flags(flags),fmFlags(fmFlags),phi(phi),ignoreWalls(ignoreWalls),obstacleType(obstacleType) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& phi, bool ignoreWalls, int obstacleType ) {
+ const IndexInt idx = flags.index(i,j,k);
+ const Real v = phi[idx];
+ if (ignoreWalls) {
+ fmFlags[idx] = (v<0) ? FlagInited : 0;
+ if ((flags[idx] & obstacleType) != 0) {
+ fmFlags[idx] = 0;
+ phi[idx] = 0;
+ }
+ } else {
+ fmFlags[idx] = (v<0) ? FlagInited : 0;
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<int>& getArg1() {
+ return fmFlags; }
+ typedef Grid<int> type1;inline Grid<Real>& getArg2() {
+ return phi; }
+ typedef Grid<Real> type2;inline bool& getArg3() {
+ return ignoreWalls; }
+ typedef bool type3;inline int& getArg4() {
+ return obstacleType; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel InitFmOut ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,fmFlags,phi,ignoreWalls,obstacleType); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,fmFlags,phi,ignoreWalls,obstacleType); }
+ }
+ }
+ const FlagGrid& flags; Grid<int>& fmFlags; Grid<Real>& phi; bool ignoreWalls; int obstacleType; }
+;
+
+
+ struct SetUninitialized : public KernelBase {
+ SetUninitialized(const Grid<int>& flags, Grid<int>& fmFlags, Grid<Real>& phi, const Real val, int ignoreWalls, int obstacleType) : KernelBase(&flags,1) ,flags(flags),fmFlags(fmFlags),phi(phi),val(val),ignoreWalls(ignoreWalls),obstacleType(obstacleType) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<int>& flags, Grid<int>& fmFlags, Grid<Real>& phi, const Real val, int ignoreWalls, int obstacleType ) {
+ if(ignoreWalls) {
+ if ( (fmFlags(i,j,k) != FlagInited) && ((flags(i,j,k) & obstacleType) == 0) ) {
+ phi(i,j,k) = val; }
+ } else {
+ if ( (fmFlags(i,j,k) != FlagInited) ) phi(i,j,k) = val;
+ }
+} inline const Grid<int>& getArg0() {
+ return flags; }
+ typedef Grid<int> type0;inline Grid<int>& getArg1() {
+ return fmFlags; }
+ typedef Grid<int> type1;inline Grid<Real>& getArg2() {
+ return phi; }
+ typedef Grid<Real> type2;inline const Real& getArg3() {
+ return val; }
+ typedef Real type3;inline int& getArg4() {
+ return ignoreWalls; }
+ typedef int type4;inline int& getArg5() {
+ return obstacleType; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel SetUninitialized ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,fmFlags,phi,val,ignoreWalls,obstacleType); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,fmFlags,phi,val,ignoreWalls,obstacleType); }
+ }
+ }
+ const Grid<int>& flags; Grid<int>& fmFlags; Grid<Real>& phi; const Real val; int ignoreWalls; int obstacleType; }
+;
+
+template<bool inward>
+inline bool isAtInterface(const Grid<int>& fmFlags, Grid<Real>& phi, const Vec3i& p) {
+ // check for interface
+ int max = phi.is3D() ? 6 : 4;
+ for (int nb=0; nb<max; nb++) {
+ const Vec3i pn(p + neighbors[nb]);
+ if (!fmFlags.isInBounds(pn)) continue;
+
+ if (fmFlags(pn) != FlagInited) continue;
+ if (( inward && phi(pn) >= 0.) ||
+ (!inward && phi(pn) < 0.)) return true;
+ }
+ return false;
+}
+
+
+//************************************************************************
+// Levelset class def
+
+LevelsetGrid::LevelsetGrid(FluidSolver* parent, bool show)
+ : Grid<Real>(parent, show)
+{
+ mType = (GridType)(TypeLevelset | TypeReal);
+}
+
+LevelsetGrid::LevelsetGrid(FluidSolver* parent, Real* data, bool show)
+ : Grid<Real>(parent, data, show)
+{
+ mType = (GridType)(TypeLevelset | TypeReal);
+}
+
+Real LevelsetGrid::invalidTimeValue() {
+ return FastMarch<FmHeapEntryOut, 1>::InvalidTime();
+}
+
+//! Kernel: perform levelset union
+ struct KnJoin : public KernelBase {
+ KnJoin(Grid<Real>& a, const Grid<Real>& b) : KernelBase(&a,0) ,a(a),b(b) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& a, const Grid<Real>& b ) {
+ a[idx] = min(a[idx], b[idx]);
+} inline Grid<Real>& getArg0() {
+ return a; }
+ typedef Grid<Real> type0;inline const Grid<Real>& getArg1() {
+ return b; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel KnJoin ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,a,b); }
+ }
+ Grid<Real>& a; const Grid<Real>& b; }
+;
+void LevelsetGrid::join(const LevelsetGrid& o) { KnJoin(*this, o); }
+
+//! subtract b, note does not preserve SDF!
+ struct KnSubtract : public KernelBase {
+ KnSubtract(Grid<Real>& a, const Grid<Real>& b) : KernelBase(&a,0) ,a(a),b(b) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& a, const Grid<Real>& b ) {
+ if(b[idx]<0.) a[idx] = b[idx] * -1.;
+} inline Grid<Real>& getArg0() {
+ return a; }
+ typedef Grid<Real> type0;inline const Grid<Real>& getArg1() {
+ return b; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel KnSubtract ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,a,b); }
+ }
+ Grid<Real>& a; const Grid<Real>& b; }
+;
+void LevelsetGrid::subtract(const LevelsetGrid& o) { KnSubtract(*this, o); }
+
+//! re-init levelset and extrapolate velocities (in & out)
+// note - uses flags to identify border (could also be done based on ls values)
+static void doReinitMarch( Grid<Real>& phi,
+ const FlagGrid& flags, Real maxTime, MACGrid* velTransport,
+ bool ignoreWalls, bool correctOuterLayer, int obstacleType )
+{
+ const int dim = (phi.is3D() ? 3 : 2);
+ Grid<int> fmFlags( phi.getParent() );
+
+ FastMarch<FmHeapEntryIn, -1> marchIn (flags, fmFlags, phi, maxTime, NULL );
+
+ // march inside
+ InitFmIn (flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FOR_IJK_BND(flags, 1) {
+ if (fmFlags(i,j,k) == FlagInited) continue;
+ if (ignoreWalls && ((flags(i,j,k) & obstacleType) != 0)) continue;
+ const Vec3i p(i,j,k);
+
+ if(isAtInterface<true>(fmFlags, phi, p)) {
+ // set value
+ fmFlags(p) = FlagInited;
+
+ // add neighbors that are not at the interface
+ for (int nb=0; nb<2*dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+ if (ignoreWalls && ((flags.get(pn) & obstacleType) != 0)) continue;
+
+ // check neighbors of neighbor
+ if (phi(pn) < 0. && !isAtInterface<true>(fmFlags, phi, pn)) {
+ marchIn.addToList(pn, p);
+ }
+ }
+ }
+ }
+ marchIn.performMarching();
+ // done with inwards marching
+
+ // now march out...
+
+ // set un initialized regions
+ SetUninitialized (flags, fmFlags, phi, -maxTime - 1., ignoreWalls, obstacleType);
+
+ InitFmOut (flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FastMarch<FmHeapEntryOut, +1> marchOut(flags, fmFlags, phi, maxTime, velTransport );
+
+ // by default, correctOuterLayer is on
+ if (correctOuterLayer) {
+ // normal version, inwards march is done, now add all outside values (0..2] to list
+ // note, this might move the interface a bit! but keeps a nice signed distance field...
+ FOR_IJK_BND(flags, 1) {
+ if (ignoreWalls && ((flags(i,j,k) & obstacleType) != 0)) continue;
+ const Vec3i p(i,j,k);
+
+ // check nbs
+ for (int nb=0; nb<2*dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+
+ if (fmFlags(pn) != FlagInited) continue;
+ if (ignoreWalls && ((flags.get(pn) & obstacleType)) != 0) continue;
+
+ const Real nbPhi = phi(pn);
+
+ // only add nodes near interface, not e.g. outer boundary vs. invalid region
+ if (nbPhi < 0 && nbPhi >= -2)
+ marchOut.addToList(p, pn);
+ }
+ }
+ } else {
+ // alternative version, keep interface, do not distort outer cells
+ // add all ouside values, but not those at the IF layer
+ FOR_IJK_BND(flags, 1) {
+ if (ignoreWalls && ((flags(i,j,k) & obstacleType) != 0)) continue;
+
+ // only look at ouside values
+ const Vec3i p(i,j,k);
+ if (phi(p) < 0) continue;
+
+ if (isAtInterface<false>(fmFlags, phi, p)) {
+ // now add all non, interface neighbors
+ fmFlags(p) = FlagInited;
+
+ // add neighbors that are not at the interface
+ for (int nb=0; nb<2*dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+ if (ignoreWalls && ((flags.get(pn) & obstacleType) != 0)) continue;
+
+ // check neighbors of neighbor
+ if (phi(pn) > 0. && !isAtInterface<false>(fmFlags, phi, pn)) {
+ marchOut.addToList(pn, p);
+ }
+ }
+ }
+ }
+ }
+ marchOut.performMarching();
+
+ // set un initialized regions
+ SetUninitialized (flags, fmFlags, phi, +maxTime + 1., ignoreWalls, obstacleType);
+}
+
+//! call for levelset grids & external real grids
+
+void LevelsetGrid::reinitMarching( const FlagGrid& flags, Real maxTime, MACGrid* velTransport,
+ bool ignoreWalls, bool correctOuterLayer, int obstacleType )
+{
+ doReinitMarch( *this, flags, maxTime, velTransport, ignoreWalls, correctOuterLayer, obstacleType );
+}
+
+
+void LevelsetGrid::initFromFlags(const FlagGrid& flags, bool ignoreWalls) {
+ FOR_IDX(*this) {
+ if (flags.isFluid(idx) || (ignoreWalls && flags.isObstacle(idx)))
+ mData[idx] = -0.5;
+ else
+ mData[idx] = 0.5;
+ }
+}
+
+void LevelsetGrid::fillHoles(int maxsize) {
+ Real cur, i1, i2, j1, j2, k1, k2;
+ Vec3i c, cTmp;
+ std::stack<Vec3i> undo;
+ std::stack<Vec3i> todo;
+
+ FOR_IJK_BND(*this, 1) {
+
+ cur = mData[index(i,j,k)];
+ i1 = mData[index(i-1,j,k)];
+ i2 = mData[index(i+1,j,k)];
+ j1 = mData[index(i,j-1,k)];
+ j2 = mData[index(i,j+1,k)];
+ k1 = mData[index(i,j,k-1)];
+ k2 = mData[index(i,j,k+1)];
+
+ /* Skip cells inside and cells outside with no inside neighbours early */
+ if (cur < 0.) continue;
+ if (cur > 0. && i1 > 0. && i2 > 0. && j1 > 0. && j2 > 0. && k1 > 0. && k2 > 0.) continue;
+
+ /* Current cell is outside and has inside neighbour(s) */
+ undo.push(Vec3i(i,j,k));
+ todo.push(Vec3i(i,j,k));
+
+ /* Cell at c is positive (outside) and has at least one negative (inside) neighbour cell */
+ c = Vec3i(i,j,k);
+
+ /* Enforce negative cell - if search depth gets exceeded this will be reverted to +0.5 */
+ mData[index(c.x, c.y, c.z)] = -0.5;
+
+ while(!todo.empty()) {
+
+ todo.pop();
+
+ /* Add neighbouring positive (inside) cells to stacks */
+ if (c.x > 0 && mData[index(c.x-1, c.y, c.z)] > 0.) { cTmp = Vec3i(c.x-1, c.y, c.z); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5;}
+ if (c.y > 0 && mData[index(c.x, c.y-1, c.z)] > 0.) { cTmp = Vec3i(c.x, c.y-1, c.z); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5; }
+ if (c.z > 0 && mData[index(c.x, c.y, c.z-1)] > 0.) { cTmp = Vec3i(c.x, c.y, c.z-1); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5; }
+ if (c.x < (*this).getSizeX()-1 && mData[index(c.x+1, c.y, c.z)] > 0.) { cTmp = Vec3i(c.x+1, c.y, c.z); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5; }
+ if (c.y < (*this).getSizeY()-1 && mData[index(c.x, c.y+1, c.z)] > 0.) { cTmp = Vec3i(c.x, c.y+1, c.z); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5; }
+ if (c.z < (*this).getSizeZ()-1 && mData[index(c.x, c.y, c.z+1)] > 0.) { cTmp = Vec3i(c.x, c.y, c.z+1); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5; }
+
+ /* Restore original value in cells if undo needed ie once cell undo count exceeds given limit */
+ if (undo.size() > maxsize) {
+ /* Clear todo stack */
+ while (!todo.empty()) {
+ todo.pop();
+ }
+ /* Clear undo stack and revert value */
+ while (!undo.empty()) {
+ c = undo.top();
+ undo.pop();
+ mData[index(c.x, c.y, c.z)] = 0.5;
+ }
+ break;
+ }
+
+ /* Ensure that undo stack is cleared at the end if no more items in todo stack left */
+ if (todo.empty()) {
+ while (!undo.empty()) {
+ undo.pop();
+ }
+ }
+ /* Pop value for next while iteration */
+ else {
+ c = todo.top();
+ }
+ }
+ }
+}
+
+//! run marching cubes to create a mesh for the 0-levelset
+void LevelsetGrid::createMesh(Mesh& mesh) {
+ assertMsg(is3D(), "Only 3D grids supported so far");
+
+ mesh.clear();
+
+ const Real invalidTime = invalidTimeValue();
+ const Real isoValue = 1e-4;
+
+ // create some temp grids
+ Grid<int> edgeVX(mParent);
+ Grid<int> edgeVY(mParent);
+ Grid<int> edgeVZ(mParent);
+
+ for(int i=0; i<mSize.x-1; i++)
+ for(int j=0; j<mSize.y-1; j++)
+ for(int k=0; k<mSize.z-1; k++) {
+ Real value[8] = { get(i,j,k), get(i+1,j,k), get(i+1,j+1,k), get(i,j+1,k),
+ get(i,j,k+1), get(i+1,j,k+1), get(i+1,j+1,k+1), get(i,j+1,k+1) };
+
+ // build lookup index, check for invalid times
+ bool skip = false;
+ int cubeIdx = 0;
+ for (int l=0;l<8;l++) {
+ value[l] *= -1;
+ if (-value[l] <= invalidTime)
+ skip = true;
+ if (value[l] < isoValue)
+ cubeIdx |= 1<<l;
+ }
+ if (skip || (mcEdgeTable[cubeIdx] == 0)) continue;
+
+ // where to look up if this point already exists
+ int triIndices[12];
+ int *eVert[12] = { &edgeVX(i,j,k), &edgeVY(i+1,j,k), &edgeVX(i,j+1,k), &edgeVY(i,j,k),
+ &edgeVX(i,j,k+1), &edgeVY(i+1,j,k+1), &edgeVX(i,j+1,k+1), &edgeVY(i,j,k+1),
+ &edgeVZ(i,j,k), &edgeVZ(i+1,j,k), &edgeVZ(i+1,j+1,k), &edgeVZ(i,j+1,k) };
+
+ const Vec3 pos[9] = { Vec3(i,j,k), Vec3(i+1,j,k), Vec3(i+1,j+1,k), Vec3(i,j+1,k),
+ Vec3(i,j,k+1), Vec3(i+1,j,k+1), Vec3(i+1,j+1,k+1), Vec3(i,j+1,k+1) };
+
+ for (int e=0; e<12; e++) {
+ if (mcEdgeTable[cubeIdx] & (1<<e)) {
+ // vertex already calculated ?
+ if (*eVert[e] == 0) {
+ // interpolate edge
+ const int e1 = mcEdges[e*2 ];
+ const int e2 = mcEdges[e*2+1];
+ const Vec3 p1 = pos[ e1 ]; // scalar field pos 1
+ const Vec3 p2 = pos[ e2 ]; // scalar field pos 2
+ const float valp1 = value[ e1 ]; // scalar field val 1
+ const float valp2 = value[ e2 ]; // scalar field val 2
+ const float mu = (isoValue - valp1) / (valp2 - valp1);
+
+ // init isolevel vertex
+ Node vertex;
+ vertex.pos = p1 + (p2-p1)*mu + Vec3(Real(0.5));
+ vertex.normal = getNormalized(
+ getGradient( *this, i+cubieOffsetX[e1], j+cubieOffsetY[e1], k+cubieOffsetZ[e1]) * (1.0-mu) +
+ getGradient( *this, i+cubieOffsetX[e2], j+cubieOffsetY[e2], k+cubieOffsetZ[e2]) * ( mu)) ;
+
+ triIndices[e] = mesh.addNode(vertex) + 1;
+
+ // store vertex
+ *eVert[e] = triIndices[e];
+ } else {
+ // retrieve from vert array
+ triIndices[e] = *eVert[e];
+ }
+ }
+ }
+
+ // Create the triangles...
+ for(int e=0; mcTriTable[cubeIdx][e]!=-1; e+=3) {
+ mesh.addTri( Triangle( triIndices[ mcTriTable[cubeIdx][e+0]] - 1,
+ triIndices[ mcTriTable[cubeIdx][e+1]] - 1,
+ triIndices[ mcTriTable[cubeIdx][e+2]] - 1));
+ }
+ }
+
+ //mesh.rebuildCorners();
+ //mesh.rebuildLookup();
+
+ // Update mdata fields
+ mesh.updateDataFields();
+}
+
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h
new file mode 100644
index 00000000000..8f168c36a79
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h
@@ -0,0 +1,118 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Levelset
+ *
+ ******************************************************************************/
+
+#ifndef _LEVELSET_H_
+#define _LEVELSET_H_
+
+#include "grid.h"
+
+namespace Manta {
+class Mesh;
+
+//! Special function for levelsets
+class LevelsetGrid : public Grid<Real> {public:
+ LevelsetGrid(FluidSolver* parent, bool show = true); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "LevelsetGrid::LevelsetGrid" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); bool show = _args.getOpt<bool >("show",1,true,&_lock); obj = new LevelsetGrid(parent,show); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"LevelsetGrid::LevelsetGrid" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::LevelsetGrid",e.what()); return -1; }
+ }
+
+
+ LevelsetGrid(FluidSolver* parent, Real* data, bool show = true);
+
+ //! reconstruct the levelset using fast marching
+
+
+void reinitMarching(const FlagGrid& flags, Real maxTime=4.0, MACGrid* velTransport=NULL, bool ignoreWalls=false, bool correctOuterLayer=true, int obstacleType = FlagGrid::TypeObstacle ); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::reinitMarching" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Real maxTime = _args.getOpt<Real >("maxTime",1,4.0,&_lock); MACGrid* velTransport = _args.getPtrOpt<MACGrid >("velTransport",2,NULL,&_lock); bool ignoreWalls = _args.getOpt<bool >("ignoreWalls",3,false,&_lock); bool correctOuterLayer = _args.getOpt<bool >("correctOuterLayer",4,true,&_lock); int obstacleType = _args.getOpt<int >("obstacleType",5,FlagGrid::TypeObstacle ,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->reinitMarching(flags,maxTime,velTransport,ignoreWalls,correctOuterLayer,obstacleType); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::reinitMarching" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::reinitMarching",e.what()); return 0; }
+ }
+
+
+ //! create a triangle mesh from the levelset isosurface
+ void createMesh(Mesh& mesh); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::createMesh" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->createMesh(mesh); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::createMesh" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::createMesh",e.what()); return 0; }
+ }
+
+
+ //! union with another levelset
+ void join(const LevelsetGrid& o); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::join" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const LevelsetGrid& o = *_args.getPtr<LevelsetGrid >("o",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->join(o); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::join" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::join",e.what()); return 0; }
+ }
+
+ void subtract(const LevelsetGrid& o); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::subtract" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const LevelsetGrid& o = *_args.getPtr<LevelsetGrid >("o",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->subtract(o); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::subtract" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::subtract",e.what()); return 0; }
+ }
+
+
+ //! initialize levelset from flags (+/- 0.5 heaviside)
+ void initFromFlags(const FlagGrid& flags, bool ignoreWalls=false); static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::initFromFlags" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); bool ignoreWalls = _args.getOpt<bool >("ignoreWalls",1,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->initFromFlags(flags,ignoreWalls); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::initFromFlags" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::initFromFlags",e.what()); return 0; }
+ }
+
+ //! fill holes (pos cells enclosed by neg ones) up to given size with -0.5 (ie not preserving sdf)
+ void fillHoles(int maxsize=10); static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::fillHoles" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int maxsize = _args.getOpt<int >("maxsize",0,10,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->fillHoles(maxsize); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::fillHoles" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::fillHoles",e.what()); return 0; }
+ }
+
+ static Real invalidTimeValue(); public: PbArgs _args; }
+#define _C_LevelsetGrid
+;
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h.reg
new file mode 100644
index 00000000000..8a0c337db06
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h.reg
@@ -0,0 +1,11 @@
+#include "levelset.h"
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","LevelsetGrid","Grid<$BT$>"); template<> const char* Namify<LevelsetGrid >::S = "LevelsetGrid";
+>LevelsetGrid^
+@LevelsetGrid^^Grid^Real
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","LevelsetGrid",LevelsetGrid::_W_0);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","reinitMarching",LevelsetGrid::_W_1);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","createMesh",LevelsetGrid::_W_2);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","join",LevelsetGrid::_W_3);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","subtract",LevelsetGrid::_W_4);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","initFromFlags",LevelsetGrid::_W_5);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","fillHoles",LevelsetGrid::_W_6);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h.reg.cpp
new file mode 100644
index 00000000000..15642f878e6
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/levelset.h.reg.cpp
@@ -0,0 +1,36 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "levelset.h"
+namespace Manta {
+#ifdef _C_LevelsetGrid
+ static const Pb::Register _R_11 ("LevelsetGrid","LevelsetGrid","Grid<Real>"); template<> const char* Namify<LevelsetGrid >::S = "LevelsetGrid";
+ static const Pb::Register _R_12 ("LevelsetGrid","LevelsetGrid",LevelsetGrid::_W_0);
+ static const Pb::Register _R_13 ("LevelsetGrid","reinitMarching",LevelsetGrid::_W_1);
+ static const Pb::Register _R_14 ("LevelsetGrid","createMesh",LevelsetGrid::_W_2);
+ static const Pb::Register _R_15 ("LevelsetGrid","join",LevelsetGrid::_W_3);
+ static const Pb::Register _R_16 ("LevelsetGrid","subtract",LevelsetGrid::_W_4);
+ static const Pb::Register _R_17 ("LevelsetGrid","initFromFlags",LevelsetGrid::_W_5);
+ static const Pb::Register _R_18 ("LevelsetGrid","fillHoles",LevelsetGrid::_W_6);
+#endif
+extern "C" {
+void PbRegister_file_11()
+{
+ KEEP_UNUSED(_R_11);
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.cpp
new file mode 100644
index 00000000000..54e925ff907
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.cpp
@@ -0,0 +1,1875 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Meshes
+ *
+ * note: this is only a temporary solution, details are bound to change
+ * long term goal is integration with Split&Merge code by Wojtan et al.
+ *
+ ******************************************************************************/
+
+#include "mesh.h"
+#include "integrator.h"
+#include "mantaio.h"
+#include "kernel.h"
+#include "shapes.h"
+#include "noisefield.h"
+//#include "grid.h"
+#include <stack>
+#include <cstring>
+
+using namespace std;
+namespace Manta {
+
+Mesh::Mesh(FluidSolver* parent) : PbClass(parent) {
+}
+
+Mesh::~Mesh()
+{
+ for(IndexInt i=0; i<(IndexInt)mMeshData.size(); ++i)
+ mMeshData[i]->setMesh(NULL);
+
+ if(mFreeMdata) {
+ for(IndexInt i=0; i<(IndexInt)mMeshData.size(); ++i)
+ delete mMeshData[i];
+ }
+}
+
+Mesh* Mesh::clone() {
+ Mesh* nm = new Mesh(mParent);
+ *nm = *this;
+ nm->setName(getName());
+ return nm;
+}
+
+void Mesh::deregister(MeshDataBase* mdata) {
+ bool done = false;
+ // remove pointer from mesh data list
+ for(IndexInt i=0; i<(IndexInt)mMeshData.size(); ++i) {
+ if(mMeshData[i] == mdata) {
+ if(i<(IndexInt)mMeshData.size()-1)
+ mMeshData[i] = mMeshData[mMeshData.size()-1];
+ mMeshData.pop_back();
+ done = true;
+ }
+ }
+ if(!done)
+ errMsg("Invalid pointer given, not registered!");
+}
+
+// create and attach a new mdata field to this mesh
+PbClass* Mesh::create(PbType t, PbTypeVec T, const string& name) {
+# if NOPYTHON!=1
+ _args.add("nocheck",true);
+ if (t.str() == "")
+ errMsg("Specify mesh data type to create");
+ //debMsg( "Mdata creating '"<< t.str <<" with size "<< this->getSizeSlow(), 5 );
+
+ PbClass* pyObj = PbClass::createPyObject(t.str() + T.str(), name, _args, this->getParent() );
+
+ MeshDataBase* mdata = dynamic_cast<MeshDataBase*>(pyObj);
+ if(!mdata) {
+ errMsg("Unable to get mesh data pointer from newly created object. Only create MeshData type with a Mesh.creat() call, eg, MdataReal, MdataVec3 etc.");
+ delete pyObj;
+ return NULL;
+ } else {
+ this->registerMdata(mdata);
+ }
+
+ // directly init size of new mdata field:
+ mdata->resize( this->getSizeSlow() );
+# else
+ PbClass* pyObj = NULL;
+# endif
+ return pyObj;
+}
+
+void Mesh::registerMdata(MeshDataBase* mdata) {
+ mdata->setMesh(this);
+ mMeshData.push_back(mdata);
+
+ if( mdata->getType() == MeshDataBase::TypeReal ) {
+ MeshDataImpl<Real>* pd = dynamic_cast< MeshDataImpl<Real>* >(mdata);
+ if(!pd) errMsg("Invalid mdata object posing as real!");
+ this->registerMdataReal(pd);
+ }
+ else if( mdata->getType() == MeshDataBase::TypeInt ) {
+ MeshDataImpl<int>* pd = dynamic_cast< MeshDataImpl<int>* >(mdata);
+ if(!pd) errMsg("Invalid mdata object posing as int!");
+ this->registerMdataInt(pd);
+ }
+ else if( mdata->getType() == MeshDataBase::TypeVec3 ) {
+ MeshDataImpl<Vec3>* pd = dynamic_cast< MeshDataImpl<Vec3>* >(mdata);
+ if(!pd) errMsg("Invalid mdata object posing as vec3!");
+ this->registerMdataVec3(pd);
+ }
+}
+void Mesh::registerMdataReal(MeshDataImpl<Real>* pd) { mMdataReal.push_back(pd); }
+void Mesh::registerMdataVec3(MeshDataImpl<Vec3>* pd) { mMdataVec3.push_back(pd); }
+void Mesh::registerMdataInt (MeshDataImpl<int >* pd) { mMdataInt .push_back(pd); }
+
+void Mesh::addAllMdata() {
+ for(IndexInt i=0; i<(IndexInt)mMeshData.size(); ++i) {
+ mMeshData[i]->addEntry();
+ }
+}
+
+Real Mesh::computeCenterOfMass(Vec3& cm) const {
+
+ // use double precision for summation, otherwise too much error accumulation
+ double vol=0;
+ Vector3D<double> cmd(0.0);
+ for(size_t tri=0; tri < mTris.size(); tri++) {
+ Vector3D<double> p1(toVec3d(getNode(tri,0)));
+ Vector3D<double> p2(toVec3d(getNode(tri,1)));
+ Vector3D<double> p3(toVec3d(getNode(tri,2)));
+
+ double cvol = dot(cross(p1,p2),p3) / 6.0;
+ cmd += (p1+p2+p3) * (cvol/4.0);
+ vol += cvol;
+ }
+ if (vol != 0.0) cmd /= vol;
+
+ cm = toVec3(cmd);
+ return (Real) vol;
+}
+
+void Mesh::clear() {
+ mNodes.clear();
+ mTris.clear();
+ mCorners.clear();
+ m1RingLookup.clear();
+ for(size_t i=0; i<mNodeChannels.size(); i++)
+ mNodeChannels[i]->resize(0);
+ for(size_t i=0; i<mTriChannels.size(); i++)
+ mTriChannels[i]->resize(0);
+
+ // clear mdata fields as well
+ for (size_t i=0; i<mMdataReal.size(); i++)
+ mMdataReal[i]->resize(0);
+ for (size_t i=0; i<mMdataVec3.size(); i++)
+ mMdataVec3[i]->resize(0);
+ for (size_t i=0; i<mMdataInt.size(); i++)
+ mMdataInt[i]->resize(0);
+}
+
+Mesh& Mesh::operator=(const Mesh& o) {
+ // wipe current data
+ clear();
+ if (mNodeChannels.size() != o.mNodeChannels.size() ||
+ mTriChannels.size() != o.mTriChannels.size())
+ errMsg("can't copy mesh, channels not identical");
+ mNodeChannels.clear();
+ mTriChannels.clear();
+
+ // copy corner, nodes, tris
+ mCorners = o.mCorners;
+ mNodes = o.mNodes;
+ mTris = o.mTris;
+ m1RingLookup = o.m1RingLookup;
+
+ // copy channels
+ for(size_t i=0; i<mNodeChannels.size(); i++)
+ mNodeChannels[i] = o.mNodeChannels[i];
+ for(size_t i=0; i<o.mTriChannels.size(); i++)
+ mTriChannels[i] = o.mTriChannels[i];
+
+ return *this;
+}
+
+void Mesh::load(string name, bool append) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".gz") // assume bobj gz
+ readBobjFile(name, this, append);
+ else if (ext == ".obj")
+ readObjFile(name, this, append);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+
+
+ // dont always rebuild...
+ //rebuildCorners();
+ //rebuildLookup();
+}
+
+void Mesh::save(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".obj")
+ writeObjFile(name, this);
+ else if (ext == ".gz")
+ writeBobjFile(name, this);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+void Mesh::fromShape(Shape& shape, bool append) {
+ if (!append)
+ clear();
+ shape.generateMesh(this);
+}
+
+void Mesh::resizeTris(int numTris) {
+ mTris .resize(numTris );
+ rebuildChannels();
+}
+void Mesh::resizeNodes(int numNodes) {
+ mNodes.resize(numNodes);
+ rebuildChannels();
+}
+
+//! do a quick check whether a rebuild is necessary, and if yes do rebuild
+void Mesh::rebuildQuickCheck() {
+ if(mCorners.size() != 3*mTris.size())
+ rebuildCorners();
+ if(m1RingLookup.size() != mNodes.size())
+ rebuildLookup();
+}
+
+void Mesh::rebuildCorners(int from, int to) {
+ mCorners.resize(3*mTris.size());
+ if (to < 0) to = mTris.size();
+
+ // fill in basic info
+ for (int tri=from; tri<to; tri++) {
+ for (int c=0; c<3; c++) {
+ const int idx = tri*3+c;
+ mCorners[idx].tri = tri;
+ mCorners[idx].node = mTris[tri].c[c];
+ mCorners[idx].next = 3*tri+((c+1)%3);
+ mCorners[idx].prev = 3*tri+((c+2)%3);
+ mCorners[idx].opposite = -1;
+ }
+ }
+
+ // set opposite info
+ int maxc = to*3;
+ for (int c=from*3; c<maxc; c++) {
+ int next = mCorners[mCorners[c].next].node;
+ int prev = mCorners[mCorners[c].prev].node;
+
+ // find corner with same next/prev nodes
+ for (int c2=c+1; c2<maxc; c2++) {
+ int next2 = mCorners[mCorners[c2].next].node;
+ if (next2 != next && next2 != prev) continue;
+ int prev2 = mCorners[mCorners[c2].prev].node;
+ if (prev2 != next && prev2 != prev) continue;
+
+ // found
+ mCorners[c].opposite = c2;
+ mCorners[c2].opposite = c;
+ break;
+ }
+ if (mCorners[c].opposite < 0) {
+ // didn't find opposite
+ errMsg("can't rebuild corners, index without an opposite");
+ }
+ }
+
+ rebuildChannels();
+}
+
+void Mesh::rebuildLookup(int from, int to) {
+ if (from==0 && to<0) m1RingLookup.clear();
+ m1RingLookup.resize(mNodes.size());
+ if (to<0) to = mTris.size();
+ from *=3; to *= 3;
+ for (int i=from; i< to; i++) {
+ const int node = mCorners[i].node;
+ m1RingLookup[node].nodes.insert(mCorners[mCorners[i].next].node);
+ m1RingLookup[node].nodes.insert(mCorners[mCorners[i].prev].node);
+ m1RingLookup[node].tris.insert(mCorners[i].tri);
+ }
+}
+
+void Mesh::rebuildChannels() {
+ for(size_t i=0; i<mTriChannels.size(); i++)
+ mTriChannels[i]->resize(mTris.size());
+ for(size_t i=0; i<mNodeChannels.size(); i++)
+ mNodeChannels[i]->resize(mNodes.size());
+}
+
+
+ struct KnAdvectMeshInGrid : public KernelBase {
+ KnAdvectMeshInGrid(vector<Node>& nodes, const FlagGrid& flags, const MACGrid& vel, const Real dt) : KernelBase(nodes.size()) ,nodes(nodes),flags(flags),vel(vel),dt(dt) ,u((size)) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, vector<Node>& nodes, const FlagGrid& flags, const MACGrid& vel, const Real dt ,vector<Vec3> & u) {
+ if (nodes[idx].flags & Mesh::NfFixed)
+ u[idx] = 0.0;
+ else if (!flags.isInBounds(nodes[idx].pos,1))
+ u[idx] = 0.0;
+ else
+ u[idx] = vel.getInterpolated(nodes[idx].pos) * dt;
+} inline operator vector<Vec3> () {
+ return u; }
+ inline vector<Vec3> & getRet() {
+ return u; }
+ inline vector<Node>& getArg0() {
+ return nodes; }
+ typedef vector<Node> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline const Real& getArg3() {
+ return dt; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel KnAdvectMeshInGrid ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,nodes,flags,vel,dt,u); }
+ }
+ vector<Node>& nodes; const FlagGrid& flags; const MACGrid& vel; const Real dt; vector<Vec3> u; }
+;
+
+// advection plugin
+void Mesh::advectInGrid(FlagGrid& flags, MACGrid& vel, int integrationMode) {
+ KnAdvectMeshInGrid kernel(mNodes, flags, vel, getParent()->getDt());
+ integratePointSet( kernel, integrationMode);
+}
+
+void Mesh::scale(Vec3 s) {
+ for (size_t i=0; i<mNodes.size(); i++)
+ mNodes[i].pos *= s;
+}
+
+void Mesh::offset(Vec3 o) {
+ for (size_t i=0; i<mNodes.size(); i++)
+ mNodes[i].pos += o;
+}
+
+void Mesh::rotate(Vec3 thetas) {
+ // rotation thetas are in radians (e.g. pi is equal to 180 degrees)
+ auto rotate = [&](Real theta, unsigned int first_axis, unsigned int second_axis)
+ {
+ if (theta == 0.0f)
+ return;
+
+ Real sin_t = sin(theta);
+ Real cos_t = cos(theta);
+
+ Real sin_sign = first_axis == 0u && second_axis == 2u ? -1.0f : 1.0f;
+ sin_t *= sin_sign;
+
+ size_t length = mNodes.size();
+ for (size_t n = 0; n < length; ++n)
+ {
+ Vec3& node = mNodes[n].pos;
+ Real first_axis_val = node[first_axis];
+ Real second_axis_val = node[second_axis];
+ node[first_axis] = first_axis_val * cos_t - second_axis_val * sin_t;
+ node[second_axis] = second_axis_val * cos_t + first_axis_val * sin_t;
+ }
+ };
+
+ // rotate x
+ rotate(thetas[0], 1u, 2u);
+ // rotate y
+ rotate(thetas[1], 0u, 2u);
+ // rotate z
+ rotate(thetas[2], 0u, 1u);
+}
+
+void Mesh::computeVelocity(Mesh& oldMesh, MACGrid& vel) {
+ // Early return if sizes do not match
+ if(oldMesh.mNodes.size() != mNodes.size())
+ return;
+
+ // temp grid
+ Grid<Vec3> veloMeanCounter(getParent());
+ veloMeanCounter.setConst(0.0f);
+
+ bool bIs2D = getParent()->is2D();
+
+ // calculate velocities from previous to current frame (per vertex)
+ for (size_t i=0; i<mNodes.size(); ++i)
+ {
+ Vec3 velo = mNodes[i].pos - oldMesh.mNodes[i].pos;
+ if(bIs2D && (mNodes[i].pos.z > -0.5f && mNodes[i].pos.z < 0.5f))
+ {
+ vel.setInterpolated(mNodes[i].pos, velo, &(veloMeanCounter[0]));
+ }
+ }
+
+ // discretize the vertex velocities by averaging them on the grid
+ vel.safeDivide(veloMeanCounter);
+}
+
+void Mesh::removeTri(int tri) {
+ // delete triangles by overwriting them with elements from the end of the array.
+ if(tri!=(int)mTris.size()-1) {
+ // if this is the last element, and it is marked for deletion,
+ // don't waste cycles transfering data to itself,
+ // and DEFINITELY don't transfer .opposite data to other, untainted triangles.
+
+ // old corners hold indices on the end of the corners array
+ // new corners holds indices in the new spot in the middle of the array
+ Corner* oldcorners[3];
+ Corner* newcorners[3];
+ int oldtri = mTris.size()-1;
+ for (int c=0; c<3; c++) {
+ oldcorners[c] = &corners(oldtri,c);
+ newcorners[c] = &corners(tri, c);
+ }
+
+ // move the position of the triangle
+ mTris[tri] = mTris[oldtri];
+
+ // 1) update c.node, c.opposite (c.next and c.prev should be fine as they are)
+ for (int c=0; c<3; c++) {
+ newcorners[c]->node = mTris[tri].c[c];
+ newcorners[c]->opposite = oldcorners[c]->opposite;
+ }
+
+ // 2) c.opposite.opposite = c
+ for (int c=0; c<3; c++) {
+ if (newcorners[c]->opposite>=0)
+ mCorners[newcorners[c]->opposite].opposite = 3*tri+c;
+ }
+
+ // update tri lookup
+ for (int c=0; c<3; c++) {
+ int node = mTris[tri].c[c];
+ m1RingLookup[node].tris.erase(oldtri);
+ m1RingLookup[node].tris.insert(tri);
+ }
+ }
+
+ // transfer tri props
+ for(size_t p=0; p < mTriChannels.size(); p++)
+ mTriChannels[p]->remove(tri);
+
+ // pop the triangle and corners out of the vector
+ mTris.pop_back();
+ mCorners.resize(mTris.size()*3);
+}
+
+void Mesh::removeNodes(const vector<int>& deletedNodes) {
+ // After we delete the nodes that are marked for removal,
+ // the size of mNodes will be the current size - the size of the deleted array.
+ // We are going to move the elements at the end of the array
+ // (everything with an index >= newsize)
+ // to the deleted spots.
+ // We have to map all references to the last few nodes to their new locations.
+ int newsize = (int)(mNodes.size() - deletedNodes.size());
+
+ vector<int> new_index (deletedNodes.size());
+ int di,ni;
+ for(ni=0; ni<(int)new_index.size(); ni++)
+ new_index[ni] = 0;
+ for(di=0; di<(int)deletedNodes.size(); di++) {
+ if(deletedNodes[di] >= newsize)
+ new_index[deletedNodes[di]-newsize] = -1; // tag this node as invalid
+ }
+ for(di=0,ni=0; ni<(int)new_index.size(); ni++,di++) {
+ // we need to find a valid node to move
+ // we marked invalid nodes in the earlier loop with a (-1),
+ // so pick anything but those
+ while(ni<(int)new_index.size() && new_index[ni]==-1)
+ ni++;
+
+ if(ni>=(int)new_index.size())
+ break;
+
+ // next we need to find a valid spot to move the node to.
+ // we iterate through deleted[] until we find a valid spot
+ while(di<(int)new_index.size() && deletedNodes[di]>=newsize)
+ di++;
+
+ // now we assign the valid node to the valid spot
+ new_index[ni] = deletedNodes[di];
+ }
+
+ // Now we have a map of valid indices.
+ // we move node[newsize+i] to location new_index[i].
+ // We ignore the nodes with a -1 index, because they should not be moved.
+ for(int i=0; i<(int)new_index.size(); i++) {
+ if(new_index[i]!=-1)
+ mNodes[ new_index[i] ] = mNodes[ newsize+i ];
+ }
+ mNodes.resize(newsize);
+
+ // handle vertex properties
+ for (size_t i=0; i<mNodeChannels.size(); i++)
+ mNodeChannels[i]->renumber(new_index, newsize);
+
+ // finally, we reconnect everything that used to point to this vertex.
+ for(size_t tri=0, n=0; tri<mTris.size(); tri++) {
+ for (int c=0; c<3; c++,n++) {
+ if (mCorners[n].node >= newsize) {
+ int newindex = new_index[mCorners[n].node - newsize];
+ mCorners[n].node = newindex;
+ mTris[mCorners[n].tri].c[c] = newindex;
+ }
+ }
+ }
+
+ // renumber 1-ring
+ for(int i=0; i<(int)new_index.size(); i++) {
+ if(new_index[i]!=-1) {
+ m1RingLookup[new_index[i]].nodes.swap(m1RingLookup[newsize+i].nodes);
+ m1RingLookup[new_index[i]].tris.swap(m1RingLookup[newsize+i].tris);
+ }
+ }
+ m1RingLookup.resize(newsize);
+ vector<int> reStack(new_index.size());
+ for(int i=0; i<newsize; i++) {
+ set<int>& cs = m1RingLookup[i].nodes;
+ int reNum = 0;
+ // find all nodes > newsize
+ set<int>::reverse_iterator itend = cs.rend();
+ for (set<int>::reverse_iterator it = cs.rbegin(); it != itend; ++it) {
+ if (*it < newsize) break;
+ reStack[reNum++] = *it;
+ }
+ // kill them and insert shifted values
+ if (reNum > 0) {
+ cs.erase(cs.find(reStack[reNum-1]), cs.end());
+ for (int j=0; j<reNum; j++) {
+ cs.insert(new_index[reStack[j]-newsize]);
+#ifdef DEBUG
+ if (new_index[reStack[j]-newsize] == -1)
+ errMsg("invalid node present in 1-ring set");
+#endif
+ }
+ }
+ }
+}
+
+void Mesh::mergeNode(int node, int delnode) {
+ set<int>& ring = m1RingLookup[delnode].nodes;
+ for(set<int>::iterator it = ring.begin(); it != ring.end(); ++it) {
+ m1RingLookup[*it].nodes.erase(delnode);
+ if (*it != node) {
+ m1RingLookup[*it].nodes.insert(node);
+ m1RingLookup[node].nodes.insert(*it);
+ }
+ }
+ set<int>& ringt = m1RingLookup[delnode].tris;
+ for(set<int>::iterator it = ringt.begin(); it != ringt.end(); ++it) {
+ const int t = *it;
+ for (int c=0; c<3; c++) {
+ if (mCorners[3*t+c].node == delnode) {
+ mCorners[3*t+c].node = node;
+ mTris[t].c[c] = node;
+ }
+ }
+ m1RingLookup[node].tris.insert(t);
+ }
+ for(size_t i=0; i<mNodeChannels.size(); i++) {
+ // weight is fixed to 1/2 for now
+ mNodeChannels[i]->mergeWith(node, delnode, 0.5);
+ }
+}
+
+void Mesh::removeTriFromLookup(int tri) {
+ for(int c=0; c<3; c++) {
+ int node = mTris[tri].c[c];
+ m1RingLookup[node].tris.erase(tri);
+ }
+}
+
+void Mesh::addCorner(Corner a) {
+ mCorners.push_back(a);
+}
+
+int Mesh::addTri(Triangle a) {
+ mTris.push_back(a);
+ for (int c=0;c<3;c++) {
+ int node = a.c[c];
+ int nextnode = a.c[(c+1)%3];
+ if ((int)m1RingLookup.size() <= node) m1RingLookup.resize(node+1);
+ if ((int)m1RingLookup.size() <= nextnode) m1RingLookup.resize(nextnode+1);
+ m1RingLookup[node].nodes.insert(nextnode);
+ m1RingLookup[nextnode].nodes.insert(node);
+ m1RingLookup[node].tris.insert(mTris.size()-1);
+ }
+ return mTris.size()-1;
+}
+
+int Mesh::addNode(Node a) {
+ mNodes.push_back(a);
+ if (m1RingLookup.size() < mNodes.size())
+ m1RingLookup.resize(mNodes.size());
+
+ // if mdata exists, add zero init for every node
+ addAllMdata();
+
+ return mNodes.size()-1;
+}
+
+void Mesh::computeVertexNormals() {
+ for (size_t i=0; i<mNodes.size(); i++) {
+ mNodes[i].normal = 0.0;
+ }
+ for (size_t t=0; t<mTris.size(); t++) {
+ Vec3 p0 = getNode(t,0), p1 = getNode(t,1), p2 = getNode(t,2);
+ Vec3 n0 = p0-p1, n1 = p1-p2, n2 = p2-p0;
+ Real l0 = normSquare(n0), l1 = normSquare(n1), l2 = normSquare(n2);
+
+ Vec3 nm = cross(n0,n1);
+
+ mNodes[mTris[t].c[0]].normal += nm * (1.0 / (l0*l2));
+ mNodes[mTris[t].c[1]].normal += nm * (1.0 / (l0*l1));
+ mNodes[mTris[t].c[2]].normal += nm * (1.0 / (l1*l2));
+ }
+ for (size_t i=0; i<mNodes.size(); i++) {
+ normalize(mNodes[i].normal);
+ }
+}
+
+void Mesh::fastNodeLookupRebuild(int corner) {
+ int node = mCorners[corner].node;
+ m1RingLookup[node].nodes.clear();
+ m1RingLookup[node].tris.clear();
+ int start = mCorners[corner].prev;
+ int current = start;
+ do {
+ m1RingLookup[node].nodes.insert(mCorners[current].node);
+ m1RingLookup[node].tris.insert(mCorners[current].tri);
+ current = mCorners[mCorners[current].opposite].next;
+ if (current < 0)
+ errMsg("Can't use fastNodeLookupRebuild on incomplete surfaces");
+ } while (current != start);
+}
+
+void Mesh::sanityCheck(bool strict, vector<int>* deletedNodes, map<int,bool>* taintedTris) {
+ const int nodes = numNodes(), tris = numTris(), corners = 3*tris;
+ for(size_t i=0; i<mNodeChannels.size(); i++) {
+ if (mNodeChannels[i]->size() != nodes)
+ errMsg("Node channel size mismatch");
+ }
+ for(size_t i=0; i<mTriChannels.size(); i++) {
+ if (mTriChannels[i]->size() != tris)
+ errMsg("Tri channel size mismatch");
+ }
+ if ((int)m1RingLookup.size() != nodes)
+ errMsg("1Ring size wrong");
+ for(size_t t=0; t<mTris.size(); t++) {
+ if (taintedTris && taintedTris->find(t) != taintedTris->end()) continue;
+ for (int c=0; c<3; c++) {
+ int corner = t*3+c;
+ int node = mTris[t].c[c];
+ int next = mTris[t].c[(c+1)%3];
+ int prev = mTris[t].c[(c+2)%3];
+ int rnext = mCorners[corner].next;
+ int rprev = mCorners[corner].prev;
+ int ro = mCorners[corner].opposite;
+ if (node < 0 || node >= nodes || next < 0 || next >= nodes || prev < 0 || prev >= nodes)
+ errMsg("invalid node entry");
+ if (mCorners[corner].node != node || mCorners[corner].tri != (int)t)
+ errMsg("invalid basic corner entry");
+ if (rnext < 0 || rnext >= corners || rprev < 0 || rprev >= corners || ro >= corners)
+ errMsg("invalid corner links");
+ if (mCorners[rnext].node != next || mCorners[rprev].node != prev)
+ errMsg("invalid corner next/prev");
+ if (strict && ro < 0)
+ errMsg("opposite missing");
+ if (mCorners[ro].opposite != corner)
+ errMsg("invalid opposite ref");
+ set<int>& rnodes = m1RingLookup[node].nodes;
+ set<int>& rtris = m1RingLookup[node].tris;
+ if (rnodes.find(next) == rnodes.end() || rnodes.find(prev) == rnodes.end()) {
+ debMsg("Tri "<< t << " " << node << " " << next << " " << prev , 1);
+ for(set<int>::iterator it= rnodes.begin(); it != rnodes.end(); ++it)
+ debMsg( *it , 1);
+ errMsg("node missing in 1ring");
+ }
+ if (rtris.find(t) == rtris.end()) {
+ debMsg("Tri "<< t << " " << node , 1);
+ errMsg("tri missing in 1ring");
+ }
+ }
+ }
+ for (int n=0; n<nodes; n++) {
+ bool docheck=true;
+ if (deletedNodes)
+ for (size_t e=0; e<deletedNodes->size(); e++)
+ if ((*deletedNodes)[e] == n) docheck=false;;
+
+ if (docheck) {
+ set<int>& sn = m1RingLookup[n].nodes;
+ set<int>& st = m1RingLookup[n].tris;
+ set<int> sn2;
+
+ for (set<int>::iterator it=st.begin(); it != st.end(); ++it) {
+ bool found = false;
+ for (int c=0; c<3; c++) {
+ if (mTris[*it].c[c] == n)
+ found = true;
+ else
+ sn2.insert(mTris[*it].c[c]);
+ }
+ if (!found) {
+ cout << *it << " " << n << endl;
+ for (int c=0; c<3; c++) cout << mTris[*it].c[c] << endl;
+ errMsg("invalid triangle in 1ring");
+ }
+ if (taintedTris && taintedTris->find(*it) != taintedTris->end()) {
+ cout << *it << endl;
+ errMsg("tainted tri still is use");
+ }
+ }
+ if (sn.size() != sn2.size())
+ errMsg("invalid nodes in 1ring");
+ for (set<int>::iterator it=sn.begin(), it2=sn2.begin(); it != sn.end(); ++it,++it2) {
+ if (*it != *it2) {
+ cout << "Node " << n << ": " << *it << " vs " << *it2 << endl;
+ errMsg("node ring mismatch");
+ }
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+// rasterization
+
+void meshSDF(Mesh& mesh, LevelsetGrid& levelset, Real sigma, Real cutoff = 0.);
+
+//! helper vec3 array container
+struct CVec3Ptr {
+ Real *x, *y, *z;
+ inline Vec3 get(int i) const { return Vec3(x[i],y[i],z[i]); };
+ inline void set(int i, const Vec3& v) { x[i]=v.x; y[i]=v.y; z[i]=v.z; };
+};
+//! helper vec3 array, for CUDA compatibility, remove at some point
+struct CVec3Array {
+ CVec3Array(int sz) {
+ x.resize(sz);
+ y.resize(sz);
+ z.resize(sz);
+ }
+ CVec3Array(const std::vector<Vec3>& v) {
+ x.resize(v.size());
+ y.resize(v.size());
+ z.resize(v.size());
+ for (size_t i=0; i<v.size(); i++) {
+ x[i] = v[i].x;
+ y[i] = v[i].y;
+ z[i] = v[i].z;
+ }
+ }
+ CVec3Ptr data() {
+ CVec3Ptr a = { x.data(), y.data(), z.data()};
+ return a;
+ }
+ inline const Vec3 operator[](int idx) const { return Vec3((Real)x[idx], (Real)y[idx], (Real)z[idx]); }
+ inline void set(int idx, const Vec3& v) { x[idx] = v.x; y[idx] = v.y; z[idx] = v.z; }
+ inline int size() { return x.size(); }
+ std::vector<Real> x, y, z;
+};
+
+
+//void SDFKernel(const int* partStart, const int* partLen, CVec3Ptr pos, CVec3Ptr normal, Real* sdf, Vec3i gridRes, int intRadius, Real safeRadius2, Real cutoff2, Real isigma2);
+//! helper for rasterization
+static void SDFKernel(Grid<int>& partStart, Grid<int>& partLen, CVec3Ptr pos, CVec3Ptr normal, LevelsetGrid& sdf, Vec3i gridRes, int intRadius, Real safeRadius2, Real cutoff2, Real isigma2)
+{
+ for (int cnt_x(0); cnt_x < gridRes[0]; ++cnt_x) {
+ for (int cnt_y(0); cnt_y < gridRes[1]; ++cnt_y) {
+ for (int cnt_z(0); cnt_z < gridRes[2]; ++cnt_z) {
+ // cell index, center
+ Vec3i cell = Vec3i(cnt_x, cnt_y, cnt_z);
+ if (cell.x >= gridRes.x || cell.y >= gridRes.y || cell.z >= gridRes.z) return;
+ Vec3 cpos = Vec3(cell.x + 0.5f, cell.y + 0.5f, cell.z + 0.5f);
+ Real sum = 0.0f;
+ Real dist = 0.0f;
+
+ // query cells within block radius
+ Vec3i minBlock = Vec3i(max(cell.x - intRadius,0), max(cell.y - intRadius,0), max(cell.z - intRadius,0));
+ Vec3i maxBlock = Vec3i(min(cell.x + intRadius, gridRes.x - 1), min(cell.y + intRadius, gridRes.y - 1), min(cell.z + intRadius, gridRes.z - 1));
+ for (int i=minBlock.x; i<=maxBlock.x; i++)
+ for (int j=minBlock.y; j<=maxBlock.y; j++)
+ for (int k=minBlock.z; k<=maxBlock.z; k++) {
+ // test if block is within radius
+ Vec3 d = Vec3(cell.x-i, cell.y-j, cell.z-k);
+ Real normSqr = d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
+ if (normSqr > safeRadius2) continue;
+
+ // find source cell, and divide it into thread blocks
+ int block = i + gridRes.x * (j + gridRes.y * k);
+ int slen = partLen[block];
+ if (slen == 0) continue;
+ int start = partStart[block];
+
+ // process sources
+ for(int s=0; s<slen; s++) {
+
+ // actual sdf kernel
+ Vec3 r = cpos - pos.get(start+s);
+ Real normSqr = r[0]*r[0] + r[1]*r[1] + r[2]*r[2];
+ Real r2 = normSqr;
+ if (r2 < cutoff2) {
+ Real w = expf(-r2*isigma2);
+ sum += w;
+ dist += dot(normal.get(start+s), r) * w;
+ }
+ }
+ }
+ // writeback
+ if (sum > 0.0f) {
+ //sdf[cell.x + gridRes.x * (cell.y + gridRes.y * cell.z)] = dist / sum;
+ sdf(cell.x ,cell.y ,cell.z) = dist / sum;
+ }
+ }
+ }
+ }
+}
+
+static inline IndexInt _cIndex(const Vec3& pos, const Vec3i& s) {
+ Vec3i p = toVec3i(pos);
+ if (p.x < 0 || p.y < 0 || p.z < 0 || p.x >= s.x || p.y >= s.y || p.z >= s.z) return -1;
+ return p.x + s.x * (p.y + s.y * p.z);
+}
+
+//! Kernel: Apply a shape to a grid, setting value inside
+
+template <class T> struct ApplyMeshToGrid : public KernelBase {
+ ApplyMeshToGrid(Grid<T>* grid, Grid<Real>& sdf, T value, FlagGrid* respectFlags) : KernelBase(grid,0) ,grid(grid),sdf(sdf),value(value),respectFlags(respectFlags) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>* grid, Grid<Real>& sdf, T value, FlagGrid* respectFlags ) {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ if (sdf(i,j,k) < 0)
+ {
+ (*grid)(i,j,k) = value;
+ }
+} inline Grid<T>* getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline Grid<Real>& getArg1() {
+ return sdf; }
+ typedef Grid<Real> type1;inline T& getArg2() {
+ return value; }
+ typedef T type2;inline FlagGrid* getArg3() {
+ return respectFlags; }
+ typedef FlagGrid type3; void runMessage() { debMsg("Executing kernel ApplyMeshToGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,sdf,value,respectFlags); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,sdf,value,respectFlags); }
+ }
+ }
+ Grid<T>* grid; Grid<Real>& sdf; T value; FlagGrid* respectFlags; }
+;
+
+void Mesh::applyMeshToGrid(GridBase* grid, FlagGrid* respectFlags, Real cutoff) {
+ FluidSolver dummy(grid->getSize());
+ LevelsetGrid mesh_sdf(&dummy, false);
+ meshSDF(*this, mesh_sdf, 2., cutoff); // meshSigma=2 fixed here
+
+# if NOPYTHON!=1
+ if (grid->getType() & GridBase::TypeInt)
+ ApplyMeshToGrid<int> ((Grid<int>*)grid, mesh_sdf, _args.get<int>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeReal)
+ ApplyMeshToGrid<Real> ((Grid<Real>*)grid, mesh_sdf, _args.get<Real>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeVec3)
+ ApplyMeshToGrid<Vec3> ((Grid<Vec3>*)grid, mesh_sdf, _args.get<Vec3>("value"), respectFlags);
+ else
+ errMsg("Shape::applyToGrid(): unknown grid type");
+# else
+ errMsg("Not yet supported...");
+# endif
+}
+
+void Mesh::computeLevelset(LevelsetGrid& levelset, Real sigma, Real cutoff) {
+ meshSDF( *this, levelset, sigma, cutoff);
+}
+
+LevelsetGrid Mesh::getLevelset(Real sigma, Real cutoff) {
+ LevelsetGrid phi(getParent());
+ meshSDF(*this, phi, sigma, cutoff);
+ return phi;
+}
+
+void meshSDF(Mesh& mesh, LevelsetGrid& levelset, Real sigma, Real cutoff)
+{
+ if (cutoff<0) cutoff = 2*sigma;
+ Real maxEdgeLength = 0.75;
+ Real numSamplesPerCell = 0.75;
+
+ Vec3i gridRes = levelset.getSize();
+ Vec3 mult = toVec3(gridRes) / toVec3(mesh.getParent()->getGridSize());
+
+ // prepare center values
+ std::vector<Vec3> center;
+ std::vector<Vec3> normals;
+ short bigEdges(0);
+ std::vector<Vec3> samplePoints;
+ for(int i=0; i<mesh.numTris(); i++){
+ center.push_back(Vec3(mesh.getFaceCenter(i) * mult));
+ normals.push_back(mesh.getFaceNormal(i));
+ //count big, stretched edges
+ bigEdges = 0;
+ for (short edge(0); edge <3; ++edge){
+ if(norm(mesh.getEdge(i,edge)) > maxEdgeLength){
+ bigEdges += 1 << edge;
+ }
+ }
+ if(bigEdges > 0){
+ samplePoints.clear();
+ short iterA, pointA, iterB, pointB;
+ int numSamples0 = norm(mesh.getEdge(i,1)) * numSamplesPerCell;
+ int numSamples1 = norm(mesh.getEdge(i,2)) * numSamplesPerCell;
+ int numSamples2 = norm(mesh.getEdge(i,0)) * numSamplesPerCell;
+ if(! (bigEdges & (1 << 0))){
+ //loop through 0,1
+ iterA = numSamples1;
+ pointA = 0;
+ iterB = numSamples2;
+ pointB = 1;
+ }
+ else if(! (bigEdges & (1 << 1))){
+ //loop through 1,2
+ iterA = numSamples2;
+ pointA = 1;
+ iterB = numSamples0;
+ pointB = 2;
+
+ }
+ else{
+ //loop through 2,0
+ iterA = numSamples0;
+ pointA = 2;
+ iterB = numSamples1;
+ pointB = 0;
+ }
+
+ Real u(0.),v(0.),w(0.); // barycentric uvw coords
+ Vec3 samplePoint,normal;
+ for (int sample0(0); sample0 < iterA; ++sample0){
+ u = Real(1. * sample0 / iterA);
+ for (int sample1(0); sample1 < iterB; ++sample1){
+ v = Real(1. * sample1 / iterB);
+ w = 1 - u - v;
+ if (w < 0.)
+ continue;
+ samplePoint = mesh.getNode(i,pointA) * mult * u +
+ mesh.getNode(i,pointB) * mult * v +
+ mesh.getNode(i,(3 - pointA - pointB)) * mult * w;
+ samplePoints.push_back(samplePoint);
+ normal = mesh.getFaceNormal(i);
+ normals.push_back(normal);
+ }
+ }
+ center.insert(center.end(), samplePoints.begin(), samplePoints.end());
+ }
+ }
+
+ // prepare grid
+ levelset.setConst( -cutoff );
+
+ // 1. count sources per cell
+ Grid<int> srcPerCell(levelset.getParent());
+ for (size_t i=0; i<center.size(); i++) {
+ IndexInt idx = _cIndex(center[i], gridRes);
+ if (idx >= 0)
+ srcPerCell[idx]++;
+ }
+
+ // 2. create start index lookup
+ Grid<int> srcCellStart(levelset.getParent());
+ int cnt=0;
+ FOR_IJK(srcCellStart) {
+ IndexInt idx = srcCellStart.index(i,j,k);
+ srcCellStart[idx] = cnt;
+ cnt += srcPerCell[idx];
+ }
+
+ // 3. reorder nodes
+ CVec3Array reorderPos(center.size());
+ CVec3Array reorderNormal(center.size());
+ {
+ Grid<int> curSrcCell(levelset.getParent());
+ for (int i=0; i<(int)center.size(); i++) {
+ IndexInt idx = _cIndex(center[i], gridRes);
+ if (idx < 0) continue;
+ IndexInt idx2 = srcCellStart[idx] + curSrcCell[idx];
+ reorderPos.set(idx2, center[i]);
+ reorderNormal.set(idx2, normals[i]);
+ curSrcCell[idx]++;
+ }
+ }
+
+ // construct parameters
+ Real safeRadius = cutoff + sqrt(3.0)*0.5;
+ Real safeRadius2 = safeRadius*safeRadius;
+ Real cutoff2 = cutoff*cutoff;
+ Real isigma2 = 1.0/(sigma*sigma);
+ int intRadius = (int)(cutoff+0.5);
+
+ SDFKernel( srcCellStart, srcPerCell,
+ reorderPos.data(), reorderNormal.data(),
+ levelset, gridRes, intRadius, safeRadius2, cutoff2, isigma2);
+
+ // floodfill outside
+ std::stack<Vec3i> outside;
+ FOR_IJK(levelset) {
+ if (levelset(i,j,k) >= cutoff-1.0f)
+ outside.push(Vec3i(i,j,k));
+ }
+ while(!outside.empty()) {
+ Vec3i c = outside.top();
+ outside.pop();
+ levelset(c) = cutoff;
+ if (c.x > 0 && levelset(c.x-1, c.y, c.z) < 0) outside.push(Vec3i(c.x-1,c.y,c.z));
+ if (c.y > 0 && levelset(c.x, c.y-1, c.z) < 0) outside.push(Vec3i(c.x,c.y-1,c.z));
+ if (c.z > 0 && levelset(c.x, c.y, c.z-1) < 0) outside.push(Vec3i(c.x,c.y,c.z-1));
+ if (c.x < levelset.getSizeX()-1 && levelset(c.x+1, c.y, c.z) < 0) outside.push(Vec3i(c.x+1,c.y,c.z));
+ if (c.y < levelset.getSizeY()-1 && levelset(c.x, c.y+1, c.z) < 0) outside.push(Vec3i(c.x,c.y+1,c.z));
+ if (c.z < levelset.getSizeZ()-1 && levelset(c.x, c.y, c.z+1) < 0) outside.push(Vec3i(c.x,c.y,c.z+1));
+ };
+}
+
+// Blender data pointer accessors
+std::string Mesh::getNodesDataPointer() {
+ std::ostringstream out;
+ out << &mNodes;
+ return out.str();
+}
+std::string Mesh::getTrisDataPointer() {
+ std::ostringstream out;
+ out << &mTris;
+ return out.str();
+}
+
+// mesh data
+
+MeshDataBase::MeshDataBase(FluidSolver* parent) :
+ PbClass(parent) , mMesh(NULL) {
+}
+
+MeshDataBase::~MeshDataBase()
+{
+ // notify parent of deletion
+ if(mMesh)
+ mMesh->deregister(this);
+}
+
+// actual data implementation
+
+template<class T>
+MeshDataImpl<T>::MeshDataImpl(FluidSolver* parent) :
+ MeshDataBase(parent) , mpGridSource(NULL), mGridSourceMAC(false) {
+}
+
+template<class T>
+MeshDataImpl<T>::MeshDataImpl(FluidSolver* parent, MeshDataImpl<T>* other) :
+ MeshDataBase(parent) , mpGridSource(NULL), mGridSourceMAC(false) {
+ this->mData = other->mData;
+ setName(other->getName());
+}
+
+template<class T>
+MeshDataImpl<T>::~MeshDataImpl() {
+}
+
+template<class T>
+IndexInt MeshDataImpl<T>::getSizeSlow() const {
+ return mData.size();
+}
+template<class T>
+void MeshDataImpl<T>::addEntry() {
+ // add zero'ed entry
+ T tmp = T(0.);
+ // for debugging, force init:
+ //tmp = T(0.02 * mData.size()); // increasing
+ //tmp = T(1.); // constant 1
+ return mData.push_back(tmp);
+}
+template<class T>
+void MeshDataImpl<T>::resize(IndexInt s) {
+ mData.resize(s);
+}
+template<class T>
+void MeshDataImpl<T>::copyValueSlow(IndexInt from, IndexInt to) {
+ this->copyValue(from,to);
+}
+template<class T>
+MeshDataBase* MeshDataImpl<T>::clone() {
+ MeshDataImpl<T>* npd = new MeshDataImpl<T>( getParent(), this );
+ return npd;
+}
+
+template<class T>
+void MeshDataImpl<T>::setSource(Grid<T>* grid, bool isMAC ) {
+ mpGridSource = grid;
+ mGridSourceMAC = isMAC;
+ if(isMAC) assertMsg( dynamic_cast<MACGrid*>(grid) != NULL , "Given grid is not a valid MAC grid");
+}
+
+template<class T>
+void MeshDataImpl<T>::initNewValue(IndexInt idx, Vec3 pos) {
+ if(!mpGridSource)
+ mData[idx] = 0;
+ else {
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ }
+}
+
+// special handling needed for velocities
+template<>
+void MeshDataImpl<Vec3>::initNewValue(IndexInt idx, Vec3 pos) {
+ if(!mpGridSource)
+ mData[idx] = 0;
+ else {
+ if(!mGridSourceMAC)
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ else
+ mData[idx] = ((MACGrid*)mpGridSource)->getInterpolated(pos);
+ }
+}
+
+//! update additional mesh data
+void Mesh::updateDataFields() {
+ for(size_t i=0; i<mNodes.size(); ++i) {
+ Vec3 pos = mNodes[i].pos;
+ for(IndexInt md=0; md<(IndexInt)mMdataReal.size(); ++md)
+ mMdataReal[md]->initNewValue(i, mNodes[i].pos);
+ for(IndexInt md=0; md<(IndexInt)mMdataVec3.size(); ++md)
+ mMdataVec3[md]->initNewValue(i, mNodes[i].pos);
+ for(IndexInt md=0; md<(IndexInt)mMdataInt.size(); ++md)
+ mMdataInt[md]->initNewValue(i, mNodes[i].pos);
+ }
+}
+
+template<typename T>
+void MeshDataImpl<T>::load(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if ( ext == ".uni")
+ readMdataUni<T>(name, this);
+ else if ( ext == ".raw") // raw = uni for now
+ readMdataUni<T>(name, this);
+ else
+ errMsg("mesh data '" + name +"' filetype not supported for loading");
+}
+
+template<typename T>
+void MeshDataImpl<T>::save(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ writeMdataUni<T>(name, this);
+ else if (ext == ".raw") // raw = uni for now
+ writeMdataUni<T>(name, this);
+ else
+ errMsg("mesh data '" + name +"' filetype not supported for saving");
+}
+
+// specializations
+
+template<>
+MeshDataBase::MdataType MeshDataImpl<Real>::getType() const {
+ return MeshDataBase::TypeReal;
+}
+template<>
+MeshDataBase::MdataType MeshDataImpl<int>::getType() const {
+ return MeshDataBase::TypeInt;
+}
+template<>
+MeshDataBase::MdataType MeshDataImpl<Vec3>::getType() const {
+ return MeshDataBase::TypeVec3;
+}
+
+template <class T> struct knSetMdataConst : public KernelBase {
+ knSetMdataConst(MeshDataImpl<T>& mdata, T value) : KernelBase(mdata.size()) ,mdata(mdata),value(value) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& mdata, T value ) { mdata[idx] = value; } inline MeshDataImpl<T>& getArg0() {
+ return mdata; }
+ typedef MeshDataImpl<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knSetMdataConst ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,mdata,value); }
+ }
+ MeshDataImpl<T>& mdata; T value; }
+;
+
+template <class T, class S> struct knMdataSet : public KernelBase {
+ knMdataSet(MeshDataImpl<T>& me, const MeshDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<S>& other ) { me[idx] += other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<S>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knMdataSet ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ MeshDataImpl<T>& me; const MeshDataImpl<S>& other; }
+;
+template <class T, class S> struct knMdataAdd : public KernelBase {
+ knMdataAdd(MeshDataImpl<T>& me, const MeshDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<S>& other ) { me[idx] += other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<S>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knMdataAdd ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ MeshDataImpl<T>& me; const MeshDataImpl<S>& other; }
+;
+template <class T, class S> struct knMdataSub : public KernelBase {
+ knMdataSub(MeshDataImpl<T>& me, const MeshDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<S>& other ) { me[idx] -= other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<S>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knMdataSub ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ MeshDataImpl<T>& me; const MeshDataImpl<S>& other; }
+;
+template <class T, class S> struct knMdataMult : public KernelBase {
+ knMdataMult(MeshDataImpl<T>& me, const MeshDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<S>& other ) { me[idx] *= other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<S>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knMdataMult ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ MeshDataImpl<T>& me; const MeshDataImpl<S>& other; }
+;
+template <class T, class S> struct knMdataDiv : public KernelBase {
+ knMdataDiv(MeshDataImpl<T>& me, const MeshDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<S>& other ) { me[idx] /= other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<S>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knMdataDiv ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ MeshDataImpl<T>& me; const MeshDataImpl<S>& other; }
+;
+
+template <class T, class S> struct knMdataSetScalar : public KernelBase {
+ knMdataSetScalar(MeshDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const S& other ) { me[idx] = other; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knMdataSetScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ MeshDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knMdataAddScalar : public KernelBase {
+ knMdataAddScalar(MeshDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const S& other ) { me[idx] += other; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knMdataAddScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ MeshDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knMdataMultScalar : public KernelBase {
+ knMdataMultScalar(MeshDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const S& other ) { me[idx] *= other; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knMdataMultScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ MeshDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knMdataScaledAdd : public KernelBase {
+ knMdataScaledAdd(MeshDataImpl<T>& me, const MeshDataImpl<T>& other, const S& factor) : KernelBase(me.size()) ,me(me),other(other),factor(factor) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<T>& other, const S& factor ) { me[idx] += factor * other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<T>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<T> type1;inline const S& getArg2() {
+ return factor; }
+ typedef S type2; void runMessage() { debMsg("Executing kernel knMdataScaledAdd ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other,factor); }
+ }
+ MeshDataImpl<T>& me; const MeshDataImpl<T>& other; const S& factor; }
+;
+
+template <class T> struct knMdataSafeDiv : public KernelBase {
+ knMdataSafeDiv(MeshDataImpl<T>& me, const MeshDataImpl<T>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<T>& other ) { me[idx] = safeDivide(me[idx], other[idx]); } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<T>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<T> type1; void runMessage() { debMsg("Executing kernel knMdataSafeDiv ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ MeshDataImpl<T>& me; const MeshDataImpl<T>& other; }
+;
+template <class T> struct knMdataSetConst : public KernelBase {
+ knMdataSetConst(MeshDataImpl<T>& mdata, T value) : KernelBase(mdata.size()) ,mdata(mdata),value(value) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& mdata, T value ) { mdata[idx] = value; } inline MeshDataImpl<T>& getArg0() {
+ return mdata; }
+ typedef MeshDataImpl<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knMdataSetConst ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,mdata,value); }
+ }
+ MeshDataImpl<T>& mdata; T value; }
+;
+
+template <class T> struct knMdataClamp : public KernelBase {
+ knMdataClamp(MeshDataImpl<T>& me, T min, T max) : KernelBase(me.size()) ,me(me),min(min),max(max) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, T min, T max ) { me[idx] = clamp( me[idx], min, max); } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline T& getArg1() {
+ return min; }
+ typedef T type1;inline T& getArg2() {
+ return max; }
+ typedef T type2; void runMessage() { debMsg("Executing kernel knMdataClamp ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,min,max); }
+ }
+ MeshDataImpl<T>& me; T min; T max; }
+;
+template <class T> struct knMdataClampMin : public KernelBase {
+ knMdataClampMin(MeshDataImpl<T>& me, const T vmin) : KernelBase(me.size()) ,me(me),vmin(vmin) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const T vmin ) { me[idx] = std::max(vmin, me[idx]); } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const T& getArg1() {
+ return vmin; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knMdataClampMin ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,vmin); }
+ }
+ MeshDataImpl<T>& me; const T vmin; }
+;
+template <class T> struct knMdataClampMax : public KernelBase {
+ knMdataClampMax(MeshDataImpl<T>& me, const T vmax) : KernelBase(me.size()) ,me(me),vmax(vmax) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const T vmax ) { me[idx] = std::min(vmax, me[idx]); } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const T& getArg1() {
+ return vmax; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knMdataClampMax ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,vmax); }
+ }
+ MeshDataImpl<T>& me; const T vmax; }
+;
+ struct knMdataClampMinVec3 : public KernelBase {
+ knMdataClampMinVec3(MeshDataImpl<Vec3>& me, const Real vmin) : KernelBase(me.size()) ,me(me),vmin(vmin) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<Vec3>& me, const Real vmin ) {
+ me[idx].x = std::max(vmin, me[idx].x);
+ me[idx].y = std::max(vmin, me[idx].y);
+ me[idx].z = std::max(vmin, me[idx].z);
+} inline MeshDataImpl<Vec3>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<Vec3> type0;inline const Real& getArg1() {
+ return vmin; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knMdataClampMinVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,vmin); }
+ }
+ MeshDataImpl<Vec3>& me; const Real vmin; }
+;
+ struct knMdataClampMaxVec3 : public KernelBase {
+ knMdataClampMaxVec3(MeshDataImpl<Vec3>& me, const Real vmax) : KernelBase(me.size()) ,me(me),vmax(vmax) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<Vec3>& me, const Real vmax ) {
+ me[idx].x = std::min(vmax, me[idx].x);
+ me[idx].y = std::min(vmax, me[idx].y);
+ me[idx].z = std::min(vmax, me[idx].z);
+} inline MeshDataImpl<Vec3>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<Vec3> type0;inline const Real& getArg1() {
+ return vmax; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knMdataClampMaxVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,vmax); }
+ }
+ MeshDataImpl<Vec3>& me; const Real vmax; }
+;
+
+// python operators
+
+
+template<typename T>
+MeshDataImpl<T>& MeshDataImpl<T>::copyFrom(const MeshDataImpl<T>& a) {
+ assertMsg (a.mData.size() == mData.size() , "different mdata size "<<a.mData.size()<<" vs "<<this->mData.size() );
+ memcpy( &mData[0], &a.mData[0], sizeof(T) * mData.size() );
+ return *this;
+}
+
+template<typename T>
+void MeshDataImpl<T>::setConst(T s) {
+ knMdataSetScalar<T,T> op( *this, s );
+}
+
+template<typename T>
+void MeshDataImpl<T>::setConstRange(T s, const int begin, const int end) {
+ for(int i=begin; i<end; ++i) (*this)[i] = s;
+}
+
+// special set by flag
+template <class T, class S> struct knMdataSetScalarIntFlag : public KernelBase {
+ knMdataSetScalarIntFlag(MeshDataImpl<T>& me, const S& other, const MeshDataImpl<int>& t, const int itype) : KernelBase(me.size()) ,me(me),other(other),t(t),itype(itype) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const S& other, const MeshDataImpl<int>& t, const int itype ) {
+ if(t[idx]&itype) me[idx] = other;
+} inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1;inline const MeshDataImpl<int>& getArg2() {
+ return t; }
+ typedef MeshDataImpl<int> type2;inline const int& getArg3() {
+ return itype; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel knMdataSetScalarIntFlag ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other,t,itype); }
+ }
+ MeshDataImpl<T>& me; const S& other; const MeshDataImpl<int>& t; const int itype; }
+;
+template<typename T>
+void MeshDataImpl<T>::setConstIntFlag(T s, const MeshDataImpl<int>& t, const int itype) {
+ knMdataSetScalarIntFlag<T,T> op(*this, s, t, itype);
+}
+
+template<typename T>
+void MeshDataImpl<T>::add(const MeshDataImpl<T>& a) {
+ knMdataAdd<T,T> op( *this, a );
+}
+template<typename T>
+void MeshDataImpl<T>::sub(const MeshDataImpl<T>& a) {
+ knMdataSub<T,T> op( *this, a );
+}
+
+template<typename T>
+void MeshDataImpl<T>::addConst(T s) {
+ knMdataAddScalar<T,T> op( *this, s );
+}
+
+template<typename T>
+void MeshDataImpl<T>::addScaled(const MeshDataImpl<T>& a, const T& factor) {
+ knMdataScaledAdd<T,T> op( *this, a, factor );
+}
+
+template<typename T>
+void MeshDataImpl<T>::mult( const MeshDataImpl<T>& a) {
+ knMdataMult<T,T> op( *this, a );
+}
+
+template<typename T>
+void MeshDataImpl<T>::safeDiv(const MeshDataImpl<T>& a) {
+ knMdataSafeDiv<T> op( *this, a );
+}
+
+template<typename T>
+void MeshDataImpl<T>::multConst(T s) {
+ knMdataMultScalar<T,T> op( *this, s );
+}
+
+
+template<typename T>
+void MeshDataImpl<T>::clamp(Real vmin, Real vmax) {
+ knMdataClamp<T> op( *this, vmin, vmax );
+}
+
+template<typename T>
+void MeshDataImpl<T>::clampMin(Real vmin) {
+ knMdataClampMin<T> op( *this, vmin );
+}
+template<typename T>
+void MeshDataImpl<T>::clampMax(Real vmax) {
+ knMdataClampMax<T> op( *this, vmax );
+}
+
+template<>
+void MeshDataImpl<Vec3>::clampMin(Real vmin) {
+ knMdataClampMinVec3 op( *this, vmin );
+}
+template<>
+void MeshDataImpl<Vec3>::clampMax(Real vmax) {
+ knMdataClampMaxVec3 op( *this, vmax );
+}
+
+template<typename T> struct KnPtsSum : public KernelBase {
+ KnPtsSum(const MeshDataImpl<T>& val, const MeshDataImpl<int> *t, const int itype) : KernelBase(val.size()) ,val(val),t(t),itype(itype) ,result(T(0.)) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<T>& val, const MeshDataImpl<int> *t, const int itype ,T& result) { if(t && !((*t)[idx]&itype)) return; result += val[idx]; } inline operator T () {
+ return result; }
+ inline T & getRet() {
+ return result; }
+ inline const MeshDataImpl<T>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<int> * getArg1() {
+ return t; }
+ typedef MeshDataImpl<int> type1;inline const int& getArg2() {
+ return itype; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel KnPtsSum ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ T result = T(0.);
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,t,itype,result);
+#pragma omp critical
+{this->result += result; } }
+ }
+ const MeshDataImpl<T>& val; const MeshDataImpl<int> * t; const int itype; T result; }
+;
+template<typename T> struct KnPtsSumSquare : public KernelBase {
+ KnPtsSumSquare(const MeshDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,result(0.) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<T>& val ,Real& result) { result += normSquare(val[idx]); } inline operator Real () {
+ return result; }
+ inline Real & getRet() {
+ return result; }
+ inline const MeshDataImpl<T>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<T> type0; void runMessage() { debMsg("Executing kernel KnPtsSumSquare ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real result = 0.;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,result);
+#pragma omp critical
+{this->result += result; } }
+ }
+ const MeshDataImpl<T>& val; Real result; }
+;
+template<typename T> struct KnPtsSumMagnitude : public KernelBase {
+ KnPtsSumMagnitude(const MeshDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,result(0.) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<T>& val ,Real& result) { result += norm(val[idx]); } inline operator Real () {
+ return result; }
+ inline Real & getRet() {
+ return result; }
+ inline const MeshDataImpl<T>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<T> type0; void runMessage() { debMsg("Executing kernel KnPtsSumMagnitude ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real result = 0.;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,result);
+#pragma omp critical
+{this->result += result; } }
+ }
+ const MeshDataImpl<T>& val; Real result; }
+;
+
+template<typename T>
+T MeshDataImpl<T>::sum(const MeshDataImpl<int> *t, const int itype) const {
+ return KnPtsSum<T>(*this, t, itype);
+}
+template<typename T>
+Real MeshDataImpl<T>::sumSquare() const {
+ return KnPtsSumSquare<T>(*this);
+}
+template<typename T>
+Real MeshDataImpl<T>::sumMagnitude() const {
+ return KnPtsSumMagnitude<T>(*this);
+}
+
+template<typename T>
+
+ struct CompMdata_Min : public KernelBase {
+ CompMdata_Min(const MeshDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<T>& val ,Real& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const MeshDataImpl<T>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<T> type0; void runMessage() { debMsg("Executing kernel CompMdata_Min ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real minVal = std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,minVal);
+#pragma omp critical
+{this->minVal = min(minVal, this->minVal); } }
+ }
+ const MeshDataImpl<T>& val; Real minVal; }
+;
+
+template<typename T>
+
+ struct CompMdata_Max : public KernelBase {
+ CompMdata_Max(const MeshDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<T>& val ,Real& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const MeshDataImpl<T>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<T> type0; void runMessage() { debMsg("Executing kernel CompMdata_Max ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real maxVal = -std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,maxVal);
+#pragma omp critical
+{this->maxVal = max(maxVal, this->maxVal); } }
+ }
+ const MeshDataImpl<T>& val; Real maxVal; }
+;
+
+template<typename T>
+Real MeshDataImpl<T>::getMin() {
+ return CompMdata_Min<T> (*this);
+}
+
+template<typename T>
+Real MeshDataImpl<T>::getMaxAbs() {
+ Real amin = CompMdata_Min<T> (*this);
+ Real amax = CompMdata_Max<T> (*this);
+ return max( fabs(amin), fabs(amax));
+}
+
+template<typename T>
+Real MeshDataImpl<T>::getMax() {
+ return CompMdata_Max<T> (*this);
+}
+
+template<typename T>
+void MeshDataImpl<T>::printMdata(IndexInt start, IndexInt stop, bool printIndex)
+{
+ std::ostringstream sstr;
+ IndexInt s = (start>0 ? start : 0 );
+ IndexInt e = (stop>0 ? stop : (IndexInt)mData.size() );
+ s = Manta::clamp(s, (IndexInt)0, (IndexInt)mData.size());
+ e = Manta::clamp(e, (IndexInt)0, (IndexInt)mData.size());
+
+ for(IndexInt i=s; i<e; ++i) {
+ if(printIndex) sstr << i<<": ";
+ sstr<<mData[i]<<" "<<"\n";
+ }
+ debMsg( sstr.str() , 1 );
+}
+template<class T> std::string MeshDataImpl<T>::getDataPointer() {
+ std::ostringstream out;
+ out << &mData;
+ return out.str();
+}
+
+// specials for vec3
+// work on length values, ie, always positive (in contrast to scalar versions above)
+
+
+ struct CompMdata_MinVec3 : public KernelBase {
+ CompMdata_MinVec3(const MeshDataImpl<Vec3>& val) : KernelBase(val.size()) ,val(val) ,minVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<Vec3>& val ,Real& minVal) {
+ const Real s = normSquare(val[idx]);
+ if (s < minVal)
+ minVal = s;
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const MeshDataImpl<Vec3>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<Vec3> type0; void runMessage() { debMsg("Executing kernel CompMdata_MinVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real minVal = -std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,minVal);
+#pragma omp critical
+{this->minVal = min(minVal, this->minVal); } }
+ }
+ const MeshDataImpl<Vec3>& val; Real minVal; }
+;
+
+
+ struct CompMdata_MaxVec3 : public KernelBase {
+ CompMdata_MaxVec3(const MeshDataImpl<Vec3>& val) : KernelBase(val.size()) ,val(val) ,maxVal(-std::numeric_limits<Real>::min()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<Vec3>& val ,Real& maxVal) {
+ const Real s = normSquare(val[idx]);
+ if (s > maxVal)
+ maxVal = s;
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const MeshDataImpl<Vec3>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<Vec3> type0; void runMessage() { debMsg("Executing kernel CompMdata_MaxVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real maxVal = -std::numeric_limits<Real>::min();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,maxVal);
+#pragma omp critical
+{this->maxVal = max(maxVal, this->maxVal); } }
+ }
+ const MeshDataImpl<Vec3>& val; Real maxVal; }
+;
+
+template<>
+Real MeshDataImpl<Vec3>::getMin() {
+ return sqrt(CompMdata_MinVec3 (*this));
+}
+
+template<>
+Real MeshDataImpl<Vec3>::getMaxAbs() {
+ return sqrt(CompMdata_MaxVec3 (*this)); // no minimum necessary here
+}
+
+template<>
+Real MeshDataImpl<Vec3>::getMax() {
+ return sqrt(CompMdata_MaxVec3 (*this));
+}
+
+
+// explicit instantiation
+template class MeshDataImpl<int>;
+template class MeshDataImpl<Real>;
+template class MeshDataImpl<Vec3>;
+
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h
new file mode 100644
index 00000000000..f7cbd416769
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h
@@ -0,0 +1,767 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Meshes
+ *
+ * note: this is only a temporary solution, details are bound to change
+ * long term goal is integration with Split&Merge code by Wojtan et al.
+ *
+ ******************************************************************************/
+
+#ifndef _MESH_H
+#define _MESH_H
+
+#include <vector>
+#include "manta.h"
+#include "vectorbase.h"
+#include <set>
+#include "levelset.h"
+
+namespace Manta {
+
+// fwd decl
+class GridBase;
+//class LevelsetGrid;
+class FlagGrid;
+class MACGrid;
+class Shape;
+class MeshDataBase;
+template<class T> class MeshDataImpl;
+
+
+//! Node position and flags
+struct Node {
+ Node() : flags(0), pos(Vec3::Zero), normal(Vec3::Zero) {}
+ Node(const Vec3& p) : flags(0), pos(p) {}
+ int flags;
+ Vec3 pos, normal;
+};
+
+//! Carries indices of its nodes
+struct Triangle {
+ Triangle() : flags(0) { c[0] = c[1] = c[2] = 0; }
+ Triangle(int n0, int n1, int n2) : flags(0) { c[0]=n0; c[1]=n1; c[2]=n2; }
+
+ int c[3];
+ int flags;
+};
+
+//! For fast access to nodes and neighboring triangles
+struct Corner {
+ Corner() : tri(-1), node(-1), opposite(-1), next(-1), prev(-1) {};
+ Corner(int t, int n) : tri(t), node(n), opposite(-1), next(-1), prev(-1) {}
+
+ int tri;
+ int node;
+ int opposite;
+ int next;
+ int prev;
+};
+
+//! Base class for mesh data channels (texture coords, vorticity, ...)
+struct NodeChannel {
+ virtual ~NodeChannel() {};
+ virtual void resize(int num) = 0;
+ virtual int size() = 0;
+ virtual NodeChannel* clone() = 0;
+
+ virtual void addInterpol(int a, int b, Real alpha) = 0;
+ virtual void mergeWith(int node, int delnode, Real alpha) = 0;
+ virtual void renumber(const std::vector<int>& newIndex, int newsize) = 0;
+};
+
+//! Node channel using only a vector
+template<class T>
+struct SimpleNodeChannel : public NodeChannel {
+ SimpleNodeChannel() {};
+ SimpleNodeChannel(const SimpleNodeChannel<T>& a) : data(a.data) {}
+ void resize(int num) { data.resize(num); }
+ virtual int size() { return data.size(); }
+ virtual void renumber(const std::vector<int>& newIndex, int newsize);
+
+ //virtual void addSplit(int from, Real alpha) { data.push_back(data[from]); }
+
+ std::vector<T> data;
+};
+
+//! Base class for mesh data channels (texture coords, vorticity, ...)
+struct TriChannel {
+ virtual ~TriChannel() {};
+ virtual void resize(int num) = 0;
+ virtual TriChannel* clone() = 0;
+ virtual int size() = 0;
+
+ virtual void addNew() = 0;
+ virtual void addSplit(int from, Real alpha) = 0;
+ virtual void remove(int tri) = 0;
+};
+
+//! Tri channel using only a vector
+template<class T>
+struct SimpleTriChannel : public TriChannel {
+ SimpleTriChannel() {};
+ SimpleTriChannel(const SimpleTriChannel<T>& a) : data(a.data) {}
+ void resize(int num) { data.resize(num); }
+ void remove(int tri) { if (tri!=(int)data.size()-1) data[tri] = *data.rbegin(); data.pop_back(); }
+ virtual int size() { return data.size(); }
+
+ virtual void addSplit(int from, Real alpha) { data.push_back(data[from]); }
+ virtual void addNew() { data.push_back(T()); }
+
+ std::vector<T> data;
+};
+
+struct OneRing {
+ OneRing() {}
+ std::set<int> nodes;
+ std::set<int> tris;
+};
+
+//! Triangle mesh class
+/*! note: this is only a temporary solution, details are bound to change
+ long term goal is integration with Split&Merge code by Wojtan et al.*/
+class Mesh : public PbClass {public:
+ Mesh(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Mesh::Mesh" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new Mesh(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Mesh::Mesh" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::Mesh",e.what()); return -1; }
+ }
+
+ virtual ~Mesh();
+ virtual Mesh* clone();
+
+ enum NodeFlags { NfNone = 0, NfFixed = 1, NfMarked = 2, NfKillme = 4, NfCollide = 8 };
+ enum FaceFlags { FfNone = 0, FfDoubled = 1, FfMarked = 2 };
+ enum MeshType { TypeNormal = 0, TypeVortexSheet };
+
+ virtual MeshType getType() { return TypeNormal; }
+
+ Real computeCenterOfMass(Vec3& cm) const;
+ void computeVertexNormals();
+
+ // plugins
+ void clear(); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::clear",e.what()); return 0; }
+ }
+
+ void load(std::string name, bool append = false); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); bool append = _args.getOpt<bool >("append",1,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name,append); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::load",e.what()); return 0; }
+ }
+
+ void fromShape(Shape& shape, bool append = false); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::fromShape" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Shape& shape = *_args.getPtr<Shape >("shape",0,&_lock); bool append = _args.getOpt<bool >("append",1,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->fromShape(shape,append); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::fromShape" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::fromShape",e.what()); return 0; }
+ }
+
+ void save(std::string name); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::save",e.what()); return 0; }
+ }
+
+ void advectInGrid(FlagGrid& flags, MACGrid& vel, int integrationMode); static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::advectInGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); int integrationMode = _args.get<int >("integrationMode",2,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->advectInGrid(flags,vel,integrationMode); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::advectInGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::advectInGrid",e.what()); return 0; }
+ }
+
+ void scale(Vec3 s); static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::scale" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 s = _args.get<Vec3 >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->scale(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::scale" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::scale",e.what()); return 0; }
+ }
+
+ void offset(Vec3 o); static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::offset" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 o = _args.get<Vec3 >("o",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->offset(o); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::offset" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::offset",e.what()); return 0; }
+ }
+
+ void rotate(Vec3 thetas); static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::rotate" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 thetas = _args.get<Vec3 >("thetas",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->rotate(thetas); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::rotate" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::rotate",e.what()); return 0; }
+ }
+
+ void computeVelocity(Mesh& oldMesh, MACGrid& vel); static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::computeVelocity" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& oldMesh = *_args.getPtr<Mesh >("oldMesh",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->computeVelocity(oldMesh,vel); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::computeVelocity" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::computeVelocity",e.what()); return 0; }
+ }
+
+
+ void computeLevelset(LevelsetGrid& levelset, Real sigma, Real cutoff=-1.); static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::computeLevelset" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; LevelsetGrid& levelset = *_args.getPtr<LevelsetGrid >("levelset",0,&_lock); Real sigma = _args.get<Real >("sigma",1,&_lock); Real cutoff = _args.getOpt<Real >("cutoff",2,-1.,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->computeLevelset(levelset,sigma,cutoff); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::computeLevelset" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::computeLevelset",e.what()); return 0; }
+ }
+
+ LevelsetGrid getLevelset(Real sigma, Real cutoff = -1.); static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::getLevelset" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real sigma = _args.get<Real >("sigma",0,&_lock); Real cutoff = _args.getOpt<Real >("cutoff",1,-1.,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->getLevelset(sigma,cutoff)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::getLevelset" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::getLevelset",e.what()); return 0; }
+ }
+
+
+ //! map mesh to grid with sdf
+ void applyMeshToGrid(GridBase* grid, FlagGrid* respectFlags=0, Real cutoff=-1.); static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::applyMeshToGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; GridBase* grid = _args.getPtr<GridBase >("grid",0,&_lock); FlagGrid* respectFlags = _args.getPtrOpt<FlagGrid >("respectFlags",1,0,&_lock); Real cutoff = _args.getOpt<Real >("cutoff",2,-1.,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->applyMeshToGrid(grid,respectFlags,cutoff); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::applyMeshToGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::applyMeshToGrid",e.what()); return 0; }
+ }
+
+
+ //! get data pointer of nodes
+ std::string getNodesDataPointer(); static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::getNodesDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getNodesDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::getNodesDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::getNodesDataPointer",e.what()); return 0; }
+ }
+
+ //! get data pointer of tris
+ std::string getTrisDataPointer(); static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::getTrisDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getTrisDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::getTrisDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::getTrisDataPointer",e.what()); return 0; }
+ }
+
+
+ // ops
+ Mesh& operator=(const Mesh& o);
+
+ // accessors
+ inline int numTris() const { return mTris.size(); }
+ inline int numNodes() const { return mNodes.size(); }
+ inline int numTriChannels() const { return mTriChannels.size(); }
+ inline int numNodeChannels() const { return mNodeChannels.size(); }
+
+ //! return size of container
+ //! note , python binding disabled for now! cannot yet deal with long-long types
+ inline IndexInt size() const { return mNodes.size(); }
+ //! slow virtual function of base class, also returns size
+ virtual IndexInt getSizeSlow() const { return size(); }
+
+ inline Triangle& tris(int i) { return mTris[i]; }
+ inline Node& nodes(int i) { return mNodes[i]; }
+ inline Corner& corners(int tri, int c) { return mCorners[tri*3+c]; }
+ inline Corner& corners(int c) { return mCorners[c]; }
+ inline NodeChannel* nodeChannel(int i) { return mNodeChannels[i]; }
+ inline TriChannel* triChannel(int i) { return mTriChannels[i]; }
+
+ // allocate memory (eg upon load)
+ void resizeTris(int numTris);
+ void resizeNodes(int numNodes);
+
+ inline bool isNodeFixed(int n) { return mNodes[n].flags & NfFixed; }
+ inline bool isTriangleFixed(int t) { return (mNodes[mTris[t].c[0]].flags & NfFixed) || (mNodes[mTris[t].c[1]].flags & NfFixed) || (mNodes[mTris[t].c[2]].flags & NfFixed); }
+
+ inline const Vec3 getNode(int tri, int c) const { return mNodes[mTris[tri].c[c]].pos; }
+ inline Vec3& getNode(int tri, int c) { return mNodes[mTris[tri].c[c]].pos; }
+ inline const Vec3 getEdge(int tri, int e) const { return getNode(tri,(e+1)%3) - getNode(tri,e); }
+ inline OneRing& get1Ring(int node) { return m1RingLookup[node]; }
+ inline Real getFaceArea(int t) const { Vec3 c0 = mNodes[mTris[t].c[0]].pos; return 0.5*norm(cross(mNodes[mTris[t].c[1]].pos - c0, mNodes[mTris[t].c[2]].pos - c0)); }
+ inline Vec3 getFaceNormal(int t) { Vec3 c0 = mNodes[mTris[t].c[0]].pos; return getNormalized(cross(mNodes[mTris[t].c[1]].pos - c0, mNodes[mTris[t].c[2]].pos - c0)); }
+ inline Vec3 getFaceCenter(int t) const { return (mNodes[mTris[t].c[0]].pos + mNodes[mTris[t].c[1]].pos + mNodes[mTris[t].c[2]].pos) / 3.0; }
+ inline std::vector<Node>& getNodeData() { return mNodes; }
+
+ void mergeNode(int node, int delnode);
+ int addNode(Node a);
+ int addTri(Triangle a);
+ void addCorner(Corner a);
+ void removeTri(int tri);
+ void removeTriFromLookup(int tri);
+ void removeNodes(const std::vector<int>& deletedNodes);
+ void rebuildCorners(int from=0, int to=-1);
+ void rebuildLookup(int from=0, int to=-1);
+ void rebuildQuickCheck();
+ void fastNodeLookupRebuild(int corner);
+ void sanityCheck(bool strict=true, std::vector<int>* deletedNodes=0, std::map<int,bool>* taintedTris=0);
+
+ void addTriChannel(TriChannel* c) { mTriChannels.push_back(c); rebuildChannels(); }
+ void addNodeChannel(NodeChannel* c) { mNodeChannels.push_back(c); rebuildChannels(); }
+
+ //! mesh data functions
+
+ //! create a mesh data object
+ PbClass* create(PbType type, PbTypeVec T=PbTypeVec(), const std::string& name = ""); static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::create" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; PbType type = _args.get<PbType >("type",0,&_lock); PbTypeVec T = _args.getOpt<PbTypeVec >("T",1,PbTypeVec(),&_lock); const std::string& name = _args.getOpt<std::string >("name",2,"",&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->create(type,T,name)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::create" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::create",e.what()); return 0; }
+ }
+
+ //! add a mesh data field, set its parent mesh pointer
+ void registerMdata(MeshDataBase* mdata);
+ void registerMdataReal(MeshDataImpl<Real>* mdata);
+ void registerMdataVec3(MeshDataImpl<Vec3>* mdata);
+ void registerMdataInt (MeshDataImpl<int >* mdata);
+ //! remove a mesh data entry
+ void deregister(MeshDataBase* mdata);
+ //! add one zero entry to all data fields
+ void addAllMdata();
+ // note - deletion of mdata is handled in compress function
+
+ //! how many are there?
+ IndexInt getNumMdata() const { return mMeshData.size(); }
+ //! access one of the fields
+ MeshDataBase* getMdata(int i) { return mMeshData[i]; }
+
+ //! update data fields
+ void updateDataFields();
+
+protected:
+ void rebuildChannels();
+
+ std::vector<Node> mNodes;
+ std::vector<Triangle> mTris;
+ std::vector<Corner> mCorners;
+ std::vector<NodeChannel*> mNodeChannels;
+ std::vector<TriChannel*> mTriChannels;
+ std::vector<OneRing> m1RingLookup;
+
+ //! store mesh data , each pointer has its own storage vector of a certain type (int, real, vec3)
+ std::vector<MeshDataBase*> mMeshData;
+ //! lists of different types, for fast operations w/o virtual function calls
+ std::vector< MeshDataImpl<Real> *> mMdataReal;
+ std::vector< MeshDataImpl<Vec3> *> mMdataVec3;
+ std::vector< MeshDataImpl<int> *> mMdataInt; //! indicate that mdata of this mesh is copied, and needs to be freed
+ bool mFreeMdata; public: PbArgs _args; }
+#define _C_Mesh
+;
+
+//******************************************************************************
+
+//! abstract interface for mesh data
+class MeshDataBase : public PbClass {public:
+ MeshDataBase(FluidSolver* parent); static int _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "MeshDataBase::MeshDataBase" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new MeshDataBase(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"MeshDataBase::MeshDataBase" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataBase::MeshDataBase",e.what()); return -1; }
+ }
+
+ virtual ~MeshDataBase();
+
+ //! data type IDs, in line with those for grids
+ enum MdataType { TypeNone = 0, TypeReal = 1, TypeInt = 2, TypeVec3 = 4 };
+
+ //! interface functions, using assert instead of pure virtual for python compatibility
+ virtual IndexInt getSizeSlow() const { assertMsg( false , "Dont use, override..."); return 0; }
+ virtual void addEntry() { assertMsg( false , "Dont use, override..."); return; }
+ virtual MeshDataBase* clone() { assertMsg( false , "Dont use, override..."); return NULL; }
+ virtual MdataType getType() const { assertMsg( false , "Dont use, override..."); return TypeNone; }
+ virtual void resize(IndexInt size) { assertMsg( false , "Dont use, override..."); return; }
+ virtual void copyValueSlow(IndexInt from, IndexInt to) { assertMsg( false , "Dont use, override..."); return; }
+
+ //! set base pointer
+ void setMesh(Mesh* set) { mMesh = set; }
+
+ //! debugging
+ inline void checkNodeIndex(IndexInt idx) const;
+
+protected: Mesh* mMesh; public: PbArgs _args; }
+#define _C_MeshDataBase
+;
+
+
+//! abstract interface for mesh data
+
+template<class T> class MeshDataImpl : public MeshDataBase {public:
+ MeshDataImpl(FluidSolver* parent); static int _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "MeshDataImpl::MeshDataImpl" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new MeshDataImpl(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"MeshDataImpl::MeshDataImpl" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::MeshDataImpl",e.what()); return -1; }
+ }
+
+ MeshDataImpl(FluidSolver* parent, MeshDataImpl<T>* other);
+ virtual ~MeshDataImpl();
+
+ //! access data
+ inline T& get(IndexInt idx) { DEBUG_ONLY(checkNodeIndex(idx)); return mData[idx]; }
+ inline const T& get(IndexInt idx) const { DEBUG_ONLY(checkNodeIndex(idx)); return mData[idx]; }
+ inline T& operator[](IndexInt idx) { DEBUG_ONLY(checkNodeIndex(idx)); return mData[idx]; }
+ inline const T& operator[](IndexInt idx) const { DEBUG_ONLY(checkNodeIndex(idx)); return mData[idx]; }
+
+ //! set all values to 0, note - different from meshSystem::clear! doesnt modify size of array (has to stay in sync with parent system)
+ void clear(); static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::clear",e.what()); return 0; }
+ }
+
+
+ //! set grid from which to get data...
+ void setSource(Grid<T>* grid, bool isMAC=false ); static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setSource" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<T>* grid = _args.getPtr<Grid<T> >("grid",0,&_lock); bool isMAC = _args.getOpt<bool >("isMAC",1,false ,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setSource(grid,isMAC); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::setSource" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::setSource",e.what()); return 0; }
+ }
+
+
+ //! mesh data base interface
+ virtual IndexInt getSizeSlow() const;
+ virtual void addEntry();
+ virtual MeshDataBase* clone();
+ virtual MdataType getType() const;
+ virtual void resize(IndexInt s);
+ virtual void copyValueSlow(IndexInt from, IndexInt to);
+
+ IndexInt size() const { return mData.size(); }
+
+ //! fast inlined functions for per mesh operations
+ inline void copyValue(IndexInt from, IndexInt to) { get(to) = get(from); }
+ void initNewValue(IndexInt idx, Vec3 pos);
+
+ //! python interface (similar to grid data)
+ void setConst(T s); static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::setConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::setConst",e.what()); return 0; }
+ }
+
+ void setConstRange(T s, const int begin, const int end); static PyObject* _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setConstRange" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); const int begin = _args.get<int >("begin",1,&_lock); const int end = _args.get<int >("end",2,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConstRange(s,begin,end); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::setConstRange" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::setConstRange",e.what()); return 0; }
+ }
+
+ MeshDataImpl<T>& copyFrom(const MeshDataImpl<T>& a); static PyObject* _W_22 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::copyFrom" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->copyFrom(a)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::copyFrom" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::copyFrom",e.what()); return 0; }
+ }
+
+ void add(const MeshDataImpl<T>& a); static PyObject* _W_23 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::add" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->add(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::add" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::add",e.what()); return 0; }
+ }
+
+ void sub(const MeshDataImpl<T>& a); static PyObject* _W_24 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sub" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->sub(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::sub" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::sub",e.what()); return 0; }
+ }
+
+ void addConst(T s); static PyObject* _W_25 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::addConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::addConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::addConst",e.what()); return 0; }
+ }
+
+ void addScaled(const MeshDataImpl<T>& a, const T& factor); static PyObject* _W_26 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::addScaled" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); const T& factor = *_args.getPtr<T >("factor",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addScaled(a,factor); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::addScaled" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::addScaled",e.what()); return 0; }
+ }
+
+ void mult( const MeshDataImpl<T>& a); static PyObject* _W_27 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::mult" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->mult(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::mult" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::mult",e.what()); return 0; }
+ }
+
+ void multConst(T s); static PyObject* _W_28 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::multConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->multConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::multConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::multConst",e.what()); return 0; }
+ }
+
+ void safeDiv(const MeshDataImpl<T>& a); static PyObject* _W_29 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::safeDiv" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->safeDiv(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::safeDiv" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::safeDiv",e.what()); return 0; }
+ }
+
+ void clamp(Real min, Real max); static PyObject* _W_30 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clamp" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real min = _args.get<Real >("min",0,&_lock); Real max = _args.get<Real >("max",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clamp(min,max); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::clamp" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::clamp",e.what()); return 0; }
+ }
+
+ void clampMin(Real vmin); static PyObject* _W_31 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clampMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real vmin = _args.get<Real >("vmin",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clampMin(vmin); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::clampMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::clampMin",e.what()); return 0; }
+ }
+
+ void clampMax(Real vmax); static PyObject* _W_32 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clampMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real vmax = _args.get<Real >("vmax",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clampMax(vmax); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::clampMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::clampMax",e.what()); return 0; }
+ }
+
+
+ Real getMaxAbs(); static PyObject* _W_33 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getMaxAbs" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxAbs()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::getMaxAbs" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::getMaxAbs",e.what()); return 0; }
+ }
+
+ Real getMax(); static PyObject* _W_34 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMax()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::getMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::getMax",e.what()); return 0; }
+ }
+
+ Real getMin(); static PyObject* _W_35 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMin()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::getMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::getMin",e.what()); return 0; }
+ }
+
+
+ T sum(const MeshDataImpl<int> *t=NULL, const int itype=0) const ; static PyObject* _W_36 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sum" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<int> * t = _args.getPtrOpt<MeshDataImpl<int> >("t",0,NULL,&_lock); const int itype = _args.getOpt<int >("itype",1,0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->sum(t,itype)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::sum" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::sum",e.what()); return 0; }
+ }
+
+ Real sumSquare() const ; static PyObject* _W_37 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sumSquare" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->sumSquare()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::sumSquare" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::sumSquare",e.what()); return 0; }
+ }
+
+ Real sumMagnitude() const ; static PyObject* _W_38 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sumMagnitude" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->sumMagnitude()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::sumMagnitude" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::sumMagnitude",e.what()); return 0; }
+ }
+
+
+ //! special, set if int flag in t has "flag"
+ void setConstIntFlag(T s, const MeshDataImpl<int>& t, const int flag); static PyObject* _W_39 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setConstIntFlag" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); const MeshDataImpl<int>& t = *_args.getPtr<MeshDataImpl<int> >("t",1,&_lock); const int flag = _args.get<int >("flag",2,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConstIntFlag(s,t,flag); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::setConstIntFlag" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::setConstIntFlag",e.what()); return 0; }
+ }
+
+
+ void printMdata(IndexInt start=-1, IndexInt stop=-1, bool printIndex=false); static PyObject* _W_40 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::printMdata" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; IndexInt start = _args.getOpt<IndexInt >("start",0,-1,&_lock); IndexInt stop = _args.getOpt<IndexInt >("stop",1,-1,&_lock); bool printIndex = _args.getOpt<bool >("printIndex",2,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->printMdata(start,stop,printIndex); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::printMdata" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::printMdata",e.what()); return 0; }
+ }
+
+
+ //! file io
+ void save(const std::string name); static PyObject* _W_41 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::save",e.what()); return 0; }
+ }
+
+ void load(const std::string name); static PyObject* _W_42 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::load",e.what()); return 0; }
+ }
+
+
+ //! get data pointer of mesh data
+ std::string getDataPointer(); static PyObject* _W_43 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::getDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::getDataPointer",e.what()); return 0; }
+ }
+
+protected:
+ //! data storage
+ std::vector<T> mData;
+
+ //! optionally , we might have an associated grid from which to grab new data
+ Grid<T>* mpGridSource; //! unfortunately , we need to distinguish mac vs regular vec3
+ bool mGridSourceMAC; public: PbArgs _args; }
+#define _C_MeshDataImpl
+;
+
+
+
+
+
+
+// ***************************************************************************************************************
+// Implementation
+
+template<class T>
+void SimpleNodeChannel<T>::renumber(const std::vector<int>& newIndex, int newsize) {
+ for(size_t i=0; i<newIndex.size(); i++) {
+ if(newIndex[i]!=-1)
+ data[newIndex[i]] = data[newsize+i];
+ }
+ data.resize(newsize);
+}
+
+inline void MeshDataBase::checkNodeIndex(IndexInt idx) const {
+ IndexInt mySize = this->getSizeSlow();
+ if (idx<0 || idx > mySize ) {
+ errMsg( "MeshData " << " size " << mySize << " : index " << idx << " out of bound " );
+ }
+ if ( mMesh && mMesh->getSizeSlow()!=mySize ) {
+ errMsg( "MeshData " << " size " << mySize << " does not match parent! (" << mMesh->getSizeSlow() << ") " );
+ }
+}
+
+template<class T>
+void MeshDataImpl<T>::clear() {
+ for(IndexInt i=0; i<(IndexInt)mData.size(); ++i) mData[i] = 0.;
+}
+
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h.reg
new file mode 100644
index 00000000000..41e012f5d5b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h.reg
@@ -0,0 +1,56 @@
+#include "mesh.h"
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","Mesh","PbClass"); template<> const char* Namify<Mesh >::S = "Mesh";
+>Mesh^
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","Mesh",Mesh::_W_0);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","clear",Mesh::_W_1);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","load",Mesh::_W_2);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","fromShape",Mesh::_W_3);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","save",Mesh::_W_4);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","advectInGrid",Mesh::_W_5);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","scale",Mesh::_W_6);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","offset",Mesh::_W_7);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","rotate",Mesh::_W_8);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","computeVelocity",Mesh::_W_9);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","computeLevelset",Mesh::_W_10);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","getLevelset",Mesh::_W_11);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","applyMeshToGrid",Mesh::_W_12);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","getNodesDataPointer",Mesh::_W_13);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","getTrisDataPointer",Mesh::_W_14);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","create",Mesh::_W_15);
++MeshDataBase^ static const Pb::Register _R_$IDX$ ("MeshDataBase","MeshDataBase","PbClass"); template<> const char* Namify<MeshDataBase >::S = "MeshDataBase";
+>MeshDataBase^
++MeshDataBase^ static const Pb::Register _R_$IDX$ ("MeshDataBase","MeshDataBase",MeshDataBase::_W_16);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","MeshDataImpl<$CT$>","MeshDataBase"); template<> const char* Namify<MeshDataImpl<$CT$> >::S = "MeshDataImpl<$CT$>";
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","MeshDataImpl",MeshDataImpl<$CT$>::_W_17);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","clear",MeshDataImpl<$CT$>::_W_18);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","setSource",MeshDataImpl<$CT$>::_W_19);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","setConst",MeshDataImpl<$CT$>::_W_20);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","setConstRange",MeshDataImpl<$CT$>::_W_21);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","copyFrom",MeshDataImpl<$CT$>::_W_22);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","add",MeshDataImpl<$CT$>::_W_23);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","sub",MeshDataImpl<$CT$>::_W_24);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","addConst",MeshDataImpl<$CT$>::_W_25);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","addScaled",MeshDataImpl<$CT$>::_W_26);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","mult",MeshDataImpl<$CT$>::_W_27);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","multConst",MeshDataImpl<$CT$>::_W_28);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","safeDiv",MeshDataImpl<$CT$>::_W_29);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","clamp",MeshDataImpl<$CT$>::_W_30);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","clampMin",MeshDataImpl<$CT$>::_W_31);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","clampMax",MeshDataImpl<$CT$>::_W_32);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","getMaxAbs",MeshDataImpl<$CT$>::_W_33);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","getMax",MeshDataImpl<$CT$>::_W_34);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","getMin",MeshDataImpl<$CT$>::_W_35);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","sum",MeshDataImpl<$CT$>::_W_36);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","sumSquare",MeshDataImpl<$CT$>::_W_37);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","sumMagnitude",MeshDataImpl<$CT$>::_W_38);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","setConstIntFlag",MeshDataImpl<$CT$>::_W_39);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","printMdata",MeshDataImpl<$CT$>::_W_40);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","save",MeshDataImpl<$CT$>::_W_41);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","load",MeshDataImpl<$CT$>::_W_42);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","getDataPointer",MeshDataImpl<$CT$>::_W_43);
+>MeshDataImpl^int
+&static const Pb::Register _R_$IDX$ ("MeshDataImpl<int>","MdataInt","");
+>MeshDataImpl^Real
+&static const Pb::Register _R_$IDX$ ("MeshDataImpl<Real>","MdataReal","");
+>MeshDataImpl^Vec3
+&static const Pb::Register _R_$IDX$ ("MeshDataImpl<Vec3>","MdataVec3","");
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h.reg.cpp
new file mode 100644
index 00000000000..74b3935f01b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/mesh.h.reg.cpp
@@ -0,0 +1,233 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "mesh.h"
+namespace Manta {
+#ifdef _C_Mesh
+ static const Pb::Register _R_12 ("Mesh","Mesh","PbClass"); template<> const char* Namify<Mesh >::S = "Mesh";
+ static const Pb::Register _R_13 ("Mesh","Mesh",Mesh::_W_0);
+ static const Pb::Register _R_14 ("Mesh","clear",Mesh::_W_1);
+ static const Pb::Register _R_15 ("Mesh","load",Mesh::_W_2);
+ static const Pb::Register _R_16 ("Mesh","fromShape",Mesh::_W_3);
+ static const Pb::Register _R_17 ("Mesh","save",Mesh::_W_4);
+ static const Pb::Register _R_18 ("Mesh","advectInGrid",Mesh::_W_5);
+ static const Pb::Register _R_19 ("Mesh","scale",Mesh::_W_6);
+ static const Pb::Register _R_20 ("Mesh","offset",Mesh::_W_7);
+ static const Pb::Register _R_21 ("Mesh","rotate",Mesh::_W_8);
+ static const Pb::Register _R_22 ("Mesh","computeVelocity",Mesh::_W_9);
+ static const Pb::Register _R_23 ("Mesh","computeLevelset",Mesh::_W_10);
+ static const Pb::Register _R_24 ("Mesh","getLevelset",Mesh::_W_11);
+ static const Pb::Register _R_25 ("Mesh","applyMeshToGrid",Mesh::_W_12);
+ static const Pb::Register _R_26 ("Mesh","getNodesDataPointer",Mesh::_W_13);
+ static const Pb::Register _R_27 ("Mesh","getTrisDataPointer",Mesh::_W_14);
+ static const Pb::Register _R_28 ("Mesh","create",Mesh::_W_15);
+#endif
+#ifdef _C_MeshDataBase
+ static const Pb::Register _R_29 ("MeshDataBase","MeshDataBase","PbClass"); template<> const char* Namify<MeshDataBase >::S = "MeshDataBase";
+ static const Pb::Register _R_30 ("MeshDataBase","MeshDataBase",MeshDataBase::_W_16);
+#endif
+#ifdef _C_MeshDataImpl
+ static const Pb::Register _R_31 ("MeshDataImpl<int>","MeshDataImpl<int>","MeshDataBase"); template<> const char* Namify<MeshDataImpl<int> >::S = "MeshDataImpl<int>";
+ static const Pb::Register _R_32 ("MeshDataImpl<int>","MeshDataImpl",MeshDataImpl<int>::_W_17);
+ static const Pb::Register _R_33 ("MeshDataImpl<int>","clear",MeshDataImpl<int>::_W_18);
+ static const Pb::Register _R_34 ("MeshDataImpl<int>","setSource",MeshDataImpl<int>::_W_19);
+ static const Pb::Register _R_35 ("MeshDataImpl<int>","setConst",MeshDataImpl<int>::_W_20);
+ static const Pb::Register _R_36 ("MeshDataImpl<int>","setConstRange",MeshDataImpl<int>::_W_21);
+ static const Pb::Register _R_37 ("MeshDataImpl<int>","copyFrom",MeshDataImpl<int>::_W_22);
+ static const Pb::Register _R_38 ("MeshDataImpl<int>","add",MeshDataImpl<int>::_W_23);
+ static const Pb::Register _R_39 ("MeshDataImpl<int>","sub",MeshDataImpl<int>::_W_24);
+ static const Pb::Register _R_40 ("MeshDataImpl<int>","addConst",MeshDataImpl<int>::_W_25);
+ static const Pb::Register _R_41 ("MeshDataImpl<int>","addScaled",MeshDataImpl<int>::_W_26);
+ static const Pb::Register _R_42 ("MeshDataImpl<int>","mult",MeshDataImpl<int>::_W_27);
+ static const Pb::Register _R_43 ("MeshDataImpl<int>","multConst",MeshDataImpl<int>::_W_28);
+ static const Pb::Register _R_44 ("MeshDataImpl<int>","safeDiv",MeshDataImpl<int>::_W_29);
+ static const Pb::Register _R_45 ("MeshDataImpl<int>","clamp",MeshDataImpl<int>::_W_30);
+ static const Pb::Register _R_46 ("MeshDataImpl<int>","clampMin",MeshDataImpl<int>::_W_31);
+ static const Pb::Register _R_47 ("MeshDataImpl<int>","clampMax",MeshDataImpl<int>::_W_32);
+ static const Pb::Register _R_48 ("MeshDataImpl<int>","getMaxAbs",MeshDataImpl<int>::_W_33);
+ static const Pb::Register _R_49 ("MeshDataImpl<int>","getMax",MeshDataImpl<int>::_W_34);
+ static const Pb::Register _R_50 ("MeshDataImpl<int>","getMin",MeshDataImpl<int>::_W_35);
+ static const Pb::Register _R_51 ("MeshDataImpl<int>","sum",MeshDataImpl<int>::_W_36);
+ static const Pb::Register _R_52 ("MeshDataImpl<int>","sumSquare",MeshDataImpl<int>::_W_37);
+ static const Pb::Register _R_53 ("MeshDataImpl<int>","sumMagnitude",MeshDataImpl<int>::_W_38);
+ static const Pb::Register _R_54 ("MeshDataImpl<int>","setConstIntFlag",MeshDataImpl<int>::_W_39);
+ static const Pb::Register _R_55 ("MeshDataImpl<int>","printMdata",MeshDataImpl<int>::_W_40);
+ static const Pb::Register _R_56 ("MeshDataImpl<int>","save",MeshDataImpl<int>::_W_41);
+ static const Pb::Register _R_57 ("MeshDataImpl<int>","load",MeshDataImpl<int>::_W_42);
+ static const Pb::Register _R_58 ("MeshDataImpl<int>","getDataPointer",MeshDataImpl<int>::_W_43);
+ static const Pb::Register _R_59 ("MeshDataImpl<Real>","MeshDataImpl<Real>","MeshDataBase"); template<> const char* Namify<MeshDataImpl<Real> >::S = "MeshDataImpl<Real>";
+ static const Pb::Register _R_60 ("MeshDataImpl<Real>","MeshDataImpl",MeshDataImpl<Real>::_W_17);
+ static const Pb::Register _R_61 ("MeshDataImpl<Real>","clear",MeshDataImpl<Real>::_W_18);
+ static const Pb::Register _R_62 ("MeshDataImpl<Real>","setSource",MeshDataImpl<Real>::_W_19);
+ static const Pb::Register _R_63 ("MeshDataImpl<Real>","setConst",MeshDataImpl<Real>::_W_20);
+ static const Pb::Register _R_64 ("MeshDataImpl<Real>","setConstRange",MeshDataImpl<Real>::_W_21);
+ static const Pb::Register _R_65 ("MeshDataImpl<Real>","copyFrom",MeshDataImpl<Real>::_W_22);
+ static const Pb::Register _R_66 ("MeshDataImpl<Real>","add",MeshDataImpl<Real>::_W_23);
+ static const Pb::Register _R_67 ("MeshDataImpl<Real>","sub",MeshDataImpl<Real>::_W_24);
+ static const Pb::Register _R_68 ("MeshDataImpl<Real>","addConst",MeshDataImpl<Real>::_W_25);
+ static const Pb::Register _R_69 ("MeshDataImpl<Real>","addScaled",MeshDataImpl<Real>::_W_26);
+ static const Pb::Register _R_70 ("MeshDataImpl<Real>","mult",MeshDataImpl<Real>::_W_27);
+ static const Pb::Register _R_71 ("MeshDataImpl<Real>","multConst",MeshDataImpl<Real>::_W_28);
+ static const Pb::Register _R_72 ("MeshDataImpl<Real>","safeDiv",MeshDataImpl<Real>::_W_29);
+ static const Pb::Register _R_73 ("MeshDataImpl<Real>","clamp",MeshDataImpl<Real>::_W_30);
+ static const Pb::Register _R_74 ("MeshDataImpl<Real>","clampMin",MeshDataImpl<Real>::_W_31);
+ static const Pb::Register _R_75 ("MeshDataImpl<Real>","clampMax",MeshDataImpl<Real>::_W_32);
+ static const Pb::Register _R_76 ("MeshDataImpl<Real>","getMaxAbs",MeshDataImpl<Real>::_W_33);
+ static const Pb::Register _R_77 ("MeshDataImpl<Real>","getMax",MeshDataImpl<Real>::_W_34);
+ static const Pb::Register _R_78 ("MeshDataImpl<Real>","getMin",MeshDataImpl<Real>::_W_35);
+ static const Pb::Register _R_79 ("MeshDataImpl<Real>","sum",MeshDataImpl<Real>::_W_36);
+ static const Pb::Register _R_80 ("MeshDataImpl<Real>","sumSquare",MeshDataImpl<Real>::_W_37);
+ static const Pb::Register _R_81 ("MeshDataImpl<Real>","sumMagnitude",MeshDataImpl<Real>::_W_38);
+ static const Pb::Register _R_82 ("MeshDataImpl<Real>","setConstIntFlag",MeshDataImpl<Real>::_W_39);
+ static const Pb::Register _R_83 ("MeshDataImpl<Real>","printMdata",MeshDataImpl<Real>::_W_40);
+ static const Pb::Register _R_84 ("MeshDataImpl<Real>","save",MeshDataImpl<Real>::_W_41);
+ static const Pb::Register _R_85 ("MeshDataImpl<Real>","load",MeshDataImpl<Real>::_W_42);
+ static const Pb::Register _R_86 ("MeshDataImpl<Real>","getDataPointer",MeshDataImpl<Real>::_W_43);
+ static const Pb::Register _R_87 ("MeshDataImpl<Vec3>","MeshDataImpl<Vec3>","MeshDataBase"); template<> const char* Namify<MeshDataImpl<Vec3> >::S = "MeshDataImpl<Vec3>";
+ static const Pb::Register _R_88 ("MeshDataImpl<Vec3>","MeshDataImpl",MeshDataImpl<Vec3>::_W_17);
+ static const Pb::Register _R_89 ("MeshDataImpl<Vec3>","clear",MeshDataImpl<Vec3>::_W_18);
+ static const Pb::Register _R_90 ("MeshDataImpl<Vec3>","setSource",MeshDataImpl<Vec3>::_W_19);
+ static const Pb::Register _R_91 ("MeshDataImpl<Vec3>","setConst",MeshDataImpl<Vec3>::_W_20);
+ static const Pb::Register _R_92 ("MeshDataImpl<Vec3>","setConstRange",MeshDataImpl<Vec3>::_W_21);
+ static const Pb::Register _R_93 ("MeshDataImpl<Vec3>","copyFrom",MeshDataImpl<Vec3>::_W_22);
+ static const Pb::Register _R_94 ("MeshDataImpl<Vec3>","add",MeshDataImpl<Vec3>::_W_23);
+ static const Pb::Register _R_95 ("MeshDataImpl<Vec3>","sub",MeshDataImpl<Vec3>::_W_24);
+ static const Pb::Register _R_96 ("MeshDataImpl<Vec3>","addConst",MeshDataImpl<Vec3>::_W_25);
+ static const Pb::Register _R_97 ("MeshDataImpl<Vec3>","addScaled",MeshDataImpl<Vec3>::_W_26);
+ static const Pb::Register _R_98 ("MeshDataImpl<Vec3>","mult",MeshDataImpl<Vec3>::_W_27);
+ static const Pb::Register _R_99 ("MeshDataImpl<Vec3>","multConst",MeshDataImpl<Vec3>::_W_28);
+ static const Pb::Register _R_100 ("MeshDataImpl<Vec3>","safeDiv",MeshDataImpl<Vec3>::_W_29);
+ static const Pb::Register _R_101 ("MeshDataImpl<Vec3>","clamp",MeshDataImpl<Vec3>::_W_30);
+ static const Pb::Register _R_102 ("MeshDataImpl<Vec3>","clampMin",MeshDataImpl<Vec3>::_W_31);
+ static const Pb::Register _R_103 ("MeshDataImpl<Vec3>","clampMax",MeshDataImpl<Vec3>::_W_32);
+ static const Pb::Register _R_104 ("MeshDataImpl<Vec3>","getMaxAbs",MeshDataImpl<Vec3>::_W_33);
+ static const Pb::Register _R_105 ("MeshDataImpl<Vec3>","getMax",MeshDataImpl<Vec3>::_W_34);
+ static const Pb::Register _R_106 ("MeshDataImpl<Vec3>","getMin",MeshDataImpl<Vec3>::_W_35);
+ static const Pb::Register _R_107 ("MeshDataImpl<Vec3>","sum",MeshDataImpl<Vec3>::_W_36);
+ static const Pb::Register _R_108 ("MeshDataImpl<Vec3>","sumSquare",MeshDataImpl<Vec3>::_W_37);
+ static const Pb::Register _R_109 ("MeshDataImpl<Vec3>","sumMagnitude",MeshDataImpl<Vec3>::_W_38);
+ static const Pb::Register _R_110 ("MeshDataImpl<Vec3>","setConstIntFlag",MeshDataImpl<Vec3>::_W_39);
+ static const Pb::Register _R_111 ("MeshDataImpl<Vec3>","printMdata",MeshDataImpl<Vec3>::_W_40);
+ static const Pb::Register _R_112 ("MeshDataImpl<Vec3>","save",MeshDataImpl<Vec3>::_W_41);
+ static const Pb::Register _R_113 ("MeshDataImpl<Vec3>","load",MeshDataImpl<Vec3>::_W_42);
+ static const Pb::Register _R_114 ("MeshDataImpl<Vec3>","getDataPointer",MeshDataImpl<Vec3>::_W_43);
+#endif
+static const Pb::Register _R_9 ("MeshDataImpl<int>","MdataInt","");
+static const Pb::Register _R_10 ("MeshDataImpl<Real>","MdataReal","");
+static const Pb::Register _R_11 ("MeshDataImpl<Vec3>","MdataVec3","");
+extern "C" {
+void PbRegister_file_9()
+{
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+ KEEP_UNUSED(_R_101);
+ KEEP_UNUSED(_R_102);
+ KEEP_UNUSED(_R_103);
+ KEEP_UNUSED(_R_104);
+ KEEP_UNUSED(_R_105);
+ KEEP_UNUSED(_R_106);
+ KEEP_UNUSED(_R_107);
+ KEEP_UNUSED(_R_108);
+ KEEP_UNUSED(_R_109);
+ KEEP_UNUSED(_R_110);
+ KEEP_UNUSED(_R_111);
+ KEEP_UNUSED(_R_112);
+ KEEP_UNUSED(_R_113);
+ KEEP_UNUSED(_R_114);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.cpp
new file mode 100644
index 00000000000..0dbd165cb50
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.cpp
@@ -0,0 +1,109 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Moving obstacles
+ *
+ ******************************************************************************/
+
+#include "movingobs.h"
+#include "commonkernels.h"
+#include "randomstream.h"
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// MovingObs class members
+
+int MovingObstacle::sIDcnt = 10;
+
+MovingObstacle::MovingObstacle (FluidSolver* parent, int emptyType)
+ : PbClass(parent), mEmptyType(emptyType)
+{
+ mID = 1<<sIDcnt;
+ sIDcnt++;
+ if (sIDcnt > 15)
+ errMsg ("currently only 5 separate moving obstacles supported (are you generating them in a loop?)");
+}
+
+void MovingObstacle::add(Shape* shape) {
+ mShapes.push_back(shape);
+}
+
+void MovingObstacle::projectOutside(FlagGrid& flags, BasicParticleSystem& parts) {
+ LevelsetGrid levelset(mParent,false);
+ Grid<Vec3> gradient(mParent);
+
+ // rebuild obstacle levelset
+ FOR_IDX(levelset) {
+ levelset[idx] = flags.isObstacle(idx) ? -0.5 : 0.5;
+ }
+ levelset.reinitMarching(flags, 6.0, 0, true, false, FlagGrid::TypeReserved);
+
+ // build levelset gradient
+ GradientOp(gradient, levelset);
+
+ parts.projectOutside(gradient);
+}
+
+void MovingObstacle::moveLinear(Real t, Real t0, Real t1, Vec3 p0, Vec3 p1, FlagGrid& flags, MACGrid& vel, bool smooth) {
+ Real alpha = (t-t0)/(t1-t0);
+ if (alpha >= 0 && alpha <= 1) {
+ Vec3 v = (p1-p0) / ((t1-t0)* getParent()->getDt() );
+
+ // ease in and out
+ if (smooth) {
+ v *= 6.0f*(alpha-square(alpha));
+ alpha = square(alpha)*(3.0f-2.0f*alpha);
+ }
+
+ Vec3 pos = alpha * p1 + (1.0f-alpha) * p0;
+ for (size_t i=0; i<mShapes.size(); i++)
+ mShapes[i]->setCenter(pos);
+
+ // reset flags
+ FOR_IDX(flags) {
+ if ((flags[idx] & mID) != 0)
+ flags[idx] = mEmptyType;
+ }
+ // apply new flags
+ for (size_t i=0; i<mShapes.size(); i++) {
+# if NOPYTHON!=1
+ mShapes[i]->_args.clear();
+ mShapes[i]->_args.add("value", FlagGrid::TypeObstacle | mID);
+ mShapes[i]->applyToGrid(&flags, 0);
+# else
+ errMsg("Not yet supported...");
+# endif
+ }
+ // apply velocities
+ FOR_IJK_BND(flags,1) {
+ bool cur = (flags(i,j,k) & mID) != 0;
+ if (cur || (flags(i-1,j,k) & mID) != 0) vel(i,j,k).x = v.x;
+ if (cur || (flags(i,j-1,k) & mID) != 0) vel(i,j,k).y = v.y;
+ if (cur || (flags(i,j,k-1) & mID) != 0) vel(i,j,k).z = v.z;
+ }
+ }
+}
+
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h
new file mode 100644
index 00000000000..c1bac5905ab
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h
@@ -0,0 +1,86 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * moving obstacles
+ *
+ ******************************************************************************/
+
+#ifndef _MOVINGOBS_H
+#define _MOVINGOBS_H
+
+#include "shapes.h"
+#include "particle.h"
+
+namespace Manta {
+
+//! Moving obstacle composed of basic shapes
+class MovingObstacle : public PbClass {public:
+ MovingObstacle(FluidSolver* parent, int emptyType=FlagGrid::TypeEmpty); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "MovingObstacle::MovingObstacle" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); int emptyType = _args.getOpt<int >("emptyType",1,FlagGrid::TypeEmpty,&_lock); obj = new MovingObstacle(parent,emptyType); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"MovingObstacle::MovingObstacle" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("MovingObstacle::MovingObstacle",e.what()); return -1; }
+ }
+
+
+ void add(Shape* shape); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MovingObstacle* pbo = dynamic_cast<MovingObstacle*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MovingObstacle::add" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Shape* shape = _args.getPtr<Shape >("shape",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->add(shape); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MovingObstacle::add" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MovingObstacle::add",e.what()); return 0; }
+ }
+
+ //! If t in [t0,t1], apply linear motion path from p0 to p1
+ void moveLinear(Real t, Real t0, Real t1, Vec3 p0, Vec3 p1, FlagGrid& flags, MACGrid& vel, bool smooth=true); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MovingObstacle* pbo = dynamic_cast<MovingObstacle*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MovingObstacle::moveLinear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real t = _args.get<Real >("t",0,&_lock); Real t0 = _args.get<Real >("t0",1,&_lock); Real t1 = _args.get<Real >("t1",2,&_lock); Vec3 p0 = _args.get<Vec3 >("p0",3,&_lock); Vec3 p1 = _args.get<Vec3 >("p1",4,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",5,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",6,&_lock); bool smooth = _args.getOpt<bool >("smooth",7,true,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->moveLinear(t,t0,t1,p0,p1,flags,vel,smooth); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MovingObstacle::moveLinear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MovingObstacle::moveLinear",e.what()); return 0; }
+ }
+
+ //! Compute levelset, and project FLIP particles outside obstacles
+ void projectOutside(FlagGrid& flags, BasicParticleSystem& flip); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MovingObstacle* pbo = dynamic_cast<MovingObstacle*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MovingObstacle::projectOutside" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); BasicParticleSystem& flip = *_args.getPtr<BasicParticleSystem >("flip",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->projectOutside(flags,flip); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MovingObstacle::projectOutside" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MovingObstacle::projectOutside",e.what()); return 0; }
+ }
+
+
+protected:
+ std::vector<Shape*> mShapes;
+ int mEmptyType;
+ int mID; static int sIDcnt; public: PbArgs _args; }
+#define _C_MovingObstacle
+;
+
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h.reg
new file mode 100644
index 00000000000..7c95949a6de
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h.reg
@@ -0,0 +1,7 @@
+#include "movingobs.h"
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","MovingObstacle","PbClass"); template<> const char* Namify<MovingObstacle >::S = "MovingObstacle";
+>MovingObstacle^
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","MovingObstacle",MovingObstacle::_W_0);
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","add",MovingObstacle::_W_1);
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","moveLinear",MovingObstacle::_W_2);
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","projectOutside",MovingObstacle::_W_3);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h.reg.cpp
new file mode 100644
index 00000000000..25a8528c7e5
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/movingobs.h.reg.cpp
@@ -0,0 +1,30 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "movingobs.h"
+namespace Manta {
+#ifdef _C_MovingObstacle
+ static const Pb::Register _R_17 ("MovingObstacle","MovingObstacle","PbClass"); template<> const char* Namify<MovingObstacle >::S = "MovingObstacle";
+ static const Pb::Register _R_18 ("MovingObstacle","MovingObstacle",MovingObstacle::_W_0);
+ static const Pb::Register _R_19 ("MovingObstacle","add",MovingObstacle::_W_1);
+ static const Pb::Register _R_20 ("MovingObstacle","moveLinear",MovingObstacle::_W_2);
+ static const Pb::Register _R_21 ("MovingObstacle","projectOutside",MovingObstacle::_W_3);
+#endif
+extern "C" {
+void PbRegister_file_17()
+{
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.cpp
new file mode 100644
index 00000000000..f42df9b8d28
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.cpp
@@ -0,0 +1,1250 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Multigrid solver
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Copyright 2016, by Florian Ferstl (florian.ferstl.ff@gmail.com)
+ *
+ * This is an implementation of the solver developed by Dick et al. [1]
+ * without topology awareness (= vertex duplication on coarser levels). This
+ * simplification allows us to use regular grids for all levels of the multigrid
+ * hierarchy and works well for moderately complex domains.
+ *
+ * [1] Solving the Fluid Pressure Poisson Equation Using Multigrid-Evaluation
+ * and Improvements, C. Dick, M. Rogowsky, R. Westermann, IEEE TVCG 2015
+ *
+ ******************************************************************************/
+
+#include "multigrid.h"
+
+#define FOR_LVL(IDX,LVL) \
+ for(int IDX=0; IDX<mb[LVL].size(); IDX++)
+
+#define FOR_VEC_MINMAX(VEC,MIN,MAX) Vec3i VEC; \
+ const Vec3i VEC##__min = (MIN), VEC##__max = (MAX); \
+ for(VEC.z=VEC##__min.z; VEC.z<=VEC##__max.z; VEC.z++) \
+ for(VEC.y=VEC##__min.y; VEC.y<=VEC##__max.y; VEC.y++) \
+ for(VEC.x=VEC##__min.x; VEC.x<=VEC##__max.x; VEC.x++)
+
+#define FOR_VECLIN_MINMAX(VEC,LIN,MIN,MAX) Vec3i VEC; int LIN = 0; \
+ const Vec3i VEC##__min = (MIN), VEC##__max = (MAX); \
+ for(VEC.z=VEC##__min.z; VEC.z<=VEC##__max.z; VEC.z++) \
+ for(VEC.y=VEC##__min.y; VEC.y<=VEC##__max.y; VEC.y++) \
+ for(VEC.x=VEC##__min.x; VEC.x<=VEC##__max.x; VEC.x++, LIN++)
+
+#define MG_TIMINGS(X)
+//#define MG_TIMINGS(X) X
+
+using namespace std;
+namespace Manta
+{
+
+// Helper class for calling mantaflow kernels with a specific number of threads
+class ThreadSize {
+ IndexInt s;
+public:
+ ThreadSize(IndexInt _s) {s=_s;}
+ IndexInt size() { return s; }
+};
+
+// ----------------------------------------------------------------------------
+// Efficient min heap for <ID, key> pairs with 0<=ID<N and 0<=key<K
+// (elements are stored in K buckets, where each bucket is a doubly linked list).
+// - if K<<N, all ops are O(1) on avg (worst case O(K)).
+// - memory usage O(K+N): (K+N) * 3 * sizeof(int).
+class NKMinHeap
+{
+private:
+ struct Entry {
+ int key, prev, next;
+ Entry() : key(-1), prev(-1), next(-1) {}
+ };
+
+ int mN, mK, mSize, mMinKey;
+
+ // Double linked lists of IDs, one for each bucket/key.
+ // The first K entries are the buckets' head pointers,
+ // and the last N entries correspond to the IDs.
+ std::vector<Entry> mEntries;
+
+public:
+ NKMinHeap(int N, int K) : mN(N), mK(K), mSize(0), mMinKey(-1), mEntries(N+K) {}
+
+ int size() { return mSize; }
+ int getKey(int ID) { return mEntries[mK+ID].key; }
+
+ // Insert, decrease or increase key (or delete by setting key to -1)
+ void setKey(int ID, int key);
+
+ // peek min key (returns ID/key pair)
+ std::pair<int,int> peekMin();
+
+ // pop min key (returns ID/key pair)
+ std::pair<int,int> popMin();
+
+ void print(); // for debugging
+};
+
+void NKMinHeap::setKey(int ID, int key)
+{
+ assertMsg(0 <=ID && ID <mN, "NKMinHeap::setKey: ID out of range");
+ assertMsg(-1<=key && key<mK, "NKMinHeap::setKey: key out of range");
+
+ const int kid = mK + ID;
+
+ if (mEntries[kid].key == key) return; // nothing changes
+
+ // remove from old key-list if ID existed previously
+ if (mEntries[kid].key != -1)
+ {
+ int pred = mEntries[kid].prev;
+ int succ = mEntries[kid].next; // can be -1
+
+ mEntries[pred].next = succ;
+ if (succ != -1) mEntries[succ].prev = pred;
+
+ // if removed key was minimum key, mMinKey may need to be updated
+ int removedKey = mEntries[kid].key;
+ if (removedKey==mMinKey)
+ {
+ if (mSize==1) { mMinKey = -1; }
+ else {
+ for (; mMinKey<mK; mMinKey++) {
+ if (mEntries[mMinKey].next != -1) break;
+ }
+ }
+ }
+
+ mSize--;
+ }
+
+ // set new key of ID
+ mEntries[kid].key = key;
+
+ if (key==-1) {
+ // finished if key was set to -1
+ mEntries[kid].next = mEntries[kid].prev = -1;
+ return;
+ }
+
+ // add key
+ mSize++;
+ if (mMinKey == -1) mMinKey = key;
+ else mMinKey = std::min(mMinKey, key);
+
+ // insert into new key-list (headed by mEntries[key])
+ int tmp = mEntries[key].next;
+
+ mEntries[key].next = kid;
+ mEntries[kid].prev = key;
+
+ mEntries[kid].next = tmp;
+ if (tmp != -1) mEntries[tmp].prev = kid;
+}
+
+std::pair<int,int> NKMinHeap::peekMin()
+{
+ if (mSize==0) return std::pair<int,int>(-1,-1); // error
+
+ const int ID = mEntries[mMinKey].next - mK;
+ return std::pair<int,int>(ID, mMinKey);
+}
+
+std::pair<int,int> NKMinHeap::popMin()
+{
+ if (mSize==0) return std::pair<int,int>(-1,-1); // error
+
+ const int kid = mEntries[mMinKey].next;
+ const int ID = kid - mK;
+ const int key = mMinKey;
+
+ // remove from key-list
+ int pred = mEntries[kid].prev;
+ int succ = mEntries[kid].next; // can be -1
+
+ mEntries[pred].next = succ;
+ if (succ != -1) mEntries[succ].prev = pred;
+
+ // remove entry
+ mEntries[kid] = Entry();
+ mSize--;
+
+ // update mMinKey
+ if (mSize==0) { mMinKey = -1; }
+ else {
+ for (; mMinKey<mK; mMinKey++) {
+ if (mEntries[mMinKey].next != -1) break;
+ }
+ }
+
+ // return result
+ return std::pair<int,int>(ID, key);
+}
+
+void NKMinHeap::print()
+{
+ std::cout << "Size: "<<mSize<<", MinKey: "<<mMinKey<< std::endl;
+ for (int key=0; key<mK; key++) {
+ if (mEntries[key].next != -1) {
+ std::cout << "Key "<<key<<": ";
+ int kid = mEntries[key].next;
+ while (kid != -1) {
+ std::cout << kid-mK<<" ";
+ kid = mEntries[kid].next;
+ }
+ std::cout << std::endl;
+ }
+ }
+ std::cout << std::endl;
+}
+
+// ----------------------------------------------------------------------------
+// GridMg methods
+//
+// Illustration of 27-point stencil indices
+// y | z = -1 z = 0 z = 1
+// ^ | 6 7 8, 15 16 17, 24 25 26
+// | | 3 4 5, 12 13 14, 21 22 23
+// o-> x | 0 1 2, 9 10 11, 18 19 20
+//
+// Symmetric storage with only 14 entries per vertex
+// y | z = -1 z = 0 z = 1
+// ^ | - - -, 2 3 4, 11 12 13
+// | | - - -, - 0 1, 8 9 10
+// o-> x | - - -, - - -, 5 6 7
+
+GridMg::GridMg(const Vec3i& gridSize)
+ : mNumPreSmooth(1),
+ mNumPostSmooth(1),
+ mCoarsestLevelAccuracy(Real(1E-8)),
+ mTrivialEquationScale(Real(1E-6)),
+ mIsASet(false),
+ mIsRhsSet(false)
+{
+ MG_TIMINGS(MuTime time;)
+
+ // 2D or 3D mode
+ mIs3D = (gridSize.z > 1);
+ mDim = mIs3D ? 3 : 2;
+ mStencilSize = mIs3D ? 14 : 5; // A has a full 27-point stencil on levels > 0
+ mStencilSize0 = mIs3D ? 4 : 3; // A has a 7-point stencil on level 0
+ mStencilMin = Vec3i(-1,-1, mIs3D ? -1:0);
+ mStencilMax = Vec3i( 1, 1, mIs3D ? 1:0);
+
+ // Create level 0 (=original grid)
+ mSize.push_back(gridSize);
+ mPitch.push_back(Vec3i(1, mSize.back().x, mSize.back().x*mSize.back().y));
+ int n = mSize.back().x * mSize.back().y * mSize.back().z;
+
+ mA.push_back(std::vector<Real>(n * mStencilSize0));
+ mx.push_back(std::vector<Real>(n));
+ mb.push_back(std::vector<Real>(n));
+ mr.push_back(std::vector<Real>(n));
+ mType.push_back(std::vector<VertexType>(n));
+ mCGtmp1.push_back(std::vector<double>());
+ mCGtmp2.push_back(std::vector<double>());
+ mCGtmp3.push_back(std::vector<double>());
+ mCGtmp4.push_back(std::vector<double>());
+
+ debMsg("GridMg::GridMg level 0: "<<mSize[0].x<<" x " << mSize[0].y << " x " << mSize[0].z << " x ", 2);
+
+ // Create coarse levels >0
+ for (int l=1; l<=100; l++)
+ {
+ if (mSize[l-1].x <= 5 && mSize[l-1].y <= 5 && mSize[l-1].z <= 5) break;
+ if (n <= 1000) break;
+
+ mSize.push_back((mSize[l-1] + 2) / 2);
+ mPitch.push_back(Vec3i(1, mSize.back().x, mSize.back().x*mSize.back().y));
+ n = mSize.back().x * mSize.back().y * mSize.back().z;
+
+ mA.push_back(std::vector<Real>(n * mStencilSize));
+ mx.push_back(std::vector<Real>(n));
+ mb.push_back(std::vector<Real>(n));
+ mr.push_back(std::vector<Real>(n));
+ mType.push_back(std::vector<VertexType>(n));
+ mCGtmp1.push_back(std::vector<double>());
+ mCGtmp2.push_back(std::vector<double>());
+ mCGtmp3.push_back(std::vector<double>());
+ mCGtmp4.push_back(std::vector<double>());
+
+ debMsg("GridMg::GridMg level "<<l<<": " << mSize[l].x << " x " << mSize[l].y << " x " << mSize[l].z << " x ", 2);
+ }
+
+ // Additional memory for CG on coarsest level
+ mCGtmp1.back() = std::vector<double>(n);
+ mCGtmp2.back() = std::vector<double>(n);
+ mCGtmp3.back() = std::vector<double>(n);
+ mCGtmp4.back() = std::vector<double>(n);
+
+ MG_TIMINGS(debMsg("GridMg: Allocation done in "<<time.update(), 1);)
+
+ // Precalculate coarsening paths:
+ // (V) <--restriction-- (U) <--A_{l-1}-- (W) <--interpolation-- (N)
+ Vec3i p7stencil[7] = { Vec3i(0,0,0), Vec3i(-1, 0, 0), Vec3i(1,0,0),
+ Vec3i( 0,-1, 0), Vec3i(0,1,0),
+ Vec3i( 0, 0,-1), Vec3i(0,0,1) };
+ Vec3i V (1,1,1); // reference coarse grid vertex at (1,1,1)
+ FOR_VEC_MINMAX(U, V*2+mStencilMin, V*2+mStencilMax) {
+ for (int i=0; i<1+2*mDim; i++) {
+ Vec3i W = U + p7stencil[i];
+ FOR_VEC_MINMAX(N, W/2, (W+1)/2) {
+ int s = dot(N,Vec3i(1,3,9));
+
+ if (s>=13) {
+ CoarseningPath path;
+ path.N = N-1; // offset of N on coarse grid
+ path.U = U-V*2; // offset of U on fine grid
+ path.W = W-V*2; // offset of W on fine grid
+ path.sc = s-13; // stencil index corresponding to V<-N on coarse grid
+ path.sf = (i+1)/2; // stencil index corresponding to U<-W on coarse grid
+ path.inUStencil = (i%2==0); // fine grid stencil entry stored at U or W?
+ path.rw = Real(1) / Real(1 << ((U.x % 2) + (U.y % 2) + (U.z % 2))); // restriction weight V<-U
+ path.iw = Real(1) / Real(1 << ((W.x % 2) + (W.y % 2) + (W.z % 2))); // interpolation weight W<-N
+ mCoarseningPaths0.push_back(path);
+ }
+ }
+ }
+ }
+
+ auto pathLess = [](const GridMg::CoarseningPath& p1, const GridMg::CoarseningPath& p2) {
+ if (p1.sc == p2.sc) return dot(p1.U+1,Vec3i(1,3,9)) < dot(p2.U+1,Vec3i(1,3,9));
+ return p1.sc < p2.sc;
+ };
+ std::sort(mCoarseningPaths0.begin(), mCoarseningPaths0.end(), pathLess);
+}
+
+void GridMg::analyzeStencil(int v, bool is3D, bool& isStencilSumNonZero, bool& isEquationTrivial) const {
+ Vec3i V = vecIdx(v,0);
+
+ // collect stencil entries
+ Real A[7];
+ A[0] = mA[0][v*mStencilSize0 + 0];
+ A[1] = mA[0][v*mStencilSize0 + 1];
+ A[2] = mA[0][v*mStencilSize0 + 2];
+ A[3] = is3D ? mA[0][v*mStencilSize0 + 3] : Real(0);
+ A[4] = V.x!=0 ? mA[0][(v-mPitch[0].x)*mStencilSize0 + 1] : Real(0);
+ A[5] = V.y!=0 ? mA[0][(v-mPitch[0].y)*mStencilSize0 + 2] : Real(0);
+ A[6] = V.z!=0 && is3D ? mA[0][(v-mPitch[0].z)*mStencilSize0 + 3] : Real(0);
+
+ // compute sum of stencil entries
+ Real stencilMax = Real(0), stencilSum = Real(0);
+ for (int i=0; i<7; i++) {
+ stencilSum += A[i];
+ stencilMax = max(stencilMax, std::abs(A[i]));
+ }
+
+ // check if sum is numerically zero
+ isStencilSumNonZero = std::abs(stencilSum / stencilMax) > Real(1E-6);
+
+ // check for trivial equation (exact comparisons)
+ isEquationTrivial = A[0]==Real(1)
+ && A[1]==Real(0) && A[2]==Real(0) && A[3]==Real(0)
+ && A[4]==Real(0) && A[5]==Real(0) && A[6]==Real(0);
+}
+
+
+
+
+ struct knCopyA : public KernelBase {
+ knCopyA(std::vector<Real>& sizeRef, std::vector<Real>& A0, int stencilSize0, bool is3D, const Grid<Real>* pA0, const Grid<Real>* pAi, const Grid<Real>* pAj, const Grid<Real>* pAk) : KernelBase(sizeRef.size()) ,sizeRef(sizeRef),A0(A0),stencilSize0(stencilSize0),is3D(is3D),pA0(pA0),pAi(pAi),pAj(pAj),pAk(pAk) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& sizeRef, std::vector<Real>& A0, int stencilSize0, bool is3D, const Grid<Real>* pA0, const Grid<Real>* pAi, const Grid<Real>* pAj, const Grid<Real>* pAk ) {
+ A0[idx*stencilSize0 + 0] = (*pA0)[idx];
+ A0[idx*stencilSize0 + 1] = (*pAi)[idx];
+ A0[idx*stencilSize0 + 2] = (*pAj)[idx];
+ if (is3D) A0[idx*stencilSize0 + 3] = (*pAk)[idx];
+} inline std::vector<Real>& getArg0() {
+ return sizeRef; }
+ typedef std::vector<Real> type0;inline std::vector<Real>& getArg1() {
+ return A0; }
+ typedef std::vector<Real> type1;inline int& getArg2() {
+ return stencilSize0; }
+ typedef int type2;inline bool& getArg3() {
+ return is3D; }
+ typedef bool type3;inline const Grid<Real>* getArg4() {
+ return pA0; }
+ typedef Grid<Real> type4;inline const Grid<Real>* getArg5() {
+ return pAi; }
+ typedef Grid<Real> type5;inline const Grid<Real>* getArg6() {
+ return pAj; }
+ typedef Grid<Real> type6;inline const Grid<Real>* getArg7() {
+ return pAk; }
+ typedef Grid<Real> type7; void runMessage() { debMsg("Executing kernel knCopyA ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,sizeRef,A0,stencilSize0,is3D,pA0,pAi,pAj,pAk); }
+ }
+ std::vector<Real>& sizeRef; std::vector<Real>& A0; int stencilSize0; bool is3D; const Grid<Real>* pA0; const Grid<Real>* pAi; const Grid<Real>* pAj; const Grid<Real>* pAk; }
+;
+
+
+
+
+ struct knActivateVertices : public KernelBase {
+ knActivateVertices(std::vector<GridMg::VertexType>& type_0, std::vector<Real>& A0, bool& nonZeroStencilSumFound, bool& trivialEquationsFound, const GridMg& mg) : KernelBase(type_0.size()) ,type_0(type_0),A0(A0),nonZeroStencilSumFound(nonZeroStencilSumFound),trivialEquationsFound(trivialEquationsFound),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<GridMg::VertexType>& type_0, std::vector<Real>& A0, bool& nonZeroStencilSumFound, bool& trivialEquationsFound, const GridMg& mg ) {
+ // active vertices on level 0 are vertices with non-zero diagonal entry in A
+ type_0[idx] = GridMg::vtInactive;
+
+ if (mg.mA[0][idx*mg.mStencilSize0 + 0] != Real(0)) {
+ type_0[idx] = GridMg::vtActive;
+
+ bool isStencilSumNonZero = false, isEquationTrivial = false;
+ mg.analyzeStencil(int(idx), mg.mIs3D, isStencilSumNonZero, isEquationTrivial);
+
+ // Note: nonZeroStencilSumFound and trivialEquationsFound are only
+ // changed from false to true, and hence there are no race conditions.
+ if (isStencilSumNonZero) nonZeroStencilSumFound = true;
+
+ // scale down trivial equations
+ if (isEquationTrivial) {
+ type_0[idx] = GridMg::vtActiveTrivial;
+ A0[idx*mg.mStencilSize0 + 0] *= mg.mTrivialEquationScale;
+ trivialEquationsFound = true;
+ };
+ }
+} inline std::vector<GridMg::VertexType>& getArg0() {
+ return type_0; }
+ typedef std::vector<GridMg::VertexType> type0;inline std::vector<Real>& getArg1() {
+ return A0; }
+ typedef std::vector<Real> type1;inline bool& getArg2() {
+ return nonZeroStencilSumFound; }
+ typedef bool type2;inline bool& getArg3() {
+ return trivialEquationsFound; }
+ typedef bool type3;inline const GridMg& getArg4() {
+ return mg; }
+ typedef GridMg type4; void runMessage() { debMsg("Executing kernel knActivateVertices ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,type_0,A0,nonZeroStencilSumFound,trivialEquationsFound,mg); }
+ }
+ std::vector<GridMg::VertexType>& type_0; std::vector<Real>& A0; bool& nonZeroStencilSumFound; bool& trivialEquationsFound; const GridMg& mg; }
+;
+
+void GridMg::setA(const Grid<Real>* pA0, const Grid<Real>* pAi, const Grid<Real>* pAj, const Grid<Real>* pAk)
+{
+ MG_TIMINGS(MuTime time;)
+
+ // Copy level 0
+ knCopyA(mx[0], mA[0], mStencilSize0, mIs3D, pA0, pAi, pAj, pAk);
+
+ // Determine active vertices and scale trivial equations
+ bool nonZeroStencilSumFound = false;
+ bool trivialEquationsFound = false;
+
+ knActivateVertices(mType[0], mA[0], nonZeroStencilSumFound, trivialEquationsFound, *this);
+
+ if (trivialEquationsFound) debMsg("GridMg::setA: Found at least one trivial equation", 2);
+
+ // Sanity check: if all rows of A sum up to 0 --> A doesn't have full rank (opposite direction isn't necessarily true)
+ if (!nonZeroStencilSumFound) debMsg("GridMg::setA: Found constant mode: A*1=0! A does not have full rank and multigrid may not converge. (forgot to fix a pressure value?)", 1);
+
+ // Create coarse grids and operators on levels >0
+ for (int l=1; l<mA.size(); l++) {
+ MG_TIMINGS(time.get();)
+ genCoarseGrid(l);
+ MG_TIMINGS(debMsg("GridMg: Generated level "<<l<<" in "<<time.update(), 1);)
+ genCoraseGridOperator(l);
+ MG_TIMINGS(debMsg("GridMg: Generated operator "<<l<<" in "<<time.update(), 1);)
+ }
+
+ mIsASet = true;
+ mIsRhsSet = false; // invalidate rhs
+}
+
+
+
+ struct knSetRhs : public KernelBase {
+ knSetRhs(std::vector<Real>& b, const Grid<Real>& rhs, const GridMg& mg) : KernelBase(b.size()) ,b(b),rhs(rhs),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& b, const Grid<Real>& rhs, const GridMg& mg ) {
+ b[idx] = rhs[idx];
+
+ // scale down trivial equations
+ if (mg.mType[0][idx] == GridMg::vtActiveTrivial) { b[idx] *= mg.mTrivialEquationScale; };
+} inline std::vector<Real>& getArg0() {
+ return b; }
+ typedef std::vector<Real> type0;inline const Grid<Real>& getArg1() {
+ return rhs; }
+ typedef Grid<Real> type1;inline const GridMg& getArg2() {
+ return mg; }
+ typedef GridMg type2; void runMessage() { debMsg("Executing kernel knSetRhs ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,b,rhs,mg); }
+ }
+ std::vector<Real>& b; const Grid<Real>& rhs; const GridMg& mg; }
+;
+
+void GridMg::setRhs(const Grid<Real>& rhs)
+{
+ assertMsg(mIsASet, "GridMg::setRhs Error: A has not been set.");
+
+ knSetRhs(mb[0], rhs, *this);
+
+ mIsRhsSet = true;
+}
+
+
+
+template <class T> struct knSet : public KernelBase {
+ knSet(std::vector<T>& data, T value) : KernelBase(data.size()) ,data(data),value(value) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<T>& data, T value ) { data[idx] = value; } inline std::vector<T>& getArg0() {
+ return data; }
+ typedef std::vector<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knSet ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,data,value); }
+ }
+ std::vector<T>& data; T value; }
+;
+
+
+template <class T> struct knCopyToVector : public KernelBase {
+ knCopyToVector(std::vector<T>& dst, const Grid<T>& src) : KernelBase(dst.size()) ,dst(dst),src(src) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<T>& dst, const Grid<T>& src ) { dst[idx] = src[idx]; } inline std::vector<T>& getArg0() {
+ return dst; }
+ typedef std::vector<T> type0;inline const Grid<T>& getArg1() {
+ return src; }
+ typedef Grid<T> type1; void runMessage() { debMsg("Executing kernel knCopyToVector ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,dst,src); }
+ }
+ std::vector<T>& dst; const Grid<T>& src; }
+;
+
+
+template <class T> struct knCopyToGrid : public KernelBase {
+ knCopyToGrid(const std::vector<T>& src, Grid<T>& dst) : KernelBase(src.size()) ,src(src),dst(dst) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const std::vector<T>& src, Grid<T>& dst ) { dst[idx] = src[idx]; } inline const std::vector<T>& getArg0() {
+ return src; }
+ typedef std::vector<T> type0;inline Grid<T>& getArg1() {
+ return dst; }
+ typedef Grid<T> type1; void runMessage() { debMsg("Executing kernel knCopyToGrid ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,src,dst); }
+ }
+ const std::vector<T>& src; Grid<T>& dst; }
+;
+
+
+template <class T> struct knAddAssign : public KernelBase {
+ knAddAssign(std::vector<T>& dst, const std::vector<T>& src) : KernelBase(dst.size()) ,dst(dst),src(src) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<T>& dst, const std::vector<T>& src ) { dst[idx] += src[idx]; } inline std::vector<T>& getArg0() {
+ return dst; }
+ typedef std::vector<T> type0;inline const std::vector<T>& getArg1() {
+ return src; }
+ typedef std::vector<T> type1; void runMessage() { debMsg("Executing kernel knAddAssign ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,dst,src); }
+ }
+ std::vector<T>& dst; const std::vector<T>& src; }
+;
+
+Real GridMg::doVCycle(Grid<Real>& dst, const Grid<Real>* src)
+{
+ MG_TIMINGS(MuTime timeSmooth; MuTime timeCG; MuTime timeI; MuTime timeR; MuTime timeTotal; MuTime time;)
+ MG_TIMINGS(timeSmooth.clear(); timeCG.clear(); timeI.clear(); timeR.clear();)
+
+ assertMsg(mIsASet && mIsRhsSet, "GridMg::doVCycle Error: A and/or rhs have not been set.");
+
+ const int maxLevel = int(mA.size()) - 1;
+
+ if (src) { knCopyToVector<Real>(mx[0], *src); }
+ else { knSet<Real>(mx[0], Real(0)); }
+
+ for (int l=0; l<maxLevel; l++)
+ {
+ MG_TIMINGS(time.update();)
+ for (int i=0; i<mNumPreSmooth; i++) {
+ smoothGS(l, false);
+ }
+
+ MG_TIMINGS(timeSmooth += time.update();)
+
+ calcResidual(l);
+ restrict(l+1, mr[l], mb[l+1]);
+
+ knSet<Real>(mx[l+1], Real(0));
+
+ MG_TIMINGS(timeR += time.update();)
+ }
+
+ MG_TIMINGS(time.update();)
+ solveCG(maxLevel);
+ MG_TIMINGS(timeCG += time.update();)
+
+ for (int l=maxLevel-1; l>=0; l--)
+ {
+ MG_TIMINGS(time.update();)
+ interpolate(l, mx[l+1], mr[l]);
+
+ knAddAssign<Real>(mx[l], mr[l]);
+
+ MG_TIMINGS(timeI += time.update();)
+
+ for (int i=0; i<mNumPostSmooth; i++) {
+ smoothGS(l, true);
+ }
+ MG_TIMINGS(timeSmooth += time.update();)
+ }
+
+ calcResidual(0);
+ Real res = calcResidualNorm(0);
+
+ knCopyToGrid<Real>(mx[0], dst);
+
+ MG_TIMINGS(debMsg("GridMg: Finished VCycle in "<<timeTotal.update()<<" (smoothing: "<<timeSmooth<<", CG: "<<timeCG<<", R: "<<timeR<<", I: "<<timeI<<")", 1);)
+
+ return res;
+}
+
+
+
+
+ struct knActivateCoarseVertices : public KernelBase {
+ knActivateCoarseVertices(std::vector<GridMg::VertexType>& type, int unused) : KernelBase(type.size()) ,type(type),unused(unused) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<GridMg::VertexType>& type, int unused ) {
+ // set all remaining 'free' vertices to 'removed',
+ if (type[idx] == GridMg::vtFree) type[idx] = GridMg::vtRemoved;
+
+ // then convert 'zero' vertices to 'active' and 'removed' vertices to 'inactive'
+ if (type[idx] == GridMg::vtZero ) type[idx] = GridMg::vtActive;
+ if (type[idx] == GridMg::vtRemoved) type[idx] = GridMg::vtInactive;
+} inline std::vector<GridMg::VertexType>& getArg0() {
+ return type; }
+ typedef std::vector<GridMg::VertexType> type0;inline int& getArg1() {
+ return unused; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel knActivateCoarseVertices ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,type,unused); }
+ }
+ std::vector<GridMg::VertexType>& type; int unused; }
+;
+
+// Determine active cells on coarse level l from active cells on fine level l-1
+// while ensuring a full-rank interpolation operator (see Section 3.3 in [1]).
+void GridMg::genCoarseGrid(int l)
+{
+ // AF_Free: unused/untouched vertices
+ // AF_Zero: vertices selected for coarser level
+ // AF_Removed: vertices removed from coarser level
+ enum activeFlags : char {AF_Removed = 0, AF_Zero = 1, AF_Free = 2};
+
+ // initialize all coarse vertices with 'free'
+ knSet<VertexType>(mType[l], vtFree);
+
+ // initialize min heap of (ID: fine grid vertex, key: #free interpolation vertices) pairs
+ NKMinHeap heap(int(mb[l-1].size()), mIs3D ? 9 : 5); // max 8 (or 4 in 2D) free interpolation vertices
+
+ FOR_LVL(v,l-1) {
+ if (mType[l-1][v] != vtInactive) {
+ Vec3i V = vecIdx(v,l-1);
+ int fiv = 1 << ((V.x % 2) + (V.y % 2) + (V.z % 2));
+ heap.setKey(v, fiv);
+ }
+ }
+
+ // process fine vertices in heap consecutively, always choosing the vertex with
+ // the currently smallest number of free interpolation vertices
+ while (heap.size() > 0)
+ {
+ int v = heap.popMin().first;
+ Vec3i V = vecIdx(v,l-1);
+
+ // loop over associated interpolation vertices of V on coarse level l:
+ // the first encountered 'free' vertex is set to 'zero',
+ // all remaining 'free' vertices are set to 'removed'.
+ bool vdone = false;
+
+ FOR_VEC_MINMAX(I, V/2, (V+1)/2) {
+ int i = linIdx(I,l);
+
+ if (mType[l][i] == vtFree) {
+ if (vdone) {
+ mType[l][i] = vtRemoved;
+ } else {
+ mType[l][i] = vtZero;
+ vdone = true;
+ }
+
+ // update #free interpolation vertices in heap:
+ // loop over all associated restriction vertices of I on fine level l-1
+ FOR_VEC_MINMAX(R, vmax(0, I*2-1), vmin(mSize[l-1]-1, I*2+1)) {
+ int r = linIdx(R,l-1);
+ int key = heap.getKey(r);
+
+ if (key > 1) { heap.setKey(r, key-1); } // decrease key of r
+ else if (key >-1) { heap.setKey(r, -1); } // removes r from heap
+ }
+ }
+ }
+ }
+
+ knActivateCoarseVertices(mType[l],0);
+}
+
+
+
+ struct knGenCoarseGridOperator : public KernelBase {
+ knGenCoarseGridOperator(std::vector<Real>& sizeRef, std::vector<Real>& A, int l, const GridMg& mg) : KernelBase(sizeRef.size()) ,sizeRef(sizeRef),A(A),l(l),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& sizeRef, std::vector<Real>& A, int l, const GridMg& mg ) {
+ if (mg.mType[l][idx] == GridMg::vtInactive) return;
+
+ for (int i=0; i<mg.mStencilSize; i++) { A[idx*mg.mStencilSize+i] = Real(0); } // clear stencil
+
+ Vec3i V = mg.vecIdx(int(idx),l);
+
+ // Calculate the stencil of A_l at V by considering all vertex paths of the form:
+ // (V) <--restriction-- (U) <--A_{l-1}-- (W) <--interpolation-- (N)
+ // V and N are vertices on the coarse grid level l,
+ // U and W are vertices on the fine grid level l-1.
+
+ if (l==1) {
+ // loop over precomputed paths
+ for (auto it = mg.mCoarseningPaths0.begin(); it != mg.mCoarseningPaths0.end(); it++) {
+ Vec3i N = V + it->N;
+ int n = mg.linIdx(N,l);
+ if (!mg.inGrid(N,l) || mg.mType[l][n]==GridMg::vtInactive) continue;
+
+ Vec3i U = V*2 + it->U;
+ int u = mg.linIdx(U,l-1);
+ if (!mg.inGrid(U,l-1) || mg.mType[l-1][u]==GridMg::vtInactive) continue;
+
+ Vec3i W = V*2 + it->W;
+ int w = mg.linIdx(W,l-1);
+ if (!mg.inGrid(W,l-1) || mg.mType[l-1][w]==GridMg::vtInactive) continue;
+
+ if (it->inUStencil) {
+ A[idx*mg.mStencilSize + it->sc] += it->rw * mg.mA[l-1][u*mg.mStencilSize0 + it->sf] *it->iw;
+ } else {
+ A[idx*mg.mStencilSize + it->sc] += it->rw * mg.mA[l-1][w*mg.mStencilSize0 + it->sf] *it->iw;
+ }
+ }
+ } else {
+ // l > 1:
+ // loop over restriction vertices U on level l-1 associated with V
+ FOR_VEC_MINMAX(U, vmax(0, V*2-1), vmin(mg.mSize[l-1]-1, V*2+1)) {
+ int u = mg.linIdx(U,l-1);
+ if (mg.mType[l-1][u] == GridMg::vtInactive) continue;
+
+ // restriction weight
+ Real rw = Real(1) / Real(1 << ((U.x % 2) + (U.y % 2) + (U.z % 2)));
+
+ // loop over all stencil neighbors N of V on level l that can be reached via restriction to U
+ FOR_VEC_MINMAX(N, (U-1)/2, vmin(mg.mSize[l]-1, (U+2)/2)) {
+ int n = mg.linIdx(N,l);
+ if (mg.mType[l][n] == GridMg::vtInactive) continue;
+
+ // stencil entry at V associated to N (coarse grid level l)
+ Vec3i SC = N - V + mg.mStencilMax;
+ int sc = SC.x + 3*SC.y + 9*SC.z;
+ if (sc < mg.mStencilSize-1) continue;
+
+ // loop over all vertices W which are in the stencil of A_{l-1} at U
+ // and which interpolate from N
+ FOR_VEC_MINMAX(W, vmax( 0, vmax(U-1,N*2-1)),
+ vmin(mg.mSize[l-1]-1, vmin(U+1,N*2+1))) {
+ int w = mg.linIdx(W,l-1);
+ if (mg.mType[l-1][w] == GridMg::vtInactive) continue;
+
+ // stencil entry at U associated to W (fine grid level l-1)
+ Vec3i SF = W - U + mg.mStencilMax;
+ int sf = SF.x + 3*SF.y + 9*SF.z;
+
+ Real iw = Real(1) / Real(1 << ((W.x % 2) + (W.y % 2) + (W.z % 2))); // interpolation weight
+
+ if (sf < mg.mStencilSize) {
+ A[idx*mg.mStencilSize + sc-mg.mStencilSize+1] += rw * mg.mA[l-1][w*mg.mStencilSize + mg.mStencilSize-1-sf] *iw;
+ } else {
+ A[idx*mg.mStencilSize + sc-mg.mStencilSize+1] += rw * mg.mA[l-1][u*mg.mStencilSize + sf-mg.mStencilSize+1] *iw;
+ }
+ }
+ }
+ }
+ }
+} inline std::vector<Real>& getArg0() {
+ return sizeRef; }
+ typedef std::vector<Real> type0;inline std::vector<Real>& getArg1() {
+ return A; }
+ typedef std::vector<Real> type1;inline int& getArg2() {
+ return l; }
+ typedef int type2;inline const GridMg& getArg3() {
+ return mg; }
+ typedef GridMg type3; void runMessage() { debMsg("Executing kernel knGenCoarseGridOperator ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for schedule(static,1)
+ for (IndexInt i = 0; i < _sz; i++) op(i,sizeRef,A,l,mg); }
+ }
+ std::vector<Real>& sizeRef; std::vector<Real>& A; int l; const GridMg& mg; }
+;
+
+
+// Calculate A_l on coarse level l from A_{l-1} on fine level l-1 using
+// Galerkin-based coarsening, i.e., compute A_l = R * A_{l-1} * I.
+void GridMg::genCoraseGridOperator(int l)
+{
+ // for each coarse grid vertex V
+ knGenCoarseGridOperator(mx[l], mA[l], l, *this);
+}
+
+
+
+
+ struct knSmoothColor : public KernelBase {
+ knSmoothColor(ThreadSize& numBlocks, std::vector<Real>& x, const Vec3i& blockSize, const std::vector<Vec3i>& colorOffs, int l, const GridMg& mg) : KernelBase(numBlocks.size()) ,numBlocks(numBlocks),x(x),blockSize(blockSize),colorOffs(colorOffs),l(l),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ThreadSize& numBlocks, std::vector<Real>& x, const Vec3i& blockSize, const std::vector<Vec3i>& colorOffs, int l, const GridMg& mg ) {
+ Vec3i blockOff (int(idx)%blockSize.x, (int(idx)%(blockSize.x*blockSize.y))/blockSize.x, int(idx)/(blockSize.x*blockSize.y));
+
+ for (int off = 0; off < colorOffs.size(); off++) {
+
+ Vec3i V = blockOff*2 + colorOffs[off];
+ if (!mg.inGrid(V,l)) continue;
+
+ const int v = mg.linIdx(V,l);
+ if (mg.mType[l][v] == GridMg::vtInactive) continue;
+
+ Real sum = mg.mb[l][v];
+
+ if (l==0) {
+ int n;
+ for (int d=0; d<mg.mDim; d++) {
+ if (V[d]>0) { n = v-mg.mPitch[0][d]; sum -= mg.mA[0][n*mg.mStencilSize0 + d+1] * mg.mx[0][n]; }
+ if (V[d]<mg.mSize[0][d]-1) { n = v+mg.mPitch[0][d]; sum -= mg.mA[0][v*mg.mStencilSize0 + d+1] * mg.mx[0][n]; }
+ }
+
+ x[v] = sum / mg.mA[0][v*mg.mStencilSize0 + 0];
+ } else {
+ FOR_VECLIN_MINMAX(S, s, mg.mStencilMin, mg.mStencilMax) {
+ if (s == mg.mStencilSize-1) continue;
+
+ Vec3i N = V + S;
+ int n = mg.linIdx(N,l);
+
+ if (mg.inGrid(N,l) && mg.mType[l][n]!=GridMg::vtInactive) {
+ if (s < mg.mStencilSize) {
+ sum -= mg.mA[l][n*mg.mStencilSize + mg.mStencilSize-1-s] * mg.mx[l][n];
+ } else {
+ sum -= mg.mA[l][v*mg.mStencilSize + s-mg.mStencilSize+1] * mg.mx[l][n];
+ }
+ }
+ }
+
+ x[v] = sum / mg.mA[l][v*mg.mStencilSize + 0];
+ }
+ }
+} inline ThreadSize& getArg0() {
+ return numBlocks; }
+ typedef ThreadSize type0;inline std::vector<Real>& getArg1() {
+ return x; }
+ typedef std::vector<Real> type1;inline const Vec3i& getArg2() {
+ return blockSize; }
+ typedef Vec3i type2;inline const std::vector<Vec3i>& getArg3() {
+ return colorOffs; }
+ typedef std::vector<Vec3i> type3;inline int& getArg4() {
+ return l; }
+ typedef int type4;inline const GridMg& getArg5() {
+ return mg; }
+ typedef GridMg type5; void runMessage() { debMsg("Executing kernel knSmoothColor ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for schedule(static,1)
+ for (IndexInt i = 0; i < _sz; i++) op(i,numBlocks,x,blockSize,colorOffs,l,mg); }
+ }
+ ThreadSize& numBlocks; std::vector<Real>& x; const Vec3i& blockSize; const std::vector<Vec3i>& colorOffs; int l; const GridMg& mg; }
+;
+
+void GridMg::smoothGS(int l, bool reversedOrder)
+{
+ // Multicolor Gauss-Seidel with two colors for the 5/7-point stencil on level 0
+ // and with four/eight colors for the 9/27-point stencil on levels > 0
+ std::vector<std::vector<Vec3i>> colorOffs;
+ const Vec3i a[8] = {Vec3i(0,0,0), Vec3i(1,0,0), Vec3i(0,1,0), Vec3i(1,1,0),
+ Vec3i(0,0,1), Vec3i(1,0,1), Vec3i(0,1,1), Vec3i(1,1,1)};
+ if (mIs3D) {
+ if (l==0) colorOffs = {{a[0],a[3],a[5],a[6]}, {a[1],a[2],a[4],a[7]}};
+ else colorOffs = {{a[0]}, {a[1]}, {a[2]}, {a[3]}, {a[4]}, {a[5]}, {a[6]}, {a[7]}};
+ } else {
+ if (l==0) colorOffs = {{a[0],a[3]}, {a[1],a[2]}};
+ else colorOffs = {{a[0]}, {a[1]}, {a[2]}, {a[3]}};
+ }
+
+ // Divide grid into 2x2 blocks for parallelization
+ Vec3i blockSize = (mSize[l]+1)/2;
+ ThreadSize numBlocks(blockSize.x * blockSize.y * blockSize.z);
+
+ for (int c = 0; c < colorOffs.size(); c++) {
+ int color = reversedOrder ? int(colorOffs.size())-1-c : c;
+
+ knSmoothColor(numBlocks, mx[l], blockSize, colorOffs[color], l, *this);
+ }
+}
+
+
+
+ struct knCalcResidual : public KernelBase {
+ knCalcResidual(std::vector<Real>& r, int l, const GridMg& mg) : KernelBase(r.size()) ,r(r),l(l),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& r, int l, const GridMg& mg ) {
+ if (mg.mType[l][idx] == GridMg::vtInactive) return;
+
+ Vec3i V = mg.vecIdx(int(idx),l);
+
+ Real sum = mg.mb[l][idx];
+
+ if (l==0) {
+ int n;
+ for (int d=0; d<mg.mDim; d++) {
+ if (V[d]>0) { n = int(idx)-mg.mPitch[0][d]; sum -= mg.mA[0][n *mg.mStencilSize0 + d+1] * mg.mx[0][n]; }
+ if (V[d]<mg.mSize[0][d]-1) { n = int(idx)+mg.mPitch[0][d]; sum -= mg.mA[0][idx*mg.mStencilSize0 + d+1] * mg.mx[0][n]; }
+ }
+ sum -= mg.mA[0][idx*mg.mStencilSize0 + 0] * mg.mx[0][idx];
+ } else {
+ FOR_VECLIN_MINMAX(S, s, mg.mStencilMin, mg.mStencilMax) {
+ Vec3i N = V + S;
+ int n = mg.linIdx(N,l);
+
+ if (mg.inGrid(N,l) && mg.mType[l][n]!=GridMg::vtInactive) {
+ if (s < mg.mStencilSize) {
+ sum -= mg.mA[l][n *mg.mStencilSize + mg.mStencilSize-1-s] * mg.mx[l][n];
+ } else {
+ sum -= mg.mA[l][idx*mg.mStencilSize + s-mg.mStencilSize+1] * mg.mx[l][n];
+ }
+ }
+ }
+ }
+
+ r[idx] = sum;
+} inline std::vector<Real>& getArg0() {
+ return r; }
+ typedef std::vector<Real> type0;inline int& getArg1() {
+ return l; }
+ typedef int type1;inline const GridMg& getArg2() {
+ return mg; }
+ typedef GridMg type2; void runMessage() { debMsg("Executing kernel knCalcResidual ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for schedule(static,1)
+ for (IndexInt i = 0; i < _sz; i++) op(i,r,l,mg); }
+ }
+ std::vector<Real>& r; int l; const GridMg& mg; }
+;
+
+void GridMg::calcResidual(int l)
+{
+ knCalcResidual(mr[l], l, *this);
+}
+
+
+
+ struct knResidualNormSumSqr : public KernelBase {
+ knResidualNormSumSqr(const vector<Real>& r, int l, const GridMg& mg) : KernelBase(r.size()) ,r(r),l(l),mg(mg) ,result(Real(0)) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const vector<Real>& r, int l, const GridMg& mg ,Real& result) {
+ if (mg.mType[l][idx] == GridMg::vtInactive) return;
+
+ result += r[idx] * r[idx];
+} inline operator Real () {
+ return result; }
+ inline Real & getRet() {
+ return result; }
+ inline const vector<Real>& getArg0() {
+ return r; }
+ typedef vector<Real> type0;inline int& getArg1() {
+ return l; }
+ typedef int type1;inline const GridMg& getArg2() {
+ return mg; }
+ typedef GridMg type2; void runMessage() { debMsg("Executing kernel knResidualNormSumSqr ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real result = Real(0);
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,r,l,mg,result);
+#pragma omp critical
+{this->result += result; } }
+ }
+ const vector<Real>& r; int l; const GridMg& mg; Real result; }
+;;
+
+Real GridMg::calcResidualNorm(int l)
+{
+ Real res = knResidualNormSumSqr(mr[l], l, *this);
+
+ return std::sqrt(res);
+}
+
+// Standard conjugate gradients with Jacobi preconditioner
+// Notes: Always run at double precision. Not parallelized since
+// coarsest level is assumed to be small.
+void GridMg::solveCG(int l)
+{
+ auto applyAStencil = [this](int v, int l, const std::vector<double>& vec) -> double {
+ Vec3i V = vecIdx(v,l);
+
+ double sum = 0;
+
+ if (l==0) {
+ int n;
+ for (int d=0; d<mDim; d++) {
+ if (V[d]>0) { n = v-mPitch[0][d]; sum += mA[0][n*mStencilSize0 + d+1] * vec[n]; }
+ if (V[d]<mSize[0][d]-1) { n = v+mPitch[0][d]; sum += mA[0][v*mStencilSize0 + d+1] * vec[n]; }
+ }
+ sum += mA[0][v*mStencilSize0 + 0] * vec[v];
+ } else {
+ FOR_VECLIN_MINMAX(S, s, mStencilMin, mStencilMax) {
+ Vec3i N = V + S;
+ int n = linIdx(N,l);
+
+ if (inGrid(N,l) && mType[l][n]!=vtInactive) {
+ if (s < mStencilSize) {
+ sum += mA[l][n*mStencilSize + mStencilSize-1-s] * vec[n];
+ } else {
+ sum += mA[l][v*mStencilSize + s-mStencilSize+1] * vec[n];
+ }
+ }
+ }
+ }
+
+ return sum;
+ };
+
+ std::vector<double>& z = mCGtmp1[l];
+ std::vector<double>& p = mCGtmp2[l];
+ std::vector<double>& x = mCGtmp3[l];
+ std::vector<double>& r = mCGtmp4[l];
+
+ // Initialization:
+ double alphaTop = 0;
+ double initialResidual = 0;
+
+ FOR_LVL(v,l) { x[v] = mx[l][v]; }
+
+ FOR_LVL(v,l) {
+ if (mType[l][v] == vtInactive) continue;
+
+ r[v] = mb[l][v] - applyAStencil(v,l,x);
+ if (l==0) { z[v] = r[v] / mA[0][v*mStencilSize0 + 0]; }
+ else { z[v] = r[v] / mA[l][v*mStencilSize + 0]; }
+
+ initialResidual += r[v] * r[v];
+ p[v] = z[v];
+ alphaTop += r[v] * z[v];
+ }
+
+ initialResidual = std::sqrt(initialResidual);
+
+ int iter = 0;
+ const int maxIter = 10000;
+ double residual = -1;
+
+ // CG iterations
+ for (; iter<maxIter && initialResidual>1E-12; iter++)
+ {
+ double alphaBot = 0;
+
+ FOR_LVL(v,l) {
+ if (mType[l][v] == vtInactive) continue;
+
+ z[v] = applyAStencil(v,l,p);
+ alphaBot += p[v] * z[v];
+ }
+
+ double alpha = alphaTop / alphaBot;
+
+ double alphaTopNew = 0;
+ residual = 0;
+
+ FOR_LVL(v,l) {
+ if (mType[l][v] == vtInactive) continue;
+
+ x[v] += alpha * p[v];
+ r[v] -= alpha * z[v];
+ residual += r[v] * r[v];
+ if (l==0) z[v] = r[v] / mA[0][v*mStencilSize0 + 0];
+ else z[v] = r[v] / mA[l][v*mStencilSize + 0];
+ alphaTopNew += r[v] * z[v];
+ }
+
+ residual = std::sqrt(residual);
+
+ if (residual / initialResidual < mCoarsestLevelAccuracy) break;
+
+ double beta = alphaTopNew / alphaTop;
+ alphaTop = alphaTopNew;
+
+ FOR_LVL(v,l) {
+ p[v] = z[v] + beta * p[v];
+ }
+ debMsg("GridMg::solveCG i="<<iter<<" rel-residual="<< (residual / initialResidual) , 5);
+ }
+
+ FOR_LVL(v,l) { mx[l][v] = Real(x[v]); }
+
+ if (iter == maxIter) { debMsg("GridMg::solveCG Warning: Reached maximum number of CG iterations", 1); }
+ else { debMsg("GridMg::solveCG Info: Reached residual "<<residual<<" in "<<iter<<" iterations", 2); }
+}
+
+
+
+ struct knRestrict : public KernelBase {
+ knRestrict(std::vector<Real>& dst, const std::vector<Real>& src, int l_dst, const GridMg& mg) : KernelBase(dst.size()) ,dst(dst),src(src),l_dst(l_dst),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& dst, const std::vector<Real>& src, int l_dst, const GridMg& mg ) {
+ if (mg.mType[l_dst][idx] == GridMg::vtInactive) return;
+
+ const int l_src = l_dst - 1;
+
+ // Coarse grid vertex
+ Vec3i V = mg.vecIdx(int(idx),l_dst);
+
+ Real sum = Real(0);
+
+ FOR_VEC_MINMAX(R, vmax(0, V*2-1), vmin(mg.mSize[l_src]-1, V*2+1)) {
+ int r = mg.linIdx(R,l_src);
+ if (mg.mType[l_src][r] == GridMg::vtInactive) continue;
+
+ // restriction weight
+ Real rw = Real(1) / Real(1 << ((R.x % 2) + (R.y % 2) + (R.z % 2)));
+
+ sum += rw * src[r];
+ }
+
+ dst[idx] = sum;
+} inline std::vector<Real>& getArg0() {
+ return dst; }
+ typedef std::vector<Real> type0;inline const std::vector<Real>& getArg1() {
+ return src; }
+ typedef std::vector<Real> type1;inline int& getArg2() {
+ return l_dst; }
+ typedef int type2;inline const GridMg& getArg3() {
+ return mg; }
+ typedef GridMg type3; void runMessage() { debMsg("Executing kernel knRestrict ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for schedule(static,1)
+ for (IndexInt i = 0; i < _sz; i++) op(i,dst,src,l_dst,mg); }
+ }
+ std::vector<Real>& dst; const std::vector<Real>& src; int l_dst; const GridMg& mg; }
+;
+
+void GridMg::restrict(int l_dst, const std::vector<Real>& src, std::vector<Real>& dst) const
+{
+ knRestrict(dst, src, l_dst, *this);
+}
+
+
+
+ struct knInterpolate : public KernelBase {
+ knInterpolate(std::vector<Real>& dst, const std::vector<Real>& src, int l_dst, const GridMg& mg) : KernelBase(dst.size()) ,dst(dst),src(src),l_dst(l_dst),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& dst, const std::vector<Real>& src, int l_dst, const GridMg& mg ) {
+ if (mg.mType[l_dst][idx] == GridMg::vtInactive) return;
+
+ const int l_src = l_dst + 1;
+
+ Vec3i V = mg.vecIdx(int(idx),l_dst);
+
+ Real sum = Real(0);
+
+ FOR_VEC_MINMAX(I, V/2, (V+1)/2) {
+ int i = mg.linIdx(I,l_src);
+ if (mg.mType[l_src][i] != GridMg::vtInactive) sum += src[i];
+ }
+
+ // interpolation weight
+ Real iw = Real(1) / Real(1 << ((V.x % 2) + (V.y % 2) + (V.z % 2)));
+
+ dst[idx] = iw * sum;
+} inline std::vector<Real>& getArg0() {
+ return dst; }
+ typedef std::vector<Real> type0;inline const std::vector<Real>& getArg1() {
+ return src; }
+ typedef std::vector<Real> type1;inline int& getArg2() {
+ return l_dst; }
+ typedef int type2;inline const GridMg& getArg3() {
+ return mg; }
+ typedef GridMg type3; void runMessage() { debMsg("Executing kernel knInterpolate ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for schedule(static,1)
+ for (IndexInt i = 0; i < _sz; i++) op(i,dst,src,l_dst,mg); }
+ }
+ std::vector<Real>& dst; const std::vector<Real>& src; int l_dst; const GridMg& mg; }
+;
+
+void GridMg::interpolate(int l_dst, const std::vector<Real>& src, std::vector<Real>& dst) const
+{
+ knInterpolate(dst, src, l_dst, *this);
+}
+
+
+
+}; // DDF
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h
new file mode 100644
index 00000000000..a8d70033971
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h
@@ -0,0 +1,154 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Multigrid solver by Florian Ferstl (florian.ferstl.ff@gmail.com)
+ *
+ * This is an implementation of the solver developed by Dick et al. [1]
+ * without topology awareness (= vertex duplication on coarser levels). This
+ * simplification allows us to use regular grids for all levels of the multigrid
+ * hierarchy and works well for moderately complex domains.
+ *
+ * [1] Solving the Fluid Pressure Poisson Equation Using Multigrid-Evaluation
+ * and Improvements, C. Dick, M. Rogowsky, R. Westermann, IEEE TVCG 2015
+ *
+ ******************************************************************************/
+
+#ifndef _MULTIGRID_H
+#define _MULTIGRID_H
+
+#include "vectorbase.h"
+#include "grid.h"
+
+namespace Manta {
+
+//! Multigrid solver
+class GridMg {
+ public:
+ //! constructor: preallocates most of required memory for multigrid hierarchy
+ GridMg(const Vec3i& gridSize);
+ ~GridMg() {};
+
+ //! update system matrix A from symmetric 7-point stencil
+ void setA(const Grid<Real>* pA0, const Grid<Real>* pAi, const Grid<Real>* pAj, const Grid<Real>* pAk);
+
+ //! set right-hand side after setting A
+ void setRhs(const Grid<Real>& rhs);
+
+ bool isASet() const { return mIsASet; }
+ bool isRhsSet() const { return mIsRhsSet; }
+
+ //! perform VCycle iteration
+ // - if src is null, then a zero vector is used instead
+ // - returns norm of residual after VCylcle
+ Real doVCycle(Grid<Real>& dst, const Grid<Real>* src = nullptr);
+
+ // access
+ void setCoarsestLevelAccuracy(Real accuracy) { mCoarsestLevelAccuracy = accuracy; }
+ Real getCoarsestLevelAccuracy() const { return mCoarsestLevelAccuracy; }
+ void setSmoothing(int numPreSmooth, int numPostSmooth) { mNumPreSmooth = numPreSmooth; mNumPostSmooth = numPostSmooth; }
+ int getNumPreSmooth() const { return mNumPreSmooth; }
+ int getNumPostSmooth() const { return mNumPostSmooth; }
+
+ //! Set factor for automated downscaling of trivial equations:
+ // 1*x_i = b_i ---> trivialEquationScale*x_i = trivialEquationScale*b_i
+ // Factor should be significantly smaller than the scale of the entries in A.
+ // Info: Trivial equations of the form x_i = b_i can have a negative
+ // effect on the coarse grid operators of the multigrid hierarchy (due
+ // to scaling mismatches), which can lead to slow multigrid convergence.
+ // To avoid this, the solver checks for such equations when updating A
+ // (and rhs) and scales these equations by a fixed factor < 1.
+ void setTrivialEquationScale(Real scale) { mTrivialEquationScale = scale; }
+
+ private:
+ Vec3i vecIdx(int v, int l) const { return Vec3i(v%mSize[l].x, (v%(mSize[l].x*mSize[l].y))/mSize[l].x, v/(mSize[l].x*mSize[l].y)); }
+ int linIdx(Vec3i V, int l) const { return V.x + V.y*mPitch[l].y + V.z*mPitch[l].z; }
+ bool inGrid(Vec3i V, int l) const { return V.x>=0 && V.y>=0 && V.z>=0 && V.x<mSize[l].x && V.y<mSize[l].y && V.z<mSize[l].z; }
+
+ void analyzeStencil(int v, bool is3D, bool& isStencilSumNonZero, bool& isEquationTrivial) const;
+
+ void genCoarseGrid(int l);
+ void genCoraseGridOperator(int l);
+
+ void smoothGS(int l, bool reversedOrder);
+ void calcResidual(int l);
+ Real calcResidualNorm(int l);
+ void solveCG(int l);
+
+ void restrict(int l_dst, const std::vector<Real>& src, std::vector<Real>& dst) const;
+ void interpolate(int l_dst, const std::vector<Real>& src, std::vector<Real>& dst) const;
+
+ private:
+ enum VertexType : char {
+ vtInactive = 0,
+ vtActive = 1,
+ vtActiveTrivial = 2, // only on finest level 0
+ vtRemoved = 3, //-+
+ vtZero = 4, // +-- only during coarse grid generation
+ vtFree = 5 //-+
+ };
+
+ struct CoarseningPath {
+ Vec3i U, W, N;
+ int sc, sf;
+ Real rw, iw;
+ bool inUStencil;
+ };
+
+ int mNumPreSmooth;
+ int mNumPostSmooth;
+ Real mCoarsestLevelAccuracy;
+ Real mTrivialEquationScale;
+
+ std::vector<std::vector<Real>> mA;
+ std::vector<std::vector<Real>> mx;
+ std::vector<std::vector<Real>> mb;
+ std::vector<std::vector<Real>> mr;
+ std::vector<std::vector<VertexType>> mType;
+ std::vector<std::vector<double>> mCGtmp1, mCGtmp2, mCGtmp3, mCGtmp4;
+ std::vector<Vec3i> mSize, mPitch;
+ std::vector<CoarseningPath> mCoarseningPaths0;
+
+ bool mIs3D;
+ int mDim;
+ int mStencilSize;
+ int mStencilSize0;
+ Vec3i mStencilMin;
+ Vec3i mStencilMax;
+
+ bool mIsASet;
+ bool mIsRhsSet;
+
+ // provide kernels with access
+ friend struct knActivateVertices;
+ friend struct knActivateCoarseVertices;
+ friend struct knSetRhs;
+ friend struct knGenCoarseGridOperator;
+ friend struct knSmoothColor;
+ friend struct knCalcResidual;
+ friend struct knResidualNormSumSqr;
+ friend struct knRestrict;
+ friend struct knInterpolate;
+}; // GridMg
+
+} // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h.reg
new file mode 100644
index 00000000000..0dd8d785437
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h.reg
@@ -0,0 +1 @@
+#include "multigrid.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h.reg.cpp
new file mode 100644
index 00000000000..5210d1aac28
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/multigrid.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "multigrid.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_4()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.cpp
new file mode 100644
index 00000000000..13effa9e89d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.cpp
@@ -0,0 +1,312 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Noise field
+ *
+ ******************************************************************************/
+
+#include "noisefield.h"
+#include "randomstream.h"
+#include "grid.h"
+
+using namespace std;
+
+//*****************************************************************************
+// Wavelet noise
+
+#if FLOATINGPOINT_PRECISION==1
+#define TILENAME "waveletNoiseTile.bin"
+#else
+#define TILENAME "waveletNoiseTileD.bin"
+#endif
+
+namespace Manta {
+
+int WaveletNoiseField::randomSeed = 13322223;
+Real* WaveletNoiseField::mNoiseTile = NULL;
+std::atomic<int> WaveletNoiseField::mNoiseReferenceCount(0);
+
+static Real _aCoeffs[32] = {
+ 0.000334,-0.001528, 0.000410, 0.003545,-0.000938,-0.008233, 0.002172, 0.019120,
+ -0.005040,-0.044412, 0.011655, 0.103311,-0.025936,-0.243780, 0.033979, 0.655340,
+ 0.655340, 0.033979,-0.243780,-0.025936, 0.103311, 0.011655,-0.044412,-0.005040,
+ 0.019120, 0.002172,-0.008233,-0.000938, 0.003546, 0.000410,-0.001528, 0.000334};
+
+void WaveletNoiseField::downsample(Real *from, Real *to, int n, int stride){
+ const Real *a = &_aCoeffs[16];
+ for (int i = 0; i < n / 2; i++) {
+ to[i * stride] = 0;
+ for (int k = 2 * i - 16; k < 2 * i + 16; k++) {
+ to[i * stride] += a[k - 2 * i] * from[modFast128(k) * stride];
+ }
+ }
+}
+
+static Real _pCoeffs[4] = {0.25, 0.75, 0.75, 0.25};
+
+void WaveletNoiseField::upsample(Real *from, Real *to, int n, int stride) {
+ const Real *pp = &_pCoeffs[1];
+
+ for (int i = 0; i < n; i++) {
+ to[i * stride] = 0;
+ for (int k = i / 2 - 1 ; k < i / 2 + 3; k++) {
+ to[i * stride] += 0.5 * pp[k - i / 2] * from[modSlow(k, n / 2) * stride];
+ } // new */
+ }
+}
+
+WaveletNoiseField::WaveletNoiseField(FluidSolver* parent, int fixedSeed, int loadFromFile) :
+ PbClass(parent), mPosOffset(0.), mPosScale(1.), mValOffset(0.), mValScale(1.), mClamp(false),
+ mClampNeg(0), mClampPos(1), mTimeAnim(0), mGsInvX(0), mGsInvY(0), mGsInvZ(0)
+{
+ Real scale = 1.0/parent->getGridSize().max();
+ mGsInvX = scale;
+ mGsInvY = scale;
+ mGsInvZ = parent->is3D() ? scale : 1;
+
+ // use global random seed with offset if none is given
+ if (fixedSeed==-1) {
+ fixedSeed = randomSeed + 123;
+ }
+ RandomStream randStreamPos(fixedSeed);
+ mSeedOffset = Vec3( randStreamPos.getVec3Norm() );
+
+ generateTile( loadFromFile );
+};
+
+string WaveletNoiseField::toString() {
+ std::ostringstream out;
+ out << "NoiseField: name '"<<mName<<"' "<<
+ " pos off="<<mPosOffset<<" scale="<<mPosScale<<
+ " val off="<<mValOffset<<" scale="<<mValScale<<
+ " clamp ="<<mClamp<<" val="<<mClampNeg<<" to "<<mClampPos<<
+ " timeAni ="<<mTimeAnim<<
+ " gridInv ="<<Vec3(mGsInvX,mGsInvY,mGsInvZ) ;
+ return out.str();
+}
+
+void WaveletNoiseField::generateTile( int loadFromFile) {
+ // generate tile
+ const int n = NOISE_TILE_SIZE;
+ const int n3 = n*n*n, n3d=n3*3;
+
+ if(mNoiseTile) { mNoiseReferenceCount++; return; }
+ Real *noise3 = new Real[n3d];
+ if(loadFromFile) {
+ FILE* fp = fopen(TILENAME,"rb");
+ if(fp) {
+ assertMsg( fread(noise3, sizeof(Real), n3d, fp) == n3d, "Failed to read wavelet noise tile, file invalid/corrupt? ("<<TILENAME<<") ");
+ fclose(fp);
+ debMsg("Noise tile loaded from file " TILENAME , 1);
+ mNoiseTile = noise3;
+ mNoiseReferenceCount++;
+ return;
+ }
+ }
+
+ debMsg("Generating 3x " << n << "^3 noise tile " , 1);
+ Real *temp13 = new Real[n3d];
+ Real *temp23 = new Real[n3d];
+
+ // initialize
+ for (int i = 0; i < n3d; i++) {
+ temp13[i] = temp23[i] =
+ noise3[i] = 0.;
+ }
+
+ // Step 1. Fill the tile with random numbers in the range -1 to 1.
+ RandomStream randStreamTile ( randomSeed );
+ for (int i = 0; i < n3d; i++) {
+ //noise3[i] = (randStream.getReal() + randStream2.getReal()) -1.; // produces repeated values??
+ noise3[i] = randStreamTile.getRandNorm(0,1);
+ }
+
+ // Steps 2 and 3. Downsample and upsample the tile
+ for (int tile=0; tile < 3; tile++) {
+ for (int iy = 0; iy < n; iy++)
+ for (int iz = 0; iz < n; iz++) {
+ const int i = iy * n + iz*n*n + tile*n3;
+ downsample(&noise3[i], &temp13[i], n, 1);
+ upsample (&temp13[i], &temp23[i], n, 1);
+ }
+ for (int ix = 0; ix < n; ix++)
+ for (int iz = 0; iz < n; iz++) {
+ const int i = ix + iz*n*n + tile*n3;
+ downsample(&temp23[i], &temp13[i], n, n);
+ upsample (&temp13[i], &temp23[i], n, n);
+ }
+ for (int ix = 0; ix < n; ix++)
+ for (int iy = 0; iy < n; iy++) {
+ const int i = ix + iy*n + tile*n3;
+ downsample(&temp23[i], &temp13[i], n, n*n);
+ upsample (&temp13[i], &temp23[i], n, n*n);
+ }
+ }
+
+ // Step 4. Subtract out the coarse-scale contribution
+ for (int i = 0; i < n3d; i++) {
+ noise3[i] -= temp23[i];
+ }
+
+ // Avoid even/odd variance difference by adding odd-offset version of noise to itself.
+ int offset = n / 2;
+ if (offset % 2 == 0) offset++;
+
+ if (n != 128) errMsg("WaveletNoise::Fast 128 mod used, change for non-128 resolution");
+
+ int icnt=0;
+ for (int tile=0; tile<3; tile++)
+ for (int ix = 0; ix < n; ix++)
+ for (int iy = 0; iy < n; iy++)
+ for (int iz = 0; iz < n; iz++) {
+ temp13[icnt] = noise3[modFast128(ix+offset) + modFast128(iy+offset)*n + modFast128(iz+offset)*n*n + tile*n3];
+ icnt++;
+ }
+
+
+ for (int i = 0; i < n3d; i++) {
+ noise3[i] += temp13[i];
+ }
+
+ mNoiseTile = noise3;
+ mNoiseReferenceCount++;
+ delete[] temp13;
+ delete[] temp23;
+
+ if(loadFromFile) {
+ FILE* fp = fopen(TILENAME,"wb");
+ if(fp) {
+ fwrite(noise3, sizeof(Real), n3d, fp);
+ fclose(fp);
+ debMsg( "Noise field saved to file " , 1);
+ }
+ }
+}
+
+
+
+void WaveletNoiseField::downsampleNeumann(const Real *from, Real *to, int n, int stride)
+{
+ // if these values are not local incorrect results are generated
+ static const Real *const aCoCenter= &_aCoeffs[16];
+ for (int i = 0; i < n / 2; i++) {
+ to[i * stride] = 0;
+ for (int k = 2 * i - 16; k < 2 * i + 16; k++) {
+ // handle boundary
+ Real fromval;
+ if (k < 0) {
+ fromval = from[0];
+ } else if(k > n - 1) {
+ fromval = from[(n - 1) * stride];
+ } else {
+ fromval = from[k * stride];
+ }
+ to[i * stride] += aCoCenter[k - 2 * i] * fromval;
+ }
+ }
+}
+
+void WaveletNoiseField::upsampleNeumann(const Real *from, Real *to, int n, int stride) {
+ static const Real *const pp = &_pCoeffs[1];
+ for (int i = 0; i < n; i++) {
+ to[i * stride] = 0;
+ for (int k = i / 2 - 1 ; k < i / 2 + 3; k++) {
+ Real fromval;
+ if(k>n/2-1) {
+ fromval = from[(n/2-1) * stride];
+ } else if(k < 0) {
+ fromval = from[0];
+ } else {
+ fromval = from[k * stride];
+ }
+ to[i * stride] += 0.5 * pp[k - i / 2] * fromval;
+ }
+ }
+}
+
+void WaveletNoiseField::computeCoefficients(Grid<Real>& input, Grid<Real>& tempIn1, Grid<Real>& tempIn2)
+{
+ // generate tile
+ const int sx = input.getSizeX();
+ const int sy = input.getSizeY();
+ const int sz = input.getSizeZ();
+ const int n3 = sx*sy*sz;
+ // just for compatibility with wavelet turb code
+ Real *temp13 = &tempIn1(0,0,0);
+ Real *temp23 = &tempIn2(0,0,0);
+ Real *noise3 = &input(0,0,0);
+
+ // clear grids
+ for (int i = 0; i < n3; i++) {
+ temp13[i] = temp23[i] = 0.f;
+ }
+
+ // Steps 2 and 3. Downsample and upsample the tile
+ for (int iz = 0; iz < sz; iz++)
+ for (int iy = 0; iy < sy; iy++)
+ {
+ const int i = iz*sx*sy + iy*sx;
+ downsampleNeumann(&noise3[i], &temp13[i], sx, 1 );
+ upsampleNeumann (&temp13[i], &temp23[i], sx, 1);
+ }
+
+ for (int iz = 0; iz < sz; iz++)
+ for (int ix = 0; ix < sx; ix++)
+ {
+ const int i = iz*sx*sy + ix;
+ downsampleNeumann(&temp23[i], &temp13[i], sy, sx );
+ upsampleNeumann (&temp13[i], &temp23[i], sy, sx );
+ }
+
+ if(input.is3D()) {
+ for (int iy = 0; iy < sy; iy++)
+ for (int ix = 0; ix < sx; ix++)
+ {
+ const int i = iy*sx+ix;
+ downsampleNeumann(&temp23[i], &temp13[i], sz, sy*sx );
+ upsampleNeumann (&temp13[i], &temp23[i], sz, sy*sx );
+ }
+ }
+
+ // Step 4. Subtract out the coarse-scale contribution
+ for (int i = 0; i < n3; i++) {
+ Real residual = noise3[i] - temp23[i];
+ temp13[i] = sqrtf( fabs(residual) );
+ }
+
+ // copy back, and compute actual weight for wavelet turbulence...
+ Real smoothingFactor = 1./6.;
+ if(!input.is3D()) smoothingFactor = 1./4.;
+ FOR_IJK_BND(input,1) {
+ // apply some brute force smoothing
+ Real res = temp13[k*sx*sy+j*sx+i-1] + temp13[k*sx*sy+j*sx+i+1];
+ res += temp13[k*sx*sy+j*sx+i-sx] + temp13[k*sx*sy+j*sx+i+sx];
+ if( input.is3D()) res += temp13[k*sx*sy+j*sx+i-sx*sy] + temp13[k*sx*sy+j*sx+i+sx*sy];
+ input(i,j,k) = res * smoothingFactor;
+ }
+}
+
+
+
+
+
+}
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h
new file mode 100644
index 00000000000..f85f3d440d0
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h
@@ -0,0 +1,450 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Wavelet noise field
+ *
+ ******************************************************************************/
+
+#ifndef _NOISEFIELD_H_
+#define _NOISEFIELD_H_
+
+#include "vectorbase.h"
+#include "manta.h"
+#include "grid.h"
+#include <atomic>
+
+namespace Manta {
+
+#define NOISE_TILE_SIZE 128
+
+// wrapper for a parametrized field of wavelet noise
+
+class WaveletNoiseField : public PbClass { public:
+ WaveletNoiseField( FluidSolver* parent, int fixedSeed=-1 , int loadFromFile=false ); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "WaveletNoiseField::WaveletNoiseField" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); int fixedSeed = _args.getOpt<int >("fixedSeed",1,-1 ,&_lock); int loadFromFile = _args.getOpt<int >("loadFromFile",2,false ,&_lock); obj = new WaveletNoiseField(parent,fixedSeed,loadFromFile); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"WaveletNoiseField::WaveletNoiseField" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("WaveletNoiseField::WaveletNoiseField",e.what()); return -1; }
+ }
+
+ ~WaveletNoiseField() {
+ if(mNoiseTile && !mNoiseReferenceCount) { delete mNoiseTile; mNoiseTile=NULL; }
+ };
+
+ //! evaluate noise
+ inline Real evaluate(Vec3 pos, int tile=0) const;
+ //! evaluate noise as a vector
+ inline Vec3 evaluateVec(Vec3 pos, int tile=0) const;
+ //! evaluate curl noise
+ inline Vec3 evaluateCurl(Vec3 pos) const;
+
+ //! direct data access
+ Real* data() { return mNoiseTile; }
+
+ //! compute wavelet decomposition of an input grid (stores residual coefficients)
+ static void computeCoefficients(Grid<Real>& input, Grid<Real>& tempIn1, Grid<Real>& tempIn2);
+
+ // helper
+ std::string toString();
+
+ // texcoord position and scale
+ Vec3 mPosOffset;static PyObject* _GET_mPosOffset(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mPosOffset); }
+ static int _SET_mPosOffset(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mPosOffset = fromPy<Vec3 >(val); return 0; }
+
+ Vec3 mPosScale;static PyObject* _GET_mPosScale(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mPosScale); }
+ static int _SET_mPosScale(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mPosScale = fromPy<Vec3 >(val); return 0; }
+
+ // value offset & scale
+ Real mValOffset;static PyObject* _GET_mValOffset(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mValOffset); }
+ static int _SET_mValOffset(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mValOffset = fromPy<Real >(val); return 0; }
+
+ Real mValScale;static PyObject* _GET_mValScale(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mValScale); }
+ static int _SET_mValScale(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mValScale = fromPy<Real >(val); return 0; }
+
+ // clamp? (default 0-1)
+ bool mClamp;static PyObject* _GET_mClamp(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mClamp); }
+ static int _SET_mClamp(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mClamp = fromPy<bool >(val); return 0; }
+
+ Real mClampNeg;static PyObject* _GET_mClampNeg(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mClampNeg); }
+ static int _SET_mClampNeg(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mClampNeg = fromPy<Real >(val); return 0; }
+
+ Real mClampPos;static PyObject* _GET_mClampPos(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mClampPos); }
+ static int _SET_mClampPos(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mClampPos = fromPy<Real >(val); return 0; }
+
+ // animated over time
+ Real mTimeAnim;static PyObject* _GET_mTimeAnim(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mTimeAnim); }
+ static int _SET_mTimeAnim(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mTimeAnim = fromPy<Real >(val); return 0; }
+
+
+ protected:
+ // noise evaluation functions
+ static inline Real WNoiseDx (const Vec3& p, Real *data);
+ static inline Vec3 WNoiseVec(const Vec3& p, Real *data);
+ static inline Real WNoise (const Vec3& p, Real *data);
+
+ // helpers for tile generation , for periodic 128 grids only
+ static void downsample(Real *from, Real *to, int n, int stride);
+ static void upsample (Real *from, Real *to, int n, int stride);
+
+ // for grids with arbitrary sizes, and neumann boundary conditions
+ static void downsampleNeumann(const Real *from, Real *to, int n, int stride);
+ static void upsampleNeumann (const Real *from, Real *to, int n, int stride);
+
+ static inline int modSlow(int x, int n) { int m = x % n; return (m<0) ? m+n : m; }
+ // warning - noiseTileSize has to be 128^3!
+ #define modFast128(x) ((x) & 127)
+
+ inline Real getTime() const { return mParent->getTime() * mParent->getDx() * mTimeAnim; }
+
+ // pre-compute tile data for wavelet noise
+ void generateTile( int loadFromFile );
+
+ // animation over time
+ // grid size normalization (inverse size)
+ Real mGsInvX, mGsInvY, mGsInvZ;
+ // random offset into tile to simulate different random seeds
+ Vec3 mSeedOffset;
+
+ static Real* mNoiseTile;
+ // global random seed storage
+ static int randomSeed;
+ // global reference count for noise tile
+ static std::atomic<int> mNoiseReferenceCount; public: PbArgs _args; }
+#define _C_WaveletNoiseField
+;
+
+
+
+// **************************************************************************
+// Implementation
+
+#define ADD_WEIGHTED(x,y,z)\
+ weight = 1.0f;\
+ xC = modFast128(midX + (x));\
+ weight *= w[0][(x) + 1];\
+ yC = modFast128(midY + (y));\
+ weight *= w[1][(y) + 1];\
+ zC = modFast128(midZ + (z));\
+ weight *= w[2][(z) + 1];\
+ result += weight * data[(zC * NOISE_TILE_SIZE + yC) * NOISE_TILE_SIZE + xC];
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// derivatives of 3D noise - unrolled for performance
+//////////////////////////////////////////////////////////////////////////////////////////
+inline Real WaveletNoiseField::WNoiseDx(const Vec3& p, Real *data) {
+ Real w[3][3], t, result = 0;
+
+ // Evaluate quadratic B-spline basis functions
+ int midX = (int)ceil(p[0] - 0.5f);
+ t = midX - (p[0] - 0.5f);
+ w[0][0] = -t;
+ w[0][2] = (1.f - t);
+ w[0][1] = 2.0f * t - 1.0f;
+
+ int midY = (int)ceil(p[1] - 0.5f);
+ t = midY - (p[1] - 0.5f);
+ w[1][0] = t * t * 0.5f;
+ w[1][2] = (1.f - t) * (1.f - t) *0.5f;
+ w[1][1] = 1.f - w[1][0] - w[1][2];
+
+ int midZ = (int)ceil(p[2] - 0.5f);
+ t = midZ - (p[2] - 0.5f);
+ w[2][0] = t * t * 0.5f;
+ w[2][2] = (1.f - t) * (1.f - t) *0.5f;
+ w[2][1] = 1.f - w[2][0] - w[2][2];
+
+ // Evaluate noise by weighting noise coefficients by basis function values
+ int xC, yC, zC;
+ Real weight = 1;
+
+ ADD_WEIGHTED(-1,-1, -1); ADD_WEIGHTED( 0,-1, -1); ADD_WEIGHTED( 1,-1, -1);
+ ADD_WEIGHTED(-1, 0, -1); ADD_WEIGHTED( 0, 0, -1); ADD_WEIGHTED( 1, 0, -1);
+ ADD_WEIGHTED(-1, 1, -1); ADD_WEIGHTED( 0, 1, -1); ADD_WEIGHTED( 1, 1, -1);
+
+ ADD_WEIGHTED(-1,-1, 0); ADD_WEIGHTED( 0,-1, 0); ADD_WEIGHTED( 1,-1, 0);
+ ADD_WEIGHTED(-1, 0, 0); ADD_WEIGHTED( 0, 0, 0); ADD_WEIGHTED( 1, 0, 0);
+ ADD_WEIGHTED(-1, 1, 0); ADD_WEIGHTED( 0, 1, 0); ADD_WEIGHTED( 1, 1, 0);
+
+ ADD_WEIGHTED(-1,-1, 1); ADD_WEIGHTED( 0,-1, 1); ADD_WEIGHTED( 1,-1, 1);
+ ADD_WEIGHTED(-1, 0, 1); ADD_WEIGHTED( 0, 0, 1); ADD_WEIGHTED( 1, 0, 1);
+ ADD_WEIGHTED(-1, 1, 1); ADD_WEIGHTED( 0, 1, 1); ADD_WEIGHTED( 1, 1, 1);
+
+ return result;
+}
+
+inline Real WaveletNoiseField::WNoise(const Vec3& p, Real *data) {
+ Real w[3][3], t, result = 0;
+
+ // Evaluate quadratic B-spline basis functions
+ int midX = (int)ceilf(p[0] - 0.5f);
+ t = midX - (p[0] - 0.5f);
+ w[0][0] = t * t * 0.5f;
+ w[0][2] = (1.f - t) * (1.f - t) *0.5f;
+ w[0][1] = 1.f - w[0][0] - w[0][2];
+
+ int midY = (int)ceilf(p[1] - 0.5f);
+ t = midY - (p[1] - 0.5f);
+ w[1][0] = t * t * 0.5f;
+ w[1][2] = (1.f - t) * (1.f - t) *0.5f;
+ w[1][1] = 1.f - w[1][0] - w[1][2];
+
+ int midZ = (int)ceilf(p[2] - 0.5f);
+ t = midZ - (p[2] - 0.5f);
+ w[2][0] = t * t * 0.5f;
+ w[2][2] = (1.f - t) * (1.f - t) *0.5f;
+ w[2][1] = 1.f - w[2][0] - w[2][2];
+
+ // Evaluate noise by weighting noise coefficients by basis function values
+ int xC, yC, zC;
+ Real weight = 1;
+
+ ADD_WEIGHTED(-1,-1, -1); ADD_WEIGHTED( 0,-1, -1); ADD_WEIGHTED( 1,-1, -1);
+ ADD_WEIGHTED(-1, 0, -1); ADD_WEIGHTED( 0, 0, -1); ADD_WEIGHTED( 1, 0, -1);
+ ADD_WEIGHTED(-1, 1, -1); ADD_WEIGHTED( 0, 1, -1); ADD_WEIGHTED( 1, 1, -1);
+
+ ADD_WEIGHTED(-1,-1, 0); ADD_WEIGHTED( 0,-1, 0); ADD_WEIGHTED( 1,-1, 0);
+ ADD_WEIGHTED(-1, 0, 0); ADD_WEIGHTED( 0, 0, 0); ADD_WEIGHTED( 1, 0, 0);
+ ADD_WEIGHTED(-1, 1, 0); ADD_WEIGHTED( 0, 1, 0); ADD_WEIGHTED( 1, 1, 0);
+
+ ADD_WEIGHTED(-1,-1, 1); ADD_WEIGHTED( 0,-1, 1); ADD_WEIGHTED( 1,-1, 1);
+ ADD_WEIGHTED(-1, 0, 1); ADD_WEIGHTED( 0, 0, 1); ADD_WEIGHTED( 1, 0, 1);
+ ADD_WEIGHTED(-1, 1, 1); ADD_WEIGHTED( 0, 1, 1); ADD_WEIGHTED( 1, 1, 1);
+
+ return result;
+}
+
+
+
+#define ADD_WEIGHTEDX(x,y,z)\
+ weight = dw[0][(x) + 1] * w[1][(y) + 1] * w[2][(z) + 1];\
+ result += weight * neighbors[x + 1][y + 1][z + 1];
+
+#define ADD_WEIGHTEDY(x,y,z)\
+ weight = w[0][(x) + 1] * dw[1][(y) + 1] * w[2][(z) + 1];\
+ result += weight * neighbors[x + 1][y + 1][z + 1];
+
+#define ADD_WEIGHTEDZ(x,y,z)\
+ weight = w[0][(x) + 1] * w[1][(y) + 1] * dw[2][(z) + 1];\
+ result += weight * neighbors[x + 1][y + 1][z + 1];
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// compute all derivatives in at once
+//////////////////////////////////////////////////////////////////////////////////////////
+inline Vec3 WaveletNoiseField::WNoiseVec(const Vec3& p, Real *data)
+{
+ Vec3 final(0.);
+ Real w[3][3];
+ Real dw[3][3];
+ Real result = 0;
+ int xC, yC, zC;
+ Real weight;
+
+ int midX = (int)ceil(p[0] - 0.5f);
+ int midY = (int)ceil(p[1] - 0.5f);
+ int midZ = (int)ceil(p[2] - 0.5f);
+
+ Real t0 = midX - (p[0] - 0.5f);
+ Real t1 = midY - (p[1] - 0.5f);
+ Real t2 = midZ - (p[2] - 0.5f);
+
+ // precache all the neighbors for fast access
+ Real neighbors[3][3][3];
+ for (int z = -1; z <=1; z++)
+ for (int y = -1; y <= 1; y++)
+ for (int x = -1; x <= 1; x++)
+ {
+ xC = modFast128(midX + (x));
+ yC = modFast128(midY + (y));
+ zC = modFast128(midZ + (z));
+ neighbors[x + 1][y + 1][z + 1] = data[zC * NOISE_TILE_SIZE * NOISE_TILE_SIZE + yC * NOISE_TILE_SIZE + xC];
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // evaluate splines
+ ///////////////////////////////////////////////////////////////////////////////////////
+ dw[0][0] = -t0;
+ dw[0][2] = (1.f - t0);
+ dw[0][1] = 2.0f * t0 - 1.0f;
+
+ dw[1][0] = -t1;
+ dw[1][2] = (1.0f - t1);
+ dw[1][1] = 2.0f * t1 - 1.0f;
+
+ dw[2][0] = -t2;
+ dw[2][2] = (1.0f - t2);
+ dw[2][1] = 2.0f * t2 - 1.0f;
+
+ w[0][0] = t0 * t0 * 0.5f;
+ w[0][2] = (1.f - t0) * (1.f - t0) *0.5f;
+ w[0][1] = 1.f - w[0][0] - w[0][2];
+
+ w[1][0] = t1 * t1 * 0.5f;
+ w[1][2] = (1.f - t1) * (1.f - t1) *0.5f;
+ w[1][1] = 1.f - w[1][0] - w[1][2];
+
+ w[2][0] = t2 * t2 * 0.5f;
+ w[2][2] = (1.f - t2) * (1.f - t2) *0.5f;
+ w[2][1] = 1.f - w[2][0] - w[2][2];
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // x derivative
+ ///////////////////////////////////////////////////////////////////////////////////////
+ result = 0.0f;
+ ADD_WEIGHTEDX(-1,-1, -1); ADD_WEIGHTEDX( 0,-1, -1); ADD_WEIGHTEDX( 1,-1, -1);
+ ADD_WEIGHTEDX(-1, 0, -1); ADD_WEIGHTEDX( 0, 0, -1); ADD_WEIGHTEDX( 1, 0, -1);
+ ADD_WEIGHTEDX(-1, 1, -1); ADD_WEIGHTEDX( 0, 1, -1); ADD_WEIGHTEDX( 1, 1, -1);
+
+ ADD_WEIGHTEDX(-1,-1, 0); ADD_WEIGHTEDX( 0,-1, 0); ADD_WEIGHTEDX( 1,-1, 0);
+ ADD_WEIGHTEDX(-1, 0, 0); ADD_WEIGHTEDX( 0, 0, 0); ADD_WEIGHTEDX( 1, 0, 0);
+ ADD_WEIGHTEDX(-1, 1, 0); ADD_WEIGHTEDX( 0, 1, 0); ADD_WEIGHTEDX( 1, 1, 0);
+
+ ADD_WEIGHTEDX(-1,-1, 1); ADD_WEIGHTEDX( 0,-1, 1); ADD_WEIGHTEDX( 1,-1, 1);
+ ADD_WEIGHTEDX(-1, 0, 1); ADD_WEIGHTEDX( 0, 0, 1); ADD_WEIGHTEDX( 1, 0, 1);
+ ADD_WEIGHTEDX(-1, 1, 1); ADD_WEIGHTEDX( 0, 1, 1); ADD_WEIGHTEDX( 1, 1, 1);
+ final[0] = result;
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // y derivative
+ ///////////////////////////////////////////////////////////////////////////////////////
+ result = 0.0f;
+ ADD_WEIGHTEDY(-1,-1, -1); ADD_WEIGHTEDY( 0,-1, -1); ADD_WEIGHTEDY( 1,-1, -1);
+ ADD_WEIGHTEDY(-1, 0, -1); ADD_WEIGHTEDY( 0, 0, -1); ADD_WEIGHTEDY( 1, 0, -1);
+ ADD_WEIGHTEDY(-1, 1, -1); ADD_WEIGHTEDY( 0, 1, -1); ADD_WEIGHTEDY( 1, 1, -1);
+
+ ADD_WEIGHTEDY(-1,-1, 0); ADD_WEIGHTEDY( 0,-1, 0); ADD_WEIGHTEDY( 1,-1, 0);
+ ADD_WEIGHTEDY(-1, 0, 0); ADD_WEIGHTEDY( 0, 0, 0); ADD_WEIGHTEDY( 1, 0, 0);
+ ADD_WEIGHTEDY(-1, 1, 0); ADD_WEIGHTEDY( 0, 1, 0); ADD_WEIGHTEDY( 1, 1, 0);
+
+ ADD_WEIGHTEDY(-1,-1, 1); ADD_WEIGHTEDY( 0,-1, 1); ADD_WEIGHTEDY( 1,-1, 1);
+ ADD_WEIGHTEDY(-1, 0, 1); ADD_WEIGHTEDY( 0, 0, 1); ADD_WEIGHTEDY( 1, 0, 1);
+ ADD_WEIGHTEDY(-1, 1, 1); ADD_WEIGHTEDY( 0, 1, 1); ADD_WEIGHTEDY( 1, 1, 1);
+ final[1] = result;
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // z derivative
+ ///////////////////////////////////////////////////////////////////////////////////////
+ result = 0.0f;
+ ADD_WEIGHTEDZ(-1,-1, -1); ADD_WEIGHTEDZ( 0,-1, -1); ADD_WEIGHTEDZ( 1,-1, -1);
+ ADD_WEIGHTEDZ(-1, 0, -1); ADD_WEIGHTEDZ( 0, 0, -1); ADD_WEIGHTEDZ( 1, 0, -1);
+ ADD_WEIGHTEDZ(-1, 1, -1); ADD_WEIGHTEDZ( 0, 1, -1); ADD_WEIGHTEDZ( 1, 1, -1);
+
+ ADD_WEIGHTEDZ(-1,-1, 0); ADD_WEIGHTEDZ( 0,-1, 0); ADD_WEIGHTEDZ( 1,-1, 0);
+ ADD_WEIGHTEDZ(-1, 0, 0); ADD_WEIGHTEDZ( 0, 0, 0); ADD_WEIGHTEDZ( 1, 0, 0);
+ ADD_WEIGHTEDZ(-1, 1, 0); ADD_WEIGHTEDZ( 0, 1, 0); ADD_WEIGHTEDZ( 1, 1, 0);
+
+ ADD_WEIGHTEDZ(-1,-1, 1); ADD_WEIGHTEDZ( 0,-1, 1); ADD_WEIGHTEDZ( 1,-1, 1);
+ ADD_WEIGHTEDZ(-1, 0, 1); ADD_WEIGHTEDZ( 0, 0, 1); ADD_WEIGHTEDZ( 1, 0, 1);
+ ADD_WEIGHTEDZ(-1, 1, 1); ADD_WEIGHTEDZ( 0, 1, 1); ADD_WEIGHTEDZ( 1, 1, 1);
+ final[2] = result;
+
+ //debMsg("FINAL","at "<<p<<" = "<<final); // DEBUG
+ return final;
+}
+#undef ADD_WEIGHTEDX
+#undef ADD_WEIGHTEDY
+#undef ADD_WEIGHTEDZ
+
+inline Real WaveletNoiseField::evaluate(Vec3 pos, int tile) const {
+ pos[0] *= mGsInvX;
+ pos[1] *= mGsInvY;
+ pos[2] *= mGsInvZ;
+ pos += mSeedOffset;
+
+ // time anim
+ pos += Vec3(getTime());
+
+ pos[0] *= mPosScale[0];
+ pos[1] *= mPosScale[1];
+ pos[2] *= mPosScale[2];
+ pos += mPosOffset;
+
+ const int n3 = square(NOISE_TILE_SIZE) * NOISE_TILE_SIZE;
+ Real v = WNoise(pos, &mNoiseTile[tile*n3]);
+
+ v += mValOffset;
+ v *= mValScale;
+ if (mClamp) {
+ if (v< mClampNeg) v = mClampNeg;
+ if (v> mClampPos) v = mClampPos;
+ }
+ return v;
+}
+
+inline Vec3 WaveletNoiseField::evaluateVec(Vec3 pos, int tile) const {
+ pos[0] *= mGsInvX;
+ pos[1] *= mGsInvY;
+ pos[2] *= mGsInvZ;
+ pos += mSeedOffset;
+
+ // time anim
+ pos += Vec3(getTime());
+
+ pos[0] *= mPosScale[0];
+ pos[1] *= mPosScale[1];
+ pos[2] *= mPosScale[2];
+ pos += mPosOffset;
+
+ const int n3 = square(NOISE_TILE_SIZE) * NOISE_TILE_SIZE;
+ Vec3 v = WNoiseVec(pos, &mNoiseTile[tile*n3]);
+
+ v += Vec3(mValOffset);
+ v *= mValScale;
+
+ if (mClamp) {
+ for(int i=0; i<3; i++) {
+ if (v[i]< mClampNeg) v[i] = mClampNeg;
+ if (v[i]> mClampPos) v[i] = mClampPos;
+ }
+ }
+ return v;
+}
+
+inline Vec3 WaveletNoiseField::evaluateCurl(Vec3 pos) const {
+ // gradients of w0-w2
+ Vec3 d0 = evaluateVec(pos,0),
+ d1 = evaluateVec(pos,1),
+ d2 = evaluateVec(pos,2);
+
+ return Vec3(d0.y-d1.z, d2.z-d0.x, d1.x-d2.y);
+}
+
+} // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h.reg
new file mode 100644
index 00000000000..74b1bd96478
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h.reg
@@ -0,0 +1,12 @@
+#include "noisefield.h"
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","NoiseField","PbClass"); template<> const char* Namify<WaveletNoiseField >::S = "WaveletNoiseField";
+>WaveletNoiseField^
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","WaveletNoiseField",WaveletNoiseField::_W_0);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","posOffset",WaveletNoiseField::_GET_mPosOffset,WaveletNoiseField::_SET_mPosOffset);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","posScale",WaveletNoiseField::_GET_mPosScale,WaveletNoiseField::_SET_mPosScale);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","valOffset",WaveletNoiseField::_GET_mValOffset,WaveletNoiseField::_SET_mValOffset);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","valScale",WaveletNoiseField::_GET_mValScale,WaveletNoiseField::_SET_mValScale);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","clamp",WaveletNoiseField::_GET_mClamp,WaveletNoiseField::_SET_mClamp);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","clampNeg",WaveletNoiseField::_GET_mClampNeg,WaveletNoiseField::_SET_mClampNeg);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","clampPos",WaveletNoiseField::_GET_mClampPos,WaveletNoiseField::_SET_mClampPos);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","timeAnim",WaveletNoiseField::_GET_mTimeAnim,WaveletNoiseField::_SET_mTimeAnim);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h.reg.cpp
new file mode 100644
index 00000000000..6eed65f816b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/noisefield.h.reg.cpp
@@ -0,0 +1,40 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "noisefield.h"
+namespace Manta {
+#ifdef _C_WaveletNoiseField
+ static const Pb::Register _R_13 ("WaveletNoiseField","NoiseField","PbClass"); template<> const char* Namify<WaveletNoiseField >::S = "WaveletNoiseField";
+ static const Pb::Register _R_14 ("WaveletNoiseField","WaveletNoiseField",WaveletNoiseField::_W_0);
+ static const Pb::Register _R_15 ("WaveletNoiseField","posOffset",WaveletNoiseField::_GET_mPosOffset,WaveletNoiseField::_SET_mPosOffset);
+ static const Pb::Register _R_16 ("WaveletNoiseField","posScale",WaveletNoiseField::_GET_mPosScale,WaveletNoiseField::_SET_mPosScale);
+ static const Pb::Register _R_17 ("WaveletNoiseField","valOffset",WaveletNoiseField::_GET_mValOffset,WaveletNoiseField::_SET_mValOffset);
+ static const Pb::Register _R_18 ("WaveletNoiseField","valScale",WaveletNoiseField::_GET_mValScale,WaveletNoiseField::_SET_mValScale);
+ static const Pb::Register _R_19 ("WaveletNoiseField","clamp",WaveletNoiseField::_GET_mClamp,WaveletNoiseField::_SET_mClamp);
+ static const Pb::Register _R_20 ("WaveletNoiseField","clampNeg",WaveletNoiseField::_GET_mClampNeg,WaveletNoiseField::_SET_mClampNeg);
+ static const Pb::Register _R_21 ("WaveletNoiseField","clampPos",WaveletNoiseField::_GET_mClampPos,WaveletNoiseField::_SET_mClampPos);
+ static const Pb::Register _R_22 ("WaveletNoiseField","timeAnim",WaveletNoiseField::_GET_mTimeAnim,WaveletNoiseField::_SET_mTimeAnim);
+#endif
+extern "C" {
+void PbRegister_file_13()
+{
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.cpp
new file mode 100644
index 00000000000..9af0c53d1d3
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.cpp
@@ -0,0 +1,1060 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2013 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Particle data functionality
+ *
+ ******************************************************************************/
+
+#include <fstream>
+#include <cstring>
+#if NO_ZLIB!=1
+#include <zlib.h>
+#endif
+#include "particle.h"
+#include "levelset.h"
+#include "mantaio.h"
+
+using namespace std;
+namespace Manta {
+
+
+ParticleBase::ParticleBase(FluidSolver* parent)
+ : PbClass(parent), mAllowCompress(true), mFreePdata(false)
+{
+}
+
+ParticleBase::~ParticleBase()
+{
+ // make sure data fields now parent system is deleted
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i)
+ mPartData[i]->setParticleSys(NULL);
+
+ if(mFreePdata) {
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i)
+ delete mPartData[i];
+ }
+
+}
+
+std::string ParticleBase::infoString() const
+{
+ return "ParticleSystem " + mName + " <no info>";
+}
+
+void ParticleBase::cloneParticleData(ParticleBase* nm)
+{
+ // clone additional data , and make sure the copied particle system deletes it
+ nm->mFreePdata = true;
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i) {
+ ParticleDataBase* pdata = mPartData[i]->clone();
+ nm->registerPdata(pdata);
+ }
+}
+
+void ParticleBase::deregister(ParticleDataBase* pdata)
+{
+ bool done = false;
+ // remove pointer from particle data list
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i) {
+ if(mPartData[i] == pdata) {
+ if(i<(IndexInt)mPartData.size()-1)
+ mPartData[i] = mPartData[mPartData.size()-1];
+ mPartData.pop_back();
+ done = true;
+ }
+ }
+ if(!done)
+ errMsg("Invalid pointer given, not registered!");
+}
+
+// create and attach a new pdata field to this particle system
+PbClass* ParticleBase::create(PbType t, PbTypeVec T, const string& name)
+{
+# if NOPYTHON!=1
+ _args.add("nocheck",true);
+ if(t.str() == "") errMsg("Specify particle data type to create");
+ //debMsg( "Pdata creating '"<< t.str <<" with size "<< this->getSizeSlow(), 5 );
+
+ PbClass* pyObj = PbClass::createPyObject(t.str() + T.str(), name, _args, this->getParent());
+
+ ParticleDataBase* pdata = dynamic_cast<ParticleDataBase*>(pyObj);
+ if(!pdata) {
+ errMsg("Unable to get particle data pointer from newly created object. Only create ParticleData type with a ParticleSys.creat() call, eg, PdataReal, PdataVec3 etc.");
+ delete pyObj;
+ return NULL;
+ } else {
+ this->registerPdata(pdata);
+ }
+
+ // directly init size of new pdata field:
+ pdata->resize(this->getSizeSlow());
+# else
+ PbClass* pyObj = NULL;
+# endif
+ return pyObj;
+}
+
+void ParticleBase::registerPdata(ParticleDataBase* pdata)
+{
+ pdata->setParticleSys(this);
+ mPartData.push_back(pdata);
+
+ if(pdata->getType() == ParticleDataBase::TypeReal) {
+ ParticleDataImpl<Real>* pd = dynamic_cast< ParticleDataImpl<Real>* >(pdata);
+ if(!pd) errMsg("Invalid pdata object posing as real!");
+ this->registerPdataReal(pd);
+ } else if(pdata->getType() == ParticleDataBase::TypeInt) {
+ ParticleDataImpl<int>* pd = dynamic_cast< ParticleDataImpl<int>* >(pdata);
+ if(!pd) errMsg("Invalid pdata object posing as int!");
+ this->registerPdataInt(pd);
+ } else if(pdata->getType() == ParticleDataBase::TypeVec3) {
+ ParticleDataImpl<Vec3>* pd = dynamic_cast< ParticleDataImpl<Vec3>* >(pdata);
+ if(!pd) errMsg("Invalid pdata object posing as vec3!");
+ this->registerPdataVec3(pd);
+ }
+}
+void ParticleBase::registerPdataReal(ParticleDataImpl<Real>* pd) { mPdataReal.push_back(pd); }
+void ParticleBase::registerPdataVec3(ParticleDataImpl<Vec3>* pd) { mPdataVec3.push_back(pd); }
+void ParticleBase::registerPdataInt (ParticleDataImpl<int >* pd) { mPdataInt .push_back(pd); }
+
+void ParticleBase::addAllPdata()
+{
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i) {
+ mPartData[i]->addEntry();
+ }
+}
+
+
+BasicParticleSystem::BasicParticleSystem(FluidSolver* parent)
+ : ParticleSystem<BasicParticleData>(parent)
+{
+ this->mAllowCompress = false;
+}
+
+// file io
+
+void BasicParticleSystem::writeParticlesText(const string name) const
+{
+ ofstream ofs(name.c_str());
+ if(!ofs.good()) errMsg("can't open file!");
+ ofs << this->size()<<", pdata: "<< mPartData.size()<<" ("<<mPdataInt.size()<<","<<mPdataReal.size()<<","<<mPdataVec3.size()<<") \n";
+ for(IndexInt i=0; i<this->size(); ++i) {
+ ofs << i<<": "<< this->getPos(i) <<" , "<< this->getStatus(i) <<". ";
+ for(IndexInt pd=0; pd<(IndexInt)mPdataInt.size() ; ++pd) ofs << mPdataInt [pd]->get(i)<<" ";
+ for(IndexInt pd=0; pd<(IndexInt)mPdataReal.size(); ++pd) ofs << mPdataReal[pd]->get(i)<<" ";
+ for(IndexInt pd=0; pd<(IndexInt)mPdataVec3.size(); ++pd) ofs << mPdataVec3[pd]->get(i)<<" ";
+ ofs << "\n";
+ }
+ ofs.close();
+}
+
+void BasicParticleSystem::writeParticlesRawPositionsGz(const string name) const
+{
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "wb1");
+ if(!gzf) errMsg("can't open file "<<name);
+ for(IndexInt i=0; i<this->size(); ++i) {
+ Vector3D<float> p = toVec3f(this->getPos(i));
+ gzwrite(gzf, &p, sizeof(float)*3);
+ }
+ gzclose(gzf);
+# else
+ cout << "file format not supported without zlib" << endl;
+# endif
+}
+
+void BasicParticleSystem::writeParticlesRawVelocityGz(const string name) const
+{
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "wb1");
+ if (!gzf) errMsg("can't open file "<<name);
+ if( mPdataVec3.size() < 1 ) errMsg("no vec3 particle data channel found!");
+ // note , assuming particle data vec3 0 is velocity! make optional...
+ for(IndexInt i=0; i<this->size(); ++i) {
+ Vector3D<float> p = toVec3f(mPdataVec3[0]->get(i));
+ gzwrite(gzf, &p, sizeof(float)*3);
+ }
+ gzclose(gzf);
+# else
+ cout << "file format not supported without zlib" << endl;
+# endif
+}
+
+
+void BasicParticleSystem::load(const string name)
+{
+ if(name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if(ext == ".uni")
+ readParticlesUni(name, this );
+ else if(ext == ".raw") // raw = uni for now
+ readParticlesUni(name, this );
+ else
+ errMsg("particle '" + name +"' filetype not supported for loading");
+}
+
+void BasicParticleSystem::save(const string name) const
+{
+ if(name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if(ext == ".txt")
+ this->writeParticlesText(name);
+ else if(ext == ".uni")
+ writeParticlesUni(name, this);
+ else if(ext == ".raw") // raw = uni for now
+ writeParticlesUni(name, this);
+ // raw data formats, very basic for simple data transfer to other programs
+ else if(ext == ".posgz")
+ this->writeParticlesRawPositionsGz(name);
+ else if(ext == ".velgz")
+ this->writeParticlesRawVelocityGz(name);
+ else
+ errMsg("particle '" + name +"' filetype not supported for saving");
+}
+
+void BasicParticleSystem::printParts(IndexInt start, IndexInt stop, bool printIndex)
+{
+ std::ostringstream sstr;
+ IndexInt s = (start>0 ? start : 0 );
+ IndexInt e = (stop>0 ? stop : (IndexInt)mData.size() );
+ s = Manta::clamp(s, (IndexInt)0, (IndexInt)mData.size());
+ e = Manta::clamp(e, (IndexInt)0, (IndexInt)mData.size());
+
+ for(IndexInt i=s; i<e; ++i) {
+ if(printIndex) sstr << i<<": ";
+ sstr<<mData[i].pos<<" "<<mData[i].flag<<"\n";
+ }
+ debMsg( sstr.str() , 1 );
+}
+
+std::string BasicParticleSystem::getDataPointer() {
+ std::ostringstream out;
+ out << &mData;
+ return out.str();
+}
+
+void BasicParticleSystem::readParticles(BasicParticleSystem* from) {
+ // re-allocate all data
+ this->resizeAll(from->size());
+ assertMsg(from->size() == this->size() , "particle size doesn't match");
+
+ for(int i=0; i<this->size(); ++i) {
+ (*this)[i].pos = (*from)[i].pos;
+ (*this)[i].flag = (*from)[i].flag;
+ }
+ this->transformPositions(from->getParent()->getGridSize(), this->getParent()->getGridSize());
+}
+
+
+// particle data
+
+ParticleDataBase::ParticleDataBase(FluidSolver* parent)
+ : PbClass(parent), mpParticleSys(NULL)
+{
+}
+
+ParticleDataBase::~ParticleDataBase()
+{
+ // notify parent of deletion
+ if(mpParticleSys)
+ mpParticleSys->deregister(this);
+}
+
+
+// actual data implementation
+
+template<class T>
+ParticleDataImpl<T>::ParticleDataImpl(FluidSolver* parent)
+ : ParticleDataBase(parent), mpGridSource(NULL), mGridSourceMAC(false)
+{
+}
+
+template<class T>
+ParticleDataImpl<T>::ParticleDataImpl(FluidSolver* parent, ParticleDataImpl<T>* other)
+ : ParticleDataBase(parent), mpGridSource(NULL), mGridSourceMAC(false)
+{
+ this->mData = other->mData;
+ setName(other->getName());
+}
+
+template<class T>
+ParticleDataImpl<T>::~ParticleDataImpl()
+{
+}
+
+template<class T>
+IndexInt ParticleDataImpl<T>::getSizeSlow() const
+{
+ return mData.size();
+}
+template<class T>
+void ParticleDataImpl<T>::addEntry()
+{
+ // add zero'ed entry
+ T tmp = T(0.);
+ // for debugging, force init:
+ //tmp = T(0.02 * mData.size()); // increasing
+ //tmp = T(1.); // constant 1
+ return mData.push_back(tmp);
+}
+template<class T>
+void ParticleDataImpl<T>::resize(IndexInt s)
+{
+ mData.resize(s);
+}
+template<class T>
+void ParticleDataImpl<T>::copyValueSlow(IndexInt from, IndexInt to)
+{
+ this->copyValue(from,to);
+}
+template<class T>
+ParticleDataBase* ParticleDataImpl<T>::clone()
+{
+ ParticleDataImpl<T>* npd = new ParticleDataImpl<T>(getParent(), this);
+ return npd;
+}
+
+template<class T>
+void ParticleDataImpl<T>::setSource(Grid<T>* grid, bool isMAC)
+{
+ mpGridSource = grid;
+ mGridSourceMAC = isMAC;
+ if(isMAC) assertMsg(dynamic_cast<MACGrid*>(grid) != NULL , "Given grid is not a valid MAC grid");
+}
+
+template<class T>
+void ParticleDataImpl<T>::initNewValue(IndexInt idx, Vec3 pos)
+{
+ if(!mpGridSource)
+ mData[idx] = 0;
+ else {
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ }
+}
+// special handling needed for velocities
+template<>
+void ParticleDataImpl<Vec3>::initNewValue(IndexInt idx, Vec3 pos)
+{
+ if(!mpGridSource)
+ mData[idx] = 0;
+ else {
+ if(!mGridSourceMAC)
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ else
+ mData[idx] = ((MACGrid*)mpGridSource)->getInterpolated(pos);
+ }
+}
+
+template<typename T>
+void ParticleDataImpl<T>::load(string name)
+{
+ if(name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if(ext == ".uni")
+ readPdataUni<T>(name, this);
+ else if(ext == ".raw") // raw = uni for now
+ readPdataUni<T>(name, this);
+ else
+ errMsg("particle data '" + name +"' filetype not supported for loading");
+}
+
+template<typename T>
+void ParticleDataImpl<T>::save(string name)
+{
+ if(name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if(ext == ".uni")
+ writePdataUni<T>(name, this);
+ else if(ext == ".raw") // raw = uni for now
+ writePdataUni<T>(name, this);
+ else
+ errMsg("particle data '" + name +"' filetype not supported for saving");
+}
+
+// specializations
+
+template<>
+ParticleDataBase::PdataType ParticleDataImpl<Real>::getType() const
+{
+ return ParticleDataBase::TypeReal;
+}
+template<>
+ParticleDataBase::PdataType ParticleDataImpl<int>::getType() const
+{
+ return ParticleDataBase::TypeInt;
+}
+template<>
+ParticleDataBase::PdataType ParticleDataImpl<Vec3>::getType() const
+{
+ return ParticleDataBase::TypeVec3;
+}
+
+// note, we need a flag value for functions such as advection
+// ideally, this value should never be modified
+int ParticleIndexData::flag = 0;
+Vec3 ParticleIndexData::pos = Vec3(0.,0.,0.);
+
+template <class T, class S> struct knPdataAdd : public KernelBase {
+ knPdataAdd(ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) { me[idx] += other[idx]; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<S>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knPdataAdd ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<S>& other; }
+;
+template <class T, class S> struct knPdataSub : public KernelBase {
+ knPdataSub(ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) { me[idx] -= other[idx]; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<S>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knPdataSub ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<S>& other; }
+;
+template <class T, class S> struct knPdataMult : public KernelBase {
+ knPdataMult(ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) { me[idx] *= other[idx]; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<S>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knPdataMult ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<S>& other; }
+;
+template <class T, class S> struct knPdataDiv : public KernelBase {
+ knPdataDiv(ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) { me[idx] /= other[idx]; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<S>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knPdataDiv ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<S>& other; }
+;
+template <class T> struct knPdataSafeDiv : public KernelBase {
+ knPdataSafeDiv(ParticleDataImpl<T>& me, const ParticleDataImpl<T>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<T>& other ) { me[idx] = safeDivide(me[idx], other[idx]); } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<T>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<T> type1; void runMessage() { debMsg("Executing kernel knPdataSafeDiv ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<T>& other; }
+;
+
+template <class T, class S> struct knPdataSetScalar : public KernelBase {
+ knPdataSetScalar(ParticleDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const S& other ) { me[idx] = other; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knPdataSetScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ ParticleDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knPdataAddScalar : public KernelBase {
+ knPdataAddScalar(ParticleDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const S& other ) { me[idx] += other; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knPdataAddScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ ParticleDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knPdataMultScalar : public KernelBase {
+ knPdataMultScalar(ParticleDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const S& other ) { me[idx] *= other; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knPdataMultScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other); }
+ }
+ ParticleDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knPdataScaledAdd : public KernelBase {
+ knPdataScaledAdd(ParticleDataImpl<T>& me, const ParticleDataImpl<T>& other, const S& factor) : KernelBase(me.size()) ,me(me),other(other),factor(factor) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<T>& other, const S& factor ) { me[idx] += factor * other[idx]; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<T>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<T> type1;inline const S& getArg2() {
+ return factor; }
+ typedef S type2; void runMessage() { debMsg("Executing kernel knPdataScaledAdd ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other,factor); }
+ }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<T>& other; const S& factor; }
+;
+
+template <class T> struct knPdataClamp : public KernelBase {
+ knPdataClamp(ParticleDataImpl<T>& me, const T vmin, const T vmax) : KernelBase(me.size()) ,me(me),vmin(vmin),vmax(vmax) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const T vmin, const T vmax ) { me[idx] = clamp(me[idx], vmin, vmax); } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const T& getArg1() {
+ return vmin; }
+ typedef T type1;inline const T& getArg2() {
+ return vmax; }
+ typedef T type2; void runMessage() { debMsg("Executing kernel knPdataClamp ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,vmin,vmax); }
+ }
+ ParticleDataImpl<T>& me; const T vmin; const T vmax; }
+;
+template <class T> struct knPdataClampMin : public KernelBase {
+ knPdataClampMin(ParticleDataImpl<T>& me, const T vmin) : KernelBase(me.size()) ,me(me),vmin(vmin) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const T vmin ) { me[idx] = std::max(vmin, me[idx]); } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const T& getArg1() {
+ return vmin; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knPdataClampMin ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,vmin); }
+ }
+ ParticleDataImpl<T>& me; const T vmin; }
+;
+template <class T> struct knPdataClampMax : public KernelBase {
+ knPdataClampMax(ParticleDataImpl<T>& me, const T vmax) : KernelBase(me.size()) ,me(me),vmax(vmax) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const T vmax ) { me[idx] = std::min(vmax, me[idx]); } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const T& getArg1() {
+ return vmax; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knPdataClampMax ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,vmax); }
+ }
+ ParticleDataImpl<T>& me; const T vmax; }
+;
+
+ struct knPdataClampMinVec3 : public KernelBase {
+ knPdataClampMinVec3(ParticleDataImpl<Vec3>& me, const Real vmin) : KernelBase(me.size()) ,me(me),vmin(vmin) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<Vec3>& me, const Real vmin ) {
+ me[idx].x = std::max(vmin, me[idx].x);
+ me[idx].y = std::max(vmin, me[idx].y);
+ me[idx].z = std::max(vmin, me[idx].z);
+} inline ParticleDataImpl<Vec3>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<Vec3> type0;inline const Real& getArg1() {
+ return vmin; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knPdataClampMinVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,vmin); }
+ }
+ ParticleDataImpl<Vec3>& me; const Real vmin; }
+;
+
+ struct knPdataClampMaxVec3 : public KernelBase {
+ knPdataClampMaxVec3(ParticleDataImpl<Vec3>& me, const Real vmax) : KernelBase(me.size()) ,me(me),vmax(vmax) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<Vec3>& me, const Real vmax ) {
+ me[idx].x = std::min(vmax, me[idx].x);
+ me[idx].y = std::min(vmax, me[idx].y);
+ me[idx].z = std::min(vmax, me[idx].z);
+} inline ParticleDataImpl<Vec3>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<Vec3> type0;inline const Real& getArg1() {
+ return vmax; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knPdataClampMaxVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,vmax); }
+ }
+ ParticleDataImpl<Vec3>& me; const Real vmax; }
+;
+
+// python operators
+
+
+template<typename T>
+ParticleDataImpl<T>& ParticleDataImpl<T>::copyFrom(const ParticleDataImpl<T>& a)
+{
+ assertMsg(a.mData.size() == mData.size() , "different pdata size "<<a.mData.size()<<" vs "<<this->mData.size());
+ mData = a.mData;
+ return *this;
+}
+
+template<typename T>
+void ParticleDataImpl<T>::setConst(const T &s)
+{
+ knPdataSetScalar<T,T> op( *this, s );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::setConstRange(const T &s, const int begin, const int end)
+{
+ for(int i=begin; i<end; ++i) (*this)[i] = s;
+}
+
+// special set by flag
+
+template <class T, class S> struct knPdataSetScalarIntFlag : public KernelBase {
+ knPdataSetScalarIntFlag(ParticleDataImpl<T> &me, const S &other, const ParticleDataImpl<int> &t, const int itype) : KernelBase(me.size()) ,me(me),other(other),t(t),itype(itype) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const S &other, const ParticleDataImpl<int> &t, const int itype ) {
+ if(t[idx]&itype) me[idx] = other;
+} inline ParticleDataImpl<T> & getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1;inline const ParticleDataImpl<int> & getArg2() {
+ return t; }
+ typedef ParticleDataImpl<int> type2;inline const int& getArg3() {
+ return itype; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel knPdataSetScalarIntFlag ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other,t,itype); }
+ }
+ ParticleDataImpl<T> & me; const S& other; const ParticleDataImpl<int> & t; const int itype; }
+;
+template<typename T>
+void ParticleDataImpl<T>::setConstIntFlag(const T &s, const ParticleDataImpl<int> &t, const int itype)
+{
+ knPdataSetScalarIntFlag<T,T> op(*this, s, t, itype);
+}
+
+template<typename T>
+void ParticleDataImpl<T>::add(const ParticleDataImpl<T>& a)
+{
+ knPdataAdd<T,T> op( *this, a );
+}
+template<typename T>
+void ParticleDataImpl<T>::sub(const ParticleDataImpl<T>& a)
+{
+ knPdataSub<T,T> op( *this, a );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::addConst(const T &s)
+{
+ knPdataAddScalar<T,T> op( *this, s );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::addScaled(const ParticleDataImpl<T>& a, const T& factor)
+{
+ knPdataScaledAdd<T,T> op( *this, a, factor );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::mult(const ParticleDataImpl<T>& a)
+{
+ knPdataMult<T,T> op( *this, a );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::safeDiv(const ParticleDataImpl<T>& a)
+{
+ knPdataSafeDiv<T> op( *this, a );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::multConst(const T &s)
+{
+ knPdataMultScalar<T,T> op( *this, s );
+}
+
+
+template<typename T>
+void ParticleDataImpl<T>::clamp(const Real vmin, const Real vmax)
+{
+ knPdataClamp<T> op( *this, vmin, vmax );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::clampMin(const Real vmin)
+{
+ knPdataClampMin<T> op( *this, vmin );
+}
+template<typename T>
+void ParticleDataImpl<T>::clampMax(const Real vmax)
+{
+ knPdataClampMax<T> op( *this, vmax );
+}
+
+template<>
+void ParticleDataImpl<Vec3>::clampMin(const Real vmin)
+{
+ knPdataClampMinVec3 op( *this, vmin );
+}
+template<>
+void ParticleDataImpl<Vec3>::clampMax(const Real vmax)
+{
+ knPdataClampMaxVec3 op( *this, vmax );
+}
+
+template<typename T> struct KnPtsSum : public KernelBase {
+ KnPtsSum(const ParticleDataImpl<T>& val, const ParticleDataImpl<int> *t, const int itype) : KernelBase(val.size()) ,val(val),t(t),itype(itype) ,result(T(0.)) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<T>& val, const ParticleDataImpl<int> *t, const int itype ,T& result) { if(t && !((*t)[idx]&itype)) return; result += val[idx]; } inline operator T () {
+ return result; }
+ inline T & getRet() {
+ return result; }
+ inline const ParticleDataImpl<T>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<int> * getArg1() {
+ return t; }
+ typedef ParticleDataImpl<int> type1;inline const int& getArg2() {
+ return itype; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel KnPtsSum ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ T result = T(0.);
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,t,itype,result);
+#pragma omp critical
+{this->result += result; } }
+ }
+ const ParticleDataImpl<T>& val; const ParticleDataImpl<int> * t; const int itype; T result; }
+;
+template<typename T> struct KnPtsSumSquare : public KernelBase {
+ KnPtsSumSquare(const ParticleDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,result(0.) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<T>& val ,Real& result) { result += normSquare(val[idx]); } inline operator Real () {
+ return result; }
+ inline Real & getRet() {
+ return result; }
+ inline const ParticleDataImpl<T>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<T> type0; void runMessage() { debMsg("Executing kernel KnPtsSumSquare ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real result = 0.;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,result);
+#pragma omp critical
+{this->result += result; } }
+ }
+ const ParticleDataImpl<T>& val; Real result; }
+;
+template<typename T> struct KnPtsSumMagnitude : public KernelBase {
+ KnPtsSumMagnitude(const ParticleDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,result(0.) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<T>& val ,Real& result) { result += norm(val[idx]); } inline operator Real () {
+ return result; }
+ inline Real & getRet() {
+ return result; }
+ inline const ParticleDataImpl<T>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<T> type0; void runMessage() { debMsg("Executing kernel KnPtsSumMagnitude ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real result = 0.;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,result);
+#pragma omp critical
+{this->result += result; } }
+ }
+ const ParticleDataImpl<T>& val; Real result; }
+;
+
+template<typename T>
+T ParticleDataImpl<T>::sum(const ParticleDataImpl<int> *t, const int itype) const
+{
+ return KnPtsSum<T>(*this, t, itype);
+}
+template<typename T>
+Real ParticleDataImpl<T>::sumSquare() const
+{
+ return KnPtsSumSquare<T>(*this);
+}
+template<typename T>
+Real ParticleDataImpl<T>::sumMagnitude() const
+{
+ return KnPtsSumMagnitude<T>(*this);
+}
+
+template<typename T>
+
+
+ struct CompPdata_Min : public KernelBase {
+ CompPdata_Min(const ParticleDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<T>& val ,Real& minVal) {
+ if(val[idx] < minVal) minVal = val[idx];
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const ParticleDataImpl<T>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<T> type0; void runMessage() { debMsg("Executing kernel CompPdata_Min ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real minVal = std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,minVal);
+#pragma omp critical
+{this->minVal = min(minVal, this->minVal); } }
+ }
+ const ParticleDataImpl<T>& val; Real minVal; }
+;
+
+template<typename T>
+
+
+ struct CompPdata_Max : public KernelBase {
+ CompPdata_Max(const ParticleDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<T>& val ,Real& maxVal) {
+ if(val[idx] > maxVal) maxVal = val[idx];
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const ParticleDataImpl<T>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<T> type0; void runMessage() { debMsg("Executing kernel CompPdata_Max ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real maxVal = -std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,maxVal);
+#pragma omp critical
+{this->maxVal = max(maxVal, this->maxVal); } }
+ }
+ const ParticleDataImpl<T>& val; Real maxVal; }
+;
+
+template<typename T>
+Real ParticleDataImpl<T>::getMin() const
+{
+ return CompPdata_Min<T>(*this);
+}
+
+template<typename T>
+Real ParticleDataImpl<T>::getMaxAbs() const
+{
+ Real amin = CompPdata_Min<T>(*this);
+ Real amax = CompPdata_Max<T>(*this);
+ return max(fabs(amin), fabs(amax));
+}
+
+template<typename T>
+Real ParticleDataImpl<T>::getMax() const
+{
+ return CompPdata_Max<T>(*this);
+}
+
+template<typename T>
+void ParticleDataImpl<T>::printPdata(IndexInt start, IndexInt stop, bool printIndex)
+{
+ std::ostringstream sstr;
+ IndexInt s = (start>0 ? start : 0 );
+ IndexInt e = (stop>0 ? stop : (IndexInt)mData.size() );
+ s = Manta::clamp(s, (IndexInt)0, (IndexInt)mData.size());
+ e = Manta::clamp(e, (IndexInt)0, (IndexInt)mData.size());
+
+ for(IndexInt i=s; i<e; ++i) {
+ if(printIndex) sstr << i<<": ";
+ sstr<<mData[i]<<" "<<"\n";
+ }
+ debMsg( sstr.str() , 1 );
+}
+template<class T> std::string ParticleDataImpl<T>::getDataPointer() {
+ std::ostringstream out;
+ out << &mData;
+ return out.str();
+}
+
+// specials for vec3
+// work on length values, ie, always positive (in contrast to scalar versions above)
+
+
+
+ struct CompPdata_MinVec3 : public KernelBase {
+ CompPdata_MinVec3(const ParticleDataImpl<Vec3>& val) : KernelBase(val.size()) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<Vec3>& val ,Real& minVal) {
+ const Real s = normSquare(val[idx]);
+ if(s < minVal) minVal = s;
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const ParticleDataImpl<Vec3>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<Vec3> type0; void runMessage() { debMsg("Executing kernel CompPdata_MinVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real minVal = std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,minVal);
+#pragma omp critical
+{this->minVal = min(minVal, this->minVal); } }
+ }
+ const ParticleDataImpl<Vec3>& val; Real minVal; }
+;
+
+
+
+ struct CompPdata_MaxVec3 : public KernelBase {
+ CompPdata_MaxVec3(const ParticleDataImpl<Vec3>& val) : KernelBase(val.size()) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<Vec3>& val ,Real& maxVal) {
+ const Real s = normSquare(val[idx]);
+ if(s > maxVal) maxVal = s;
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const ParticleDataImpl<Vec3>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<Vec3> type0; void runMessage() { debMsg("Executing kernel CompPdata_MaxVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ Real maxVal = -std::numeric_limits<Real>::max();
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,val,maxVal);
+#pragma omp critical
+{this->maxVal = max(maxVal, this->maxVal); } }
+ }
+ const ParticleDataImpl<Vec3>& val; Real maxVal; }
+;
+
+template<>
+Real ParticleDataImpl<Vec3>::getMin() const
+{
+ return sqrt(CompPdata_MinVec3(*this));
+}
+
+template<>
+Real ParticleDataImpl<Vec3>::getMaxAbs() const
+{
+ return sqrt(CompPdata_MaxVec3(*this)); // no minimum necessary here
+}
+
+template<>
+Real ParticleDataImpl<Vec3>::getMax() const
+{
+ return sqrt(CompPdata_MaxVec3(*this));
+}
+
+
+// explicit instantiation
+template class ParticleDataImpl<int>;
+template class ParticleDataImpl<Real>;
+template class ParticleDataImpl<Vec3>;
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h
new file mode 100644
index 00000000000..a21aee343f4
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h
@@ -0,0 +1,1251 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Base class for particle systems
+ *
+ ******************************************************************************/
+
+#ifndef _PARTICLE_H
+#define _PARTICLE_H
+
+#include <vector>
+#include "grid.h"
+#include "vectorbase.h"
+#include "integrator.h"
+#include "randomstream.h"
+namespace Manta {
+
+// fwd decl
+template<class T> class Grid;
+class ParticleDataBase;
+template<class T> class ParticleDataImpl;
+
+//! Baseclass for particle systems. Does not implement any data
+class ParticleBase : public PbClass {public:
+ enum SystemType { BASE=0, PARTICLE, VORTEX, FILAMENT, FLIP, TURBULENCE, INDEX };
+
+ enum ParticleStatus {
+ PNONE = 0,
+ PNEW = (1<<0), // particles newly created in this step
+ PSPRAY = (1<<1), // secondary particle types
+ PBUBBLE = (1<<2),
+ PFOAM = (1<<3),
+ PTRACER = (1<<4),
+ PDELETE = (1<<10), // mark as deleted, will be deleted in next compress() step
+ PINVALID = (1<<30), // unused
+ };
+
+ ParticleBase(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ParticleBase::ParticleBase" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ParticleBase(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ParticleBase::ParticleBase" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ParticleBase::ParticleBase",e.what()); return -1; }
+ }
+
+ virtual ~ParticleBase();
+
+ //! copy all the particle data thats registered with the other particle system to this one
+ virtual void cloneParticleData(ParticleBase* nm);
+
+ virtual SystemType getType() const { return BASE; }
+ virtual std::string infoString() const;
+ virtual ParticleBase* clone() { assertMsg( false , "Dont use, override..."); return NULL; }
+
+ //! slow virtual function to query size, do not use in kernels! use size() instead
+ virtual IndexInt getSizeSlow() const { assertMsg( false , "Dont use, override..."); return 0; }
+
+ //! add a position as potential candidate for new particle (todo, make usable from parallel threads)
+ inline void addBuffered(const Vec3& pos, int flag=0);
+
+ //! particle data functions
+
+ //! create a particle data object
+ PbClass* create(PbType type, PbTypeVec T=PbTypeVec(), const std::string& name = ""); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleBase* pbo = dynamic_cast<ParticleBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleBase::create" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; PbType type = _args.get<PbType >("type",0,&_lock); PbTypeVec T = _args.getOpt<PbTypeVec >("T",1,PbTypeVec(),&_lock); const std::string& name = _args.getOpt<std::string >("name",2,"",&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->create(type,T,name)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleBase::create" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleBase::create",e.what()); return 0; }
+ }
+
+ //! add a particle data field, set its parent particle-system pointer
+ void registerPdata(ParticleDataBase* pdata);
+ void registerPdataReal(ParticleDataImpl<Real>* pdata);
+ void registerPdataVec3(ParticleDataImpl<Vec3>* pdata);
+ void registerPdataInt (ParticleDataImpl<int >* pdata);
+ //! remove a particle data entry
+ void deregister(ParticleDataBase* pdata);
+ //! add one zero entry to all data fields
+ void addAllPdata();
+ // note - deletion of pdata is handled in compress function
+
+ //! how many are there?
+ IndexInt getNumPdata() const { return mPartData.size(); }
+ //! access one of the fields
+ ParticleDataBase* getPdata(int i) { return mPartData[i]; }
+
+protected:
+ //! new particle candidates
+ std::vector<Vec3> mNewBufferPos;
+ std::vector<int> mNewBufferFlag;
+
+ //! allow automatic compression / resize? disallowed for, eg, flip particle systems
+ bool mAllowCompress;
+
+ //! store particle data , each pointer has its own storage vector of a certain type (int, real, vec3)
+ std::vector<ParticleDataBase*> mPartData;
+ //! lists of different types, for fast operations w/o virtual function calls (all calls necessary per particle)
+ std::vector< ParticleDataImpl<Real> *> mPdataReal;
+ std::vector< ParticleDataImpl<Vec3> *> mPdataVec3;
+ std::vector< ParticleDataImpl<int> *> mPdataInt; //! indicate that pdata of this particle system is copied, and needs to be freed
+ bool mFreePdata; public: PbArgs _args; }
+#define _C_ParticleBase
+;
+
+
+//! Main class for particle systems
+/*! Basetype S must at least contain flag, pos fields */
+template<class S> class ParticleSystem : public ParticleBase {public:
+ ParticleSystem(FluidSolver* parent) :ParticleBase(parent),mDeletes(0),mDeleteChunk(0){} static int _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ParticleSystem::ParticleSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ParticleSystem(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ParticleSystem::ParticleSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::ParticleSystem",e.what()); return -1; }
+ }
+
+ virtual ~ParticleSystem() {};
+
+ virtual SystemType getType() const { return S::getType(); };
+
+ //! accessors
+ inline S& operator[](IndexInt idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const S& operator[](IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ //! return size of container
+ //! note , python binding disabled for now! cannot yet deal with long-long types
+ inline IndexInt size() const { return mData.size(); }
+ //! slow virtual function of base class, also returns size
+ virtual IndexInt getSizeSlow() const { return size(); }
+ //! note , special call for python, note - doesnt support more than 2b parts!
+ int pySize() const { return (int)mData.size(); } static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::pySize" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->pySize()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::pySize" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::pySize",e.what()); return 0; }
+ }
+
+
+ //! query status
+ inline int getStatus(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx].flag; }
+ inline bool isActive(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PDELETE) == 0; }
+ inline bool isSpray(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PSPRAY); }
+ inline bool isBubble(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PBUBBLE); }
+ inline bool isFoam(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PFOAM); }
+ inline bool isTracer(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PTRACER); }
+
+ //! update status
+ inline void setStatus(IndexInt idx, const int status) { DEBUG_ONLY(checkPartIndex(idx)); mData[idx].flag = status; }
+
+ //! safe accessor for python
+ void setPos(const IndexInt idx, const Vec3& pos) { DEBUG_ONLY(checkPartIndex(idx)); mData[idx].pos = pos; } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::setPos" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const IndexInt idx = _args.get<IndexInt >("idx",0,&_lock); const Vec3& pos = _args.get<Vec3 >("pos",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setPos(idx,pos); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::setPos" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::setPos",e.what()); return 0; }
+ }
+
+ const Vec3& getPos(const IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx].pos; } static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::getPos" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const IndexInt idx = _args.get<IndexInt >("idx",0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->getPos(idx)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::getPos" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::getPos",e.what()); return 0; }
+ }
+
+ //! copy all positions into pdata vec3 field
+ void getPosPdata(ParticleDataImpl<Vec3>& target) const ; static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::getPosPdata" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; ParticleDataImpl<Vec3>& target = *_args.getPtr<ParticleDataImpl<Vec3> >("target",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->getPosPdata(target); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::getPosPdata" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::getPosPdata",e.what()); return 0; }
+ }
+
+ void setPosPdata(const ParticleDataImpl<Vec3>& source); static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::setPosPdata" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<Vec3>& source = *_args.getPtr<ParticleDataImpl<Vec3> >("source",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setPosPdata(source); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::setPosPdata" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::setPosPdata",e.what()); return 0; }
+ }
+
+ //! transform coordinate system from one grid size to another (usually upon load)
+ void transformPositions( Vec3i dimOld, Vec3i dimNew );
+
+ //! explicitly trigger compression from outside
+ void doCompress() { if ( mDeletes > mDeleteChunk) compress(); }
+ //! insert buffered positions as new particles, update additional particle data
+ void insertBufferedParticles();
+ //! resize data vector, and all pdata fields
+ void resizeAll(IndexInt newsize);
+
+ //! adding and deleting
+ inline void kill(IndexInt idx);
+ IndexInt add(const S& data);
+ //! remove all particles, init 0 length arrays (also pdata)
+ void clear(); static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::clear",e.what()); return 0; }
+ }
+
+
+ //! Advect particle in grid velocity field
+ void advectInGrid(const FlagGrid &flags, const MACGrid &vel, const int integrationMode, const bool deleteInObstacle=true, const bool stopInObstacle=true, const ParticleDataImpl<int> *ptype=NULL, const int exclude=0); static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::advectInGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const int integrationMode = _args.get<int >("integrationMode",2,&_lock); const bool deleteInObstacle = _args.getOpt<bool >("deleteInObstacle",3,true,&_lock); const bool stopInObstacle = _args.getOpt<bool >("stopInObstacle",4,true,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",5,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",6,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->advectInGrid(flags,vel,integrationMode,deleteInObstacle,stopInObstacle,ptype,exclude); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::advectInGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::advectInGrid",e.what()); return 0; }
+ }
+
+
+ //! Project particles outside obstacles
+ void projectOutside(Grid<Vec3> &gradient); static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::projectOutside" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3> & gradient = *_args.getPtr<Grid<Vec3> >("gradient",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->projectOutside(gradient); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::projectOutside" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::projectOutside",e.what()); return 0; }
+ }
+
+ void projectOutOfBnd(const FlagGrid &flags, const Real bnd, const std::string &plane="xXyYzZ", const ParticleDataImpl<int> *ptype=NULL, const int exclude=0); static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::projectOutOfBnd" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const Real bnd = _args.get<Real >("bnd",1,&_lock); const std::string& plane = _args.getOpt<std::string >("plane",2,"xXyYzZ",&_lock); const ParticleDataImpl<int> * ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",3,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",4,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->projectOutOfBnd(flags,bnd,plane,ptype,exclude); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::projectOutOfBnd" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::projectOutOfBnd",e.what()); return 0; }
+ }
+
+
+ virtual ParticleBase* clone();
+ virtual std::string infoString() const;
+
+ //! debugging
+ inline void checkPartIndex(IndexInt idx) const;
+
+protected:
+ //! deletion count , and interval for re-compressing
+ IndexInt mDeletes, mDeleteChunk;
+ //! the particle data
+ std::vector<S> mData;
+ //! reduce storage , called by doCompress
+ virtual void compress(); public: PbArgs _args; }
+#define _C_ParticleSystem
+;
+
+//******************************************************************************
+
+//! Simplest data class for particle systems
+//! contains a position and an int flag; note that these are deprectated, and will at
+//! some point be replaced by the more flexible pdata fields. For now manually copy with
+//! getPosPdata / setPosPdata.
+struct BasicParticleData {
+public:
+ BasicParticleData() : pos(0.), flag(0) {}
+ BasicParticleData(const Vec3& p) : pos(p), flag(0) {}
+ static ParticleBase::SystemType getType() { return ParticleBase::PARTICLE; }
+
+ //! data (note, this size is currently hard coded for uni i/o)
+ Vec3 pos;
+ int flag;
+};
+
+class BasicParticleSystem : public ParticleSystem<BasicParticleData> {public:
+ BasicParticleSystem(FluidSolver* parent); static int _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "BasicParticleSystem::BasicParticleSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new BasicParticleSystem(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"BasicParticleSystem::BasicParticleSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::BasicParticleSystem",e.what()); return -1; }
+ }
+
+
+ //! file io
+ void save(const std::string name) const ; static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::save",e.what()); return 0; }
+ }
+
+ void load(const std::string name); static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::load",e.what()); return 0; }
+ }
+
+
+ //! save to text file
+ void writeParticlesText(const std::string name) const;
+ //! other output formats
+ void writeParticlesRawPositionsGz(const std::string name) const;
+ void writeParticlesRawVelocityGz(const std::string name) const;
+
+ //! read from other particle system (with resize)
+ void readParticles(BasicParticleSystem* from); static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::readParticles" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem* from = _args.getPtr<BasicParticleSystem >("from",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->readParticles(from); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::readParticles" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::readParticles",e.what()); return 0; }
+ }
+
+
+ //! add particles in python
+ void addParticle(Vec3 pos) { add(BasicParticleData(pos)); } static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::addParticle" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 pos = _args.get<Vec3 >("pos",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addParticle(pos); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::addParticle" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::addParticle",e.what()); return 0; }
+ }
+
+
+ //! dangerous, get low level access - avoid usage, only used in vortex filament advection for now
+ std::vector<BasicParticleData>& getData() { return mData; }
+
+ void printParts(IndexInt start=-1, IndexInt stop=-1, bool printIndex=false); static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::printParts" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; IndexInt start = _args.getOpt<IndexInt >("start",0,-1,&_lock); IndexInt stop = _args.getOpt<IndexInt >("stop",1,-1,&_lock); bool printIndex = _args.getOpt<bool >("printIndex",2,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->printParts(start,stop,printIndex); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::printParts" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::printParts",e.what()); return 0; }
+ }
+
+ //! get data pointer of particle data
+ std::string getDataPointer(); static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::getDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::getDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::getDataPointer",e.what()); return 0; }
+ }
+ public: PbArgs _args; }
+#define _C_BasicParticleSystem
+;
+
+
+//******************************************************************************
+
+//! Index into other particle system
+// used for grid based neighborhood searches on generic particle systems (stores
+// only active particles, and reduces copied data)
+// note - pos & flag are disabled here, do not use!
+struct ParticleIndexData {
+public:
+ ParticleIndexData() : sourceIndex(0) {}
+ static ParticleBase::SystemType getType() { return ParticleBase::INDEX; }
+
+ IndexInt sourceIndex; // index of this particle in the original particle system
+ //! note - the following two are needed for template instantiation, but not used
+ //! for the particle index system (use values from original one!)
+ static Vec3 pos; // do not use...
+ static int flag; // not needed usally
+ //Vec3 pos; // enable for debugging
+};
+
+class ParticleIndexSystem : public ParticleSystem<ParticleIndexData> {public:
+ ParticleIndexSystem(FluidSolver* parent) :ParticleSystem<ParticleIndexData>(parent){} static int _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ParticleIndexSystem::ParticleIndexSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ParticleIndexSystem(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ParticleIndexSystem::ParticleIndexSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ParticleIndexSystem::ParticleIndexSystem",e.what()); return -1; }
+ }
+;
+ //! we only need a resize function...
+ void resize(IndexInt size) { mData.resize(size); } public: PbArgs _args; }
+#define _C_ParticleIndexSystem
+;
+
+
+
+//******************************************************************************
+
+//! Particle set with connectivity
+
+template<class DATA, class CON> class ConnectedParticleSystem : public ParticleSystem<DATA> {public:
+ ConnectedParticleSystem(FluidSolver* parent) :ParticleSystem<DATA>(parent){} static int _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ConnectedParticleSystem::ConnectedParticleSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ConnectedParticleSystem(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ConnectedParticleSystem::ConnectedParticleSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ConnectedParticleSystem::ConnectedParticleSystem",e.what()); return -1; }
+ }
+
+
+ //! accessors
+ inline bool isSegActive(int i) { return (mSegments[i].flag & ParticleBase::PDELETE) == 0; }
+ inline int segSize() const { return mSegments.size(); }
+ inline CON& seg(int i) { return mSegments[i]; }
+ inline const CON& seg(int i) const { return mSegments[i]; }
+
+ virtual ParticleBase* clone();
+
+protected:
+ std::vector<CON> mSegments; virtual void compress(); public: PbArgs _args; }
+#define _C_ConnectedParticleSystem
+;
+
+//******************************************************************************
+
+//! abstract interface for particle data
+class ParticleDataBase : public PbClass {public:
+ ParticleDataBase(FluidSolver* parent); static int _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ParticleDataBase::ParticleDataBase" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ParticleDataBase(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ParticleDataBase::ParticleDataBase" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataBase::ParticleDataBase",e.what()); return -1; }
+ }
+
+ virtual ~ParticleDataBase();
+
+ //! data type IDs, in line with those for grids
+ enum PdataType { TypeNone = 0, TypeReal = 1, TypeInt = 2, TypeVec3 = 4 };
+
+ //! interface functions, using assert instead of pure virtual for python compatibility
+ virtual IndexInt getSizeSlow() const { assertMsg( false , "Dont use, override..."); return 0; }
+ virtual void addEntry() { assertMsg( false , "Dont use, override..."); return; }
+ virtual ParticleDataBase* clone() { assertMsg( false , "Dont use, override..."); return NULL; }
+ virtual PdataType getType() const { assertMsg( false , "Dont use, override..."); return TypeNone; }
+ virtual void resize(IndexInt size) { assertMsg( false , "Dont use, override..."); return; }
+ virtual void copyValueSlow(IndexInt from, IndexInt to) { assertMsg( false , "Dont use, override..."); return; }
+
+ //! set base pointer
+ void setParticleSys(ParticleBase* set) { mpParticleSys = set; }
+
+ //! debugging
+ inline void checkPartIndex(IndexInt idx) const;
+
+protected: ParticleBase* mpParticleSys; public: PbArgs _args; }
+#define _C_ParticleDataBase
+;
+
+
+//! abstract interface for particle data
+
+template<class T> class ParticleDataImpl : public ParticleDataBase {public:
+ ParticleDataImpl(FluidSolver* parent); static int _W_22 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ParticleDataImpl::ParticleDataImpl" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ParticleDataImpl(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ParticleDataImpl::ParticleDataImpl" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::ParticleDataImpl",e.what()); return -1; }
+ }
+
+ ParticleDataImpl(FluidSolver* parent, ParticleDataImpl<T>* other);
+ virtual ~ParticleDataImpl();
+
+ //! access data
+ inline T& get(const IndexInt idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const T& get(const IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline T& operator[](const IndexInt idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const T& operator[](const IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+
+ //! set all values to 0, note - different from particleSystem::clear! doesnt modify size of array (has to stay in sync with parent system)
+ void clear(); static PyObject* _W_23 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::clear",e.what()); return 0; }
+ }
+
+
+ //! set grid from which to get data...
+ void setSource(Grid<T>* grid, bool isMAC=false ); static PyObject* _W_24 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setSource" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<T>* grid = _args.getPtr<Grid<T> >("grid",0,&_lock); bool isMAC = _args.getOpt<bool >("isMAC",1,false ,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setSource(grid,isMAC); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::setSource" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::setSource",e.what()); return 0; }
+ }
+
+
+ //! particle data base interface
+ virtual IndexInt getSizeSlow() const;
+ virtual void addEntry();
+ virtual ParticleDataBase* clone();
+ virtual PdataType getType() const;
+ virtual void resize(IndexInt s);
+ virtual void copyValueSlow(IndexInt from, IndexInt to);
+
+ IndexInt size() const { return mData.size(); }
+
+ //! fast inlined functions for per particle operations
+ inline void copyValue(IndexInt from, IndexInt to) { get(to) = get(from); }
+ void initNewValue(IndexInt idx, Vec3 pos);
+
+ //! python interface (similar to grid data)
+ ParticleDataImpl<T>& copyFrom(const ParticleDataImpl<T>& a); static PyObject* _W_25 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::copyFrom" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->copyFrom(a)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::copyFrom" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::copyFrom",e.what()); return 0; }
+ }
+
+ void setConst(const T &s); static PyObject* _W_26 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& s = *_args.getPtr<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::setConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::setConst",e.what()); return 0; }
+ }
+
+ void setConstRange(const T &s, const int begin, const int end); static PyObject* _W_27 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setConstRange" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& s = *_args.getPtr<T >("s",0,&_lock); const int begin = _args.get<int >("begin",1,&_lock); const int end = _args.get<int >("end",2,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConstRange(s,begin,end); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::setConstRange" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::setConstRange",e.what()); return 0; }
+ }
+
+ void add(const ParticleDataImpl<T>& a); static PyObject* _W_28 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::add" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->add(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::add" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::add",e.what()); return 0; }
+ }
+
+ void sub(const ParticleDataImpl<T>& a); static PyObject* _W_29 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sub" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->sub(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::sub" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::sub",e.what()); return 0; }
+ }
+
+ void addConst(const T &s); static PyObject* _W_30 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::addConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& s = *_args.getPtr<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::addConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::addConst",e.what()); return 0; }
+ }
+
+ void addScaled(const ParticleDataImpl<T>& a, const T& factor); static PyObject* _W_31 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::addScaled" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); const T& factor = *_args.getPtr<T >("factor",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addScaled(a,factor); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::addScaled" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::addScaled",e.what()); return 0; }
+ }
+
+ void mult(const ParticleDataImpl<T>& a); static PyObject* _W_32 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::mult" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->mult(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::mult" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::mult",e.what()); return 0; }
+ }
+
+ void multConst(const T &s); static PyObject* _W_33 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::multConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& s = *_args.getPtr<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->multConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::multConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::multConst",e.what()); return 0; }
+ }
+
+ void safeDiv(const ParticleDataImpl<T>& a); static PyObject* _W_34 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::safeDiv" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->safeDiv(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::safeDiv" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::safeDiv",e.what()); return 0; }
+ }
+
+ void clamp(const Real vmin, const Real vmax); static PyObject* _W_35 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clamp" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Real vmin = _args.get<Real >("vmin",0,&_lock); const Real vmax = _args.get<Real >("vmax",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clamp(vmin,vmax); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::clamp" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::clamp",e.what()); return 0; }
+ }
+
+ void clampMin(const Real vmin); static PyObject* _W_36 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clampMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Real vmin = _args.get<Real >("vmin",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clampMin(vmin); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::clampMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::clampMin",e.what()); return 0; }
+ }
+
+ void clampMax(const Real vmax); static PyObject* _W_37 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clampMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Real vmax = _args.get<Real >("vmax",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clampMax(vmax); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::clampMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::clampMax",e.what()); return 0; }
+ }
+
+
+ Real getMaxAbs() const ; static PyObject* _W_38 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMaxAbs" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxAbs()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::getMaxAbs" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::getMaxAbs",e.what()); return 0; }
+ }
+
+ Real getMax() const ; static PyObject* _W_39 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMax()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::getMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::getMax",e.what()); return 0; }
+ }
+
+ Real getMin() const ; static PyObject* _W_40 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMin()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::getMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::getMin",e.what()); return 0; }
+ }
+
+
+ T sum(const ParticleDataImpl<int> *t=NULL, const int itype=0) const ; static PyObject* _W_41 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sum" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<int> * t = _args.getPtrOpt<ParticleDataImpl<int> >("t",0,NULL,&_lock); const int itype = _args.getOpt<int >("itype",1,0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->sum(t,itype)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::sum" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::sum",e.what()); return 0; }
+ }
+
+ Real sumSquare() const ; static PyObject* _W_42 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sumSquare" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->sumSquare()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::sumSquare" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::sumSquare",e.what()); return 0; }
+ }
+
+ Real sumMagnitude() const ; static PyObject* _W_43 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sumMagnitude" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->sumMagnitude()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::sumMagnitude" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::sumMagnitude",e.what()); return 0; }
+ }
+
+
+ //! special, set if int flag in t has "flag"
+ void setConstIntFlag(const T &s, const ParticleDataImpl<int> &t, const int flag); static PyObject* _W_44 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setConstIntFlag" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& s = *_args.getPtr<T >("s",0,&_lock); const ParticleDataImpl<int> & t = *_args.getPtr<ParticleDataImpl<int> >("t",1,&_lock); const int flag = _args.get<int >("flag",2,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConstIntFlag(s,t,flag); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::setConstIntFlag" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::setConstIntFlag",e.what()); return 0; }
+ }
+
+
+ void printPdata(IndexInt start=-1, IndexInt stop=-1, bool printIndex=false); static PyObject* _W_45 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::printPdata" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; IndexInt start = _args.getOpt<IndexInt >("start",0,-1,&_lock); IndexInt stop = _args.getOpt<IndexInt >("stop",1,-1,&_lock); bool printIndex = _args.getOpt<bool >("printIndex",2,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->printPdata(start,stop,printIndex); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::printPdata" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::printPdata",e.what()); return 0; }
+ }
+
+
+ //! file io
+ void save(const std::string name); static PyObject* _W_46 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::save",e.what()); return 0; }
+ }
+
+ void load(const std::string name); static PyObject* _W_47 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::load",e.what()); return 0; }
+ }
+
+
+ //! get data pointer of particle data
+ std::string getDataPointer(); static PyObject* _W_48 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::getDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::getDataPointer",e.what()); return 0; }
+ }
+
+protected:
+ //! data storage
+ std::vector<T> mData;
+
+ //! optionally , we might have an associated grid from which to grab new data
+ Grid<T>* mpGridSource; //! unfortunately , we need to distinguish mac vs regular vec3
+ bool mGridSourceMAC; public: PbArgs _args; }
+#define _C_ParticleDataImpl
+;
+
+
+
+
+
+
+//******************************************************************************
+// Implementation
+//******************************************************************************
+
+const int DELETE_PART = 20; // chunk size for compression
+
+void ParticleBase::addBuffered(const Vec3& pos, int flag) {
+ mNewBufferPos.push_back(pos);
+ mNewBufferFlag.push_back(flag);
+}
+
+template<class S>
+void ParticleSystem<S>::clear() {
+ mDeleteChunk = mDeletes = 0;
+ this->resizeAll(0); // instead of mData.clear
+}
+
+template<class S>
+IndexInt ParticleSystem<S>::add(const S& data) {
+ mData.push_back(data);
+ mDeleteChunk = mData.size() / DELETE_PART;
+ this->addAllPdata();
+ return mData.size()-1;
+}
+
+template<class S>
+inline void ParticleSystem<S>::kill(IndexInt idx) {
+ assertMsg(idx>=0 && idx<size(), "Index out of bounds");
+ mData[idx].flag |= PDELETE;
+ if ( (++mDeletes > mDeleteChunk) && (mAllowCompress) ) compress();
+}
+
+template<class S>
+void ParticleSystem<S>::getPosPdata(ParticleDataImpl<Vec3>& target) const {
+ for(IndexInt i=0; i<(IndexInt)this->size(); ++i) {
+ target[i] = this->getPos(i);
+ }
+}
+template<class S>
+void ParticleSystem<S>::setPosPdata(const ParticleDataImpl<Vec3>& source) {
+ for(IndexInt i=0; i<(IndexInt)this->size(); ++i) {
+ this->setPos(i, source[i]);
+ }
+}
+
+template<class S>
+void ParticleSystem<S>::transformPositions( Vec3i dimOld, Vec3i dimNew )
+{
+ const Vec3 factor = calcGridSizeFactor( dimNew, dimOld );
+ for(IndexInt i=0; i<(IndexInt)this->size(); ++i) {
+ this->setPos(i, this->getPos(i) * factor );
+ }
+}
+
+// check for deletion/invalid position, otherwise return velocity
+
+
+
+
+
+template <class S> struct GridAdvectKernel : public KernelBase {
+ GridAdvectKernel( std::vector<S>& p, const MACGrid& vel, const FlagGrid& flags, const Real dt, const bool deleteInObstacle, const bool stopInObstacle, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(p.size()) ,p(p),vel(vel),flags(flags),dt(dt),deleteInObstacle(deleteInObstacle),stopInObstacle(stopInObstacle),ptype(ptype),exclude(exclude) ,u((size)) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<S>& p, const MACGrid& vel, const FlagGrid& flags, const Real dt, const bool deleteInObstacle, const bool stopInObstacle, const ParticleDataImpl<int> *ptype, const int exclude ,std::vector<Vec3> & u) {
+ if ((p[idx].flag & ParticleBase::PDELETE) || (ptype && ((*ptype)[idx] & exclude))) {
+ u[idx] = 0.; return;
+ }
+ // special handling
+ if(deleteInObstacle || stopInObstacle) {
+ if (!flags.isInBounds(p[idx].pos, 1) || flags.isObstacle(p[idx].pos) ) {
+ if(stopInObstacle)
+ u[idx] = 0.;
+ // for simple tracer particles, its convenient to delete particles right away
+ // for other sim types, eg flip, we can try to fix positions later on
+ if(deleteInObstacle)
+ p[idx].flag |= ParticleBase::PDELETE;
+ return;
+ }
+ }
+ u[idx] = vel.getInterpolated(p[idx].pos) * dt;
+} inline operator std::vector<Vec3> () {
+ return u; }
+ inline std::vector<Vec3> & getRet() {
+ return u; }
+ inline std::vector<S>& getArg0() {
+ return p; }
+ typedef std::vector<S> type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const FlagGrid& getArg2() {
+ return flags; }
+ typedef FlagGrid type2;inline const Real& getArg3() {
+ return dt; }
+ typedef Real type3;inline const bool& getArg4() {
+ return deleteInObstacle; }
+ typedef bool type4;inline const bool& getArg5() {
+ return stopInObstacle; }
+ typedef bool type5;inline const ParticleDataImpl<int> * getArg6() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type6;inline const int& getArg7() {
+ return exclude; }
+ typedef int type7; void runMessage() { debMsg("Executing kernel GridAdvectKernel ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,p,vel,flags,dt,deleteInObstacle,stopInObstacle,ptype,exclude,u); }
+ }
+ std::vector<S>& p; const MACGrid& vel; const FlagGrid& flags; const Real dt; const bool deleteInObstacle; const bool stopInObstacle; const ParticleDataImpl<int> * ptype; const int exclude; std::vector<Vec3> u; }
+;;
+
+// final check after advection to make sure particles haven't escaped
+// (similar to particle advection kernel)
+
+template <class S> struct KnDeleteInObstacle : public KernelBase {
+ KnDeleteInObstacle(std::vector<S>& p, const FlagGrid& flags) : KernelBase(p.size()) ,p(p),flags(flags) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<S>& p, const FlagGrid& flags ) {
+ if (p[idx].flag & ParticleBase::PDELETE) return;
+ if (!flags.isInBounds(p[idx].pos,1) || flags.isObstacle(p[idx].pos)) {
+ p[idx].flag |= ParticleBase::PDELETE;
+ }
+} inline std::vector<S>& getArg0() {
+ return p; }
+ typedef std::vector<S> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1; void runMessage() { debMsg("Executing kernel KnDeleteInObstacle ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,p,flags); }
+ }
+ std::vector<S>& p; const FlagGrid& flags; }
+;
+
+// try to get closer to actual obstacle boundary
+static inline Vec3 bisectBacktracePos(const FlagGrid& flags, const Vec3& oldp, const Vec3& newp)
+{
+ Real s = 0.;
+ for(int i=1; i<5; ++i) {
+ Real ds = 1./(Real)(1<<i);
+ if (!flags.isObstacle( oldp*(1.-(s+ds)) + newp*(s+ds) )) {
+ s += ds;
+ }
+ }
+ return( oldp*(1.-(s)) + newp*(s) );
+}
+
+// at least make sure all particles are inside domain
+
+
+
+
+template <class S> struct KnClampPositions : public KernelBase {
+ KnClampPositions( std::vector<S>& p, const FlagGrid& flags, ParticleDataImpl<Vec3> *posOld=NULL, bool stopInObstacle=true, const ParticleDataImpl<int> *ptype=NULL, const int exclude=0) : KernelBase(p.size()) ,p(p),flags(flags),posOld(posOld),stopInObstacle(stopInObstacle),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<S>& p, const FlagGrid& flags, ParticleDataImpl<Vec3> *posOld=NULL, bool stopInObstacle=true, const ParticleDataImpl<int> *ptype=NULL, const int exclude=0 ) {
+ if (p[idx].flag & ParticleBase::PDELETE) return;
+ if (ptype && ((*ptype)[idx] & exclude)) {
+ if(posOld) p[idx].pos = (*posOld)[idx];
+ return;
+ }
+ if (!flags.isInBounds(p[idx].pos,0) ) {
+ p[idx].pos = clamp( p[idx].pos, Vec3(0.), toVec3(flags.getSize())-Vec3(1.) );
+ }
+ if (stopInObstacle && (flags.isObstacle(p[idx].pos)) ) {
+ p[idx].pos = bisectBacktracePos(flags, (*posOld)[idx], p[idx].pos);
+ }
+} inline std::vector<S>& getArg0() {
+ return p; }
+ typedef std::vector<S> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline ParticleDataImpl<Vec3> * getArg2() {
+ return posOld; }
+ typedef ParticleDataImpl<Vec3> type2;inline bool& getArg3() {
+ return stopInObstacle; }
+ typedef bool type3;inline const ParticleDataImpl<int> * getArg4() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type4;inline const int& getArg5() {
+ return exclude; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnClampPositions ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,p,flags,posOld,stopInObstacle,ptype,exclude); }
+ }
+ std::vector<S>& p; const FlagGrid& flags; ParticleDataImpl<Vec3> * posOld; bool stopInObstacle; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+
+// advection plugin
+template<class S>
+void ParticleSystem<S>::advectInGrid(
+ const FlagGrid &flags, const MACGrid &vel, const int integrationMode,
+ const bool deleteInObstacle, const bool stopInObstacle,
+ const ParticleDataImpl<int> *ptype, const int exclude)
+{
+ // position clamp requires old positions, backup
+ ParticleDataImpl<Vec3> *posOld = NULL;
+ if(!deleteInObstacle) {
+ posOld = new ParticleDataImpl<Vec3>(this->getParent());
+ posOld->resize(mData.size());
+ for(IndexInt i=0; i<(IndexInt)mData.size();++i) (*posOld)[i] = mData[i].pos;
+ }
+
+ // update positions
+ GridAdvectKernel<S> kernel(mData, vel, flags, getParent()->getDt(), deleteInObstacle, stopInObstacle, ptype, exclude);
+ integratePointSet(kernel, integrationMode);
+
+ if(!deleteInObstacle) {
+ KnClampPositions<S> (mData, flags, posOld, stopInObstacle, ptype, exclude);
+ delete posOld;
+ } else {
+ KnDeleteInObstacle<S>(mData, flags);
+ }
+}
+
+
+
+template <class S> struct KnProjectParticles : public KernelBase {
+ KnProjectParticles(ParticleSystem<S>& part, Grid<Vec3>& gradient) : KernelBase(part.size()) ,part(part),gradient(gradient) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleSystem<S>& part, Grid<Vec3>& gradient ) {
+ static RandomStream rand (3123984);
+ const double jlen = 0.1;
+
+ if (part.isActive(idx)) {
+ // project along levelset gradient
+ Vec3 p = part[idx].pos;
+ if (gradient.isInBounds(p)) {
+ Vec3 n = gradient.getInterpolated(p);
+ Real dist = normalize(n);
+ Vec3 dx = n * (-dist + jlen * (1 + rand.getReal()));
+ p += dx;
+ }
+ // clamp to outer boundaries (+jitter)
+ const double jlen = 0.1;
+ Vec3 jitter = jlen * rand.getVec3();
+ part[idx].pos = clamp(p, Vec3(1,1,1)+jitter, toVec3(gradient.getSize()-1)-jitter);
+ }
+} inline ParticleSystem<S>& getArg0() {
+ return part; }
+ typedef ParticleSystem<S> type0;inline Grid<Vec3>& getArg1() {
+ return gradient; }
+ typedef Grid<Vec3> type1; void runMessage() { debMsg("Executing kernel KnProjectParticles ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size; for (IndexInt i = 0; i < _sz; i++) op(i, part,gradient); }
+ ParticleSystem<S>& part; Grid<Vec3>& gradient; }
+;
+
+template<class S>
+void ParticleSystem<S>::projectOutside(Grid<Vec3> &gradient) {
+ KnProjectParticles<S>(*this, gradient);
+}
+
+
+template <class S> struct KnProjectOutOfBnd : public KernelBase {
+ KnProjectOutOfBnd(ParticleSystem<S> &part, const FlagGrid &flags, const Real bnd, const bool *axis, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(part.size()) ,part(part),flags(flags),bnd(bnd),axis(axis),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleSystem<S> &part, const FlagGrid &flags, const Real bnd, const bool *axis, const ParticleDataImpl<int> *ptype, const int exclude ) {
+ if(!part.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ if(axis[0]) part[idx].pos.x = std::max(part[idx].pos.x, bnd);
+ if(axis[1]) part[idx].pos.x = std::min(part[idx].pos.x, static_cast<Real>(flags.getSizeX())-bnd);
+ if(axis[2]) part[idx].pos.y = std::max(part[idx].pos.y, bnd);
+ if(axis[3]) part[idx].pos.y = std::min(part[idx].pos.y, static_cast<Real>(flags.getSizeY())-bnd);
+ if(flags.is3D()) {
+ if(axis[4]) part[idx].pos.z = std::max(part[idx].pos.z, bnd);
+ if(axis[5]) part[idx].pos.z = std::min(part[idx].pos.z, static_cast<Real>(flags.getSizeZ())-bnd);
+ }
+} inline ParticleSystem<S> & getArg0() {
+ return part; }
+ typedef ParticleSystem<S> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Real& getArg2() {
+ return bnd; }
+ typedef Real type2;inline const bool* getArg3() {
+ return axis; }
+ typedef bool type3;inline const ParticleDataImpl<int> * getArg4() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type4;inline const int& getArg5() {
+ return exclude; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnProjectOutOfBnd ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,part,flags,bnd,axis,ptype,exclude); }
+ }
+ ParticleSystem<S> & part; const FlagGrid& flags; const Real bnd; const bool* axis; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+
+template<class S>
+void ParticleSystem<S>::projectOutOfBnd(const FlagGrid &flags, const Real bnd, const std::string &plane, const ParticleDataImpl<int> *ptype, const int exclude) {
+ bool axis[6] = { false };
+ for(std::string::const_iterator it=plane.begin(); it!=plane.end(); ++it) {
+ if(*it=='x') axis[0] = true;
+ if(*it=='X') axis[1] = true;
+ if(*it=='y') axis[2] = true;
+ if(*it=='Y') axis[3] = true;
+ if(*it=='z') axis[4] = true;
+ if(*it=='Z') axis[5] = true;
+ }
+ KnProjectOutOfBnd<S>(*this, flags, bnd, axis, ptype, exclude);
+}
+
+template<class S>
+void ParticleSystem<S>::resizeAll(IndexInt size) {
+ // resize all buffers to target size in 1 go
+ mData.resize(size);
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i)
+ mPartData[i]->resize(size);
+}
+
+template<class S>
+void ParticleSystem<S>::compress() {
+ IndexInt nextRead = mData.size();
+ for (IndexInt i=0; i<(IndexInt)mData.size(); i++) {
+ while ((mData[i].flag & PDELETE) != 0) {
+ nextRead--;
+ mData[i] = mData[nextRead];
+ // ugly, but prevent virtual function calls here:
+ for(IndexInt pd=0; pd<(IndexInt)mPdataReal.size(); ++pd) mPdataReal[pd]->copyValue(nextRead, i);
+ for(IndexInt pd=0; pd<(IndexInt)mPdataVec3.size(); ++pd) mPdataVec3[pd]->copyValue(nextRead, i);
+ for(IndexInt pd=0; pd<(IndexInt)mPdataInt .size(); ++pd) mPdataInt [pd]->copyValue(nextRead, i);
+ mData[nextRead].flag = PINVALID;
+ }
+ }
+ if(nextRead<(IndexInt)mData.size()) debMsg("Deleted "<<((IndexInt)mData.size() - nextRead)<<" particles", 1); // debug info
+
+ resizeAll(nextRead);
+ mDeletes = 0;
+ mDeleteChunk = mData.size() / DELETE_PART;
+}
+
+//! insert buffered positions as new particles, update additional particle data
+template<class S>
+void ParticleSystem<S>::insertBufferedParticles() {
+ if(mNewBufferPos.size()==0) return;
+ IndexInt newCnt = mData.size();
+ resizeAll(newCnt + mNewBufferPos.size());
+
+ // clear new flag everywhere
+ for(IndexInt i=0; i<(IndexInt)mData.size(); ++i) mData[i].flag &= ~PNEW;
+
+ for(IndexInt i=0; i<(IndexInt)mNewBufferPos.size(); ++i) {
+ int flag = (mNewBufferFlag.size() > 0) ? mNewBufferFlag[i] : 0;
+ // note, other fields are not initialized here...
+ mData[newCnt].pos = mNewBufferPos[i];
+ mData[newCnt].flag = PNEW | flag;
+ // now init pdata fields from associated grids...
+ for(IndexInt pd=0; pd<(IndexInt)mPdataReal.size(); ++pd)
+ mPdataReal[pd]->initNewValue(newCnt, mNewBufferPos[i] );
+ for(IndexInt pd=0; pd<(IndexInt)mPdataVec3.size(); ++pd)
+ mPdataVec3[pd]->initNewValue(newCnt, mNewBufferPos[i] );
+ for(IndexInt pd=0; pd<(IndexInt)mPdataInt.size(); ++pd)
+ mPdataInt[pd]->initNewValue(newCnt, mNewBufferPos[i] );
+ newCnt++;
+ }
+ if(mNewBufferPos.size()>0) debMsg("Added & initialized "<<(IndexInt)mNewBufferPos.size()<<" particles", 2); // debug info
+ mNewBufferPos.clear();
+ mNewBufferFlag.clear();
+}
+
+
+template<class DATA, class CON>
+void ConnectedParticleSystem<DATA,CON>::compress() {
+ const IndexInt sz = ParticleSystem<DATA>::size();
+ IndexInt *renumber_back = new IndexInt[sz];
+ IndexInt *renumber = new IndexInt[sz];
+ for (IndexInt i=0; i<sz; i++)
+ renumber[i] = renumber_back[i] = -1;
+
+ // reorder elements
+ std::vector<DATA>& data = ParticleSystem<DATA>::mData;
+ IndexInt nextRead = sz;
+ for (IndexInt i=0; i<nextRead; i++) {
+ if ((data[i].flag & ParticleBase::PDELETE) != 0) {
+ nextRead--;
+ data[i] = data[nextRead];
+ data[nextRead].flag = 0;
+ renumber_back[i] = nextRead;
+ } else
+ renumber_back[i] = i;
+ }
+
+ // acceleration structure
+ for (IndexInt i=0; i<nextRead; i++)
+ renumber[renumber_back[i]] = i;
+
+ // rename indices in filaments
+ for (IndexInt i=0; i<(IndexInt)mSegments.size(); i++)
+ mSegments[i].renumber(renumber);
+
+ ParticleSystem<DATA>::mData.resize(nextRead);
+ ParticleSystem<DATA>::mDeletes = 0;
+ ParticleSystem<DATA>::mDeleteChunk = ParticleSystem<DATA>::size() / DELETE_PART;
+
+ delete[] renumber;
+ delete[] renumber_back;
+}
+
+template<class S>
+ParticleBase* ParticleSystem<S>::clone() {
+ ParticleSystem<S>* nm = new ParticleSystem<S>(getParent());
+ if(this->mAllowCompress) compress();
+
+ nm->mData = mData;
+ nm->setName(getName());
+ this->cloneParticleData(nm);
+ return nm;
+}
+
+template<class DATA,class CON>
+ParticleBase* ConnectedParticleSystem<DATA,CON>::clone() {
+ ConnectedParticleSystem<DATA,CON>* nm = new ConnectedParticleSystem<DATA,CON>(this->getParent());
+ if(this->mAllowCompress) compress();
+
+ nm->mData = this->mData;
+ nm->mSegments = mSegments;
+ nm->setName(this->getName());
+ this->cloneParticleData(nm);
+ return nm;
+}
+
+template<class S>
+std::string ParticleSystem<S>::infoString() const {
+ std::stringstream s;
+ s << "ParticleSys '" << getName() << "'\n-> ";
+ if(this->getNumPdata()>0) s<< "pdata: "<< this->getNumPdata();
+ s << "parts: " << size();
+ //for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i) { sstr << i<<":" << mPartData[i]->size() <<" "; }
+ return s.str();
+}
+
+template<class S>
+inline void ParticleSystem<S>::checkPartIndex(IndexInt idx) const {
+ IndexInt mySize = this->size();
+ if (idx<0 || idx > mySize ) {
+ errMsg( "ParticleBase " << " size " << mySize << " : index " << idx << " out of bound " );
+ }
+}
+
+inline void ParticleDataBase::checkPartIndex(IndexInt idx) const {
+ IndexInt mySize = this->getSizeSlow();
+ if (idx<0 || idx > mySize ) {
+ errMsg( "ParticleData " << " size " << mySize << " : index " << idx << " out of bound " );
+ }
+ if ( mpParticleSys && mpParticleSys->getSizeSlow()!=mySize ) {
+ errMsg( "ParticleData " << " size " << mySize << " does not match parent! (" << mpParticleSys->getSizeSlow() << ") " );
+ }
+}
+
+// set contents to zero, as for a grid
+template<class T>
+void ParticleDataImpl<T>::clear() {
+ for(IndexInt i=0; i<(IndexInt)mData.size(); ++i) mData[i] = 0.;
+}
+
+//! count by type flag
+int countParticles(const ParticleDataImpl<int> &t, const int flag);
+
+} // namespace
+
+#endif
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h.reg
new file mode 100644
index 00000000000..b681770c1d1
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h.reg
@@ -0,0 +1,70 @@
+#include "particle.h"
++ParticleBase^ static const Pb::Register _R_$IDX$ ("ParticleBase","ParticleBase","PbClass"); template<> const char* Namify<ParticleBase >::S = "ParticleBase";
+>ParticleBase^
++ParticleBase^ static const Pb::Register _R_$IDX$ ("ParticleBase","ParticleBase",ParticleBase::_W_0);
++ParticleBase^ static const Pb::Register _R_$IDX$ ("ParticleBase","create",ParticleBase::_W_1);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","ParticleSystem<$CT$>","ParticleBase"); template<> const char* Namify<ParticleSystem<$CT$> >::S = "ParticleSystem<$CT$>";
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","ParticleSystem",ParticleSystem<$CT$>::_W_2);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","pySize",ParticleSystem<$CT$>::_W_3);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","setPos",ParticleSystem<$CT$>::_W_4);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","getPos",ParticleSystem<$CT$>::_W_5);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","getPosPdata",ParticleSystem<$CT$>::_W_6);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","setPosPdata",ParticleSystem<$CT$>::_W_7);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","clear",ParticleSystem<$CT$>::_W_8);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","advectInGrid",ParticleSystem<$CT$>::_W_9);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","projectOutside",ParticleSystem<$CT$>::_W_10);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","projectOutOfBnd",ParticleSystem<$CT$>::_W_11);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","BasicParticleSystem","ParticleSystem<$BT$>"); template<> const char* Namify<BasicParticleSystem >::S = "BasicParticleSystem";
+>BasicParticleSystem^
+@BasicParticleSystem^^ParticleSystem^BasicParticleData
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","BasicParticleSystem",BasicParticleSystem::_W_12);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","save",BasicParticleSystem::_W_13);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","load",BasicParticleSystem::_W_14);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","readParticles",BasicParticleSystem::_W_15);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","addParticle",BasicParticleSystem::_W_16);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","printParts",BasicParticleSystem::_W_17);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","getDataPointer",BasicParticleSystem::_W_18);
++ParticleIndexSystem^ static const Pb::Register _R_$IDX$ ("ParticleIndexSystem","ParticleIndexSystem","ParticleSystem<$BT$>"); template<> const char* Namify<ParticleIndexSystem >::S = "ParticleIndexSystem";
+>ParticleIndexSystem^
+@ParticleIndexSystem^^ParticleSystem^ParticleIndexData
++ParticleIndexSystem^ static const Pb::Register _R_$IDX$ ("ParticleIndexSystem","ParticleIndexSystem",ParticleIndexSystem::_W_19);
++ConnectedParticleSystem^ static const Pb::Register _R_$IDX$ ("ConnectedParticleSystem<$CT$>","ConnectedParticleSystem<$CT$>","ParticleSystem<$BT$>"); template<> const char* Namify<ConnectedParticleSystem<$CT$> >::S = "ConnectedParticleSystem<$CT$>";
+@ConnectedParticleSystem^DATA,CON^ParticleSystem^DATA
++ConnectedParticleSystem^ static const Pb::Register _R_$IDX$ ("ConnectedParticleSystem<$CT$>","ConnectedParticleSystem",ConnectedParticleSystem<$CT$>::_W_20);
++ParticleDataBase^ static const Pb::Register _R_$IDX$ ("ParticleDataBase","ParticleDataBase","PbClass"); template<> const char* Namify<ParticleDataBase >::S = "ParticleDataBase";
+>ParticleDataBase^
++ParticleDataBase^ static const Pb::Register _R_$IDX$ ("ParticleDataBase","ParticleDataBase",ParticleDataBase::_W_21);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","ParticleDataImpl<$CT$>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<$CT$> >::S = "ParticleDataImpl<$CT$>";
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","ParticleDataImpl",ParticleDataImpl<$CT$>::_W_22);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","clear",ParticleDataImpl<$CT$>::_W_23);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","setSource",ParticleDataImpl<$CT$>::_W_24);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","copyFrom",ParticleDataImpl<$CT$>::_W_25);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","setConst",ParticleDataImpl<$CT$>::_W_26);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","setConstRange",ParticleDataImpl<$CT$>::_W_27);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","add",ParticleDataImpl<$CT$>::_W_28);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","sub",ParticleDataImpl<$CT$>::_W_29);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","addConst",ParticleDataImpl<$CT$>::_W_30);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","addScaled",ParticleDataImpl<$CT$>::_W_31);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","mult",ParticleDataImpl<$CT$>::_W_32);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","multConst",ParticleDataImpl<$CT$>::_W_33);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","safeDiv",ParticleDataImpl<$CT$>::_W_34);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","clamp",ParticleDataImpl<$CT$>::_W_35);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","clampMin",ParticleDataImpl<$CT$>::_W_36);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","clampMax",ParticleDataImpl<$CT$>::_W_37);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","getMaxAbs",ParticleDataImpl<$CT$>::_W_38);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","getMax",ParticleDataImpl<$CT$>::_W_39);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","getMin",ParticleDataImpl<$CT$>::_W_40);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","sum",ParticleDataImpl<$CT$>::_W_41);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","sumSquare",ParticleDataImpl<$CT$>::_W_42);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","sumMagnitude",ParticleDataImpl<$CT$>::_W_43);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","setConstIntFlag",ParticleDataImpl<$CT$>::_W_44);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","printPdata",ParticleDataImpl<$CT$>::_W_45);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","save",ParticleDataImpl<$CT$>::_W_46);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","load",ParticleDataImpl<$CT$>::_W_47);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","getDataPointer",ParticleDataImpl<$CT$>::_W_48);
+>ParticleDataImpl^int
+&static const Pb::Register _R_$IDX$ ("ParticleDataImpl<int>","PdataInt","");
+>ParticleDataImpl^Real
+&static const Pb::Register _R_$IDX$ ("ParticleDataImpl<Real>","PdataReal","");
+>ParticleDataImpl^Vec3
+&static const Pb::Register _R_$IDX$ ("ParticleDataImpl<Vec3>","PdataVec3","");
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h.reg.cpp
new file mode 100644
index 00000000000..cd4865f4f3d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/particle.h.reg.cpp
@@ -0,0 +1,275 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "particle.h"
+namespace Manta {
+#ifdef _C_BasicParticleSystem
+ static const Pb::Register _R_13 ("BasicParticleSystem","BasicParticleSystem","ParticleSystem<BasicParticleData>"); template<> const char* Namify<BasicParticleSystem >::S = "BasicParticleSystem";
+ static const Pb::Register _R_14 ("BasicParticleSystem","BasicParticleSystem",BasicParticleSystem::_W_12);
+ static const Pb::Register _R_15 ("BasicParticleSystem","save",BasicParticleSystem::_W_13);
+ static const Pb::Register _R_16 ("BasicParticleSystem","load",BasicParticleSystem::_W_14);
+ static const Pb::Register _R_17 ("BasicParticleSystem","readParticles",BasicParticleSystem::_W_15);
+ static const Pb::Register _R_18 ("BasicParticleSystem","addParticle",BasicParticleSystem::_W_16);
+ static const Pb::Register _R_19 ("BasicParticleSystem","printParts",BasicParticleSystem::_W_17);
+ static const Pb::Register _R_20 ("BasicParticleSystem","getDataPointer",BasicParticleSystem::_W_18);
+#endif
+#ifdef _C_ParticleBase
+ static const Pb::Register _R_21 ("ParticleBase","ParticleBase","PbClass"); template<> const char* Namify<ParticleBase >::S = "ParticleBase";
+ static const Pb::Register _R_22 ("ParticleBase","ParticleBase",ParticleBase::_W_0);
+ static const Pb::Register _R_23 ("ParticleBase","create",ParticleBase::_W_1);
+#endif
+#ifdef _C_ParticleDataBase
+ static const Pb::Register _R_24 ("ParticleDataBase","ParticleDataBase","PbClass"); template<> const char* Namify<ParticleDataBase >::S = "ParticleDataBase";
+ static const Pb::Register _R_25 ("ParticleDataBase","ParticleDataBase",ParticleDataBase::_W_21);
+#endif
+#ifdef _C_ParticleDataImpl
+ static const Pb::Register _R_26 ("ParticleDataImpl<int>","ParticleDataImpl<int>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<int> >::S = "ParticleDataImpl<int>";
+ static const Pb::Register _R_27 ("ParticleDataImpl<int>","ParticleDataImpl",ParticleDataImpl<int>::_W_22);
+ static const Pb::Register _R_28 ("ParticleDataImpl<int>","clear",ParticleDataImpl<int>::_W_23);
+ static const Pb::Register _R_29 ("ParticleDataImpl<int>","setSource",ParticleDataImpl<int>::_W_24);
+ static const Pb::Register _R_30 ("ParticleDataImpl<int>","copyFrom",ParticleDataImpl<int>::_W_25);
+ static const Pb::Register _R_31 ("ParticleDataImpl<int>","setConst",ParticleDataImpl<int>::_W_26);
+ static const Pb::Register _R_32 ("ParticleDataImpl<int>","setConstRange",ParticleDataImpl<int>::_W_27);
+ static const Pb::Register _R_33 ("ParticleDataImpl<int>","add",ParticleDataImpl<int>::_W_28);
+ static const Pb::Register _R_34 ("ParticleDataImpl<int>","sub",ParticleDataImpl<int>::_W_29);
+ static const Pb::Register _R_35 ("ParticleDataImpl<int>","addConst",ParticleDataImpl<int>::_W_30);
+ static const Pb::Register _R_36 ("ParticleDataImpl<int>","addScaled",ParticleDataImpl<int>::_W_31);
+ static const Pb::Register _R_37 ("ParticleDataImpl<int>","mult",ParticleDataImpl<int>::_W_32);
+ static const Pb::Register _R_38 ("ParticleDataImpl<int>","multConst",ParticleDataImpl<int>::_W_33);
+ static const Pb::Register _R_39 ("ParticleDataImpl<int>","safeDiv",ParticleDataImpl<int>::_W_34);
+ static const Pb::Register _R_40 ("ParticleDataImpl<int>","clamp",ParticleDataImpl<int>::_W_35);
+ static const Pb::Register _R_41 ("ParticleDataImpl<int>","clampMin",ParticleDataImpl<int>::_W_36);
+ static const Pb::Register _R_42 ("ParticleDataImpl<int>","clampMax",ParticleDataImpl<int>::_W_37);
+ static const Pb::Register _R_43 ("ParticleDataImpl<int>","getMaxAbs",ParticleDataImpl<int>::_W_38);
+ static const Pb::Register _R_44 ("ParticleDataImpl<int>","getMax",ParticleDataImpl<int>::_W_39);
+ static const Pb::Register _R_45 ("ParticleDataImpl<int>","getMin",ParticleDataImpl<int>::_W_40);
+ static const Pb::Register _R_46 ("ParticleDataImpl<int>","sum",ParticleDataImpl<int>::_W_41);
+ static const Pb::Register _R_47 ("ParticleDataImpl<int>","sumSquare",ParticleDataImpl<int>::_W_42);
+ static const Pb::Register _R_48 ("ParticleDataImpl<int>","sumMagnitude",ParticleDataImpl<int>::_W_43);
+ static const Pb::Register _R_49 ("ParticleDataImpl<int>","setConstIntFlag",ParticleDataImpl<int>::_W_44);
+ static const Pb::Register _R_50 ("ParticleDataImpl<int>","printPdata",ParticleDataImpl<int>::_W_45);
+ static const Pb::Register _R_51 ("ParticleDataImpl<int>","save",ParticleDataImpl<int>::_W_46);
+ static const Pb::Register _R_52 ("ParticleDataImpl<int>","load",ParticleDataImpl<int>::_W_47);
+ static const Pb::Register _R_53 ("ParticleDataImpl<int>","getDataPointer",ParticleDataImpl<int>::_W_48);
+ static const Pb::Register _R_54 ("ParticleDataImpl<Real>","ParticleDataImpl<Real>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<Real> >::S = "ParticleDataImpl<Real>";
+ static const Pb::Register _R_55 ("ParticleDataImpl<Real>","ParticleDataImpl",ParticleDataImpl<Real>::_W_22);
+ static const Pb::Register _R_56 ("ParticleDataImpl<Real>","clear",ParticleDataImpl<Real>::_W_23);
+ static const Pb::Register _R_57 ("ParticleDataImpl<Real>","setSource",ParticleDataImpl<Real>::_W_24);
+ static const Pb::Register _R_58 ("ParticleDataImpl<Real>","copyFrom",ParticleDataImpl<Real>::_W_25);
+ static const Pb::Register _R_59 ("ParticleDataImpl<Real>","setConst",ParticleDataImpl<Real>::_W_26);
+ static const Pb::Register _R_60 ("ParticleDataImpl<Real>","setConstRange",ParticleDataImpl<Real>::_W_27);
+ static const Pb::Register _R_61 ("ParticleDataImpl<Real>","add",ParticleDataImpl<Real>::_W_28);
+ static const Pb::Register _R_62 ("ParticleDataImpl<Real>","sub",ParticleDataImpl<Real>::_W_29);
+ static const Pb::Register _R_63 ("ParticleDataImpl<Real>","addConst",ParticleDataImpl<Real>::_W_30);
+ static const Pb::Register _R_64 ("ParticleDataImpl<Real>","addScaled",ParticleDataImpl<Real>::_W_31);
+ static const Pb::Register _R_65 ("ParticleDataImpl<Real>","mult",ParticleDataImpl<Real>::_W_32);
+ static const Pb::Register _R_66 ("ParticleDataImpl<Real>","multConst",ParticleDataImpl<Real>::_W_33);
+ static const Pb::Register _R_67 ("ParticleDataImpl<Real>","safeDiv",ParticleDataImpl<Real>::_W_34);
+ static const Pb::Register _R_68 ("ParticleDataImpl<Real>","clamp",ParticleDataImpl<Real>::_W_35);
+ static const Pb::Register _R_69 ("ParticleDataImpl<Real>","clampMin",ParticleDataImpl<Real>::_W_36);
+ static const Pb::Register _R_70 ("ParticleDataImpl<Real>","clampMax",ParticleDataImpl<Real>::_W_37);
+ static const Pb::Register _R_71 ("ParticleDataImpl<Real>","getMaxAbs",ParticleDataImpl<Real>::_W_38);
+ static const Pb::Register _R_72 ("ParticleDataImpl<Real>","getMax",ParticleDataImpl<Real>::_W_39);
+ static const Pb::Register _R_73 ("ParticleDataImpl<Real>","getMin",ParticleDataImpl<Real>::_W_40);
+ static const Pb::Register _R_74 ("ParticleDataImpl<Real>","sum",ParticleDataImpl<Real>::_W_41);
+ static const Pb::Register _R_75 ("ParticleDataImpl<Real>","sumSquare",ParticleDataImpl<Real>::_W_42);
+ static const Pb::Register _R_76 ("ParticleDataImpl<Real>","sumMagnitude",ParticleDataImpl<Real>::_W_43);
+ static const Pb::Register _R_77 ("ParticleDataImpl<Real>","setConstIntFlag",ParticleDataImpl<Real>::_W_44);
+ static const Pb::Register _R_78 ("ParticleDataImpl<Real>","printPdata",ParticleDataImpl<Real>::_W_45);
+ static const Pb::Register _R_79 ("ParticleDataImpl<Real>","save",ParticleDataImpl<Real>::_W_46);
+ static const Pb::Register _R_80 ("ParticleDataImpl<Real>","load",ParticleDataImpl<Real>::_W_47);
+ static const Pb::Register _R_81 ("ParticleDataImpl<Real>","getDataPointer",ParticleDataImpl<Real>::_W_48);
+ static const Pb::Register _R_82 ("ParticleDataImpl<Vec3>","ParticleDataImpl<Vec3>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<Vec3> >::S = "ParticleDataImpl<Vec3>";
+ static const Pb::Register _R_83 ("ParticleDataImpl<Vec3>","ParticleDataImpl",ParticleDataImpl<Vec3>::_W_22);
+ static const Pb::Register _R_84 ("ParticleDataImpl<Vec3>","clear",ParticleDataImpl<Vec3>::_W_23);
+ static const Pb::Register _R_85 ("ParticleDataImpl<Vec3>","setSource",ParticleDataImpl<Vec3>::_W_24);
+ static const Pb::Register _R_86 ("ParticleDataImpl<Vec3>","copyFrom",ParticleDataImpl<Vec3>::_W_25);
+ static const Pb::Register _R_87 ("ParticleDataImpl<Vec3>","setConst",ParticleDataImpl<Vec3>::_W_26);
+ static const Pb::Register _R_88 ("ParticleDataImpl<Vec3>","setConstRange",ParticleDataImpl<Vec3>::_W_27);
+ static const Pb::Register _R_89 ("ParticleDataImpl<Vec3>","add",ParticleDataImpl<Vec3>::_W_28);
+ static const Pb::Register _R_90 ("ParticleDataImpl<Vec3>","sub",ParticleDataImpl<Vec3>::_W_29);
+ static const Pb::Register _R_91 ("ParticleDataImpl<Vec3>","addConst",ParticleDataImpl<Vec3>::_W_30);
+ static const Pb::Register _R_92 ("ParticleDataImpl<Vec3>","addScaled",ParticleDataImpl<Vec3>::_W_31);
+ static const Pb::Register _R_93 ("ParticleDataImpl<Vec3>","mult",ParticleDataImpl<Vec3>::_W_32);
+ static const Pb::Register _R_94 ("ParticleDataImpl<Vec3>","multConst",ParticleDataImpl<Vec3>::_W_33);
+ static const Pb::Register _R_95 ("ParticleDataImpl<Vec3>","safeDiv",ParticleDataImpl<Vec3>::_W_34);
+ static const Pb::Register _R_96 ("ParticleDataImpl<Vec3>","clamp",ParticleDataImpl<Vec3>::_W_35);
+ static const Pb::Register _R_97 ("ParticleDataImpl<Vec3>","clampMin",ParticleDataImpl<Vec3>::_W_36);
+ static const Pb::Register _R_98 ("ParticleDataImpl<Vec3>","clampMax",ParticleDataImpl<Vec3>::_W_37);
+ static const Pb::Register _R_99 ("ParticleDataImpl<Vec3>","getMaxAbs",ParticleDataImpl<Vec3>::_W_38);
+ static const Pb::Register _R_100 ("ParticleDataImpl<Vec3>","getMax",ParticleDataImpl<Vec3>::_W_39);
+ static const Pb::Register _R_101 ("ParticleDataImpl<Vec3>","getMin",ParticleDataImpl<Vec3>::_W_40);
+ static const Pb::Register _R_102 ("ParticleDataImpl<Vec3>","sum",ParticleDataImpl<Vec3>::_W_41);
+ static const Pb::Register _R_103 ("ParticleDataImpl<Vec3>","sumSquare",ParticleDataImpl<Vec3>::_W_42);
+ static const Pb::Register _R_104 ("ParticleDataImpl<Vec3>","sumMagnitude",ParticleDataImpl<Vec3>::_W_43);
+ static const Pb::Register _R_105 ("ParticleDataImpl<Vec3>","setConstIntFlag",ParticleDataImpl<Vec3>::_W_44);
+ static const Pb::Register _R_106 ("ParticleDataImpl<Vec3>","printPdata",ParticleDataImpl<Vec3>::_W_45);
+ static const Pb::Register _R_107 ("ParticleDataImpl<Vec3>","save",ParticleDataImpl<Vec3>::_W_46);
+ static const Pb::Register _R_108 ("ParticleDataImpl<Vec3>","load",ParticleDataImpl<Vec3>::_W_47);
+ static const Pb::Register _R_109 ("ParticleDataImpl<Vec3>","getDataPointer",ParticleDataImpl<Vec3>::_W_48);
+#endif
+#ifdef _C_ParticleIndexSystem
+ static const Pb::Register _R_110 ("ParticleIndexSystem","ParticleIndexSystem","ParticleSystem<ParticleIndexData>"); template<> const char* Namify<ParticleIndexSystem >::S = "ParticleIndexSystem";
+ static const Pb::Register _R_111 ("ParticleIndexSystem","ParticleIndexSystem",ParticleIndexSystem::_W_19);
+#endif
+#ifdef _C_ParticleSystem
+ static const Pb::Register _R_112 ("ParticleSystem<BasicParticleData>","ParticleSystem<BasicParticleData>","ParticleBase"); template<> const char* Namify<ParticleSystem<BasicParticleData> >::S = "ParticleSystem<BasicParticleData>";
+ static const Pb::Register _R_113 ("ParticleSystem<BasicParticleData>","ParticleSystem",ParticleSystem<BasicParticleData>::_W_2);
+ static const Pb::Register _R_114 ("ParticleSystem<BasicParticleData>","pySize",ParticleSystem<BasicParticleData>::_W_3);
+ static const Pb::Register _R_115 ("ParticleSystem<BasicParticleData>","setPos",ParticleSystem<BasicParticleData>::_W_4);
+ static const Pb::Register _R_116 ("ParticleSystem<BasicParticleData>","getPos",ParticleSystem<BasicParticleData>::_W_5);
+ static const Pb::Register _R_117 ("ParticleSystem<BasicParticleData>","getPosPdata",ParticleSystem<BasicParticleData>::_W_6);
+ static const Pb::Register _R_118 ("ParticleSystem<BasicParticleData>","setPosPdata",ParticleSystem<BasicParticleData>::_W_7);
+ static const Pb::Register _R_119 ("ParticleSystem<BasicParticleData>","clear",ParticleSystem<BasicParticleData>::_W_8);
+ static const Pb::Register _R_120 ("ParticleSystem<BasicParticleData>","advectInGrid",ParticleSystem<BasicParticleData>::_W_9);
+ static const Pb::Register _R_121 ("ParticleSystem<BasicParticleData>","projectOutside",ParticleSystem<BasicParticleData>::_W_10);
+ static const Pb::Register _R_122 ("ParticleSystem<BasicParticleData>","projectOutOfBnd",ParticleSystem<BasicParticleData>::_W_11);
+ static const Pb::Register _R_123 ("ParticleSystem<ParticleIndexData>","ParticleSystem<ParticleIndexData>","ParticleBase"); template<> const char* Namify<ParticleSystem<ParticleIndexData> >::S = "ParticleSystem<ParticleIndexData>";
+ static const Pb::Register _R_124 ("ParticleSystem<ParticleIndexData>","ParticleSystem",ParticleSystem<ParticleIndexData>::_W_2);
+ static const Pb::Register _R_125 ("ParticleSystem<ParticleIndexData>","pySize",ParticleSystem<ParticleIndexData>::_W_3);
+ static const Pb::Register _R_126 ("ParticleSystem<ParticleIndexData>","setPos",ParticleSystem<ParticleIndexData>::_W_4);
+ static const Pb::Register _R_127 ("ParticleSystem<ParticleIndexData>","getPos",ParticleSystem<ParticleIndexData>::_W_5);
+ static const Pb::Register _R_128 ("ParticleSystem<ParticleIndexData>","getPosPdata",ParticleSystem<ParticleIndexData>::_W_6);
+ static const Pb::Register _R_129 ("ParticleSystem<ParticleIndexData>","setPosPdata",ParticleSystem<ParticleIndexData>::_W_7);
+ static const Pb::Register _R_130 ("ParticleSystem<ParticleIndexData>","clear",ParticleSystem<ParticleIndexData>::_W_8);
+ static const Pb::Register _R_131 ("ParticleSystem<ParticleIndexData>","advectInGrid",ParticleSystem<ParticleIndexData>::_W_9);
+ static const Pb::Register _R_132 ("ParticleSystem<ParticleIndexData>","projectOutside",ParticleSystem<ParticleIndexData>::_W_10);
+ static const Pb::Register _R_133 ("ParticleSystem<ParticleIndexData>","projectOutOfBnd",ParticleSystem<ParticleIndexData>::_W_11);
+#endif
+static const Pb::Register _R_10 ("ParticleDataImpl<int>","PdataInt","");
+static const Pb::Register _R_11 ("ParticleDataImpl<Real>","PdataReal","");
+static const Pb::Register _R_12 ("ParticleDataImpl<Vec3>","PdataVec3","");
+extern "C" {
+void PbRegister_file_10()
+{
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+ KEEP_UNUSED(_R_101);
+ KEEP_UNUSED(_R_102);
+ KEEP_UNUSED(_R_103);
+ KEEP_UNUSED(_R_104);
+ KEEP_UNUSED(_R_105);
+ KEEP_UNUSED(_R_106);
+ KEEP_UNUSED(_R_107);
+ KEEP_UNUSED(_R_108);
+ KEEP_UNUSED(_R_109);
+ KEEP_UNUSED(_R_110);
+ KEEP_UNUSED(_R_111);
+ KEEP_UNUSED(_R_112);
+ KEEP_UNUSED(_R_113);
+ KEEP_UNUSED(_R_114);
+ KEEP_UNUSED(_R_115);
+ KEEP_UNUSED(_R_116);
+ KEEP_UNUSED(_R_117);
+ KEEP_UNUSED(_R_118);
+ KEEP_UNUSED(_R_119);
+ KEEP_UNUSED(_R_120);
+ KEEP_UNUSED(_R_121);
+ KEEP_UNUSED(_R_122);
+ KEEP_UNUSED(_R_123);
+ KEEP_UNUSED(_R_124);
+ KEEP_UNUSED(_R_125);
+ KEEP_UNUSED(_R_126);
+ KEEP_UNUSED(_R_127);
+ KEEP_UNUSED(_R_128);
+ KEEP_UNUSED(_R_129);
+ KEEP_UNUSED(_R_130);
+ KEEP_UNUSED(_R_131);
+ KEEP_UNUSED(_R_132);
+ KEEP_UNUSED(_R_133);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/advection.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/advection.cpp
new file mode 100644
index 00000000000..8b577b17583
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/advection.cpp
@@ -0,0 +1,802 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2015 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for advection
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+#include <limits>
+
+using namespace std;
+
+namespace Manta {
+
+
+//! Semi-Lagrange interpolation kernel
+
+
+template <class T> struct SemiLagrange : public KernelBase {
+ SemiLagrange(const FlagGrid& flags, const MACGrid& vel, Grid<T>& dst, const Grid<T>& src, Real dt, bool isLevelset, int orderSpace, int orderTrace) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),src(src),dt(dt),isLevelset(isLevelset),orderSpace(orderSpace),orderTrace(orderTrace) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, Grid<T>& dst, const Grid<T>& src, Real dt, bool isLevelset, int orderSpace, int orderTrace ) {
+ if (orderTrace == 1) {
+ // traceback position
+ Vec3 pos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getCentered(i,j,k) * dt;
+ dst(i,j,k) = src.getInterpolatedHi(pos, orderSpace);
+ } else if (orderTrace == 2) {
+ // backtracing using explicit midpoint
+ Vec3 p0 = Vec3(i+0.5f,j+0.5f,k+0.5f);
+ Vec3 p1 = p0 - vel.getCentered(i,j,k)*dt*0.5;
+ Vec3 p2 = p0 - vel.getInterpolated(p1)*dt;
+ dst(i,j,k) = src.getInterpolatedHi(p2, orderSpace);
+ } else {
+ assertMsg(false, "Unknown backtracing order "<<orderTrace);
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline Grid<T>& getArg2() {
+ return dst; }
+ typedef Grid<T> type2;inline const Grid<T>& getArg3() {
+ return src; }
+ typedef Grid<T> type3;inline Real& getArg4() {
+ return dt; }
+ typedef Real type4;inline bool& getArg5() {
+ return isLevelset; }
+ typedef bool type5;inline int& getArg6() {
+ return orderSpace; }
+ typedef int type6;inline int& getArg7() {
+ return orderTrace; }
+ typedef int type7; void runMessage() { debMsg("Executing kernel SemiLagrange ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,dst,src,dt,isLevelset,orderSpace,orderTrace); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,dst,src,dt,isLevelset,orderSpace,orderTrace); }
+ }
+ }
+ const FlagGrid& flags; const MACGrid& vel; Grid<T>& dst; const Grid<T>& src; Real dt; bool isLevelset; int orderSpace; int orderTrace; }
+;
+
+//! Semi-Lagrange interpolation kernel for MAC grids
+
+
+ struct SemiLagrangeMAC : public KernelBase {
+ SemiLagrangeMAC(const FlagGrid& flags, const MACGrid& vel, MACGrid& dst, const MACGrid& src, Real dt, int orderSpace, int orderTrace) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),src(src),dt(dt),orderSpace(orderSpace),orderTrace(orderTrace) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, MACGrid& dst, const MACGrid& src, Real dt, int orderSpace, int orderTrace ) {
+ if (orderTrace == 1) {
+ // get currect velocity at MAC position
+ // no need to shift xpos etc. as lookup field is also shifted
+ Vec3 xpos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACX(i,j,k) * dt;
+ Real vx = src.getInterpolatedComponentHi<0>(xpos, orderSpace);
+ Vec3 ypos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACY(i,j,k) * dt;
+ Real vy = src.getInterpolatedComponentHi<1>(ypos, orderSpace);
+ Vec3 zpos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACZ(i,j,k) * dt;
+ Real vz = src.getInterpolatedComponentHi<2>(zpos, orderSpace);
+
+ dst(i,j,k) = Vec3(vx,vy,vz);
+ } else if (orderTrace == 2) {
+ Vec3 p0 = Vec3(i+0.5,j+0.5,k+0.5);
+ Vec3 xp0 = Vec3(i,j+0.5f,k+0.5f);
+ Vec3 xp1 = xp0 - src.getAtMACX(i,j,k)*dt*0.5;
+ Vec3 xp2 = p0 - src.getInterpolated(xp1)*dt;
+ Real vx = src.getInterpolatedComponentHi<0>(xp2, orderSpace);
+ Vec3 yp0 = Vec3(i+0.5f,j,k+0.5f);
+ Vec3 yp1 = yp0 - src.getAtMACY(i,j,k)*dt*0.5;
+ Vec3 yp2 = p0 - src.getInterpolated(yp1)*dt;
+ Real vy = src.getInterpolatedComponentHi<1>(yp2, orderSpace);
+ Vec3 zp0 = Vec3(i+0.5f,j+0.5f,k);
+ Vec3 zp1 = zp0 - src.getAtMACZ(i,j,k)*dt*0.5;
+ Vec3 zp2 = p0 - src.getInterpolated(zp1)*dt;
+ Real vz = src.getInterpolatedComponentHi<2>(zp2, orderSpace);
+
+ dst(i,j,k) = Vec3(vx,vy,vz);
+ } else {
+ assertMsg(false, "Unknown backtracing order "<<orderTrace);
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return dst; }
+ typedef MACGrid type2;inline const MACGrid& getArg3() {
+ return src; }
+ typedef MACGrid type3;inline Real& getArg4() {
+ return dt; }
+ typedef Real type4;inline int& getArg5() {
+ return orderSpace; }
+ typedef int type5;inline int& getArg6() {
+ return orderTrace; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel SemiLagrangeMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,dst,src,dt,orderSpace,orderTrace); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,dst,src,dt,orderSpace,orderTrace); }
+ }
+ }
+ const FlagGrid& flags; const MACGrid& vel; MACGrid& dst; const MACGrid& src; Real dt; int orderSpace; int orderTrace; }
+;
+
+
+//! Kernel: Correct based on forward and backward SL steps (for both centered & mac grids)
+
+
+
+template <class T> struct MacCormackCorrect : public KernelBase {
+ MacCormackCorrect(const FlagGrid& flags, Grid<T>& dst, const Grid<T>& old, const Grid<T>& fwd, const Grid<T>& bwd, Real strength, bool isLevelSet, bool isMAC=false ) : KernelBase(&flags,0) ,flags(flags),dst(dst),old(old),fwd(fwd),bwd(bwd),strength(strength),isLevelSet(isLevelSet),isMAC(isMAC) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags, Grid<T>& dst, const Grid<T>& old, const Grid<T>& fwd, const Grid<T>& bwd, Real strength, bool isLevelSet, bool isMAC=false ) {
+ dst[idx] = fwd[idx];
+
+ if (flags.isFluid(idx)) {
+ // only correct inside fluid region; note, strenth of correction can be modified here
+ dst[idx] += strength * 0.5 * (old[idx] - bwd[idx]);
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<T>& getArg1() {
+ return dst; }
+ typedef Grid<T> type1;inline const Grid<T>& getArg2() {
+ return old; }
+ typedef Grid<T> type2;inline const Grid<T>& getArg3() {
+ return fwd; }
+ typedef Grid<T> type3;inline const Grid<T>& getArg4() {
+ return bwd; }
+ typedef Grid<T> type4;inline Real& getArg5() {
+ return strength; }
+ typedef Real type5;inline bool& getArg6() {
+ return isLevelSet; }
+ typedef bool type6;inline bool& getArg7() {
+ return isMAC; }
+ typedef bool type7; void runMessage() { debMsg("Executing kernel MacCormackCorrect ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,flags,dst,old,fwd,bwd,strength,isLevelSet,isMAC); }
+ }
+ const FlagGrid& flags; Grid<T>& dst; const Grid<T>& old; const Grid<T>& fwd; const Grid<T>& bwd; Real strength; bool isLevelSet; bool isMAC; }
+;
+
+//! Kernel: Correct based on forward and backward SL steps (for both centered & mac grids)
+
+
+
+template <class T> struct MacCormackCorrectMAC : public KernelBase {
+ MacCormackCorrectMAC(const FlagGrid& flags, Grid<T>& dst, const Grid<T>& old, const Grid<T>& fwd, const Grid<T>& bwd, Real strength, bool isLevelSet, bool isMAC=false ) : KernelBase(&flags,0) ,flags(flags),dst(dst),old(old),fwd(fwd),bwd(bwd),strength(strength),isLevelSet(isLevelSet),isMAC(isMAC) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<T>& dst, const Grid<T>& old, const Grid<T>& fwd, const Grid<T>& bwd, Real strength, bool isLevelSet, bool isMAC=false ) {
+ bool skip[3] = { false, false, false };
+
+ if (!flags.isFluid(i,j,k)) skip[0] = skip[1] = skip[2] = true;
+ if(isMAC) {
+ if( (i>0) && (!flags.isFluid(i-1,j,k) )) skip[0] = true;
+ if( (j>0) && (!flags.isFluid(i,j-1,k) )) skip[1] = true;
+ if( (k>0) && (!flags.isFluid(i,j,k-1) )) skip[2] = true;
+ }
+
+ for(int c=0; c<3; ++c ) {
+ if ( skip[c] ) {
+ dst(i,j,k)[c] = fwd(i,j,k)[c];
+ } else {
+ // perform actual correction with given strength
+ dst(i,j,k)[c] = fwd(i,j,k)[c] + strength * 0.5 * (old(i,j,k)[c] - bwd(i,j,k)[c]);
+ }
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<T>& getArg1() {
+ return dst; }
+ typedef Grid<T> type1;inline const Grid<T>& getArg2() {
+ return old; }
+ typedef Grid<T> type2;inline const Grid<T>& getArg3() {
+ return fwd; }
+ typedef Grid<T> type3;inline const Grid<T>& getArg4() {
+ return bwd; }
+ typedef Grid<T> type4;inline Real& getArg5() {
+ return strength; }
+ typedef Real type5;inline bool& getArg6() {
+ return isLevelSet; }
+ typedef bool type6;inline bool& getArg7() {
+ return isMAC; }
+ typedef bool type7; void runMessage() { debMsg("Executing kernel MacCormackCorrectMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,dst,old,fwd,bwd,strength,isLevelSet,isMAC); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,dst,old,fwd,bwd,strength,isLevelSet,isMAC); }
+ }
+ }
+ const FlagGrid& flags; Grid<T>& dst; const Grid<T>& old; const Grid<T>& fwd; const Grid<T>& bwd; Real strength; bool isLevelSet; bool isMAC; }
+;
+
+// Helper to collect min/max in a template
+template<class T> inline void getMinMax(T& minv, T& maxv, const T& val) {
+ if (val < minv) minv = val;
+ if (val > maxv) maxv = val;
+}
+template<> inline void getMinMax<Vec3>(Vec3& minv, Vec3& maxv, const Vec3& val) {
+ getMinMax(minv.x, maxv.x, val.x);
+ getMinMax(minv.y, maxv.y, val.y);
+ getMinMax(minv.z, maxv.z, val.z);
+}
+
+//! detect out of bounds value
+template<class T> inline bool cmpMinMax(T& minv, T& maxv, const T& val) {
+ if (val < minv) return true;
+ if (val > maxv) return true;
+ return false;
+}
+template<> inline bool cmpMinMax<Vec3>(Vec3& minv, Vec3& maxv, const Vec3& val) {
+ return( cmpMinMax(minv.x, maxv.x, val.x) | cmpMinMax(minv.y, maxv.y, val.y) | cmpMinMax(minv.z, maxv.z, val.z));
+}
+
+
+#define checkFlag(x,y,z) (flags((x),(y),(z)) & (FlagGrid::TypeFluid|FlagGrid::TypeEmpty))
+
+//! Helper function for clamping non-mac grids (those have specialized per component version below)
+// Note - 2 clamp modes, a sharper one (default, clampMode 1, also uses backward step),
+// and a softer version (clampMode 2) that is recommended in Andy's paper
+template<class T>
+inline T doClampComponent(const Vec3i& gridSize, const FlagGrid& flags, T dst, const Grid<T>& orig, const T fwd, const Vec3& pos, const Vec3& vel, const int clampMode )
+{
+ T minv( std::numeric_limits<Real>::max()), maxv( -std::numeric_limits<Real>::max());
+ bool haveFl = false;
+
+ // forward (and optionally) backward
+ Vec3i positions[2];
+ int numPos = 1;
+ positions[0] = toVec3i(pos - vel);
+ if(clampMode==1) { numPos = 2;
+ positions[1] = toVec3i(pos + vel); }
+
+ for(int l=0; l<numPos; ++l) {
+ Vec3i& currPos = positions[l];
+
+ // clamp lookup to grid
+ const int i0 = clamp(currPos.x, 0, gridSize.x-1); // note! gridsize already has -1 from call
+ const int j0 = clamp(currPos.y, 0, gridSize.y-1);
+ const int k0 = clamp(currPos.z, 0, (orig.is3D() ? (gridSize.z-1) : 1) );
+ const int i1 = i0+1, j1 = j0+1, k1= (orig.is3D() ? (k0+1) : k0);
+
+ // find min/max around source pos
+ if(checkFlag(i0,j0,k0)) { getMinMax(minv, maxv, orig(i0,j0,k0)); haveFl=true; }
+ if(checkFlag(i1,j0,k0)) { getMinMax(minv, maxv, orig(i1,j0,k0)); haveFl=true; }
+ if(checkFlag(i0,j1,k0)) { getMinMax(minv, maxv, orig(i0,j1,k0)); haveFl=true; }
+ if(checkFlag(i1,j1,k0)) { getMinMax(minv, maxv, orig(i1,j1,k0)); haveFl=true; }
+
+ if(orig.is3D()) {
+ if(checkFlag(i0,j0,k1)) { getMinMax(minv, maxv, orig(i0,j0,k1)); haveFl=true; }
+ if(checkFlag(i1,j0,k1)) { getMinMax(minv, maxv, orig(i1,j0,k1)); haveFl=true; }
+ if(checkFlag(i0,j1,k1)) { getMinMax(minv, maxv, orig(i0,j1,k1)); haveFl=true; }
+ if(checkFlag(i1,j1,k1)) { getMinMax(minv, maxv, orig(i1,j1,k1)); haveFl=true; } }
+ }
+
+ if(!haveFl) return fwd;
+ if(clampMode==1) {
+ dst = clamp(dst, minv, maxv); // hard clamp
+ } else {
+ if(cmpMinMax(minv,maxv,dst)) dst = fwd; // recommended in paper, "softer"
+ }
+ return dst;
+}
+
+//! Helper function for clamping MAC grids, slight differences in flag checks
+// similar to scalar version, just uses single component c of vec3 values
+// for symmetry, reverts to first order near boundaries for clampMode 2
+template<int c>
+inline Real doClampComponentMAC(const FlagGrid& flags, const Vec3i& gridSize, Real dst, const MACGrid& orig, Real fwd, const Vec3& pos, const Vec3& vel, const int clampMode )
+{
+ Real minv = std::numeric_limits<Real>::max(), maxv = -std::numeric_limits<Real>::max();
+ //bool haveFl = false;
+
+ // forward (and optionally) backward
+ Vec3i positions[2];
+ int numPos = 1;
+ positions[0] = toVec3i(pos - vel);
+ if(clampMode==1) { numPos = 2;
+ positions[1] = toVec3i(pos + vel); }
+
+ Vec3i oPos = toVec3i(pos);
+ Vec3i nbPos = oPos; nbPos[c] -= 1;
+ if(clampMode==2 && (! (checkFlag(oPos.x,oPos.y,oPos.z) && checkFlag(nbPos.x,nbPos.y,nbPos.z)) )) return fwd; // replaces haveFl check
+
+ for(int l=0; l<numPos; ++l) {
+ Vec3i& currPos = positions[l];
+
+ const int i0 = clamp(currPos.x, 0, gridSize.x-1); // note! gridsize already has -1 from call
+ const int j0 = clamp(currPos.y, 0, gridSize.y-1); // but we need a clamp to -2 for the +1 offset below
+ const int k0 = clamp(currPos.z, 0, (orig.is3D() ? (gridSize.z-1) : 0) );
+ const int i1 = i0+1, j1 = j0+1, k1= (orig.is3D() ? (k0+1) : k0);
+
+ // find min/max around source pos
+ getMinMax(minv, maxv, orig(i0,j0,k0)[c]);
+ getMinMax(minv, maxv, orig(i1,j0,k0)[c]);
+ getMinMax(minv, maxv, orig(i0,j1,k0)[c]);
+ getMinMax(minv, maxv, orig(i1,j1,k0)[c]);
+
+ if(orig.is3D()) {
+ getMinMax(minv, maxv, orig(i0,j0,k1)[c]);
+ getMinMax(minv, maxv, orig(i1,j0,k1)[c]);
+ getMinMax(minv, maxv, orig(i0,j1,k1)[c]);
+ getMinMax(minv, maxv, orig(i1,j1,k1)[c]); }
+ }
+
+ if(clampMode==1) {
+ dst = clamp(dst, minv, maxv); // hard clamp
+ } else {
+ if(cmpMinMax(minv,maxv,dst)) dst = fwd; // recommended in paper, "softer"
+ }
+ return dst;
+}
+
+#undef checkFlag
+
+//! Kernel: Clamp obtained value to min/max in source area, and reset values that point out of grid or into boundaries
+// (note - MAC grids are handled below)
+
+
+template <class T> struct MacCormackClamp : public KernelBase {
+ MacCormackClamp(const FlagGrid& flags, const MACGrid& vel, Grid<T>& dst, const Grid<T>& orig, const Grid<T>& fwd, Real dt, const int clampMode) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),orig(orig),fwd(fwd),dt(dt),clampMode(clampMode) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, Grid<T>& dst, const Grid<T>& orig, const Grid<T>& fwd, Real dt, const int clampMode ) {
+ T dval = dst(i,j,k);
+ Vec3i gridUpper = flags.getSize() - 1;
+
+ dval = doClampComponent<T>(gridUpper, flags, dval, orig, fwd(i,j,k), Vec3(i,j,k), vel.getCentered(i,j,k) * dt, clampMode );
+
+ if(1 && clampMode==1) {
+ // lookup forward/backward , round to closest NB
+ Vec3i posFwd = toVec3i( Vec3(i,j,k) + Vec3(0.5,0.5,0.5) - vel.getCentered(i,j,k) * dt );
+ Vec3i posBwd = toVec3i( Vec3(i,j,k) + Vec3(0.5,0.5,0.5) + vel.getCentered(i,j,k) * dt );
+
+ // test if lookups point out of grid or into obstacle (note doClampComponent already checks sides, below is needed for valid flags access)
+ if (posFwd.x < 0 || posFwd.y < 0 || posFwd.z < 0 ||
+ posBwd.x < 0 || posBwd.y < 0 || posBwd.z < 0 ||
+ posFwd.x > gridUpper.x || posFwd.y > gridUpper.y || ((posFwd.z > gridUpper.z)&&flags.is3D()) ||
+ posBwd.x > gridUpper.x || posBwd.y > gridUpper.y || ((posBwd.z > gridUpper.z)&&flags.is3D()) ||
+ flags.isObstacle(posFwd) || flags.isObstacle(posBwd) )
+ {
+ dval = fwd(i,j,k);
+ }
+ }
+ // clampMode 2 handles flags in doClampComponent call
+
+ dst(i,j,k) = dval;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline Grid<T>& getArg2() {
+ return dst; }
+ typedef Grid<T> type2;inline const Grid<T>& getArg3() {
+ return orig; }
+ typedef Grid<T> type3;inline const Grid<T>& getArg4() {
+ return fwd; }
+ typedef Grid<T> type4;inline Real& getArg5() {
+ return dt; }
+ typedef Real type5;inline const int& getArg6() {
+ return clampMode; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel MacCormackClamp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,dst,orig,fwd,dt,clampMode); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,dst,orig,fwd,dt,clampMode); }
+ }
+ }
+ const FlagGrid& flags; const MACGrid& vel; Grid<T>& dst; const Grid<T>& orig; const Grid<T>& fwd; Real dt; const int clampMode; }
+;
+
+//! Kernel: same as MacCormackClamp above, but specialized version for MAC grids
+
+
+ struct MacCormackClampMAC : public KernelBase {
+ MacCormackClampMAC(const FlagGrid& flags, const MACGrid& vel, MACGrid& dst, const MACGrid& orig, const MACGrid& fwd, Real dt, const int clampMode) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),orig(orig),fwd(fwd),dt(dt),clampMode(clampMode) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, MACGrid& dst, const MACGrid& orig, const MACGrid& fwd, Real dt, const int clampMode ) {
+ Vec3 pos(i,j,k);
+ Vec3 dval = dst(i,j,k);
+ Vec3 dfwd = fwd(i,j,k);
+ Vec3i gridUpper = flags.getSize() - 1;
+
+ dval.x = doClampComponentMAC<0>(flags, gridUpper, dval.x, orig, dfwd.x, pos, vel.getAtMACX(i,j,k) * dt, clampMode );
+ dval.y = doClampComponentMAC<1>(flags, gridUpper, dval.y, orig, dfwd.y, pos, vel.getAtMACY(i,j,k) * dt, clampMode );
+ if(flags.is3D())
+ dval.z = doClampComponentMAC<2>(flags, gridUpper, dval.z, orig, dfwd.z, pos, vel.getAtMACZ(i,j,k) * dt, clampMode );
+
+ // note - the MAC version currently does not check whether source points were inside an obstacle! (unlike centered version)
+ // this would need to be done for each face separately to stay symmetric...
+
+ dst(i,j,k) = dval;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return dst; }
+ typedef MACGrid type2;inline const MACGrid& getArg3() {
+ return orig; }
+ typedef MACGrid type3;inline const MACGrid& getArg4() {
+ return fwd; }
+ typedef MACGrid type4;inline Real& getArg5() {
+ return dt; }
+ typedef Real type5;inline const int& getArg6() {
+ return clampMode; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel MacCormackClampMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,dst,orig,fwd,dt,clampMode); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,dst,orig,fwd,dt,clampMode); }
+ }
+ }
+ const FlagGrid& flags; const MACGrid& vel; MACGrid& dst; const MACGrid& orig; const MACGrid& fwd; Real dt; const int clampMode; }
+;
+
+
+//! template function for performing SL advection
+//! (Note boundary width only needed for specialization for MAC grids below)
+template<class GridType>
+void fnAdvectSemiLagrange(FluidSolver* parent, const FlagGrid& flags, const MACGrid& vel, GridType& orig, int order, Real strength, int orderSpace, int clampMode, int orderTrace) {
+ typedef typename GridType::BASETYPE T;
+
+ Real dt = parent->getDt();
+ bool levelset = orig.getType() & GridBase::TypeLevelset;
+
+ // forward step
+ GridType fwd(parent);
+ SemiLagrange<T> (flags, vel, fwd, orig, dt, levelset, orderSpace, orderTrace);
+
+ if (order == 1) {
+ orig.swap(fwd);
+ }
+ else if (order == 2) { // MacCormack
+ GridType bwd(parent);
+ GridType newGrid(parent);
+
+ // bwd <- backwards step
+ SemiLagrange<T> (flags, vel, bwd, fwd, -dt, levelset, orderSpace, orderTrace);
+
+ // newGrid <- compute correction
+ MacCormackCorrect<T> (flags, newGrid, orig, fwd, bwd, strength, levelset);
+
+ // clamp values
+ MacCormackClamp<T> (flags, vel, newGrid, orig, fwd, dt, clampMode);
+
+ orig.swap(newGrid);
+ }
+}
+
+// outflow functions
+
+//! calculate local propagation velocity for cell (i,j,k)
+Vec3 getBulkVel(const FlagGrid& flags, const MACGrid& vel, int i, int j, int k){
+ Vec3 avg = Vec3(0.);
+ int count = 0;
+ int size = 1; // stencil size
+ int nmax = (flags.is3D() ? size : 0);
+ // average the neighboring fluid / outflow cell's velocity
+ for (int n = -nmax; n <= nmax; n++){
+ for (int m = -size; m <= size; m++){
+ for (int l = -size; l <= size; l++){
+ if (flags.isInBounds(Vec3i(i+l,j+m,k+n)) && (flags.isFluid(i+l,j+m,k+n) || flags.isOutflow(i+l,j+m,k+n))){
+ avg += vel(i+l,j+m,k+n);
+ count++;
+ }
+ }
+ }
+ }
+ return count>0 ? avg/count : avg;
+}
+
+//! extrapolate normal velocity components into outflow cell
+ struct extrapolateVelConvectiveBC : public KernelBase {
+ extrapolateVelConvectiveBC(const FlagGrid& flags, const MACGrid& vel, MACGrid& velDst, const MACGrid& velPrev, Real timeStep) : KernelBase(&flags,0) ,flags(flags),vel(vel),velDst(velDst),velPrev(velPrev),timeStep(timeStep) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, MACGrid& velDst, const MACGrid& velPrev, Real timeStep ) {
+ if (flags.isOutflow(i, j, k)) {
+ Vec3 bulkVel = getBulkVel(flags, vel, i, j, k);
+ int dim = flags.is3D() ? 3 : 2;
+ const Vec3i cur = Vec3i(i, j, k);
+ Vec3i low, up, flLow, flUp;
+ int cnt = 0;
+ // iterate over each velocity component x, y, z
+ for (int c = 0; c < dim; c++) {
+ low = up = flLow = flUp = cur;
+ Real factor = timeStep * max((Real)1.0, bulkVel[c]); // prevent the extrapolated velocity from exploding when bulk velocity below 1
+ low[c] = flLow[c] = cur[c] - 1;
+ up[c] = flUp[c] = cur[c] + 1;
+ // iterate over bWidth to allow for extrapolation into more distant outflow cells; hard-coded extrapolation distance of two cells
+ for (int d = 0; d<2; d++) {
+ bool extrapolateFromLower = flags.isInBounds(flLow) && flags.isFluid(flLow);
+ bool extrapolateFromUpper = flags.isInBounds(flUp) && flags.isFluid(flUp);
+ if (extrapolateFromLower || extrapolateFromUpper) {
+ if (extrapolateFromLower) {
+ velDst(i, j, k) += ((vel(i, j, k) - velPrev(i, j, k)) / factor) + vel(low);
+ cnt++;
+ }
+ if (extrapolateFromUpper) {
+ // check for cells equally far away from two fluid cells -> average value between both sides
+ velDst(i, j, k) += ((vel(i, j, k) - velPrev(i, j, k)) / factor) + vel(up);
+ cnt++;
+ }
+ break;
+ }
+ flLow[c]--;
+ flUp[c]++;
+ }
+ }
+ if (cnt > 0) velDst(i, j, k) /= cnt;
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return velDst; }
+ typedef MACGrid type2;inline const MACGrid& getArg3() {
+ return velPrev; }
+ typedef MACGrid type3;inline Real& getArg4() {
+ return timeStep; }
+ typedef Real type4; void runMessage() { debMsg("Executing kernel extrapolateVelConvectiveBC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,vel,velDst,velPrev,timeStep); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,vel,velDst,velPrev,timeStep); }
+ }
+ }
+ const FlagGrid& flags; const MACGrid& vel; MACGrid& velDst; const MACGrid& velPrev; Real timeStep; }
+;
+
+//! copy extrapolated velocity components
+ struct copyChangedVels : public KernelBase {
+ copyChangedVels(const FlagGrid& flags, const MACGrid& velDst, MACGrid& vel) : KernelBase(&flags,0) ,flags(flags),velDst(velDst),vel(vel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& velDst, MACGrid& vel ) { if (flags.isOutflow(i,j,k)) vel(i, j, k) = velDst(i, j, k); } inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return velDst; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2; void runMessage() { debMsg("Executing kernel copyChangedVels ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,velDst,vel); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,velDst,vel); }
+ }
+ }
+ const FlagGrid& flags; const MACGrid& velDst; MACGrid& vel; }
+;
+
+//! extrapolate normal velocity components into open boundary cells (marked as outflow cells)
+void applyOutflowBC(const FlagGrid& flags, MACGrid& vel, const MACGrid& velPrev, double timeStep) {
+ MACGrid velDst(vel.getParent()); // do not overwrite vel while it is read
+ extrapolateVelConvectiveBC(flags, vel, velDst, velPrev, max(1.0,timeStep*4));
+ copyChangedVels(flags,velDst,vel);
+}
+
+// advection helpers
+
+//! prevent parts of the surface getting "stuck" in obstacle regions
+ struct knResetPhiInObs : public KernelBase {
+ knResetPhiInObs(const FlagGrid& flags, Grid<Real>& sdf) : KernelBase(&flags,0) ,flags(flags),sdf(sdf) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& sdf ) {
+ if( flags.isObstacle(i,j,k) && (sdf(i,j,k)<0.) ) {
+ sdf(i,j,k) = 0.1;
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return sdf; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel knResetPhiInObs ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,sdf); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,sdf); }
+ }
+ }
+ const FlagGrid& flags; Grid<Real>& sdf; }
+;
+void resetPhiInObs(const FlagGrid& flags, Grid<Real>& sdf) { knResetPhiInObs(flags, sdf); } static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "resetPhiInObs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& sdf = *_args.getPtr<Grid<Real> >("sdf",1,&_lock); _retval = getPyNone(); resetPhiInObs(flags,sdf); _args.check(); }
+ pbFinalizePlugin(parent,"resetPhiInObs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("resetPhiInObs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_resetPhiInObs ("","resetPhiInObs",_W_0);
+extern "C" {
+ void PbRegister_resetPhiInObs() {
+ KEEP_UNUSED(_RP_resetPhiInObs); }
+ }
+
+
+
+// advection main calls
+
+//! template function for performing SL advection: specialized version for MAC grids
+template<>
+void fnAdvectSemiLagrange<MACGrid>(FluidSolver* parent, const FlagGrid& flags, const MACGrid& vel, MACGrid& orig, int order, Real strength, int orderSpace, int clampMode, int orderTrace) {
+ Real dt = parent->getDt();
+
+ // forward step
+ MACGrid fwd(parent);
+ SemiLagrangeMAC (flags, vel, fwd, orig, dt, orderSpace, orderTrace);
+
+ if (orderSpace != 1) { debMsg("Warning higher order for MAC grids not yet implemented...",1); }
+
+ if (order == 1) {
+ applyOutflowBC(flags, fwd, orig, dt);
+ orig.swap(fwd);
+ }
+ else if (order == 2) { // MacCormack
+ MACGrid bwd(parent);
+ MACGrid newGrid(parent);
+
+ // bwd <- backwards step
+ SemiLagrangeMAC (flags, vel, bwd, fwd, -dt, orderSpace, orderTrace);
+
+ // newGrid <- compute correction
+ MacCormackCorrectMAC<Vec3> (flags, newGrid, orig, fwd, bwd, strength, false, true);
+
+ // clamp values
+ MacCormackClampMAC (flags, vel, newGrid, orig, fwd, dt, clampMode);
+
+ applyOutflowBC(flags, newGrid, orig, dt);
+ orig.swap(newGrid);
+ }
+}
+
+
+//! Perform semi-lagrangian advection of target Real- or Vec3 grid
+//! Open boundary handling needs information about width of border
+//! Clamping modes: 1 regular clamp leading to more overshoot and sharper results, 2 revert to 1st order slightly smoother less overshoot (enable when 1 gives artifacts)
+
+
+void advectSemiLagrange(const FlagGrid* flags, const MACGrid* vel, GridBase* grid, int order = 1, Real strength = 1.0, int orderSpace = 1, bool openBounds = false, int boundaryWidth = -1, int clampMode = 2, int orderTrace = 1) {
+ assertMsg(order==1 || order==2, "AdvectSemiLagrange: Only order 1 (regular SL) and 2 (MacCormack) supported");
+ if((boundaryWidth!=-1)||(openBounds)) { debMsg("Warning: boundaryWidth and openBounds parameters in AdvectSemiLagrange plugin are deprecated (and have no more effect), please remove.", 0); }
+
+ // determine type of grid
+ if (grid->getType() & GridBase::TypeReal) {
+ fnAdvectSemiLagrange< Grid<Real> >(flags->getParent(), *flags, *vel, *((Grid<Real>*) grid), order, strength, orderSpace, clampMode, orderTrace);
+ }
+ else if (grid->getType() & GridBase::TypeMAC) {
+ fnAdvectSemiLagrange< MACGrid >(flags->getParent(), *flags, *vel, *((MACGrid*) grid), order, strength, orderSpace, clampMode, orderTrace);
+ }
+ else if (grid->getType() & GridBase::TypeVec3) {
+ fnAdvectSemiLagrange< Grid<Vec3> >(flags->getParent(), *flags, *vel, *((Grid<Vec3>*) grid), order, strength, orderSpace, clampMode, orderTrace);
+ }
+ else
+ errMsg("AdvectSemiLagrange: Grid Type is not supported (only Real, Vec3, MAC, Levelset)");
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "advectSemiLagrange" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid* flags = _args.getPtr<FlagGrid >("flags",0,&_lock); const MACGrid* vel = _args.getPtr<MACGrid >("vel",1,&_lock); GridBase* grid = _args.getPtr<GridBase >("grid",2,&_lock); int order = _args.getOpt<int >("order",3,1,&_lock); Real strength = _args.getOpt<Real >("strength",4,1.0,&_lock); int orderSpace = _args.getOpt<int >("orderSpace",5,1,&_lock); bool openBounds = _args.getOpt<bool >("openBounds",6,false,&_lock); int boundaryWidth = _args.getOpt<int >("boundaryWidth",7,-1,&_lock); int clampMode = _args.getOpt<int >("clampMode",8,2,&_lock); int orderTrace = _args.getOpt<int >("orderTrace",9,1,&_lock); _retval = getPyNone(); advectSemiLagrange(flags,vel,grid,order,strength,orderSpace,openBounds,boundaryWidth,clampMode,orderTrace); _args.check(); }
+ pbFinalizePlugin(parent,"advectSemiLagrange", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("advectSemiLagrange",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_advectSemiLagrange ("","advectSemiLagrange",_W_1);
+extern "C" {
+ void PbRegister_advectSemiLagrange() {
+ KEEP_UNUSED(_RP_advectSemiLagrange); }
+ }
+
+
+
+} // end namespace DDF
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/apic.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/apic.cpp
new file mode 100644
index 00000000000..63dff0353fa
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/apic.cpp
@@ -0,0 +1,278 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+// ----------------------------------------------------------------------------
+//
+// MantaFlow fluid solver framework
+// Copyright 2016-2017 Kiwon Um, Nils Thuerey
+//
+// This program is free software, distributed under the terms of the
+// Apache License, Version 2.0
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Affine Particle-In-Cell
+//
+// ----------------------------------------------------------------------------
+
+#include "particle.h"
+#include "grid.h"
+
+namespace Manta {
+
+
+
+
+
+
+ struct knApicMapLinearVec3ToMACGrid : public KernelBase {
+ knApicMapLinearVec3ToMACGrid( const BasicParticleSystem &p, MACGrid &mg, MACGrid &vg, const ParticleDataImpl<Vec3> &vp, const ParticleDataImpl<Vec3> &cpx, const ParticleDataImpl<Vec3> &cpy, const ParticleDataImpl<Vec3> &cpz, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(p.size()) ,p(p),mg(mg),vg(vg),vp(vp),cpx(cpx),cpy(cpy),cpz(cpz),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem &p, MACGrid &mg, MACGrid &vg, const ParticleDataImpl<Vec3> &vp, const ParticleDataImpl<Vec3> &cpx, const ParticleDataImpl<Vec3> &cpy, const ParticleDataImpl<Vec3> &cpz, const ParticleDataImpl<int> *ptype, const int exclude ) {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ const IndexInt dX[2] = { 0, vg.getStrideX() };
+ const IndexInt dY[2] = { 0, vg.getStrideY() };
+ const IndexInt dZ[2] = { 0, vg.getStrideZ() };
+
+ const Vec3 &pos = p[idx].pos, &vel = vp[idx];
+ const IndexInt fi = static_cast<IndexInt>(pos.x ), fj = static_cast<IndexInt>(pos.y ), fk = static_cast<IndexInt>(pos.z );
+ const IndexInt ci = static_cast<IndexInt>(pos.x-0.5), cj = static_cast<IndexInt>(pos.y-0.5), ck = static_cast<IndexInt>(pos.z-0.5);
+ const Real wfi = clamp(pos.x-fi, Real(0), Real(1)), wfj = clamp(pos.y-fj, Real(0), Real(1)), wfk = clamp(pos.z-fk, Real(0), Real(1));
+ const Real wci = clamp(Real(pos.x-ci-0.5), Real(0), Real(1)), wcj = clamp(Real(pos.y-cj-0.5), Real(0), Real(1)), wck = clamp(Real(pos.z-ck-0.5), Real(0), Real(1));
+ // TODO: check index for safety
+ { // u-face
+ const IndexInt gidx = fi*dX[1] + cj*dY[1] + ck*dZ[1];
+ const Vec3 gpos(fi, cj+0.5, ck+0.5);
+ const Real wi[2] = { Real(1)-wfi, wfi };
+ const Real wj[2] = { Real(1)-wcj, wcj };
+ const Real wk[2] = { Real(1)-wck, wck };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const Real w = wi[i]*wj[j]*wk[k];
+ mg[gidx+dX[i]+dY[j]+dZ[k]].x += w;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].x += w*vel.x;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].x += w*dot(cpx[idx], gpos + Vec3(i, j, k) - pos);
+ }
+ }
+ { // v-face
+ const IndexInt gidx = ci*dX[1] + fj*dY[1] + ck*dZ[1];
+ const Vec3 gpos(ci+0.5, fj, ck+0.5);
+ const Real wi[2] = { Real(1)-wci, wci };
+ const Real wj[2] = { Real(1)-wfj, wfj };
+ const Real wk[2] = { Real(1)-wck, wck };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const Real w = wi[i]*wj[j]*wk[k];
+ mg[gidx+dX[i]+dY[j]+dZ[k]].y += w;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].y += w*vel.y;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].y += w*dot(cpy[idx], gpos + Vec3(i, j, k) - pos);
+ }
+ }
+ if(!vg.is3D()) return;
+ { // w-face
+ const IndexInt gidx = ci*dX[1] + cj*dY[1] + fk*dZ[1];
+ const Vec3 gpos(ci+0.5, cj+0.5, fk);
+ const Real wi[2] = { Real(1)-wci, wci };
+ const Real wj[2] = { Real(1)-wcj, wcj };
+ const Real wk[2] = { Real(1)-wfk, wfk };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const Real w = wi[i]*wj[j]*wk[k];
+ mg[gidx+dX[i]+dY[j]+dZ[k]].z += w;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].z += w*vel.z;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].z += w*dot(cpz[idx], gpos + Vec3(i, j, k) - pos);
+ }
+ }
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline MACGrid& getArg1() {
+ return mg; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return vg; }
+ typedef MACGrid type2;inline const ParticleDataImpl<Vec3> & getArg3() {
+ return vp; }
+ typedef ParticleDataImpl<Vec3> type3;inline const ParticleDataImpl<Vec3> & getArg4() {
+ return cpx; }
+ typedef ParticleDataImpl<Vec3> type4;inline const ParticleDataImpl<Vec3> & getArg5() {
+ return cpy; }
+ typedef ParticleDataImpl<Vec3> type5;inline const ParticleDataImpl<Vec3> & getArg6() {
+ return cpz; }
+ typedef ParticleDataImpl<Vec3> type6;inline const ParticleDataImpl<int> * getArg7() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type7;inline const int& getArg8() {
+ return exclude; }
+ typedef int type8; void runMessage() { debMsg("Executing kernel knApicMapLinearVec3ToMACGrid ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size; for (IndexInt i = 0; i < _sz; i++) op(i, p,mg,vg,vp,cpx,cpy,cpz,ptype,exclude); }
+ const BasicParticleSystem& p; MACGrid& mg; MACGrid& vg; const ParticleDataImpl<Vec3> & vp; const ParticleDataImpl<Vec3> & cpx; const ParticleDataImpl<Vec3> & cpy; const ParticleDataImpl<Vec3> & cpz; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+
+
+
+
+
+
+
+void apicMapPartsToMAC( const FlagGrid &flags, MACGrid &vel, const BasicParticleSystem &parts, const ParticleDataImpl<Vec3> &partVel, const ParticleDataImpl<Vec3> &cpx, const ParticleDataImpl<Vec3> &cpy, const ParticleDataImpl<Vec3> &cpz, MACGrid *mass=NULL, const ParticleDataImpl<int> *ptype=NULL, const int exclude=0) {
+ // affine map
+ // let's assume that the particle mass is constant, 1.0
+ const bool freeMass = !mass;
+ if(!mass) mass = new MACGrid(flags.getParent());
+ else mass->clear();
+
+ vel.clear();
+ knApicMapLinearVec3ToMACGrid(parts, *mass, vel, partVel, cpx, cpy, cpz, ptype, exclude);
+ mass->stomp(VECTOR_EPSILON);
+ vel.safeDivide(*mass);
+
+ if(freeMass) delete mass;
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "apicMapPartsToMAC" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); const ParticleDataImpl<Vec3> & partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",3,&_lock); const ParticleDataImpl<Vec3> & cpx = *_args.getPtr<ParticleDataImpl<Vec3> >("cpx",4,&_lock); const ParticleDataImpl<Vec3> & cpy = *_args.getPtr<ParticleDataImpl<Vec3> >("cpy",5,&_lock); const ParticleDataImpl<Vec3> & cpz = *_args.getPtr<ParticleDataImpl<Vec3> >("cpz",6,&_lock); MACGrid* mass = _args.getPtrOpt<MACGrid >("mass",7,NULL,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",8,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",9,0,&_lock); _retval = getPyNone(); apicMapPartsToMAC(flags,vel,parts,partVel,cpx,cpy,cpz,mass,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"apicMapPartsToMAC", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("apicMapPartsToMAC",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_apicMapPartsToMAC ("","apicMapPartsToMAC",_W_0);
+extern "C" {
+ void PbRegister_apicMapPartsToMAC() {
+ KEEP_UNUSED(_RP_apicMapPartsToMAC); }
+ }
+
+
+
+
+
+
+
+
+ struct knApicMapLinearMACGridToVec3 : public KernelBase {
+ knApicMapLinearMACGridToVec3( ParticleDataImpl<Vec3> &vp, ParticleDataImpl<Vec3> &cpx, ParticleDataImpl<Vec3> &cpy, ParticleDataImpl<Vec3> &cpz, const BasicParticleSystem &p, const MACGrid &vg, const FlagGrid &flags, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(vp.size()) ,vp(vp),cpx(cpx),cpy(cpy),cpz(cpz),p(p),vg(vg),flags(flags),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<Vec3> &vp, ParticleDataImpl<Vec3> &cpx, ParticleDataImpl<Vec3> &cpy, ParticleDataImpl<Vec3> &cpz, const BasicParticleSystem &p, const MACGrid &vg, const FlagGrid &flags, const ParticleDataImpl<int> *ptype, const int exclude ) {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+
+ vp[idx] = cpx[idx] = cpy[idx] = cpz[idx] = Vec3(Real(0));
+ const IndexInt dX[2] = {0, vg.getStrideX()}, dY[2] = {0, vg.getStrideY()}, dZ[2] = {0, vg.getStrideZ()};
+ const Real gw[2] = {-Real(1), Real(1)};
+
+ const Vec3 &pos = p[idx].pos;
+ const IndexInt fi = static_cast<IndexInt>(pos.x ), fj = static_cast<IndexInt>(pos.y ), fk = static_cast<IndexInt>(pos.z );
+ const IndexInt ci = static_cast<IndexInt>(pos.x-0.5), cj = static_cast<IndexInt>(pos.y-0.5), ck = static_cast<IndexInt>(pos.z-0.5);
+ const Real wfi = clamp(pos.x-fi, Real(0), Real(1)), wfj = clamp(pos.y-fj, Real(0), Real(1)), wfk = clamp(pos.z-fk, Real(0), Real(1));
+ const Real wci = clamp(Real(pos.x-ci-0.5), Real(0), Real(1)), wcj = clamp(Real(pos.y-cj-0.5), Real(0), Real(1)), wck = clamp(Real(pos.z-ck-0.5), Real(0), Real(1));
+ // TODO: check index for safety
+ { // u
+ const IndexInt gidx = fi*dX[1] + cj*dY[1] + ck*dZ[1];
+ const Real wx[2] = { Real(1)-wfi, wfi };
+ const Real wy[2] = { Real(1)-wcj, wcj };
+ const Real wz[2] = { Real(1)-wck, wck };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const IndexInt vidx = gidx+dX[i]+dY[j]+dZ[k];
+ Real vgx = vg[vidx].x;
+ vp[idx].x += wx[i]*wy[j]*wz[k]*vgx;
+ cpx[idx].x += gw[i]*wy[j]*wz[k]*vgx;
+ cpx[idx].y += wx[i]*gw[j]*wz[k]*vgx;
+ cpx[idx].z += wx[i]*wy[j]*gw[k]*vgx;
+ }
+ }
+ { // v
+ const IndexInt gidx = ci*dX[1] + fj*dY[1] + ck*dZ[1];
+ const Real wx[2] = { Real(1)-wci, wci };
+ const Real wy[2] = { Real(1)-wfj, wfj };
+ const Real wz[2] = { Real(1)-wck, wck };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const IndexInt vidx = gidx+dX[i]+dY[j]+dZ[k];
+ Real vgy = vg[vidx].y;
+ vp[idx].y += wx[i]*wy[j]*wz[k]*vgy;
+ cpy[idx].x += gw[i]*wy[j]*wz[k]*vgy;
+ cpy[idx].y += wx[i]*gw[j]*wz[k]*vgy;
+ cpy[idx].z += wx[i]*wy[j]*gw[k]*vgy;
+ }
+ }
+ if(!vg.is3D()) return;
+ { // w
+ const IndexInt gidx = ci*dX[1] + cj*dY[1] + fk*dZ[1];
+ const Real wx[2] = { Real(1)-wci, wci };
+ const Real wy[2] = { Real(1)-wcj, wcj };
+ const Real wz[2] = { Real(1)-wfk, wfk };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const IndexInt vidx = gidx+dX[i]+dY[j]+dZ[k];
+ Real vgz = vg[vidx].z;
+ vp[idx].z += wx[i]*wy[j]*wz[k]*vgz;
+ cpz[idx].x += gw[i]*wy[j]*wz[k]*vgz;
+ cpz[idx].y += wx[i]*gw[j]*wz[k]*vgz;
+ cpz[idx].z += wx[i]*wy[j]*gw[k]*vgz;
+ }
+ }
+} inline ParticleDataImpl<Vec3> & getArg0() {
+ return vp; }
+ typedef ParticleDataImpl<Vec3> type0;inline ParticleDataImpl<Vec3> & getArg1() {
+ return cpx; }
+ typedef ParticleDataImpl<Vec3> type1;inline ParticleDataImpl<Vec3> & getArg2() {
+ return cpy; }
+ typedef ParticleDataImpl<Vec3> type2;inline ParticleDataImpl<Vec3> & getArg3() {
+ return cpz; }
+ typedef ParticleDataImpl<Vec3> type3;inline const BasicParticleSystem& getArg4() {
+ return p; }
+ typedef BasicParticleSystem type4;inline const MACGrid& getArg5() {
+ return vg; }
+ typedef MACGrid type5;inline const FlagGrid& getArg6() {
+ return flags; }
+ typedef FlagGrid type6;inline const ParticleDataImpl<int> * getArg7() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type7;inline const int& getArg8() {
+ return exclude; }
+ typedef int type8; void runMessage() { debMsg("Executing kernel knApicMapLinearMACGridToVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,vp,cpx,cpy,cpz,p,vg,flags,ptype,exclude); }
+ }
+ ParticleDataImpl<Vec3> & vp; ParticleDataImpl<Vec3> & cpx; ParticleDataImpl<Vec3> & cpy; ParticleDataImpl<Vec3> & cpz; const BasicParticleSystem& p; const MACGrid& vg; const FlagGrid& flags; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+
+
+
+
+
+
+void apicMapMACGridToParts( ParticleDataImpl<Vec3> &partVel, ParticleDataImpl<Vec3> &cpx, ParticleDataImpl<Vec3> &cpy, ParticleDataImpl<Vec3> &cpz, const BasicParticleSystem &parts, const MACGrid &vel, const FlagGrid &flags, const ParticleDataImpl<int> *ptype=NULL, const int exclude=0) {
+ knApicMapLinearMACGridToVec3(partVel, cpx, cpy, cpz, parts, vel, flags, ptype, exclude);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "apicMapMACGridToParts" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; ParticleDataImpl<Vec3> & partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",0,&_lock); ParticleDataImpl<Vec3> & cpx = *_args.getPtr<ParticleDataImpl<Vec3> >("cpx",1,&_lock); ParticleDataImpl<Vec3> & cpy = *_args.getPtr<ParticleDataImpl<Vec3> >("cpy",2,&_lock); ParticleDataImpl<Vec3> & cpz = *_args.getPtr<ParticleDataImpl<Vec3> >("cpz",3,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",4,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",5,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",6,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",7,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",8,0,&_lock); _retval = getPyNone(); apicMapMACGridToParts(partVel,cpx,cpy,cpz,parts,vel,flags,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"apicMapMACGridToParts", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("apicMapMACGridToParts",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_apicMapMACGridToParts ("","apicMapMACGridToParts",_W_1);
+extern "C" {
+ void PbRegister_apicMapMACGridToParts() {
+ KEEP_UNUSED(_RP_apicMapMACGridToParts); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/extforces.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/extforces.cpp
new file mode 100644
index 00000000000..693252ca1d2
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/extforces.cpp
@@ -0,0 +1,855 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * Set boundary conditions, gravity
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "commonkernels.h"
+#include "particle.h"
+
+using namespace std;
+
+namespace Manta {
+
+//! add constant force between fl/fl and fl/em cells
+ struct KnApplyForceField : public KernelBase {
+ KnApplyForceField(const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force, const Grid<Real>* include, bool additive, bool isMAC) : KernelBase(&flags,1) ,flags(flags),vel(vel),force(force),include(include),additive(additive),isMAC(isMAC) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force, const Grid<Real>* include, bool additive, bool isMAC ) {
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curEmpty = flags.isEmpty(i,j,k);
+ if (!curFluid && !curEmpty) return;
+ if (include && ((*include)(i,j,k) > 0.)) return;
+
+ Real forceX = (isMAC) ? force(i,j,k).x : 0.5*(force(i-1,j,k).x + force(i,j,k).x);
+ Real forceY = (isMAC) ? force(i,j,k).y : 0.5*(force(i,j-1,k).y + force(i,j,k).y);
+
+ Real forceZ = 0.;
+ if(vel.is3D())
+ forceZ = (isMAC) ? force(i,j,k).z : 0.5*(force(i,j,k-1).z + force(i,j,k).z);
+
+ if (flags.isFluid(i-1,j,k) || (curFluid && flags.isEmpty(i-1,j,k)))
+ vel(i,j,k).x = (additive) ? vel(i,j,k).x+forceX : forceX;
+ if (flags.isFluid(i,j-1,k) || (curFluid && flags.isEmpty(i,j-1,k)))
+ vel(i,j,k).y = (additive) ? vel(i,j,k).y+forceY : forceY;
+ if (vel.is3D() && (flags.isFluid(i,j,k-1) || (curFluid && flags.isEmpty(i,j,k-1))))
+ vel(i,j,k).z = (additive) ? vel(i,j,k).z+forceZ : forceZ;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const Grid<Vec3>& getArg2() {
+ return force; }
+ typedef Grid<Vec3> type2;inline const Grid<Real>* getArg3() {
+ return include; }
+ typedef Grid<Real> type3;inline bool& getArg4() {
+ return additive; }
+ typedef bool type4;inline bool& getArg5() {
+ return isMAC; }
+ typedef bool type5; void runMessage() { debMsg("Executing kernel KnApplyForceField ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,force,include,additive,isMAC); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,force,include,additive,isMAC); }
+ }
+ }
+ const FlagGrid& flags; MACGrid& vel; const Grid<Vec3>& force; const Grid<Real>* include; bool additive; bool isMAC; }
+;
+
+//! add constant force between fl/fl and fl/em cells
+ struct KnApplyForce : public KernelBase {
+ KnApplyForce(const FlagGrid& flags, MACGrid& vel, Vec3 force, const Grid<Real>* exclude, bool additive) : KernelBase(&flags,1) ,flags(flags),vel(vel),force(force),exclude(exclude),additive(additive) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, MACGrid& vel, Vec3 force, const Grid<Real>* exclude, bool additive ) {
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curEmpty = flags.isEmpty(i,j,k);
+ if (!curFluid && !curEmpty) return;
+ if (exclude && ((*exclude)(i,j,k) < 0.)) return;
+
+ if (flags.isFluid(i-1,j,k) || (curFluid && flags.isEmpty(i-1,j,k)))
+ vel(i,j,k).x = (additive) ? vel(i,j,k).x+force.x : force.x;
+ if (flags.isFluid(i,j-1,k) || (curFluid && flags.isEmpty(i,j-1,k)))
+ vel(i,j,k).y = (additive) ? vel(i,j,k).y+force.y : force.y;
+ if (vel.is3D() && (flags.isFluid(i,j,k-1) || (curFluid && flags.isEmpty(i,j,k-1))))
+ vel(i,j,k).z = (additive) ? vel(i,j,k).z+force.z : force.z;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline Vec3& getArg2() {
+ return force; }
+ typedef Vec3 type2;inline const Grid<Real>* getArg3() {
+ return exclude; }
+ typedef Grid<Real> type3;inline bool& getArg4() {
+ return additive; }
+ typedef bool type4; void runMessage() { debMsg("Executing kernel KnApplyForce ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,force,exclude,additive); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,force,exclude,additive); }
+ }
+ }
+ const FlagGrid& flags; MACGrid& vel; Vec3 force; const Grid<Real>* exclude; bool additive; }
+;
+
+//! add gravity forces to all fluid cells, automatically adapts to different grid sizes
+void addGravity(const FlagGrid& flags, MACGrid& vel, Vec3 gravity, const Grid<Real>* exclude=NULL) {
+ Vec3 f = gravity * flags.getParent()->getDt() / flags.getDx();
+ KnApplyForce(flags, vel, f, exclude, true);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addGravity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); Vec3 gravity = _args.get<Vec3 >("gravity",2,&_lock); const Grid<Real>* exclude = _args.getPtrOpt<Grid<Real> >("exclude",3,NULL,&_lock); _retval = getPyNone(); addGravity(flags,vel,gravity,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"addGravity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addGravity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addGravity ("","addGravity",_W_0);
+extern "C" {
+ void PbRegister_addGravity() {
+ KEEP_UNUSED(_RP_addGravity); }
+ }
+
+
+//! add gravity forces to all fluid cells , but dont account for changing cell size
+void addGravityNoScale(const FlagGrid& flags, MACGrid& vel, const Vec3& gravity, const Grid<Real>* exclude=NULL) {
+ const Vec3 f = gravity * flags.getParent()->getDt();
+ KnApplyForce(flags, vel, f, exclude, true);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addGravityNoScale" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Vec3& gravity = _args.get<Vec3 >("gravity",2,&_lock); const Grid<Real>* exclude = _args.getPtrOpt<Grid<Real> >("exclude",3,NULL,&_lock); _retval = getPyNone(); addGravityNoScale(flags,vel,gravity,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"addGravityNoScale", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addGravityNoScale",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addGravityNoScale ("","addGravityNoScale",_W_1);
+extern "C" {
+ void PbRegister_addGravityNoScale() {
+ KEEP_UNUSED(_RP_addGravityNoScale); }
+ }
+
+
+
+//! kernel to add Buoyancy force
+ struct KnAddBuoyancy : public KernelBase {
+ KnAddBuoyancy(const FlagGrid& flags, const Grid<Real>& factor, MACGrid& vel, Vec3 strength) : KernelBase(&flags,1) ,flags(flags),factor(factor),vel(vel),strength(strength) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const Grid<Real>& factor, MACGrid& vel, Vec3 strength ) {
+ if (!flags.isFluid(i,j,k)) return;
+ if (flags.isFluid(i-1,j,k))
+ vel(i,j,k).x += (0.5 * strength.x) * (factor(i,j,k)+factor(i-1,j,k));
+ if (flags.isFluid(i,j-1,k))
+ vel(i,j,k).y += (0.5 * strength.y) * (factor(i,j,k)+factor(i,j-1,k));
+ if (vel.is3D() && flags.isFluid(i,j,k-1))
+ vel(i,j,k).z += (0.5 * strength.z) * (factor(i,j,k)+factor(i,j,k-1));
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const Grid<Real>& getArg1() {
+ return factor; }
+ typedef Grid<Real> type1;inline MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline Vec3& getArg3() {
+ return strength; }
+ typedef Vec3 type3; void runMessage() { debMsg("Executing kernel KnAddBuoyancy ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,factor,vel,strength); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,factor,vel,strength); }
+ }
+ }
+ const FlagGrid& flags; const Grid<Real>& factor; MACGrid& vel; Vec3 strength; }
+;
+
+//! add Buoyancy force based on fctor (e.g. smoke density)
+void addBuoyancy(const FlagGrid& flags, const Grid<Real>& density, MACGrid& vel, Vec3 gravity, Real coefficient=1.) {
+ Vec3 f = -gravity * flags.getParent()->getDt() / flags.getParent()->getDx() * coefficient;
+ KnAddBuoyancy(flags,density, vel, f);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addBuoyancy" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",2,&_lock); Vec3 gravity = _args.get<Vec3 >("gravity",3,&_lock); Real coefficient = _args.getOpt<Real >("coefficient",4,1.,&_lock); _retval = getPyNone(); addBuoyancy(flags,density,vel,gravity,coefficient); _args.check(); }
+ pbFinalizePlugin(parent,"addBuoyancy", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addBuoyancy",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addBuoyancy ("","addBuoyancy",_W_2);
+extern "C" {
+ void PbRegister_addBuoyancy() {
+ KEEP_UNUSED(_RP_addBuoyancy); }
+ }
+
+
+
+// inflow / outflow boundaries
+
+//! helper to parse openbounds string [xXyYzZ] , convert to vec3
+inline void convertDescToVec(const string& desc, Vector3D<bool>& lo, Vector3D<bool>& up) {
+ for (size_t i = 0; i<desc.size(); i++) {
+ if (desc[i] == 'x') lo.x = true;
+ else if (desc[i] == 'y') lo.y = true;
+ else if (desc[i] == 'z') lo.z = true;
+ else if (desc[i] == 'X') up.x = true;
+ else if (desc[i] == 'Y') up.y = true;
+ else if (desc[i] == 'Z') up.z = true;
+ else errMsg("invalid character in boundary description string. Only [xyzXYZ] allowed.");
+ }
+}
+
+//! add empty and outflow flag to cells of open boundaries
+void setOpenBound(FlagGrid& flags, int bWidth, string openBound = "", int type = FlagGrid::TypeOutflow | FlagGrid::TypeEmpty){
+ if (openBound == "") return;
+ Vector3D<bool> lo, up;
+ convertDescToVec(openBound, lo, up);
+
+ FOR_IJK(flags){
+ bool loX = lo.x && i <= bWidth; // a cell which belongs to the lower x open bound
+ bool loY = lo.y && j <= bWidth;
+ bool upX = up.x && i >= flags.getSizeX() - bWidth - 1; // a cell which belongs to the upper x open bound
+ bool upY = up.y && j >= flags.getSizeY() - bWidth - 1;
+ bool innerI = i>bWidth && i<flags.getSizeX() - bWidth - 1; // a cell which does not belong to the lower or upper x bound
+ bool innerJ = j>bWidth && j<flags.getSizeY() - bWidth - 1;
+
+ // when setting boundaries to open: don't set shared part of wall to empty if neighboring wall is not open
+ if ( (!flags.is3D()) && (loX||upX||loY||upY)){
+ if ((loX || upX || innerI) && (loY || upY || innerJ) && flags.isObstacle(i, j, k)) flags(i, j, k) = type;
+ } else {
+ bool loZ = lo.z && k <= bWidth; // a cell which belongs to the lower z open bound
+ bool upZ = up.z && k >= flags.getSizeZ() - bWidth - 1; // a cell which belongs to the upper z open bound
+ bool innerK = k>bWidth && k<flags.getSizeZ() - bWidth - 1; // a cell which does not belong to the lower or upper z bound
+ if (loX || upX || loY || upY || loZ || upZ) {
+ if ((loX || upX || innerI) && (loY || upY || innerJ) && (loZ || upZ || innerK) && flags.isObstacle(i, j, k)) flags(i, j, k) = type;
+ }
+ }
+ }
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setOpenBound" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); int bWidth = _args.get<int >("bWidth",1,&_lock); string openBound = _args.getOpt<string >("openBound",2,"",&_lock); int type = _args.getOpt<int >("type",3,FlagGrid::TypeOutflow | FlagGrid::TypeEmpty,&_lock); _retval = getPyNone(); setOpenBound(flags,bWidth,openBound,type); _args.check(); }
+ pbFinalizePlugin(parent,"setOpenBound", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setOpenBound",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setOpenBound ("","setOpenBound",_W_3);
+extern "C" {
+ void PbRegister_setOpenBound() {
+ KEEP_UNUSED(_RP_setOpenBound); }
+ }
+
+
+
+//! delete fluid and ensure empty flag in outflow cells, delete particles and density and set phi to 0.5
+void resetOutflow(FlagGrid& flags, Grid<Real>* phi = 0, BasicParticleSystem* parts = 0, Grid<Real>* real = 0, Grid<int>* index = 0, ParticleIndexSystem* indexSys = 0){
+ // check if phi and parts -> pindex and gpi already created -> access particles from cell index, avoid extra looping over particles
+ if (parts && (!index || !indexSys)){
+ if (phi) debMsg("resetOpenBound for phi and particles, but missing index and indexSys for enhanced particle access!",1);
+ for (int idx = 0; idx < (int)parts->size(); idx++)
+ if (parts->isActive(idx) && flags.isInBounds(parts->getPos(idx)) && flags.isOutflow(parts->getPos(idx))) parts->kill(idx);
+ }
+ FOR_IJK(flags){
+ if (flags.isOutflow(i,j,k)){
+ flags(i, j, k) = (flags(i, j, k) | FlagGrid::TypeEmpty) & ~FlagGrid::TypeFluid; // make sure there is not fluid flag set and to reset the empty flag
+ // the particles in a cell i,j,k are particles[index(i,j,k)] to particles[index(i+1,j,k)-1]
+ if (parts && index && indexSys){
+ int isysIdxS = index->index(i, j, k);
+ int pStart = (*index)(isysIdxS), pEnd = 0;
+ if (flags.isInBounds(isysIdxS + 1)) pEnd = (*index)(isysIdxS + 1);
+ else pEnd = indexSys->size();
+ // now loop over particles in cell
+ for (int p = pStart; p<pEnd; ++p) {
+ int psrc = (*indexSys)[p].sourceIndex;
+ if (parts->isActive(psrc) && flags.isInBounds(parts->getPos(psrc))) parts->kill(psrc);
+ }
+ }
+ if (phi) (*phi)(i, j, k) = 0.5;
+ if (real) (*real)(i, j, k) = 0;
+ }
+ }
+ if (parts) parts->doCompress();
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "resetOutflow" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",1,0,&_lock); BasicParticleSystem* parts = _args.getPtrOpt<BasicParticleSystem >("parts",2,0,&_lock); Grid<Real>* real = _args.getPtrOpt<Grid<Real> >("real",3,0,&_lock); Grid<int>* index = _args.getPtrOpt<Grid<int> >("index",4,0,&_lock); ParticleIndexSystem* indexSys = _args.getPtrOpt<ParticleIndexSystem >("indexSys",5,0,&_lock); _retval = getPyNone(); resetOutflow(flags,phi,parts,real,index,indexSys); _args.check(); }
+ pbFinalizePlugin(parent,"resetOutflow", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("resetOutflow",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_resetOutflow ("","resetOutflow",_W_4);
+extern "C" {
+ void PbRegister_resetOutflow() {
+ KEEP_UNUSED(_RP_resetOutflow); }
+ }
+
+
+
+//! enforce a constant inflow/outflow at the grid boundaries
+ struct KnSetInflow : public KernelBase {
+ KnSetInflow(MACGrid& vel, int dim, int p0, const Vec3& val) : KernelBase(&vel,0) ,vel(vel),dim(dim),p0(p0),val(val) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& vel, int dim, int p0, const Vec3& val ) {
+ Vec3i p(i,j,k);
+ if (p[dim] == p0 || p[dim] == p0+1)
+ vel(i,j,k) = val;
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline int& getArg1() {
+ return dim; }
+ typedef int type1;inline int& getArg2() {
+ return p0; }
+ typedef int type2;inline const Vec3& getArg3() {
+ return val; }
+ typedef Vec3 type3; void runMessage() { debMsg("Executing kernel KnSetInflow ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,vel,dim,p0,val); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,vel,dim,p0,val); }
+ }
+ }
+ MACGrid& vel; int dim; int p0; const Vec3& val; }
+;
+
+//! enforce a constant inflow/outflow at the grid boundaries
+void setInflowBcs(MACGrid& vel, string dir, Vec3 value) {
+ for(size_t i=0; i<dir.size(); i++) {
+ if (dir[i] >= 'x' && dir[i] <= 'z') {
+ int dim = dir[i]-'x';
+ KnSetInflow(vel,dim,0,value);
+ } else if (dir[i] >= 'X' && dir[i] <= 'Z') {
+ int dim = dir[i]-'X';
+ KnSetInflow(vel,dim,vel.getSize()[dim]-1,value);
+ } else
+ errMsg("invalid character in direction string. Only [xyzXYZ] allowed.");
+ }
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setInflowBcs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); string dir = _args.get<string >("dir",1,&_lock); Vec3 value = _args.get<Vec3 >("value",2,&_lock); _retval = getPyNone(); setInflowBcs(vel,dir,value); _args.check(); }
+ pbFinalizePlugin(parent,"setInflowBcs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setInflowBcs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setInflowBcs ("","setInflowBcs",_W_5);
+extern "C" {
+ void PbRegister_setInflowBcs() {
+ KEEP_UNUSED(_RP_setInflowBcs); }
+ }
+
+
+
+// set obstacle boundary conditions
+
+//! set no-stick wall boundary condition between ob/fl and ob/ob cells
+ struct KnSetWallBcs : public KernelBase {
+ KnSetWallBcs(const FlagGrid& flags, MACGrid& vel, const MACGrid* obvel) : KernelBase(&flags,0) ,flags(flags),vel(vel),obvel(obvel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, MACGrid& vel, const MACGrid* obvel ) {
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curObs = flags.isObstacle(i,j,k);
+ Vec3 bcsVel(0.,0.,0.);
+ if (!curFluid && !curObs) return;
+
+ if (obvel) {
+ bcsVel.x = (*obvel)(i,j,k).x;
+ bcsVel.y = (*obvel)(i,j,k).y;
+ if((*obvel).is3D()) bcsVel.z = (*obvel)(i,j,k).z;
+ }
+
+ // we use i>0 instead of bnd=1 to check outer wall
+ if (i>0 && flags.isObstacle(i-1,j,k)) vel(i,j,k).x = bcsVel.x;
+ if (i>0 && curObs && flags.isFluid(i-1,j,k)) vel(i,j,k).x = bcsVel.x;
+ if (j>0 && flags.isObstacle(i,j-1,k)) vel(i,j,k).y = bcsVel.y;
+ if (j>0 && curObs && flags.isFluid(i,j-1,k)) vel(i,j,k).y = bcsVel.y;
+
+ if(!vel.is3D()) { vel(i,j,k).z = 0; } else {
+ if (k>0 && flags.isObstacle(i,j,k-1)) vel(i,j,k).z = bcsVel.z;
+ if (k>0 && curObs && flags.isFluid(i,j,k-1)) vel(i,j,k).z = bcsVel.z; }
+
+ if (curFluid) {
+ if ((i>0 && flags.isStick(i-1,j,k)) || (i<flags.getSizeX()-1 && flags.isStick(i+1,j,k)))
+ vel(i,j,k).y = vel(i,j,k).z = 0;
+ if ((j>0 && flags.isStick(i,j-1,k)) || (j<flags.getSizeY()-1 && flags.isStick(i,j+1,k)))
+ vel(i,j,k).x = vel(i,j,k).z = 0;
+ if (vel.is3D() && ((k>0 && flags.isStick(i,j,k-1)) || (k<flags.getSizeZ()-1 && flags.isStick(i,j,k+1))))
+ vel(i,j,k).x = vel(i,j,k).y = 0;
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const MACGrid* getArg2() {
+ return obvel; }
+ typedef MACGrid type2; void runMessage() { debMsg("Executing kernel KnSetWallBcs ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,vel,obvel); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,vel,obvel); }
+ }
+ }
+ const FlagGrid& flags; MACGrid& vel; const MACGrid* obvel; }
+;
+
+//! set wall BCs for fill fraction mode, note - only needs obstacle SDF
+
+ struct KnSetWallBcsFrac : public KernelBase {
+ KnSetWallBcsFrac(const FlagGrid& flags, const MACGrid& vel, MACGrid& velTarget, const MACGrid* obvel, const Grid<Real>* phiObs, const int &boundaryWidth=0) : KernelBase(&flags,0) ,flags(flags),vel(vel),velTarget(velTarget),obvel(obvel),phiObs(phiObs),boundaryWidth(boundaryWidth) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, MACGrid& velTarget, const MACGrid* obvel, const Grid<Real>* phiObs, const int &boundaryWidth=0 ) {
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curObs = flags.isObstacle(i,j,k);
+ velTarget(i,j,k) = vel(i,j,k);
+ if (!curFluid && !curObs) return;
+
+ // zero normal component in all obstacle regions
+ if(flags.isInBounds(Vec3i(i,j,k),1)) {
+
+ if( curObs | flags.isObstacle(i-1,j,k) ) {
+ Vec3 dphi(0.,0.,0.);
+ const Real tmp1 = (phiObs->get(i,j,k)+phiObs->get(i-1,j,k))*.5;
+ Real tmp2 = (phiObs->get(i,j+1,k)+phiObs->get(i-1,j+1,k))*.5;
+ Real phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i,j-1,k)+phiObs->get(i-1,j-1,k))*.5;
+ Real phi2 = (tmp1+tmp2)*.5;
+
+ dphi.x = phiObs->get(i,j,k)-phiObs->get(i-1,j,k);
+ dphi.y = phi1-phi2;
+
+ if(phiObs->is3D()) {
+ tmp2 = (phiObs->get(i,j,k+1)+phiObs->get(i-1,j,k+1))*.5;
+ phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i,j,k-1)+phiObs->get(i-1,j,k-1))*.5;
+ phi2 = (tmp1+tmp2)*.5;
+ dphi.z = phi1-phi2;
+ }
+
+ normalize(dphi);
+ Vec3 velMAC = vel.getAtMACX(i,j,k);
+ velTarget(i,j,k).x = velMAC.x - dot(dphi, velMAC) * dphi.x;
+ if (obvel) { // TODO (sebbas): TBC
+ Vec3 obvelMAC = (*obvel).getAtMACX(i,j,k);
+ velTarget(i,j,k).x += dot(dphi, obvelMAC) * dphi.x;
+ }
+ }
+
+ if( curObs | flags.isObstacle(i,j-1,k) ) {
+ Vec3 dphi(0.,0.,0.);
+ const Real tmp1 = (phiObs->get(i,j,k)+phiObs->get(i,j-1,k))*.5;
+ Real tmp2 = (phiObs->get(i+1,j,k)+phiObs->get(i+1,j-1,k))*.5;
+ Real phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i-1,j,k)+phiObs->get(i-1,j-1,k))*.5;
+ Real phi2 = (tmp1+tmp2)*.5;
+
+ dphi.x = phi1-phi2;
+ dphi.y = phiObs->get(i,j,k)-phiObs->get(i,j-1,k);
+ if(phiObs->is3D()) {
+ tmp2 = (phiObs->get(i,j,k+1)+phiObs->get(i,j-1,k+1))*.5;
+ phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i,j,k-1)+phiObs->get(i,j-1,k-1))*.5;
+ phi2 = (tmp1+tmp2)*.5;
+ dphi.z = phi1-phi2;
+ }
+
+ normalize(dphi);
+ Vec3 velMAC = vel.getAtMACY(i,j,k);
+ velTarget(i,j,k).y = velMAC.y - dot(dphi, velMAC) * dphi.y;
+ if (obvel) { // TODO (sebbas): TBC
+ Vec3 obvelMAC = (*obvel).getAtMACY(i,j,k);
+ velTarget(i,j,k).y += dot(dphi, obvelMAC) * dphi.y;
+ }
+ }
+
+ if( phiObs->is3D() && (curObs | flags.isObstacle(i,j,k-1)) ) {
+ Vec3 dphi(0.,0.,0.);
+ const Real tmp1 = (phiObs->get(i,j,k)+phiObs->get(i,j,k-1))*.5;
+
+ Real tmp2;
+ tmp2 = (phiObs->get(i+1,j,k)+phiObs->get(i+1,j,k-1))*.5;
+ Real phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i-1,j,k)+phiObs->get(i-1,j,k-1))*.5;
+ Real phi2 = (tmp1+tmp2)*.5;
+ dphi.x = phi1-phi2;
+
+ tmp2 = (phiObs->get(i,j+1,k)+phiObs->get(i,j+1,k-1))*.5;
+ phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i,j-1,k)+phiObs->get(i,j-1,k-1))*.5;
+ phi2 = (tmp1+tmp2)*.5;
+ dphi.y = phi1-phi2;
+
+ dphi.z = phiObs->get(i,j,k) - phiObs->get(i,j,k-1);
+
+ normalize(dphi);
+ Vec3 velMAC = vel.getAtMACZ(i,j,k);
+ velTarget(i,j,k).z = velMAC.z - dot(dphi, velMAC) * dphi.z;
+ if (obvel) { // TODO (sebbas): TBC
+ Vec3 obvelMAC = (*obvel).getAtMACZ(i,j,k);
+ velTarget(i,j,k).z += dot(dphi, obvelMAC) * dphi.z;
+ }
+ }
+ } // not at boundary
+
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return velTarget; }
+ typedef MACGrid type2;inline const MACGrid* getArg3() {
+ return obvel; }
+ typedef MACGrid type3;inline const Grid<Real>* getArg4() {
+ return phiObs; }
+ typedef Grid<Real> type4;inline const int& getArg5() {
+ return boundaryWidth; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnSetWallBcsFrac ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,vel,velTarget,obvel,phiObs,boundaryWidth); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,vel,velTarget,obvel,phiObs,boundaryWidth); }
+ }
+ }
+ const FlagGrid& flags; const MACGrid& vel; MACGrid& velTarget; const MACGrid* obvel; const Grid<Real>* phiObs; const int& boundaryWidth; }
+;
+
+//! set zero normal velocity boundary condition on walls
+// (optionally with second order accuracy using the obstacle SDF , fractions grid currentlyl not needed)
+void setWallBcs(const FlagGrid& flags, MACGrid& vel, const MACGrid* obvel = 0, const MACGrid* fractions = 0, const Grid<Real>* phiObs = 0, int boundaryWidth=0) {
+ if(!phiObs || !fractions) {
+ KnSetWallBcs(flags, vel, obvel);
+ } else {
+ MACGrid tmpvel(vel.getParent());
+ KnSetWallBcsFrac(flags, vel, tmpvel, obvel, phiObs, boundaryWidth);
+ vel.swap(tmpvel);
+ }
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setWallBcs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const MACGrid* obvel = _args.getPtrOpt<MACGrid >("obvel",2,0,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",3,0,&_lock); const Grid<Real>* phiObs = _args.getPtrOpt<Grid<Real> >("phiObs",4,0,&_lock); int boundaryWidth = _args.getOpt<int >("boundaryWidth",5,0,&_lock); _retval = getPyNone(); setWallBcs(flags,vel,obvel,fractions,phiObs,boundaryWidth); _args.check(); }
+ pbFinalizePlugin(parent,"setWallBcs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setWallBcs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setWallBcs ("","setWallBcs",_W_6);
+extern "C" {
+ void PbRegister_setWallBcs() {
+ KEEP_UNUSED(_RP_setWallBcs); }
+ }
+
+
+
+//! add Forces between fl/fl and fl/em cells (interpolate cell centered forces to MAC grid)
+ struct KnAddForceIfLower : public KernelBase {
+ KnAddForceIfLower(const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force) : KernelBase(&flags,1) ,flags(flags),vel(vel),force(force) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force ) {
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curEmpty = flags.isEmpty(i,j,k);
+ if (!curFluid && !curEmpty) return;
+
+ if (flags.isFluid(i-1,j,k) || (curFluid && flags.isEmpty(i-1,j,k))) {
+ Real forceMACX = 0.5*(force(i-1,j,k).x + force(i,j,k).x);
+ Real min = std::min(vel(i,j,k).x, forceMACX);
+ Real max = std::max(vel(i,j,k).x, forceMACX);
+ Real sum = vel(i,j,k).x + forceMACX;
+ vel(i,j,k).x = (forceMACX > 0) ? std::min(sum, max) : std::max(sum, min);
+ }
+ if (flags.isFluid(i,j-1,k) || (curFluid && flags.isEmpty(i,j-1,k))) {
+ Real forceMACY = 0.5*(force(i,j-1,k).y + force(i,j,k).y);
+ Real min = std::min(vel(i,j,k).y, forceMACY);
+ Real max = std::max(vel(i,j,k).y, forceMACY);
+ Real sum = vel(i,j,k).y + forceMACY;
+ vel(i,j,k).y = (forceMACY > 0) ? std::min(sum, max) : std::max(sum, min);
+ }
+ if (vel.is3D() && (flags.isFluid(i,j,k-1) || (curFluid && flags.isEmpty(i,j,k-1)))) {
+ Real forceMACZ = 0.5*(force(i,j,k-1).z + force(i,j,k).z);
+ Real min = std::min(vel(i,j,k).z, forceMACZ);
+ Real max = std::max(vel(i,j,k).z, forceMACZ);
+ Real sum = vel(i,j,k).z + forceMACZ;
+ vel(i,j,k).z = (forceMACZ > 0) ? std::min(sum, max) : std::max(sum, min);
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const Grid<Vec3>& getArg2() {
+ return force; }
+ typedef Grid<Vec3> type2; void runMessage() { debMsg("Executing kernel KnAddForceIfLower ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,force); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,force); }
+ }
+ }
+ const FlagGrid& flags; MACGrid& vel; const Grid<Vec3>& force; }
+;
+
+// Initial velocity for smoke
+void setInitialVelocity(const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& invel) {
+ KnAddForceIfLower(flags, vel, invel);
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setInitialVelocity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Grid<Vec3>& invel = *_args.getPtr<Grid<Vec3> >("invel",2,&_lock); _retval = getPyNone(); setInitialVelocity(flags,vel,invel); _args.check(); }
+ pbFinalizePlugin(parent,"setInitialVelocity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setInitialVelocity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setInitialVelocity ("","setInitialVelocity",_W_7);
+extern "C" {
+ void PbRegister_setInitialVelocity() {
+ KEEP_UNUSED(_RP_setInitialVelocity); }
+ }
+
+
+
+//! Kernel: gradient norm operator
+ struct KnConfForce : public KernelBase {
+ KnConfForce(Grid<Vec3>& force, const Grid<Real>& grid, const Grid<Vec3>& curl, Real str) : KernelBase(&force,1) ,force(force),grid(grid),curl(curl),str(str) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& force, const Grid<Real>& grid, const Grid<Vec3>& curl, Real str ) {
+ Vec3 grad = 0.5 * Vec3( grid(i+1,j,k)-grid(i-1,j,k),
+ grid(i,j+1,k)-grid(i,j-1,k), 0.);
+ if(grid.is3D()) grad[2]= 0.5*( grid(i,j,k+1)-grid(i,j,k-1) );
+ normalize(grad);
+ force(i,j,k) = str * cross(grad, curl(i,j,k));
+} inline Grid<Vec3>& getArg0() {
+ return force; }
+ typedef Grid<Vec3> type0;inline const Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1;inline const Grid<Vec3>& getArg2() {
+ return curl; }
+ typedef Grid<Vec3> type2;inline Real& getArg3() {
+ return str; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel KnConfForce ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,force,grid,curl,str); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,force,grid,curl,str); }
+ }
+ }
+ Grid<Vec3>& force; const Grid<Real>& grid; const Grid<Vec3>& curl; Real str; }
+;
+
+void vorticityConfinement(MACGrid& vel, const FlagGrid& flags, Real strength) {
+ Grid<Vec3> velCenter(flags.getParent()), curl(flags.getParent()), force(flags.getParent());
+ Grid<Real> norm(flags.getParent());
+
+ GetCentered(velCenter, vel);
+ CurlOp(velCenter, curl);
+ GridNorm(norm, curl);
+ KnConfForce(force, norm, curl, strength);
+ KnApplyForceField(flags, vel, force, NULL, true, false);
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "vorticityConfinement" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); Real strength = _args.get<Real >("strength",2,&_lock); _retval = getPyNone(); vorticityConfinement(vel,flags,strength); _args.check(); }
+ pbFinalizePlugin(parent,"vorticityConfinement", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("vorticityConfinement",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_vorticityConfinement ("","vorticityConfinement",_W_8);
+extern "C" {
+ void PbRegister_vorticityConfinement() {
+ KEEP_UNUSED(_RP_vorticityConfinement); }
+ }
+
+
+
+void addForceField(const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force, const Grid<Real>* region=NULL, bool isMAC=false) {
+ KnApplyForceField(flags, vel, force, region, true, isMAC);
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addForceField" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Grid<Vec3>& force = *_args.getPtr<Grid<Vec3> >("force",2,&_lock); const Grid<Real>* region = _args.getPtrOpt<Grid<Real> >("region",3,NULL,&_lock); bool isMAC = _args.getOpt<bool >("isMAC",4,false,&_lock); _retval = getPyNone(); addForceField(flags,vel,force,region,isMAC); _args.check(); }
+ pbFinalizePlugin(parent,"addForceField", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addForceField",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addForceField ("","addForceField",_W_9);
+extern "C" {
+ void PbRegister_addForceField() {
+ KEEP_UNUSED(_RP_addForceField); }
+ }
+
+
+
+void setForceField(const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force, const Grid<Real>* region=NULL, bool isMAC=false) {
+ KnApplyForceField(flags, vel, force, region, false, isMAC);
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setForceField" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Grid<Vec3>& force = *_args.getPtr<Grid<Vec3> >("force",2,&_lock); const Grid<Real>* region = _args.getPtrOpt<Grid<Real> >("region",3,NULL,&_lock); bool isMAC = _args.getOpt<bool >("isMAC",4,false,&_lock); _retval = getPyNone(); setForceField(flags,vel,force,region,isMAC); _args.check(); }
+ pbFinalizePlugin(parent,"setForceField", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setForceField",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setForceField ("","setForceField",_W_10);
+extern "C" {
+ void PbRegister_setForceField() {
+ KEEP_UNUSED(_RP_setForceField); }
+ }
+
+
+
+
+
+void dissolveSmoke(const FlagGrid& flags, Grid<Real>& density, Grid<Real>* heat=NULL, Grid<Real>* red=NULL, Grid<Real>* green=NULL, Grid<Real>* blue=NULL, int speed=5, bool logFalloff=true) {
+ float dydx = 1.0f / (float)speed; // max density/speed = dydx
+ float fac = 1.0f - dydx;
+
+ FOR_IJK_BND(density, 0) {
+ bool curFluid = flags.isFluid(i,j,k);
+ if (!curFluid) continue;
+
+ if (logFalloff) {
+ density(i,j,k) *= fac;
+ if (heat) {
+ (*heat)(i,j,k) *= fac;
+ }
+ if (red) {
+ (*red)(i,j,k) *= fac;
+ (*green)(i,j,k) *= fac;
+ (*blue)(i,j,k) *= fac;
+ }
+ }
+ else { // linear falloff
+ float d = density(i,j,k);
+ density(i,j,k) -= dydx;
+ if (density(i,j,k) < 0.0f)
+ density(i,j,k) = 0.0f;
+ if (heat) {
+ if (fabs((*heat)(i,j,k)) < dydx) (*heat)(i,j,k) = 0.0f;
+ else if ((*heat)(i,j,k) > 0.0f) (*heat)(i,j,k) -= dydx;
+ else if ((*heat)(i,j,k) < 0.0f) (*heat)(i,j,k) += dydx;
+ }
+ if (red && notZero(d) ) {
+ (*red)(i,j,k) *= (density(i,j,k)/d);
+ (*green)(i,j,k) *= (density(i,j,k)/d);
+ (*blue)(i,j,k) *= (density(i,j,k)/d);
+ }
+ }
+ }
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "dissolveSmoke" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); Grid<Real>* heat = _args.getPtrOpt<Grid<Real> >("heat",2,NULL,&_lock); Grid<Real>* red = _args.getPtrOpt<Grid<Real> >("red",3,NULL,&_lock); Grid<Real>* green = _args.getPtrOpt<Grid<Real> >("green",4,NULL,&_lock); Grid<Real>* blue = _args.getPtrOpt<Grid<Real> >("blue",5,NULL,&_lock); int speed = _args.getOpt<int >("speed",6,5,&_lock); bool logFalloff = _args.getOpt<bool >("logFalloff",7,true,&_lock); _retval = getPyNone(); dissolveSmoke(flags,density,heat,red,green,blue,speed,logFalloff); _args.check(); }
+ pbFinalizePlugin(parent,"dissolveSmoke", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("dissolveSmoke",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_dissolveSmoke ("","dissolveSmoke",_W_11);
+extern "C" {
+ void PbRegister_dissolveSmoke() {
+ KEEP_UNUSED(_RP_dissolveSmoke); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/fire.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/fire.cpp
new file mode 100644
index 00000000000..df6a827420e
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/fire.cpp
@@ -0,0 +1,207 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2016 Sebastian Barschkis, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Fire modeling plugin
+ *
+ ******************************************************************************/
+
+#include "general.h"
+#include "grid.h"
+#include "vectorbase.h"
+
+using namespace std;
+
+namespace Manta {
+
+
+
+
+
+
+ struct KnProcessBurn : public KernelBase {
+ KnProcessBurn(Grid<Real>& fuel, Grid<Real>& density, Grid<Real>& react, Grid<Real>* red, Grid<Real>* green, Grid<Real>* blue, Grid<Real>* heat, Real burningRate, Real flameSmoke, Real ignitionTemp, Real maxTemp, Real dt, Vec3 flameSmokeColor) : KernelBase(&fuel,1) ,fuel(fuel),density(density),react(react),red(red),green(green),blue(blue),heat(heat),burningRate(burningRate),flameSmoke(flameSmoke),ignitionTemp(ignitionTemp),maxTemp(maxTemp),dt(dt),flameSmokeColor(flameSmokeColor) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& fuel, Grid<Real>& density, Grid<Real>& react, Grid<Real>* red, Grid<Real>* green, Grid<Real>* blue, Grid<Real>* heat, Real burningRate, Real flameSmoke, Real ignitionTemp, Real maxTemp, Real dt, Vec3 flameSmokeColor ) {
+ // Save initial values
+ Real origFuel = fuel(i,j,k);
+ Real origSmoke = density(i,j,k);
+ Real smokeEmit = 0.0f;
+ Real flame = 0.0f;
+
+ // Process fuel
+ fuel(i,j,k) -= burningRate * dt;
+ if (fuel(i,j,k) < 0.0f)
+ fuel(i,j,k) = 0.0f;
+
+ // Process reaction coordinate
+ if (origFuel > VECTOR_EPSILON) {
+ react(i,j,k) *= fuel(i,j,k) / origFuel;
+ flame = pow(react(i,j,k), 0.5f);
+ } else {
+ react(i,j,k) = 0.0f;
+ }
+
+ // Set fluid temperature based on fuel burn rate and "flameSmoke" factor
+ smokeEmit = (origFuel < 1.0f) ? (1.0 - origFuel) * 0.5f : 0.0f;
+ smokeEmit = (smokeEmit + 0.5f) * (origFuel - fuel(i,j,k)) * 0.1f * flameSmoke;
+ density(i,j,k) += smokeEmit;
+ clamp( density(i,j,k), (Real)0.0f, (Real)1.0f);
+
+ // Set fluid temperature from the flame temperature profile
+ if (heat && flame)
+ (*heat)(i,j,k) = (1.0f - flame) * ignitionTemp + flame * maxTemp;
+
+ // Mix new color
+ if (smokeEmit > VECTOR_EPSILON) {
+ float smokeFactor = density(i,j,k) / (origSmoke + smokeEmit);
+ if(red) (*red)(i,j,k) = ((*red)(i,j,k) + flameSmokeColor.x * smokeEmit) * smokeFactor;
+ if(green) (*green)(i,j,k) = ((*green)(i,j,k) + flameSmokeColor.y * smokeEmit) * smokeFactor;
+ if(blue) (*blue)(i,j,k) = ((*blue)(i,j,k) + flameSmokeColor.z * smokeEmit) * smokeFactor;
+ }
+} inline Grid<Real>& getArg0() {
+ return fuel; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return density; }
+ typedef Grid<Real> type1;inline Grid<Real>& getArg2() {
+ return react; }
+ typedef Grid<Real> type2;inline Grid<Real>* getArg3() {
+ return red; }
+ typedef Grid<Real> type3;inline Grid<Real>* getArg4() {
+ return green; }
+ typedef Grid<Real> type4;inline Grid<Real>* getArg5() {
+ return blue; }
+ typedef Grid<Real> type5;inline Grid<Real>* getArg6() {
+ return heat; }
+ typedef Grid<Real> type6;inline Real& getArg7() {
+ return burningRate; }
+ typedef Real type7;inline Real& getArg8() {
+ return flameSmoke; }
+ typedef Real type8;inline Real& getArg9() {
+ return ignitionTemp; }
+ typedef Real type9;inline Real& getArg10() {
+ return maxTemp; }
+ typedef Real type10;inline Real& getArg11() {
+ return dt; }
+ typedef Real type11;inline Vec3& getArg12() {
+ return flameSmokeColor; }
+ typedef Vec3 type12; void runMessage() { debMsg("Executing kernel KnProcessBurn ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,fuel,density,react,red,green,blue,heat,burningRate,flameSmoke,ignitionTemp,maxTemp,dt,flameSmokeColor); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,fuel,density,react,red,green,blue,heat,burningRate,flameSmoke,ignitionTemp,maxTemp,dt,flameSmokeColor); }
+ }
+ }
+ Grid<Real>& fuel; Grid<Real>& density; Grid<Real>& react; Grid<Real>* red; Grid<Real>* green; Grid<Real>* blue; Grid<Real>* heat; Real burningRate; Real flameSmoke; Real ignitionTemp; Real maxTemp; Real dt; Vec3 flameSmokeColor; }
+;
+
+
+
+
+
+
+void processBurn(Grid<Real>& fuel, Grid<Real>& density, Grid<Real>& react, Grid<Real>* red = NULL, Grid<Real>* green = NULL, Grid<Real>* blue = NULL, Grid<Real>* heat = NULL, Real burningRate = 0.75f, Real flameSmoke = 1.0f, Real ignitionTemp = 1.25f, Real maxTemp = 1.75f, Vec3 flameSmokeColor = Vec3(0.7f, 0.7f, 0.7f)) {
+ Real dt = fuel.getParent()->getDt();
+ KnProcessBurn(fuel, density, react, red, green, blue, heat, burningRate,
+ flameSmoke, ignitionTemp, maxTemp, dt, flameSmokeColor);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "processBurn" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& fuel = *_args.getPtr<Grid<Real> >("fuel",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); Grid<Real>& react = *_args.getPtr<Grid<Real> >("react",2,&_lock); Grid<Real>* red = _args.getPtrOpt<Grid<Real> >("red",3,NULL,&_lock); Grid<Real>* green = _args.getPtrOpt<Grid<Real> >("green",4,NULL,&_lock); Grid<Real>* blue = _args.getPtrOpt<Grid<Real> >("blue",5,NULL,&_lock); Grid<Real>* heat = _args.getPtrOpt<Grid<Real> >("heat",6,NULL,&_lock); Real burningRate = _args.getOpt<Real >("burningRate",7,0.75f,&_lock); Real flameSmoke = _args.getOpt<Real >("flameSmoke",8,1.0f,&_lock); Real ignitionTemp = _args.getOpt<Real >("ignitionTemp",9,1.25f,&_lock); Real maxTemp = _args.getOpt<Real >("maxTemp",10,1.75f,&_lock); Vec3 flameSmokeColor = _args.getOpt<Vec3 >("flameSmokeColor",11,Vec3(0.7f, 0.7f, 0.7f),&_lock); _retval = getPyNone(); processBurn(fuel,density,react,red,green,blue,heat,burningRate,flameSmoke,ignitionTemp,maxTemp,flameSmokeColor); _args.check(); }
+ pbFinalizePlugin(parent,"processBurn", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("processBurn",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_processBurn ("","processBurn",_W_0);
+extern "C" {
+ void PbRegister_processBurn() {
+ KEEP_UNUSED(_RP_processBurn); }
+ }
+
+
+
+
+
+
+ struct KnUpdateFlame : public KernelBase {
+ KnUpdateFlame(const Grid<Real>& react, Grid<Real>& flame) : KernelBase(&react,1) ,react(react),flame(flame) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Real>& react, Grid<Real>& flame ) {
+ if (react(i,j,k) > 0.0f)
+ flame(i,j,k) = pow(react(i,j,k), 0.5f);
+ else
+ flame(i,j,k) = 0.0f;
+} inline const Grid<Real>& getArg0() {
+ return react; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return flame; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel KnUpdateFlame ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,react,flame); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,react,flame); }
+ }
+ }
+ const Grid<Real>& react; Grid<Real>& flame; }
+;
+
+
+void updateFlame(const Grid<Real>& react, Grid<Real>& flame) {
+ KnUpdateFlame(react, flame);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "updateFlame" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& react = *_args.getPtr<Grid<Real> >("react",0,&_lock); Grid<Real>& flame = *_args.getPtr<Grid<Real> >("flame",1,&_lock); _retval = getPyNone(); updateFlame(react,flame); _args.check(); }
+ pbFinalizePlugin(parent,"updateFlame", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("updateFlame",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_updateFlame ("","updateFlame",_W_1);
+extern "C" {
+ void PbRegister_updateFlame() {
+ KEEP_UNUSED(_RP_updateFlame); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/flip.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/flip.cpp
new file mode 100644
index 00000000000..ae4094605ce
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/flip.cpp
@@ -0,0 +1,1444 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * FLIP (fluid implicit particles)
+ * for use with particle data fields
+ *
+ ******************************************************************************/
+
+#include "particle.h"
+#include "grid.h"
+#include "commonkernels.h"
+#include "randomstream.h"
+#include "levelset.h"
+#include "shapes.h"
+#include "matrixbase.h"
+
+using namespace std;
+namespace Manta {
+
+
+
+// init
+
+//! note - this is a simplified version , sampleLevelsetWithParticles has more functionality
+
+
+void sampleFlagsWithParticles(const FlagGrid& flags, BasicParticleSystem& parts, const int discretization, const Real randomness) {
+ const bool is3D = flags.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp (1.0 / discretization, 1.0 / discretization, 1.0/discretization);
+ RandomStream mRand(9832);
+
+ FOR_IJK_BND(flags, 0) {
+ if ( flags.isObstacle(i,j,k) ) continue;
+ if ( flags.isFluid(i,j,k) ) {
+ const Vec3 pos (i,j,k);
+ for (int dk=0; dk<(is3D ? discretization : 1); dk++)
+ for (int dj=0; dj<discretization; dj++)
+ for (int di=0; di<discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5+di, 0.5+dj, 0.5+dk);
+ subpos += jlen * (Vec3(1,1,1) - 2.0 * mRand.getVec3());
+ if(!is3D) subpos[2] = 0.5;
+ parts.addBuffered(subpos);
+ }
+ }
+ }
+ parts.insertBufferedParticles();
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "sampleFlagsWithParticles" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",1,&_lock); const int discretization = _args.get<int >("discretization",2,&_lock); const Real randomness = _args.get<Real >("randomness",3,&_lock); _retval = getPyNone(); sampleFlagsWithParticles(flags,parts,discretization,randomness); _args.check(); }
+ pbFinalizePlugin(parent,"sampleFlagsWithParticles", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("sampleFlagsWithParticles",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_sampleFlagsWithParticles ("","sampleFlagsWithParticles",_W_0);
+extern "C" {
+ void PbRegister_sampleFlagsWithParticles() {
+ KEEP_UNUSED(_RP_sampleFlagsWithParticles); }
+ }
+
+
+
+//! sample a level set with particles, use reset to clear the particle buffer,
+//! and skipEmpty for a continuous inflow (in the latter case, only empty cells will
+//! be re-filled once they empty when calling sampleLevelsetWithParticles during
+//! the main loop).
+
+
+void sampleLevelsetWithParticles(const LevelsetGrid& phi, const FlagGrid& flags, BasicParticleSystem& parts, const int discretization, const Real randomness, const bool reset=false, const bool refillEmpty=false, const int particleFlag=-1) {
+ const bool is3D = phi.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp (1.0 / discretization, 1.0 / discretization, 1.0/discretization);
+ RandomStream mRand(9832);
+
+ if(reset) {
+ parts.clear();
+ parts.doCompress();
+ }
+
+ FOR_IJK_BND(phi, 0) {
+ if ( flags.isObstacle(i,j,k) ) continue;
+ if ( refillEmpty && flags.isFluid(i,j,k) ) continue;
+ if ( phi(i,j,k) < 1.733 ) {
+ const Vec3 pos (i,j,k);
+ for (int dk=0; dk<(is3D ? discretization : 1); dk++)
+ for (int dj=0; dj<discretization; dj++)
+ for (int di=0; di<discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5+di, 0.5+dj, 0.5+dk);
+ subpos += jlen * (Vec3(1,1,1) - 2.0 * mRand.getVec3());
+ if(!is3D) subpos[2] = 0.5;
+ if( phi.getInterpolated(subpos) > 0. ) continue;
+ if(particleFlag < 0){
+ parts.addBuffered(subpos);
+ }
+ else{
+ parts.addBuffered(subpos, particleFlag);
+ }
+ }
+ }
+ }
+
+ parts.insertBufferedParticles();
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "sampleLevelsetWithParticles" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); const int discretization = _args.get<int >("discretization",3,&_lock); const Real randomness = _args.get<Real >("randomness",4,&_lock); const bool reset = _args.getOpt<bool >("reset",5,false,&_lock); const bool refillEmpty = _args.getOpt<bool >("refillEmpty",6,false,&_lock); const int particleFlag = _args.getOpt<int >("particleFlag",7,-1,&_lock); _retval = getPyNone(); sampleLevelsetWithParticles(phi,flags,parts,discretization,randomness,reset,refillEmpty,particleFlag); _args.check(); }
+ pbFinalizePlugin(parent,"sampleLevelsetWithParticles", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("sampleLevelsetWithParticles",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_sampleLevelsetWithParticles ("","sampleLevelsetWithParticles",_W_1);
+extern "C" {
+ void PbRegister_sampleLevelsetWithParticles() {
+ KEEP_UNUSED(_RP_sampleLevelsetWithParticles); }
+ }
+
+
+
+//! sample a shape with particles, use reset to clear the particle buffer,
+//! and skipEmpty for a continuous inflow (in the latter case, only empty cells will
+//! be re-filled once they empty when calling sampleShapeWithParticles during
+//! the main loop).
+
+
+
+void sampleShapeWithParticles(const Shape& shape, const FlagGrid& flags, BasicParticleSystem& parts, const int discretization, const Real randomness, const bool reset=false, const bool refillEmpty=false, const LevelsetGrid *exclude=NULL) {
+ const bool is3D = flags.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp (1.0 / discretization, 1.0 / discretization, 1.0/discretization);
+ RandomStream mRand(9832);
+
+ if(reset) {
+ parts.clear();
+ parts.doCompress();
+ }
+
+ FOR_IJK_BND(flags, 0) {
+ if ( flags.isObstacle(i,j,k) ) continue;
+ if ( refillEmpty && flags.isFluid(i,j,k) ) continue;
+ const Vec3 pos (i,j,k);
+ for (int dk=0; dk<(is3D ? discretization : 1); dk++)
+ for (int dj=0; dj<discretization; dj++)
+ for (int di=0; di<discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5+di, 0.5+dj, 0.5+dk);
+ subpos += jlen * (Vec3(1,1,1) - 2.0 * mRand.getVec3());
+ if(!is3D) subpos[2] = 0.5;
+ if(exclude && exclude->getInterpolated(subpos) <= 0.) continue;
+ if(!shape.isInside(subpos)) continue;
+ parts.addBuffered(subpos);
+ }
+ }
+
+ parts.insertBufferedParticles();
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "sampleShapeWithParticles" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Shape& shape = *_args.getPtr<Shape >("shape",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); const int discretization = _args.get<int >("discretization",3,&_lock); const Real randomness = _args.get<Real >("randomness",4,&_lock); const bool reset = _args.getOpt<bool >("reset",5,false,&_lock); const bool refillEmpty = _args.getOpt<bool >("refillEmpty",6,false,&_lock); const LevelsetGrid* exclude = _args.getPtrOpt<LevelsetGrid >("exclude",7,NULL,&_lock); _retval = getPyNone(); sampleShapeWithParticles(shape,flags,parts,discretization,randomness,reset,refillEmpty,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"sampleShapeWithParticles", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("sampleShapeWithParticles",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_sampleShapeWithParticles ("","sampleShapeWithParticles",_W_2);
+extern "C" {
+ void PbRegister_sampleShapeWithParticles() {
+ KEEP_UNUSED(_RP_sampleShapeWithParticles); }
+ }
+
+
+
+//! mark fluid cells and helpers
+ struct knClearFluidFlags : public KernelBase {
+ knClearFluidFlags(FlagGrid& flags, int dummy=0) : KernelBase(&flags,0) ,flags(flags),dummy(dummy) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, FlagGrid& flags, int dummy=0 ) {
+ if (flags.isFluid(i,j,k)) {
+ flags(i,j,k) = (flags(i,j,k) | FlagGrid::TypeEmpty) & ~FlagGrid::TypeFluid;
+ }
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline int& getArg1() {
+ return dummy; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel knClearFluidFlags ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,dummy); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,dummy); }
+ }
+ }
+ FlagGrid& flags; int dummy; }
+;
+
+ struct knSetNbObstacle : public KernelBase {
+ knSetNbObstacle(FlagGrid& nflags, const FlagGrid& flags, const Grid<Real>& phiObs) : KernelBase(&nflags,1) ,nflags(nflags),flags(flags),phiObs(phiObs) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, FlagGrid& nflags, const FlagGrid& flags, const Grid<Real>& phiObs ) {
+ if ( phiObs(i,j,k)>0. ) return;
+ if (flags.isEmpty(i,j,k)) {
+ bool set=false;
+ if( (flags.isFluid(i-1,j,k)) && (phiObs(i+1,j,k)<=0.) ) set=true;
+ if( (flags.isFluid(i+1,j,k)) && (phiObs(i-1,j,k)<=0.) ) set=true;
+ if( (flags.isFluid(i,j-1,k)) && (phiObs(i,j+1,k)<=0.) ) set=true;
+ if( (flags.isFluid(i,j+1,k)) && (phiObs(i,j-1,k)<=0.) ) set=true;
+ if(flags.is3D()) {
+ if( (flags.isFluid(i,j,k-1)) && (phiObs(i,j,k+1)<=0.) ) set=true;
+ if( (flags.isFluid(i,j,k+1)) && (phiObs(i,j,k-1)<=0.) ) set=true;
+ }
+ if(set) nflags(i,j,k) = (flags(i,j,k) | FlagGrid::TypeFluid) & ~FlagGrid::TypeEmpty;
+ }
+} inline FlagGrid& getArg0() {
+ return nflags; }
+ typedef FlagGrid type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<Real>& getArg2() {
+ return phiObs; }
+ typedef Grid<Real> type2; void runMessage() { debMsg("Executing kernel knSetNbObstacle ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,nflags,flags,phiObs); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,nflags,flags,phiObs); }
+ }
+ }
+ FlagGrid& nflags; const FlagGrid& flags; const Grid<Real>& phiObs; }
+;
+void markFluidCells(const BasicParticleSystem& parts, FlagGrid& flags, const Grid<Real>* phiObs=NULL, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ // remove all fluid cells
+ knClearFluidFlags(flags, 0);
+
+ // mark all particles in flaggrid as fluid
+ for(IndexInt idx=0; idx<parts.size(); idx++) {
+ if (!parts.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) continue;
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if (flags.isInBounds(p) && flags.isEmpty(p))
+ flags(p) = (flags(p) | FlagGrid::TypeFluid) & ~FlagGrid::TypeEmpty;
+ }
+
+ // special for second order obstacle BCs, check empty cells in boundary region
+ if(phiObs) {
+ FlagGrid tmp(flags);
+ knSetNbObstacle(tmp, flags, *phiObs);
+ flags.swap(tmp);
+ }
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "markFluidCells" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const Grid<Real>* phiObs = _args.getPtrOpt<Grid<Real> >("phiObs",2,NULL,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",3,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",4,0,&_lock); _retval = getPyNone(); markFluidCells(parts,flags,phiObs,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"markFluidCells", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("markFluidCells",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_markFluidCells ("","markFluidCells",_W_3);
+extern "C" {
+ void PbRegister_markFluidCells() {
+ KEEP_UNUSED(_RP_markFluidCells); }
+ }
+
+
+
+// for testing purposes only...
+void testInitGridWithPos(Grid<Real>& grid) {
+ FOR_IJK(grid) { grid(i,j,k) = norm( Vec3(i,j,k) ); }
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "testInitGridWithPos" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& grid = *_args.getPtr<Grid<Real> >("grid",0,&_lock); _retval = getPyNone(); testInitGridWithPos(grid); _args.check(); }
+ pbFinalizePlugin(parent,"testInitGridWithPos", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("testInitGridWithPos",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_testInitGridWithPos ("","testInitGridWithPos",_W_4);
+extern "C" {
+ void PbRegister_testInitGridWithPos() {
+ KEEP_UNUSED(_RP_testInitGridWithPos); }
+ }
+
+
+
+
+
+//! helper to calculate particle radius factor to cover the diagonal of a cell in 2d/3d
+inline Real calculateRadiusFactor(const Grid<Real>& grid, Real factor) {
+ return (grid.is3D() ? sqrt(3.) : sqrt(2.) ) * (factor+.01); // note, a 1% safety factor is added here
+}
+
+//! re-sample particles based on an input levelset
+// optionally skip seeding new particles in "exclude" SDF
+
+
+
+void adjustNumber(BasicParticleSystem& parts, const MACGrid& vel, const FlagGrid& flags, int minParticles, int maxParticles, const LevelsetGrid& phi, Real radiusFactor=1. , Real narrowBand=-1. , const Grid<Real>* exclude=NULL ) {
+ // which levelset to use as threshold
+ const Real SURFACE_LS = -1.0 * calculateRadiusFactor(phi, radiusFactor);
+ Grid<int> tmp( vel.getParent() );
+ std::ostringstream out;
+
+ // count particles in cells, and delete excess particles
+ for (IndexInt idx=0; idx<(int)parts.size(); idx++) {
+ if (parts.isActive(idx)) {
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if (!tmp.isInBounds(p) ) {
+ parts.kill(idx); // out of domain, remove
+ continue;
+ }
+
+ Real phiv = phi.getInterpolated( parts.getPos(idx) );
+ if( phiv > 0 ) { parts.kill(idx); continue; }
+ if( narrowBand>0. && phiv < -narrowBand) { parts.kill(idx); continue; }
+
+ bool atSurface = false;
+ if (phiv > SURFACE_LS) atSurface = true;
+ int num = tmp(p);
+
+ // dont delete particles in non fluid cells here, the particles are "always right"
+ if ( num > maxParticles && (!atSurface) ) {
+ parts.kill(idx);
+ } else {
+ tmp(p) = num+1;
+ }
+ }
+ }
+
+ // seed new particles
+ RandomStream mRand(9832);
+ FOR_IJK(tmp) {
+ int cnt = tmp(i,j,k);
+
+ // skip cells near surface
+ if (phi(i,j,k) > SURFACE_LS) continue;
+ if( narrowBand>0. && phi(i,j,k) < -narrowBand ) { continue; }
+ if( exclude && ( (*exclude)(i,j,k) < 0.) ) { continue; }
+
+ if (flags.isFluid(i,j,k) && cnt < minParticles) {
+ for (int m=cnt; m < minParticles; m++) {
+ Vec3 pos = Vec3(i,j,k) + mRand.getVec3();
+ //Vec3 pos (i + 0.5, j + 0.5, k + 0.5); // cell center
+ parts.addBuffered( pos );
+ }
+ }
+ }
+
+ parts.doCompress();
+ parts.insertBufferedParticles();
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "adjustNumber" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); int minParticles = _args.get<int >("minParticles",3,&_lock); int maxParticles = _args.get<int >("maxParticles",4,&_lock); const LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",5,&_lock); Real radiusFactor = _args.getOpt<Real >("radiusFactor",6,1. ,&_lock); Real narrowBand = _args.getOpt<Real >("narrowBand",7,-1. ,&_lock); const Grid<Real>* exclude = _args.getPtrOpt<Grid<Real> >("exclude",8,NULL ,&_lock); _retval = getPyNone(); adjustNumber(parts,vel,flags,minParticles,maxParticles,phi,radiusFactor,narrowBand,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"adjustNumber", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("adjustNumber",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_adjustNumber ("","adjustNumber",_W_5);
+extern "C" {
+ void PbRegister_adjustNumber() {
+ KEEP_UNUSED(_RP_adjustNumber); }
+ }
+
+
+
+// simple and slow helper conversion to show contents of int grids like a real grid in the ui
+// (use eg to quickly display contents of the particle-index grid)
+
+void debugIntToReal(const Grid<int>& source, Grid<Real>& dest, Real factor=1. ) {
+ FOR_IJK( source ) { dest(i,j,k) = (Real)source(i,j,k) * factor; }
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "debugIntToReal" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<int>& source = *_args.getPtr<Grid<int> >("source",0,&_lock); Grid<Real>& dest = *_args.getPtr<Grid<Real> >("dest",1,&_lock); Real factor = _args.getOpt<Real >("factor",2,1. ,&_lock); _retval = getPyNone(); debugIntToReal(source,dest,factor); _args.check(); }
+ pbFinalizePlugin(parent,"debugIntToReal", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("debugIntToReal",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_debugIntToReal ("","debugIntToReal",_W_6);
+extern "C" {
+ void PbRegister_debugIntToReal() {
+ KEEP_UNUSED(_RP_debugIntToReal); }
+ }
+
+
+
+// build a grid that contains indices for a particle system
+// the particles in a cell i,j,k are particles[index(i,j,k)] to particles[index(i+1,j,k)-1]
+// (ie, particles[index(i+1,j,k)] already belongs to cell i+1,j,k)
+
+
+void gridParticleIndex(const BasicParticleSystem& parts, ParticleIndexSystem& indexSys, const FlagGrid& flags, Grid<int>& index, Grid<int>* counter=NULL ) {
+ bool delCounter = false;
+ if(!counter) { counter = new Grid<int>( flags.getParent() ); delCounter=true; }
+ else { counter->clear(); }
+
+ // count particles in cells, and delete excess particles
+ index.clear();
+ int inactive = 0;
+ for (IndexInt idx=0; idx<(IndexInt)parts.size(); idx++) {
+ if (parts.isActive(idx)) {
+ // check index for validity...
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if (! index.isInBounds(p)) { inactive++; continue; }
+
+ index(p)++;
+ } else {
+ inactive++;
+ }
+ }
+
+ // note - this one might be smaller...
+ indexSys.resize( parts.size()-inactive );
+
+ // convert per cell number to continuous index
+ IndexInt idx=0;
+ FOR_IJK( index ) {
+ int num = index(i,j,k);
+ index(i,j,k) = idx;
+ idx += num;
+ }
+
+ // add particles to indexed array, we still need a per cell particle counter
+ for (IndexInt idx=0; idx<(IndexInt)parts.size(); idx++) {
+ if (!parts.isActive(idx)) continue;
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if (! index.isInBounds(p)) { continue; }
+
+ // initialize position and index into original array
+ //indexSys[ index(p)+(*counter)(p) ].pos = parts[idx].pos;
+ indexSys[ index(p)+(*counter)(p) ].sourceIndex = idx;
+ (*counter)(p)++;
+ }
+
+ if(delCounter) delete counter;
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "gridParticleIndex" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleIndexSystem& indexSys = *_args.getPtr<ParticleIndexSystem >("indexSys",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); Grid<int>& index = *_args.getPtr<Grid<int> >("index",3,&_lock); Grid<int>* counter = _args.getPtrOpt<Grid<int> >("counter",4,NULL ,&_lock); _retval = getPyNone(); gridParticleIndex(parts,indexSys,flags,index,counter); _args.check(); }
+ pbFinalizePlugin(parent,"gridParticleIndex", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("gridParticleIndex",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_gridParticleIndex ("","gridParticleIndex",_W_7);
+extern "C" {
+ void PbRegister_gridParticleIndex() {
+ KEEP_UNUSED(_RP_gridParticleIndex); }
+ }
+
+
+
+
+
+
+
+ struct ComputeUnionLevelsetPindex : public KernelBase {
+ ComputeUnionLevelsetPindex(const Grid<int>& index, const BasicParticleSystem& parts, const ParticleIndexSystem& indexSys, LevelsetGrid& phi, const Real radius, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(&index,0) ,index(index),parts(parts),indexSys(indexSys),phi(phi),radius(radius),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<int>& index, const BasicParticleSystem& parts, const ParticleIndexSystem& indexSys, LevelsetGrid& phi, const Real radius, const ParticleDataImpl<int> *ptype, const int exclude ) {
+ const Vec3 gridPos = Vec3(i,j,k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.0; // outside
+
+ int r = int(radius) + 1;
+ int rZ = phi.is3D() ? r : 0;
+ for(int zj=k-rZ; zj<=k+rZ; zj++)
+ for(int yj=j-r ; yj<=j+r ; yj++)
+ for(int xj=i-r ; xj<=i+r ; xj++) {
+ if (!phi.isInBounds(Vec3i(xj,yj,zj))) continue;
+
+ // note, for the particle indices in indexSys the access is periodic (ie, dont skip for eg inBounds(sx,10,10)
+ IndexInt isysIdxS = index.index(xj,yj,zj);
+ IndexInt pStart = index(isysIdxS), pEnd=0;
+ if(phi.isInBounds(isysIdxS+1)) pEnd = index(isysIdxS+1);
+ else pEnd = indexSys.size();
+
+ // now loop over particles in cell
+ for(IndexInt p=pStart; p<pEnd; ++p) {
+ const int psrc = indexSys[p].sourceIndex;
+ if(ptype && ((*ptype)[psrc] & exclude)) continue;
+ const Vec3 pos = parts[psrc].pos;
+ phiv = std::min( phiv , fabs( norm(gridPos-pos) )-radius );
+ }
+ }
+ phi(i,j,k) = phiv;
+} inline const Grid<int>& getArg0() {
+ return index; }
+ typedef Grid<int> type0;inline const BasicParticleSystem& getArg1() {
+ return parts; }
+ typedef BasicParticleSystem type1;inline const ParticleIndexSystem& getArg2() {
+ return indexSys; }
+ typedef ParticleIndexSystem type2;inline LevelsetGrid& getArg3() {
+ return phi; }
+ typedef LevelsetGrid type3;inline const Real& getArg4() {
+ return radius; }
+ typedef Real type4;inline const ParticleDataImpl<int> * getArg5() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type5;inline const int& getArg6() {
+ return exclude; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel ComputeUnionLevelsetPindex ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,index,parts,indexSys,phi,radius,ptype,exclude); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,index,parts,indexSys,phi,radius,ptype,exclude); }
+ }
+ }
+ const Grid<int>& index; const BasicParticleSystem& parts; const ParticleIndexSystem& indexSys; LevelsetGrid& phi; const Real radius; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+
+
+
+
+void unionParticleLevelset(const BasicParticleSystem& parts, const ParticleIndexSystem& indexSys, const FlagGrid& flags, const Grid<int>& index, LevelsetGrid& phi, const Real radiusFactor=1., const ParticleDataImpl<int> *ptype=NULL, const int exclude=0) {
+ // use half a cell diagonal as base radius
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor);
+ // no reset of phi necessary here
+ ComputeUnionLevelsetPindex(index, parts, indexSys, phi, radius, ptype, exclude);
+
+ phi.setBound(0.5, 0);
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "unionParticleLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const ParticleIndexSystem& indexSys = *_args.getPtr<ParticleIndexSystem >("indexSys",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); const Grid<int>& index = *_args.getPtr<Grid<int> >("index",3,&_lock); LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",4,&_lock); const Real radiusFactor = _args.getOpt<Real >("radiusFactor",5,1.,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",6,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",7,0,&_lock); _retval = getPyNone(); unionParticleLevelset(parts,indexSys,flags,index,phi,radiusFactor,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"unionParticleLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("unionParticleLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_unionParticleLevelset ("","unionParticleLevelset",_W_8);
+extern "C" {
+ void PbRegister_unionParticleLevelset() {
+ KEEP_UNUSED(_RP_unionParticleLevelset); }
+ }
+
+
+
+//! kernel for computing averaged particle level set weights
+
+
+
+
+
+
+ struct ComputeAveragedLevelsetWeight : public KernelBase {
+ ComputeAveragedLevelsetWeight(const BasicParticleSystem& parts, const Grid<int>& index, const ParticleIndexSystem& indexSys, LevelsetGrid& phi, const Real radius, const ParticleDataImpl<int>* ptype, const int exclude, Grid<Vec3>* save_pAcc = NULL, Grid<Real>* save_rAcc = NULL) : KernelBase(&index,0) ,parts(parts),index(index),indexSys(indexSys),phi(phi),radius(radius),ptype(ptype),exclude(exclude),save_pAcc(save_pAcc),save_rAcc(save_rAcc) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const BasicParticleSystem& parts, const Grid<int>& index, const ParticleIndexSystem& indexSys, LevelsetGrid& phi, const Real radius, const ParticleDataImpl<int>* ptype, const int exclude, Grid<Vec3>* save_pAcc = NULL, Grid<Real>* save_rAcc = NULL ) {
+ const Vec3 gridPos = Vec3(i,j,k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.0; // outside
+
+ // loop over neighborhood, similar to ComputeUnionLevelsetPindex
+ const Real sradiusInv = 1. / (4. * radius * radius) ;
+ int r = int(1. * radius) + 1;
+ int rZ = phi.is3D() ? r : 0;
+ // accumulators
+ Real wacc = 0.;
+ Vec3 pacc = Vec3(0.);
+ Real racc = 0.;
+
+ for(int zj=k-rZ; zj<=k+rZ; zj++)
+ for(int yj=j-r ; yj<=j+r ; yj++)
+ for(int xj=i-r ; xj<=i+r ; xj++) {
+ if (! phi.isInBounds(Vec3i(xj,yj,zj)) ) continue;
+
+ IndexInt isysIdxS = index.index(xj,yj,zj);
+ IndexInt pStart = index(isysIdxS), pEnd=0;
+ if(phi.isInBounds(isysIdxS+1)) pEnd = index(isysIdxS+1);
+ else pEnd = indexSys.size();
+ for(IndexInt p=pStart; p<pEnd; ++p) {
+ IndexInt psrc = indexSys[p].sourceIndex;
+ if(ptype && ((*ptype)[psrc] & exclude)) continue;
+
+ Vec3 pos = parts[psrc].pos;
+ Real s = normSquare(gridPos-pos) * sradiusInv;
+ //Real w = std::max(0., cubed(1.-s) );
+ Real w = std::max(0., (1.-s)); // a bit smoother
+ wacc += w;
+ racc += radius * w;
+ pacc += pos * w;
+ }
+ }
+
+ if(wacc > VECTOR_EPSILON) {
+ racc /= wacc;
+ pacc /= wacc;
+ phiv = fabs( norm(gridPos-pacc) )-racc;
+
+ if (save_pAcc) (*save_pAcc)(i, j, k) = pacc;
+ if (save_rAcc) (*save_rAcc)(i, j, k) = racc;
+ }
+ phi(i,j,k) = phiv;
+} inline const BasicParticleSystem& getArg0() {
+ return parts; }
+ typedef BasicParticleSystem type0;inline const Grid<int>& getArg1() {
+ return index; }
+ typedef Grid<int> type1;inline const ParticleIndexSystem& getArg2() {
+ return indexSys; }
+ typedef ParticleIndexSystem type2;inline LevelsetGrid& getArg3() {
+ return phi; }
+ typedef LevelsetGrid type3;inline const Real& getArg4() {
+ return radius; }
+ typedef Real type4;inline const ParticleDataImpl<int>* getArg5() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type5;inline const int& getArg6() {
+ return exclude; }
+ typedef int type6;inline Grid<Vec3>* getArg7() {
+ return save_pAcc; }
+ typedef Grid<Vec3> type7;inline Grid<Real>* getArg8() {
+ return save_rAcc; }
+ typedef Grid<Real> type8; void runMessage() { debMsg("Executing kernel ComputeAveragedLevelsetWeight ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,parts,index,indexSys,phi,radius,ptype,exclude,save_pAcc,save_rAcc); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,parts,index,indexSys,phi,radius,ptype,exclude,save_pAcc,save_rAcc); }
+ }
+ }
+ const BasicParticleSystem& parts; const Grid<int>& index; const ParticleIndexSystem& indexSys; LevelsetGrid& phi; const Real radius; const ParticleDataImpl<int>* ptype; const int exclude; Grid<Vec3>* save_pAcc; Grid<Real>* save_rAcc; }
+;
+
+template<class T> T smoothingValue(const Grid<T> val, int i, int j, int k, T center) {
+ return val(i,j,k);
+}
+
+// smoothing, and
+
+template <class T> struct knSmoothGrid : public KernelBase {
+ knSmoothGrid(const Grid<T>& me, Grid<T>& tmp, Real factor) : KernelBase(&me,1) ,me(me),tmp(tmp),factor(factor) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<T>& me, Grid<T>& tmp, Real factor ) {
+ T val = me(i,j,k) +
+ me(i+1,j,k) + me(i-1,j,k) +
+ me(i,j+1,k) + me(i,j-1,k) ;
+ if(me.is3D()) {
+ val += me(i,j,k+1) + me(i,j,k-1);
+ }
+ tmp(i,j,k) = val * factor;
+} inline const Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline Grid<T>& getArg1() {
+ return tmp; }
+ typedef Grid<T> type1;inline Real& getArg2() {
+ return factor; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel knSmoothGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,me,tmp,factor); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,me,tmp,factor); }
+ }
+ }
+ const Grid<T>& me; Grid<T>& tmp; Real factor; }
+;
+
+
+template <class T> struct knSmoothGridNeg : public KernelBase {
+ knSmoothGridNeg(const Grid<T>& me, Grid<T>& tmp, Real factor) : KernelBase(&me,1) ,me(me),tmp(tmp),factor(factor) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<T>& me, Grid<T>& tmp, Real factor ) {
+ T val = me(i,j,k) +
+ me(i+1,j,k) + me(i-1,j,k) +
+ me(i,j+1,k) + me(i,j-1,k) ;
+ if(me.is3D()) {
+ val += me(i,j,k+1) + me(i,j,k-1);
+ }
+ val *= factor;
+ if(val<tmp(i,j,k)) tmp(i,j,k) = val;
+ else tmp(i,j,k) = me(i,j,k);
+} inline const Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline Grid<T>& getArg1() {
+ return tmp; }
+ typedef Grid<T> type1;inline Real& getArg2() {
+ return factor; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel knSmoothGridNeg ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,me,tmp,factor); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,me,tmp,factor); }
+ }
+ }
+ const Grid<T>& me; Grid<T>& tmp; Real factor; }
+;
+
+//! Zhu & Bridson particle level set creation
+
+
+
+
+void averagedParticleLevelset(const BasicParticleSystem& parts, const ParticleIndexSystem& indexSys, const FlagGrid& flags, const Grid<int>& index, LevelsetGrid& phi, const Real radiusFactor=1., const int smoothen=1, const int smoothenNeg=1, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ // use half a cell diagonal as base radius
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor);
+ ComputeAveragedLevelsetWeight(parts, index, indexSys, phi, radius, ptype, exclude);
+
+ // post-process level-set
+ for(int i=0; i<std::max(smoothen,smoothenNeg); ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ if(i<smoothen) {
+ knSmoothGrid <Real> (phi,tmp, 1./(phi.is3D() ? 7. : 5.) );
+ phi.swap(tmp);
+ }
+ if(i<smoothenNeg) {
+ knSmoothGridNeg <Real> (phi,tmp, 1./(phi.is3D() ? 7. : 5.) );
+ phi.swap(tmp);
+ }
+ }
+ phi.setBound(0.5, 0);
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "averagedParticleLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const ParticleIndexSystem& indexSys = *_args.getPtr<ParticleIndexSystem >("indexSys",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); const Grid<int>& index = *_args.getPtr<Grid<int> >("index",3,&_lock); LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",4,&_lock); const Real radiusFactor = _args.getOpt<Real >("radiusFactor",5,1.,&_lock); const int smoothen = _args.getOpt<int >("smoothen",6,1,&_lock); const int smoothenNeg = _args.getOpt<int >("smoothenNeg",7,1,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",8,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",9,0,&_lock); _retval = getPyNone(); averagedParticleLevelset(parts,indexSys,flags,index,phi,radiusFactor,smoothen,smoothenNeg,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"averagedParticleLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("averagedParticleLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_averagedParticleLevelset ("","averagedParticleLevelset",_W_9);
+extern "C" {
+ void PbRegister_averagedParticleLevelset() {
+ KEEP_UNUSED(_RP_averagedParticleLevelset); }
+ }
+
+
+
+//! kernel for improvedParticleLevelset
+
+
+
+ struct correctLevelset : public KernelBase {
+ correctLevelset(LevelsetGrid& phi, const Grid<Vec3>& pAcc, const Grid<Real>& rAcc, const Real radius, const Real t_low, const Real t_high) : KernelBase(&phi,1) ,phi(phi),pAcc(pAcc),rAcc(rAcc),radius(radius),t_low(t_low),t_high(t_high) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, LevelsetGrid& phi, const Grid<Vec3>& pAcc, const Grid<Real>& rAcc, const Real radius, const Real t_low, const Real t_high ) {
+ if (rAcc(i, j, k) <= VECTOR_EPSILON) return; //outside nothing happens
+ Real x = pAcc(i, j, k).x;
+
+ // create jacobian of pAcc via central differences
+ Matrix3x3f jacobian = Matrix3x3f(
+ 0.5 * (pAcc(i+1, j, k ).x - pAcc(i-1, j, k ).x),
+ 0.5 * (pAcc(i, j+1, k ).x - pAcc(i, j-1, k ).x),
+ 0.5 * (pAcc(i, j , k+1).x - pAcc(i, j, k-1).x),
+ 0.5 * (pAcc(i+1, j, k ).y - pAcc(i-1, j, k ).y),
+ 0.5 * (pAcc(i, j+1, k ).y - pAcc(i, j-1, k ).y),
+ 0.5 * (pAcc(i, j, k+1).y - pAcc(i, j, k-1).y),
+ 0.5 * (pAcc(i+1, j, k ).z - pAcc(i-1, j, k ).z),
+ 0.5 * (pAcc(i, j+1, k ).z - pAcc(i, j-1, k ).z),
+ 0.5 * (pAcc(i, j, k+1).z - pAcc(i, j, k-1).z)
+ );
+
+ // compute largest eigenvalue of jacobian
+ Vec3 EV = jacobian.eigenvalues();
+ Real maxEV = std::max(std::max(EV.x, EV.y), EV.z);
+
+ // calculate correction factor
+ Real correction = 1;
+ if (maxEV >= t_low) {
+ Real t = (t_high - maxEV) / (t_high - t_low);
+ correction = t*t*t - 3 * t*t + 3 * t;
+ }
+ correction = (correction < 0) ? 0 : correction; // enforce correction factor to [0,1] (not explicitly in paper)
+
+ const Vec3 gridPos = Vec3(i, j, k) + Vec3(0.5); // shifted by half cell
+ const Real correctedPhi = fabs(norm(gridPos - pAcc(i, j, k))) - rAcc(i, j, k) * correction;
+ phi(i, j, k) = (correctedPhi > radius) ? radius : correctedPhi; // adjust too high outside values when too few particles are
+ // nearby to make smoothing possible (not in paper)
+} inline LevelsetGrid& getArg0() {
+ return phi; }
+ typedef LevelsetGrid type0;inline const Grid<Vec3>& getArg1() {
+ return pAcc; }
+ typedef Grid<Vec3> type1;inline const Grid<Real>& getArg2() {
+ return rAcc; }
+ typedef Grid<Real> type2;inline const Real& getArg3() {
+ return radius; }
+ typedef Real type3;inline const Real& getArg4() {
+ return t_low; }
+ typedef Real type4;inline const Real& getArg5() {
+ return t_high; }
+ typedef Real type5; void runMessage() { debMsg("Executing kernel correctLevelset ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,phi,pAcc,rAcc,radius,t_low,t_high); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,phi,pAcc,rAcc,radius,t_low,t_high); }
+ }
+ }
+ LevelsetGrid& phi; const Grid<Vec3>& pAcc; const Grid<Real>& rAcc; const Real radius; const Real t_low; const Real t_high; }
+;
+
+//! Approach from "A unified particle model for fluid-solid interactions" by Solenthaler et al. in 2007
+
+
+
+void improvedParticleLevelset(const BasicParticleSystem& parts, const ParticleIndexSystem& indexSys, const FlagGrid& flags, const Grid<int>& index, LevelsetGrid& phi, const Real radiusFactor = 1., const int smoothen = 1,const int smoothenNeg = 1, const Real t_low = 0.4, const Real t_high = 3.5, const ParticleDataImpl<int>* ptype = NULL, const int exclude = 0) {
+ // create temporary grids to store values from levelset weight computation
+ Grid<Vec3> save_pAcc(flags.getParent());
+ Grid<Real> save_rAcc(flags.getParent());
+
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor); // use half a cell diagonal as base radius
+ ComputeAveragedLevelsetWeight(parts, index, indexSys, phi, radius, ptype, exclude, &save_pAcc, &save_rAcc);
+ correctLevelset(phi, save_pAcc, save_rAcc, radius, t_low, t_high);
+
+ // post-process level-set
+ for (int i = 0; i<std::max(smoothen, smoothenNeg); ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ if (i<smoothen) {
+ knSmoothGrid <Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ if (i<smoothenNeg) {
+ knSmoothGridNeg <Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ }
+ phi.setBound(0.5, 0);
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "improvedParticleLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const ParticleIndexSystem& indexSys = *_args.getPtr<ParticleIndexSystem >("indexSys",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); const Grid<int>& index = *_args.getPtr<Grid<int> >("index",3,&_lock); LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",4,&_lock); const Real radiusFactor = _args.getOpt<Real >("radiusFactor",5,1.,&_lock); const int smoothen = _args.getOpt<int >("smoothen",6,1,&_lock); const int smoothenNeg = _args.getOpt<int >("smoothenNeg",7,1,&_lock); const Real t_low = _args.getOpt<Real >("t_low",8,0.4,&_lock); const Real t_high = _args.getOpt<Real >("t_high",9,3.5,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",10,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",11,0,&_lock); _retval = getPyNone(); improvedParticleLevelset(parts,indexSys,flags,index,phi,radiusFactor,smoothen,smoothenNeg,t_low,t_high,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"improvedParticleLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("improvedParticleLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_improvedParticleLevelset ("","improvedParticleLevelset",_W_10);
+extern "C" {
+ void PbRegister_improvedParticleLevelset() {
+ KEEP_UNUSED(_RP_improvedParticleLevelset); }
+ }
+
+
+
+
+
+
+ struct knPushOutofObs : public KernelBase {
+ knPushOutofObs(BasicParticleSystem& parts, const FlagGrid& flags, const Grid<Real>& phiObs, const Real shift, const Real thresh, const ParticleDataImpl<int>* ptype, const int exclude) : KernelBase(parts.size()) ,parts(parts),flags(flags),phiObs(phiObs),shift(shift),thresh(thresh),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystem& parts, const FlagGrid& flags, const Grid<Real>& phiObs, const Real shift, const Real thresh, const ParticleDataImpl<int>* ptype, const int exclude ) {
+ if (!parts.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ Vec3i p = toVec3i( parts.getPos(idx) );
+
+ if (!flags.isInBounds(p)) return;
+ Real v = phiObs.getInterpolated(parts.getPos(idx));
+ if(v < thresh) {
+ Vec3 grad = getGradient( phiObs, p.x,p.y,p.z );
+ if( normalize(grad) < VECTOR_EPSILON ) return;
+ parts.setPos(idx, parts.getPos(idx) + grad*(thresh - v + shift));
+ }
+} inline BasicParticleSystem& getArg0() {
+ return parts; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<Real>& getArg2() {
+ return phiObs; }
+ typedef Grid<Real> type2;inline const Real& getArg3() {
+ return shift; }
+ typedef Real type3;inline const Real& getArg4() {
+ return thresh; }
+ typedef Real type4;inline const ParticleDataImpl<int>* getArg5() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type5;inline const int& getArg6() {
+ return exclude; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel knPushOutofObs ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,parts,flags,phiObs,shift,thresh,ptype,exclude); }
+ }
+ BasicParticleSystem& parts; const FlagGrid& flags; const Grid<Real>& phiObs; const Real shift; const Real thresh; const ParticleDataImpl<int>* ptype; const int exclude; }
+;
+//! push particles out of obstacle levelset
+
+void pushOutofObs(BasicParticleSystem& parts, const FlagGrid& flags, const Grid<Real>& phiObs, const Real shift=0, const Real thresh=0, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ knPushOutofObs(parts, flags, phiObs, shift, thresh, ptype, exclude);
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "pushOutofObs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const Grid<Real>& phiObs = *_args.getPtr<Grid<Real> >("phiObs",2,&_lock); const Real shift = _args.getOpt<Real >("shift",3,0,&_lock); const Real thresh = _args.getOpt<Real >("thresh",4,0,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",5,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",6,0,&_lock); _retval = getPyNone(); pushOutofObs(parts,flags,phiObs,shift,thresh,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"pushOutofObs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("pushOutofObs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_pushOutofObs ("","pushOutofObs",_W_11);
+extern "C" {
+ void PbRegister_pushOutofObs() {
+ KEEP_UNUSED(_RP_pushOutofObs); }
+ }
+
+
+
+//******************************************************************************
+// grid interpolation functions
+
+
+template <class T> struct knSafeDivReal : public KernelBase {
+ knSafeDivReal(Grid<T>& me, const Grid<Real>& other, Real cutoff=VECTOR_EPSILON) : KernelBase(&me,0) ,me(me),other(other),cutoff(cutoff) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<Real>& other, Real cutoff=VECTOR_EPSILON ) {
+ if(other[idx]<cutoff) {
+ me[idx] = 0.;
+ } else {
+ T div( other[idx] );
+ me[idx] = safeDivide(me[idx], div );
+ }
+} inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<Real>& getArg1() {
+ return other; }
+ typedef Grid<Real> type1;inline Real& getArg2() {
+ return cutoff; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel knSafeDivReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,me,other,cutoff); }
+ }
+ Grid<T>& me; const Grid<Real>& other; Real cutoff; }
+;
+
+// Set velocities on the grid from the particle system
+
+
+
+
+ struct knMapLinearVec3ToMACGrid : public KernelBase {
+ knMapLinearVec3ToMACGrid(const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, Grid<Vec3>& tmp, const ParticleDataImpl<Vec3>& pvel, const ParticleDataImpl<int>* ptype, const int exclude) : KernelBase(p.size()) ,p(p),flags(flags),vel(vel),tmp(tmp),pvel(pvel),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, Grid<Vec3>& tmp, const ParticleDataImpl<Vec3>& pvel, const ParticleDataImpl<int>* ptype, const int exclude ) {
+ unusedParameter(flags);
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ vel.setInterpolated( p[idx].pos, pvel[idx], &tmp[0] );
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline Grid<Vec3>& getArg3() {
+ return tmp; }
+ typedef Grid<Vec3> type3;inline const ParticleDataImpl<Vec3>& getArg4() {
+ return pvel; }
+ typedef ParticleDataImpl<Vec3> type4;inline const ParticleDataImpl<int>* getArg5() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type5;inline const int& getArg6() {
+ return exclude; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel knMapLinearVec3ToMACGrid ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size; for (IndexInt i = 0; i < _sz; i++) op(i, p,flags,vel,tmp,pvel,ptype,exclude); }
+ const BasicParticleSystem& p; const FlagGrid& flags; const MACGrid& vel; Grid<Vec3>& tmp; const ParticleDataImpl<Vec3>& pvel; const ParticleDataImpl<int>* ptype; const int exclude; }
+;
+
+// optionally , this function can use an existing vec3 grid to store the weights
+// this is useful in combination with the simple extrapolation function
+
+
+
+void mapPartsToMAC(const FlagGrid& flags, MACGrid& vel, MACGrid& velOld, const BasicParticleSystem& parts, const ParticleDataImpl<Vec3>& partVel, Grid<Vec3>* weight=NULL, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ // interpol -> grid. tmpgrid for particle contribution weights
+ bool freeTmp = false;
+ if(!weight) {
+ weight = new Grid<Vec3>(flags.getParent());
+ freeTmp = true;
+ } else {
+ weight->clear(); // make sure we start with a zero grid!
+ }
+ vel.clear();
+ knMapLinearVec3ToMACGrid( parts, flags, vel, *weight, partVel, ptype, exclude );
+
+ // stomp small values in weight to zero to prevent roundoff errors
+ weight->stomp(Vec3(VECTOR_EPSILON));
+ vel.safeDivide(*weight);
+
+ // store original state
+ velOld.copyFrom( vel );
+ if(freeTmp) delete weight;
+} static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapPartsToMAC" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); MACGrid& velOld = *_args.getPtr<MACGrid >("velOld",2,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",3,&_lock); const ParticleDataImpl<Vec3>& partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",4,&_lock); Grid<Vec3>* weight = _args.getPtrOpt<Grid<Vec3> >("weight",5,NULL,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",6,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",7,0,&_lock); _retval = getPyNone(); mapPartsToMAC(flags,vel,velOld,parts,partVel,weight,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"mapPartsToMAC", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapPartsToMAC",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapPartsToMAC ("","mapPartsToMAC",_W_12);
+extern "C" {
+ void PbRegister_mapPartsToMAC() {
+ KEEP_UNUSED(_RP_mapPartsToMAC); }
+ }
+
+
+
+
+
+
+template <class T> struct knMapLinear : public KernelBase {
+ knMapLinear(const BasicParticleSystem& p, const FlagGrid& flags, const Grid<T>& target, Grid<Real>& gtmp, const ParticleDataImpl<T>& psource ) : KernelBase(p.size()) ,p(p),flags(flags),target(target),gtmp(gtmp),psource(psource) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& p, const FlagGrid& flags, const Grid<T>& target, Grid<Real>& gtmp, const ParticleDataImpl<T>& psource ) {
+ unusedParameter(flags);
+ if (!p.isActive(idx)) return;
+ target.setInterpolated( p[idx].pos, psource[idx], gtmp );
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<T>& getArg2() {
+ return target; }
+ typedef Grid<T> type2;inline Grid<Real>& getArg3() {
+ return gtmp; }
+ typedef Grid<Real> type3;inline const ParticleDataImpl<T>& getArg4() {
+ return psource; }
+ typedef ParticleDataImpl<T> type4; void runMessage() { debMsg("Executing kernel knMapLinear ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size; for (IndexInt i = 0; i < _sz; i++) op(i, p,flags,target,gtmp,psource); }
+ const BasicParticleSystem& p; const FlagGrid& flags; const Grid<T>& target; Grid<Real>& gtmp; const ParticleDataImpl<T>& psource; }
+;
+
+template<class T>
+void mapLinearRealHelper(const FlagGrid& flags, Grid<T>& target,
+ const BasicParticleSystem& parts, const ParticleDataImpl<T>& source )
+{
+ Grid<Real> tmp(flags.getParent());
+ target.clear();
+ knMapLinear<T>( parts, flags, target, tmp, source );
+ knSafeDivReal<T>( target, tmp );
+}
+
+void mapPartsToGrid(const FlagGrid& flags, Grid<Real>& target , const BasicParticleSystem& parts , const ParticleDataImpl<Real>& source ) {
+ mapLinearRealHelper<Real>(flags,target,parts,source);
+} static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapPartsToGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",1,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); const ParticleDataImpl<Real>& source = *_args.getPtr<ParticleDataImpl<Real> >("source",3,&_lock); _retval = getPyNone(); mapPartsToGrid(flags,target,parts,source); _args.check(); }
+ pbFinalizePlugin(parent,"mapPartsToGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapPartsToGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapPartsToGrid ("","mapPartsToGrid",_W_13);
+extern "C" {
+ void PbRegister_mapPartsToGrid() {
+ KEEP_UNUSED(_RP_mapPartsToGrid); }
+ }
+
+
+void mapPartsToGridVec3(const FlagGrid& flags, Grid<Vec3>& target , const BasicParticleSystem& parts , const ParticleDataImpl<Vec3>& source ) {
+ mapLinearRealHelper<Vec3>(flags,target,parts,source);
+} static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapPartsToGridVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); const ParticleDataImpl<Vec3>& source = *_args.getPtr<ParticleDataImpl<Vec3> >("source",3,&_lock); _retval = getPyNone(); mapPartsToGridVec3(flags,target,parts,source); _args.check(); }
+ pbFinalizePlugin(parent,"mapPartsToGridVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapPartsToGridVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapPartsToGridVec3 ("","mapPartsToGridVec3",_W_14);
+extern "C" {
+ void PbRegister_mapPartsToGridVec3() {
+ KEEP_UNUSED(_RP_mapPartsToGridVec3); }
+ }
+
+
+// integers need "max" mode, not yet implemented
+//PYTHON() void mapPartsToGridInt ( FlagGrid& flags, Grid<int >& target , BasicParticleSystem& parts , ParticleDataImpl<int >& source ) {
+// mapLinearRealHelper<int >(flags,target,parts,source);
+//}
+
+
+
+template <class T> struct knMapFromGrid : public KernelBase {
+ knMapFromGrid(const BasicParticleSystem& p, const Grid<T>& gsrc, ParticleDataImpl<T>& target ) : KernelBase(p.size()) ,p(p),gsrc(gsrc),target(target) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& p, const Grid<T>& gsrc, ParticleDataImpl<T>& target ) {
+ if (!p.isActive(idx)) return;
+ target[idx] = gsrc.getInterpolated( p[idx].pos );
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const Grid<T>& getArg1() {
+ return gsrc; }
+ typedef Grid<T> type1;inline ParticleDataImpl<T>& getArg2() {
+ return target; }
+ typedef ParticleDataImpl<T> type2; void runMessage() { debMsg("Executing kernel knMapFromGrid ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,p,gsrc,target); }
+ }
+ const BasicParticleSystem& p; const Grid<T>& gsrc; ParticleDataImpl<T>& target; }
+;
+void mapGridToParts(const Grid<Real>& source , const BasicParticleSystem& parts , ParticleDataImpl<Real>& target ) {
+ knMapFromGrid<Real>(parts, source, target);
+} static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapGridToParts" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",0,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",1,&_lock); ParticleDataImpl<Real>& target = *_args.getPtr<ParticleDataImpl<Real> >("target",2,&_lock); _retval = getPyNone(); mapGridToParts(source,parts,target); _args.check(); }
+ pbFinalizePlugin(parent,"mapGridToParts", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapGridToParts",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapGridToParts ("","mapGridToParts",_W_15);
+extern "C" {
+ void PbRegister_mapGridToParts() {
+ KEEP_UNUSED(_RP_mapGridToParts); }
+ }
+
+
+void mapGridToPartsVec3(const Grid<Vec3>& source , const BasicParticleSystem& parts , ParticleDataImpl<Vec3>& target ) {
+ knMapFromGrid<Vec3>(parts, source, target);
+} static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapGridToPartsVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Vec3>& source = *_args.getPtr<Grid<Vec3> >("source",0,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",1,&_lock); ParticleDataImpl<Vec3>& target = *_args.getPtr<ParticleDataImpl<Vec3> >("target",2,&_lock); _retval = getPyNone(); mapGridToPartsVec3(source,parts,target); _args.check(); }
+ pbFinalizePlugin(parent,"mapGridToPartsVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapGridToPartsVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapGridToPartsVec3 ("","mapGridToPartsVec3",_W_16);
+extern "C" {
+ void PbRegister_mapGridToPartsVec3() {
+ KEEP_UNUSED(_RP_mapGridToPartsVec3); }
+ }
+
+
+
+
+// Get velocities from grid
+
+
+
+
+ struct knMapLinearMACGridToVec3_PIC : public KernelBase {
+ knMapLinearMACGridToVec3_PIC(const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, ParticleDataImpl<Vec3>& pvel, const ParticleDataImpl<int>* ptype, const int exclude) : KernelBase(p.size()) ,p(p),flags(flags),vel(vel),pvel(pvel),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, ParticleDataImpl<Vec3>& pvel, const ParticleDataImpl<int>* ptype, const int exclude ) {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ // pure PIC
+ pvel[idx] = vel.getInterpolated( p[idx].pos );
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline ParticleDataImpl<Vec3>& getArg3() {
+ return pvel; }
+ typedef ParticleDataImpl<Vec3> type3;inline const ParticleDataImpl<int>* getArg4() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type4;inline const int& getArg5() {
+ return exclude; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel knMapLinearMACGridToVec3_PIC ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,p,flags,vel,pvel,ptype,exclude); }
+ }
+ const BasicParticleSystem& p; const FlagGrid& flags; const MACGrid& vel; ParticleDataImpl<Vec3>& pvel; const ParticleDataImpl<int>* ptype; const int exclude; }
+;
+
+
+void mapMACToParts(const FlagGrid& flags, const MACGrid& vel , const BasicParticleSystem& parts , ParticleDataImpl<Vec3>& partVel, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ knMapLinearMACGridToVec3_PIC( parts, flags, vel, partVel, ptype, exclude );
+} static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapMACToParts" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); ParticleDataImpl<Vec3>& partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",3,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",4,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",5,0,&_lock); _retval = getPyNone(); mapMACToParts(flags,vel,parts,partVel,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"mapMACToParts", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapMACToParts",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapMACToParts ("","mapMACToParts",_W_17);
+extern "C" {
+ void PbRegister_mapMACToParts() {
+ KEEP_UNUSED(_RP_mapMACToParts); }
+ }
+
+
+
+// with flip delta interpolation
+
+
+
+
+ struct knMapLinearMACGridToVec3_FLIP : public KernelBase {
+ knMapLinearMACGridToVec3_FLIP(const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, const MACGrid& oldVel, ParticleDataImpl<Vec3>& pvel, const Real flipRatio, const ParticleDataImpl<int>* ptype, const int exclude) : KernelBase(p.size()) ,p(p),flags(flags),vel(vel),oldVel(oldVel),pvel(pvel),flipRatio(flipRatio),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, const MACGrid& oldVel, ParticleDataImpl<Vec3>& pvel, const Real flipRatio, const ParticleDataImpl<int>* ptype, const int exclude ) {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ Vec3 v = vel.getInterpolated(p[idx].pos);
+ Vec3 delta = v - oldVel.getInterpolated(p[idx].pos);
+ pvel[idx] = flipRatio * (pvel[idx] + delta) + (1.0 - flipRatio) * v;
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline const MACGrid& getArg3() {
+ return oldVel; }
+ typedef MACGrid type3;inline ParticleDataImpl<Vec3>& getArg4() {
+ return pvel; }
+ typedef ParticleDataImpl<Vec3> type4;inline const Real& getArg5() {
+ return flipRatio; }
+ typedef Real type5;inline const ParticleDataImpl<int>* getArg6() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type6;inline const int& getArg7() {
+ return exclude; }
+ typedef int type7; void runMessage() { debMsg("Executing kernel knMapLinearMACGridToVec3_FLIP ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,p,flags,vel,oldVel,pvel,flipRatio,ptype,exclude); }
+ }
+ const BasicParticleSystem& p; const FlagGrid& flags; const MACGrid& vel; const MACGrid& oldVel; ParticleDataImpl<Vec3>& pvel; const Real flipRatio; const ParticleDataImpl<int>* ptype; const int exclude; }
+;
+
+
+
+void flipVelocityUpdate(const FlagGrid& flags, const MACGrid& vel, const MACGrid& velOld, const BasicParticleSystem& parts, ParticleDataImpl<Vec3>& partVel, const Real flipRatio, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ knMapLinearMACGridToVec3_FLIP( parts, flags, vel, velOld, partVel, flipRatio, ptype, exclude );
+} static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipVelocityUpdate" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const MACGrid& velOld = *_args.getPtr<MACGrid >("velOld",2,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",3,&_lock); ParticleDataImpl<Vec3>& partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",4,&_lock); const Real flipRatio = _args.get<Real >("flipRatio",5,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",6,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",7,0,&_lock); _retval = getPyNone(); flipVelocityUpdate(flags,vel,velOld,parts,partVel,flipRatio,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"flipVelocityUpdate", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipVelocityUpdate",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipVelocityUpdate ("","flipVelocityUpdate",_W_18);
+extern "C" {
+ void PbRegister_flipVelocityUpdate() {
+ KEEP_UNUSED(_RP_flipVelocityUpdate); }
+ }
+
+
+
+
+//******************************************************************************
+// narrow band
+
+
+ struct knCombineVels : public KernelBase {
+ knCombineVels(MACGrid& vel, const Grid<Vec3>& w, MACGrid& combineVel, const LevelsetGrid* phi, Real narrowBand, Real thresh ) : KernelBase(&vel,0) ,vel(vel),w(w),combineVel(combineVel),phi(phi),narrowBand(narrowBand),thresh(thresh) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& vel, const Grid<Vec3>& w, MACGrid& combineVel, const LevelsetGrid* phi, Real narrowBand, Real thresh ) {
+ int idx = vel.index(i,j,k);
+
+ for(int c=0; c<3; ++c)
+ {
+ // Correct narrow-band FLIP
+ if(phi) {
+ Vec3 pos(i,j,k);
+ pos[(c+1)%3] += Real(0.5);
+ pos[(c+2)%3] += Real(0.5);
+ Real p = phi->getInterpolated(pos);
+ if (p < -narrowBand) { vel[idx][c] = 0; continue; }
+ }
+
+ if (w[idx][c] > thresh) {
+ combineVel[idx][c] = vel[idx][c];
+ vel[idx][c] = -1;
+ } else {
+ vel[idx][c] = 0;
+ }
+ }
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const Grid<Vec3>& getArg1() {
+ return w; }
+ typedef Grid<Vec3> type1;inline MACGrid& getArg2() {
+ return combineVel; }
+ typedef MACGrid type2;inline const LevelsetGrid* getArg3() {
+ return phi; }
+ typedef LevelsetGrid type3;inline Real& getArg4() {
+ return narrowBand; }
+ typedef Real type4;inline Real& getArg5() {
+ return thresh; }
+ typedef Real type5; void runMessage() { debMsg("Executing kernel knCombineVels ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,vel,w,combineVel,phi,narrowBand,thresh); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,vel,w,combineVel,phi,narrowBand,thresh); }
+ }
+ }
+ MACGrid& vel; const Grid<Vec3>& w; MACGrid& combineVel; const LevelsetGrid* phi; Real narrowBand; Real thresh; }
+;
+
+//! narrow band velocity combination
+
+void combineGridVel( MACGrid& vel, const Grid<Vec3>& weight, MACGrid& combineVel, const LevelsetGrid* phi=NULL, Real narrowBand=0.0, Real thresh=0.0) {
+ knCombineVels(vel, weight, combineVel, phi, narrowBand, thresh);
+} static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "combineGridVel" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); const Grid<Vec3>& weight = *_args.getPtr<Grid<Vec3> >("weight",1,&_lock); MACGrid& combineVel = *_args.getPtr<MACGrid >("combineVel",2,&_lock); const LevelsetGrid* phi = _args.getPtrOpt<LevelsetGrid >("phi",3,NULL,&_lock); Real narrowBand = _args.getOpt<Real >("narrowBand",4,0.0,&_lock); Real thresh = _args.getOpt<Real >("thresh",5,0.0,&_lock); _retval = getPyNone(); combineGridVel(vel,weight,combineVel,phi,narrowBand,thresh); _args.check(); }
+ pbFinalizePlugin(parent,"combineGridVel", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("combineGridVel",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_combineGridVel ("","combineGridVel",_W_19);
+extern "C" {
+ void PbRegister_combineGridVel() {
+ KEEP_UNUSED(_RP_combineGridVel); }
+ }
+
+
+
+//! surface tension helper
+void getLaplacian(Grid<Real> &laplacian, const Grid<Real> &grid) {
+ LaplaceOp(laplacian, grid);
+} static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getLaplacian" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & laplacian = *_args.getPtr<Grid<Real> >("laplacian",0,&_lock); const Grid<Real> & grid = *_args.getPtr<Grid<Real> >("grid",1,&_lock); _retval = getPyNone(); getLaplacian(laplacian,grid); _args.check(); }
+ pbFinalizePlugin(parent,"getLaplacian", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getLaplacian",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getLaplacian ("","getLaplacian",_W_20);
+extern "C" {
+ void PbRegister_getLaplacian() {
+ KEEP_UNUSED(_RP_getLaplacian); }
+ }
+
+
+
+void getCurvature(Grid<Real> &curv, const Grid<Real> &grid, const Real h=1.0) {
+ CurvatureOp(curv, grid, h);
+} static PyObject* _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getCurvature" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & curv = *_args.getPtr<Grid<Real> >("curv",0,&_lock); const Grid<Real> & grid = *_args.getPtr<Grid<Real> >("grid",1,&_lock); const Real h = _args.getOpt<Real >("h",2,1.0,&_lock); _retval = getPyNone(); getCurvature(curv,grid,h); _args.check(); }
+ pbFinalizePlugin(parent,"getCurvature", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getCurvature",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getCurvature ("","getCurvature",_W_21);
+extern "C" {
+ void PbRegister_getCurvature() {
+ KEEP_UNUSED(_RP_getCurvature); }
+ }
+
+
+
+} // namespace
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/fluidguiding.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/fluidguiding.cpp
new file mode 100644
index 00000000000..60929c8527b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/fluidguiding.cpp
@@ -0,0 +1,516 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for pressure correction: solve_pressure, and ghost fluid helpers
+ *
+ ******************************************************************************/
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+#include "conjugategrad.h"
+#include "rcmatrix.h"
+
+using namespace std;
+namespace Manta {
+
+// only supports a single blur size for now, globals stored here
+bool gBlurPrecomputed = false;
+int gBlurKernelRadius = -1;
+Matrix gBlurKernel;
+
+// *****************************************************************************
+// Helper functions for fluid guiding
+
+//! creates a 1D (horizontal) Gaussian blur kernel of size n and standard deviation sigma
+Matrix get1DGaussianBlurKernel(const int n, const int sigma) {
+ Matrix x(n), y(n);
+ for (int j = 0; j < n; j++) {
+ x.add_to_element(0, j, - (n - 1)*0.5);
+ y.add_to_element(0, j, j - (n - 1)*0.5);
+ }
+ Matrix G(n);
+ Real sumG = 0;
+ for (int j = 0; j < n; j++) {
+ G.add_to_element(0, j, 1 / (2 * M_PI*sigma*sigma)*exp(-(x(0, j)*x(0, j) + y(0, j)*y(0, j)) / (2 * sigma*sigma)));
+ sumG += G(0, j);
+ }
+ G = G*(1.0 / sumG);
+ return G;
+}
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the x-direction
+//! (out must be a grid of zeros)
+ struct apply1DKernelDirX : public KernelBase {
+ apply1DKernelDirX(const MACGrid &in, MACGrid &out, const Matrix &kernel) : KernelBase(&in,0) ,in(in),out(out),kernel(kernel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel ) {
+ int nx = in.getSizeX();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, ii = i - kCentre; m < kn; m++, ind--, ii++) {
+ if (ii < 0) continue;
+ else if (ii >= nx) break;
+ else out(i, j, k) += in(ii, j, k)*kernel(0,ind);
+ }
+} inline const MACGrid& getArg0() {
+ return in; }
+ typedef MACGrid type0;inline MACGrid& getArg1() {
+ return out; }
+ typedef MACGrid type1;inline const Matrix& getArg2() {
+ return kernel; }
+ typedef Matrix type2; void runMessage() { debMsg("Executing kernel apply1DKernelDirX ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,in,out,kernel); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,in,out,kernel); }
+ }
+ }
+ const MACGrid& in; MACGrid& out; const Matrix& kernel; }
+;
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the y-direction
+//! (out must be a grid of zeros)
+ struct apply1DKernelDirY : public KernelBase {
+ apply1DKernelDirY(const MACGrid &in, MACGrid &out, const Matrix &kernel) : KernelBase(&in,0) ,in(in),out(out),kernel(kernel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel ) {
+ int ny = in.getSizeY();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, jj = j - kCentre; m < kn; m++, ind--, jj++) {
+ if (jj < 0) continue;
+ else if (jj >= ny) break;
+ else out(i, j, k) += in(i, jj, k)*kernel(0, ind);
+ }
+} inline const MACGrid& getArg0() {
+ return in; }
+ typedef MACGrid type0;inline MACGrid& getArg1() {
+ return out; }
+ typedef MACGrid type1;inline const Matrix& getArg2() {
+ return kernel; }
+ typedef Matrix type2; void runMessage() { debMsg("Executing kernel apply1DKernelDirY ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,in,out,kernel); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,in,out,kernel); }
+ }
+ }
+ const MACGrid& in; MACGrid& out; const Matrix& kernel; }
+;
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the z-direction
+//! (out must be a grid of zeros)
+ struct apply1DKernelDirZ : public KernelBase {
+ apply1DKernelDirZ(const MACGrid &in, MACGrid &out, const Matrix &kernel) : KernelBase(&in,0) ,in(in),out(out),kernel(kernel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel ) {
+ int nz = in.getSizeZ();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, kk = k - kCentre; m < kn; m++, ind--, kk++) {
+ if (kk < 0) continue;
+ else if (kk >= nz) break;
+ else out(i, j, k) += in(i, j, kk)*kernel(0, ind);
+ }
+} inline const MACGrid& getArg0() {
+ return in; }
+ typedef MACGrid type0;inline MACGrid& getArg1() {
+ return out; }
+ typedef MACGrid type1;inline const Matrix& getArg2() {
+ return kernel; }
+ typedef Matrix type2; void runMessage() { debMsg("Executing kernel apply1DKernelDirZ ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,in,out,kernel); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,in,out,kernel); }
+ }
+ }
+ const MACGrid& in; MACGrid& out; const Matrix& kernel; }
+;
+
+//! Apply separable Gaussian blur in 2D
+void applySeparableKernel2D(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel) {
+ //int nx = grid.getSizeX(), ny = grid.getSizeY();
+ //int kn = kernel.n;
+ //int kCentre = kn / 2;
+ FluidSolver* parent = grid.getParent();
+ MACGrid orig = MACGrid(parent);
+ orig.copyFrom(grid);
+ MACGrid gridX = MACGrid(parent);
+ apply1DKernelDirX(grid, gridX, kernel);
+ MACGrid gridXY = MACGrid(parent);
+ apply1DKernelDirY(gridX, gridXY, kernel);
+ grid.copyFrom(gridXY);
+ FOR_IJK(grid) {
+ if ((i>0 && flags.isObstacle(i - 1, j, k)) || (j>0 && flags.isObstacle(i, j - 1, k)) || flags.isObstacle(i, j, k)) {
+ grid(i, j, k).x = orig(i, j, k).x;
+ grid(i, j, k).y = orig(i, j, k).y;
+ grid(i, j, k).z = orig(i, j, k).z;
+ }
+ }
+}
+
+//! Apply separable Gaussian blur in 3D
+void applySeparableKernel3D(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel) {
+ //int nx = grid.getSizeX(), ny = grid.getSizeY(), nz = grid.getSizeZ();
+ //int kn = kernel.n;
+ //int kCentre = kn / 2;
+ FluidSolver* parent = grid.getParent();
+ MACGrid orig = MACGrid(parent);
+ orig.copyFrom(grid);
+ MACGrid gridX = MACGrid(parent);
+ apply1DKernelDirX(grid, gridX, kernel);
+ MACGrid gridXY = MACGrid(parent);
+ apply1DKernelDirY(gridX, gridXY, kernel);
+ MACGrid gridXYZ = MACGrid(parent);
+ apply1DKernelDirZ(gridXY, gridXYZ, kernel);
+ grid.copyFrom(gridXYZ);
+ FOR_IJK(grid) {
+ if ((i>0 && flags.isObstacle(i - 1, j, k)) || (j>0 && flags.isObstacle(i, j - 1, k)) || (k>0 && flags.isObstacle(i, j, k - 1)) || flags.isObstacle(i, j, k)) {
+ grid(i, j, k).x = orig(i, j, k).x;
+ grid(i, j, k).y = orig(i, j, k).y;
+ grid(i, j, k).z = orig(i, j, k).z;
+ }
+ }
+}
+
+//! Apply separable Gaussian blur in 2D or 3D depending on input dimensions
+void applySeparableKernel(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel) {
+ if (!grid.is3D()) applySeparableKernel2D(grid, flags, kernel);
+ else applySeparableKernel3D(grid, flags, kernel);
+}
+
+
+//! Compute r-norm for the stopping criterion
+Real getRNorm(const MACGrid &x, const MACGrid &z) {
+ MACGrid r = MACGrid(x.getParent());
+ r.copyFrom(x);
+ r.sub(z);
+ return r.getMaxAbs();
+}
+
+//! Compute s-norm for the stopping criterion
+Real getSNorm(const Real rho, const MACGrid &z, const MACGrid &z_prev) {
+ MACGrid s = MACGrid(z_prev.getParent());
+ s.copyFrom(z_prev);
+ s.sub(z);
+ s.multConst(rho);
+ return s.getMaxAbs();
+}
+
+//! Compute primal eps for the stopping criterion
+Real getEpsPri(const Real eps_abs, const Real eps_rel,
+ const MACGrid &x, const MACGrid &z) {
+ Real max_norm = max(x.getMaxAbs(), z.getMaxAbs());
+ Real eps_pri = sqrt(x.is3D() ? 3.0 : 2.0)*eps_abs + eps_rel*max_norm;
+ return eps_pri;
+}
+
+//! Compute dual eps for the stopping criterion
+Real getEpsDual(const Real eps_abs, const Real eps_rel, const MACGrid &y) {
+ Real eps_dual = sqrt(y.is3D() ? 3.0 : 2.0)*eps_abs + eps_rel*y.getMaxAbs();
+ return eps_dual;
+}
+
+//! Create a spiral velocity field in 2D as a test scene (optionally in 3D)
+void getSpiralVelocity(const FlagGrid &flags, MACGrid &vel, Real strength = 1.0, bool with3D=false) {
+ int nx = flags.getSizeX(), ny = flags.getSizeY(), nz = 1;
+ if (with3D) nz = flags.getSizeZ();
+ Real midX = 0.5*(Real)(nx - 1);
+ Real midY = 0.5*(Real)(ny - 1);
+ Real midZ = 0.5*(Real)(nz - 1);
+ for (int i = 0; i < nx; i++) {
+ for (int j = 0; j < ny; j++) {
+ for (int k = 0; k < nz; k++) {
+ int idx = flags.index(i, j, k);
+ Real diffX = midX - i;
+ Real diffY = midY - j;
+ Real hypotenuse = sqrt(diffX*diffX + diffY*diffY);
+ if (hypotenuse > 0) {
+ vel[idx].x = diffY / hypotenuse;
+ vel[idx].y = -diffX / hypotenuse;
+ }
+ }
+ }
+ }
+ vel.multConst(strength);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getSpiralVelocity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); Real strength = _args.getOpt<Real >("strength",2,1.0,&_lock); bool with3D = _args.getOpt<bool >("with3D",3,false,&_lock); _retval = getPyNone(); getSpiralVelocity(flags,vel,strength,with3D); _args.check(); }
+ pbFinalizePlugin(parent,"getSpiralVelocity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getSpiralVelocity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getSpiralVelocity ("","getSpiralVelocity",_W_0);
+extern "C" {
+ void PbRegister_getSpiralVelocity() {
+ KEEP_UNUSED(_RP_getSpiralVelocity); }
+ }
+
+
+
+//! Set the guiding weight W as a gradient in the y-direction
+void setGradientYWeight(Grid<Real> &W, const int minY, const int maxY, const Real valAtMin, const Real valAtMax) {
+ FOR_IJK(W) {
+ if (minY <= j && j <= maxY) {
+ Real val = valAtMin;
+ if (valAtMax != valAtMin) {
+ Real ratio = (Real)(j - minY) / (Real)(maxY - minY);
+ val = ratio*valAtMax + (1.0 - ratio)*valAtMin;
+ }
+ W(i, j, k) = val;
+ }
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setGradientYWeight" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & W = *_args.getPtr<Grid<Real> >("W",0,&_lock); const int minY = _args.get<int >("minY",1,&_lock); const int maxY = _args.get<int >("maxY",2,&_lock); const Real valAtMin = _args.get<Real >("valAtMin",3,&_lock); const Real valAtMax = _args.get<Real >("valAtMax",4,&_lock); _retval = getPyNone(); setGradientYWeight(W,minY,maxY,valAtMin,valAtMax); _args.check(); }
+ pbFinalizePlugin(parent,"setGradientYWeight", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setGradientYWeight",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setGradientYWeight ("","setGradientYWeight",_W_1);
+extern "C" {
+ void PbRegister_setGradientYWeight() {
+ KEEP_UNUSED(_RP_setGradientYWeight); }
+ }
+
+
+
+// *****************************************************************************
+// More helper functions for fluid guiding
+
+//! Apply Gaussian blur (either 2D or 3D) in a separable way
+void applySeparableGaussianBlur(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel1D) {
+ assertMsg(gBlurPrecomputed, "Error - blue kernel not precomputed");
+ applySeparableKernel(grid, flags, kernel1D);
+}
+
+//! Precomputation performed before the first PD iteration
+void ADMM_precompute_Separable(int blurRadius) {
+ if (gBlurPrecomputed) {
+ assertMsg( gBlurKernelRadius == blurRadius, "More than a single blur radius not supported at the moment." );
+ return;
+ }
+ int kernelSize = 2 * blurRadius + 1;
+ gBlurKernel = get1DGaussianBlurKernel(kernelSize, kernelSize);
+ gBlurPrecomputed = true;
+ gBlurKernelRadius = blurRadius;
+}
+
+//! Apply approximate multiplication of inverse(M)
+void applyApproxInvM(MACGrid& v, const FlagGrid &flags, const MACGrid& invA) {
+ MACGrid v_new = MACGrid(v.getParent());
+ v_new.copyFrom(v);
+ v_new.mult(invA);
+ applySeparableGaussianBlur(v_new, flags, gBlurKernel);
+ applySeparableGaussianBlur(v_new, flags, gBlurKernel);
+ v_new.multConst(2.0);
+ v_new.mult(invA);
+ v.mult(invA);
+ v.sub(v_new);
+}
+
+//! Precompute Q, a reused quantity in the PD iterations
+//! Q = 2*G*G*(velT-velC)-sigma*velC
+void precomputeQ(MACGrid &Q, const FlagGrid &flags, const MACGrid &velT_region, const MACGrid &velC, const Matrix &gBlurKernel, const Real sigma) {
+ Q.copyFrom(velT_region);
+ Q.sub(velC);
+ applySeparableGaussianBlur(Q, flags, gBlurKernel);
+ applySeparableGaussianBlur(Q, flags, gBlurKernel);
+ Q.multConst(2.0);
+ Q.addScaled(velC, -sigma);
+}
+
+//! Precompute inverse(A), a reused quantity in the PD iterations
+//! A = 2*S^2 + p*I, invA = elementwise 1/A
+void precomputeInvA(MACGrid &invA, const Grid<Real> &weight, const Real sigma) {
+ FOR_IJK(invA) {
+ Real val = 2 * weight(i, j, k)*weight(i, j, k) + sigma;
+ if (val<0.01) val = 0.01;
+ Real invVal = 1.0 / val;
+ invA(i, j, k).x = invVal;
+ invA(i, j, k).y = invVal;
+ invA(i, j, k).z = invVal;
+ }
+}
+
+//! proximal operator of f , guiding
+void prox_f(MACGrid& v, const FlagGrid &flags, const MACGrid& Q, const MACGrid& velC, const Real sigma, const MACGrid& invA) {
+ v.multConst(sigma);
+ v.add(Q);
+ applyApproxInvM(v, flags, invA);
+ v.add(velC);
+}
+
+// *****************************************************************************
+
+// re-uses main pressure solve from pressure.cpp
+void solvePressure(
+ MACGrid& vel, Grid<Real>& pressure, const FlagGrid& flags, Real cgAccuracy = 1e-3,
+ const Grid<Real>* phi = 0,
+ const Grid<Real>* perCellCorr = 0,
+ const MACGrid* fractions = 0,
+ Real gfClamp = 1e-04,
+ Real cgMaxIterFac = 1.5,
+ bool precondition = true,
+ int preconditioner = 1,
+ bool enforceCompatibility = false,
+ bool useL2Norm = false,
+ bool zeroPressureFixing = false,
+ const Grid<Real> *curv = NULL,
+ const Real surfTens = 0.0,
+ Grid<Real>* retRhs = NULL );
+
+//! Main function for fluid guiding , includes "regular" pressure solve
+
+
+
+
+
+
+
+void PD_fluid_guiding(MACGrid& vel, MACGrid& velT, Grid<Real>& pressure, FlagGrid& flags, Grid<Real>& weight, int blurRadius = 5, Real theta = 1.0, Real tau = 1.0, Real sigma = 1.0, Real epsRel = 1e-3, Real epsAbs = 1e-3, int maxIters = 200, Grid<Real>* phi = 0, Grid<Real>* perCellCorr = 0, MACGrid* fractions = 0, Real gfClamp = 1e-04, Real cgMaxIterFac = 1.5, Real cgAccuracy = 1e-3, int preconditioner = 1, bool zeroPressureFixing = false, const Grid<Real> *curv = NULL, const Real surfTens = 0.) {
+ FluidSolver* parent = vel.getParent();
+
+ // initialize dual/slack variables
+ MACGrid velC = MACGrid(parent); velC.copyFrom(vel);
+ MACGrid x = MACGrid(parent);
+ MACGrid y = MACGrid(parent);
+ MACGrid z = MACGrid(parent);
+ MACGrid x0 = MACGrid(parent);
+ MACGrid z0 = MACGrid(parent);
+
+ // precomputation
+ ADMM_precompute_Separable(blurRadius);
+ MACGrid Q = MACGrid(parent);
+ precomputeQ(Q, flags, velT, velC, gBlurKernel, sigma);
+ MACGrid invA = MACGrid(parent);
+ precomputeInvA(invA, weight, sigma);
+
+ // loop
+ int iter = 0;
+ for (iter = 0; iter < maxIters; iter++) {
+ // x-update
+ x0.copyFrom(x);
+ x.multConst(1.0 / sigma);
+ x.add(y);
+ prox_f(x, flags, Q, velC, sigma, invA);
+ x.multConst(-sigma); x.addScaled(y, sigma); x.add(x0);
+
+ // z-update
+ z0.copyFrom(z);
+ z.addScaled(x, -tau);
+ Real cgAccuracyAdaptive = cgAccuracy;
+
+ solvePressure (z, pressure, flags, cgAccuracyAdaptive, phi, perCellCorr, fractions, gfClamp,
+ cgMaxIterFac, true, preconditioner, false, false, zeroPressureFixing, curv, surfTens );
+
+ // y-update
+ y.copyFrom(z);
+ y.sub(z0);
+ y.multConst(theta);
+ y.add(z);
+
+ // stopping criterion
+ bool stop = (iter > 0 && getRNorm(z, z0) < getEpsDual(epsAbs, epsRel, z));
+
+ if (stop || (iter == maxIters - 1)) break;
+ }
+
+ // vel_new = z
+ vel.copyFrom(z);
+
+ debMsg("PD_fluid_guiding iterations:" << iter, 1);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "PD_fluid_guiding" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); MACGrid& velT = *_args.getPtr<MACGrid >("velT",1,&_lock); Grid<Real>& pressure = *_args.getPtr<Grid<Real> >("pressure",2,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",3,&_lock); Grid<Real>& weight = *_args.getPtr<Grid<Real> >("weight",4,&_lock); int blurRadius = _args.getOpt<int >("blurRadius",5,5,&_lock); Real theta = _args.getOpt<Real >("theta",6,1.0,&_lock); Real tau = _args.getOpt<Real >("tau",7,1.0,&_lock); Real sigma = _args.getOpt<Real >("sigma",8,1.0,&_lock); Real epsRel = _args.getOpt<Real >("epsRel",9,1e-3,&_lock); Real epsAbs = _args.getOpt<Real >("epsAbs",10,1e-3,&_lock); int maxIters = _args.getOpt<int >("maxIters",11,200,&_lock); Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",12,0,&_lock); Grid<Real>* perCellCorr = _args.getPtrOpt<Grid<Real> >("perCellCorr",13,0,&_lock); MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",14,0,&_lock); Real gfClamp = _args.getOpt<Real >("gfClamp",15,1e-04,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",16,1.5,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",17,1e-3,&_lock); int preconditioner = _args.getOpt<int >("preconditioner",18,1,&_lock); bool zeroPressureFixing = _args.getOpt<bool >("zeroPressureFixing",19,false,&_lock); const Grid<Real> * curv = _args.getPtrOpt<Grid<Real> >("curv",20,NULL,&_lock); const Real surfTens = _args.getOpt<Real >("surfTens",21,0.,&_lock); _retval = getPyNone(); PD_fluid_guiding(vel,velT,pressure,flags,weight,blurRadius,theta,tau,sigma,epsRel,epsAbs,maxIters,phi,perCellCorr,fractions,gfClamp,cgMaxIterFac,cgAccuracy,preconditioner,zeroPressureFixing,curv,surfTens); _args.check(); }
+ pbFinalizePlugin(parent,"PD_fluid_guiding", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("PD_fluid_guiding",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_PD_fluid_guiding ("","PD_fluid_guiding",_W_2);
+extern "C" {
+ void PbRegister_PD_fluid_guiding() {
+ KEEP_UNUSED(_RP_PD_fluid_guiding); }
+ }
+
+
+
+//! reset precomputation
+void releaseBlurPrecomp() {
+ gBlurPrecomputed = false;
+ gBlurKernelRadius = -1;
+ gBlurKernel = 0.f;
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "releaseBlurPrecomp" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; _retval = getPyNone(); releaseBlurPrecomp(); _args.check(); }
+ pbFinalizePlugin(parent,"releaseBlurPrecomp", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("releaseBlurPrecomp",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_releaseBlurPrecomp ("","releaseBlurPrecomp",_W_3);
+extern "C" {
+ void PbRegister_releaseBlurPrecomp() {
+ KEEP_UNUSED(_RP_releaseBlurPrecomp); }
+ }
+
+
+
+
+} // end namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/initplugins.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/initplugins.cpp
new file mode 100644
index 00000000000..a9e7c59f7e4
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/initplugins.cpp
@@ -0,0 +1,1265 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Tools to setup fields and inflows
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "shapes.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include "noisefield.h"
+#include "mesh.h"
+
+// disable saving projected images as ppms in blender
+#if BLENDER!=1
+#include "simpleimage.h"
+#endif
+
+using namespace std;
+
+namespace Manta {
+
+//! Apply noise to grid
+
+
+ struct KnApplyNoiseInfl : public KernelBase {
+ KnApplyNoiseInfl(const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, const Grid<Real>& sdf, Real scale, Real sigma) : KernelBase(&flags,0) ,flags(flags),density(density),noise(noise),sdf(sdf),scale(scale),sigma(sigma) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, const Grid<Real>& sdf, Real scale, Real sigma ) {
+ if (!flags.isFluid(i,j,k) || sdf(i,j,k) > sigma) return;
+ Real factor = clamp(1.0-0.5/sigma * (sdf(i,j,k)+sigma), 0.0, 1.0);
+
+ Real target = noise.evaluate(Vec3(i,j,k)) * scale * factor;
+ if (density(i,j,k) < target)
+ density(i,j,k) = target;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return density; }
+ typedef Grid<Real> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline const Grid<Real>& getArg3() {
+ return sdf; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return scale; }
+ typedef Real type4;inline Real& getArg5() {
+ return sigma; }
+ typedef Real type5; void runMessage() { debMsg("Executing kernel KnApplyNoiseInfl ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,density,noise,sdf,scale,sigma); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,density,noise,sdf,scale,sigma); }
+ }
+ }
+ const FlagGrid& flags; Grid<Real>& density; const WaveletNoiseField& noise; const Grid<Real>& sdf; Real scale; Real sigma; }
+;
+
+//! Init noise-modulated density inside shape
+
+void densityInflow(const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, Shape* shape, Real scale=1.0, Real sigma=0) {
+ Grid<Real> sdf = shape->computeLevelset();
+ KnApplyNoiseInfl(flags, density, noise, sdf, scale, sigma);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "densityInflow" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Shape* shape = _args.getPtr<Shape >("shape",3,&_lock); Real scale = _args.getOpt<Real >("scale",4,1.0,&_lock); Real sigma = _args.getOpt<Real >("sigma",5,0,&_lock); _retval = getPyNone(); densityInflow(flags,density,noise,shape,scale,sigma); _args.check(); }
+ pbFinalizePlugin(parent,"densityInflow", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("densityInflow",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_densityInflow ("","densityInflow",_W_0);
+extern "C" {
+ void PbRegister_densityInflow() {
+ KEEP_UNUSED(_RP_densityInflow); }
+ }
+
+
+//! Apply noise to real grid based on an SDF
+ struct KnAddNoise : public KernelBase {
+ KnAddNoise(const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, const Grid<Real>* sdf, Real scale) : KernelBase(&flags,0) ,flags(flags),density(density),noise(noise),sdf(sdf),scale(scale) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, const Grid<Real>* sdf, Real scale ) {
+ if (!flags.isFluid(i,j,k) || (sdf && (*sdf)(i,j,k) > 0.) ) return;
+ density(i,j,k) += noise.evaluate(Vec3(i,j,k)) * scale;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return density; }
+ typedef Grid<Real> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline const Grid<Real>* getArg3() {
+ return sdf; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return scale; }
+ typedef Real type4; void runMessage() { debMsg("Executing kernel KnAddNoise ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,density,noise,sdf,scale); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,density,noise,sdf,scale); }
+ }
+ }
+ const FlagGrid& flags; Grid<Real>& density; const WaveletNoiseField& noise; const Grid<Real>* sdf; Real scale; }
+;
+void addNoise(const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, const Grid<Real>* sdf=NULL, Real scale=1.0 ) {
+ KnAddNoise(flags, density, noise, sdf, scale );
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addNoise" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); const Grid<Real>* sdf = _args.getPtrOpt<Grid<Real> >("sdf",3,NULL,&_lock); Real scale = _args.getOpt<Real >("scale",4,1.0 ,&_lock); _retval = getPyNone(); addNoise(flags,density,noise,sdf,scale); _args.check(); }
+ pbFinalizePlugin(parent,"addNoise", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addNoise",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addNoise ("","addNoise",_W_1);
+extern "C" {
+ void PbRegister_addNoise() {
+ KEEP_UNUSED(_RP_addNoise); }
+ }
+
+
+
+//! sample noise field and set pdata with its values (for convenience, scale the noise values)
+
+template <class T> struct knSetPdataNoise : public KernelBase {
+ knSetPdataNoise(const BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, const WaveletNoiseField& noise, Real scale) : KernelBase(parts.size()) ,parts(parts),pdata(pdata),noise(noise),scale(scale) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, const WaveletNoiseField& noise, Real scale ) {
+ pdata[idx] = noise.evaluate( parts.getPos(idx) ) * scale;
+} inline const BasicParticleSystem& getArg0() {
+ return parts; }
+ typedef BasicParticleSystem type0;inline ParticleDataImpl<T>& getArg1() {
+ return pdata; }
+ typedef ParticleDataImpl<T> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Real& getArg3() {
+ return scale; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel knSetPdataNoise ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,parts,pdata,noise,scale); }
+ }
+ const BasicParticleSystem& parts; ParticleDataImpl<T>& pdata; const WaveletNoiseField& noise; Real scale; }
+;
+
+template <class T> struct knSetPdataNoiseVec : public KernelBase {
+ knSetPdataNoiseVec(const BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, const WaveletNoiseField& noise, Real scale) : KernelBase(parts.size()) ,parts(parts),pdata(pdata),noise(noise),scale(scale) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, const WaveletNoiseField& noise, Real scale ) {
+ pdata[idx] = noise.evaluateVec( parts.getPos(idx) ) * scale;
+} inline const BasicParticleSystem& getArg0() {
+ return parts; }
+ typedef BasicParticleSystem type0;inline ParticleDataImpl<T>& getArg1() {
+ return pdata; }
+ typedef ParticleDataImpl<T> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Real& getArg3() {
+ return scale; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel knSetPdataNoiseVec ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,parts,pdata,noise,scale); }
+ }
+ const BasicParticleSystem& parts; ParticleDataImpl<T>& pdata; const WaveletNoiseField& noise; Real scale; }
+;
+void setNoisePdata(const BasicParticleSystem& parts, ParticleDataImpl<Real>& pd, const WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoise<Real>(parts, pd,noise,scale); } static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setNoisePdata" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<Real>& pd = *_args.getPtr<ParticleDataImpl<Real> >("pd",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.,&_lock); _retval = getPyNone(); setNoisePdata(parts,pd,noise,scale); _args.check(); }
+ pbFinalizePlugin(parent,"setNoisePdata", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setNoisePdata",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setNoisePdata ("","setNoisePdata",_W_2);
+extern "C" {
+ void PbRegister_setNoisePdata() {
+ KEEP_UNUSED(_RP_setNoisePdata); }
+ }
+
+
+void setNoisePdataVec3(const BasicParticleSystem& parts, ParticleDataImpl<Vec3>& pd, const WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoiseVec<Vec3>(parts, pd,noise,scale); } static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setNoisePdataVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<Vec3>& pd = *_args.getPtr<ParticleDataImpl<Vec3> >("pd",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.,&_lock); _retval = getPyNone(); setNoisePdataVec3(parts,pd,noise,scale); _args.check(); }
+ pbFinalizePlugin(parent,"setNoisePdataVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setNoisePdataVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setNoisePdataVec3 ("","setNoisePdataVec3",_W_3);
+extern "C" {
+ void PbRegister_setNoisePdataVec3() {
+ KEEP_UNUSED(_RP_setNoisePdataVec3); }
+ }
+
+
+void setNoisePdataInt(const BasicParticleSystem& parts, ParticleDataImpl<int >& pd, const WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoise<int> (parts, pd,noise,scale); } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setNoisePdataInt" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<int >& pd = *_args.getPtr<ParticleDataImpl<int > >("pd",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.,&_lock); _retval = getPyNone(); setNoisePdataInt(parts,pd,noise,scale); _args.check(); }
+ pbFinalizePlugin(parent,"setNoisePdataInt", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setNoisePdataInt",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setNoisePdataInt ("","setNoisePdataInt",_W_4);
+extern "C" {
+ void PbRegister_setNoisePdataInt() {
+ KEEP_UNUSED(_RP_setNoisePdataInt); }
+ }
+
+
+
+//! SDF gradient from obstacle flags, for turbulence.py
+// FIXME, slow, without kernel...
+Grid<Vec3> obstacleGradient(const FlagGrid& flags) {
+ LevelsetGrid levelset(flags.getParent(),false);
+ Grid<Vec3> gradient(flags.getParent());
+
+ // rebuild obstacle levelset
+ FOR_IDX(levelset) {
+ levelset[idx] = flags.isObstacle(idx) ? -0.5 : 0.5;
+ }
+ levelset.reinitMarching(flags, 6.0, 0, true, false, FlagGrid::TypeReserved);
+
+ // build levelset gradient
+ GradientOp(gradient, levelset);
+
+ FOR_IDX(levelset) {
+ Vec3 grad = gradient[idx];
+ Real s = normalize(grad);
+ if (s <= 0.1 || levelset[idx] >= 0)
+ grad=Vec3(0.);
+ gradient[idx] = grad * levelset[idx];
+ }
+
+ return gradient;
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "obstacleGradient" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); _retval = toPy(obstacleGradient(flags)); _args.check(); }
+ pbFinalizePlugin(parent,"obstacleGradient", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("obstacleGradient",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_obstacleGradient ("","obstacleGradient",_W_5);
+extern "C" {
+ void PbRegister_obstacleGradient() {
+ KEEP_UNUSED(_RP_obstacleGradient); }
+ }
+
+
+
+//! SDF from obstacle flags, for turbulence.py
+LevelsetGrid obstacleLevelset(const FlagGrid& flags) {
+ LevelsetGrid levelset(flags.getParent(),false);
+
+ // rebuild obstacle levelset
+ FOR_IDX(levelset) {
+ levelset[idx] = flags.isObstacle(idx) ? -0.5 : 0.5;
+ }
+ levelset.reinitMarching(flags, 6.0, 0, true, false, FlagGrid::TypeReserved);
+
+ return levelset;
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "obstacleLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); _retval = toPy(obstacleLevelset(flags)); _args.check(); }
+ pbFinalizePlugin(parent,"obstacleLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("obstacleLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_obstacleLevelset ("","obstacleLevelset",_W_6);
+extern "C" {
+ void PbRegister_obstacleLevelset() {
+ KEEP_UNUSED(_RP_obstacleLevelset); }
+ }
+
+
+
+
+//*****************************************************************************
+// blender init functions
+
+
+
+ struct KnApplyEmission : public KernelBase {
+ KnApplyEmission(const FlagGrid& flags, Grid<Real>& target, const Grid<Real>& source, const Grid<Real>* emissionTexture, bool isAbsolute, int type) : KernelBase(&flags,0) ,flags(flags),target(target),source(source),emissionTexture(emissionTexture),isAbsolute(isAbsolute),type(type) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& target, const Grid<Real>& source, const Grid<Real>* emissionTexture, bool isAbsolute, int type ) {
+ // if type is given, only apply emission when celltype matches type from flaggrid
+ // and if emission texture is given, only apply emission when some emission is present at cell (important for emit from particles)
+ bool isInflow = (type & FlagGrid::TypeInflow && flags.isInflow(i,j,k));
+ bool isOutflow = (type & FlagGrid::TypeOutflow && flags.isOutflow(i,j,k));
+ if ( (type && !isInflow && !isOutflow) && (emissionTexture && !(*emissionTexture)(i,j,k)) ) return;
+
+ if (isAbsolute)
+ target(i,j,k) = source(i,j,k);
+ else
+ target(i,j,k) += source(i,j,k);
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return target; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return source; }
+ typedef Grid<Real> type2;inline const Grid<Real>* getArg3() {
+ return emissionTexture; }
+ typedef Grid<Real> type3;inline bool& getArg4() {
+ return isAbsolute; }
+ typedef bool type4;inline int& getArg5() {
+ return type; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnApplyEmission ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,target,source,emissionTexture,isAbsolute,type); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,target,source,emissionTexture,isAbsolute,type); }
+ }
+ }
+ const FlagGrid& flags; Grid<Real>& target; const Grid<Real>& source; const Grid<Real>* emissionTexture; bool isAbsolute; int type; }
+;
+
+//! Add emission values
+//isAbsolute: whether to add emission values to existing, or replace
+void applyEmission(FlagGrid& flags, Grid<Real>& target, Grid<Real>& source, Grid<Real>* emissionTexture=NULL, bool isAbsolute=true, int type=0) {
+ KnApplyEmission(flags, target, source, emissionTexture, isAbsolute, type);
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "applyEmission" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",1,&_lock); Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",2,&_lock); Grid<Real>* emissionTexture = _args.getPtrOpt<Grid<Real> >("emissionTexture",3,NULL,&_lock); bool isAbsolute = _args.getOpt<bool >("isAbsolute",4,true,&_lock); int type = _args.getOpt<int >("type",5,0,&_lock); _retval = getPyNone(); applyEmission(flags,target,source,emissionTexture,isAbsolute,type); _args.check(); }
+ pbFinalizePlugin(parent,"applyEmission", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("applyEmission",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_applyEmission ("","applyEmission",_W_7);
+extern "C" {
+ void PbRegister_applyEmission() {
+ KEEP_UNUSED(_RP_applyEmission); }
+ }
+
+
+
+// blender init functions for meshes
+
+
+
+ struct KnApplyDensity : public KernelBase {
+ KnApplyDensity(const FlagGrid& flags, Grid<Real>& density, const Grid<Real>& sdf, Real value, Real sigma) : KernelBase(&flags,0) ,flags(flags),density(density),sdf(sdf),value(value),sigma(sigma) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& density, const Grid<Real>& sdf, Real value, Real sigma ) {
+ if (!flags.isFluid(i,j,k) || sdf(i,j,k) > sigma) return;
+ density(i,j,k) = value;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return density; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return sdf; }
+ typedef Grid<Real> type2;inline Real& getArg3() {
+ return value; }
+ typedef Real type3;inline Real& getArg4() {
+ return sigma; }
+ typedef Real type4; void runMessage() { debMsg("Executing kernel KnApplyDensity ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,density,sdf,value,sigma); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,density,sdf,value,sigma); }
+ }
+ }
+ const FlagGrid& flags; Grid<Real>& density; const Grid<Real>& sdf; Real value; Real sigma; }
+;
+//! Init noise-modulated density inside mesh
+
+void densityInflowMeshNoise(const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, Mesh* mesh, Real scale=1.0, Real sigma=0) {
+ LevelsetGrid sdf(density.getParent(), false);
+ mesh->computeLevelset(sdf, 1.);
+ KnApplyNoiseInfl(flags, density, noise, sdf, scale, sigma);
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "densityInflowMeshNoise" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Mesh* mesh = _args.getPtr<Mesh >("mesh",3,&_lock); Real scale = _args.getOpt<Real >("scale",4,1.0,&_lock); Real sigma = _args.getOpt<Real >("sigma",5,0,&_lock); _retval = getPyNone(); densityInflowMeshNoise(flags,density,noise,mesh,scale,sigma); _args.check(); }
+ pbFinalizePlugin(parent,"densityInflowMeshNoise", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("densityInflowMeshNoise",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_densityInflowMeshNoise ("","densityInflowMeshNoise",_W_8);
+extern "C" {
+ void PbRegister_densityInflowMeshNoise() {
+ KEEP_UNUSED(_RP_densityInflowMeshNoise); }
+ }
+
+
+
+//! Init constant density inside mesh
+
+void densityInflowMesh(const FlagGrid& flags, Grid<Real>& density, Mesh* mesh, Real value=1., Real cutoff = 7, Real sigma=0) {
+ LevelsetGrid sdf(density.getParent(), false);
+ mesh->computeLevelset(sdf, 2., cutoff);
+ KnApplyDensity(flags, density, sdf, value, sigma);
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "densityInflowMesh" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); Mesh* mesh = _args.getPtr<Mesh >("mesh",2,&_lock); Real value = _args.getOpt<Real >("value",3,1.,&_lock); Real cutoff = _args.getOpt<Real >("cutoff",4,7,&_lock); Real sigma = _args.getOpt<Real >("sigma",5,0,&_lock); _retval = getPyNone(); densityInflowMesh(flags,density,mesh,value,cutoff,sigma); _args.check(); }
+ pbFinalizePlugin(parent,"densityInflowMesh", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("densityInflowMesh",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_densityInflowMesh ("","densityInflowMesh",_W_9);
+extern "C" {
+ void PbRegister_densityInflowMesh() {
+ KEEP_UNUSED(_RP_densityInflowMesh); }
+ }
+
+
+
+
+//*****************************************************************************
+
+//! check for symmetry , optionally enfore by copying
+
+void checkSymmetry( Grid<Real>& a, Grid<Real>* err=NULL, bool symmetrize=false, int axis=0, int bound=0) {
+ const int c = axis;
+ const int s = a.getSize()[c];
+ FOR_IJK(a) {
+ Vec3i idx(i,j,k), mdx(i,j,k);
+ mdx[c] = s-1-idx[c];
+ if( bound>0 && ((!a.isInBounds(idx,bound)) || (!a.isInBounds(mdx,bound))) ) continue;
+
+ if(err) (*err)(idx) = fabs( (double)(a(idx) - a(mdx) ) );
+ if(symmetrize && (idx[c]<s/2)) {
+ a(idx) = a(mdx);
+ }
+ }
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "checkSymmetry" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& a = *_args.getPtr<Grid<Real> >("a",0,&_lock); Grid<Real>* err = _args.getPtrOpt<Grid<Real> >("err",1,NULL,&_lock); bool symmetrize = _args.getOpt<bool >("symmetrize",2,false,&_lock); int axis = _args.getOpt<int >("axis",3,0,&_lock); int bound = _args.getOpt<int >("bound",4,0,&_lock); _retval = getPyNone(); checkSymmetry(a,err,symmetrize,axis,bound); _args.check(); }
+ pbFinalizePlugin(parent,"checkSymmetry", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("checkSymmetry",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_checkSymmetry ("","checkSymmetry",_W_10);
+extern "C" {
+ void PbRegister_checkSymmetry() {
+ KEEP_UNUSED(_RP_checkSymmetry); }
+ }
+
+
+//! check for symmetry , mac grid version
+
+
+void checkSymmetryVec3( Grid<Vec3>& a, Grid<Real>* err=NULL, bool symmetrize=false , int axis=0, int bound=0, int disable=0) {
+ if(err) err->setConst(0.);
+
+ // each dimension is measured separately for flexibility (could be combined)
+ const int c = axis;
+ const int o1 = (c+1)%3;
+ const int o2 = (c+2)%3;
+
+ // x
+ if(! (disable&1) ) {
+ const int s = a.getSize()[c]+1;
+ FOR_IJK(a) {
+ Vec3i idx(i,j,k), mdx(i,j,k);
+ mdx[c] = s-1-idx[c];
+ if(mdx[c] >= a.getSize()[c]) continue;
+ if( bound>0 && ((!a.isInBounds(idx,bound)) || (!a.isInBounds(mdx,bound))) ) continue;
+
+ // special case: center "line" of values , should be zero!
+ if(mdx[c] == idx[c] ) {
+ if(err) (*err)(idx) += fabs( (double)( a(idx)[c] ) );
+ if(symmetrize) a(idx)[c] = 0.;
+ continue;
+ }
+
+ // note - the a(mdx) component needs to be inverted here!
+ if(err) (*err)(idx) += fabs( (double)( a(idx)[c]- (a(mdx)[c]*-1.) ) );
+ if(symmetrize && (idx[c]<s/2)) {
+ a(idx)[c] = a(mdx)[c] * -1.;
+ }
+ }
+ }
+
+ // y
+ if(! (disable&2) ) {
+ const int s = a.getSize()[c];
+ FOR_IJK(a) {
+ Vec3i idx(i,j,k), mdx(i,j,k);
+ mdx[c] = s-1-idx[c];
+ if( bound>0 && ((!a.isInBounds(idx,bound)) || (!a.isInBounds(mdx,bound))) ) continue;
+
+ if(err) (*err)(idx) += fabs( (double)( a(idx)[o1]-a(mdx)[o1] ) );
+ if(symmetrize && (idx[c]<s/2)) {
+ a(idx)[o1] = a(mdx)[o1];
+ }
+ }
+ }
+
+ // z
+ if(! (disable&4) ) {
+ const int s = a.getSize()[c];
+ FOR_IJK(a) {
+ Vec3i idx(i,j,k), mdx(i,j,k);
+ mdx[c] = s-1-idx[c];
+ if( bound>0 && ((!a.isInBounds(idx,bound)) || (!a.isInBounds(mdx,bound))) ) continue;
+
+ if(err) (*err)(idx) += fabs( (double)( a(idx)[o2]-a(mdx)[o2] ) );
+ if(symmetrize && (idx[c]<s/2)) {
+ a(idx)[o2] = a(mdx)[o2];
+ }
+ }
+ }
+
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "checkSymmetryVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& a = *_args.getPtr<Grid<Vec3> >("a",0,&_lock); Grid<Real>* err = _args.getPtrOpt<Grid<Real> >("err",1,NULL,&_lock); bool symmetrize = _args.getOpt<bool >("symmetrize",2,false ,&_lock); int axis = _args.getOpt<int >("axis",3,0,&_lock); int bound = _args.getOpt<int >("bound",4,0,&_lock); int disable = _args.getOpt<int >("disable",5,0,&_lock); _retval = getPyNone(); checkSymmetryVec3(a,err,symmetrize,axis,bound,disable); _args.check(); }
+ pbFinalizePlugin(parent,"checkSymmetryVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("checkSymmetryVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_checkSymmetryVec3 ("","checkSymmetryVec3",_W_11);
+extern "C" {
+ void PbRegister_checkSymmetryVec3() {
+ KEEP_UNUSED(_RP_checkSymmetryVec3); }
+ }
+
+
+
+#if BLENDER!=1
+// from simpleimage.cpp
+void projectImg(SimpleImage& img, const Grid<Real>& val, int shadeMode = 0, Real scale = 1.);
+#endif
+
+//! output shaded (all 3 axes at once for 3D)
+//! shading modes: 0 smoke, 1 surfaces
+
+void projectPpmFull( const Grid<Real>& val, string name, int shadeMode=0, Real scale=1.) {
+ #if BLENDER!=1
+ SimpleImage img;
+ projectImg( img, val, shadeMode, scale );
+ img.writePpm( name );
+ #endif
+} static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "projectPpmFull" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& val = *_args.getPtr<Grid<Real> >("val",0,&_lock); string name = _args.get<string >("name",1,&_lock); int shadeMode = _args.getOpt<int >("shadeMode",2,0,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.,&_lock); _retval = getPyNone(); projectPpmFull(val,name,shadeMode,scale); _args.check(); }
+ pbFinalizePlugin(parent,"projectPpmFull", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("projectPpmFull",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_projectPpmFull ("","projectPpmFull",_W_12);
+extern "C" {
+ void PbRegister_projectPpmFull() {
+ KEEP_UNUSED(_RP_projectPpmFull); }
+ }
+
+
+
+// helper functions for pdata operator tests
+
+//! init some test particles at the origin
+
+void addTestParts( BasicParticleSystem& parts, int num) {
+ for(int i=0; i<num; ++i)
+ parts.addBuffered( Vec3(0,0,0) );
+
+ parts.doCompress();
+ parts.insertBufferedParticles();
+} static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addTestParts" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); int num = _args.get<int >("num",1,&_lock); _retval = getPyNone(); addTestParts(parts,num); _args.check(); }
+ pbFinalizePlugin(parent,"addTestParts", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addTestParts",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addTestParts ("","addTestParts",_W_13);
+extern "C" {
+ void PbRegister_addTestParts() {
+ KEEP_UNUSED(_RP_addTestParts); }
+ }
+
+
+
+//! calculate the difference between two pdata fields (note - slow!, not parallelized)
+
+Real pdataMaxDiff( const ParticleDataBase* a, const ParticleDataBase* b ) {
+ double maxVal = 0.;
+ //debMsg(" PD "<< a->getType()<<" as"<<a->getSizeSlow()<<" bs"<<b->getSizeSlow() , 1);
+ assertMsg(a->getType() == b->getType() , "pdataMaxDiff problem - different pdata types!");
+ assertMsg(a->getSizeSlow() == b->getSizeSlow(), "pdataMaxDiff problem - different pdata sizes!");
+
+ if (a->getType() & ParticleDataBase::TypeReal)
+ {
+ const ParticleDataImpl<Real>& av = *dynamic_cast<const ParticleDataImpl<Real>*>(a);
+ const ParticleDataImpl<Real>& bv = *dynamic_cast<const ParticleDataImpl<Real>*>(b);
+ FOR_PARTS(av) {
+ maxVal = std::max(maxVal, (double)fabs( av[idx]-bv[idx] ));
+ }
+ } else if (a->getType() & ParticleDataBase::TypeInt)
+ {
+ const ParticleDataImpl<int>& av = *dynamic_cast<const ParticleDataImpl<int>*>(a);
+ const ParticleDataImpl<int>& bv = *dynamic_cast<const ParticleDataImpl<int>*>(b);
+ FOR_PARTS(av) {
+ maxVal = std::max(maxVal, (double)fabs( (double)av[idx]-bv[idx] ));
+ }
+ } else if (a->getType() & ParticleDataBase::TypeVec3) {
+ const ParticleDataImpl<Vec3>& av = *dynamic_cast<const ParticleDataImpl<Vec3>*>(a);
+ const ParticleDataImpl<Vec3>& bv = *dynamic_cast<const ParticleDataImpl<Vec3>*>(b);
+ FOR_PARTS(av) {
+ double d = 0.;
+ for(int c=0; c<3; ++c) {
+ d += fabs( (double)av[idx][c] - (double)bv[idx][c] );
+ }
+ maxVal = std::max(maxVal, d );
+ }
+ } else {
+ errMsg("pdataMaxDiff: Grid Type is not supported (only Real, Vec3, int)");
+ }
+
+ return maxVal;
+} static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "pdataMaxDiff" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataBase* a = _args.getPtr<ParticleDataBase >("a",0,&_lock); const ParticleDataBase* b = _args.getPtr<ParticleDataBase >("b",1,&_lock); _retval = toPy(pdataMaxDiff(a,b)); _args.check(); }
+ pbFinalizePlugin(parent,"pdataMaxDiff", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("pdataMaxDiff",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_pdataMaxDiff ("","pdataMaxDiff",_W_14);
+extern "C" {
+ void PbRegister_pdataMaxDiff() {
+ KEEP_UNUSED(_RP_pdataMaxDiff); }
+ }
+
+
+
+
+//! calculate center of mass given density grid, for re-centering
+
+Vec3 calcCenterOfMass(const Grid<Real>& density) {
+ Vec3 p(0.0f);
+ Real w = 0.0f;
+ FOR_IJK(density){
+ p += density(i, j, k) * Vec3(i + 0.5f, j + 0.5f, k + 0.5f);
+ w += density(i, j, k);
+ }
+ if (w > 1e-6f)
+ p /= w;
+ return p;
+} static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "calcCenterOfMass" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",0,&_lock); _retval = toPy(calcCenterOfMass(density)); _args.check(); }
+ pbFinalizePlugin(parent,"calcCenterOfMass", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("calcCenterOfMass",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_calcCenterOfMass ("","calcCenterOfMass",_W_15);
+extern "C" {
+ void PbRegister_calcCenterOfMass() {
+ KEEP_UNUSED(_RP_calcCenterOfMass); }
+ }
+
+
+
+
+//*****************************************************************************
+// helper functions for volume fractions (which are needed for second order obstacle boundaries)
+
+
+
+inline static Real calcFraction(Real phi1, Real phi2)
+{
+ if(phi1>0. && phi2>0.) return 1.;
+ if(phi1<0. && phi2<0.) return 0.;
+
+ // make sure phi1 < phi2
+ if (phi2<phi1) { Real t = phi1; phi1= phi2; phi2 = t; }
+ Real denom = phi1-phi2;
+ if (denom > -1e-04) return 0.5;
+
+ Real frac = 1. - phi1/denom;
+ if(frac<0.01) frac = 0.; // stomp small values , dont mark as fluid
+ return std::min(Real(1), frac );
+}
+
+
+ struct KnUpdateFractions : public KernelBase {
+ KnUpdateFractions(const FlagGrid& flags, const Grid<Real>& phiObs, MACGrid& fractions, const int &boundaryWidth) : KernelBase(&flags,1) ,flags(flags),phiObs(phiObs),fractions(fractions),boundaryWidth(boundaryWidth) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const Grid<Real>& phiObs, MACGrid& fractions, const int &boundaryWidth ) {
+
+ // walls at domain bounds and inner objects
+ fractions(i,j,k).x = calcFraction( phiObs(i,j,k) , phiObs(i-1,j,k));
+ fractions(i,j,k).y = calcFraction( phiObs(i,j,k) , phiObs(i,j-1,k));
+ if(phiObs.is3D()) {
+ fractions(i,j,k).z = calcFraction( phiObs(i,j,k) , phiObs(i,j,k-1));
+ }
+
+ // remaining BCs at the domain boundaries
+ const int w = boundaryWidth;
+ // only set if not in obstacle
+ if(phiObs(i,j,k)<0.) return;
+
+ // x-direction boundaries
+ if(i <= w+1) { //min x
+ if( (flags.isInflow(i-1,j,k)) ||
+ (flags.isOutflow(i-1,j,k)) ||
+ (flags.isOpen(i-1,j,k)) ) {
+ fractions(i,j,k).x = fractions(i,j,k).y = 1.; if(flags.is3D()) fractions(i,j,k).z = 1.;
+ }
+ }
+ if(i >= flags.getSizeX()-w-2) { //max x
+ if( (flags.isInflow(i+1,j,k)) ||
+ (flags.isOutflow(i+1,j,k)) ||
+ (flags.isOpen(i+1,j,k)) ) {
+ fractions(i+1,j,k).x = fractions(i+1,j,k).y = 1.; if(flags.is3D()) fractions(i+1,j,k).z = 1.;
+ }
+ }
+ // y-direction boundaries
+ if(j <= w+1) { //min y
+ if( (flags.isInflow(i,j-1,k)) ||
+ (flags.isOutflow(i,j-1,k)) ||
+ (flags.isOpen(i,j-1,k)) ) {
+ fractions(i,j,k).x = fractions(i,j,k).y = 1.; if(flags.is3D()) fractions(i,j,k).z = 1.;
+ }
+ }
+ if(j >= flags.getSizeY()-w-2) { //max y
+ if( (flags.isInflow(i,j+1,k)) ||
+ (flags.isOutflow(i,j+1,k)) ||
+ (flags.isOpen(i,j+1,k)) ) {
+ fractions(i,j+1,k).x = fractions(i,j+1,k).y = 1.; if(flags.is3D()) fractions(i,j+1,k).z = 1.;
+ }
+ }
+ // z-direction boundaries
+ if(flags.is3D()) {
+ if(k <= w+1) { //min z
+ if( (flags.isInflow(i,j,k-1)) ||
+ (flags.isOutflow(i,j,k-1)) ||
+ (flags.isOpen(i,j,k-1)) ) {
+ fractions(i,j,k).x = fractions(i,j,k).y = 1.; if(flags.is3D()) fractions(i,j,k).z = 1.;
+ }
+ }
+ if(j >= flags.getSizeZ()-w-2) { //max z
+ if( (flags.isInflow(i,j,k+1)) ||
+ (flags.isOutflow(i,j,k+1)) ||
+ (flags.isOpen(i,j,k+1)) ) {
+ fractions(i,j,k+1).x = fractions(i,j,k+1).y = 1.; if(flags.is3D()) fractions(i,j,k+1).z = 1.;
+ }
+ }
+ }
+
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const Grid<Real>& getArg1() {
+ return phiObs; }
+ typedef Grid<Real> type1;inline MACGrid& getArg2() {
+ return fractions; }
+ typedef MACGrid type2;inline const int& getArg3() {
+ return boundaryWidth; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel KnUpdateFractions ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,phiObs,fractions,boundaryWidth); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,phiObs,fractions,boundaryWidth); }
+ }
+ }
+ const FlagGrid& flags; const Grid<Real>& phiObs; MACGrid& fractions; const int& boundaryWidth; }
+;
+
+//! update fill fraction values
+void updateFractions(const FlagGrid& flags, const Grid<Real>& phiObs, MACGrid& fractions, const int &boundaryWidth=0) {
+ fractions.setConst( Vec3(0.) );
+ KnUpdateFractions(flags, phiObs, fractions, boundaryWidth);
+} static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "updateFractions" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const Grid<Real>& phiObs = *_args.getPtr<Grid<Real> >("phiObs",1,&_lock); MACGrid& fractions = *_args.getPtr<MACGrid >("fractions",2,&_lock); const int& boundaryWidth = _args.getOpt<int >("boundaryWidth",3,0,&_lock); _retval = getPyNone(); updateFractions(flags,phiObs,fractions,boundaryWidth); _args.check(); }
+ pbFinalizePlugin(parent,"updateFractions", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("updateFractions",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_updateFractions ("","updateFractions",_W_16);
+extern "C" {
+ void PbRegister_updateFractions() {
+ KEEP_UNUSED(_RP_updateFractions); }
+ }
+
+
+
+
+ struct KnUpdateFlagsObs : public KernelBase {
+ KnUpdateFlagsObs(FlagGrid& flags, const MACGrid* fractions, const Grid<Real>& phiObs, const Grid<Real>* phiOut, const Grid<Real>* phiIn) : KernelBase(&flags,1) ,flags(flags),fractions(fractions),phiObs(phiObs),phiOut(phiOut),phiIn(phiIn) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, FlagGrid& flags, const MACGrid* fractions, const Grid<Real>& phiObs, const Grid<Real>* phiOut, const Grid<Real>* phiIn ) {
+
+ bool isObs = false;
+ if(fractions) {
+ Real f = 0.;
+ f += fractions->get(i ,j,k).x;
+ f += fractions->get(i+1,j,k).x;
+ f += fractions->get(i,j ,k).y;
+ f += fractions->get(i,j+1,k).y;
+ if (flags.is3D()) {
+ f += fractions->get(i,j,k ).z;
+ f += fractions->get(i,j,k+1).z; }
+ if(f==0.) isObs = true;
+ } else {
+ if(phiObs(i,j,k) < 0.) isObs = true;
+ }
+
+ bool isOutflow = false;
+ bool isInflow = false;
+ if (phiOut && (*phiOut)(i,j,k) < 0.) isOutflow = true;
+ if (phiIn && (*phiIn)(i,j,k) < 0.) isInflow = true;
+
+ if (isObs) flags(i,j,k) = FlagGrid::TypeObstacle;
+ else if (isInflow) flags(i,j,k) = (FlagGrid::TypeFluid | FlagGrid::TypeInflow);
+ else if (isOutflow) flags(i,j,k) = (FlagGrid::TypeEmpty | FlagGrid::TypeOutflow);
+ else flags(i,j,k) = FlagGrid::TypeEmpty;
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid* getArg1() {
+ return fractions; }
+ typedef MACGrid type1;inline const Grid<Real>& getArg2() {
+ return phiObs; }
+ typedef Grid<Real> type2;inline const Grid<Real>* getArg3() {
+ return phiOut; }
+ typedef Grid<Real> type3;inline const Grid<Real>* getArg4() {
+ return phiIn; }
+ typedef Grid<Real> type4; void runMessage() { debMsg("Executing kernel KnUpdateFlagsObs ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,fractions,phiObs,phiOut,phiIn); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,fractions,phiObs,phiOut,phiIn); }
+ }
+ }
+ FlagGrid& flags; const MACGrid* fractions; const Grid<Real>& phiObs; const Grid<Real>* phiOut; const Grid<Real>* phiIn; }
+;
+
+//! update obstacle and outflow flags from levelsets
+//! optionally uses fill fractions for obstacle
+void setObstacleFlags(FlagGrid& flags, const Grid<Real>& phiObs, const MACGrid* fractions=NULL, const Grid<Real>* phiOut=NULL, const Grid<Real>* phiIn=NULL) {
+ KnUpdateFlagsObs(flags, fractions, phiObs, phiOut, phiIn);
+} static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setObstacleFlags" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const Grid<Real>& phiObs = *_args.getPtr<Grid<Real> >("phiObs",1,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",2,NULL,&_lock); const Grid<Real>* phiOut = _args.getPtrOpt<Grid<Real> >("phiOut",3,NULL,&_lock); const Grid<Real>* phiIn = _args.getPtrOpt<Grid<Real> >("phiIn",4,NULL,&_lock); _retval = getPyNone(); setObstacleFlags(flags,phiObs,fractions,phiOut,phiIn); _args.check(); }
+ pbFinalizePlugin(parent,"setObstacleFlags", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setObstacleFlags",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setObstacleFlags ("","setObstacleFlags",_W_17);
+extern "C" {
+ void PbRegister_setObstacleFlags() {
+ KEEP_UNUSED(_RP_setObstacleFlags); }
+ }
+
+
+
+
+//! small helper for test case test_1040_secOrderBnd.py
+ struct kninitVortexVelocity : public KernelBase {
+ kninitVortexVelocity(const Grid<Real> &phiObs, MACGrid& vel, const Vec3 &center, const Real &radius) : KernelBase(&phiObs,0) ,phiObs(phiObs),vel(vel),center(center),radius(radius) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Real> &phiObs, MACGrid& vel, const Vec3 &center, const Real &radius ) {
+
+ if(phiObs(i,j,k) >= -1.) {
+
+ Real dx = i - center.x; if(dx>=0) dx -= .5; else dx += .5;
+ Real dy = j - center.y;
+ Real r = std::sqrt(dx*dx+dy*dy);
+ Real alpha = atan2(dy,dx);
+
+ vel(i,j,k).x = -std::sin(alpha)*(r/radius);
+
+ dx = i - center.x;
+ dy = j - center.y; if(dy>=0) dy -= .5; else dy += .5;
+ r = std::sqrt(dx*dx+dy*dy);
+ alpha = atan2(dy,dx);
+
+ vel(i,j,k).y = std::cos(alpha)*(r/radius);
+
+ }
+
+} inline const Grid<Real> & getArg0() {
+ return phiObs; }
+ typedef Grid<Real> type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const Vec3& getArg2() {
+ return center; }
+ typedef Vec3 type2;inline const Real& getArg3() {
+ return radius; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel kninitVortexVelocity ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,phiObs,vel,center,radius); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,phiObs,vel,center,radius); }
+ }
+ }
+ const Grid<Real> & phiObs; MACGrid& vel; const Vec3& center; const Real& radius; }
+;
+
+void initVortexVelocity(const Grid<Real> &phiObs, MACGrid& vel, const Vec3 &center, const Real &radius) {
+ kninitVortexVelocity(phiObs, vel, center, radius);
+} static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "initVortexVelocity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real> & phiObs = *_args.getPtr<Grid<Real> >("phiObs",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Vec3& center = _args.get<Vec3 >("center",2,&_lock); const Real& radius = _args.get<Real >("radius",3,&_lock); _retval = getPyNone(); initVortexVelocity(phiObs,vel,center,radius); _args.check(); }
+ pbFinalizePlugin(parent,"initVortexVelocity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("initVortexVelocity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_initVortexVelocity ("","initVortexVelocity",_W_18);
+extern "C" {
+ void PbRegister_initVortexVelocity() {
+ KEEP_UNUSED(_RP_initVortexVelocity); }
+ }
+
+
+
+
+//*****************************************************************************
+// helper functions for blurring
+
+//! class for Gaussian Blur
+struct GaussianKernelCreator{
+public:
+
+ float mSigma;
+ int mDim;
+ float* mMat1D;
+
+ GaussianKernelCreator() : mSigma(0.0f), mDim(0), mMat1D(NULL) {}
+ GaussianKernelCreator(float sigma, int dim = 0)
+ : mSigma(0.0f), mDim(0), mMat1D(NULL) {
+ setGaussianSigma(sigma, dim);
+ }
+
+ Real getWeiAtDis(float disx, float disy){
+ float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma);
+ float v = m * exp(-(1.0*disx*disx + 1.0*disy*disy) / (2.0 * mSigma * mSigma));
+ return v;
+ }
+
+ Real getWeiAtDis(float disx, float disy, float disz){
+ float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma);
+ float v = m * exp(-(1.0*disx*disx + 1.0*disy*disy + 1.0*disz*disz) / (2.0 * mSigma * mSigma));
+ return v;
+ }
+
+ void setGaussianSigma(float sigma, int dim = 0){
+ mSigma = sigma;
+ if (dim < 3)
+ mDim = (int)(2.0 * 3.0 * sigma + 1.0f);
+ else
+ mDim = dim;
+ if (mDim < 3) mDim = 3;
+
+ if (mDim % 2 == 0) ++mDim;// make dim odd
+
+ float s2 = mSigma * mSigma;
+ int c = mDim / 2;
+ float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma);
+
+ // create 1D matrix
+ if (mMat1D) delete[] mMat1D;
+ mMat1D = new float[mDim];
+ for (int i = 0; i < (mDim + 1) / 2; i++){
+ float v = m * exp(-(1.0*i*i) / (2.0 * s2));
+ mMat1D[c + i] = v;
+ mMat1D[c - i] = v;
+ }
+ }
+
+ ~GaussianKernelCreator(){
+ if (mMat1D) delete[] mMat1D;
+ }
+
+ float get1DKernelValue(int off){
+ assertMsg(off >= 0 && off < mDim, "off exceeded boundary in Gaussian Kernel 1D!");
+ return mMat1D[off];
+ }
+
+};
+
+template<class T>
+T convolveGrid(Grid<T>& originGrid, GaussianKernelCreator& gkSigma, Vec3 pos, int cdir){
+ // pos should be the centre pos, e.g., 1.5, 4.5, 0.5 for grid pos 1,4,0
+ Vec3 step(1.0, 0.0, 0.0);
+ if (cdir == 1)// todo, z
+ step = Vec3(0.0, 1.0, 0.0);
+ else if (cdir == 2)
+ step = Vec3(0.0, 0.0, 1.0);
+ T pxResult(0);
+ for (int i = 0; i < gkSigma.mDim; ++i){
+ Vec3i curpos = toVec3i(pos - step*(i - gkSigma.mDim / 2));
+ if (originGrid.isInBounds(curpos))
+ pxResult += gkSigma.get1DKernelValue(i) * originGrid.get(curpos);
+ else{ // TODO , improve...
+ Vec3i curfitpos = curpos;
+ if (curfitpos.x < 0) curfitpos.x = 0;
+ else if (curfitpos.x >= originGrid.getSizeX()) curfitpos.x = originGrid.getSizeX() - 1;
+ if (curfitpos.y < 0) curfitpos.y = 0;
+ else if (curfitpos.y >= originGrid.getSizeY()) curfitpos.y = originGrid.getSizeY() - 1;
+ if (curfitpos.z < 0) curfitpos.z = 0;
+ else if (curfitpos.z >= originGrid.getSizeZ()) curfitpos.z = originGrid.getSizeZ() - 1;
+ pxResult += gkSigma.get1DKernelValue(i) * originGrid.get(curfitpos);
+ }
+ }
+ return pxResult;
+}
+
+
+template <class T> struct knBlurGrid : public KernelBase {
+ knBlurGrid(Grid<T>& originGrid, Grid<T>& targetGrid, GaussianKernelCreator& gkSigma, int cdir) : KernelBase(&originGrid,0) ,originGrid(originGrid),targetGrid(targetGrid),gkSigma(gkSigma),cdir(cdir) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>& originGrid, Grid<T>& targetGrid, GaussianKernelCreator& gkSigma, int cdir ) {
+ targetGrid(i, j, k) = convolveGrid<T>(originGrid, gkSigma, Vec3(i, j, k), cdir);
+} inline Grid<T>& getArg0() {
+ return originGrid; }
+ typedef Grid<T> type0;inline Grid<T>& getArg1() {
+ return targetGrid; }
+ typedef Grid<T> type1;inline GaussianKernelCreator& getArg2() {
+ return gkSigma; }
+ typedef GaussianKernelCreator type2;inline int& getArg3() {
+ return cdir; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel knBlurGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,originGrid,targetGrid,gkSigma,cdir); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,originGrid,targetGrid,gkSigma,cdir); }
+ }
+ }
+ Grid<T>& originGrid; Grid<T>& targetGrid; GaussianKernelCreator& gkSigma; int cdir; }
+;
+
+template<class T>
+int blurGrid(Grid<T>& originGrid, Grid<T>& targetGrid, float sigma){
+ GaussianKernelCreator tmGK(sigma);
+ Grid<T> tmpGrid(originGrid);
+ knBlurGrid<T>(originGrid, tmpGrid, tmGK, 0); //blur x
+ knBlurGrid<T>(tmpGrid, targetGrid, tmGK, 1); //blur y
+ if (targetGrid.is3D()){
+ tmpGrid.copyFrom(targetGrid);
+ knBlurGrid<T>(tmpGrid, targetGrid, tmGK, 2);
+ }
+ return tmGK.mDim;
+}
+
+
+
+ struct KnBlurMACGridGauss : public KernelBase {
+ KnBlurMACGridGauss(MACGrid& originGrid, MACGrid& target, GaussianKernelCreator& gkSigma, int cdir) : KernelBase(&originGrid,0) ,originGrid(originGrid),target(target),gkSigma(gkSigma),cdir(cdir) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& originGrid, MACGrid& target, GaussianKernelCreator& gkSigma, int cdir ) {
+ Vec3 pos(i, j, k);
+ Vec3 step(1.0, 0.0, 0.0);
+ if (cdir == 1)
+ step = Vec3(0.0, 1.0, 0.0);
+ else if (cdir == 2)
+ step = Vec3(0.0, 0.0, 1.0);
+
+ Vec3 pxResult(0.0f);
+ for (int di = 0; di < gkSigma.mDim; ++di){
+ Vec3i curpos = toVec3i(pos - step*(di - gkSigma.mDim / 2));
+ if (!originGrid.isInBounds(curpos)){
+ if (curpos.x < 0) curpos.x = 0;
+ else if (curpos.x >= originGrid.getSizeX()) curpos.x = originGrid.getSizeX() - 1;
+ if (curpos.y < 0) curpos.y = 0;
+ else if (curpos.y >= originGrid.getSizeY()) curpos.y = originGrid.getSizeY() - 1;
+ if (curpos.z < 0) curpos.z = 0;
+ else if (curpos.z >= originGrid.getSizeZ()) curpos.z = originGrid.getSizeZ() - 1;
+ }
+ pxResult += gkSigma.get1DKernelValue(di) * originGrid.get(curpos);
+ }
+ target(i,j,k) = pxResult;
+} inline MACGrid& getArg0() {
+ return originGrid; }
+ typedef MACGrid type0;inline MACGrid& getArg1() {
+ return target; }
+ typedef MACGrid type1;inline GaussianKernelCreator& getArg2() {
+ return gkSigma; }
+ typedef GaussianKernelCreator type2;inline int& getArg3() {
+ return cdir; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel KnBlurMACGridGauss ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,originGrid,target,gkSigma,cdir); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,originGrid,target,gkSigma,cdir); }
+ }
+ }
+ MACGrid& originGrid; MACGrid& target; GaussianKernelCreator& gkSigma; int cdir; }
+;
+
+int blurMacGrid(MACGrid& oG, MACGrid& tG, float si){
+ GaussianKernelCreator tmGK(si);
+ MACGrid tmpGrid(oG);
+ KnBlurMACGridGauss(oG, tmpGrid, tmGK, 0); //blur x
+ KnBlurMACGridGauss(tmpGrid, tG, tmGK, 1); //blur y
+ if (tG.is3D()){
+ tmpGrid.copyFrom(tG);
+ KnBlurMACGridGauss(tmpGrid, tG, tmGK, 2);
+ }
+ return tmGK.mDim;
+} static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "blurMacGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& oG = *_args.getPtr<MACGrid >("oG",0,&_lock); MACGrid& tG = *_args.getPtr<MACGrid >("tG",1,&_lock); float si = _args.get<float >("si",2,&_lock); _retval = toPy(blurMacGrid(oG,tG,si)); _args.check(); }
+ pbFinalizePlugin(parent,"blurMacGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("blurMacGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_blurMacGrid ("","blurMacGrid",_W_19);
+extern "C" {
+ void PbRegister_blurMacGrid() {
+ KEEP_UNUSED(_RP_blurMacGrid); }
+ }
+
+
+
+int blurRealGrid(Grid<Real>& oG, Grid<Real>& tG, float si){
+ return blurGrid<Real> (oG, tG, si);
+} static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "blurRealGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& oG = *_args.getPtr<Grid<Real> >("oG",0,&_lock); Grid<Real>& tG = *_args.getPtr<Grid<Real> >("tG",1,&_lock); float si = _args.get<float >("si",2,&_lock); _retval = toPy(blurRealGrid(oG,tG,si)); _args.check(); }
+ pbFinalizePlugin(parent,"blurRealGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("blurRealGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_blurRealGrid ("","blurRealGrid",_W_20);
+extern "C" {
+ void PbRegister_blurRealGrid() {
+ KEEP_UNUSED(_RP_blurRealGrid); }
+ }
+
+
+
+} // namespace
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/kepsilon.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/kepsilon.cpp
new file mode 100644
index 00000000000..fd594284c47
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/kepsilon.cpp
@@ -0,0 +1,334 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Turbulence modeling plugins
+ *
+ ******************************************************************************/
+
+#include "grid.h"
+#include "commonkernels.h"
+#include "vortexsheet.h"
+#include "conjugategrad.h"
+
+using namespace std;
+
+namespace Manta {
+
+// k-epsilon model constants
+const Real keCmu = 0.09;
+const Real keC1 = 1.44;
+const Real keC2 = 1.92;
+const Real keS1 = 1.0;
+const Real keS2 = 1.3;
+
+// k-epsilon limiters
+const Real keU0 = 1.0;
+const Real keImin = 2e-3;
+const Real keImax = 1.0;
+const Real keNuMin = 1e-3;
+const Real keNuMax = 5.0;
+
+//! clamp k and epsilon to limits
+
+ struct KnTurbulenceClamp : public KernelBase {
+ KnTurbulenceClamp(Grid<Real>& kgrid, Grid<Real>& egrid, Real minK, Real maxK, Real minNu, Real maxNu) : KernelBase(&kgrid,0) ,kgrid(kgrid),egrid(egrid),minK(minK),maxK(maxK),minNu(minNu),maxNu(maxNu) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& kgrid, Grid<Real>& egrid, Real minK, Real maxK, Real minNu, Real maxNu ) {
+ Real eps = egrid[idx];
+ Real ke = clamp(kgrid[idx],minK,maxK);
+ Real nu = keCmu*square(ke)/eps;
+ if (nu > maxNu)
+ eps = keCmu*square(ke)/maxNu;
+ if (nu < minNu)
+ eps = keCmu*square(ke)/minNu;
+
+ kgrid[idx] = ke;
+ egrid[idx] = eps;
+} inline Grid<Real>& getArg0() {
+ return kgrid; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return egrid; }
+ typedef Grid<Real> type1;inline Real& getArg2() {
+ return minK; }
+ typedef Real type2;inline Real& getArg3() {
+ return maxK; }
+ typedef Real type3;inline Real& getArg4() {
+ return minNu; }
+ typedef Real type4;inline Real& getArg5() {
+ return maxNu; }
+ typedef Real type5; void runMessage() { debMsg("Executing kernel KnTurbulenceClamp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,kgrid,egrid,minK,maxK,minNu,maxNu); }
+ }
+ Grid<Real>& kgrid; Grid<Real>& egrid; Real minK; Real maxK; Real minNu; Real maxNu; }
+;
+
+//! Compute k-epsilon production term P = 2*nu_T*sum_ij(Sij^2) and the turbulent viscosity nu_T=C_mu*k^2/eps
+
+
+
+ struct KnComputeProduction : public KernelBase {
+ KnComputeProduction(const MACGrid& vel, const Grid<Vec3>& velCenter, const Grid<Real>& ke, const Grid<Real>& eps, Grid<Real>& prod, Grid<Real>& nuT, Grid<Real>* strain, Real pscale = 1.0f) : KernelBase(&vel,1) ,vel(vel),velCenter(velCenter),ke(ke),eps(eps),prod(prod),nuT(nuT),strain(strain),pscale(pscale) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid& vel, const Grid<Vec3>& velCenter, const Grid<Real>& ke, const Grid<Real>& eps, Grid<Real>& prod, Grid<Real>& nuT, Grid<Real>* strain, Real pscale = 1.0f ) {
+ Real curEps = eps(i,j,k);
+ if (curEps > 0) {
+ // turbulent viscosity: nu_T = C_mu * k^2/eps
+ Real curNu = keCmu * square(ke(i,j,k)) / curEps;
+
+ // compute Sij = 1/2 * (dU_i/dx_j + dU_j/dx_i)
+ Vec3 diag = Vec3(vel(i+1,j,k).x, vel(i,j+1,k).y, vel(i,j,k+1).z) - vel(i,j,k);
+ Vec3 ux = 0.5*(velCenter(i+1,j,k)-velCenter(i-1,j,k));
+ Vec3 uy = 0.5*(velCenter(i,j+1,k)-velCenter(i,j-1,k));
+ Vec3 uz = 0.5*(velCenter(i,j,k+1)-velCenter(i,j,k-1));
+ Real S12 = 0.5*(ux.y+uy.x);
+ Real S13 = 0.5*(ux.z+uz.x);
+ Real S23 = 0.5*(uy.z+uz.y);
+ Real S2 = square(diag.x) + square(diag.y) + square(diag.z) +
+ 2.0*square(S12) + 2.0*square(S13) + 2.0*square(S23);
+
+ // P = 2*nu_T*sum_ij(Sij^2)
+ prod(i,j,k) = 2.0 * curNu * S2 * pscale;
+ nuT(i,j,k) = curNu;
+ if (strain) (*strain)(i,j,k) = sqrt(S2);
+ }
+ else {
+ prod(i,j,k) = 0;
+ nuT(i,j,k) = 0;
+ if (strain) (*strain)(i,j,k) = 0;
+ }
+} inline const MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const Grid<Vec3>& getArg1() {
+ return velCenter; }
+ typedef Grid<Vec3> type1;inline const Grid<Real>& getArg2() {
+ return ke; }
+ typedef Grid<Real> type2;inline const Grid<Real>& getArg3() {
+ return eps; }
+ typedef Grid<Real> type3;inline Grid<Real>& getArg4() {
+ return prod; }
+ typedef Grid<Real> type4;inline Grid<Real>& getArg5() {
+ return nuT; }
+ typedef Grid<Real> type5;inline Grid<Real>* getArg6() {
+ return strain; }
+ typedef Grid<Real> type6;inline Real& getArg7() {
+ return pscale; }
+ typedef Real type7; void runMessage() { debMsg("Executing kernel KnComputeProduction ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,velCenter,ke,eps,prod,nuT,strain,pscale); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,velCenter,ke,eps,prod,nuT,strain,pscale); }
+ }
+ }
+ const MACGrid& vel; const Grid<Vec3>& velCenter; const Grid<Real>& ke; const Grid<Real>& eps; Grid<Real>& prod; Grid<Real>& nuT; Grid<Real>* strain; Real pscale; }
+;
+
+//! Compute k-epsilon production term P = 2*nu_T*sum_ij(Sij^2) and the turbulent viscosity nu_T=C_mu*k^2/eps
+
+void KEpsilonComputeProduction(const MACGrid& vel, Grid<Real>& k, Grid<Real>& eps, Grid<Real>& prod, Grid<Real>& nuT, Grid<Real>* strain=0, Real pscale = 1.0f) {
+ // get centered velocity grid
+ Grid<Vec3> vcenter(k.getParent());
+ GetCentered(vcenter, vel);
+ FillInBoundary(vcenter,1);
+
+ // compute limits
+ const Real minK = 1.5*square(keU0)*square(keImin);
+ const Real maxK = 1.5*square(keU0)*square(keImax);
+ KnTurbulenceClamp(k, eps, minK, maxK, keNuMin, keNuMax);
+
+ KnComputeProduction(vel, vcenter, k, eps, prod, nuT, strain, pscale);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "KEpsilonComputeProduction" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Real>& k = *_args.getPtr<Grid<Real> >("k",1,&_lock); Grid<Real>& eps = *_args.getPtr<Grid<Real> >("eps",2,&_lock); Grid<Real>& prod = *_args.getPtr<Grid<Real> >("prod",3,&_lock); Grid<Real>& nuT = *_args.getPtr<Grid<Real> >("nuT",4,&_lock); Grid<Real>* strain = _args.getPtrOpt<Grid<Real> >("strain",5,0,&_lock); Real pscale = _args.getOpt<Real >("pscale",6,1.0f,&_lock); _retval = getPyNone(); KEpsilonComputeProduction(vel,k,eps,prod,nuT,strain,pscale); _args.check(); }
+ pbFinalizePlugin(parent,"KEpsilonComputeProduction", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("KEpsilonComputeProduction",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_KEpsilonComputeProduction ("","KEpsilonComputeProduction",_W_0);
+extern "C" {
+ void PbRegister_KEpsilonComputeProduction() {
+ KEEP_UNUSED(_RP_KEpsilonComputeProduction); }
+ }
+
+
+
+//! Integrate source terms of k-epsilon equation
+
+ struct KnAddTurbulenceSource : public KernelBase {
+ KnAddTurbulenceSource(Grid<Real>& kgrid, Grid<Real>& egrid, const Grid<Real>& pgrid, Real dt) : KernelBase(&kgrid,0) ,kgrid(kgrid),egrid(egrid),pgrid(pgrid),dt(dt) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& kgrid, Grid<Real>& egrid, const Grid<Real>& pgrid, Real dt ) {
+ Real eps = egrid[idx], prod = pgrid[idx], ke = kgrid[idx];
+ if (ke <= 0) ke = 1e-3; // pre-clamp to avoid nan
+
+ Real newK = ke + dt*(prod - eps);
+ Real newEps = eps + dt*(prod * keC1 - eps * keC2) * (eps / ke);
+ if (newEps <= 0) newEps = 1e-4; // pre-clamp to avoid nan
+
+ kgrid[idx] = newK;
+ egrid[idx] = newEps;
+} inline Grid<Real>& getArg0() {
+ return kgrid; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return egrid; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return pgrid; }
+ typedef Grid<Real> type2;inline Real& getArg3() {
+ return dt; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel KnAddTurbulenceSource ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,kgrid,egrid,pgrid,dt); }
+ }
+ Grid<Real>& kgrid; Grid<Real>& egrid; const Grid<Real>& pgrid; Real dt; }
+;
+
+
+//! Integrate source terms of k-epsilon equation
+void KEpsilonSources(Grid<Real>& k, Grid<Real>& eps, Grid<Real>& prod) {
+ Real dt = k.getParent()->getDt();
+
+ KnAddTurbulenceSource(k, eps, prod, dt);
+
+ // compute limits
+ const Real minK = 1.5*square(keU0)*square(keImin);
+ const Real maxK = 1.5*square(keU0)*square(keImax);
+ KnTurbulenceClamp(k, eps, minK, maxK, keNuMin, keNuMax);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "KEpsilonSources" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& k = *_args.getPtr<Grid<Real> >("k",0,&_lock); Grid<Real>& eps = *_args.getPtr<Grid<Real> >("eps",1,&_lock); Grid<Real>& prod = *_args.getPtr<Grid<Real> >("prod",2,&_lock); _retval = getPyNone(); KEpsilonSources(k,eps,prod); _args.check(); }
+ pbFinalizePlugin(parent,"KEpsilonSources", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("KEpsilonSources",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_KEpsilonSources ("","KEpsilonSources",_W_1);
+extern "C" {
+ void PbRegister_KEpsilonSources() {
+ KEEP_UNUSED(_RP_KEpsilonSources); }
+ }
+
+
+
+//! Initialize the domain or boundary conditions
+void KEpsilonBcs(const FlagGrid& flags, Grid<Real>& k, Grid<Real>& eps, Real intensity, Real nu, bool fillArea) {
+ // compute limits
+ const Real vk = 1.5*square(keU0)*square(intensity);
+ const Real ve = keCmu*square(vk) / nu;
+
+ FOR_IDX(k) {
+ if (fillArea || flags.isObstacle(idx)) {
+ k[idx] = vk;
+ eps[idx] = ve;
+ }
+ }
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "KEpsilonBcs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& k = *_args.getPtr<Grid<Real> >("k",1,&_lock); Grid<Real>& eps = *_args.getPtr<Grid<Real> >("eps",2,&_lock); Real intensity = _args.get<Real >("intensity",3,&_lock); Real nu = _args.get<Real >("nu",4,&_lock); bool fillArea = _args.get<bool >("fillArea",5,&_lock); _retval = getPyNone(); KEpsilonBcs(flags,k,eps,intensity,nu,fillArea); _args.check(); }
+ pbFinalizePlugin(parent,"KEpsilonBcs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("KEpsilonBcs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_KEpsilonBcs ("","KEpsilonBcs",_W_2);
+extern "C" {
+ void PbRegister_KEpsilonBcs() {
+ KEEP_UNUSED(_RP_KEpsilonBcs); }
+ }
+
+
+
+//! Gradient diffusion smoothing. Not unconditionally stable -- should probably do substepping etc.
+void ApplyGradDiff(const Grid<Real>& grid, Grid<Real>& res, const Grid<Real>& nu, Real dt, Real sigma) {
+ // should do this (but requires better boundary handling)
+ /*MACGrid grad(grid.getParent());
+ GradientOpMAC(grad, grid);
+ grad *= nu;
+ DivergenceOpMAC(res, grad);
+ res *= dt/sigma; */
+
+ LaplaceOp(res, grid);
+ res *= nu;
+ res *= dt/sigma;
+}
+
+//! Compute k-epsilon turbulent viscosity
+void KEpsilonGradientDiffusion(Grid<Real>& k, Grid<Real>& eps, Grid<Real>& nuT, Real sigmaU=4.0, MACGrid* vel=0) {
+ Real dt = k.getParent()->getDt();
+ Grid<Real> res(k.getParent());
+
+ // gradient diffusion of k
+ ApplyGradDiff(k, res, nuT, dt, keS1);
+ k += res;
+
+ // gradient diffusion of epsilon
+ ApplyGradDiff(eps, res, nuT, dt, keS2);
+ eps += res;
+
+ // gradient diffusion of velocity
+ if (vel) {
+ Grid<Real> vc(k.getParent());
+ for (int c=0; c<3; c++) {
+ GetComponent(*vel, vc, c);
+ ApplyGradDiff(vc, res, nuT, dt, sigmaU);
+ vc += res;
+ SetComponent(*vel, vc, c);
+ }
+ }
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "KEpsilonGradientDiffusion" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& k = *_args.getPtr<Grid<Real> >("k",0,&_lock); Grid<Real>& eps = *_args.getPtr<Grid<Real> >("eps",1,&_lock); Grid<Real>& nuT = *_args.getPtr<Grid<Real> >("nuT",2,&_lock); Real sigmaU = _args.getOpt<Real >("sigmaU",3,4.0,&_lock); MACGrid* vel = _args.getPtrOpt<MACGrid >("vel",4,0,&_lock); _retval = getPyNone(); KEpsilonGradientDiffusion(k,eps,nuT,sigmaU,vel); _args.check(); }
+ pbFinalizePlugin(parent,"KEpsilonGradientDiffusion", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("KEpsilonGradientDiffusion",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_KEpsilonGradientDiffusion ("","KEpsilonGradientDiffusion",_W_3);
+extern "C" {
+ void PbRegister_KEpsilonGradientDiffusion() {
+ KEEP_UNUSED(_RP_KEpsilonGradientDiffusion); }
+ }
+
+
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/meshplugins.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/meshplugins.cpp
new file mode 100644
index 00000000000..f6109cefe90
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/meshplugins.cpp
@@ -0,0 +1,678 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Smoothing etc. for meshes
+ *
+ ******************************************************************************/
+
+/******************************************************************************/
+// Copyright note:
+//
+// These functions (C) Chris Wojtan
+// Long-term goal is to unify with his split&merge codebase
+//
+/******************************************************************************/
+
+#include <queue>
+#include <algorithm>
+#include "mesh.h"
+#include "kernel.h"
+#include "edgecollapse.h"
+#include <mesh.h>
+#include <stack>
+
+using namespace std;
+
+namespace Manta {
+
+//! Mesh smoothing
+/*! see Desbrun 99 "Implicit fairing of of irregular meshes using diffusion and curvature flow"*/
+void smoothMesh(Mesh& mesh, Real strength, int steps = 1, Real minLength=1e-5) {
+ const Real dt = mesh.getParent()->getDt();
+ const Real str = min(dt * strength, (Real)1);
+ mesh.rebuildQuickCheck();
+
+ // calculate original mesh volume
+ Vec3 origCM;
+ Real origVolume = mesh.computeCenterOfMass(origCM);
+
+ // temp vertices
+ const int numCorners = mesh.numTris() * 3;
+ const int numNodes= mesh.numNodes();
+ vector<Vec3> temp(numNodes);
+ vector<bool> visited(numNodes);
+
+ for (int s = 0; s<steps; s++) {
+ // reset markers
+ for(size_t i=0; i<visited.size(); i++) visited[i] = false;
+
+ for (int c = 0; c < numCorners; c++) {
+ const int node = mesh.corners(c).node;
+ if (visited[node]) continue;
+
+ const Vec3 pos = mesh.nodes(node).pos;
+ Vec3 dx(0.0);
+ Real totalLen = 0;
+
+ // rotate around vertex
+ set<int>& ring = mesh.get1Ring(node).nodes;
+ for(set<int>::iterator it=ring.begin(); it!=ring.end(); it++) {
+ Vec3 edge = mesh.nodes(*it).pos - pos;
+ Real len = norm(edge);
+
+ if (len > minLength) {
+ dx += edge * (1.0/len);
+ totalLen += len;
+ } else {
+ totalLen = 0.0;
+ break;
+ }
+ }
+ visited[node] = true;
+ temp[node] = pos;
+ if (totalLen != 0)
+ temp[node] += dx * (str / totalLen);
+ }
+
+ // copy back
+ for (int n=0; n<numNodes; n++)
+ if (!mesh.isNodeFixed(n))
+ mesh.nodes(n).pos = temp[n];
+ }
+
+ // calculate new mesh volume
+ Vec3 newCM;
+ Real newVolume = mesh.computeCenterOfMass(newCM);
+
+ // preserve volume : scale relative to CM
+ Real beta;
+#if defined(WIN32) || defined(_WIN32)
+ beta = pow( (Real)std::abs(origVolume/newVolume), (Real)(1./3.) );
+#else
+ beta = cbrt( origVolume/newVolume );
+# endif
+
+ for (int n=0; n<numNodes; n++)
+ if (!mesh.isNodeFixed(n))
+ mesh.nodes(n).pos = origCM + (mesh.nodes(n).pos - newCM) * beta;
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "smoothMesh" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); Real strength = _args.get<Real >("strength",1,&_lock); int steps = _args.getOpt<int >("steps",2,1,&_lock); Real minLength = _args.getOpt<Real >("minLength",3,1e-5,&_lock); _retval = getPyNone(); smoothMesh(mesh,strength,steps,minLength); _args.check(); }
+ pbFinalizePlugin(parent,"smoothMesh", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("smoothMesh",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_smoothMesh ("","smoothMesh",_W_0);
+extern "C" {
+ void PbRegister_smoothMesh() {
+ KEEP_UNUSED(_RP_smoothMesh); }
+ }
+
+
+
+//! Subdivide and edgecollapse to guarantee mesh with edgelengths between
+//! min/maxLength and an angle below minAngle
+void subdivideMesh(Mesh& mesh, Real minAngle, Real minLength, Real maxLength, bool cutTubes = false) {
+ // gather some statistics
+ int edgeSubdivs = 0, edgeCollsAngle = 0, edgeCollsLen = 0, edgeKill = 0;
+ mesh.rebuildQuickCheck();
+
+ vector<int> deletedNodes;
+ map<int,bool> taintedTris;
+ priority_queue<pair<Real,int> > pq;
+
+ //////////////////////////////////////////
+ // EDGE COLLAPSE //
+ // - particles marked for deletation //
+ //////////////////////////////////////////
+
+ for (int t=0; t<mesh.numTris(); t++) {
+ if(taintedTris.find(t)!=taintedTris.end())
+ continue;
+
+ // check if at least 2 nodes are marked for delete
+ bool k[3];
+ int numKill = 0;
+ for (int i=0; i<3; i++) {
+ k[i] = mesh.nodes(mesh.tris(t).c[i]).flags & Mesh::NfKillme;
+ if (k[i]) numKill++;
+ }
+ if (numKill<2) continue;
+
+ if (k[0] && k[1])
+ CollapseEdge(mesh, t, 2, mesh.getEdge(t,0), mesh.getNode(t,0), deletedNodes, taintedTris, edgeKill, cutTubes);
+ else if (k[1] && k[2])
+ CollapseEdge(mesh, t, 0, mesh.getEdge(t,1), mesh.getNode(t,1), deletedNodes, taintedTris, edgeKill, cutTubes);
+ else if (k[2] && k[0])
+ CollapseEdge(mesh, t, 1, mesh.getEdge(t,2), mesh.getNode(t,2), deletedNodes, taintedTris, edgeKill, cutTubes);
+ }
+
+ //////////////////////////////////////////
+ // EDGE COLLAPSING //
+ // - based on small triangle angle //
+ //////////////////////////////////////////
+
+ if (minAngle > 0) {
+ for(int t=0; t<mesh.numTris(); t++) {
+ // we only want to run through the edge list ONCE.
+ // we achieve this in a method very similar to the above subdivision method.
+
+ // if this triangle has already been deleted, ignore it
+ if(taintedTris.find(t)!=taintedTris.end())
+ continue;
+
+ // first we find the angles of this triangle
+ Vec3 e0 = mesh.getEdge(t,0), e1 = mesh.getEdge(t,1), e2 = mesh.getEdge(t,2);
+ Vec3 ne0 = e0;
+ Vec3 ne1 = e1;
+ Vec3 ne2 = e2;
+ normalize(ne0);
+ normalize(ne1);
+ normalize(ne2);
+
+ //Real thisArea = sqrMag(cross(-e2,e0));
+ // small angle approximation says sin(x) = arcsin(x) = x,
+ // arccos(x) = pi/2 - arcsin(x),
+ // cos(x) = dot(A,B),
+ // so angle is approximately 1 - dot(A,B).
+ Real angle[3];
+ angle[0] = 1.0-dot(ne0,-ne2);
+ angle[1] = 1.0-dot(ne1,-ne0);
+ angle[2] = 1.0-dot(ne2,-ne1);
+ Real worstAngle = angle[0];
+ int which = 0;
+ if(angle[1]<worstAngle) {
+ worstAngle = angle[1];
+ which = 1;
+ }
+ if(angle[2]<worstAngle) {
+ worstAngle = angle[2];
+ which = 2;
+ }
+
+ // then we see if the angle is too small
+ if(worstAngle<minAngle) {
+ Vec3 edgevect;
+ Vec3 endpoint;
+ switch(which) {
+ case 0:
+ endpoint = mesh.getNode(t,1);
+ edgevect = e1;
+ break;
+ case 1:
+ endpoint = mesh.getNode(t,2);
+ edgevect = e2;
+ break;
+ case 2:
+ endpoint = mesh.getNode(t,0);
+ edgevect = e0;
+ break;
+ default:
+ break;
+ }
+
+ CollapseEdge(mesh, t,which,edgevect,endpoint,deletedNodes,taintedTris, edgeCollsAngle, cutTubes);
+ }
+ }
+ }
+
+ //////////////////////
+ // EDGE SUBDIVISION //
+ //////////////////////
+
+ Real maxLength2 = maxLength*maxLength;
+ for (int t=0; t<mesh.numTris(); t++) {
+ // first we find the maximum length edge in this triangle
+ Vec3 e0 = mesh.getEdge(t,0), e1 = mesh.getEdge(t,1), e2 = mesh.getEdge(t,2);
+ Real d0 = normSquare(e0);
+ Real d1 = normSquare(e1);
+ Real d2 = normSquare(e2);
+
+ Real longest = max(d0,max(d1,d2));
+ if(longest > maxLength2) {
+ pq.push(pair<Real,int>(longest,t));
+ }
+ }
+ if (maxLength > 0) {
+
+ while(!pq.empty() && pq.top().first>maxLength2) {
+ // we only want to run through the edge list ONCE
+ // and we want to subdivide the original edges before we subdivide any newer, shorter edges,
+ // so whenever we subdivide, we add the 2 new triangles on the end of the SurfaceTri vector
+ // and mark the original subdivided triangles for deletion.
+ // when we are done subdividing, we delete the obsolete triangles
+
+ int triA = pq.top().second;
+ pq.pop();
+
+ if(taintedTris.find(triA)!=taintedTris.end())
+ continue;
+
+ // first we find the maximum length edge in this triangle
+ Vec3 e0 = mesh.getEdge(triA,0), e1 = mesh.getEdge(triA,1), e2 = mesh.getEdge(triA,2);
+ Real d0 = normSquare(e0);
+ Real d1 = normSquare(e1);
+ Real d2 = normSquare(e2);
+
+ Vec3 edgevect;
+ Vec3 endpoint;
+ int which;
+ if(d0>d1) {
+ if(d0>d2) {
+ edgevect = e0;
+ endpoint = mesh.getNode(triA, 0);;
+ which = 2; // 2 opposite of edge 0-1
+ } else {
+ edgevect = e2;
+ endpoint = mesh.getNode(triA, 2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ } else {
+ if(d1>d2) {
+ edgevect = e1;
+ endpoint = mesh.getNode(triA, 1);
+ which = 0; // 0 opposite of edge 1-2
+ } else {
+ edgevect = e2;
+ endpoint = mesh.getNode(triA, 2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ }
+ // This edge is too long, so we split it in the middle
+
+ // *
+ // / \.
+ // /C0 \.
+ // / \.
+ // / \.
+ // / B \.
+ // / \.
+ // /C1 C2 \.
+ // *---------------*
+ // \C2 C1 /
+ // \ /
+ // \ A /
+ // \ /
+ // \ /
+ // \C0 /
+ // \ /
+ // *
+ //
+ // BECOMES
+ //
+ // *
+ // /|\.
+ // / | \.
+ // /C0|C0\.
+ // / | \.
+ // / B1 | B2 \.
+ // / | \.
+ // /C1 C2|C1 C2 \.
+ // *-------*-------*
+ // \C2 C1|C2 C1/
+ // \ | /
+ // \ A2 | A1 /
+ // \ | /
+ // \C0|C0/
+ // \ | /
+ // \|/
+ // *
+
+ int triB = -1; bool haveB = false;
+ Corner ca_old[3],cb_old[3];
+ ca_old[0] = mesh.corners(triA, which);
+ ca_old[1] = mesh.corners(ca_old[0].next);
+ ca_old[2] = mesh.corners(ca_old[0].prev);
+ if (ca_old[0].opposite>=0) {
+ cb_old[0] = mesh.corners(ca_old[0].opposite);
+ cb_old[1] = mesh.corners(cb_old[0].next);
+ cb_old[2] = mesh.corners(cb_old[0].prev);
+ triB = cb_old[0].tri;
+ haveB = true;
+ }
+ //else throw Error("nonmanifold");
+
+ // subdivide in the middle of the edge and create new triangles
+ Node newNode;
+ newNode.flags = 0;
+
+ newNode.pos = endpoint + 0.5*edgevect; // fallback: linear average
+ // default: use butterfly
+ if (haveB)
+ newNode.pos = ModifiedButterflySubdivision(mesh, ca_old[0], cb_old[0], newNode.pos);
+
+ // find indices of two points of 'which'-edge
+ // merge flags
+ int P0 = ca_old[1].node;
+ int P1 = ca_old[2].node;
+ newNode.flags = mesh.nodes(P0).flags | mesh.nodes(P1).flags;
+
+ Real len0 = norm(mesh.nodes(P0).pos - newNode.pos);
+ Real len1 = norm(mesh.nodes(P1).pos - newNode.pos);
+
+ // remove P0/P1 1-ring connection
+ mesh.get1Ring(P0).nodes.erase(P1);
+ mesh.get1Ring(P1).nodes.erase(P0);
+ mesh.get1Ring(P0).tris.erase(triA);
+ mesh.get1Ring(P1).tris.erase(triA);
+ mesh.get1Ring(ca_old[0].node).tris.erase(triA);
+ if (haveB) {
+ mesh.get1Ring(P0).tris.erase(triB);
+ mesh.get1Ring(P1).tris.erase(triB);
+ mesh.get1Ring(cb_old[0].node).tris.erase(triB);
+ }
+
+ // init channel properties for new node
+ for(int i=0; i<mesh.numNodeChannels(); i++) {
+ mesh.nodeChannel(i)->addInterpol(P0, P1, len0/(len0+len1));
+ }
+
+ // write to array
+ mesh.addTri(Triangle(ca_old[0].node, ca_old[1].node, mesh.numNodes()));
+ mesh.addTri(Triangle(ca_old[0].node, mesh.numNodes(), ca_old[2].node));
+ if (haveB) {
+ mesh.addTri(Triangle(cb_old[0].node, cb_old[1].node, mesh.numNodes()));
+ mesh.addTri(Triangle(cb_old[0].node, mesh.numNodes(), cb_old[2].node));
+ }
+ mesh.addNode(newNode);
+
+ const int nt = haveB ? 4 : 2;
+ int triA1 = mesh.numTris()-nt;
+ int triA2 = mesh.numTris()-nt+1;
+ int triB1=0, triB2=0;
+ if (haveB) {
+ triB1 = mesh.numTris()-nt+2;
+ triB2 = mesh.numTris()-nt+3;
+ }
+ mesh.tris(triA1).flags = mesh.tris(triA).flags;
+ mesh.tris(triA2).flags = mesh.tris(triA).flags;
+ mesh.tris(triB1).flags = mesh.tris(triB).flags;
+ mesh.tris(triB2).flags = mesh.tris(triB).flags;
+
+ // connect new triangles to outside triangles,
+ // and connect outside triangles to these new ones
+ for (int c=0; c<3; c++) mesh.addCorner(Corner(triA1,mesh.tris(triA1).c[c]));
+ for (int c=0; c<3; c++) mesh.addCorner(Corner(triA2,mesh.tris(triA2).c[c]));
+ if (haveB) {
+ for (int c=0; c<3; c++) mesh.addCorner(Corner(triB1,mesh.tris(triB1).c[c]));
+ for (int c=0; c<3; c++) mesh.addCorner(Corner(triB2,mesh.tris(triB2).c[c]));
+ }
+
+ int baseIdx = 3*(mesh.numTris()-nt);
+ Corner* cBase = &mesh.corners(baseIdx);
+
+ // set next/prev
+ for (int t=0; t<nt; t++)
+ for (int c=0; c<3; c++) {
+ cBase[t*3+c].next = baseIdx+t*3+((c+1)%3);
+ cBase[t*3+c].prev = baseIdx+t*3+((c+2)%3);
+ }
+
+ // set opposites
+ // A1
+ cBase[0].opposite = haveB ? (baseIdx+9) : -1;
+ cBase[1].opposite = baseIdx+5;
+ cBase[2].opposite = -1;
+ if (ca_old[2].opposite>=0) {
+ cBase[2].opposite = ca_old[2].opposite;
+ mesh.corners(cBase[2].opposite).opposite = baseIdx+2;
+ }
+ // A2
+ cBase[3].opposite = haveB ? (baseIdx+6) : -1;
+ cBase[4].opposite = -1;
+ if (ca_old[1].opposite>=0) {
+ cBase[4].opposite = ca_old[1].opposite;
+ mesh.corners(cBase[4].opposite).opposite = baseIdx+4;
+ }
+ cBase[5].opposite = baseIdx+1;
+ if (haveB) {
+ // B1
+ cBase[6].opposite = baseIdx+3;
+ cBase[7].opposite = baseIdx+11;
+ cBase[8].opposite = -1;
+ if (cb_old[2].opposite>=0) {
+ cBase[8].opposite = cb_old[2].opposite;
+ mesh.corners(cBase[8].opposite).opposite = baseIdx+8;
+ }
+ // B2
+ cBase[9].opposite = baseIdx+0;
+ cBase[10].opposite = -1;
+ if (cb_old[1].opposite>=0) {
+ cBase[10].opposite = cb_old[1].opposite;
+ mesh.corners(cBase[10].opposite).opposite = baseIdx+10;
+ }
+ cBase[11].opposite = baseIdx+7;
+ }
+
+ ////////////////////
+ // mark the two original triangles for deletion
+ taintedTris[triA] = true;
+ mesh.removeTriFromLookup(triA);
+ if (haveB) {
+ taintedTris[triB] = true;
+ mesh.removeTriFromLookup(triB);
+ }
+
+ Real areaA1 = mesh.getFaceArea(triA1), areaA2 = mesh.getFaceArea(triA2);
+ Real areaB1=0, areaB2=0;
+ if (haveB) {
+ areaB1 = mesh.getFaceArea(triB1);
+ areaB2 = mesh.getFaceArea(triB2);
+ }
+
+ // add channel props for new triangles
+ for(int i=0; i<mesh.numTriChannels(); i++) {
+ mesh.triChannel(i)->addSplit(triA, areaA1/(areaA1+areaA2));
+ mesh.triChannel(i)->addSplit(triA, areaA2/(areaA1+areaA2));
+ if (haveB) {
+ mesh.triChannel(i)->addSplit(triB, areaB1/(areaB1+areaB2));
+ mesh.triChannel(i)->addSplit(triB, areaB2/(areaB1+areaB2));
+ }
+ }
+
+ // add the four new triangles to the prority queue
+ for(int i=mesh.numTris()-nt; i<mesh.numTris(); i++) {
+ // find the maximum length edge in this triangle
+ Vec3 ne0 = mesh.getEdge(i, 0), ne1 = mesh.getEdge(i, 1), ne2 = mesh.getEdge(i, 2);
+ Real nd0 = normSquare(ne0);
+ Real nd1 = normSquare(ne1);
+ Real nd2 = normSquare(ne2);
+ Real longest = max(nd0,max(nd1,nd2));
+ //longest = (int)(longest * 1e2) / 1e2; // HACK: truncate
+ pq.push(pair<Real,int>(longest,i));
+ }
+ edgeSubdivs++;
+ }
+ }
+
+ //////////////////////////////////////////
+ // EDGE COLLAPSING //
+ // - based on short edge length //
+ //////////////////////////////////////////
+ if (minLength > 0) {
+ const Real minLength2 = minLength*minLength;
+ for(int t=0; t<mesh.numTris(); t++) {
+ // we only want to run through the edge list ONCE.
+ // we achieve this in a method very similar to the above subdivision method.
+
+ // NOTE:
+ // priority queue does not work so great in the edge collapse case,
+ // because collapsing one triangle affects the edge lengths
+ // of many neighbor triangles,
+ // and we do not update their maximum edge length in the queue.
+
+ // if this triangle has already been deleted, ignore it
+ //if(taintedTris[t])
+ // continue;
+
+ if(taintedTris.find(t)!=taintedTris.end())
+ continue;
+
+ // first we find the minimum length edge in this triangle
+ Vec3 e0 = mesh.getEdge(t,0), e1 = mesh.getEdge(t,1), e2 = mesh.getEdge(t,2);
+ Real d0 = normSquare(e0);
+ Real d1 = normSquare(e1);
+ Real d2 = normSquare(e2);
+
+ Vec3 edgevect;
+ Vec3 endpoint;
+ Real dist2;
+ int which;
+ if(d0<d1) {
+ if(d0<d2) {
+ dist2 = d0;
+ edgevect = e0;
+ endpoint = mesh.getNode(t,0);
+ which = 2; // 2 opposite of edge 0-1
+ } else {
+ dist2 = d2;
+ edgevect = e2;
+ endpoint = mesh.getNode(t,2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ } else {
+ if(d1<d2) {
+ dist2 = d1;
+ edgevect = e1;
+ endpoint = mesh.getNode(t,1);
+ which = 0; // 0 opposite of edge 1-2
+ } else {
+ dist2 = d2;
+ edgevect = e2;
+ endpoint = mesh.getNode(t,2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ }
+ // then we see if the min length edge is too short
+ if(dist2<minLength2) {
+ CollapseEdge(mesh, t,which,edgevect,endpoint, deletedNodes,taintedTris, edgeCollsLen, cutTubes);
+ }
+ }
+ }
+ // cleanup nodes and triangles marked for deletion
+
+ // we run backwards through the deleted array,
+ // replacing triangles with ones from the back
+ // (this avoids the potential problem of overwriting a triangle
+ // with a to-be-deleted triangle)
+ std::map<int,bool>::reverse_iterator tti = taintedTris.rbegin();
+ for(;tti!=taintedTris.rend(); tti++)
+ mesh.removeTri(tti->first);
+
+ mesh.removeNodes(deletedNodes);
+ cout << "Surface subdivision finished with " << mesh.numNodes() << " surface nodes and " << mesh.numTris();
+ cout << " surface triangles, edgeSubdivs:" << edgeSubdivs << ", edgeCollapses: " << edgeCollsLen;
+ cout << " + " << edgeCollsAngle << " + " << edgeKill << endl;
+ //mesh.sanityCheck();
+
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "subdivideMesh" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); Real minAngle = _args.get<Real >("minAngle",1,&_lock); Real minLength = _args.get<Real >("minLength",2,&_lock); Real maxLength = _args.get<Real >("maxLength",3,&_lock); bool cutTubes = _args.getOpt<bool >("cutTubes",4,false,&_lock); _retval = getPyNone(); subdivideMesh(mesh,minAngle,minLength,maxLength,cutTubes); _args.check(); }
+ pbFinalizePlugin(parent,"subdivideMesh", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("subdivideMesh",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_subdivideMesh ("","subdivideMesh",_W_1);
+extern "C" {
+ void PbRegister_subdivideMesh() {
+ KEEP_UNUSED(_RP_subdivideMesh); }
+ }
+
+
+
+void killSmallComponents(Mesh& mesh, int elements = 10) {
+ const int num = mesh.numTris();
+ vector<int> comp(num);
+ vector<int> numEl;
+ vector<int> deletedNodes;
+ vector<bool> isNodeDel(mesh.numNodes());
+ map<int,bool> taintedTris;
+ // enumerate components
+ int cur=0;
+ for (int i=0; i<num; i++) {
+ if (comp[i]==0) {
+ cur++;
+ comp[i] = cur;
+
+ stack<int> stack;
+ stack.push(i);
+ int cnt = 1;
+ while(!stack.empty()) {
+ int tri = stack.top();
+ stack.pop();
+ for (int c=0; c<3; c++) {
+ int op = mesh.corners(tri,c).opposite;
+ if (op < 0) continue;
+ int ntri = mesh.corners(op).tri;
+ if (comp[ntri]==0) {
+ comp[ntri] = cur;
+ stack.push(ntri);
+ cnt++;
+ }
+ }
+ }
+ numEl.push_back(cnt);
+ }
+ }
+ // kill small components
+ for (int j=0; j<num; j++) {
+ if (numEl[comp[j]-1] < elements) {
+ taintedTris[j] = true;
+ for (int c=0; c<3; c++) {
+ int n=mesh.tris(j).c[c];
+ if (!isNodeDel[n]) {
+ isNodeDel[n] = true;
+ deletedNodes.push_back(n);
+ }
+ }
+ }
+ }
+
+ std::map<int,bool>::reverse_iterator tti = taintedTris.rbegin();
+ for(;tti!=taintedTris.rend(); tti++)
+ mesh.removeTri(tti->first);
+
+ mesh.removeNodes(deletedNodes);
+
+ if (!taintedTris.empty())
+ cout << "Killed small components : " << deletedNodes.size() << " nodes, " << taintedTris.size() << " tris deleted." << endl;
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "killSmallComponents" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); int elements = _args.getOpt<int >("elements",1,10,&_lock); _retval = getPyNone(); killSmallComponents(mesh,elements); _args.check(); }
+ pbFinalizePlugin(parent,"killSmallComponents", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("killSmallComponents",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_killSmallComponents ("","killSmallComponents",_W_2);
+extern "C" {
+ void PbRegister_killSmallComponents() {
+ KEEP_UNUSED(_RP_killSmallComponents); }
+ }
+
+
+
+
+} //namespace
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/pressure.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/pressure.cpp
new file mode 100644
index 00000000000..2831483b5f8
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/pressure.cpp
@@ -0,0 +1,783 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for pressure correction: solve_pressure, and ghost fluid helpers
+ *
+ ******************************************************************************/
+#include "vectorbase.h"
+#include "kernel.h"
+#include "conjugategrad.h"
+#include "multigrid.h"
+
+using namespace std;
+namespace Manta {
+
+//! Preconditioner for CG solver
+// - None: Use standard CG
+// - MIC: Modified incomplete Cholesky preconditioner
+// - MGDynamic: Multigrid preconditioner, rebuilt for each solve
+// - MGStatic: Multigrid preconditioner, built only once (faster than
+// MGDynamic, but works only if Poisson equation does not change)
+enum Preconditioner { PcNone = 0, PcMIC = 1, PcMGDynamic = 2, PcMGStatic = 3 };
+
+inline static Real surfTensHelper(const IndexInt idx, const int offset, const Grid<Real> &phi, const Grid<Real> &curv, const Real surfTens, const Real gfClamp);
+
+//! Kernel: Construct the right-hand side of the poisson equation
+
+
+
+
+
+
+ struct MakeRhs : public KernelBase {
+ MakeRhs( const FlagGrid& flags, Grid<Real>& rhs, const MACGrid& vel, const Grid<Real>* perCellCorr, const MACGrid* fractions, const Grid<Real> *phi, const Grid<Real> *curv, const Real surfTens, const Real gfClamp) : KernelBase(&flags,1) ,flags(flags),rhs(rhs),vel(vel),perCellCorr(perCellCorr),fractions(fractions),phi(phi),curv(curv),surfTens(surfTens),gfClamp(gfClamp) ,cnt(0),sum(0) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& rhs, const MACGrid& vel, const Grid<Real>* perCellCorr, const MACGrid* fractions, const Grid<Real> *phi, const Grid<Real> *curv, const Real surfTens, const Real gfClamp ,int& cnt,double& sum) {
+ if(!flags.isFluid(i,j,k)) {
+ rhs(i,j,k) = 0;
+ return;
+ }
+
+ // compute negative divergence
+ // no flag checks: assumes vel at obstacle interfaces is set to zero
+ Real set(0);
+ if(!fractions) {
+ set = vel(i,j,k).x - vel(i+1,j,k).x + vel(i,j,k).y - vel(i,j+1,k).y;
+ if(vel.is3D()) set += vel(i,j,k).z - vel(i,j,k+1).z;
+ } else {
+ set = (*fractions)(i,j,k).x * vel(i,j,k).x - (*fractions)(i+1,j,k).x * vel(i+1,j,k).x + (*fractions)(i,j,k).y * vel(i,j,k).y - (*fractions)(i,j+1,k).y * vel(i,j+1,k).y;
+ if(vel.is3D()) set += (*fractions)(i,j,k).z * vel(i,j,k).z - (*fractions)(i,j,k+1).z * vel(i,j,k+1).z;
+ }
+
+ // compute surface tension effect (optional)
+ if(phi && curv) {
+ const IndexInt idx = flags.index(i,j,k);
+ const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ if(flags.isEmpty(i-1,j,k)) set += surfTensHelper(idx, -X, *phi, *curv, surfTens, gfClamp);
+ if(flags.isEmpty(i+1,j,k)) set += surfTensHelper(idx, +X, *phi, *curv, surfTens, gfClamp);
+ if(flags.isEmpty(i,j-1,k)) set += surfTensHelper(idx, -Y, *phi, *curv, surfTens, gfClamp);
+ if(flags.isEmpty(i,j+1,k)) set += surfTensHelper(idx, +Y, *phi, *curv, surfTens, gfClamp);
+ if(vel.is3D()) {
+ if(flags.isEmpty(i,j,k-1)) set += surfTensHelper(idx, -Z, *phi, *curv, surfTens, gfClamp);
+ if(flags.isEmpty(i,j,k+1)) set += surfTensHelper(idx, +Z, *phi, *curv, surfTens, gfClamp);
+ }
+ }
+
+ // per cell divergence correction (optional)
+ if(perCellCorr)
+ set += perCellCorr->get(i,j,k);
+
+ // obtain sum, cell count
+ sum += set;
+ cnt++;
+
+ rhs(i,j,k) = set;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return rhs; }
+ typedef Grid<Real> type1;inline const MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline const Grid<Real>* getArg3() {
+ return perCellCorr; }
+ typedef Grid<Real> type3;inline const MACGrid* getArg4() {
+ return fractions; }
+ typedef MACGrid type4;inline const Grid<Real> * getArg5() {
+ return phi; }
+ typedef Grid<Real> type5;inline const Grid<Real> * getArg6() {
+ return curv; }
+ typedef Grid<Real> type6;inline const Real& getArg7() {
+ return surfTens; }
+ typedef Real type7;inline const Real& getArg8() {
+ return gfClamp; }
+ typedef Real type8; void runMessage() { debMsg("Executing kernel MakeRhs ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+ int cnt = 0;double sum = 0;
+#pragma omp for nowait
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,rhs,vel,perCellCorr,fractions,phi,curv,surfTens,gfClamp,cnt,sum);
+#pragma omp critical
+{this->cnt += cnt; this->sum += sum; } }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+ int cnt = 0;double sum = 0;
+#pragma omp for nowait
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,rhs,vel,perCellCorr,fractions,phi,curv,surfTens,gfClamp,cnt,sum);
+#pragma omp critical
+{this->cnt += cnt; this->sum += sum; } }
+ }
+ }
+ const FlagGrid& flags; Grid<Real>& rhs; const MACGrid& vel; const Grid<Real>* perCellCorr; const MACGrid* fractions; const Grid<Real> * phi; const Grid<Real> * curv; const Real surfTens; const Real gfClamp; int cnt; double sum; }
+;
+
+//! Kernel: make velocity divergence free by subtracting pressure gradient
+
+
+ struct knCorrectVelocity : public KernelBase {
+ knCorrectVelocity(const FlagGrid& flags, MACGrid& vel, const Grid<Real>& pressure) : KernelBase(&flags,1) ,flags(flags),vel(vel),pressure(pressure) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, MACGrid& vel, const Grid<Real>& pressure ) {
+ const IndexInt idx = flags.index(i,j,k);
+ if(flags.isFluid(idx)) {
+ if( flags.isFluid(i-1,j,k)) vel[idx].x -= (pressure[idx] - pressure(i-1,j,k));
+ if( flags.isFluid(i,j-1,k)) vel[idx].y -= (pressure[idx] - pressure(i,j-1,k));
+ if(flags.is3D() && flags.isFluid(i,j,k-1)) vel[idx].z -= (pressure[idx] - pressure(i,j,k-1));
+
+ if( flags.isEmpty(i-1,j,k)) vel[idx].x -= pressure[idx];
+ if( flags.isEmpty(i,j-1,k)) vel[idx].y -= pressure[idx];
+ if(flags.is3D() && flags.isEmpty(i,j,k-1)) vel[idx].z -= pressure[idx];
+ } else if(flags.isEmpty(idx)&&!flags.isOutflow(idx)) { // don't change velocities in outflow cells
+ if(flags.isFluid(i-1,j,k)) vel[idx].x += pressure(i-1,j,k);
+ else vel[idx].x = 0.f;
+ if(flags.isFluid(i,j-1,k)) vel[idx].y += pressure(i,j-1,k);
+ else vel[idx].y = 0.f;
+ if(flags.is3D()) {
+ if(flags.isFluid(i,j,k-1)) vel[idx].z += pressure(i,j,k-1);
+ else vel[idx].z = 0.f;
+ }
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const Grid<Real>& getArg2() {
+ return pressure; }
+ typedef Grid<Real> type2; void runMessage() { debMsg("Executing kernel knCorrectVelocity ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,pressure); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,vel,pressure); }
+ }
+ }
+ const FlagGrid& flags; MACGrid& vel; const Grid<Real>& pressure; }
+;
+
+// *****************************************************************************
+// Ghost fluid helpers
+
+// calculate fraction filled with liquid (note, assumes inside value is < outside!)
+inline static Real thetaHelper(const Real inside, const Real outside)
+{
+ const Real denom = inside-outside;
+ if(denom > -1e-04) return 0.5; // should always be neg, and large enough...
+ return std::max(Real(0), std::min(Real(1), inside/denom));
+}
+
+// calculate ghost fluid factor, cell at idx should be a fluid cell
+inline static Real ghostFluidHelper(const IndexInt idx, const int offset, const Grid<Real> &phi, const Real gfClamp)
+{
+ Real alpha = thetaHelper(phi[idx], phi[idx+offset]);
+ if(alpha < gfClamp) return alpha = gfClamp;
+ return (1.-(1./alpha));
+}
+
+inline static Real surfTensHelper(const IndexInt idx, const int offset, const Grid<Real> &phi, const Grid<Real> &curv, const Real surfTens, const Real gfClamp)
+{
+ return surfTens*(curv[idx+offset] - ghostFluidHelper(idx, offset, phi, gfClamp)*curv[idx]);
+}
+
+//! Kernel: Adapt A0 for ghost fluid
+
+
+ struct ApplyGhostFluidDiagonal : public KernelBase {
+ ApplyGhostFluidDiagonal(Grid<Real> &A0, const FlagGrid &flags, const Grid<Real> &phi, const Real gfClamp) : KernelBase(&A0,1) ,A0(A0),flags(flags),phi(phi),gfClamp(gfClamp) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real> &A0, const FlagGrid &flags, const Grid<Real> &phi, const Real gfClamp ) {
+ const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ const IndexInt idx = flags.index(i,j,k);
+ if(!flags.isFluid(idx)) return;
+
+ if(flags.isEmpty(i-1,j,k)) A0[idx] -= ghostFluidHelper(idx, -X, phi, gfClamp);
+ if(flags.isEmpty(i+1,j,k)) A0[idx] -= ghostFluidHelper(idx, +X, phi, gfClamp);
+ if(flags.isEmpty(i,j-1,k)) A0[idx] -= ghostFluidHelper(idx, -Y, phi, gfClamp);
+ if(flags.isEmpty(i,j+1,k)) A0[idx] -= ghostFluidHelper(idx, +Y, phi, gfClamp);
+ if(flags.is3D()) {
+ if(flags.isEmpty(i,j,k-1)) A0[idx] -= ghostFluidHelper(idx, -Z, phi, gfClamp);
+ if(flags.isEmpty(i,j,k+1)) A0[idx] -= ghostFluidHelper(idx, +Z, phi, gfClamp);
+ }
+} inline Grid<Real> & getArg0() {
+ return A0; }
+ typedef Grid<Real> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<Real> & getArg2() {
+ return phi; }
+ typedef Grid<Real> type2;inline const Real& getArg3() {
+ return gfClamp; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel ApplyGhostFluidDiagonal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,A0,flags,phi,gfClamp); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,A0,flags,phi,gfClamp); }
+ }
+ }
+ Grid<Real> & A0; const FlagGrid& flags; const Grid<Real> & phi; const Real gfClamp; }
+;
+
+//! Kernel: Apply velocity update: ghost fluid contribution
+
+
+
+
+ struct knCorrectVelocityGhostFluid : public KernelBase {
+ knCorrectVelocityGhostFluid( MACGrid &vel, const FlagGrid &flags, const Grid<Real> &pressure, const Grid<Real> &phi, Real gfClamp, const Grid<Real> *curv, const Real surfTens) : KernelBase(&vel,1) ,vel(vel),flags(flags),pressure(pressure),phi(phi),gfClamp(gfClamp),curv(curv),surfTens(surfTens) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid &vel, const FlagGrid &flags, const Grid<Real> &pressure, const Grid<Real> &phi, Real gfClamp, const Grid<Real> *curv, const Real surfTens ) {
+ const IndexInt X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ const IndexInt idx = flags.index(i,j,k);
+ if(flags.isFluid(idx)) {
+ if( flags.isEmpty(i-1,j,k)) vel[idx][0] += pressure[idx] * ghostFluidHelper(idx, -X, phi, gfClamp);
+ if( flags.isEmpty(i,j-1,k)) vel[idx][1] += pressure[idx] * ghostFluidHelper(idx, -Y, phi, gfClamp);
+ if(flags.is3D() && flags.isEmpty(i,j,k-1)) vel[idx][2] += pressure[idx] * ghostFluidHelper(idx, -Z, phi, gfClamp);
+ } else if(flags.isEmpty(idx) && !flags.isOutflow(idx)) { // do not change velocities in outflow cells
+ if(flags.isFluid(i-1,j,k)) vel[idx][0] -= pressure(i-1,j,k) * ghostFluidHelper(idx-X, +X, phi, gfClamp);
+ else vel[idx].x = 0.f;
+ if(flags.isFluid(i,j-1,k)) vel[idx][1] -= pressure(i,j-1,k) * ghostFluidHelper(idx-Y, +Y, phi, gfClamp);
+ else vel[idx].y = 0.f;
+ if(flags.is3D()) {
+ if(flags.isFluid(i,j,k-1)) vel[idx][2] -= pressure(i,j,k-1) * ghostFluidHelper(idx-Z, +Z, phi, gfClamp);
+ else vel[idx].z = 0.f;
+ }
+ }
+
+ if(curv) {
+ if(flags.isFluid(idx)) {
+ if( flags.isEmpty(i-1,j,k)) vel[idx].x += surfTensHelper(idx, -X, phi, *curv, surfTens, gfClamp);
+ if( flags.isEmpty(i,j-1,k)) vel[idx].y += surfTensHelper(idx, -Y, phi, *curv, surfTens, gfClamp);
+ if(flags.is3D() && flags.isEmpty(i,j,k-1)) vel[idx].z += surfTensHelper(idx, -Z, phi, *curv, surfTens, gfClamp);
+ } else if(flags.isEmpty(idx) && !flags.isOutflow(idx)) { // do not change velocities in outflow cells
+ vel[idx].x -= (flags.isFluid(i-1,j,k)) ? surfTensHelper(idx-X, +X, phi, *curv, surfTens, gfClamp) : 0.f;
+ vel[idx].y -= (flags.isFluid(i,j-1,k)) ? surfTensHelper(idx-Y, +Y, phi, *curv, surfTens, gfClamp) : 0.f;
+ if(flags.is3D()) vel[idx].z -= (flags.isFluid(i,j,k-1)) ? surfTensHelper(idx-Z, +Z, phi, *curv, surfTens, gfClamp) : 0.f;
+ }
+ }
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<Real> & getArg2() {
+ return pressure; }
+ typedef Grid<Real> type2;inline const Grid<Real> & getArg3() {
+ return phi; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return gfClamp; }
+ typedef Real type4;inline const Grid<Real> * getArg5() {
+ return curv; }
+ typedef Grid<Real> type5;inline const Real& getArg6() {
+ return surfTens; }
+ typedef Real type6; void runMessage() { debMsg("Executing kernel knCorrectVelocityGhostFluid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,flags,pressure,phi,gfClamp,curv,surfTens); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,flags,pressure,phi,gfClamp,curv,surfTens); }
+ }
+ }
+ MACGrid& vel; const FlagGrid& flags; const Grid<Real> & pressure; const Grid<Real> & phi; Real gfClamp; const Grid<Real> * curv; const Real surfTens; }
+;
+
+
+// improve behavior of clamping for large time steps:
+inline static Real ghostFluidWasClamped(const IndexInt idx, const int offset, const Grid<Real> &phi, const Real gfClamp)
+{
+ const Real alpha = thetaHelper(phi[idx], phi[idx+offset]);
+ if(alpha < gfClamp) return true;
+ return false;
+}
+
+
+
+
+
+ struct knReplaceClampedGhostFluidVels : public KernelBase {
+ knReplaceClampedGhostFluidVels( MACGrid &vel, const FlagGrid &flags, const Grid<Real> &pressure, const Grid<Real> &phi, Real gfClamp ) : KernelBase(&vel,1) ,vel(vel),flags(flags),pressure(pressure),phi(phi),gfClamp(gfClamp) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid &vel, const FlagGrid &flags, const Grid<Real> &pressure, const Grid<Real> &phi, Real gfClamp ) {
+ const IndexInt idx = flags.index(i,j,k);
+ const IndexInt X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ if(!flags.isEmpty(idx)) return;
+
+ if( flags.isFluid(i-1,j,k) && ghostFluidWasClamped(idx-X, +X, phi, gfClamp)) vel[idx][0] = vel[idx-X][0];
+ if( flags.isFluid(i,j-1,k) && ghostFluidWasClamped(idx-Y, +Y, phi, gfClamp)) vel[idx][1] = vel[idx-Y][1];
+ if(flags.is3D() && flags.isFluid(i,j,k-1) && ghostFluidWasClamped(idx-Z, +Z, phi, gfClamp)) vel[idx][2] = vel[idx-Z][2];
+
+ if( flags.isFluid(i+1,j,k) && ghostFluidWasClamped(idx+X, -X, phi, gfClamp)) vel[idx][0] = vel[idx+X][0];
+ if( flags.isFluid(i,j+1,k) && ghostFluidWasClamped(idx+Y, -Y, phi, gfClamp)) vel[idx][1] = vel[idx+Y][1];
+ if(flags.is3D() && flags.isFluid(i,j,k+1) && ghostFluidWasClamped(idx+Z, -Z, phi, gfClamp)) vel[idx][2] = vel[idx+Z][2];
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<Real> & getArg2() {
+ return pressure; }
+ typedef Grid<Real> type2;inline const Grid<Real> & getArg3() {
+ return phi; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return gfClamp; }
+ typedef Real type4; void runMessage() { debMsg("Executing kernel knReplaceClampedGhostFluidVels ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,flags,pressure,phi,gfClamp); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,flags,pressure,phi,gfClamp); }
+ }
+ }
+ MACGrid& vel; const FlagGrid& flags; const Grid<Real> & pressure; const Grid<Real> & phi; Real gfClamp; }
+;
+
+//! Kernel: Compute min value of Real grid
+
+ struct CountEmptyCells : public KernelBase {
+ CountEmptyCells(const FlagGrid& flags) : KernelBase(&flags,0) ,flags(flags) ,numEmpty(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags ,int& numEmpty) {
+ if(flags.isEmpty(idx)) numEmpty++;
+} inline operator int () {
+ return numEmpty; }
+ inline int & getRet() {
+ return numEmpty; }
+ inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0; void runMessage() { debMsg("Executing kernel CountEmptyCells ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ int numEmpty = 0;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,flags,numEmpty);
+#pragma omp critical
+{this->numEmpty += numEmpty; } }
+ }
+ const FlagGrid& flags; int numEmpty; }
+;
+
+// *****************************************************************************
+// Misc helpers
+
+//! Change 'A' and 'rhs' such that pressure at 'fixPidx' is fixed to 'value'
+void fixPressure(int fixPidx, Real value, Grid<Real>& rhs, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak)
+{
+ // Bring to rhs at neighbors
+ rhs[fixPidx + Ai.getStrideX()] -= Ai[fixPidx] * value;
+ rhs[fixPidx + Aj.getStrideY()] -= Aj[fixPidx] * value;
+ rhs[fixPidx - Ai.getStrideX()] -= Ai[fixPidx - Ai.getStrideX()] * value;
+ rhs[fixPidx - Aj.getStrideY()] -= Aj[fixPidx - Aj.getStrideY()] * value;
+ if(rhs.is3D()) {
+ rhs[fixPidx + Ak.getStrideZ()] -= Ak[fixPidx] * value;
+ rhs[fixPidx - Ak.getStrideZ()] -= Ak[fixPidx - Ak.getStrideZ()] * value;
+ }
+
+ // Trivialize equation at 'fixPidx' to: pressure[fixPidx] = value
+ rhs[fixPidx] = value;
+ A0[fixPidx] = Real(1);
+ Ai[fixPidx] = Aj[fixPidx] = Ak[fixPidx] = Real(0);
+ Ai[fixPidx - Ai.getStrideX()] = Real(0);
+ Aj[fixPidx - Aj.getStrideY()] = Real(0);
+ if(rhs.is3D()) { Ak[fixPidx - Ak.getStrideZ()] = Real(0); }
+}
+
+// for "static" MG mode, keep one MG data structure per fluid solver
+// leave cleanup to OS/user if nonzero at program termination (PcMGStatic mode)
+// alternatively, manually release in scene file with releaseMG
+static std::map<FluidSolver*, GridMg*> gMapMG;
+
+void releaseMG(FluidSolver* solver=nullptr) {
+ // release all?
+ if(!solver) {
+ for(std::map<FluidSolver*, GridMg*>::iterator it = gMapMG.begin(); it != gMapMG.end(); it++) {
+ if(it->first != nullptr) releaseMG(it->first);
+ }
+ return;
+ }
+
+ GridMg* mg = gMapMG[solver];
+ if(mg) {
+ delete mg;
+ gMapMG[solver] = nullptr;
+ }
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "releaseMG" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FluidSolver* solver = _args.getPtrOpt<FluidSolver >("solver",0,nullptr,&_lock); _retval = getPyNone(); releaseMG(solver); _args.check(); }
+ pbFinalizePlugin(parent,"releaseMG", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("releaseMG",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_releaseMG ("","releaseMG",_W_0);
+extern "C" {
+ void PbRegister_releaseMG() {
+ KEEP_UNUSED(_RP_releaseMG); }
+ }
+
+
+
+
+// *****************************************************************************
+// Main pressure solve
+
+// Note , all three pressure solve helper functions take
+// identical parameters, apart from the RHS grid (and different const values)
+
+
+//! Compute rhs for pressure solve
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void computePressureRhs( Grid<Real>& rhs, const MACGrid& vel, const Grid<Real>& pressure, const FlagGrid& flags, Real cgAccuracy = 1e-3, const Grid<Real>* phi = 0, const Grid<Real>* perCellCorr = 0, const MACGrid* fractions = 0, Real gfClamp = 1e-04, Real cgMaxIterFac = 1.5, bool precondition = true, int preconditioner = PcMIC, bool enforceCompatibility = false, bool useL2Norm = false, bool zeroPressureFixing = false, const Grid<Real> *curv = NULL, const Real surfTens = 0. ) {
+ // compute divergence and init right hand side
+ MakeRhs kernMakeRhs (flags, rhs, vel, perCellCorr, fractions, phi, curv, surfTens, gfClamp );
+
+ if(enforceCompatibility)
+ rhs += (Real)(-kernMakeRhs.sum / (Real)kernMakeRhs.cnt);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "computePressureRhs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& rhs = *_args.getPtr<Grid<Real> >("rhs",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Grid<Real>& pressure = *_args.getPtr<Grid<Real> >("pressure",2,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",3,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",4,1e-3,&_lock); const Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",5,0,&_lock); const Grid<Real>* perCellCorr = _args.getPtrOpt<Grid<Real> >("perCellCorr",6,0,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",7,0,&_lock); Real gfClamp = _args.getOpt<Real >("gfClamp",8,1e-04,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",9,1.5,&_lock); bool precondition = _args.getOpt<bool >("precondition",10,true,&_lock); int preconditioner = _args.getOpt<int >("preconditioner",11,PcMIC,&_lock); bool enforceCompatibility = _args.getOpt<bool >("enforceCompatibility",12,false,&_lock); bool useL2Norm = _args.getOpt<bool >("useL2Norm",13,false,&_lock); bool zeroPressureFixing = _args.getOpt<bool >("zeroPressureFixing",14,false,&_lock); const Grid<Real> * curv = _args.getPtrOpt<Grid<Real> >("curv",15,NULL,&_lock); const Real surfTens = _args.getOpt<Real >("surfTens",16,0. ,&_lock); _retval = getPyNone(); computePressureRhs(rhs,vel,pressure,flags,cgAccuracy,phi,perCellCorr,fractions,gfClamp,cgMaxIterFac,precondition,preconditioner,enforceCompatibility,useL2Norm,zeroPressureFixing,curv,surfTens); _args.check(); }
+ pbFinalizePlugin(parent,"computePressureRhs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("computePressureRhs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_computePressureRhs ("","computePressureRhs",_W_1);
+extern "C" {
+ void PbRegister_computePressureRhs() {
+ KEEP_UNUSED(_RP_computePressureRhs); }
+ }
+
+
+
+//! Build and solve pressure system of equations
+//! perCellCorr: a divergence correction for each cell, optional
+//! fractions: for 2nd order obstacle boundaries, optional
+//! gfClamp: clamping threshold for ghost fluid method
+//! cgMaxIterFac: heuristic to determine maximal number of CG iteations, increase for more accurate solutions
+//! preconditioner: MIC, or MG (see Preconditioner enum)
+//! useL2Norm: use max norm by default, can be turned to L2 here
+//! zeroPressureFixing: remove null space by fixing a single pressure value, needed for MG
+//! curv: curvature for surface tension effects
+//! surfTens: surface tension coefficient
+//! retRhs: return RHS divergence, e.g., for debugging; optional
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void solvePressureSystem( Grid<Real>& rhs, MACGrid& vel, Grid<Real>& pressure, const FlagGrid& flags, Real cgAccuracy = 1e-3, const Grid<Real>* phi = 0, const Grid<Real>* perCellCorr = 0, const MACGrid* fractions = 0, Real gfClamp = 1e-04, Real cgMaxIterFac = 1.5, bool precondition = true, int preconditioner = PcMIC, const bool enforceCompatibility = false, const bool useL2Norm = false, const bool zeroPressureFixing = false, const Grid<Real> *curv = NULL, const Real surfTens = 0.) {
+ if(precondition==false) preconditioner = PcNone; // for backwards compatibility
+
+ // reserve temp grids
+ FluidSolver* parent = flags.getParent();
+ Grid<Real> residual(parent);
+ Grid<Real> search(parent);
+ Grid<Real> A0(parent);
+ Grid<Real> Ai(parent);
+ Grid<Real> Aj(parent);
+ Grid<Real> Ak(parent);
+ Grid<Real> tmp(parent);
+
+ // setup matrix and boundaries
+ MakeLaplaceMatrix(flags, A0, Ai, Aj, Ak, fractions);
+
+ if(phi) {
+ ApplyGhostFluidDiagonal(A0, flags, *phi, gfClamp);
+ }
+
+ // check whether we need to fix some pressure value...
+ // (manually enable, or automatically for high accuracy, can cause asymmetries otherwise)
+ if(zeroPressureFixing || cgAccuracy<1e-07) {
+ if(FLOATINGPOINT_PRECISION==1) debMsg("Warning - high CG accuracy with single-precision floating point accuracy might not converge...", 2);
+
+ int numEmpty = CountEmptyCells(flags);
+ IndexInt fixPidx = -1;
+ if(numEmpty==0) {
+ // Determine appropriate fluid cell for pressure fixing
+ // 1) First check some preferred positions for approx. symmetric zeroPressureFixing
+ Vec3i topCenter(flags.getSizeX() / 2, flags.getSizeY() - 1, flags.is3D() ? flags.getSizeZ() / 2 : 0);
+ Vec3i preferredPos [] = { topCenter,
+ topCenter - Vec3i(0,1,0),
+ topCenter - Vec3i(0,2,0) };
+
+ for (Vec3i pos : preferredPos) {
+ if(flags.isFluid(pos)) {
+ fixPidx = flags.index(pos);
+ break;
+ }
+ }
+
+ // 2) Then search whole domain
+ if(fixPidx == -1) {
+ FOR_IJK_BND(flags,1) {
+ if(flags.isFluid(i,j,k)) {
+ fixPidx = flags.index(i,j,k);
+ // break FOR_IJK_BND loop
+ i = flags.getSizeX()-1;
+ j = flags.getSizeY()-1;
+ k = __kmax;
+ }
+ }
+ }
+ //debMsg("No empty cells! Fixing pressure of cell "<<fixPidx<<" to zero",1);
+ }
+ if(fixPidx>=0) {
+ fixPressure(fixPidx, Real(0), rhs, A0, Ai, Aj, Ak);
+ static bool msgOnce = false;
+ if(!msgOnce) { debMsg("Pinning pressure of cell "<<fixPidx<<" to zero", 2); msgOnce=true; }
+ }
+ }
+
+ // CG setup
+ // note: the last factor increases the max iterations for 2d, which right now can't use a preconditioner
+ GridCgInterface *gcg;
+ if(vel.is3D())
+ gcg = new GridCg<ApplyMatrix> (pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+ else
+ gcg = new GridCg<ApplyMatrix2D>(pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+
+ gcg->setAccuracy( cgAccuracy );
+ gcg->setUseL2Norm( useL2Norm );
+
+ int maxIter = 0;
+
+ Grid<Real> *pca0 = nullptr, *pca1 = nullptr, *pca2 = nullptr, *pca3 = nullptr;
+ GridMg* pmg = nullptr;
+
+ // optional preconditioning
+ if(preconditioner == PcNone || preconditioner == PcMIC) {
+ maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
+
+ pca0 = new Grid<Real>(parent);
+ pca1 = new Grid<Real>(parent);
+ pca2 = new Grid<Real>(parent);
+ pca3 = new Grid<Real>(parent);
+
+ gcg->setICPreconditioner(
+ preconditioner == PcMIC ? GridCgInterface::PC_mICP : GridCgInterface::PC_None,
+ pca0, pca1, pca2, pca3);
+ } else if(preconditioner == PcMGDynamic || preconditioner == PcMGStatic) {
+ maxIter = 100;
+
+ pmg = gMapMG[parent];
+ if(!pmg) {
+ pmg = new GridMg(pressure.getSize());
+ gMapMG[parent] = pmg;
+ }
+
+ gcg->setMGPreconditioner( GridCgInterface::PC_MGP, pmg);
+ }
+
+ // CG solve
+ for (int iter=0; iter<maxIter; iter++) {
+ if(!gcg->iterate()) iter=maxIter;
+ if(iter<maxIter) debMsg("FluidSolver::solvePressure iteration "<<iter<<", residual: "<<gcg->getResNorm(), 9);
+ }
+ debMsg("FluidSolver::solvePressure done. Iterations:"<<gcg->getIterations()<<", residual:"<<gcg->getResNorm(), 2);
+
+ // Cleanup
+ if(gcg) delete gcg;
+ if(pca0) delete pca0;
+ if(pca1) delete pca1;
+ if(pca2) delete pca2;
+ if(pca3) delete pca3;
+
+ // PcMGDynamic: always delete multigrid solver after use
+ // PcMGStatic: keep multigrid solver for next solve
+ if(pmg && preconditioner==PcMGDynamic) releaseMG(parent);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "solvePressureSystem" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& rhs = *_args.getPtr<Grid<Real> >("rhs",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); Grid<Real>& pressure = *_args.getPtr<Grid<Real> >("pressure",2,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",3,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",4,1e-3,&_lock); const Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",5,0,&_lock); const Grid<Real>* perCellCorr = _args.getPtrOpt<Grid<Real> >("perCellCorr",6,0,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",7,0,&_lock); Real gfClamp = _args.getOpt<Real >("gfClamp",8,1e-04,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",9,1.5,&_lock); bool precondition = _args.getOpt<bool >("precondition",10,true,&_lock); int preconditioner = _args.getOpt<int >("preconditioner",11,PcMIC,&_lock); const bool enforceCompatibility = _args.getOpt<bool >("enforceCompatibility",12,false,&_lock); const bool useL2Norm = _args.getOpt<bool >("useL2Norm",13,false,&_lock); const bool zeroPressureFixing = _args.getOpt<bool >("zeroPressureFixing",14,false,&_lock); const Grid<Real> * curv = _args.getPtrOpt<Grid<Real> >("curv",15,NULL,&_lock); const Real surfTens = _args.getOpt<Real >("surfTens",16,0.,&_lock); _retval = getPyNone(); solvePressureSystem(rhs,vel,pressure,flags,cgAccuracy,phi,perCellCorr,fractions,gfClamp,cgMaxIterFac,precondition,preconditioner,enforceCompatibility,useL2Norm,zeroPressureFixing,curv,surfTens); _args.check(); }
+ pbFinalizePlugin(parent,"solvePressureSystem", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("solvePressureSystem",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_solvePressureSystem ("","solvePressureSystem",_W_2);
+extern "C" {
+ void PbRegister_solvePressureSystem() {
+ KEEP_UNUSED(_RP_solvePressureSystem); }
+ }
+
+
+
+//! Apply pressure gradient to make velocity field divergence free
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void correctVelocity( MACGrid& vel, Grid<Real>& pressure, const FlagGrid& flags, Real cgAccuracy = 1e-3, const Grid<Real>* phi = 0, const Grid<Real>* perCellCorr = 0, const MACGrid* fractions = 0, Real gfClamp = 1e-04, Real cgMaxIterFac = 1.5, bool precondition = true, int preconditioner = PcMIC, bool enforceCompatibility = false, bool useL2Norm = false, bool zeroPressureFixing = false, const Grid<Real> *curv = NULL, const Real surfTens = 0.) {
+ knCorrectVelocity(flags, vel, pressure);
+ if(phi) {
+ knCorrectVelocityGhostFluid(vel, flags, pressure, *phi, gfClamp, curv, surfTens);
+ // improve behavior of clamping for large time steps:
+ knReplaceClampedGhostFluidVels(vel, flags, pressure, *phi, gfClamp);
+ }
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "correctVelocity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Real>& pressure = *_args.getPtr<Grid<Real> >("pressure",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",3,1e-3,&_lock); const Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",4,0,&_lock); const Grid<Real>* perCellCorr = _args.getPtrOpt<Grid<Real> >("perCellCorr",5,0,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",6,0,&_lock); Real gfClamp = _args.getOpt<Real >("gfClamp",7,1e-04,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",8,1.5,&_lock); bool precondition = _args.getOpt<bool >("precondition",9,true,&_lock); int preconditioner = _args.getOpt<int >("preconditioner",10,PcMIC,&_lock); bool enforceCompatibility = _args.getOpt<bool >("enforceCompatibility",11,false,&_lock); bool useL2Norm = _args.getOpt<bool >("useL2Norm",12,false,&_lock); bool zeroPressureFixing = _args.getOpt<bool >("zeroPressureFixing",13,false,&_lock); const Grid<Real> * curv = _args.getPtrOpt<Grid<Real> >("curv",14,NULL,&_lock); const Real surfTens = _args.getOpt<Real >("surfTens",15,0.,&_lock); _retval = getPyNone(); correctVelocity(vel,pressure,flags,cgAccuracy,phi,perCellCorr,fractions,gfClamp,cgMaxIterFac,precondition,preconditioner,enforceCompatibility,useL2Norm,zeroPressureFixing,curv,surfTens); _args.check(); }
+ pbFinalizePlugin(parent,"correctVelocity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("correctVelocity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_correctVelocity ("","correctVelocity",_W_3);
+extern "C" {
+ void PbRegister_correctVelocity() {
+ KEEP_UNUSED(_RP_correctVelocity); }
+ }
+
+
+
+//! Perform pressure projection of the velocity grid, calls
+//! all three pressure helper functions in a row.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void solvePressure( MACGrid& vel, Grid<Real>& pressure, const FlagGrid& flags, Real cgAccuracy = 1e-3, const Grid<Real>* phi = 0, const Grid<Real>* perCellCorr = 0, const MACGrid* fractions = 0, Real gfClamp = 1e-04, Real cgMaxIterFac = 1.5, bool precondition = true, int preconditioner = PcMIC, bool enforceCompatibility = false, bool useL2Norm = false, bool zeroPressureFixing = false, const Grid<Real> *curv = NULL, const Real surfTens = 0., Grid<Real>* retRhs = NULL) {
+ Grid<Real> rhs(vel.getParent());
+
+ computePressureRhs(
+ rhs, vel, pressure, flags, cgAccuracy,
+ phi, perCellCorr, fractions, gfClamp,
+ cgMaxIterFac, precondition, preconditioner, enforceCompatibility,
+ useL2Norm, zeroPressureFixing, curv, surfTens);
+
+ solvePressureSystem(
+ rhs, vel, pressure, flags, cgAccuracy,
+ phi, perCellCorr, fractions, gfClamp,
+ cgMaxIterFac, precondition, preconditioner, enforceCompatibility,
+ useL2Norm, zeroPressureFixing, curv, surfTens);
+
+ correctVelocity(
+ vel, pressure, flags, cgAccuracy,
+ phi, perCellCorr, fractions, gfClamp,
+ cgMaxIterFac, precondition, preconditioner, enforceCompatibility,
+ useL2Norm, zeroPressureFixing, curv, surfTens);
+
+ // optionally , return RHS
+ if(retRhs) {
+ retRhs->copyFrom(rhs);
+ }
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "solvePressure" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Real>& pressure = *_args.getPtr<Grid<Real> >("pressure",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",3,1e-3,&_lock); const Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",4,0,&_lock); const Grid<Real>* perCellCorr = _args.getPtrOpt<Grid<Real> >("perCellCorr",5,0,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",6,0,&_lock); Real gfClamp = _args.getOpt<Real >("gfClamp",7,1e-04,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",8,1.5,&_lock); bool precondition = _args.getOpt<bool >("precondition",9,true,&_lock); int preconditioner = _args.getOpt<int >("preconditioner",10,PcMIC,&_lock); bool enforceCompatibility = _args.getOpt<bool >("enforceCompatibility",11,false,&_lock); bool useL2Norm = _args.getOpt<bool >("useL2Norm",12,false,&_lock); bool zeroPressureFixing = _args.getOpt<bool >("zeroPressureFixing",13,false,&_lock); const Grid<Real> * curv = _args.getPtrOpt<Grid<Real> >("curv",14,NULL,&_lock); const Real surfTens = _args.getOpt<Real >("surfTens",15,0.,&_lock); Grid<Real>* retRhs = _args.getPtrOpt<Grid<Real> >("retRhs",16,NULL,&_lock); _retval = getPyNone(); solvePressure(vel,pressure,flags,cgAccuracy,phi,perCellCorr,fractions,gfClamp,cgMaxIterFac,precondition,preconditioner,enforceCompatibility,useL2Norm,zeroPressureFixing,curv,surfTens,retRhs); _args.check(); }
+ pbFinalizePlugin(parent,"solvePressure", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("solvePressure",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_solvePressure ("","solvePressure",_W_4);
+extern "C" {
+ void PbRegister_solvePressure() {
+ KEEP_UNUSED(_RP_solvePressure); }
+ }
+
+
+
+} // end namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/ptsplugins.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/ptsplugins.cpp
new file mode 100644
index 00000000000..451e550f75b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/ptsplugins.cpp
@@ -0,0 +1,226 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+// ----------------------------------------------------------------------------
+//
+// MantaFlow fluid solver framework
+// Copyright 2018 Kiwon Um, Nils Thuerey
+//
+// This program is free software, distributed under the terms of the
+// GNU General Public License (GPL)
+// http://www.gnu.org/licenses
+//
+// Particle system helper
+//
+// ----------------------------------------------------------------------------
+
+#include "particle.h"
+
+
+namespace Manta {
+
+
+
+ struct KnAddForcePvel : public KernelBase {
+ KnAddForcePvel(ParticleDataImpl<Vec3> &v, const Vec3 &da, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(v.size()) ,v(v),da(da),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<Vec3> &v, const Vec3 &da, const ParticleDataImpl<int> *ptype, const int exclude ) {
+ if(ptype && ((*ptype)[idx] & exclude)) return;
+ v[idx] += da;
+} inline ParticleDataImpl<Vec3> & getArg0() {
+ return v; }
+ typedef ParticleDataImpl<Vec3> type0;inline const Vec3& getArg1() {
+ return da; }
+ typedef Vec3 type1;inline const ParticleDataImpl<int> * getArg2() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type2;inline const int& getArg3() {
+ return exclude; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel KnAddForcePvel ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,v,da,ptype,exclude); }
+ }
+ ParticleDataImpl<Vec3> & v; const Vec3& da; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+//! add force to vec3 particle data; a: acceleration
+
+void addForcePvel(ParticleDataImpl<Vec3> &vel, const Vec3 &a, const Real dt, const ParticleDataImpl<int> *ptype, const int exclude) {
+ KnAddForcePvel(vel, a*dt, ptype, exclude);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addForcePvel" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; ParticleDataImpl<Vec3> & vel = *_args.getPtr<ParticleDataImpl<Vec3> >("vel",0,&_lock); const Vec3& a = _args.get<Vec3 >("a",1,&_lock); const Real dt = _args.get<Real >("dt",2,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtr<ParticleDataImpl<int> >("ptype",3,&_lock); const int exclude = _args.get<int >("exclude",4,&_lock); _retval = getPyNone(); addForcePvel(vel,a,dt,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"addForcePvel", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addForcePvel",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addForcePvel ("","addForcePvel",_W_0);
+extern "C" {
+ void PbRegister_addForcePvel() {
+ KEEP_UNUSED(_RP_addForcePvel); }
+ }
+
+
+
+
+
+ struct KnUpdateVelocityFromDeltaPos : public KernelBase {
+ KnUpdateVelocityFromDeltaPos(const BasicParticleSystem &p, ParticleDataImpl<Vec3> &v, const ParticleDataImpl<Vec3> &x_prev, const Real over_dt, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(p.size()) ,p(p),v(v),x_prev(x_prev),over_dt(over_dt),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem &p, ParticleDataImpl<Vec3> &v, const ParticleDataImpl<Vec3> &x_prev, const Real over_dt, const ParticleDataImpl<int> *ptype, const int exclude ) {
+ if(ptype && ((*ptype)[idx] & exclude)) return;
+ v[idx] = (p[idx].pos - x_prev[idx])*over_dt;
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline ParticleDataImpl<Vec3> & getArg1() {
+ return v; }
+ typedef ParticleDataImpl<Vec3> type1;inline const ParticleDataImpl<Vec3> & getArg2() {
+ return x_prev; }
+ typedef ParticleDataImpl<Vec3> type2;inline const Real& getArg3() {
+ return over_dt; }
+ typedef Real type3;inline const ParticleDataImpl<int> * getArg4() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type4;inline const int& getArg5() {
+ return exclude; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnUpdateVelocityFromDeltaPos ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,p,v,x_prev,over_dt,ptype,exclude); }
+ }
+ const BasicParticleSystem& p; ParticleDataImpl<Vec3> & v; const ParticleDataImpl<Vec3> & x_prev; const Real over_dt; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+//! retrieve velocity from position change
+
+void updateVelocityFromDeltaPos(const BasicParticleSystem& parts, ParticleDataImpl<Vec3> &vel, const ParticleDataImpl<Vec3> &x_prev, const Real dt, const ParticleDataImpl<int> *ptype, const int exclude) {
+ KnUpdateVelocityFromDeltaPos(parts, vel, x_prev, 1.0/dt, ptype, exclude);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "updateVelocityFromDeltaPos" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<Vec3> & vel = *_args.getPtr<ParticleDataImpl<Vec3> >("vel",1,&_lock); const ParticleDataImpl<Vec3> & x_prev = *_args.getPtr<ParticleDataImpl<Vec3> >("x_prev",2,&_lock); const Real dt = _args.get<Real >("dt",3,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtr<ParticleDataImpl<int> >("ptype",4,&_lock); const int exclude = _args.get<int >("exclude",5,&_lock); _retval = getPyNone(); updateVelocityFromDeltaPos(parts,vel,x_prev,dt,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"updateVelocityFromDeltaPos", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("updateVelocityFromDeltaPos",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_updateVelocityFromDeltaPos ("","updateVelocityFromDeltaPos",_W_1);
+extern "C" {
+ void PbRegister_updateVelocityFromDeltaPos() {
+ KEEP_UNUSED(_RP_updateVelocityFromDeltaPos); }
+ }
+
+
+
+
+
+ struct KnStepEuler : public KernelBase {
+ KnStepEuler(BasicParticleSystem &p, const ParticleDataImpl<Vec3> &v, const Real dt, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(p.size()) ,p(p),v(v),dt(dt),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystem &p, const ParticleDataImpl<Vec3> &v, const Real dt, const ParticleDataImpl<int> *ptype, const int exclude ) {
+ if(ptype && ((*ptype)[idx] & exclude)) return;
+ p[idx].pos += v[idx]*dt;
+} inline BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const ParticleDataImpl<Vec3> & getArg1() {
+ return v; }
+ typedef ParticleDataImpl<Vec3> type1;inline const Real& getArg2() {
+ return dt; }
+ typedef Real type2;inline const ParticleDataImpl<int> * getArg3() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type3;inline const int& getArg4() {
+ return exclude; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel KnStepEuler ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,p,v,dt,ptype,exclude); }
+ }
+ BasicParticleSystem& p; const ParticleDataImpl<Vec3> & v; const Real dt; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+//! simple foward Euler integration for particle system
+
+void eulerStep(BasicParticleSystem& parts, const ParticleDataImpl<Vec3> &vel, const ParticleDataImpl<int> *ptype, const int exclude) {
+ KnStepEuler(parts, vel, parts.getParent()->getDt(), ptype, exclude);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "eulerStep" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const ParticleDataImpl<Vec3> & vel = *_args.getPtr<ParticleDataImpl<Vec3> >("vel",1,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtr<ParticleDataImpl<int> >("ptype",2,&_lock); const int exclude = _args.get<int >("exclude",3,&_lock); _retval = getPyNone(); eulerStep(parts,vel,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"eulerStep", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("eulerStep",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_eulerStep ("","eulerStep",_W_2);
+extern "C" {
+ void PbRegister_eulerStep() {
+ KEEP_UNUSED(_RP_eulerStep); }
+ }
+
+
+
+
+
+
+ struct KnSetPartType : public KernelBase {
+ KnSetPartType(ParticleDataImpl<int> &ptype, const BasicParticleSystem &part, const int mark, const int stype, const FlagGrid &flags, const int cflag) : KernelBase(ptype.size()) ,ptype(ptype),part(part),mark(mark),stype(stype),flags(flags),cflag(cflag) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<int> &ptype, const BasicParticleSystem &part, const int mark, const int stype, const FlagGrid &flags, const int cflag ) {
+ if(flags.isInBounds(part.getPos(idx), 0) && (flags.getAt(part.getPos(idx))&cflag) && (ptype[idx]&stype)) ptype[idx] = mark;
+} inline ParticleDataImpl<int> & getArg0() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type0;inline const BasicParticleSystem& getArg1() {
+ return part; }
+ typedef BasicParticleSystem type1;inline const int& getArg2() {
+ return mark; }
+ typedef int type2;inline const int& getArg3() {
+ return stype; }
+ typedef int type3;inline const FlagGrid& getArg4() {
+ return flags; }
+ typedef FlagGrid type4;inline const int& getArg5() {
+ return cflag; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnSetPartType ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,ptype,part,mark,stype,flags,cflag); }
+ }
+ ParticleDataImpl<int> & ptype; const BasicParticleSystem& part; const int mark; const int stype; const FlagGrid& flags; const int cflag; }
+;
+//! if particle is stype and in cflag cell, set ptype as mark
+
+void setPartType(const BasicParticleSystem &parts, ParticleDataImpl<int> &ptype, const int mark, const int stype, const FlagGrid &flags, const int cflag) {
+ KnSetPartType(ptype, parts, mark, stype, flags, cflag);
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setPartType" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<int> & ptype = *_args.getPtr<ParticleDataImpl<int> >("ptype",1,&_lock); const int mark = _args.get<int >("mark",2,&_lock); const int stype = _args.get<int >("stype",3,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",4,&_lock); const int cflag = _args.get<int >("cflag",5,&_lock); _retval = getPyNone(); setPartType(parts,ptype,mark,stype,flags,cflag); _args.check(); }
+ pbFinalizePlugin(parent,"setPartType", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setPartType",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setPartType ("","setPartType",_W_3);
+extern "C" {
+ void PbRegister_setPartType() {
+ KEEP_UNUSED(_RP_setPartType); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/secondaryparticles.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/secondaryparticles.cpp
new file mode 100644
index 00000000000..901a17b04bb
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/secondaryparticles.cpp
@@ -0,0 +1,1343 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+*
+* MantaFlow fluid solver framework
+* Copyright 2017 Georg Kohl, Nils Thuerey
+*
+* This program is free software, distributed under the terms of the
+* GNU General Public License (GPL)
+* http://www.gnu.org/licenses
+*
+* Secondary particle plugin for FLIP simulations
+*
+******************************************************************************/
+
+#include "particle.h"
+#include "commonkernels.h"
+
+namespace Manta {
+
+#pragma region Secondary Particles for FLIP
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+// Secondary Particles for FLIP
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+
+// helper function that clamps the value in potential to the interval [tauMin, tauMax] and normalizes it to [0, 1] afterwards
+Real clampPotential(Real potential, Real tauMin, Real tauMax) {
+ return (std::min(potential, tauMax) - std::min(potential, tauMin)) / (tauMax - tauMin);
+}
+
+// computes all three potentials(trapped air, wave crest, kinetic energy) and the neighbor ratio for every fluid cell and stores it in the respective grid.
+// Is less readable but significantly faster than using seperate potential computation
+
+
+
+
+ struct knFlipComputeSecondaryParticlePotentials : public KernelBase {
+ knFlipComputeSecondaryParticlePotentials( Grid<Real> &potTA, Grid<Real> &potWC, Grid<Real> &potKE, Grid<Real> &neighborRatio, const FlagGrid &flags, const MACGrid &v, const Grid<Vec3> &normal, const int radius, const Real tauMinTA, const Real tauMaxTA, const Real tauMinWC, const Real tauMaxWC, const Real tauMinKE, const Real tauMaxKE, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle | FlagGrid::TypeOutflow | FlagGrid::TypeInflow) : KernelBase(&potTA,radius) ,potTA(potTA),potWC(potWC),potKE(potKE),neighborRatio(neighborRatio),flags(flags),v(v),normal(normal),radius(radius),tauMinTA(tauMinTA),tauMaxTA(tauMaxTA),tauMinWC(tauMinWC),tauMaxWC(tauMaxWC),tauMinKE(tauMinKE),tauMaxKE(tauMaxKE),scaleFromManta(scaleFromManta),itype(itype),jtype(jtype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real> &potTA, Grid<Real> &potWC, Grid<Real> &potKE, Grid<Real> &neighborRatio, const FlagGrid &flags, const MACGrid &v, const Grid<Vec3> &normal, const int radius, const Real tauMinTA, const Real tauMaxTA, const Real tauMinWC, const Real tauMaxWC, const Real tauMinKE, const Real tauMaxKE, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle | FlagGrid::TypeOutflow | FlagGrid::TypeInflow ) {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ //compute trapped air potential + wave crest potential + neighbor ratio at once
+ const Vec3 &xi = scaleFromManta * Vec3(i, j, k); //scale to unit cube
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k);
+ const Vec3 &ni = getNormalized(normal(i, j, k));
+ Real vdiff = 0; //for trapped air
+ Real kappa = 0; //for wave crests
+ int countFluid = 0; //for neighbor ratio
+ int countMaxFluid = 0; //for neighbor ratio
+
+ //iterate over neighboring cells within radius
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || !flags.isInBounds(Vec3i(x, y, z)) || (flags(x, y, z) & jtype)) continue;
+
+ if (flags(x, y, z) & itype) {
+ countFluid++;
+ countMaxFluid++;
+ }
+ else {
+ countMaxFluid++;
+ }
+
+ const Vec3 &xj = scaleFromManta * Vec3(x, y, z); //scale to unit cube
+ const Vec3 &vj = scaleFromManta * v.getCentered(x, y, z);
+ const Vec3 &nj = getNormalized(normal(x, y, z));
+ const Vec3 xij = xi - xj;
+ const Vec3 vij = vi - vj;
+ Real h = !potTA.is3D() ? 1.414*radius : 1.732*radius; //estimate sqrt(2)*radius resp. sqrt(3)*radius for h, due to squared resp. cubic neighbor area
+ vdiff += norm(vij) * (1 - dot(getNormalized(vij), getNormalized(xij))) * (1 - norm(xij) / h);
+
+ if (dot(getNormalized(xij), ni) < 0) { //identifies wave crests
+ kappa += (1 - dot(ni, nj)) * (1 - norm(xij) / h);
+ }
+ }
+ }
+ }
+
+ neighborRatio(i, j, k) = float(countFluid) / float(countMaxFluid);
+
+ potTA(i, j, k) = clampPotential(vdiff, tauMinTA, tauMaxTA);
+ if (dot(getNormalized(vi), ni) >= 0.6) { //avoid to mark boarders of the scene as wave crest
+ potWC(i, j, k) = clampPotential(kappa, tauMinWC, tauMaxWC);
+ }
+ else {
+ potWC(i, j, k) = Real(0);
+ }
+
+ //compute kinetic energy potential
+ Real ek = Real(0.5) * 125 * normSquare(vi); //use arbitrary constant for mass, potential adjusts with thresholds anyways
+ potKE(i, j, k) = clampPotential(ek, tauMinKE, tauMaxKE);
+} inline Grid<Real> & getArg0() {
+ return potTA; }
+ typedef Grid<Real> type0;inline Grid<Real> & getArg1() {
+ return potWC; }
+ typedef Grid<Real> type1;inline Grid<Real> & getArg2() {
+ return potKE; }
+ typedef Grid<Real> type2;inline Grid<Real> & getArg3() {
+ return neighborRatio; }
+ typedef Grid<Real> type3;inline const FlagGrid& getArg4() {
+ return flags; }
+ typedef FlagGrid type4;inline const MACGrid& getArg5() {
+ return v; }
+ typedef MACGrid type5;inline const Grid<Vec3> & getArg6() {
+ return normal; }
+ typedef Grid<Vec3> type6;inline const int& getArg7() {
+ return radius; }
+ typedef int type7;inline const Real& getArg8() {
+ return tauMinTA; }
+ typedef Real type8;inline const Real& getArg9() {
+ return tauMaxTA; }
+ typedef Real type9;inline const Real& getArg10() {
+ return tauMinWC; }
+ typedef Real type10;inline const Real& getArg11() {
+ return tauMaxWC; }
+ typedef Real type11;inline const Real& getArg12() {
+ return tauMinKE; }
+ typedef Real type12;inline const Real& getArg13() {
+ return tauMaxKE; }
+ typedef Real type13;inline const Real& getArg14() {
+ return scaleFromManta; }
+ typedef Real type14;inline const int& getArg15() {
+ return itype; }
+ typedef int type15;inline const int& getArg16() {
+ return jtype; }
+ typedef int type16; void runMessage() { debMsg("Executing kernel knFlipComputeSecondaryParticlePotentials ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=radius; j < _maxY; j++) for (int i=radius; i < _maxX; i++) op(i,j,k,potTA,potWC,potKE,neighborRatio,flags,v,normal,radius,tauMinTA,tauMaxTA,tauMinWC,tauMaxWC,tauMinKE,tauMaxKE,scaleFromManta,itype,jtype); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=radius; j < _maxY; j++) for (int i=radius; i < _maxX; i++) op(i,j,k,potTA,potWC,potKE,neighborRatio,flags,v,normal,radius,tauMinTA,tauMaxTA,tauMinWC,tauMaxWC,tauMinKE,tauMaxKE,scaleFromManta,itype,jtype); }
+ }
+ }
+ Grid<Real> & potTA; Grid<Real> & potWC; Grid<Real> & potKE; Grid<Real> & neighborRatio; const FlagGrid& flags; const MACGrid& v; const Grid<Vec3> & normal; const int radius; const Real tauMinTA; const Real tauMaxTA; const Real tauMinWC; const Real tauMaxWC; const Real tauMinKE; const Real tauMaxKE; const Real scaleFromManta; const int itype; const int jtype; }
+;
+
+
+
+
+void flipComputeSecondaryParticlePotentials( Grid<Real> &potTA, Grid<Real> &potWC, Grid<Real> &potKE, Grid<Real> &neighborRatio, const FlagGrid &flags, const MACGrid &v, Grid<Vec3>& normal, const Grid<Real>& phi, const int radius, const Real tauMinTA, const Real tauMaxTA, const Real tauMinWC, const Real tauMaxWC, const Real tauMinKE, const Real tauMaxKE, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle | FlagGrid::TypeOutflow | FlagGrid::TypeInflow) {
+ potTA.clear();
+ potWC.clear();
+ potKE.clear();
+ neighborRatio.clear();
+ GradientOp(normal, phi);
+ knFlipComputeSecondaryParticlePotentials(potTA, potWC, potKE, neighborRatio, flags, v, normal, radius, tauMinTA, tauMaxTA, tauMinWC, tauMaxWC, tauMinKE, tauMaxKE, scaleFromManta, itype, jtype);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipComputeSecondaryParticlePotentials" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & potTA = *_args.getPtr<Grid<Real> >("potTA",0,&_lock); Grid<Real> & potWC = *_args.getPtr<Grid<Real> >("potWC",1,&_lock); Grid<Real> & potKE = *_args.getPtr<Grid<Real> >("potKE",2,&_lock); Grid<Real> & neighborRatio = *_args.getPtr<Grid<Real> >("neighborRatio",3,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",4,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",5,&_lock); Grid<Vec3>& normal = *_args.getPtr<Grid<Vec3> >("normal",6,&_lock); const Grid<Real>& phi = *_args.getPtr<Grid<Real> >("phi",7,&_lock); const int radius = _args.get<int >("radius",8,&_lock); const Real tauMinTA = _args.get<Real >("tauMinTA",9,&_lock); const Real tauMaxTA = _args.get<Real >("tauMaxTA",10,&_lock); const Real tauMinWC = _args.get<Real >("tauMinWC",11,&_lock); const Real tauMaxWC = _args.get<Real >("tauMaxWC",12,&_lock); const Real tauMinKE = _args.get<Real >("tauMinKE",13,&_lock); const Real tauMaxKE = _args.get<Real >("tauMaxKE",14,&_lock); const Real scaleFromManta = _args.get<Real >("scaleFromManta",15,&_lock); const int itype = _args.getOpt<int >("itype",16,FlagGrid::TypeFluid,&_lock); const int jtype = _args.getOpt<int >("jtype",17,FlagGrid::TypeObstacle | FlagGrid::TypeOutflow | FlagGrid::TypeInflow,&_lock); _retval = getPyNone(); flipComputeSecondaryParticlePotentials(potTA,potWC,potKE,neighborRatio,flags,v,normal,phi,radius,tauMinTA,tauMaxTA,tauMinWC,tauMaxWC,tauMinKE,tauMaxKE,scaleFromManta,itype,jtype); _args.check(); }
+ pbFinalizePlugin(parent,"flipComputeSecondaryParticlePotentials", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipComputeSecondaryParticlePotentials",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipComputeSecondaryParticlePotentials ("","flipComputeSecondaryParticlePotentials",_W_0);
+extern "C" {
+ void PbRegister_flipComputeSecondaryParticlePotentials() {
+ KEEP_UNUSED(_RP_flipComputeSecondaryParticlePotentials); }
+ }
+
+
+
+// adds secondary particles to &pts_sec for every fluid cell in &flags according to the potential grids &potTA, &potWC and &potKE
+// secondary particles are uniformly sampled in every fluid cell in a randomly offset cylinder in fluid movement direction
+// In contrast to flipSampleSecondaryParticles this uses more cylinders per cell and interpolates velocity and potentials.
+// To control number of cylinders in each dimension adjust radius(0.25=>2 cyl, 0.1666=>3 cyl, 0.125=>3cyl etc.).
+
+
+
+
+
+ struct knFlipSampleSecondaryParticlesMoreCylinders : public KernelBase {
+ knFlipSampleSecondaryParticlesMoreCylinders( const FlagGrid &flags, const MACGrid &v, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const Real lMin, const Real lMax, const Grid<Real> &potTA, const Grid<Real> &potWC, const Grid<Real> &potKE, const Grid<Real> &neighborRatio, const Real c_s, const Real c_b, const Real k_ta, const Real k_wc, const Real dt, const int itype = FlagGrid::TypeFluid) : KernelBase(&flags,0) ,flags(flags),v(v),pts_sec(pts_sec),v_sec(v_sec),l_sec(l_sec),lMin(lMin),lMax(lMax),potTA(potTA),potWC(potWC),potKE(potKE),neighborRatio(neighborRatio),c_s(c_s),c_b(c_b),k_ta(k_ta),k_wc(k_wc),dt(dt),itype(itype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid &flags, const MACGrid &v, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const Real lMin, const Real lMax, const Grid<Real> &potTA, const Grid<Real> &potWC, const Grid<Real> &potKE, const Grid<Real> &neighborRatio, const Real c_s, const Real c_b, const Real k_ta, const Real k_wc, const Real dt, const int itype = FlagGrid::TypeFluid ) {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ RandomStream mRand(9832);
+ Real radius = 0.25; //diameter=0.5 => sampling with two cylinders in each dimension since cell size=1
+ for (Real x = i - radius; x <= i + radius; x += 2 * radius) {
+ for (Real y = j - radius; y <= j + radius; y += 2 * radius) {
+ for (Real z = k - radius; z <= k + radius; z += 2 * radius) {
+
+ Vec3 xi = Vec3(x, y, z);
+ Real KE = potKE.getInterpolated(xi);
+ Real TA = potTA.getInterpolated(xi);
+ Real WC = potWC.getInterpolated(xi);
+
+ const int n = KE * (k_ta*TA + k_wc*WC) * dt; //number of secondary particles
+ if (n == 0) continue;
+ Vec3 vi = v.getInterpolated(xi);
+ Vec3 dir = dt*vi; //direction of movement of current particle
+ Vec3 e1 = getNormalized(Vec3(dir.z, 0, -dir.x)); //perpendicular to dir
+ Vec3 e2 = getNormalized(cross(e1, dir)); //perpendicular to dir and e1, so e1 and e1 create reference plane
+
+ for (int di = 0; di < n; di++) {
+ const Real r = radius * sqrt(mRand.getReal()); //distance to cylinder axis
+ const Real theta = mRand.getReal() * Real(2) * M_PI; //azimuth
+ const Real h = mRand.getReal() * norm(dt*vi); //distance to reference plane
+ Vec3 xd = xi + r*cos(theta)*e1 + r*sin(theta)*e2 + h*getNormalized(vi);
+ if (!flags.is3D()) xd.z = 0;
+ pts_sec.add(xd);
+
+ v_sec[v_sec.size() - 1] = r*cos(theta)*e1 + r*sin(theta)*e2 + vi; //init velocity of new particle
+ Real temp = (KE + TA + WC) / 3;
+ l_sec[l_sec.size() - 1] = ((lMax - lMin) * temp) + lMin + mRand.getReal()*0.1; //init lifetime of new particle
+
+ //init type of new particle
+ if (neighborRatio(i, j, k) < c_s) { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PSPRAY; }
+ else if (neighborRatio(i, j, k) > c_b) { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PBUBBLE; }
+ else { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PFOAM; }
+ }
+ }
+ }
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return v; }
+ typedef MACGrid type1;inline BasicParticleSystem& getArg2() {
+ return pts_sec; }
+ typedef BasicParticleSystem type2;inline ParticleDataImpl<Vec3> & getArg3() {
+ return v_sec; }
+ typedef ParticleDataImpl<Vec3> type3;inline ParticleDataImpl<Real> & getArg4() {
+ return l_sec; }
+ typedef ParticleDataImpl<Real> type4;inline const Real& getArg5() {
+ return lMin; }
+ typedef Real type5;inline const Real& getArg6() {
+ return lMax; }
+ typedef Real type6;inline const Grid<Real> & getArg7() {
+ return potTA; }
+ typedef Grid<Real> type7;inline const Grid<Real> & getArg8() {
+ return potWC; }
+ typedef Grid<Real> type8;inline const Grid<Real> & getArg9() {
+ return potKE; }
+ typedef Grid<Real> type9;inline const Grid<Real> & getArg10() {
+ return neighborRatio; }
+ typedef Grid<Real> type10;inline const Real& getArg11() {
+ return c_s; }
+ typedef Real type11;inline const Real& getArg12() {
+ return c_b; }
+ typedef Real type12;inline const Real& getArg13() {
+ return k_ta; }
+ typedef Real type13;inline const Real& getArg14() {
+ return k_wc; }
+ typedef Real type14;inline const Real& getArg15() {
+ return dt; }
+ typedef Real type15;inline const int& getArg16() {
+ return itype; }
+ typedef int type16; void runMessage() { debMsg("Executing kernel knFlipSampleSecondaryParticlesMoreCylinders ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=0; j< _maxY; j++) for (int i=0; i< _maxX; i++) op(i,j,k, flags,v,pts_sec,v_sec,l_sec,lMin,lMax,potTA,potWC,potKE,neighborRatio,c_s,c_b,k_ta,k_wc,dt,itype); }
+ const FlagGrid& flags; const MACGrid& v; BasicParticleSystem& pts_sec; ParticleDataImpl<Vec3> & v_sec; ParticleDataImpl<Real> & l_sec; const Real lMin; const Real lMax; const Grid<Real> & potTA; const Grid<Real> & potWC; const Grid<Real> & potKE; const Grid<Real> & neighborRatio; const Real c_s; const Real c_b; const Real k_ta; const Real k_wc; const Real dt; const int itype; }
+;
+
+// adds secondary particles to &pts_sec for every fluid cell in &flags according to the potential grids &potTA, &potWC and &potKE
+// secondary particles are uniformly sampled in every fluid cell in a randomly offset cylinder in fluid movement direction
+
+
+
+
+
+ struct knFlipSampleSecondaryParticles : public KernelBase {
+ knFlipSampleSecondaryParticles( const FlagGrid &flags, const MACGrid &v, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const Real lMin, const Real lMax, const Grid<Real> &potTA, const Grid<Real> &potWC, const Grid<Real> &potKE, const Grid<Real> &neighborRatio, const Real c_s, const Real c_b, const Real k_ta, const Real k_wc, const Real dt, const int itype = FlagGrid::TypeFluid) : KernelBase(&flags,0) ,flags(flags),v(v),pts_sec(pts_sec),v_sec(v_sec),l_sec(l_sec),lMin(lMin),lMax(lMax),potTA(potTA),potWC(potWC),potKE(potKE),neighborRatio(neighborRatio),c_s(c_s),c_b(c_b),k_ta(k_ta),k_wc(k_wc),dt(dt),itype(itype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid &flags, const MACGrid &v, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const Real lMin, const Real lMax, const Grid<Real> &potTA, const Grid<Real> &potWC, const Grid<Real> &potKE, const Grid<Real> &neighborRatio, const Real c_s, const Real c_b, const Real k_ta, const Real k_wc, const Real dt, const int itype = FlagGrid::TypeFluid ) {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ Real KE = potKE(i, j, k);
+ Real TA = potTA(i, j, k);
+ Real WC = potWC(i, j, k);
+
+ const int n = KE * (k_ta*TA + k_wc*WC) * dt; //number of secondary particles
+ if (n == 0) return;
+ RandomStream mRand(9832);
+
+ Vec3 xi = Vec3(i + mRand.getReal(), j + mRand.getReal(), k + mRand.getReal()); //randomized offset uniform in cell
+ Vec3 vi = v.getInterpolated(xi);
+ Vec3 dir = dt*vi; //direction of movement of current particle
+ Vec3 e1 = getNormalized(Vec3(dir.z, 0, -dir.x)); //perpendicular to dir
+ Vec3 e2 = getNormalized(cross(e1, dir)); //perpendicular to dir and e1, so e1 and e1 create reference plane
+
+ for (int di = 0; di < n; di++) {
+ const Real r = Real(0.5) * sqrt(mRand.getReal()); //distance to cylinder axis
+ const Real theta = mRand.getReal() * Real(2) * M_PI; //azimuth
+ const Real h = mRand.getReal() * norm(dt*vi); //distance to reference plane
+ Vec3 xd = xi + r*cos(theta)*e1 + r*sin(theta)*e2 + h*getNormalized(vi);
+ if (!flags.is3D()) xd.z = 0;
+ pts_sec.add(xd);
+
+ v_sec[v_sec.size() - 1] = r*cos(theta)*e1 + r*sin(theta)*e2 + vi; //init velocity of new particle
+ Real temp = (KE + TA + WC) / 3;
+ l_sec[l_sec.size() - 1] = ((lMax - lMin) * temp) + lMin + mRand.getReal()*0.1; //init lifetime of new particle
+
+ //init type of new particle
+ if (neighborRatio(i, j, k) < c_s) { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PSPRAY; }
+ else if (neighborRatio(i, j, k) > c_b) { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PBUBBLE; }
+ else { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PFOAM; }
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return v; }
+ typedef MACGrid type1;inline BasicParticleSystem& getArg2() {
+ return pts_sec; }
+ typedef BasicParticleSystem type2;inline ParticleDataImpl<Vec3> & getArg3() {
+ return v_sec; }
+ typedef ParticleDataImpl<Vec3> type3;inline ParticleDataImpl<Real> & getArg4() {
+ return l_sec; }
+ typedef ParticleDataImpl<Real> type4;inline const Real& getArg5() {
+ return lMin; }
+ typedef Real type5;inline const Real& getArg6() {
+ return lMax; }
+ typedef Real type6;inline const Grid<Real> & getArg7() {
+ return potTA; }
+ typedef Grid<Real> type7;inline const Grid<Real> & getArg8() {
+ return potWC; }
+ typedef Grid<Real> type8;inline const Grid<Real> & getArg9() {
+ return potKE; }
+ typedef Grid<Real> type9;inline const Grid<Real> & getArg10() {
+ return neighborRatio; }
+ typedef Grid<Real> type10;inline const Real& getArg11() {
+ return c_s; }
+ typedef Real type11;inline const Real& getArg12() {
+ return c_b; }
+ typedef Real type12;inline const Real& getArg13() {
+ return k_ta; }
+ typedef Real type13;inline const Real& getArg14() {
+ return k_wc; }
+ typedef Real type14;inline const Real& getArg15() {
+ return dt; }
+ typedef Real type15;inline const int& getArg16() {
+ return itype; }
+ typedef int type16; void runMessage() { debMsg("Executing kernel knFlipSampleSecondaryParticles ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=0; j< _maxY; j++) for (int i=0; i< _maxX; i++) op(i,j,k, flags,v,pts_sec,v_sec,l_sec,lMin,lMax,potTA,potWC,potKE,neighborRatio,c_s,c_b,k_ta,k_wc,dt,itype); }
+ const FlagGrid& flags; const MACGrid& v; BasicParticleSystem& pts_sec; ParticleDataImpl<Vec3> & v_sec; ParticleDataImpl<Real> & l_sec; const Real lMin; const Real lMax; const Grid<Real> & potTA; const Grid<Real> & potWC; const Grid<Real> & potKE; const Grid<Real> & neighborRatio; const Real c_s; const Real c_b; const Real k_ta; const Real k_wc; const Real dt; const int itype; }
+;
+
+
+
+
+
+void flipSampleSecondaryParticles( const std::string mode, const FlagGrid &flags, const MACGrid &v, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const Real lMin, const Real lMax, const Grid<Real> &potTA, const Grid<Real> &potWC, const Grid<Real> &potKE, const Grid<Real> &neighborRatio, const Real c_s, const Real c_b, const Real k_ta, const Real k_wc, const Real dt, const int itype = FlagGrid::TypeFluid) {
+ if (mode == "single") {
+ knFlipSampleSecondaryParticles(flags, v, pts_sec, v_sec, l_sec, lMin, lMax, potTA, potWC, potKE, neighborRatio, c_s, c_b, k_ta, k_wc, dt, itype);
+ }
+ else if (mode == "multiple") {
+ knFlipSampleSecondaryParticlesMoreCylinders(flags, v, pts_sec, v_sec, l_sec, lMin, lMax, potTA, potWC, potKE, neighborRatio, c_s, c_b, k_ta, k_wc, dt, itype);
+ }
+ else {
+ throw std::invalid_argument("Unknown mode: use \"single\" or \"multiple\" instead!");
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipSampleSecondaryParticles" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string mode = _args.get<std::string >("mode",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",2,&_lock); BasicParticleSystem& pts_sec = *_args.getPtr<BasicParticleSystem >("pts_sec",3,&_lock); ParticleDataImpl<Vec3> & v_sec = *_args.getPtr<ParticleDataImpl<Vec3> >("v_sec",4,&_lock); ParticleDataImpl<Real> & l_sec = *_args.getPtr<ParticleDataImpl<Real> >("l_sec",5,&_lock); const Real lMin = _args.get<Real >("lMin",6,&_lock); const Real lMax = _args.get<Real >("lMax",7,&_lock); const Grid<Real> & potTA = *_args.getPtr<Grid<Real> >("potTA",8,&_lock); const Grid<Real> & potWC = *_args.getPtr<Grid<Real> >("potWC",9,&_lock); const Grid<Real> & potKE = *_args.getPtr<Grid<Real> >("potKE",10,&_lock); const Grid<Real> & neighborRatio = *_args.getPtr<Grid<Real> >("neighborRatio",11,&_lock); const Real c_s = _args.get<Real >("c_s",12,&_lock); const Real c_b = _args.get<Real >("c_b",13,&_lock); const Real k_ta = _args.get<Real >("k_ta",14,&_lock); const Real k_wc = _args.get<Real >("k_wc",15,&_lock); const Real dt = _args.get<Real >("dt",16,&_lock); const int itype = _args.getOpt<int >("itype",17,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); flipSampleSecondaryParticles(mode,flags,v,pts_sec,v_sec,l_sec,lMin,lMax,potTA,potWC,potKE,neighborRatio,c_s,c_b,k_ta,k_wc,dt,itype); _args.check(); }
+ pbFinalizePlugin(parent,"flipSampleSecondaryParticles", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipSampleSecondaryParticles",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipSampleSecondaryParticles ("","flipSampleSecondaryParticles",_W_1);
+extern "C" {
+ void PbRegister_flipSampleSecondaryParticles() {
+ KEEP_UNUSED(_RP_flipSampleSecondaryParticles); }
+ }
+
+
+
+
+
+
+// evaluates cubic spline with radius h and distance l in dim dimensions
+Real cubicSpline(const Real h, const Real l, const int dim) {
+ const Real h2 = square(h), h3 = h2*h, h4 = h3*h, h5 = h4*h;
+ const Real c[] = { Real(2e0 / (3e0*h)), Real(10e0 / (7e0*M_PI*h2)), Real(1e0 / (M_PI*h3)) };
+ const Real q = l / h;
+ if (q<1e0) return c[dim - 1] * (1e0 - 1.5*square(q) + 0.75*cubed(q));
+ else if (q<2e0) return c[dim - 1] * (0.25*cubed(2e0 - q));
+ return 0;
+}
+
+
+// updates position &pts_sec.pos and velocity &v_sec of secondary particles according to the particle type determined by the neighbor ratio with linear interpolation
+
+
+
+
+ struct knFlipUpdateSecondaryParticlesLinear : public KernelBase {
+ knFlipUpdateSecondaryParticlesLinear( BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const ParticleDataImpl<Vec3> &f_sec, const FlagGrid &flags, const MACGrid &v, const Grid<Real> &neighborRatio, const Vec3 gravity, const Real k_b, const Real k_d, const Real c_s, const Real c_b, const Real dt, const int exclude, const int antitunneling) : KernelBase(pts_sec.size()) ,pts_sec(pts_sec),v_sec(v_sec),l_sec(l_sec),f_sec(f_sec),flags(flags),v(v),neighborRatio(neighborRatio),gravity(gravity),k_b(k_b),k_d(k_d),c_s(c_s),c_b(c_b),dt(dt),exclude(exclude),antitunneling(antitunneling) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const ParticleDataImpl<Vec3> &f_sec, const FlagGrid &flags, const MACGrid &v, const Grid<Real> &neighborRatio, const Vec3 gravity, const Real k_b, const Real k_d, const Real c_s, const Real c_b, const Real dt, const int exclude, const int antitunneling ) {
+
+ if (!pts_sec.isActive(idx) || pts_sec[idx].flag & exclude) return;
+ if (!flags.isInBounds(pts_sec[idx].pos)) {
+ pts_sec.kill(idx);
+ return;
+ }
+
+ Vec3i gridpos = toVec3i(pts_sec[idx].pos);
+ int i = gridpos.x;
+ int j = gridpos.y;
+ int k = gridpos.z;
+
+ //spray particle
+ if (neighborRatio(gridpos) < c_s) {
+ pts_sec[idx].flag |= ParticleBase::PSPRAY;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PFOAM);
+ v_sec[idx] += dt * ((f_sec[idx] / 1) + gravity); //TODO: if forces are added (e.g. fluid guiding), add parameter for mass instead of 1
+
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ //air bubble particle
+ else if (neighborRatio(gridpos) > c_b) {
+ pts_sec[idx].flag |= ParticleBase::PBUBBLE;
+ pts_sec[idx].flag &= ~(ParticleBase::PSPRAY | ParticleBase::PFOAM);
+
+ const Vec3 vj = (v.getInterpolated(pts_sec[idx].pos) - v_sec[idx]) / dt;
+ v_sec[idx] += dt * (k_b * -gravity + k_d * vj);
+
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ //foam particle
+ else {
+ pts_sec[idx].flag |= ParticleBase::PFOAM;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PSPRAY);
+
+ const Vec3 vj = v.getInterpolated(pts_sec[idx].pos);
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * vj);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v.getInterpolated(pts_sec[idx].pos);
+ }
+
+ //lifetime
+ l_sec[idx] -= dt;
+ if (l_sec[idx] <= Real(0)) {
+ pts_sec.kill(idx);
+ }
+} inline BasicParticleSystem& getArg0() {
+ return pts_sec; }
+ typedef BasicParticleSystem type0;inline ParticleDataImpl<Vec3> & getArg1() {
+ return v_sec; }
+ typedef ParticleDataImpl<Vec3> type1;inline ParticleDataImpl<Real> & getArg2() {
+ return l_sec; }
+ typedef ParticleDataImpl<Real> type2;inline const ParticleDataImpl<Vec3> & getArg3() {
+ return f_sec; }
+ typedef ParticleDataImpl<Vec3> type3;inline const FlagGrid& getArg4() {
+ return flags; }
+ typedef FlagGrid type4;inline const MACGrid& getArg5() {
+ return v; }
+ typedef MACGrid type5;inline const Grid<Real> & getArg6() {
+ return neighborRatio; }
+ typedef Grid<Real> type6;inline const Vec3& getArg7() {
+ return gravity; }
+ typedef Vec3 type7;inline const Real& getArg8() {
+ return k_b; }
+ typedef Real type8;inline const Real& getArg9() {
+ return k_d; }
+ typedef Real type9;inline const Real& getArg10() {
+ return c_s; }
+ typedef Real type10;inline const Real& getArg11() {
+ return c_b; }
+ typedef Real type11;inline const Real& getArg12() {
+ return dt; }
+ typedef Real type12;inline const int& getArg13() {
+ return exclude; }
+ typedef int type13;inline const int& getArg14() {
+ return antitunneling; }
+ typedef int type14; void runMessage() { debMsg("Executing kernel knFlipUpdateSecondaryParticlesLinear ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,pts_sec,v_sec,l_sec,f_sec,flags,v,neighborRatio,gravity,k_b,k_d,c_s,c_b,dt,exclude,antitunneling); }
+ }
+ BasicParticleSystem& pts_sec; ParticleDataImpl<Vec3> & v_sec; ParticleDataImpl<Real> & l_sec; const ParticleDataImpl<Vec3> & f_sec; const FlagGrid& flags; const MACGrid& v; const Grid<Real> & neighborRatio; const Vec3 gravity; const Real k_b; const Real k_d; const Real c_s; const Real c_b; const Real dt; const int exclude; const int antitunneling; }
+;
+// updates position &pts_sec.pos and velocity &v_sec of secondary particles according to the particle type determined by the neighbor ratio with cubic spline interpolation
+
+
+
+
+
+ struct knFlipUpdateSecondaryParticlesCubic : public KernelBase {
+ knFlipUpdateSecondaryParticlesCubic( BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const ParticleDataImpl<Vec3> &f_sec, const FlagGrid &flags, const MACGrid &v, const Grid<Real> &neighborRatio, const int radius, const Vec3 gravity, const Real k_b, const Real k_d, const Real c_s, const Real c_b, const Real dt, const int exclude, const int antitunneling, const int itype) : KernelBase(pts_sec.size()) ,pts_sec(pts_sec),v_sec(v_sec),l_sec(l_sec),f_sec(f_sec),flags(flags),v(v),neighborRatio(neighborRatio),radius(radius),gravity(gravity),k_b(k_b),k_d(k_d),c_s(c_s),c_b(c_b),dt(dt),exclude(exclude),antitunneling(antitunneling),itype(itype) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const ParticleDataImpl<Vec3> &f_sec, const FlagGrid &flags, const MACGrid &v, const Grid<Real> &neighborRatio, const int radius, const Vec3 gravity, const Real k_b, const Real k_d, const Real c_s, const Real c_b, const Real dt, const int exclude, const int antitunneling, const int itype ) {
+
+ if (!pts_sec.isActive(idx) || pts_sec[idx].flag & exclude) return;
+ if (!flags.isInBounds(pts_sec[idx].pos)) {
+ pts_sec.kill(idx);
+ return;
+ }
+
+ Vec3i gridpos = toVec3i(pts_sec[idx].pos);
+ int i = gridpos.x;
+ int j = gridpos.y;
+ int k = gridpos.z;
+
+ //spray particle
+ if (neighborRatio(gridpos) < c_s) {
+ pts_sec[idx].flag |= ParticleBase::PSPRAY;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PFOAM);
+ v_sec[idx] += dt * ((f_sec[idx] / 1) + gravity); //TODO: if forces are added (e.g. fluid guiding), add parameter for mass instead of 1
+
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ //air bubble particle
+ else if (neighborRatio(gridpos) > c_b) {
+ pts_sec[idx].flag |= ParticleBase::PBUBBLE;
+ pts_sec[idx].flag &= ~(ParticleBase::PSPRAY | ParticleBase::PFOAM);
+ const Vec3 &xi = pts_sec[idx].pos;
+ Vec3 sumNumerator = Vec3(0, 0, 0);
+ Real sumDenominator = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ Vec3i xj = Vec3i(x, y, z);
+ if ((x == i && y == j && z == k) || !flags.isInBounds(xj)) continue;
+ if (!(flags(xj) & itype)) continue;
+ const Real len_xij = norm(xi - Vec3(x, y, z));
+
+ int dim = flags.is3D() ? 3 : 2;
+ Real dist = flags.is3D() ? 1.732 : 1.414;
+ Real weight = cubicSpline(radius * dist, len_xij, dim);
+ sumNumerator += v.getCentered(xj) * weight; //estimate next position by current velocity
+ sumDenominator += weight;
+ }
+ }
+ }
+ const Vec3 temp = ((sumNumerator / sumDenominator) - v_sec[idx]) / dt;
+ v_sec[idx] += dt * (k_b * -gravity + k_d * temp);
+
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ //foam particle
+ else {
+ pts_sec[idx].flag |= ParticleBase::PFOAM;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PSPRAY);
+ const Vec3 &xi = pts_sec[idx].pos;
+ Vec3 sumNumerator = Vec3(0, 0, 0);
+ Real sumDenominator = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ Vec3i xj = Vec3i(x, y, z);
+ if ((x == i && y == j && z == k) || !flags.isInBounds(xj)) continue;
+ if (!(flags(xj) & itype)) continue;
+ const Real len_xij = norm(xi - Vec3(x, y, z));
+
+ int dim = flags.is3D() ? 3 : 2;
+ Real dist = flags.is3D() ? 1.732 : 1.414;
+ Real weight = cubicSpline(radius * dist, len_xij, dim);
+ sumNumerator += v.getCentered(xj) * weight; //estimate next position by current velocity
+ sumDenominator += weight;
+ }
+ }
+ }
+
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * (sumNumerator / sumDenominator));
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * (sumNumerator / sumDenominator);
+ }
+
+ //lifetime
+ l_sec[idx] -= dt;
+ if (l_sec[idx] <= Real(0)) {
+ pts_sec.kill(idx);
+ }
+} inline BasicParticleSystem& getArg0() {
+ return pts_sec; }
+ typedef BasicParticleSystem type0;inline ParticleDataImpl<Vec3> & getArg1() {
+ return v_sec; }
+ typedef ParticleDataImpl<Vec3> type1;inline ParticleDataImpl<Real> & getArg2() {
+ return l_sec; }
+ typedef ParticleDataImpl<Real> type2;inline const ParticleDataImpl<Vec3> & getArg3() {
+ return f_sec; }
+ typedef ParticleDataImpl<Vec3> type3;inline const FlagGrid& getArg4() {
+ return flags; }
+ typedef FlagGrid type4;inline const MACGrid& getArg5() {
+ return v; }
+ typedef MACGrid type5;inline const Grid<Real> & getArg6() {
+ return neighborRatio; }
+ typedef Grid<Real> type6;inline const int& getArg7() {
+ return radius; }
+ typedef int type7;inline const Vec3& getArg8() {
+ return gravity; }
+ typedef Vec3 type8;inline const Real& getArg9() {
+ return k_b; }
+ typedef Real type9;inline const Real& getArg10() {
+ return k_d; }
+ typedef Real type10;inline const Real& getArg11() {
+ return c_s; }
+ typedef Real type11;inline const Real& getArg12() {
+ return c_b; }
+ typedef Real type12;inline const Real& getArg13() {
+ return dt; }
+ typedef Real type13;inline const int& getArg14() {
+ return exclude; }
+ typedef int type14;inline const int& getArg15() {
+ return antitunneling; }
+ typedef int type15;inline const int& getArg16() {
+ return itype; }
+ typedef int type16; void runMessage() { debMsg("Executing kernel knFlipUpdateSecondaryParticlesCubic ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,pts_sec,v_sec,l_sec,f_sec,flags,v,neighborRatio,radius,gravity,k_b,k_d,c_s,c_b,dt,exclude,antitunneling,itype); }
+ }
+ BasicParticleSystem& pts_sec; ParticleDataImpl<Vec3> & v_sec; ParticleDataImpl<Real> & l_sec; const ParticleDataImpl<Vec3> & f_sec; const FlagGrid& flags; const MACGrid& v; const Grid<Real> & neighborRatio; const int radius; const Vec3 gravity; const Real k_b; const Real k_d; const Real c_s; const Real c_b; const Real dt; const int exclude; const int antitunneling; const int itype; }
+;
+
+
+
+
+
+void flipUpdateSecondaryParticles( const std::string mode, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const ParticleDataImpl<Vec3> &f_sec, FlagGrid &flags, const MACGrid &v, const Grid<Real> &neighborRatio, const int radius, const Vec3 gravity, const Real k_b, const Real k_d, const Real c_s, const Real c_b, const Real dt, const int exclude = ParticleBase::PTRACER, const int antitunneling=0, const int itype = FlagGrid::TypeFluid) {
+
+ Vec3 g = gravity / flags.getDx();
+ if (mode == "linear") {
+ knFlipUpdateSecondaryParticlesLinear(pts_sec, v_sec, l_sec, f_sec, flags, v, neighborRatio, g, k_b, k_d, c_s, c_b, dt, exclude, antitunneling);
+ }
+ else if (mode == "cubic") {
+ knFlipUpdateSecondaryParticlesCubic(pts_sec, v_sec, l_sec, f_sec, flags, v, neighborRatio, radius, g, k_b, k_d, c_s, c_b, dt, exclude, antitunneling, itype);
+ }
+ else {
+ throw std::invalid_argument("Unknown mode: use \"linear\" or \"cubic\" instead!");
+ }
+ pts_sec.doCompress();
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipUpdateSecondaryParticles" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string mode = _args.get<std::string >("mode",0,&_lock); BasicParticleSystem& pts_sec = *_args.getPtr<BasicParticleSystem >("pts_sec",1,&_lock); ParticleDataImpl<Vec3> & v_sec = *_args.getPtr<ParticleDataImpl<Vec3> >("v_sec",2,&_lock); ParticleDataImpl<Real> & l_sec = *_args.getPtr<ParticleDataImpl<Real> >("l_sec",3,&_lock); const ParticleDataImpl<Vec3> & f_sec = *_args.getPtr<ParticleDataImpl<Vec3> >("f_sec",4,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",5,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",6,&_lock); const Grid<Real> & neighborRatio = *_args.getPtr<Grid<Real> >("neighborRatio",7,&_lock); const int radius = _args.get<int >("radius",8,&_lock); const Vec3 gravity = _args.get<Vec3 >("gravity",9,&_lock); const Real k_b = _args.get<Real >("k_b",10,&_lock); const Real k_d = _args.get<Real >("k_d",11,&_lock); const Real c_s = _args.get<Real >("c_s",12,&_lock); const Real c_b = _args.get<Real >("c_b",13,&_lock); const Real dt = _args.get<Real >("dt",14,&_lock); const int exclude = _args.getOpt<int >("exclude",15,ParticleBase::PTRACER,&_lock); const int antitunneling = _args.getOpt<int >("antitunneling",16,0,&_lock); const int itype = _args.getOpt<int >("itype",17,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); flipUpdateSecondaryParticles(mode,pts_sec,v_sec,l_sec,f_sec,flags,v,neighborRatio,radius,gravity,k_b,k_d,c_s,c_b,dt,exclude,antitunneling,itype); _args.check(); }
+ pbFinalizePlugin(parent,"flipUpdateSecondaryParticles", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipUpdateSecondaryParticles",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipUpdateSecondaryParticles ("","flipUpdateSecondaryParticles",_W_2);
+extern "C" {
+ void PbRegister_flipUpdateSecondaryParticles() {
+ KEEP_UNUSED(_RP_flipUpdateSecondaryParticles); }
+ }
+
+
+
+
+// removes secondary particles in &pts_sec that are inside boundaries (cells that are marked as obstacle/outflow in &flags)
+
+
+ struct knFlipDeleteParticlesInObstacle : public KernelBase {
+ knFlipDeleteParticlesInObstacle( BasicParticleSystem &pts, const FlagGrid &flags) : KernelBase(pts.size()) ,pts(pts),flags(flags) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystem &pts, const FlagGrid &flags ) {
+
+ if (!pts.isActive(idx)) return;
+
+ const Vec3 &xi = pts[idx].pos;
+ const Vec3i xidx = toVec3i(xi);
+ //remove particles that completely left the bounds
+ if (!flags.isInBounds(xidx)) {
+ pts.kill(idx);
+ return;
+ }
+ int gridIndex = flags.index(xidx);
+ //remove particles that penetrate obstacles
+ if (flags[gridIndex] == FlagGrid::TypeObstacle || flags[gridIndex] == FlagGrid::TypeOutflow) {
+ pts.kill(idx);
+ }
+} inline BasicParticleSystem& getArg0() {
+ return pts; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1; void runMessage() { debMsg("Executing kernel knFlipDeleteParticlesInObstacle ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,pts,flags); }
+ }
+ BasicParticleSystem& pts; const FlagGrid& flags; }
+;
+
+
+void flipDeleteParticlesInObstacle( BasicParticleSystem &pts, const FlagGrid &flags) {
+
+ knFlipDeleteParticlesInObstacle(pts, flags);
+ pts.doCompress();
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipDeleteParticlesInObstacle" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem& pts = *_args.getPtr<BasicParticleSystem >("pts",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); _retval = getPyNone(); flipDeleteParticlesInObstacle(pts,flags); _args.check(); }
+ pbFinalizePlugin(parent,"flipDeleteParticlesInObstacle", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipDeleteParticlesInObstacle",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipDeleteParticlesInObstacle ("","flipDeleteParticlesInObstacle",_W_3);
+extern "C" {
+ void PbRegister_flipDeleteParticlesInObstacle() {
+ KEEP_UNUSED(_RP_flipDeleteParticlesInObstacle); }
+ }
+
+
+
+//helper method to debug statistical data from grid
+
+
+void debugGridInfo( const FlagGrid &flags, Grid<Real> &grid, std::string name, const int itype = FlagGrid::TypeFluid) {
+ FluidSolver* s = flags.getParent();
+ int countFluid = 0;
+ int countLargerZero = 0;
+ Real avg = 0;
+ Real max = 0;
+ Real sum = 0;
+ Real avgLargerZero = 0;
+ FOR_IJK_BND(grid, 1) {
+ if (!(flags(i, j, k) & itype)) continue;
+ countFluid++;
+ if (grid(i, j, k) > 0) countLargerZero++;
+ sum += grid(i, j, k);
+ if (grid(i, j, k) > max) max = grid(i, j, k);
+ }
+ avg = sum / std::max(Real(countFluid), Real(1));
+ avgLargerZero = sum / std::max(Real(countLargerZero), Real(1));
+
+ debMsg("Step: " << s->mFrame << " - Grid " << name <<
+ "\n\tcountFluid \t\t" << countFluid <<
+ "\n\tcountLargerZero \t" << countLargerZero <<
+ "\n\tsum \t\t\t" << sum <<
+ "\n\tavg \t\t\t" << avg <<
+ "\n\tavgLargerZero \t\t" << avgLargerZero <<
+ "\n\tmax \t\t\t" << max, 1);
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "debugGridInfo" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real> & grid = *_args.getPtr<Grid<Real> >("grid",1,&_lock); std::string name = _args.get<std::string >("name",2,&_lock); const int itype = _args.getOpt<int >("itype",3,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); debugGridInfo(flags,grid,name,itype); _args.check(); }
+ pbFinalizePlugin(parent,"debugGridInfo", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("debugGridInfo",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_debugGridInfo ("","debugGridInfo",_W_4);
+extern "C" {
+ void PbRegister_debugGridInfo() {
+ KEEP_UNUSED(_RP_debugGridInfo); }
+ }
+
+
+
+
+
+// The following methods are helper functions to recreate the velocity and flag grid from the underlying FLIP simulation.
+// They cannot simply be loaded because of the upres to a higher resolution, instead a levelset is used.
+
+
+ struct knSetFlagsFromLevelset : public KernelBase {
+ knSetFlagsFromLevelset( FlagGrid &flags, const Grid<Real> &phi, const int exclude = FlagGrid::TypeObstacle, const int itype = FlagGrid::TypeFluid) : KernelBase(&flags,0) ,flags(flags),phi(phi),exclude(exclude),itype(itype) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, FlagGrid &flags, const Grid<Real> &phi, const int exclude = FlagGrid::TypeObstacle, const int itype = FlagGrid::TypeFluid ) {
+ if (phi(idx) < 0 && !(flags(idx) & exclude)) flags(idx) = itype;
+
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const Grid<Real> & getArg1() {
+ return phi; }
+ typedef Grid<Real> type1;inline const int& getArg2() {
+ return exclude; }
+ typedef int type2;inline const int& getArg3() {
+ return itype; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel knSetFlagsFromLevelset ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,flags,phi,exclude,itype); }
+ }
+ FlagGrid& flags; const Grid<Real> & phi; const int exclude; const int itype; }
+;
+
+
+void setFlagsFromLevelset( FlagGrid &flags, const Grid<Real> &phi, const int exclude = FlagGrid::TypeObstacle, const int itype = FlagGrid::TypeFluid) {
+ knSetFlagsFromLevelset(flags, phi, exclude, itype);
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setFlagsFromLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const Grid<Real> & phi = *_args.getPtr<Grid<Real> >("phi",1,&_lock); const int exclude = _args.getOpt<int >("exclude",2,FlagGrid::TypeObstacle,&_lock); const int itype = _args.getOpt<int >("itype",3,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); setFlagsFromLevelset(flags,phi,exclude,itype); _args.check(); }
+ pbFinalizePlugin(parent,"setFlagsFromLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setFlagsFromLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setFlagsFromLevelset ("","setFlagsFromLevelset",_W_5);
+extern "C" {
+ void PbRegister_setFlagsFromLevelset() {
+ KEEP_UNUSED(_RP_setFlagsFromLevelset); }
+ }
+
+
+
+
+
+ struct knSetMACFromLevelset : public KernelBase {
+ knSetMACFromLevelset( MACGrid &v, const Grid<Real> &phi, const Vec3 c) : KernelBase(&v,0) ,v(v),phi(phi),c(c) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid &v, const Grid<Real> &phi, const Vec3 c ) {
+ if (phi.getInterpolated(Vec3(i, j, k)) > 0) v(i, j, k) = c;
+} inline MACGrid& getArg0() {
+ return v; }
+ typedef MACGrid type0;inline const Grid<Real> & getArg1() {
+ return phi; }
+ typedef Grid<Real> type1;inline const Vec3& getArg2() {
+ return c; }
+ typedef Vec3 type2; void runMessage() { debMsg("Executing kernel knSetMACFromLevelset ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,v,phi,c); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,v,phi,c); }
+ }
+ }
+ MACGrid& v; const Grid<Real> & phi; const Vec3 c; }
+;
+
+
+void setMACFromLevelset( MACGrid &v, const Grid<Real> &phi, const Vec3 c) {
+ knSetMACFromLevelset(v, phi, c);
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setMACFromLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& v = *_args.getPtr<MACGrid >("v",0,&_lock); const Grid<Real> & phi = *_args.getPtr<Grid<Real> >("phi",1,&_lock); const Vec3 c = _args.get<Vec3 >("c",2,&_lock); _retval = getPyNone(); setMACFromLevelset(v,phi,c); _args.check(); }
+ pbFinalizePlugin(parent,"setMACFromLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setMACFromLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setMACFromLevelset ("","setMACFromLevelset",_W_6);
+extern "C" {
+ void PbRegister_setMACFromLevelset() {
+ KEEP_UNUSED(_RP_setMACFromLevelset); }
+ }
+
+
+
+
+
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+// END Secondary Particles for FLIP
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+#pragma endregion
+
+
+
+#pragma region Legacy Methods (still useful for debugging)
+//----------------------------------------------------------------------------------------------------------------------------------- -----------------
+// Legacy Methods (still useful for debugging)
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes trapped air potential for all fluid cells in &flags and saves it in &pot
+
+
+
+
+
+ struct knFlipComputePotentialTrappedAir : public KernelBase {
+ knFlipComputePotentialTrappedAir( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid) : KernelBase(&pot,1) ,pot(pot),flags(flags),v(v),radius(radius),tauMin(tauMin),tauMax(tauMax),scaleFromManta(scaleFromManta),itype(itype),jtype(jtype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid ) {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ const Vec3 &xi = scaleFromManta * Vec3(i, j, k); //scale to unit cube
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k);
+ Real vdiff = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || !(flags(x, y, z) & jtype)) continue;
+
+ const Vec3 &xj = scaleFromManta * Vec3(x, y, z); //scale to unit cube
+ const Vec3 &vj = scaleFromManta * v.getCentered(x, y, z);
+ const Vec3 xij = xi - xj;
+ const Vec3 vij = vi - vj;
+ Real h = !pot.is3D() ? 1.414*radius : 1.732*radius; //estimate sqrt(2)*radius resp. sqrt(3)*radius for h, due to squared resp. cubic neighbor area
+ vdiff += norm(vij) * (1 - dot(getNormalized(vij), getNormalized(xij))) * (1 - norm(xij) / h);
+ }
+ }
+ }
+ pot(i, j, k) = (std::min(vdiff, tauMax) - std::min(vdiff, tauMin)) / (tauMax - tauMin);
+} inline Grid<Real> & getArg0() {
+ return pot; }
+ typedef Grid<Real> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return v; }
+ typedef MACGrid type2;inline const int& getArg3() {
+ return radius; }
+ typedef int type3;inline const Real& getArg4() {
+ return tauMin; }
+ typedef Real type4;inline const Real& getArg5() {
+ return tauMax; }
+ typedef Real type5;inline const Real& getArg6() {
+ return scaleFromManta; }
+ typedef Real type6;inline const int& getArg7() {
+ return itype; }
+ typedef int type7;inline const int& getArg8() {
+ return jtype; }
+ typedef int type8; void runMessage() { debMsg("Executing kernel knFlipComputePotentialTrappedAir ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,pot,flags,v,radius,tauMin,tauMax,scaleFromManta,itype,jtype); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,pot,flags,v,radius,tauMin,tauMax,scaleFromManta,itype,jtype); }
+ }
+ }
+ Grid<Real> & pot; const FlagGrid& flags; const MACGrid& v; const int radius; const Real tauMin; const Real tauMax; const Real scaleFromManta; const int itype; const int jtype; }
+;
+
+
+
+
+
+void flipComputePotentialTrappedAir( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid) {
+ pot.clear();
+ knFlipComputePotentialTrappedAir(pot, flags, v, radius, tauMin, tauMax, scaleFromManta, itype, jtype);
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipComputePotentialTrappedAir" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & pot = *_args.getPtr<Grid<Real> >("pot",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",2,&_lock); const int radius = _args.get<int >("radius",3,&_lock); const Real tauMin = _args.get<Real >("tauMin",4,&_lock); const Real tauMax = _args.get<Real >("tauMax",5,&_lock); const Real scaleFromManta = _args.get<Real >("scaleFromManta",6,&_lock); const int itype = _args.getOpt<int >("itype",7,FlagGrid::TypeFluid,&_lock); const int jtype = _args.getOpt<int >("jtype",8,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); flipComputePotentialTrappedAir(pot,flags,v,radius,tauMin,tauMax,scaleFromManta,itype,jtype); _args.check(); }
+ pbFinalizePlugin(parent,"flipComputePotentialTrappedAir", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipComputePotentialTrappedAir",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipComputePotentialTrappedAir ("","flipComputePotentialTrappedAir",_W_7);
+extern "C" {
+ void PbRegister_flipComputePotentialTrappedAir() {
+ KEEP_UNUSED(_RP_flipComputePotentialTrappedAir); }
+ }
+
+
+
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes kinetic energy potential for all fluid cells in &flags and saves it in &pot
+
+
+
+
+ struct knFlipComputePotentialKineticEnergy : public KernelBase {
+ knFlipComputePotentialKineticEnergy( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid) : KernelBase(&pot,0) ,pot(pot),flags(flags),v(v),tauMin(tauMin),tauMax(tauMax),scaleFromManta(scaleFromManta),itype(itype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid ) {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k); //scale to unit cube
+ Real ek = Real(0.5) * 125 * normSquare(vi); //use arbitrary constant for mass, potential adjusts with thresholds anyways
+ pot(i, j, k) = (std::min(ek, tauMax) - std::min(ek, tauMin)) / (tauMax - tauMin);
+} inline Grid<Real> & getArg0() {
+ return pot; }
+ typedef Grid<Real> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return v; }
+ typedef MACGrid type2;inline const Real& getArg3() {
+ return tauMin; }
+ typedef Real type3;inline const Real& getArg4() {
+ return tauMax; }
+ typedef Real type4;inline const Real& getArg5() {
+ return scaleFromManta; }
+ typedef Real type5;inline const int& getArg6() {
+ return itype; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel knFlipComputePotentialKineticEnergy ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,pot,flags,v,tauMin,tauMax,scaleFromManta,itype); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,pot,flags,v,tauMin,tauMax,scaleFromManta,itype); }
+ }
+ }
+ Grid<Real> & pot; const FlagGrid& flags; const MACGrid& v; const Real tauMin; const Real tauMax; const Real scaleFromManta; const int itype; }
+;
+
+
+
+
+void flipComputePotentialKineticEnergy( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid) {
+ pot.clear();
+ knFlipComputePotentialKineticEnergy(pot, flags, v, tauMin, tauMax, scaleFromManta, itype);
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipComputePotentialKineticEnergy" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & pot = *_args.getPtr<Grid<Real> >("pot",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",2,&_lock); const Real tauMin = _args.get<Real >("tauMin",3,&_lock); const Real tauMax = _args.get<Real >("tauMax",4,&_lock); const Real scaleFromManta = _args.get<Real >("scaleFromManta",5,&_lock); const int itype = _args.getOpt<int >("itype",6,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); flipComputePotentialKineticEnergy(pot,flags,v,tauMin,tauMax,scaleFromManta,itype); _args.check(); }
+ pbFinalizePlugin(parent,"flipComputePotentialKineticEnergy", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipComputePotentialKineticEnergy",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipComputePotentialKineticEnergy ("","flipComputePotentialKineticEnergy",_W_8);
+extern "C" {
+ void PbRegister_flipComputePotentialKineticEnergy() {
+ KEEP_UNUSED(_RP_flipComputePotentialKineticEnergy); }
+ }
+
+
+
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes wave crest potential for all fluid cells in &flags and saves it in &pot
+
+
+
+
+ struct knFlipComputePotentialWaveCrest : public KernelBase {
+ knFlipComputePotentialWaveCrest( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, Grid<Vec3> &normal, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid) : KernelBase(&pot,1) ,pot(pot),flags(flags),v(v),radius(radius),normal(normal),tauMin(tauMin),tauMax(tauMax),scaleFromManta(scaleFromManta),itype(itype),jtype(jtype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, Grid<Vec3> &normal, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid ) {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ const Vec3 &xi = scaleFromManta * Vec3(i, j, k); //scale to unit cube
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k);
+ const Vec3 &ni = normal(i, j, k);
+ Real kappa = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || !(flags(x, y, z) & jtype)) continue;
+ const Vec3 &xj = scaleFromManta * Vec3(x, y, z); //scale to unit cube
+ const Vec3 &nj = normal(x, y, z);
+ const Vec3 xij = xi - xj;
+ if (dot(getNormalized(xij), ni) < 0) { //identifies wave crests
+ Real h = !pot.is3D() ? 1.414*radius : 1.732*radius; //estimate sqrt(2)*radius resp. sqrt(3)*radius for h, due to squared resp. cubic neighbor area
+ kappa += (1 - dot(ni, nj)) * (1 - norm(xij) / h);
+ }
+ }
+ }
+ }
+
+ if (dot(getNormalized(vi), ni) >= 0.6) { //avoid to mark boarders of the scene as wave crest
+ pot(i, j, k) = (std::min(kappa, tauMax) - std::min(kappa, tauMin)) / (tauMax - tauMin);
+ }
+ else {
+ pot(i, j, k) = Real(0);
+ }
+} inline Grid<Real> & getArg0() {
+ return pot; }
+ typedef Grid<Real> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return v; }
+ typedef MACGrid type2;inline const int& getArg3() {
+ return radius; }
+ typedef int type3;inline Grid<Vec3> & getArg4() {
+ return normal; }
+ typedef Grid<Vec3> type4;inline const Real& getArg5() {
+ return tauMin; }
+ typedef Real type5;inline const Real& getArg6() {
+ return tauMax; }
+ typedef Real type6;inline const Real& getArg7() {
+ return scaleFromManta; }
+ typedef Real type7;inline const int& getArg8() {
+ return itype; }
+ typedef int type8;inline const int& getArg9() {
+ return jtype; }
+ typedef int type9; void runMessage() { debMsg("Executing kernel knFlipComputePotentialWaveCrest ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,pot,flags,v,radius,normal,tauMin,tauMax,scaleFromManta,itype,jtype); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,pot,flags,v,radius,normal,tauMin,tauMax,scaleFromManta,itype,jtype); }
+ }
+ }
+ Grid<Real> & pot; const FlagGrid& flags; const MACGrid& v; const int radius; Grid<Vec3> & normal; const Real tauMin; const Real tauMax; const Real scaleFromManta; const int itype; const int jtype; }
+;
+
+
+
+
+void flipComputePotentialWaveCrest( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, Grid<Vec3> &normal, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid) {
+
+ pot.clear();
+ knFlipComputePotentialWaveCrest(pot, flags, v, radius, normal, tauMin, tauMax, scaleFromManta, itype, jtype);
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipComputePotentialWaveCrest" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & pot = *_args.getPtr<Grid<Real> >("pot",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",2,&_lock); const int radius = _args.get<int >("radius",3,&_lock); Grid<Vec3> & normal = *_args.getPtr<Grid<Vec3> >("normal",4,&_lock); const Real tauMin = _args.get<Real >("tauMin",5,&_lock); const Real tauMax = _args.get<Real >("tauMax",6,&_lock); const Real scaleFromManta = _args.get<Real >("scaleFromManta",7,&_lock); const int itype = _args.getOpt<int >("itype",8,FlagGrid::TypeFluid,&_lock); const int jtype = _args.getOpt<int >("jtype",9,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); flipComputePotentialWaveCrest(pot,flags,v,radius,normal,tauMin,tauMax,scaleFromManta,itype,jtype); _args.check(); }
+ pbFinalizePlugin(parent,"flipComputePotentialWaveCrest", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipComputePotentialWaveCrest",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipComputePotentialWaveCrest ("","flipComputePotentialWaveCrest",_W_9);
+extern "C" {
+ void PbRegister_flipComputePotentialWaveCrest() {
+ KEEP_UNUSED(_RP_flipComputePotentialWaveCrest); }
+ }
+
+
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes normal grid &normal as gradient of levelset &phi and normalizes it
+
+ struct knFlipComputeSurfaceNormals : public KernelBase {
+ knFlipComputeSurfaceNormals(Grid<Vec3>& normal, const Grid<Real>& phi) : KernelBase(&normal,0) ,normal(normal),phi(phi) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Vec3>& normal, const Grid<Real>& phi ) {
+ normal[idx] = getNormalized(normal[idx]);
+} inline Grid<Vec3>& getArg0() {
+ return normal; }
+ typedef Grid<Vec3> type0;inline const Grid<Real>& getArg1() {
+ return phi; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel knFlipComputeSurfaceNormals ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,normal,phi); }
+ }
+ Grid<Vec3>& normal; const Grid<Real>& phi; }
+;
+
+void flipComputeSurfaceNormals(Grid<Vec3>& normal, const Grid<Real>& phi) {
+ GradientOp(normal, phi);
+ knFlipComputeSurfaceNormals(normal, phi);
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipComputeSurfaceNormals" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& normal = *_args.getPtr<Grid<Vec3> >("normal",0,&_lock); const Grid<Real>& phi = *_args.getPtr<Grid<Real> >("phi",1,&_lock); _retval = getPyNone(); flipComputeSurfaceNormals(normal,phi); _args.check(); }
+ pbFinalizePlugin(parent,"flipComputeSurfaceNormals", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipComputeSurfaceNormals",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipComputeSurfaceNormals ("","flipComputeSurfaceNormals",_W_10);
+extern "C" {
+ void PbRegister_flipComputeSurfaceNormals() {
+ KEEP_UNUSED(_RP_flipComputeSurfaceNormals); }
+ }
+
+
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes the neighbor ratio for every fluid cell in &flags as the number of fluid neighbors over the maximum possible number of fluid neighbors
+
+
+
+ struct knFlipUpdateNeighborRatio : public KernelBase {
+ knFlipUpdateNeighborRatio( const FlagGrid &flags, Grid<Real> &neighborRatio, const int radius, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle) : KernelBase(&flags,1) ,flags(flags),neighborRatio(neighborRatio),radius(radius),itype(itype),jtype(jtype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid &flags, Grid<Real> &neighborRatio, const int radius, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle ) {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ int countFluid = 0;
+ int countMaxFluid = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || (flags(x, y, z) & jtype)) continue;
+ if (flags(x, y, z) & itype) {
+ countFluid++;
+ countMaxFluid++;
+ }
+ else {
+ countMaxFluid++;
+ }
+ }
+ }
+ }
+ neighborRatio(i, j, k) = float(countFluid) / float(countMaxFluid);
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real> & getArg1() {
+ return neighborRatio; }
+ typedef Grid<Real> type1;inline const int& getArg2() {
+ return radius; }
+ typedef int type2;inline const int& getArg3() {
+ return itype; }
+ typedef int type3;inline const int& getArg4() {
+ return jtype; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel knFlipUpdateNeighborRatio ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,neighborRatio,radius,itype,jtype); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,neighborRatio,radius,itype,jtype); }
+ }
+ }
+ const FlagGrid& flags; Grid<Real> & neighborRatio; const int radius; const int itype; const int jtype; }
+;
+
+
+
+void flipUpdateNeighborRatio( const FlagGrid &flags, Grid<Real> &neighborRatio, const int radius, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle) {
+
+ neighborRatio.clear();
+ knFlipUpdateNeighborRatio(flags, neighborRatio, radius, itype, jtype);
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipUpdateNeighborRatio" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real> & neighborRatio = *_args.getPtr<Grid<Real> >("neighborRatio",1,&_lock); const int radius = _args.get<int >("radius",2,&_lock); const int itype = _args.getOpt<int >("itype",3,FlagGrid::TypeFluid,&_lock); const int jtype = _args.getOpt<int >("jtype",4,FlagGrid::TypeObstacle,&_lock); _retval = getPyNone(); flipUpdateNeighborRatio(flags,neighborRatio,radius,itype,jtype); _args.check(); }
+ pbFinalizePlugin(parent,"flipUpdateNeighborRatio", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipUpdateNeighborRatio",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipUpdateNeighborRatio ("","flipUpdateNeighborRatio",_W_11);
+extern "C" {
+ void PbRegister_flipUpdateNeighborRatio() {
+ KEEP_UNUSED(_RP_flipUpdateNeighborRatio); }
+ }
+
+
+
+
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+// Legacy Methods (still useful for debugging)
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+#pragma endregion
+
+
+
+} //namespace
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/surfaceturbulence.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/surfaceturbulence.cpp
new file mode 100644
index 00000000000..d2488d2d58c
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/surfaceturbulence.cpp
@@ -0,0 +1,1500 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2016 Olivier Mercier, oli.mercier@gmail.com
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Surface Turbulence for Particle-Based Liquid Simulations
+ * Mercier et al., SIGGRAPH Asia 2015
+ *
+ * Possible speedups :
+ * - only initialize surface points around coarse particles near the surface. Use the flags in the fluid
+ * grid and only use cells with non-fluid neighbors.
+ *
+ ******************************************************************************/
+
+// use chrono stl for detailed timing only if available
+#ifdef __GNUC__
+#if __GNUC__<5
+#define USE_CHRONO 0
+#endif
+#endif
+
+#if MANTA_WITHCPP11==1
+#ifndef USE_CHRONO
+#define USE_CHRONO 1
+#endif
+#endif
+
+#include <iomanip>
+#if USE_CHRONO==1
+#include <chrono>
+#endif
+#include "particle.h"
+
+using namespace std;
+namespace Manta {
+
+// own namespace for globals
+namespace SurfaceTurbulence {
+
+
+//
+// **** surface turbulence parameters ****
+//
+struct SurfaceTurbulenceParameters {
+ int res;
+ Real outerRadius;
+ int surfaceDensity;
+ int nbSurfaceMaintenanceIterations;
+ Real dt;
+ Real waveSpeed;
+ Real waveDamping;
+ Real waveSeedFrequency;
+ Real waveMaxAmplitude;
+ Real waveMaxFrequency;
+ Real waveMaxSeedingAmplitude; // as ratio of max amp;
+ Real waveSeedingCurvatureThresholdRegionCenter;
+ Real waveSeedingCurvatureThresholdRegionRadius;
+ Real waveSeedStepSizeRatioOfMax;
+ Real innerRadius;
+ Real meanFineDistance;
+ Real constraintA;
+ Real normalRadius;
+ Real tangentRadius;
+ Real bndXm, bndXp, bndYm, bndYp, bndZm, bndZp;
+};
+SurfaceTurbulenceParameters params;
+
+
+//
+// **** acceleration grid for particle neighbor queries ****
+//
+struct ParticleAccelGrid{
+ int res;
+ vector<int>*** indices;
+
+ void init(int inRes) {
+ res = inRes;
+ indices = new vector<int>**[res];
+ for(int i=0; i<res; i++){
+ indices[i] = new vector<int>*[res];
+ for(int j=0; j<res; j++) {
+ indices[i][j] = new vector<int>[res];
+ }
+ }
+ }
+
+ void fillWith(const BasicParticleSystem& particles) {
+ // clear
+ for(int i=0; i<res; i++) {
+ for(int j=0; j<res; j++) {
+ for(int k=0; k<res; k++) {
+ indices[i][j][k].clear();
+ }}}
+
+ // fill
+ for(int id=0;id<particles.size();id++) {
+ Vec3 pos = particles.getPos(id);
+ int i = clamp<int>(floor(pos.x/params.res*res), 0, res-1);
+ int j = clamp<int>(floor(pos.y/params.res*res), 0, res-1);
+ int k = clamp<int>(floor(pos.z/params.res*res), 0, res-1);
+ indices[i][j][k].push_back(id);
+ }
+ }
+
+ void fillWith(const ParticleDataImpl<Vec3>& particles){
+ // clear
+ for(int i=0; i<res; i++) {
+ for(int j=0; j<res; j++) {
+ for(int k=0; k<res; k++) {
+ indices[i][j][k].clear();
+ }}}
+
+ // fill
+ for(int id=0;id<particles.size();id++) {
+ Vec3 pos = particles[id];
+ int i = clamp<int>(floor(pos.x/params.res*res), 0, res-1);
+ int j = clamp<int>(floor(pos.y/params.res*res), 0, res-1);
+ int k = clamp<int>(floor(pos.z/params.res*res), 0, res-1);
+ indices[i][j][k].push_back(id);
+ }
+ }
+};
+
+#define LOOP_NEIGHBORS_BEGIN(points, center, radius) \
+ int minI = clamp<int>(floor((center.x-radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ int maxI = clamp<int>(floor((center.x+radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ int minJ = clamp<int>(floor((center.y-radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ int maxJ = clamp<int>(floor((center.y+radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ int minK = clamp<int>(floor((center.z-radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ int maxK = clamp<int>(floor((center.z+radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ for(int i=minI; i<=maxI; i++) { \
+ for(int j=minJ; j<=maxJ; j++) { \
+ for(int k=minK; k<=maxK; k++) { \
+ for(int idLOOPNEIGHBORS=0;idLOOPNEIGHBORS<(int)points.accel->indices[i][j][k].size();idLOOPNEIGHBORS++) { \
+ int idn = points.accel->indices[i][j][k][idLOOPNEIGHBORS]; \
+ if(points.isActive(idn)) {
+#define LOOP_NEIGHBORS_END \
+ } \
+ } \
+ }}}
+
+#define LOOP_GHOSTS_POS_BEGIN(pos, radius) \
+ int flagLOOPGHOSTS = -1; \
+ Vec3 gPos; \
+ while(flagLOOPGHOSTS < 6) { \
+ if (flagLOOPGHOSTS < 0 && pos.x - params.bndXm <= radius) { flagLOOPGHOSTS = 0; gPos = Vec3(2.f*params.bndXm - pos.x, pos.y, pos.z); } \
+ else if(flagLOOPGHOSTS < 1 && params.bndXp - pos.x <= radius) { flagLOOPGHOSTS = 1; gPos = Vec3(2.f*params.bndXp - pos.x, pos.y, pos.z); } \
+ else if(flagLOOPGHOSTS < 2 && pos.y - params.bndYm <= radius) { flagLOOPGHOSTS = 2; gPos = Vec3(pos.x, 2.f*params.bndYm - pos.y, pos.z); } \
+ else if(flagLOOPGHOSTS < 3 && params.bndYp - pos.y <= radius) { flagLOOPGHOSTS = 3; gPos = Vec3(pos.x, 2.f*params.bndYp - pos.y, pos.z); } \
+ else if(flagLOOPGHOSTS < 4 && pos.z - params.bndZm <= radius) { flagLOOPGHOSTS = 4; gPos = Vec3(pos.x, pos.y, 2.f*params.bndZm - pos.z); } \
+ else if(flagLOOPGHOSTS < 5 && params.bndZp - pos.Z <= radius) { flagLOOPGHOSTS = 5; gPos = Vec3(pos.x, pos.y, 2.f*params.bndZp - pos.z); } \
+ else { flagLOOPGHOSTS = 6; gPos = Vec3(pos.x, pos.y, pos.z); }
+#define LOOP_GHOSTS_POS_NORMAL_BEGIN(pos, normal, radius) \
+ int flagLOOPGHOSTS = -1; \
+ Vec3 gPos, gNormal; \
+ while(flagLOOPGHOSTS < 6) { \
+ if (flagLOOPGHOSTS < 0 && pos.x - params.bndXm <= radius) { flagLOOPGHOSTS = 0; gPos = Vec3(2.f*params.bndXm - pos.x, pos.y, pos.z); gNormal = Vec3(-normal.x, normal.y, normal.z); } \
+ else if(flagLOOPGHOSTS < 1 && params.bndXp - pos.x <= radius) { flagLOOPGHOSTS = 1; gPos = Vec3(2.f*params.bndXp - pos.x, pos.y, pos.z); gNormal = Vec3(-normal.x, normal.y, normal.z); } \
+ else if(flagLOOPGHOSTS < 2 && pos.y - params.bndYm <= radius) { flagLOOPGHOSTS = 2; gPos = Vec3(pos.x, 2.f*params.bndYm - pos.y, pos.z); gNormal = Vec3( normal.x, -normal.y, normal.z); } \
+ else if(flagLOOPGHOSTS < 3 && params.bndYp - pos.y <= radius) { flagLOOPGHOSTS = 3; gPos = Vec3(pos.x, 2.f*params.bndYp - pos.y, pos.z); gNormal = Vec3( normal.x, -normal.y, normal.z); } \
+ else if(flagLOOPGHOSTS < 4 && pos.z - params.bndZm <= radius) { flagLOOPGHOSTS = 4; gPos = Vec3(pos.x, pos.y, 2.f*params.bndZm - pos.z); gNormal = Vec3( normal.x, normal.y, -normal.z); } \
+ else if(flagLOOPGHOSTS < 5 && params.bndZp - pos.Z <= radius) { flagLOOPGHOSTS = 5; gPos = Vec3(pos.x, pos.y, 2.f*params.bndZp - pos.z); gNormal = Vec3( normal.x, normal.y, -normal.z); } \
+ else { flagLOOPGHOSTS = 6; gPos = pos; gNormal = normal; }
+#define LOOP_GHOSTS_END \
+ }
+
+
+//
+// **** Wrappers around point sets to attach it an acceleration grid ****
+//
+struct PointSetWrapper {
+ ParticleAccelGrid* accel;
+
+ PointSetWrapper(ParticleAccelGrid* inAccel) {accel = inAccel;}
+ virtual void updateAccel() = 0;
+};
+
+struct BasicParticleSystemWrapper : PointSetWrapper {
+ BasicParticleSystem* points;
+
+ BasicParticleSystemWrapper(ParticleAccelGrid* inAccel) : PointSetWrapper(inAccel) {}
+
+ Vec3 getPos(int id) const {return points->getPos(id);}
+ void setPos(int id, Vec3 pos) {points->setPos(id, pos);}
+ void updateAccel() {accel->fillWith(*points);}
+ void clear() {points->clear();}
+ int size() const {return points->size();}
+ bool isActive(int id) const {return points->isActive(id);}
+ void addParticle(Vec3 pos) {points->addParticle(pos);}
+ int getStatus(int id) const {return points->getStatus(id);}
+ void addBuffered(Vec3 pos) {points->addBuffered(pos);}
+ void doCompress() {points->doCompress();}
+ void insertBufferedParticles() {points->insertBufferedParticles();}
+ void kill(int id) {points->kill(id);}
+
+ bool hasNeighbor(Vec3 pos, Real radius) const {
+ bool answer = false;
+ int minI = clamp<int>(floor((pos.x-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxI = clamp<int>(floor((pos.x+radius)/params.res*accel->res), 0, accel->res-1);
+ int minJ = clamp<int>(floor((pos.y-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxJ = clamp<int>(floor((pos.y+radius)/params.res*accel->res), 0, accel->res-1);
+ int minK = clamp<int>(floor((pos.z-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxK = clamp<int>(floor((pos.z+radius)/params.res*accel->res), 0, accel->res-1);
+ for(int i=minI; i<=maxI; i++) {
+ for(int j=minJ; j<=maxJ; j++) {
+ for(int k=minK; k<=maxK; k++) {
+ for(int id=0;id<(int)accel->indices[i][j][k].size();id++) {
+ if(points->isActive(accel->indices[i][j][k][id]) &&
+ norm(points->getPos(accel->indices[i][j][k][id]) - pos) <= radius
+ ) {answer = true; break;}
+ }
+ if(answer)break;}
+ if(answer)break;}
+ if(answer)break;}
+ return answer;
+ }
+
+ bool hasNeighborOtherThanItself(int idx, Real radius) const {
+ bool answer = false;
+ Vec3 pos = points->getPos(idx);
+ int minI = clamp<int>(floor((pos.x-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxI = clamp<int>(floor((pos.x+radius)/params.res*accel->res), 0, accel->res-1);
+ int minJ = clamp<int>(floor((pos.y-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxJ = clamp<int>(floor((pos.y+radius)/params.res*accel->res), 0, accel->res-1);
+ int minK = clamp<int>(floor((pos.z-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxK = clamp<int>(floor((pos.z+radius)/params.res*accel->res), 0, accel->res-1);
+ for(int i=minI; i<=maxI; i++) {
+ for(int j=minJ; j<=maxJ; j++) {
+ for(int k=minK; k<=maxK; k++) {
+ for(int id=0;id<(int)accel->indices[i][j][k].size();id++) {
+ if(accel->indices[i][j][k][id] != idx &&
+ points->isActive(accel->indices[i][j][k][id]) &&
+ norm(points->getPos(accel->indices[i][j][k][id]) - pos) <= radius
+ ) {answer = true; break;}
+ }
+ if(answer)break;}
+ if(answer)break;}
+ if(answer)break;}
+ return answer;
+ }
+
+ void removeInvalidIndices(vector<int>& indices) {
+ vector<int> copy;
+ copy.resize(indices.size());
+ for(int i=0; i<(int)indices.size(); i++) {
+ copy[i] = indices[i];
+ }
+ indices.clear();
+ for(int i=0; i<(int)copy.size(); i++) {
+ if(points->isActive(copy[i])) {
+ indices.push_back(copy[i]);
+ }
+ }
+ }
+};
+
+struct ParticleDataImplVec3Wrapper : PointSetWrapper {
+ ParticleDataImpl<Vec3>* points;
+
+ ParticleDataImplVec3Wrapper(ParticleAccelGrid* inAccel) : PointSetWrapper(inAccel) {}
+
+ Vec3 getVec3(int id) const {return (*points)[id];}
+ void setVec3(int id, Vec3 vec) {(*points)[id] = vec;}
+ void updateAccel() {accel->fillWith(*points);}
+ bool isActive(int i) const {return true;}
+
+};
+
+
+//
+// **** globals ****
+//
+ParticleAccelGrid accelCoarse, accelSurface;
+BasicParticleSystemWrapper coarseParticles(&accelCoarse), surfacePoints(&accelSurface);
+ParticleDataImplVec3Wrapper coarseParticlesPrevPos(&accelCoarse); // WARNING: reusing the coarse accel grid to save space, don't query coarseParticlesPrevPos and coarseParticles at the same time.
+vector<Vec3> tempSurfaceVec3; // to store misc info on surface points
+vector<Real> tempSurfaceFloat; // to store misc info on surface points
+int frameCount = 0;
+
+
+
+
+//
+//**** weighting kernels *****
+//
+Real triangularWeight(Real distance, Real radius) {
+ return 1.0f - distance/radius;
+}
+Real exponentialWeight(Real distance, Real radius, Real falloff) {
+ if(distance > radius) return 0;
+ Real tmp = distance/radius;
+ return expf(-falloff*tmp*tmp);
+}
+
+Real weightKernelAdvection(Real distance) {
+ if(distance > 2.f*params.outerRadius) {
+ return 0;
+ } else {
+ return triangularWeight(distance, 2.f*params.outerRadius);
+ }
+}
+
+Real weightKernelCoarseDensity(Real distance) {
+ return exponentialWeight(distance, params.outerRadius, 2.0f);
+}
+
+Real weightSurfaceNormal(Real distance) {
+ if(distance > params.normalRadius) {
+ return 0;
+ } else {
+ return triangularWeight(distance, params.normalRadius);
+ }
+}
+
+Real weightSurfaceTangent(Real distance) {
+ if(distance > params.tangentRadius) {
+ return 0;
+ } else {
+ return triangularWeight(distance, params.tangentRadius);
+ }
+}
+
+
+//
+// **** utility ****
+//
+
+bool isInDomain(Vec3 pos)
+{
+ return params.bndXm <= pos.x && pos.x <= params.bndXp &&
+ params.bndYm <= pos.y && pos.y <= params.bndYp &&
+ params.bndZm <= pos.z && pos.z <= params.bndZp ;
+}
+
+Real smoothstep( Real edgeLeft, Real edgeRight, Real val ){
+ Real x = clamp((val - edgeLeft)/(edgeRight - edgeLeft), Real(0.), Real(1.) );
+ return x*x*(3 - 2*x);
+}
+
+
+//
+// **** surface initialization ****
+//
+
+void initFines(
+ const BasicParticleSystemWrapper& coarseParticles,
+ BasicParticleSystemWrapper& surfacePoints,
+ const FlagGrid& flags
+){
+ unsigned int discretization = (unsigned int) M_PI*(params.outerRadius+params.innerRadius)/params.meanFineDistance;
+ Real dtheta = 2*params.meanFineDistance/(params.outerRadius+params.innerRadius);
+ Real outerRadius2 = params.outerRadius*params.outerRadius;
+
+ surfacePoints.clear();
+ for (int idx=0; idx<(int)coarseParticles.size(); idx++) {
+
+ if(idx % 500 == 0) {cout << "Initializing surface points : " << setprecision(4) << 100.f*idx/coarseParticles.size() << "%" << endl;}
+
+ if (coarseParticles.isActive(idx)) {
+
+ // check flags if we are near surface
+ bool nearSurface = false;
+ Vec3 pos = coarseParticles.getPos(idx);
+ for(int i=-1; i<=1; i++) {
+ for(int j=-1; j<=1; j++) {
+ for(int k=-1; k<=1; k++) {
+ if( !flags.isFluid( ((int)pos.x)+i, ((int)pos.y)+j, ((int)pos.z)+k ) ) {
+ nearSurface = true;
+ break;
+ }
+ }}}
+
+ if(nearSurface) {
+ for(unsigned int i = 0; i <= discretization/2; ++i){
+ Real discretization2 = Real(floor(2*M_PI*sin(i*dtheta)/dtheta)+1);
+ for(Real phi = 0; phi < 2*M_PI; phi += Real(2*M_PI/discretization2)){
+ Real theta = i*dtheta;
+ Vec3 normal(sin(theta)*cos(phi), cos(theta), sin(theta)*sin(phi));
+ Vec3 position = coarseParticles.getPos(idx) + params.outerRadius*normal;
+
+ bool valid = true;
+ LOOP_NEIGHBORS_BEGIN(coarseParticles, position, 2.f*params.outerRadius)
+ if(idx!=idn && normSquare(position-coarseParticles.getPos(idn)) < outerRadius2) {
+ valid = false;
+ break;
+ }
+ LOOP_NEIGHBORS_END
+ if(valid) {
+ surfacePoints.addParticle(position);
+ }
+ }
+ }
+ }
+
+ }
+ }
+}
+
+//
+// **** surface advection ****
+//
+
+
+
+
+
+
+
+ struct advectSurfacePoints : public KernelBase {
+ advectSurfacePoints( BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles, const ParticleDataImplVec3Wrapper& coarseParticlesPrevPos ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),coarseParticles(coarseParticles),coarseParticlesPrevPos(coarseParticlesPrevPos) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles, const ParticleDataImplVec3Wrapper& coarseParticlesPrevPos ) {
+ if(surfacePoints.isActive(idx)) {
+ Vec3 avgDisplacement(0,0,0);
+ Real totalWeight = 0;
+ Vec3 p = surfacePoints.getPos(idx);
+ LOOP_NEIGHBORS_BEGIN(coarseParticlesPrevPos, surfacePoints.getPos(idx), 2.0f*params.outerRadius)
+ if((coarseParticles.getStatus(idn) & ParticleBase::PNEW)==0 &&
+ (coarseParticles.getStatus(idn) & ParticleBase::PDELETE)==0)
+ {
+ Vec3 disp = coarseParticles.getPos(idn) - coarseParticlesPrevPos.getVec3(idn);
+ Real distance = norm(coarseParticlesPrevPos.getVec3(idn) - p);
+ Real w = weightKernelAdvection(distance);
+ avgDisplacement += w * disp;
+ totalWeight += w;
+ }
+ LOOP_NEIGHBORS_END
+ if(totalWeight != 0) avgDisplacement /= totalWeight;
+ surfacePoints.setPos(idx, p + avgDisplacement);
+ }
+} inline BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const BasicParticleSystemWrapper& getArg1() {
+ return coarseParticles; }
+ typedef BasicParticleSystemWrapper type1;inline const ParticleDataImplVec3Wrapper& getArg2() {
+ return coarseParticlesPrevPos; }
+ typedef ParticleDataImplVec3Wrapper type2; void runMessage() { debMsg("Executing kernel advectSurfacePoints ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,coarseParticles,coarseParticlesPrevPos); }
+ }
+ BasicParticleSystemWrapper& surfacePoints; const BasicParticleSystemWrapper& coarseParticles; const ParticleDataImplVec3Wrapper& coarseParticlesPrevPos; }
+;
+
+
+//
+// **** value and gradient of level-set band constraint ****
+//
+Real computeConstraintLevel(
+ const BasicParticleSystemWrapper& coarseParticles,
+ Vec3 pos
+){
+ Real lvl = 0.0f;
+ LOOP_NEIGHBORS_BEGIN(coarseParticles, pos, 1.5f*params.outerRadius)
+ lvl += expf(-params.constraintA*normSquare(coarseParticles.getPos(idn) - pos));
+ LOOP_NEIGHBORS_END
+ if(lvl > 1.0f) lvl = 1.0f;
+ lvl = (sqrtf(-logf(lvl)/params.constraintA)-params.innerRadius)/(params.outerRadius-params.innerRadius);
+ return lvl;
+}
+
+Vec3 computeConstraintGradient(
+ const BasicParticleSystemWrapper& coarseParticles,
+ Vec3 pos
+){
+ Vec3 gradient(0,0,0);
+ LOOP_NEIGHBORS_BEGIN(coarseParticles, pos, 1.5f*params.outerRadius)
+ gradient += 2.f*params.constraintA*(Real)(expf(-params.constraintA*normSquare(coarseParticles.getPos(idn) - pos)))*(pos - coarseParticles.getPos(idn));
+ LOOP_NEIGHBORS_END
+ return getNormalized(gradient);
+}
+
+
+//
+// **** compute surface normals ****
+//
+
+
+
+
+
+
+ struct computeSurfaceNormals : public KernelBase {
+ computeSurfaceNormals( const BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles, ParticleDataImpl<Vec3>& surfaceNormals ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),coarseParticles(coarseParticles),surfaceNormals(surfaceNormals) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles, ParticleDataImpl<Vec3>& surfaceNormals ) {
+ Vec3 pos = surfacePoints.getPos(idx);
+
+ // approx normal with gradient
+ Vec3 gradient = computeConstraintGradient(coarseParticles, pos);
+
+ // get tangent frame
+ Vec3 n = getNormalized(gradient);
+ Vec3 vx(1,0,0);
+ Vec3 vy(0,1,0);
+ Real dotX = dot(n, vx);
+ Real dotY = dot(n, vy);
+ Vec3 t1 = getNormalized(fabs(dotX)<fabs(dotY) ? cross(n, vx) : cross(n, vy));
+ Vec3 t2 = getNormalized( cross(n,t1) ); // initial frame
+
+ // linear fit of neighboring surface points in approximated tangent frame
+ Real sw = 0, swx = 0, swy = 0, swxy = 0, swx2 = 0, swy2 = 0, swxz = 0, swyz = 0, swz = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.normalRadius)
+ Real x = dot(gPos - pos, t1);
+ Real y = dot(gPos - pos, t2);
+ Real z = dot(gPos - pos, n);
+ Real w = weightSurfaceNormal(norm(pos - gPos));
+ swx2 += w*x*x;
+ swy2 += w*y*y;
+ swxy += w*x*y;
+ swxz += w*x*z;
+ swyz += w*y*z;
+ swx += w*x;
+ swy += w*y;
+ swz += w*z;
+ sw += w;
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ Real det = -sw*swxy*swxy + 2.f*swx*swxy*swy - swx2*swy*swy - swx*swx*swy2 + sw*swx2*swy2;
+ if(det == 0) {surfaceNormals[idx]=Vec3(0,0,0);}
+ else {
+ Vec3 abc = 1.f/det*Vec3(
+ swxz*(-swy*swy+sw*swy2) + swyz*(-sw*swxy+swx*swy) + swz*(swxy*swy-swx*swy2),
+ swxz*(-sw*swxy+swx*swy) + swyz*(-swx*swx+sw*swx2) + swz*(swx*swxy-swx2*swy),
+ swxz*(swxy*swy-swx*swy2) + swyz*(swx*swxy-swx2*swy) + swz*(-swxy*swxy + swx2*swy2)
+ );
+ Vec3 normal = -getNormalized(t1*abc.x + t2*abc.y - n);
+ if(dot(gradient, normal) < 0) {normal = -normal;}
+ surfaceNormals[idx] = normal;
+ }
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const BasicParticleSystemWrapper& getArg1() {
+ return coarseParticles; }
+ typedef BasicParticleSystemWrapper type1;inline ParticleDataImpl<Vec3>& getArg2() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type2; void runMessage() { debMsg("Executing kernel computeSurfaceNormals ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,coarseParticles,surfaceNormals); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; const BasicParticleSystemWrapper& coarseParticles; ParticleDataImpl<Vec3>& surfaceNormals; }
+;
+
+
+//
+// **** smooth surface normals ****
+//
+
+
+
+
+
+ struct computeAveragedNormals : public KernelBase {
+ computeAveragedNormals( const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Vec3 newNormal = Vec3(0,0,0);
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+ Real w = weightSurfaceNormal(norm(pos - surfacePoints.getPos(idn)));
+ newNormal += w * surfaceNormals[idn];
+ LOOP_NEIGHBORS_END
+ tempSurfaceVec3[idx] = getNormalized(newNormal);
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1; void runMessage() { debMsg("Executing kernel computeAveragedNormals ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,surfaceNormals); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; const ParticleDataImpl<Vec3>& surfaceNormals; }
+;
+
+
+
+
+
+ struct assignNormals : public KernelBase {
+ assignNormals( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Vec3>& surfaceNormals ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Vec3>& surfaceNormals ) {
+ surfaceNormals[idx] = tempSurfaceVec3[idx];
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1; void runMessage() { debMsg("Executing kernel assignNormals ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,surfaceNormals); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Vec3>& surfaceNormals; }
+;
+
+void smoothSurfaceNormals(
+ const BasicParticleSystemWrapper& surfacePoints,
+ ParticleDataImpl<Vec3>& surfaceNormals
+){
+ tempSurfaceVec3.resize(surfacePoints.size());
+
+ computeAveragedNormals(surfacePoints, surfaceNormals);
+ assignNormals(surfacePoints, surfaceNormals);
+}
+
+
+
+//
+// **** addition/deletion of particles. Not parallel to prevent write/delete conflicts ****
+//
+
+void addDeleteSurfacePoints(
+ BasicParticleSystemWrapper& surfacePoints
+){
+ int fixedSize = surfacePoints.size();
+ for (int idx=0; idx<fixedSize; idx++) {
+ // compute proxy tangent displacement
+ Vec3 pos = surfacePoints.getPos(idx);
+
+ Vec3 gradient = computeConstraintGradient(coarseParticles, pos);
+
+ Real wt = 0;
+ Vec3 tangentDisplacement(0,0,0);
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
+ if(idn != idx) {
+ Vec3 dir = pos - surfacePoints.getPos(idn);
+ Real length = norm(dir);
+ dir = getNormalized(dir);
+
+ // Decompose direction into normal and tangent directions.
+ Vec3 dn = dot(dir, gradient)*gradient;
+ Vec3 dt = dir - dn;
+
+ Real w = weightSurfaceTangent(length);
+ wt += w;
+ tangentDisplacement += w * dt;
+ }
+ LOOP_NEIGHBORS_END
+ if(norm(tangentDisplacement)!=0) {tangentDisplacement = getNormalized(tangentDisplacement);}
+
+ // check density criterion, add surface point if necessary
+ Vec3 creationPos = pos + params.meanFineDistance*tangentDisplacement;
+ if(
+ isInDomain(creationPos) &&
+ !surfacePoints.hasNeighbor(creationPos, params.meanFineDistance-(1e-6))
+ ) {
+ //create point
+ surfacePoints.addBuffered(creationPos);
+ }
+
+ }
+
+
+ surfacePoints.doCompress();
+ surfacePoints.insertBufferedParticles();
+
+
+ // check density criterion, delete surface points if necessary
+ fixedSize = surfacePoints.size();
+ for (int idx=0; idx<fixedSize; idx++) {
+ if(
+ !isInDomain(surfacePoints.getPos(idx)) ||
+ surfacePoints.hasNeighborOtherThanItself(idx, 0.67*params.meanFineDistance)
+ ) {
+ surfacePoints.kill(idx);
+ }
+ }
+
+ // delete surface points if no coarse neighbors in advection radius
+ fixedSize = surfacePoints.size();
+ for (int idx=0; idx<fixedSize; idx++) {
+ Vec3 pos = surfacePoints.getPos(idx);
+ if(!coarseParticles.hasNeighbor(pos, 2.f*params.outerRadius)) {
+ surfacePoints.kill(idx);
+ }
+ }
+
+ // delete surface point if too far from constraint
+ fixedSize = surfacePoints.size();
+ for (int idx=0; idx<fixedSize; idx++) {
+ Real level = computeConstraintLevel(coarseParticles, surfacePoints.getPos(idx));
+ if(level < -0.2 || level > 1.2) {
+ surfacePoints.kill(idx);
+ }
+ }
+
+
+ surfacePoints.doCompress();
+ surfacePoints.insertBufferedParticles();
+}
+
+
+//
+// **** surface maintenance ****
+//
+
+
+
+
+
+ struct computeSurfaceDensities : public KernelBase {
+ computeSurfaceDensities( const BasicParticleSystemWrapper& surfacePoints, void* dummy ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),dummy(dummy) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, void* dummy ) {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Real density = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.normalRadius)
+ density += weightSurfaceNormal(norm(pos-gPos));
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ tempSurfaceFloat[idx] = density;
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline void* getArg1() {
+ return dummy; }
+ typedef void type1; void runMessage() { debMsg("Executing kernel computeSurfaceDensities ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,dummy); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; void* dummy; }
+;
+
+
+
+
+
+ struct computeSurfaceDisplacements : public KernelBase {
+ computeSurfaceDisplacements( const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Vec3 normal = surfaceNormals[idx];
+
+ Vec3 displacementNormal(0,0,0);
+ Vec3 displacementTangent(0,0,0);
+ Real wTotal = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+
+ LOOP_GHOSTS_POS_NORMAL_BEGIN(surfacePoints.getPos(idn), surfaceNormals[idn], params.normalRadius)
+ Vec3 dir = pos - gPos;
+ Real length = norm(dir);
+ Vec3 dn = dot(dir,surfaceNormals[idx])*surfaceNormals[idx];
+ Vec3 dt = dir - dn;
+ if(tempSurfaceFloat[idn]==0) {continue;}
+ Real w = weightSurfaceNormal( length ) / tempSurfaceFloat[idn];
+
+ Vec3 crossVec = getNormalized(cross(normal, -dir));
+ Vec3 projectedNormal = getNormalized(gNormal - dot(crossVec,gNormal)*crossVec);
+ if(dot(projectedNormal, normal) < 0 || abs(dot(normal,normal+projectedNormal)) < 1e-6) {continue;}
+ dn = -dot(normal+projectedNormal,dir)/dot(normal,normal+projectedNormal)*normal;
+
+ displacementNormal += w * dn;
+ displacementTangent += w * getNormalized(dt);
+ wTotal += w;
+ LOOP_GHOSTS_END
+
+ LOOP_NEIGHBORS_END
+ if(wTotal != 0) {
+ displacementNormal /= wTotal;
+ displacementTangent /= wTotal;
+ }
+ displacementNormal *= .75f;
+ displacementTangent *= .25f * params.meanFineDistance;
+ tempSurfaceVec3[idx] = displacementNormal + displacementTangent;
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1; void runMessage() { debMsg("Executing kernel computeSurfaceDisplacements ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,surfaceNormals); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; const ParticleDataImpl<Vec3>& surfaceNormals; }
+;
+
+
+
+
+
+ struct applySurfaceDisplacements : public KernelBase {
+ applySurfaceDisplacements( BasicParticleSystemWrapper& surfacePoints, void* dummy ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),dummy(dummy) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystemWrapper& surfacePoints, void* dummy ) {
+ surfacePoints.setPos(idx, surfacePoints.getPos(idx) + tempSurfaceVec3[idx]);
+} inline BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline void* getArg1() {
+ return dummy; }
+ typedef void type1; void runMessage() { debMsg("Executing kernel applySurfaceDisplacements ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,dummy); }
+ }
+ BasicParticleSystemWrapper& surfacePoints; void* dummy; }
+;
+
+
+void regularizeSurfacePoints(
+ BasicParticleSystemWrapper& surfacePoints,
+ const ParticleDataImpl<Vec3>& surfaceNormals
+){
+ tempSurfaceVec3.resize(surfacePoints.size());
+ tempSurfaceFloat.resize(surfacePoints.size());
+
+ computeSurfaceDensities(surfacePoints, 0);
+ computeSurfaceDisplacements(surfacePoints, surfaceNormals);
+ applySurfaceDisplacements(surfacePoints, 0);
+}
+
+
+
+
+
+
+ struct constrainSurface : public KernelBase {
+ constrainSurface( BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),coarseParticles(coarseParticles) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles ) {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Real level = computeConstraintLevel(coarseParticles, surfacePoints.getPos(idx));
+ if(level > 1) {
+ surfacePoints.setPos(idx, pos - (params.outerRadius-params.innerRadius)*(level-1)*computeConstraintGradient(coarseParticles, surfacePoints.getPos(idx)));
+ }else if(level < 0) {
+ surfacePoints.setPos(idx, pos - (params.outerRadius-params.innerRadius)* level *computeConstraintGradient(coarseParticles, surfacePoints.getPos(idx)));
+ }
+} inline BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const BasicParticleSystemWrapper& getArg1() {
+ return coarseParticles; }
+ typedef BasicParticleSystemWrapper type1; void runMessage() { debMsg("Executing kernel constrainSurface ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,coarseParticles); }
+ }
+ BasicParticleSystemWrapper& surfacePoints; const BasicParticleSystemWrapper& coarseParticles; }
+;
+
+
+
+
+
+
+
+
+
+ struct interpolateNewWaveData : public KernelBase {
+ interpolateNewWaveData( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, ParticleDataImpl<Real>& surfaceWaveDtH, ParticleDataImpl<Real>& surfaceWaveSeed, ParticleDataImpl<Real>& surfaceWaveSeedAmplitude ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceWaveH(surfaceWaveH),surfaceWaveDtH(surfaceWaveDtH),surfaceWaveSeed(surfaceWaveSeed),surfaceWaveSeedAmplitude(surfaceWaveSeedAmplitude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, ParticleDataImpl<Real>& surfaceWaveDtH, ParticleDataImpl<Real>& surfaceWaveSeed, ParticleDataImpl<Real>& surfaceWaveSeedAmplitude ) {
+ if(surfacePoints.getStatus(idx) & ParticleBase::PNEW) {
+ Vec3 pos = surfacePoints.getPos(idx);
+ surfaceWaveH[idx] = 0;
+ surfaceWaveDtH[idx] = 0;
+ Real wTotal = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
+ if(!(surfacePoints.getStatus(idn) & ParticleBase::PNEW)) {
+ Real w = weightSurfaceTangent(norm( pos - surfacePoints.getPos(idn) ));
+ surfaceWaveH[idx] += w * surfaceWaveH[idn];
+ surfaceWaveDtH[idx] += w * surfaceWaveDtH[idn];
+ surfaceWaveSeed[idx] += w * surfaceWaveSeed[idn];
+ surfaceWaveSeedAmplitude[idx] += w * surfaceWaveSeedAmplitude[idn];
+ wTotal += w;
+ }
+ LOOP_NEIGHBORS_END
+ if(wTotal != 0) {
+ surfaceWaveH[idx] /= wTotal;
+ surfaceWaveDtH[idx] /= wTotal;
+ surfaceWaveSeed[idx] /= wTotal;
+ surfaceWaveSeedAmplitude[idx] /= wTotal;
+ }
+ }
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Real>& getArg1() {
+ return surfaceWaveH; }
+ typedef ParticleDataImpl<Real> type1;inline ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveDtH; }
+ typedef ParticleDataImpl<Real> type2;inline ParticleDataImpl<Real>& getArg3() {
+ return surfaceWaveSeed; }
+ typedef ParticleDataImpl<Real> type3;inline ParticleDataImpl<Real>& getArg4() {
+ return surfaceWaveSeedAmplitude; }
+ typedef ParticleDataImpl<Real> type4; void runMessage() { debMsg("Executing kernel interpolateNewWaveData ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,surfaceWaveH,surfaceWaveDtH,surfaceWaveSeed,surfaceWaveSeedAmplitude); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Real>& surfaceWaveH; ParticleDataImpl<Real>& surfaceWaveDtH; ParticleDataImpl<Real>& surfaceWaveSeed; ParticleDataImpl<Real>& surfaceWaveSeedAmplitude; }
+;
+
+
+void surfaceMaintenance(
+ const BasicParticleSystemWrapper& coarseParticles,
+ BasicParticleSystemWrapper& surfacePoints,
+ ParticleDataImpl<Vec3>& surfaceNormals,
+ ParticleDataImpl<Real>& surfaceWaveH,
+ ParticleDataImpl<Real>& surfaceWaveDtH,
+ ParticleDataImpl<Real>& surfaceWaveSeed,
+ ParticleDataImpl<Real>& surfaceWaveSeedAmplitude,
+ int nbIterations
+){
+ int countIterations = nbIterations;
+ while(countIterations > 0) {
+ addDeleteSurfacePoints(surfacePoints);
+ surfacePoints.updateAccel();
+ computeSurfaceNormals(surfacePoints, coarseParticles, surfaceNormals);
+ smoothSurfaceNormals(surfacePoints, surfaceNormals);
+
+ regularizeSurfacePoints(surfacePoints, surfaceNormals);
+ surfacePoints.updateAccel();
+ constrainSurface(surfacePoints, coarseParticles);
+ surfacePoints.updateAccel();
+
+ interpolateNewWaveData(surfacePoints, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed, surfaceWaveSeedAmplitude);
+
+ countIterations--;
+ }
+}
+
+
+
+
+//
+// **** surface wave seeding and evolution ****
+//
+
+
+
+
+
+
+
+ struct addSeed : public KernelBase {
+ addSeed( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, const ParticleDataImpl<Real>& surfaceWaveSeed ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceWaveH(surfaceWaveH),surfaceWaveSeed(surfaceWaveSeed) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, const ParticleDataImpl<Real>& surfaceWaveSeed ) {
+ surfaceWaveH[idx] += surfaceWaveSeed[idx];
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Real>& getArg1() {
+ return surfaceWaveH; }
+ typedef ParticleDataImpl<Real> type1;inline const ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveSeed; }
+ typedef ParticleDataImpl<Real> type2; void runMessage() { debMsg("Executing kernel addSeed ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,surfaceWaveH,surfaceWaveSeed); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Real>& surfaceWaveH; const ParticleDataImpl<Real>& surfaceWaveSeed; }
+;
+
+
+
+
+
+
+
+ struct computeSurfaceWaveNormal : public KernelBase {
+ computeSurfaceWaveNormal( const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals, const ParticleDataImpl<Real>& surfaceWaveH ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals),surfaceWaveH(surfaceWaveH) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals, const ParticleDataImpl<Real>& surfaceWaveH ) {
+ Vec3 pos = surfacePoints.getPos(idx);
+
+ // get tangent frame
+ Vec3 n = getNormalized(surfaceNormals[idx]);
+ Vec3 vx(1,0,0);
+ Vec3 vy(0,1,0);
+ Real dotX = dot(n, vx);
+ Real dotY = dot(n, vy);
+ Vec3 t1 = getNormalized(fabs(dotX)<fabs(dotY) ? cross(n, vx) : cross(n, vy));
+ Vec3 t2 = getNormalized( cross(n,t1) );
+
+ // linear fit
+ Real sw = 0, swx = 0, swy = 0, swxy = 0, swx2 = 0, swy2 = 0, swxz = 0, swyz = 0, swz = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.tangentRadius)
+ Real x = dot(gPos - pos, t1);
+ Real y = dot(gPos - pos, t2);
+ Real z = surfaceWaveH[idn];
+ Real w = weightSurfaceTangent(norm(pos - gPos));
+ swx2 += w*x*x;
+ swy2 += w*y*y;
+ swxy += w*x*y;
+ swxz += w*x*z;
+ swyz += w*y*z;
+ swx += w*x;
+ swy += w*y;
+ swz += w*z;
+ sw += w;
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ Real det = -sw*swxy*swxy + 2.f*swx*swxy*swy - swx2*swy*swy - swx*swx*swy2 + sw*swx2*swy2;
+ if(det == 0) {tempSurfaceVec3[idx]=Vec3(0,0,0);}
+ else {
+ Vec3 abc = 1.f/det*Vec3(
+ swxz*(-swy*swy+sw*swy2) + swyz*(-sw*swxy+swx*swy) + swz*(swxy*swy-swx*swy2),
+ swxz*(-sw*swxy+swx*swy) + swyz*(-swx*swx+sw*swx2) + swz*(swx*swxy-swx2*swy),
+ swxz*(swxy*swy-swx*swy2) + swyz*(swx*swxy-swx2*swy) + swz*(-swxy*swxy + swx2*swy2)
+ );
+ Vec3 waveNormal = -getNormalized(vx*abc.x + vy*abc.y - Vec3(0,0,1));
+ tempSurfaceVec3[idx] = waveNormal;
+ }
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1;inline const ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveH; }
+ typedef ParticleDataImpl<Real> type2; void runMessage() { debMsg("Executing kernel computeSurfaceWaveNormal ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,surfaceNormals,surfaceWaveH); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; const ParticleDataImpl<Vec3>& surfaceNormals; const ParticleDataImpl<Real>& surfaceWaveH; }
+;
+
+
+
+
+
+
+ struct computeSurfaceWaveLaplacians : public KernelBase {
+ computeSurfaceWaveLaplacians( const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals, const ParticleDataImpl<Real>& surfaceWaveH ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals),surfaceWaveH(surfaceWaveH) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals, const ParticleDataImpl<Real>& surfaceWaveH ) {
+ Real laplacian = 0;
+ Real wTotal = 0;
+ Vec3 pPos = surfacePoints.getPos(idx);
+ Vec3 pNormal = surfaceNormals[idx];
+
+ Vec3 vx(1,0,0);
+ Vec3 vy(0,1,0);
+ Real dotX = dot(pNormal, vx);
+ Real dotY = dot(pNormal, vy);
+ Vec3 t1 = getNormalized(fabs(dotX)<fabs(dotY) ? cross(pNormal, vx) : cross(pNormal, vy));
+ Vec3 t2 = getNormalized( cross(pNormal,t1) );
+
+ Vec3 pWaveNormal = tempSurfaceVec3[idx];
+ Real ph = surfaceWaveH[idx];
+ if(pWaveNormal.z == 0) {tempSurfaceFloat[idx]=0;}
+ else {
+
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.tangentRadius)
+ Real nh = surfaceWaveH[idn];
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.tangentRadius)
+ Vec3 dir = gPos - pPos;
+ Real lengthDir = norm(dir);
+ if(lengthDir < 1e-5) continue;
+ Vec3 tangentDir = lengthDir*getNormalized(dir - dot(dir, pNormal)*pNormal);
+ Real dirX = dot(tangentDir, t1);
+ Real dirY = dot(tangentDir, t2);
+ Real dz = nh - ph - (-pWaveNormal.x/pWaveNormal.z)*dirX - (-pWaveNormal.y/pWaveNormal.z)*dirY;
+ Real w = weightSurfaceTangent(norm(pPos - gPos));
+ wTotal += w;
+ laplacian += clamp(w * 4*dz/(lengthDir*lengthDir), Real(-100.), Real(100.) );
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ if(wTotal != 0) {tempSurfaceFloat[idx] = laplacian/wTotal;}
+ else {tempSurfaceFloat[idx] = 0;}
+ }
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1;inline const ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveH; }
+ typedef ParticleDataImpl<Real> type2; void runMessage() { debMsg("Executing kernel computeSurfaceWaveLaplacians ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,surfaceNormals,surfaceWaveH); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; const ParticleDataImpl<Vec3>& surfaceNormals; const ParticleDataImpl<Real>& surfaceWaveH; }
+;
+
+
+
+
+
+
+
+
+ struct evolveWave : public KernelBase {
+ evolveWave( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, ParticleDataImpl<Real>& surfaceWaveDtH, const ParticleDataImpl<Real>& surfaceWaveSeed ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceWaveH(surfaceWaveH),surfaceWaveDtH(surfaceWaveDtH),surfaceWaveSeed(surfaceWaveSeed) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, ParticleDataImpl<Real>& surfaceWaveDtH, const ParticleDataImpl<Real>& surfaceWaveSeed ) {
+ surfaceWaveDtH[idx] += params.waveSpeed*params.waveSpeed * params.dt * tempSurfaceFloat[idx];
+ surfaceWaveDtH[idx] /= (1 + params.dt * params.waveDamping);
+ surfaceWaveH[idx] += params.dt * surfaceWaveDtH[idx];
+ surfaceWaveH[idx] /= (1 + params.dt * params.waveDamping);
+ surfaceWaveH[idx] -= surfaceWaveSeed[idx];
+
+ // clamp H and DtH (to prevent rare extreme behaviors)
+ surfaceWaveDtH[idx] = clamp(surfaceWaveDtH[idx], -params.waveMaxFrequency*params.waveMaxAmplitude, params.waveMaxFrequency*params.waveMaxAmplitude);
+ surfaceWaveH[idx] = clamp(surfaceWaveH[idx], -params.waveMaxAmplitude, params.waveMaxAmplitude);
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Real>& getArg1() {
+ return surfaceWaveH; }
+ typedef ParticleDataImpl<Real> type1;inline ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveDtH; }
+ typedef ParticleDataImpl<Real> type2;inline const ParticleDataImpl<Real>& getArg3() {
+ return surfaceWaveSeed; }
+ typedef ParticleDataImpl<Real> type3; void runMessage() { debMsg("Executing kernel evolveWave ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,surfaceWaveH,surfaceWaveDtH,surfaceWaveSeed); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Real>& surfaceWaveH; ParticleDataImpl<Real>& surfaceWaveDtH; const ParticleDataImpl<Real>& surfaceWaveSeed; }
+;
+
+
+
+
+
+
+ struct computeSurfaceCurvature : public KernelBase {
+ computeSurfaceCurvature( const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) {
+ Vec3 pPos = surfacePoints.getPos(idx);
+ Real wTotal = 0;
+ Real curv = 0;
+ Vec3 pNormal = surfaceNormals[idx];
+
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.normalRadius)
+ LOOP_GHOSTS_POS_NORMAL_BEGIN(surfacePoints.getPos(idn), surfaceNormals[idn], params.normalRadius)
+ Vec3 dir = pPos - gPos;
+ if(dot(pNormal, gNormal) < 0) {continue;} // backfacing
+ Real dist = norm(dir);
+ if(dist < params.normalRadius/100.f){ continue; }
+
+ Real distn = dot(dir, pNormal);
+
+ Real w = weightSurfaceNormal(dist);
+ curv += w * distn;
+ wTotal += w;
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ if(wTotal!=0) {curv /= wTotal;}
+ tempSurfaceFloat[idx] = fabs(curv);
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1; void runMessage() { debMsg("Executing kernel computeSurfaceCurvature ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,surfaceNormals); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; const ParticleDataImpl<Vec3>& surfaceNormals; }
+;
+
+
+
+
+
+
+ struct smoothCurvature : public KernelBase {
+ smoothCurvature( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveSource ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceWaveSource(surfaceWaveSource) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveSource ) {
+ Vec3 pPos = surfacePoints.getPos(idx);
+ Real curv = 0;
+ Real wTotal = 0;
+
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.normalRadius)
+ Real w = weightSurfaceNormal(norm( pPos - surfacePoints.getPos(idn) ));
+ curv += w * tempSurfaceFloat[idn];
+ wTotal += w;
+ LOOP_NEIGHBORS_END
+ if(wTotal!=0) {curv /= wTotal;}
+ surfaceWaveSource[idx] = curv;
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Real>& getArg1() {
+ return surfaceWaveSource; }
+ typedef ParticleDataImpl<Real> type1; void runMessage() { debMsg("Executing kernel smoothCurvature ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,surfaceWaveSource); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Real>& surfaceWaveSource; }
+;
+
+
+
+
+
+
+
+
+ struct seedWaves : public KernelBase {
+ seedWaves( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveSeed, ParticleDataImpl<Real>& surfaceWaveSeedAmplitude, ParticleDataImpl<Real>& surfaceWaveSource ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceWaveSeed(surfaceWaveSeed),surfaceWaveSeedAmplitude(surfaceWaveSeedAmplitude),surfaceWaveSource(surfaceWaveSource) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveSeed, ParticleDataImpl<Real>& surfaceWaveSeedAmplitude, ParticleDataImpl<Real>& surfaceWaveSource ) {
+ Real source = smoothstep(params.waveSeedingCurvatureThresholdRegionCenter - params.waveSeedingCurvatureThresholdRegionRadius, params.waveSeedingCurvatureThresholdRegionCenter + params.waveSeedingCurvatureThresholdRegionRadius, (Real) surfaceWaveSource[idx]) * 2.f - 1.f;
+ Real freq = params.waveSeedFrequency;
+ Real theta = params.dt * frameCount * params.waveSpeed * freq;
+ Real costheta = cosf(theta);
+ Real maxSeedAmplitude = params.waveMaxSeedingAmplitude * params.waveMaxAmplitude;
+
+ surfaceWaveSeedAmplitude[idx] = clamp<Real>(surfaceWaveSeedAmplitude[idx]+source*params.waveSeedStepSizeRatioOfMax*maxSeedAmplitude, 0.f, maxSeedAmplitude);
+ surfaceWaveSeed[idx] = surfaceWaveSeedAmplitude[idx] * costheta;
+
+ // source values for display (not used after this point anyway)
+ surfaceWaveSource[idx] = (source>=0) ? 1 : 0;
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Real>& getArg1() {
+ return surfaceWaveSeed; }
+ typedef ParticleDataImpl<Real> type1;inline ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveSeedAmplitude; }
+ typedef ParticleDataImpl<Real> type2;inline ParticleDataImpl<Real>& getArg3() {
+ return surfaceWaveSource; }
+ typedef ParticleDataImpl<Real> type3; void runMessage() { debMsg("Executing kernel seedWaves ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,surfacePoints,surfaceWaveSeed,surfaceWaveSeedAmplitude,surfaceWaveSource); }
+ }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Real>& surfaceWaveSeed; ParticleDataImpl<Real>& surfaceWaveSeedAmplitude; ParticleDataImpl<Real>& surfaceWaveSource; }
+;
+
+
+
+void surfaceWaves(
+ const BasicParticleSystemWrapper& surfacePoints,
+ const ParticleDataImpl<Vec3>& surfaceNormals,
+ ParticleDataImpl<Real>& surfaceWaveH,
+ ParticleDataImpl<Real>& surfaceWaveDtH,
+ ParticleDataImpl<Real>& surfaceWaveSource,
+ ParticleDataImpl<Real>& surfaceWaveSeed,
+ ParticleDataImpl<Real>& surfaceWaveSeedAmplitude
+){
+ addSeed(surfacePoints, surfaceWaveH, surfaceWaveSeed);
+ computeSurfaceWaveNormal(surfacePoints, surfaceNormals, surfaceWaveH);
+ computeSurfaceWaveLaplacians(surfacePoints, surfaceNormals, surfaceWaveH);
+ evolveWave(surfacePoints, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed);
+ computeSurfaceCurvature(surfacePoints, surfaceNormals);
+ smoothCurvature(surfacePoints, surfaceWaveSource);
+ seedWaves(surfacePoints, surfaceWaveSeed, surfaceWaveSeedAmplitude, surfaceWaveSource);
+}
+
+
+
+//
+// **** main function ****
+//
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void particleSurfaceTurbulence( const FlagGrid& flags, BasicParticleSystem& coarseParts, ParticleDataImpl<Vec3>& coarsePartsPrevPos, BasicParticleSystem& surfPoints, ParticleDataImpl<Vec3>& surfaceNormals, ParticleDataImpl<Real>& surfaceWaveH, ParticleDataImpl<Real>& surfaceWaveDtH, BasicParticleSystem& surfacePointsDisplaced, ParticleDataImpl<Real>& surfaceWaveSource, ParticleDataImpl<Real>& surfaceWaveSeed, ParticleDataImpl<Real>& surfaceWaveSeedAmplitude, int res, Real outerRadius = 1.0f, int surfaceDensity = 20, int nbSurfaceMaintenanceIterations = 4, Real dt = 0.005f, Real waveSpeed = 16.0f, Real waveDamping = 0.0f, Real waveSeedFrequency = 4, Real waveMaxAmplitude = 0.25f, Real waveMaxFrequency = 800, Real waveMaxSeedingAmplitude = 0.5, Real waveSeedingCurvatureThresholdRegionCenter = 0.025f, Real waveSeedingCurvatureThresholdRegionRadius = 0.01f, Real waveSeedStepSizeRatioOfMax = 0.05f ) {
+# if USE_CHRONO==1
+ static std::chrono::high_resolution_clock::time_point begin, end;
+ end = std::chrono::high_resolution_clock::now();
+ cout << std::chrono::duration_cast<std::chrono::nanoseconds>(end-begin).count()/1000000000.f << " : time sim" << endl;
+ begin = std::chrono::high_resolution_clock::now();
+# endif
+
+ // wrap data
+ coarseParticles.points = &coarseParts;
+ coarseParticlesPrevPos.points = &coarsePartsPrevPos;
+ surfacePoints.points = &surfPoints;
+
+ // copy parameters
+ params.res = res;
+ params.outerRadius = outerRadius;
+ params.surfaceDensity = surfaceDensity;
+ params.nbSurfaceMaintenanceIterations = nbSurfaceMaintenanceIterations;
+ params.dt = dt;
+ params.waveSpeed = waveSpeed;
+ params.waveDamping = waveDamping;
+ params.waveSeedFrequency = waveSeedFrequency;
+ params.waveMaxAmplitude = waveMaxAmplitude;
+ params.waveMaxFrequency = waveMaxFrequency;
+ params.waveMaxSeedingAmplitude = waveMaxSeedingAmplitude;
+ params.waveSeedingCurvatureThresholdRegionCenter = waveSeedingCurvatureThresholdRegionCenter;
+ params.waveSeedingCurvatureThresholdRegionRadius = waveSeedingCurvatureThresholdRegionRadius;
+ params.waveSeedStepSizeRatioOfMax = waveSeedStepSizeRatioOfMax;
+
+ // compute other parameters
+ params.innerRadius = params.outerRadius/2.0;
+ params.meanFineDistance = M_PI*(params.outerRadius+params.innerRadius)/params.surfaceDensity;
+ params.constraintA = logf(2.0f/(1.0f + weightKernelCoarseDensity(params.outerRadius+params.innerRadius)))/(powf((params.outerRadius+params.innerRadius)/2,2) - params.innerRadius*params.innerRadius);
+ params.normalRadius = 0.5f*(params.outerRadius + params.innerRadius);
+ params.tangentRadius = 2.1f*params.meanFineDistance;
+ params.bndXm = params.bndYm = params.bndZm = 2;
+ params.bndXp = params.bndYp = params.bndZp = params.res-2;
+
+ if(frameCount==0) {
+
+ // initialize accel grids
+ accelCoarse.init(2.f*res/params.outerRadius);
+ accelSurface.init(1.f*res/(2.f*params.meanFineDistance));
+
+ // update coarse accel structure
+ coarseParticles.updateAccel();
+
+ // create surface points
+ initFines(coarseParticles, surfacePoints, flags);
+
+ // smooth surface
+ surfaceMaintenance(coarseParticles, surfacePoints, surfaceNormals, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed, surfaceWaveSeedAmplitude, 6*params.nbSurfaceMaintenanceIterations);
+
+ // set wave values to zero
+ for (int idx=0; idx<surfacePoints.size(); idx++) {
+ surfaceWaveH[idx] = 0;
+ surfaceWaveDtH[idx] = 0;
+ surfaceWaveSeed[idx] = 0;
+ surfaceWaveSeedAmplitude[idx] = 0;
+ }
+
+ } else {
+
+ // update coarse accel structure with previous coarse particles positions
+ coarseParticlesPrevPos.updateAccel();
+
+ //advect surface points following coarse particles
+ advectSurfacePoints(surfacePoints, coarseParticles, coarseParticlesPrevPos);
+ surfacePoints.updateAccel();
+
+ // update acceleration structure for surface points
+ coarseParticles.updateAccel();
+
+ //surface maintenance
+ surfaceMaintenance(coarseParticles, surfacePoints, surfaceNormals, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed, surfaceWaveSeedAmplitude, params.nbSurfaceMaintenanceIterations);
+
+ // surface waves
+ surfaceWaves(surfacePoints, surfaceNormals, surfaceWaveH, surfaceWaveDtH, surfaceWaveSource, surfaceWaveSeed, surfaceWaveSeedAmplitude);
+ }
+ frameCount++;
+
+ // save positions as previous positions for next step
+ for(int id=0;id<coarseParticles.size();id++) {
+ if((coarseParticles.getStatus(id) & ParticleBase::PNEW) == 0 &&
+ (coarseParticles.getStatus(id) & ParticleBase::PDELETE) == 0
+ ){
+ coarseParticlesPrevPos.setVec3(id, coarseParticles.getPos(id));
+ }
+ }
+
+ // create displaced points for display
+ surfacePointsDisplaced.clear();
+ for(int idx=0;idx<surfacePoints.size();idx++) {
+ if((surfacePoints.getStatus(idx) & ParticleBase::PDELETE) == 0) {
+ surfacePointsDisplaced.addParticle(surfacePoints.getPos(idx) + surfaceNormals[idx]*surfaceWaveH[idx]);
+ }
+ }
+
+# if USE_CHRONO==1
+ end = std::chrono::high_resolution_clock::now();
+ cout << std::chrono::duration_cast<std::chrono::nanoseconds>(end-begin).count()/1000000000.f << " : time upres" << endl;
+ begin = std::chrono::high_resolution_clock::now();
+# endif
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "particleSurfaceTurbulence" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); BasicParticleSystem& coarseParts = *_args.getPtr<BasicParticleSystem >("coarseParts",1,&_lock); ParticleDataImpl<Vec3>& coarsePartsPrevPos = *_args.getPtr<ParticleDataImpl<Vec3> >("coarsePartsPrevPos",2,&_lock); BasicParticleSystem& surfPoints = *_args.getPtr<BasicParticleSystem >("surfPoints",3,&_lock); ParticleDataImpl<Vec3>& surfaceNormals = *_args.getPtr<ParticleDataImpl<Vec3> >("surfaceNormals",4,&_lock); ParticleDataImpl<Real>& surfaceWaveH = *_args.getPtr<ParticleDataImpl<Real> >("surfaceWaveH",5,&_lock); ParticleDataImpl<Real>& surfaceWaveDtH = *_args.getPtr<ParticleDataImpl<Real> >("surfaceWaveDtH",6,&_lock); BasicParticleSystem& surfacePointsDisplaced = *_args.getPtr<BasicParticleSystem >("surfacePointsDisplaced",7,&_lock); ParticleDataImpl<Real>& surfaceWaveSource = *_args.getPtr<ParticleDataImpl<Real> >("surfaceWaveSource",8,&_lock); ParticleDataImpl<Real>& surfaceWaveSeed = *_args.getPtr<ParticleDataImpl<Real> >("surfaceWaveSeed",9,&_lock); ParticleDataImpl<Real>& surfaceWaveSeedAmplitude = *_args.getPtr<ParticleDataImpl<Real> >("surfaceWaveSeedAmplitude",10,&_lock); int res = _args.get<int >("res",11,&_lock); Real outerRadius = _args.getOpt<Real >("outerRadius",12,1.0f,&_lock); int surfaceDensity = _args.getOpt<int >("surfaceDensity",13,20,&_lock); int nbSurfaceMaintenanceIterations = _args.getOpt<int >("nbSurfaceMaintenanceIterations",14,4,&_lock); Real dt = _args.getOpt<Real >("dt",15,0.005f,&_lock); Real waveSpeed = _args.getOpt<Real >("waveSpeed",16,16.0f,&_lock); Real waveDamping = _args.getOpt<Real >("waveDamping",17,0.0f,&_lock); Real waveSeedFrequency = _args.getOpt<Real >("waveSeedFrequency",18,4,&_lock); Real waveMaxAmplitude = _args.getOpt<Real >("waveMaxAmplitude",19,0.25f,&_lock); Real waveMaxFrequency = _args.getOpt<Real >("waveMaxFrequency",20,800,&_lock); Real waveMaxSeedingAmplitude = _args.getOpt<Real >("waveMaxSeedingAmplitude",21,0.5,&_lock); Real waveSeedingCurvatureThresholdRegionCenter = _args.getOpt<Real >("waveSeedingCurvatureThresholdRegionCenter",22,0.025f,&_lock); Real waveSeedingCurvatureThresholdRegionRadius = _args.getOpt<Real >("waveSeedingCurvatureThresholdRegionRadius",23,0.01f,&_lock); Real waveSeedStepSizeRatioOfMax = _args.getOpt<Real >("waveSeedStepSizeRatioOfMax",24,0.05f ,&_lock); _retval = getPyNone(); particleSurfaceTurbulence(flags,coarseParts,coarsePartsPrevPos,surfPoints,surfaceNormals,surfaceWaveH,surfaceWaveDtH,surfacePointsDisplaced,surfaceWaveSource,surfaceWaveSeed,surfaceWaveSeedAmplitude,res,outerRadius,surfaceDensity,nbSurfaceMaintenanceIterations,dt,waveSpeed,waveDamping,waveSeedFrequency,waveMaxAmplitude,waveMaxFrequency,waveMaxSeedingAmplitude,waveSeedingCurvatureThresholdRegionCenter,waveSeedingCurvatureThresholdRegionRadius,waveSeedStepSizeRatioOfMax); _args.check(); }
+ pbFinalizePlugin(parent,"particleSurfaceTurbulence", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("particleSurfaceTurbulence",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_particleSurfaceTurbulence ("","particleSurfaceTurbulence",_W_0);
+extern "C" {
+ void PbRegister_particleSurfaceTurbulence() {
+ KEEP_UNUSED(_RP_particleSurfaceTurbulence); }
+ }
+
+
+
+
+
+
+void debugCheckParts(const BasicParticleSystem& parts, const FlagGrid& flags) {
+ for(int idx=0;idx<parts.size();idx++) {
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if(! flags.isInBounds(p) ) {
+ debMsg("bad position??? "<<idx<<" "<< parts.getPos(idx) ,1 ); exit(1);
+ }
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "debugCheckParts" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); _retval = getPyNone(); debugCheckParts(parts,flags); _args.check(); }
+ pbFinalizePlugin(parent,"debugCheckParts", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("debugCheckParts",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_debugCheckParts ("","debugCheckParts",_W_1);
+extern "C" {
+ void PbRegister_debugCheckParts() {
+ KEEP_UNUSED(_RP_debugCheckParts); }
+ }
+
+
+
+
+
+
+} // namespace SurfaceTurbulence
+
+} // namespace Manta
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/vortexplugins.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/vortexplugins.cpp
new file mode 100644
index 00000000000..fec0285a47a
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/vortexplugins.cpp
@@ -0,0 +1,457 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for using vortex sheet meshes
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include "vortexsheet.h"
+#include "vortexpart.h"
+#include "shapes.h"
+#include "commonkernels.h"
+#include "conjugategrad.h"
+#include "randomstream.h"
+#include "levelset.h"
+
+using namespace std;
+
+namespace Manta {
+
+//! Mark area of mesh inside shape as fixed nodes.
+//! Remove all other fixed nodes if 'exclusive' is set
+
+void markAsFixed(Mesh& mesh, const Shape* shape, bool exclusive=true) {
+ for (int i=0; i<mesh.numNodes(); i++) {
+ if (shape->isInside(mesh.nodes(i).pos))
+ mesh.nodes(i).flags |= Mesh::NfFixed;
+ else if (exclusive)
+ mesh.nodes(i).flags &= ~Mesh::NfFixed;
+ }
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "markAsFixed" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); const Shape* shape = _args.getPtr<Shape >("shape",1,&_lock); bool exclusive = _args.getOpt<bool >("exclusive",2,true,&_lock); _retval = getPyNone(); markAsFixed(mesh,shape,exclusive); _args.check(); }
+ pbFinalizePlugin(parent,"markAsFixed", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("markAsFixed",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_markAsFixed ("","markAsFixed",_W_0);
+extern "C" {
+ void PbRegister_markAsFixed() {
+ KEEP_UNUSED(_RP_markAsFixed); }
+ }
+
+
+
+//! Adapt texture coordinates of mesh inside shape
+//! to obtain an effective inflow effect
+
+void texcoordInflow(VortexSheetMesh& mesh, const Shape* shape, const MACGrid& vel) {
+ static Vec3 t0 = Vec3::Zero;
+
+ // get mean velocity
+ int cnt=0;
+ Vec3 meanV(0.0);
+ FOR_IJK(vel) {
+ if (shape->isInsideGrid(i,j,k)) {
+ cnt++;
+ meanV += vel.getCentered(i,j,k);
+ }
+ }
+ meanV /= (Real) cnt;
+ t0 -= mesh.getParent()->getDt() * meanV;
+ mesh.setReferenceTexOffset(t0);
+
+ // apply mean velocity
+ for (int i=0; i<mesh.numNodes(); i++) {
+ if (shape->isInside(mesh.nodes(i).pos)) {
+ Vec3 tc = mesh.nodes(i).pos + t0;
+ mesh.tex1(i) = tc;
+ mesh.tex2(i) = tc;
+ }
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "texcoordInflow" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); const Shape* shape = _args.getPtr<Shape >("shape",1,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",2,&_lock); _retval = getPyNone(); texcoordInflow(mesh,shape,vel); _args.check(); }
+ pbFinalizePlugin(parent,"texcoordInflow", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("texcoordInflow",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_texcoordInflow ("","texcoordInflow",_W_1);
+extern "C" {
+ void PbRegister_texcoordInflow() {
+ KEEP_UNUSED(_RP_texcoordInflow); }
+ }
+
+;
+
+//! Init smoke density values of the mesh surface inside source shape
+
+void meshSmokeInflow(VortexSheetMesh& mesh, const Shape* shape, Real amount) {
+ for (int t=0; t<mesh.numTris(); t++) {
+ if (shape->isInside(mesh.getFaceCenter(t)))
+ mesh.sheet(t).smokeAmount = amount;
+ }
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "meshSmokeInflow" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); const Shape* shape = _args.getPtr<Shape >("shape",1,&_lock); Real amount = _args.get<Real >("amount",2,&_lock); _retval = getPyNone(); meshSmokeInflow(mesh,shape,amount); _args.check(); }
+ pbFinalizePlugin(parent,"meshSmokeInflow", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("meshSmokeInflow",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_meshSmokeInflow ("","meshSmokeInflow",_W_2);
+extern "C" {
+ void PbRegister_meshSmokeInflow() {
+ KEEP_UNUSED(_RP_meshSmokeInflow); }
+ }
+
+
+
+
+ struct KnAcceleration : public KernelBase {
+ KnAcceleration(MACGrid& a, const MACGrid& v1, const MACGrid& v0, const Real idt) : KernelBase(&a,0) ,a(a),v1(v1),v0(v0),idt(idt) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MACGrid& a, const MACGrid& v1, const MACGrid& v0, const Real idt ) {
+ a[idx] = (v1[idx]-v0[idx])*idt;
+} inline MACGrid& getArg0() {
+ return a; }
+ typedef MACGrid type0;inline const MACGrid& getArg1() {
+ return v1; }
+ typedef MACGrid type1;inline const MACGrid& getArg2() {
+ return v0; }
+ typedef MACGrid type2;inline const Real& getArg3() {
+ return idt; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel KnAcceleration ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,a,v1,v0,idt); }
+ }
+ MACGrid& a; const MACGrid& v1; const MACGrid& v0; const Real idt; }
+;
+
+//! Add vorticity to vortex sheets based on buoyancy
+
+
+
+void vorticitySource(VortexSheetMesh& mesh, Vec3 gravity, const MACGrid* vel=NULL, const MACGrid* velOld=NULL, Real scale = 0.1, Real maxAmount = 0, Real mult = 1.0) {
+ Real dt = mesh.getParent()->getDt();
+ Real dx = mesh.getParent()->getDx();
+ MACGrid acceleration(mesh.getParent());
+ if (vel)
+ KnAcceleration(acceleration, *vel, *velOld, 1.0/dt);
+ const Real A= -1.0;
+ Real maxV = 0, meanV = 0;
+
+ for (int t=0; t<mesh.numTris(); t++) {
+ Vec3 fn = mesh.getFaceNormal(t);
+ Vec3 source;
+ if (vel) {
+ Vec3 a = acceleration.getInterpolated(mesh.getFaceCenter(t));
+ source = A*cross(fn, a-gravity) * scale;
+ } else {
+ source = A*cross(fn, -gravity) * scale;
+ }
+
+ if (mesh.isTriangleFixed(t)) source = 0;
+
+ mesh.sheet(t).vorticity *= mult;
+ mesh.sheet(t).vorticity += dt * source / dx;
+ // upper limit
+ Real v = norm(mesh.sheet(t).vorticity);
+ if (maxAmount>0 && v > maxAmount)
+ mesh.sheet(t).vorticity *= maxAmount/v;
+
+ //stats
+ if (v > maxV) maxV = v;
+ meanV += v;
+ }
+
+ cout << "vorticity: max " << maxV << " / mean " << meanV/mesh.numTris() << endl;
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "vorticitySource" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); Vec3 gravity = _args.get<Vec3 >("gravity",1,&_lock); const MACGrid* vel = _args.getPtrOpt<MACGrid >("vel",2,NULL,&_lock); const MACGrid* velOld = _args.getPtrOpt<MACGrid >("velOld",3,NULL,&_lock); Real scale = _args.getOpt<Real >("scale",4,0.1,&_lock); Real maxAmount = _args.getOpt<Real >("maxAmount",5,0,&_lock); Real mult = _args.getOpt<Real >("mult",6,1.0,&_lock); _retval = getPyNone(); vorticitySource(mesh,gravity,vel,velOld,scale,maxAmount,mult); _args.check(); }
+ pbFinalizePlugin(parent,"vorticitySource", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("vorticitySource",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_vorticitySource ("","vorticitySource",_W_3);
+extern "C" {
+ void PbRegister_vorticitySource() {
+ KEEP_UNUSED(_RP_vorticitySource); }
+ }
+
+
+
+
+void smoothVorticity(VortexSheetMesh& mesh, int iter=1, Real sigma=0.2, Real alpha=0.8) {
+ const Real mult = -0.5 / sigma / sigma;
+
+ // pre-calculate positions and weights
+ vector<Vec3> vort(mesh.numTris()), pos(mesh.numTris());
+ vector<Real> weights(3*mesh.numTris());
+ vector<int> index(3*mesh.numTris());
+ for(int i=0; i<mesh.numTris(); i++) {
+ pos[i] = mesh.getFaceCenter(i);
+ mesh.sheet(i).vorticitySmoothed = mesh.sheet(i).vorticity;
+ }
+ for(int i=0; i<mesh.numTris(); i++) {
+ for (int c=0; c<3; c++) {
+ int oc = mesh.corners(i,c).opposite;
+ if (oc>=0) {
+ int t = mesh.corners(oc).tri;
+ weights[3*i+c] = exp(normSquare(pos[t]-pos[i])*mult);
+ index[3*i+c] = t;
+ }
+ else {
+ weights[3*i+c] = 0;
+ index[3*i+c] = 0;
+ }
+ }
+ }
+
+ for (int it=0; it<iter; ++it) {
+ // first, preload
+ for(int i=0; i<mesh.numTris(); i++) vort[i] = mesh.sheet(i).vorticitySmoothed;
+
+ for(int i=0,idx=0; i<mesh.numTris(); i++) {
+ // loop over adjacent tris
+ Real sum=1.0f;
+ Vec3 v=vort[i];
+ for (int c=0;c<3;c++,idx++) {
+ Real w = weights[index[idx]];
+ v += w*vort[index[idx]];
+ sum += w;
+ }
+ mesh.sheet(i).vorticitySmoothed = v/sum;
+ }
+ }
+ for(int i=0; i<mesh.numTris(); i++) mesh.sheet(i).vorticitySmoothed *= alpha;
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "smoothVorticity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); int iter = _args.getOpt<int >("iter",1,1,&_lock); Real sigma = _args.getOpt<Real >("sigma",2,0.2,&_lock); Real alpha = _args.getOpt<Real >("alpha",3,0.8,&_lock); _retval = getPyNone(); smoothVorticity(mesh,iter,sigma,alpha); _args.check(); }
+ pbFinalizePlugin(parent,"smoothVorticity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("smoothVorticity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_smoothVorticity ("","smoothVorticity",_W_4);
+extern "C" {
+ void PbRegister_smoothVorticity() {
+ KEEP_UNUSED(_RP_smoothVorticity); }
+ }
+
+
+
+//! Seed Vortex Particles inside shape with K41 characteristics
+void VPseedK41(VortexParticleSystem& system, const Shape* shape, Real strength=0, Real sigma0=0.2, Real sigma1=1.0, Real probability=1.0, Real N=3.0) {
+ Grid<Real> temp(system.getParent());
+ const Real dt = system.getParent()->getDt();
+ static RandomStream rand(3489572);
+ Real s0 = pow( (Real)sigma0, (Real)(-N+1.0) );
+ Real s1 = pow( (Real)sigma1, (Real)(-N+1.0) );
+
+ FOR_IJK(temp) {
+ if (shape->isInsideGrid(i,j,k)) {
+ if (rand.getReal() < probability*dt) {
+ Real p = rand.getReal();
+ Real sigma = pow( (1.0-p)*s0 + p*s1, 1./(-N+1.0) );
+ Vec3 randDir (rand.getReal(), rand.getReal(), rand.getReal());
+ Vec3 posUpd (i+rand.getReal(), j+rand.getReal(), k+rand.getReal());
+ normalize(randDir);
+ Vec3 vorticity = randDir * strength * pow( (Real)sigma, (Real)(-10./6.+N/2.0) );
+ system.add(VortexParticleData(posUpd, vorticity, sigma));
+ }
+ }
+ }
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "VPseedK41" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexParticleSystem& system = *_args.getPtr<VortexParticleSystem >("system",0,&_lock); const Shape* shape = _args.getPtr<Shape >("shape",1,&_lock); Real strength = _args.getOpt<Real >("strength",2,0,&_lock); Real sigma0 = _args.getOpt<Real >("sigma0",3,0.2,&_lock); Real sigma1 = _args.getOpt<Real >("sigma1",4,1.0,&_lock); Real probability = _args.getOpt<Real >("probability",5,1.0,&_lock); Real N = _args.getOpt<Real >("N",6,3.0,&_lock); _retval = getPyNone(); VPseedK41(system,shape,strength,sigma0,sigma1,probability,N); _args.check(); }
+ pbFinalizePlugin(parent,"VPseedK41", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VPseedK41",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_VPseedK41 ("","VPseedK41",_W_5);
+extern "C" {
+ void PbRegister_VPseedK41() {
+ KEEP_UNUSED(_RP_VPseedK41); }
+ }
+
+
+
+//! Vortex-in-cell integration
+
+void VICintegration(VortexSheetMesh& mesh, Real sigma, Grid<Vec3>& vel, const FlagGrid& flags, Grid<Vec3>* vorticity=NULL, Real cgMaxIterFac=1.5, Real cgAccuracy=1e-3, Real scale = 0.01, int precondition=0) {
+
+ MuTime t0;
+ const Real fac = 16.0; // experimental factor to balance out regularization
+
+ // if no vort grid is given, use a temporary one
+ Grid<Vec3> vortTemp(mesh.getParent());
+ Grid<Vec3>& vort = (vorticity) ? (*vorticity) : (vortTemp);
+ vort.clear();
+
+ // map vorticity to grid using Peskin kernel
+ int sgi = ceil(sigma);
+ Real pkfac=M_PI/sigma;
+ const int numTris = mesh.numTris();
+ for (int t=0; t<numTris; t++) {
+ Vec3 pos = mesh.getFaceCenter(t);
+ Vec3 v = mesh.sheet(t).vorticity * mesh.getFaceArea(t) * fac;
+
+ // inner kernel
+ // first, summate
+ Real sum=0;
+ for (int i=-sgi; i<sgi; i++) {
+ if (pos.x+i < 0 || (int)pos.x+i >= vort.getSizeX()) continue;
+ for (int j=-sgi; j<sgi; j++) {
+ if (pos.y+j < 0 || (int)pos.y+j >= vort.getSizeY()) continue;
+ for (int k=-sgi; k<sgi; k++) {
+ if (pos.z+k < 0 || (int)pos.z+k >= vort.getSizeZ()) continue;
+ Vec3i cell(pos.x+i, pos.y+j, pos.z+k);
+ if (!flags.isFluid(cell)) continue;
+ Vec3 d = pos - Vec3(i+0.5+floor(pos.x), j+0.5+floor(pos.y), k+0.5+floor(pos.z));
+ Real dl = norm(d);
+ if (dl > sigma) continue;
+ // precalc Peskin kernel
+ sum += 1.0 + cos(dl * pkfac);
+ }
+ }
+ }
+ // then, apply normalized kernel
+ Real wnorm = 1.0/sum;
+ for (int i=-sgi; i<sgi; i++) {
+ if (pos.x+i < 0 || (int)pos.x+i >= vort.getSizeX()) continue;
+ for (int j=-sgi; j<sgi; j++) {
+ if (pos.y+j < 0 || (int)pos.y+j >= vort.getSizeY()) continue;
+ for (int k=-sgi; k<sgi; k++) {
+ if (pos.z+k < 0 || (int)pos.z+k >= vort.getSizeZ()) continue;
+ Vec3i cell(pos.x+i, pos.y+j, pos.z+k);
+ if (!flags.isFluid(cell)) continue;
+ Vec3 d = pos - Vec3(i+0.5+floor(pos.x), j+0.5+floor(pos.y), k+0.5+floor(pos.z));
+ Real dl = norm(d);
+ if (dl > sigma) continue;
+ Real w = (1.0 + cos(dl * pkfac))*wnorm;
+ vort(cell) += v * w;
+ }
+ }
+ }
+ }
+
+ // Prepare grids for poisson solve
+ Grid<Vec3> vortexCurl(mesh.getParent());
+ Grid<Real> rhs(mesh.getParent());
+ Grid<Real> solution(mesh.getParent());
+ Grid<Real> residual(mesh.getParent());
+ Grid<Real> search(mesh.getParent());
+ Grid<Real> temp1(mesh.getParent());
+ Grid<Real> A0(mesh.getParent());
+ Grid<Real> Ai(mesh.getParent());
+ Grid<Real> Aj(mesh.getParent());
+ Grid<Real> Ak(mesh.getParent());
+ Grid<Real> pca0(mesh.getParent());
+ Grid<Real> pca1(mesh.getParent());
+ Grid<Real> pca2(mesh.getParent());
+ Grid<Real> pca3(mesh.getParent());
+
+ MakeLaplaceMatrix (flags, A0, Ai, Aj, Ak);
+ CurlOp(vort, vortexCurl);
+
+ // Solve vector poisson equation
+ for (int c=0; c<3; c++) {
+ // construct rhs
+ if (vel.getType() & GridBase::TypeMAC)
+ GetShiftedComponent(vortexCurl, rhs, c);
+ else
+ GetComponent(vortexCurl, rhs, c);
+
+ // prepare CG solver
+ const int maxIter = (int)(cgMaxIterFac * vel.getSize().max());
+ GridCgInterface *gcg = new GridCg<ApplyMatrix>(solution, rhs, residual, search, flags, temp1, &A0, &Ai, &Aj, &Ak );
+ gcg->setAccuracy(cgAccuracy);
+ gcg->setUseL2Norm(true);
+ gcg->setICPreconditioner( (GridCgInterface::PreconditionType)precondition, &pca0, &pca1, &pca2, &pca3);
+
+ // iterations
+ for (int iter=0; iter<maxIter; iter++) {
+ if (!gcg->iterate()) iter=maxIter;
+ }
+ debMsg("VICintegration CG iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma(), 1);
+ delete gcg;
+
+ // copy back
+ solution *= scale;
+ SetComponent(vel, solution, c);
+ }
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "VICintegration" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); Real sigma = _args.get<Real >("sigma",1,&_lock); Grid<Vec3>& vel = *_args.getPtr<Grid<Vec3> >("vel",2,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",3,&_lock); Grid<Vec3>* vorticity = _args.getPtrOpt<Grid<Vec3> >("vorticity",4,NULL,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",5,1.5,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",6,1e-3,&_lock); Real scale = _args.getOpt<Real >("scale",7,0.01,&_lock); int precondition = _args.getOpt<int >("precondition",8,0,&_lock); _retval = getPyNone(); VICintegration(mesh,sigma,vel,flags,vorticity,cgMaxIterFac,cgAccuracy,scale,precondition); _args.check(); }
+ pbFinalizePlugin(parent,"VICintegration", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VICintegration",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_VICintegration ("","VICintegration",_W_6);
+extern "C" {
+ void PbRegister_VICintegration() {
+ KEEP_UNUSED(_RP_VICintegration); }
+ }
+
+
+
+//! Obtain density field from levelset with linear gradient of size sigma over the interface
+void densityFromLevelset(const LevelsetGrid& phi, Grid<Real>& density, Real value=1.0, Real sigma=1.0) {
+ FOR_IJK(phi) {
+ // remove boundary
+ if (i<2 || j<2 || k<2 || i>=phi.getSizeX()-2 || j>=phi.getSizeY()-2 || k>=phi.getSizeZ()-2)
+ density(i,j,k) = 0;
+ else if (phi(i,j,k) < -sigma)
+ density(i,j,k) = value;
+ else if (phi(i,j,k) > sigma)
+ density(i,j,k) = 0;
+ else
+ density(i,j,k) = clamp((Real)(0.5*value/sigma*(1.0-phi(i,j,k))), (Real)0.0, value);
+ }
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "densityFromLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); Real value = _args.getOpt<Real >("value",2,1.0,&_lock); Real sigma = _args.getOpt<Real >("sigma",3,1.0,&_lock); _retval = getPyNone(); densityFromLevelset(phi,density,value,sigma); _args.check(); }
+ pbFinalizePlugin(parent,"densityFromLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("densityFromLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_densityFromLevelset ("","densityFromLevelset",_W_7);
+extern "C" {
+ void PbRegister_densityFromLevelset() {
+ KEEP_UNUSED(_RP_densityFromLevelset); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/waveletturbulence.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/waveletturbulence.cpp
new file mode 100644
index 00000000000..5f8bfed2f52
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/waveletturbulence.cpp
@@ -0,0 +1,691 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Functions for calculating wavelet turbulence,
+ * plus helpers to compute vorticity, and strain rate magnitude
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "shapes.h"
+#include "commonkernels.h"
+#include "noisefield.h"
+
+using namespace std;
+
+namespace Manta {
+
+//*****************************************************************************
+
+// first some fairly generic interpolation functions for grids with multiple sizes
+
+//! same as in grid.h , but takes an additional optional "desired" size
+inline void calcGridSizeFactorMod(Vec3i s1, Vec3i s2, Vec3i optSize, Vec3 scale, Vec3& sourceFactor, Vec3& retOff ) {
+ for(int c=0; c<3; c++) {
+ if(optSize[c] > 0){ s2[c] = optSize[c]; }
+ }
+ sourceFactor = calcGridSizeFactor(s1,s2) / scale;
+ retOff = -retOff * sourceFactor + sourceFactor*0.5;
+}
+
+
+void interpolateGrid( Grid<Real>& target, const Grid<Real>& source , Vec3 scale=Vec3(1.), Vec3 offset=Vec3(0.), Vec3i size=Vec3i(-1,-1,-1) , int orderSpace=1 ) {
+ Vec3 sourceFactor(1.), off2 = offset;
+ calcGridSizeFactorMod(source.getSize(), target.getSize(), size, scale, sourceFactor, off2);
+
+ // a brief note on a mantaflow specialty: the target grid has to be the first argument here!
+ // the parent fluidsolver object is taken from the first grid, and it determines the size of the
+ // loop for the kernel call. as we're writing into target, it's important to loop exactly over
+ // all cells of the target grid... (note, when calling the plugin in python, it doesnt matter anymore).
+
+ // sourceFactor offset necessary to shift eval points by half a small cell width
+ knInterpolateGridTempl<Real>(target, source, sourceFactor, off2, orderSpace);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "interpolateGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",0,&_lock); const Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",1,&_lock); Vec3 scale = _args.getOpt<Vec3 >("scale",2,Vec3(1.),&_lock); Vec3 offset = _args.getOpt<Vec3 >("offset",3,Vec3(0.),&_lock); Vec3i size = _args.getOpt<Vec3i >("size",4,Vec3i(-1,-1,-1) ,&_lock); int orderSpace = _args.getOpt<int >("orderSpace",5,1 ,&_lock); _retval = getPyNone(); interpolateGrid(target,source,scale,offset,size,orderSpace); _args.check(); }
+ pbFinalizePlugin(parent,"interpolateGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("interpolateGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_interpolateGrid ("","interpolateGrid",_W_0);
+extern "C" {
+ void PbRegister_interpolateGrid() {
+ KEEP_UNUSED(_RP_interpolateGrid); }
+ }
+
+
+
+
+void interpolateGridVec3( Grid<Vec3>& target, const Grid<Vec3>& source , Vec3 scale=Vec3(1.), Vec3 offset=Vec3(0.), Vec3i size=Vec3i(-1,-1,-1) , int orderSpace=1 ) {
+ Vec3 sourceFactor(1.), off2 = offset;
+ calcGridSizeFactorMod(source.getSize(), target.getSize(), size, scale, sourceFactor, off2);
+ knInterpolateGridTempl<Vec3>(target, source, sourceFactor, off2, orderSpace);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "interpolateGridVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",0,&_lock); const Grid<Vec3>& source = *_args.getPtr<Grid<Vec3> >("source",1,&_lock); Vec3 scale = _args.getOpt<Vec3 >("scale",2,Vec3(1.),&_lock); Vec3 offset = _args.getOpt<Vec3 >("offset",3,Vec3(0.),&_lock); Vec3i size = _args.getOpt<Vec3i >("size",4,Vec3i(-1,-1,-1) ,&_lock); int orderSpace = _args.getOpt<int >("orderSpace",5,1 ,&_lock); _retval = getPyNone(); interpolateGridVec3(target,source,scale,offset,size,orderSpace); _args.check(); }
+ pbFinalizePlugin(parent,"interpolateGridVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("interpolateGridVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_interpolateGridVec3 ("","interpolateGridVec3",_W_1);
+extern "C" {
+ void PbRegister_interpolateGridVec3() {
+ KEEP_UNUSED(_RP_interpolateGridVec3); }
+ }
+
+
+
+
+//!interpolate a mac velocity grid from one size to another size
+
+
+ struct KnInterpolateMACGrid : public KernelBase {
+ KnInterpolateMACGrid(MACGrid& target, const MACGrid& source, const Vec3& sourceFactor, const Vec3& off, int orderSpace) : KernelBase(&target,0) ,target(target),source(source),sourceFactor(sourceFactor),off(off),orderSpace(orderSpace) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& target, const MACGrid& source, const Vec3& sourceFactor, const Vec3& off, int orderSpace ) {
+ Vec3 pos = Vec3(i,j,k) * sourceFactor + off;
+
+ Real vx = source.getInterpolatedHi(pos - Vec3(0.5,0,0), orderSpace)[0];
+ Real vy = source.getInterpolatedHi(pos - Vec3(0,0.5,0), orderSpace)[1];
+ Real vz = 0.f;
+ if(source.is3D()) vz = source.getInterpolatedHi(pos - Vec3(0,0,0.5), orderSpace)[2];
+
+ target(i,j,k) = Vec3(vx,vy,vz);
+} inline MACGrid& getArg0() {
+ return target; }
+ typedef MACGrid type0;inline const MACGrid& getArg1() {
+ return source; }
+ typedef MACGrid type1;inline const Vec3& getArg2() {
+ return sourceFactor; }
+ typedef Vec3 type2;inline const Vec3& getArg3() {
+ return off; }
+ typedef Vec3 type3;inline int& getArg4() {
+ return orderSpace; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel KnInterpolateMACGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,target,source,sourceFactor,off,orderSpace); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,target,source,sourceFactor,off,orderSpace); }
+ }
+ }
+ MACGrid& target; const MACGrid& source; const Vec3& sourceFactor; const Vec3& off; int orderSpace; }
+;
+
+
+void interpolateMACGrid(MACGrid& target, const MACGrid& source, Vec3 scale=Vec3(1.), Vec3 offset=Vec3(0.), Vec3i size=Vec3i(-1,-1,-1) , int orderSpace=1) {
+ Vec3 sourceFactor(1.), off2 = offset;
+ calcGridSizeFactorMod(source.getSize(), target.getSize(), size, scale, sourceFactor, off2);
+ KnInterpolateMACGrid(target, source, sourceFactor, off2, orderSpace);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "interpolateMACGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& target = *_args.getPtr<MACGrid >("target",0,&_lock); const MACGrid& source = *_args.getPtr<MACGrid >("source",1,&_lock); Vec3 scale = _args.getOpt<Vec3 >("scale",2,Vec3(1.),&_lock); Vec3 offset = _args.getOpt<Vec3 >("offset",3,Vec3(0.),&_lock); Vec3i size = _args.getOpt<Vec3i >("size",4,Vec3i(-1,-1,-1) ,&_lock); int orderSpace = _args.getOpt<int >("orderSpace",5,1,&_lock); _retval = getPyNone(); interpolateMACGrid(target,source,scale,offset,size,orderSpace); _args.check(); }
+ pbFinalizePlugin(parent,"interpolateMACGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("interpolateMACGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_interpolateMACGrid ("","interpolateMACGrid",_W_2);
+extern "C" {
+ void PbRegister_interpolateMACGrid() {
+ KEEP_UNUSED(_RP_interpolateMACGrid); }
+ }
+
+
+
+
+
+//*****************************************************************************
+
+//! Apply vector noise to grid, this is a simplified version - no position scaling or UVs
+
+
+
+ struct knApplySimpleNoiseVec3 : public KernelBase {
+ knApplySimpleNoiseVec3(const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale, const Grid<Real>* weight ) : KernelBase(&flags,0) ,flags(flags),target(target),noise(noise),scale(scale),weight(weight) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale, const Grid<Real>* weight ) {
+ if ( !flags.isFluid(i,j,k) ) return;
+ Real factor = 1;
+ if(weight) factor = (*weight)(i,j,k);
+ target(i,j,k) += noise.evaluateCurl( Vec3(i,j,k)+Vec3(0.5) ) * scale * factor;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Vec3>& getArg1() {
+ return target; }
+ typedef Grid<Vec3> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Real& getArg3() {
+ return scale; }
+ typedef Real type3;inline const Grid<Real>* getArg4() {
+ return weight; }
+ typedef Grid<Real> type4; void runMessage() { debMsg("Executing kernel knApplySimpleNoiseVec3 ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,target,noise,scale,weight); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,target,noise,scale,weight); }
+ }
+ }
+ const FlagGrid& flags; Grid<Vec3>& target; const WaveletNoiseField& noise; Real scale; const Grid<Real>* weight; }
+;
+
+
+void applySimpleNoiseVec3(const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale=1.0 , const Grid<Real>* weight=NULL ) {
+ // note - passing a MAC grid here is slightly inaccurate, we should evaluate each component separately
+ knApplySimpleNoiseVec3(flags, target, noise, scale , weight );
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "applySimpleNoiseVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.0 ,&_lock); const Grid<Real>* weight = _args.getPtrOpt<Grid<Real> >("weight",4,NULL ,&_lock); _retval = getPyNone(); applySimpleNoiseVec3(flags,target,noise,scale,weight); _args.check(); }
+ pbFinalizePlugin(parent,"applySimpleNoiseVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("applySimpleNoiseVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_applySimpleNoiseVec3 ("","applySimpleNoiseVec3",_W_3);
+extern "C" {
+ void PbRegister_applySimpleNoiseVec3() {
+ KEEP_UNUSED(_RP_applySimpleNoiseVec3); }
+ }
+
+
+
+
+//! Simple noise for a real grid , follows applySimpleNoiseVec3
+
+
+
+ struct knApplySimpleNoiseReal : public KernelBase {
+ knApplySimpleNoiseReal(const FlagGrid& flags, Grid<Real>& target, const WaveletNoiseField& noise, Real scale, const Grid<Real>* weight ) : KernelBase(&flags,0) ,flags(flags),target(target),noise(noise),scale(scale),weight(weight) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& target, const WaveletNoiseField& noise, Real scale, const Grid<Real>* weight ) {
+ if ( !flags.isFluid(i,j,k) ) return;
+ Real factor = 1;
+ if(weight) factor = (*weight)(i,j,k);
+ target(i,j,k) += noise.evaluate( Vec3(i,j,k)+Vec3(0.5) ) * scale * factor;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return target; }
+ typedef Grid<Real> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Real& getArg3() {
+ return scale; }
+ typedef Real type3;inline const Grid<Real>* getArg4() {
+ return weight; }
+ typedef Grid<Real> type4; void runMessage() { debMsg("Executing kernel knApplySimpleNoiseReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,target,noise,scale,weight); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,target,noise,scale,weight); }
+ }
+ }
+ const FlagGrid& flags; Grid<Real>& target; const WaveletNoiseField& noise; Real scale; const Grid<Real>* weight; }
+;
+
+
+void applySimpleNoiseReal(const FlagGrid& flags, Grid<Real>& target, const WaveletNoiseField& noise, Real scale=1.0 , const Grid<Real>* weight=NULL ) {
+ knApplySimpleNoiseReal(flags, target, noise, scale , weight );
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "applySimpleNoiseReal" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.0 ,&_lock); const Grid<Real>* weight = _args.getPtrOpt<Grid<Real> >("weight",4,NULL ,&_lock); _retval = getPyNone(); applySimpleNoiseReal(flags,target,noise,scale,weight); _args.check(); }
+ pbFinalizePlugin(parent,"applySimpleNoiseReal", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("applySimpleNoiseReal",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_applySimpleNoiseReal ("","applySimpleNoiseReal",_W_4);
+extern "C" {
+ void PbRegister_applySimpleNoiseReal() {
+ KEEP_UNUSED(_RP_applySimpleNoiseReal); }
+ }
+
+
+
+
+
+//! Apply vector-based wavelet noise to target grid
+//! This is the version with more functionality - supports uv grids, and on-the-fly interpolation
+//! of input grids.
+
+
+
+ struct knApplyNoiseVec3 : public KernelBase {
+ knApplyNoiseVec3(const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale, Real scaleSpatial, const Grid<Real>* weight, const Grid<Vec3>* uv, bool uvInterpol, const Vec3& sourceFactor ) : KernelBase(&flags,0) ,flags(flags),target(target),noise(noise),scale(scale),scaleSpatial(scaleSpatial),weight(weight),uv(uv),uvInterpol(uvInterpol),sourceFactor(sourceFactor) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale, Real scaleSpatial, const Grid<Real>* weight, const Grid<Vec3>* uv, bool uvInterpol, const Vec3& sourceFactor ) {
+ if ( !flags.isFluid(i,j,k) ) return;
+
+ // get weighting, interpolate if necessary
+ Real w = 1;
+ if(weight) {
+ if(!uvInterpol) {
+ w = (*weight)(i,j,k);
+ } else {
+ w = weight->getInterpolated( Vec3(i,j,k) * sourceFactor );
+ }
+ }
+
+ // compute position where to evaluate the noise
+ Vec3 pos = Vec3(i,j,k)+Vec3(0.5);
+ if(uv) {
+ if(!uvInterpol) {
+ pos = (*uv)(i,j,k);
+ } else {
+ pos = uv->getInterpolated( Vec3(i,j,k) * sourceFactor );
+ // uv coordinates are in local space - so we need to adjust the values of the positions
+ pos /= sourceFactor;
+ }
+ }
+ pos *= scaleSpatial;
+
+ Vec3 noiseVec3 = noise.evaluateCurl( pos ) * scale * w;
+ //noiseVec3=pos; // debug , show interpolated positions
+ target(i,j,k) += noiseVec3;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Vec3>& getArg1() {
+ return target; }
+ typedef Grid<Vec3> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Real& getArg3() {
+ return scale; }
+ typedef Real type3;inline Real& getArg4() {
+ return scaleSpatial; }
+ typedef Real type4;inline const Grid<Real>* getArg5() {
+ return weight; }
+ typedef Grid<Real> type5;inline const Grid<Vec3>* getArg6() {
+ return uv; }
+ typedef Grid<Vec3> type6;inline bool& getArg7() {
+ return uvInterpol; }
+ typedef bool type7;inline const Vec3& getArg8() {
+ return sourceFactor; }
+ typedef Vec3 type8; void runMessage() { debMsg("Executing kernel knApplyNoiseVec3 ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,target,noise,scale,scaleSpatial,weight,uv,uvInterpol,sourceFactor); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,target,noise,scale,scaleSpatial,weight,uv,uvInterpol,sourceFactor); }
+ }
+ }
+ const FlagGrid& flags; Grid<Vec3>& target; const WaveletNoiseField& noise; Real scale; Real scaleSpatial; const Grid<Real>* weight; const Grid<Vec3>* uv; bool uvInterpol; const Vec3& sourceFactor; }
+;
+
+
+void applyNoiseVec3(const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale=1.0 , Real scaleSpatial=1.0 , const Grid<Real>* weight=NULL , const Grid<Vec3>* uv=NULL ) {
+ // check whether the uv grid has a different resolution
+ bool uvInterpol = false;
+ // and pre-compute conversion (only used if uvInterpol==true)
+ // used for both uv and weight grid...
+ Vec3 sourceFactor = Vec3(1.);
+ if(uv) {
+ uvInterpol = (target.getSize() != uv->getSize());
+ sourceFactor = calcGridSizeFactor( uv->getSize(), target.getSize() );
+ } else if(weight) {
+ uvInterpol = (target.getSize() != weight->getSize());
+ sourceFactor = calcGridSizeFactor( weight->getSize(), target.getSize() );
+ }
+ if(uv && weight) assertMsg( uv->getSize() == weight->getSize(), "UV and weight grid have to match!");
+
+ // note - passing a MAC grid here is slightly inaccurate, we should evaluate each component separately
+ knApplyNoiseVec3(flags, target, noise, scale, scaleSpatial, weight , uv,uvInterpol,sourceFactor );
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "applyNoiseVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.0 ,&_lock); Real scaleSpatial = _args.getOpt<Real >("scaleSpatial",4,1.0 ,&_lock); const Grid<Real>* weight = _args.getPtrOpt<Grid<Real> >("weight",5,NULL ,&_lock); const Grid<Vec3>* uv = _args.getPtrOpt<Grid<Vec3> >("uv",6,NULL ,&_lock); _retval = getPyNone(); applyNoiseVec3(flags,target,noise,scale,scaleSpatial,weight,uv); _args.check(); }
+ pbFinalizePlugin(parent,"applyNoiseVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("applyNoiseVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_applyNoiseVec3 ("","applyNoiseVec3",_W_5);
+extern "C" {
+ void PbRegister_applyNoiseVec3() {
+ KEEP_UNUSED(_RP_applyNoiseVec3); }
+ }
+
+
+
+
+
+//! Compute energy of a staggered velocity field (at cell center)
+
+
+ struct KnApplyComputeEnergy : public KernelBase {
+ KnApplyComputeEnergy( const FlagGrid& flags, const MACGrid& vel, Grid<Real>& energy ) : KernelBase(&flags,0) ,flags(flags),vel(vel),energy(energy) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, Grid<Real>& energy ) {
+ Real e = 0.f;
+ if ( flags.isFluid(i,j,k) ) {
+ Vec3 v = vel.getCentered(i,j,k);
+ e = 0.5 * (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+ }
+ energy(i,j,k) = e;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline Grid<Real>& getArg2() {
+ return energy; }
+ typedef Grid<Real> type2; void runMessage() { debMsg("Executing kernel KnApplyComputeEnergy ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,vel,energy); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,flags,vel,energy); }
+ }
+ }
+ const FlagGrid& flags; const MACGrid& vel; Grid<Real>& energy; }
+;
+
+
+void computeEnergy( const FlagGrid& flags, const MACGrid& vel, Grid<Real>& energy ) {
+ KnApplyComputeEnergy( flags, vel, energy );
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "computeEnergy" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); Grid<Real>& energy = *_args.getPtr<Grid<Real> >("energy",2,&_lock); _retval = getPyNone(); computeEnergy(flags,vel,energy); _args.check(); }
+ pbFinalizePlugin(parent,"computeEnergy", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("computeEnergy",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_computeEnergy ("","computeEnergy",_W_6);
+extern "C" {
+ void PbRegister_computeEnergy() {
+ KEEP_UNUSED(_RP_computeEnergy); }
+ }
+
+
+
+
+
+void computeWaveletCoeffs(Grid<Real>& input) {
+ Grid<Real> temp1(input.getParent()), temp2(input.getParent());
+ WaveletNoiseField::computeCoefficients(input, temp1, temp2);
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "computeWaveletCoeffs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& input = *_args.getPtr<Grid<Real> >("input",0,&_lock); _retval = getPyNone(); computeWaveletCoeffs(input); _args.check(); }
+ pbFinalizePlugin(parent,"computeWaveletCoeffs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("computeWaveletCoeffs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_computeWaveletCoeffs ("","computeWaveletCoeffs",_W_7);
+extern "C" {
+ void PbRegister_computeWaveletCoeffs() {
+ KEEP_UNUSED(_RP_computeWaveletCoeffs); }
+ }
+
+
+
+// note - alomst the same as for vorticity confinement
+void computeVorticity(const MACGrid& vel, Grid<Vec3>& vorticity, Grid<Real>* norm=NULL) {
+ Grid<Vec3> velCenter(vel.getParent());
+ GetCentered(velCenter, vel);
+ CurlOp(velCenter, vorticity);
+ if(norm) GridNorm( *norm, vorticity);
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "computeVorticity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Vec3>& vorticity = *_args.getPtr<Grid<Vec3> >("vorticity",1,&_lock); Grid<Real>* norm = _args.getPtrOpt<Grid<Real> >("norm",2,NULL,&_lock); _retval = getPyNone(); computeVorticity(vel,vorticity,norm); _args.check(); }
+ pbFinalizePlugin(parent,"computeVorticity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("computeVorticity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_computeVorticity ("","computeVorticity",_W_8);
+extern "C" {
+ void PbRegister_computeVorticity() {
+ KEEP_UNUSED(_RP_computeVorticity); }
+ }
+
+
+
+// note - very similar to KnComputeProductionStrain, but for use as wavelet turb weighting
+
+
+ struct KnComputeStrainRateMag : public KernelBase {
+ KnComputeStrainRateMag(const MACGrid& vel, const Grid<Vec3>& velCenter, Grid<Real>& prod ) : KernelBase(&vel,1) ,vel(vel),velCenter(velCenter),prod(prod) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid& vel, const Grid<Vec3>& velCenter, Grid<Real>& prod ) {
+ // compute Sij = 1/2 * (dU_i/dx_j + dU_j/dx_i)
+ Vec3 diag = Vec3(vel(i+1,j,k).x, vel(i,j+1,k).y, 0. ) - vel(i,j,k);
+ if(vel.is3D()) diag[2] += vel(i,j,k+1).z;
+ else diag[2] = 0.;
+
+ Vec3 ux = 0.5*(velCenter(i+1,j,k)-velCenter(i-1,j,k));
+ Vec3 uy = 0.5*(velCenter(i,j+1,k)-velCenter(i,j-1,k));
+ Vec3 uz;
+ if(vel.is3D()) uz=0.5*(velCenter(i,j,k+1)-velCenter(i,j,k-1));
+
+ Real S12 = 0.5*(ux.y+uy.x);
+ Real S13 = 0.5*(ux.z+uz.x);
+ Real S23 = 0.5*(uy.z+uz.y);
+ Real S2 = square(diag.x) + square(diag.y) + square(diag.z) +
+ 2.0*square(S12) + 2.0*square(S13) + 2.0*square(S23);
+ prod(i,j,k) = S2;
+} inline const MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const Grid<Vec3>& getArg1() {
+ return velCenter; }
+ typedef Grid<Vec3> type1;inline Grid<Real>& getArg2() {
+ return prod; }
+ typedef Grid<Real> type2; void runMessage() { debMsg("Executing kernel KnComputeStrainRateMag ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,velCenter,prod); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,vel,velCenter,prod); }
+ }
+ }
+ const MACGrid& vel; const Grid<Vec3>& velCenter; Grid<Real>& prod; }
+;
+void computeStrainRateMag(const MACGrid& vel, Grid<Real>& mag) {
+ Grid<Vec3> velCenter(vel.getParent());
+ GetCentered(velCenter, vel);
+ KnComputeStrainRateMag(vel, velCenter, mag);
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "computeStrainRateMag" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Real>& mag = *_args.getPtr<Grid<Real> >("mag",1,&_lock); _retval = getPyNone(); computeStrainRateMag(vel,mag); _args.check(); }
+ pbFinalizePlugin(parent,"computeStrainRateMag", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("computeStrainRateMag",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_computeStrainRateMag ("","computeStrainRateMag",_W_9);
+extern "C" {
+ void PbRegister_computeStrainRateMag() {
+ KEEP_UNUSED(_RP_computeStrainRateMag); }
+ }
+
+
+
+
+// extrapolate a real grid into a flagged region (based on initial flags)
+// by default extrapolates from fluid to obstacle cells
+template<class T>
+void extrapolSimpleFlagsHelper (const FlagGrid& flags, Grid<T>& val, int distance = 4,
+ int flagFrom=FlagGrid::TypeFluid, int flagTo=FlagGrid::TypeObstacle )
+{
+ Grid<int> tmp( flags.getParent() );
+ int dim = (flags.is3D() ? 3:2);
+ const Vec3i nb[6] = {
+ Vec3i(1 ,0,0), Vec3i(-1,0,0),
+ Vec3i(0,1 ,0), Vec3i(0,-1,0),
+ Vec3i(0,0,1 ), Vec3i(0,0,-1) };
+
+ // remove all fluid cells (set to 1)
+ tmp.clear();
+ bool foundTarget = false;
+ FOR_IJK_BND(flags,0) {
+ if (flags(i,j,k) & flagFrom)
+ tmp( Vec3i(i,j,k) ) = 1;
+ if (!foundTarget && (flags(i,j,k) & flagTo)) foundTarget=true;
+ }
+ // optimization, skip extrapolation if we dont have any cells to extrapolate to
+ if(!foundTarget) {
+ debMsg("No target cells found, skipping extrapolation", 1);
+ return;
+ }
+
+ // extrapolate for given distance
+ for(int d=1; d<1+distance; ++d) {
+
+ // TODO, parallelize
+ FOR_IJK_BND(flags,1) {
+ if (tmp(i,j,k) != 0) continue;
+ if (!(flags(i,j,k) & flagTo)) continue;
+
+ // copy from initialized neighbors
+ Vec3i p(i,j,k);
+ int nbs = 0;
+ T avgVal = 0.;
+ for (int n=0; n<2*dim; ++n) {
+ if (tmp(p+nb[n]) == d) {
+ avgVal += val(p+nb[n]);
+ nbs++;
+ }
+ }
+
+ if(nbs>0) {
+ tmp(p) = d+1;
+ val(p) = avgVal / nbs;
+ }
+ }
+
+ } // distance
+}
+
+
+void extrapolateSimpleFlags(const FlagGrid& flags, GridBase* val, int distance = 4, int flagFrom=FlagGrid::TypeFluid, int flagTo=FlagGrid::TypeObstacle ) {
+ if (val->getType() & GridBase::TypeReal) {
+ extrapolSimpleFlagsHelper<Real>(flags,*((Grid<Real>*) val),distance,flagFrom,flagTo);
+ }
+ else if (val->getType() & GridBase::TypeInt) {
+ extrapolSimpleFlagsHelper<int >(flags,*((Grid<int >*) val),distance,flagFrom,flagTo);
+ }
+ else if (val->getType() & GridBase::TypeVec3) {
+ extrapolSimpleFlagsHelper<Vec3>(flags,*((Grid<Vec3>*) val),distance,flagFrom,flagTo);
+ }
+ else
+ errMsg("extrapolateSimpleFlags: Grid Type is not supported (only int, Real, Vec3)");
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "extrapolateSimpleFlags" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); GridBase* val = _args.getPtr<GridBase >("val",1,&_lock); int distance = _args.getOpt<int >("distance",2,4,&_lock); int flagFrom = _args.getOpt<int >("flagFrom",3,FlagGrid::TypeFluid,&_lock); int flagTo = _args.getOpt<int >("flagTo",4,FlagGrid::TypeObstacle ,&_lock); _retval = getPyNone(); extrapolateSimpleFlags(flags,val,distance,flagFrom,flagTo); _args.check(); }
+ pbFinalizePlugin(parent,"extrapolateSimpleFlags", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("extrapolateSimpleFlags",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_extrapolateSimpleFlags ("","extrapolateSimpleFlags",_W_10);
+extern "C" {
+ void PbRegister_extrapolateSimpleFlags() {
+ KEEP_UNUSED(_RP_extrapolateSimpleFlags); }
+ }
+
+
+
+//! convert vel to a centered grid, then compute its curl
+void getCurl(const MACGrid& vel, Grid<Real>& vort, int comp) {
+ Grid<Vec3> velCenter(vel.getParent()), curl(vel.getParent());
+
+ GetCentered(velCenter, vel);
+ CurlOp(velCenter, curl);
+ GetComponent(curl, vort, comp);
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getCurl" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Real>& vort = *_args.getPtr<Grid<Real> >("vort",1,&_lock); int comp = _args.get<int >("comp",2,&_lock); _retval = getPyNone(); getCurl(vel,vort,comp); _args.check(); }
+ pbFinalizePlugin(parent,"getCurl", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getCurl",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getCurl ("","getCurl",_W_11);
+extern "C" {
+ void PbRegister_getCurl() {
+ KEEP_UNUSED(_RP_getCurl); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/waves.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/waves.cpp
new file mode 100644
index 00000000000..b5f29e14728
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/plugin/waves.cpp
@@ -0,0 +1,314 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Wave equation
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include "conjugategrad.h"
+#include <cmath>
+
+using namespace std;
+
+namespace Manta {
+
+
+/******************************************************************************
+ *
+ * explicit integration
+ *
+ ******************************************************************************/
+
+
+
+ struct knCalcSecDeriv2d : public KernelBase {
+ knCalcSecDeriv2d(const Grid<Real>& v, Grid<Real>& ret) : KernelBase(&v,1) ,v(v),ret(ret) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Real>& v, Grid<Real>& ret ) {
+ ret(i,j,k) =
+ ( -4. * v(i,j,k) + v(i-1,j,k) + v(i+1,j,k) + v(i,j-1,k) + v(i,j+1,k) );
+} inline const Grid<Real>& getArg0() {
+ return v; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return ret; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel knCalcSecDeriv2d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,v,ret); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,v,ret); }
+ }
+ }
+ const Grid<Real>& v; Grid<Real>& ret; }
+;;
+
+//! calculate a second derivative for the wave equation
+void calcSecDeriv2d(const Grid<Real>& v, Grid<Real>& curv) {
+ knCalcSecDeriv2d(v,curv);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "calcSecDeriv2d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& v = *_args.getPtr<Grid<Real> >("v",0,&_lock); Grid<Real>& curv = *_args.getPtr<Grid<Real> >("curv",1,&_lock); _retval = getPyNone(); calcSecDeriv2d(v,curv); _args.check(); }
+ pbFinalizePlugin(parent,"calcSecDeriv2d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("calcSecDeriv2d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_calcSecDeriv2d ("","calcSecDeriv2d",_W_0);
+extern "C" {
+ void PbRegister_calcSecDeriv2d() {
+ KEEP_UNUSED(_RP_calcSecDeriv2d); }
+ }
+
+
+
+
+// mass conservation
+
+
+ struct knTotalSum : public KernelBase {
+ knTotalSum(Grid<Real>& h) : KernelBase(&h,1) ,h(h) ,sum(0) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& h ,double& sum) { sum += h(i,j,k); } inline operator double () {
+ return sum; }
+ inline double & getRet() {
+ return sum; }
+ inline Grid<Real>& getArg0() {
+ return h; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel knTotalSum ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+ double sum = 0;
+#pragma omp for nowait
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,h,sum);
+#pragma omp critical
+{this->sum += sum; } }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+ double sum = 0;
+#pragma omp for nowait
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,h,sum);
+#pragma omp critical
+{this->sum += sum; } }
+ }
+ }
+ Grid<Real>& h; double sum; }
+;
+
+//! calculate the sum of all values in a grid (for wave equation solves)
+Real totalSum(Grid<Real>& height) {
+ knTotalSum ts(height);
+ return ts.sum;
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "totalSum" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& height = *_args.getPtr<Grid<Real> >("height",0,&_lock); _retval = toPy(totalSum(height)); _args.check(); }
+ pbFinalizePlugin(parent,"totalSum", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("totalSum",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_totalSum ("","totalSum",_W_1);
+extern "C" {
+ void PbRegister_totalSum() {
+ KEEP_UNUSED(_RP_totalSum); }
+ }
+
+
+
+//! normalize all values in a grid (for wave equation solves)
+void normalizeSumTo(Grid<Real>& height, Real target) {
+ knTotalSum ts(height);
+ Real factor = target / ts.sum;
+ height.multConst(factor);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "normalizeSumTo" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& height = *_args.getPtr<Grid<Real> >("height",0,&_lock); Real target = _args.get<Real >("target",1,&_lock); _retval = getPyNone(); normalizeSumTo(height,target); _args.check(); }
+ pbFinalizePlugin(parent,"normalizeSumTo", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("normalizeSumTo",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_normalizeSumTo ("","normalizeSumTo",_W_2);
+extern "C" {
+ void PbRegister_normalizeSumTo() {
+ KEEP_UNUSED(_RP_normalizeSumTo); }
+ }
+
+
+
+
+/******************************************************************************
+ *
+ * implicit time integration
+ *
+ ******************************************************************************/
+
+
+
+//! Kernel: Construct the right-hand side of the poisson equation
+
+
+
+ struct MakeRhsWE : public KernelBase {
+ MakeRhsWE(const FlagGrid& flags, Grid<Real>& rhs, const Grid<Real>& ut, const Grid<Real>& utm1, Real s, bool crankNic=false) : KernelBase(&flags,1) ,flags(flags),rhs(rhs),ut(ut),utm1(utm1),s(s),crankNic(crankNic) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& rhs, const Grid<Real>& ut, const Grid<Real>& utm1, Real s, bool crankNic=false ) {
+ rhs(i,j,k) = ( 2.*ut(i,j,k) - utm1(i,j,k) );
+ if(crankNic) {
+ rhs(i,j,k) += s * ( -4.*ut(i,j,k) + 1.*ut(i-1,j,k) + 1.*ut(i+1,j,k) + 1.*ut(i,j-1,k) + 1.*ut(i,j+1,k) );
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return rhs; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return ut; }
+ typedef Grid<Real> type2;inline const Grid<Real>& getArg3() {
+ return utm1; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return s; }
+ typedef Real type4;inline bool& getArg5() {
+ return crankNic; }
+ typedef bool type5; void runMessage() { debMsg("Executing kernel MakeRhsWE ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,rhs,ut,utm1,s,crankNic); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=1; j < _maxY; j++) for (int i=1; i < _maxX; i++) op(i,j,k,flags,rhs,ut,utm1,s,crankNic); }
+ }
+ }
+ const FlagGrid& flags; Grid<Real>& rhs; const Grid<Real>& ut; const Grid<Real>& utm1; Real s; bool crankNic; }
+;
+
+
+
+
+
+//! do a CG solve for the wave equation (note, out grid only there for debugging... could be removed)
+
+
+
+
+
+void cgSolveWE(const FlagGrid& flags, Grid<Real>& ut, Grid<Real>& utm1, Grid<Real>& out, bool crankNic = false, Real cSqr = 0.25, Real cgMaxIterFac = 1.5, Real cgAccuracy = 1e-5 ) {
+ // reserve temp grids
+ FluidSolver* parent = flags.getParent();
+ Grid<Real> rhs(parent);
+ Grid<Real> residual(parent);
+ Grid<Real> search(parent);
+ Grid<Real> A0(parent);
+ Grid<Real> Ai(parent);
+ Grid<Real> Aj(parent);
+ Grid<Real> Ak(parent);
+ Grid<Real> tmp(parent);
+ // solution...
+ out.clear();
+
+ // setup matrix and boundaries
+ MakeLaplaceMatrix (flags, A0, Ai, Aj, Ak);
+ Real dt = parent->getDt();
+ Real s = dt*dt*cSqr * 0.5;
+ FOR_IJK(flags) {
+ Ai(i,j,k) *= s;
+ Aj(i,j,k) *= s;
+ Ak(i,j,k) *= s;
+ A0(i,j,k) *= s;
+ A0(i,j,k) += 1.;
+ }
+
+ // compute divergence and init right hand side
+ rhs.clear();
+ // h=dt
+ // rhs: = 2 ut - ut-1
+ // A: (h2 c2/ dx)=s , (1+4s)uij + s ui-1j + ...
+ // Cr.Nic.
+ // rhs: cr nic = 2 ut - ut-1 + h^2c^2/2 b
+ // A: (h2 c2/2 dx)=s , (1+4s)uij + s ui-1j + ...
+ MakeRhsWE kernMakeRhs(flags, rhs, ut,utm1, s, crankNic);
+
+ const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
+ GridCgInterface *gcg;
+ if (flags.is3D())
+ gcg = new GridCg<ApplyMatrix >(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+ else
+ gcg = new GridCg<ApplyMatrix2D>(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+
+ gcg->setAccuracy( cgAccuracy );
+
+ // no preconditioning for now...
+ for (int iter=0; iter<maxIter; iter++) {
+ if (!gcg->iterate()) iter=maxIter;
+ }
+ debMsg("cgSolveWaveEq iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma(), 1);
+
+ utm1.swap( ut );
+ ut.copyFrom( out );
+
+ delete gcg;
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "cgSolveWE" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& ut = *_args.getPtr<Grid<Real> >("ut",1,&_lock); Grid<Real>& utm1 = *_args.getPtr<Grid<Real> >("utm1",2,&_lock); Grid<Real>& out = *_args.getPtr<Grid<Real> >("out",3,&_lock); bool crankNic = _args.getOpt<bool >("crankNic",4,false,&_lock); Real cSqr = _args.getOpt<Real >("cSqr",5,0.25,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",6,1.5,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",7,1e-5 ,&_lock); _retval = getPyNone(); cgSolveWE(flags,ut,utm1,out,crankNic,cSqr,cgMaxIterFac,cgAccuracy); _args.check(); }
+ pbFinalizePlugin(parent,"cgSolveWE", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("cgSolveWE",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_cgSolveWE ("","cgSolveWE",_W_3);
+extern "C" {
+ void PbRegister_cgSolveWE() {
+ KEEP_UNUSED(_RP_cgSolveWE); }
+ }
+
+
+
+
+
+
+} //namespace
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py b/intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py
new file mode 100644
index 00000000000..1c7f01ab034
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py
@@ -0,0 +1,11 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py.reg
new file mode 100644
index 00000000000..bd36ccac6c2
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py.reg
@@ -0,0 +1,2 @@
+#include "registry.h"
+static const Pb::Register _reg("python/defines.py", "################################################################################\n#\n# MantaFlow fluid solver framework\n# Copyright 2011 Tobias Pfaff, Nils Thuerey \n#\n# This program is free software, distributed under the terms of the\n# Apache License, Version 2.0 \n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Defines some constants for use in python subprograms\n#\n#################################################################################\n\n# mantaflow conventions\nReal = float\n\n# some defines to make C code and scripts more alike...\nfalse = False\ntrue = True\nVec3 = vec3\nVec4 = vec4\nVec3Grid = VecGrid\n\n# grid flags\nFlagFluid = 1\nFlagObstacle = 2\nFlagEmpty = 4\nFlagInflow = 8\nFlagOutflow = 16\nFlagStick = 64\nFlagReserved = 256\n# and same for FlagGrid::CellType enum names:\nTypeFluid = 1\nTypeObstacle = 2\nTypeEmpty = 4\nTypeInflow = 8\nTypeOutflow = 16\nTypeStick = 64\nTypeReserved = 256\n\n# integration mode\nIntEuler = 0\nIntRK2 = 1\nIntRK4 = 2\n\n# CG preconditioner\nPcNone = 0\nPcMIC = 1\nPcMGDynamic = 2\nPcMGStatic = 3\n\n# particles\nPtypeSpray = 2\nPtypeBubble = 4\nPtypeFoam = 8\nPtypeTracer = 16\n\n\n\n\n");
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py.reg.cpp
new file mode 100644
index 00000000000..4453b91c673
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/python/defines.py.reg.cpp
@@ -0,0 +1,8 @@
+#include "registry.h"
+static const Pb::Register _reg("python/defines.py", "################################################################################\n#\n# MantaFlow fluid solver framework\n# Copyright 2011 Tobias Pfaff, Nils Thuerey \n#\n# This program is free software, distributed under the terms of the\n# Apache License, Version 2.0 \n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Defines some constants for use in python subprograms\n#\n#################################################################################\n\n# mantaflow conventions\nReal = float\n\n# some defines to make C code and scripts more alike...\nfalse = False\ntrue = True\nVec3 = vec3\nVec4 = vec4\nVec3Grid = VecGrid\n\n# grid flags\nFlagFluid = 1\nFlagObstacle = 2\nFlagEmpty = 4\nFlagInflow = 8\nFlagOutflow = 16\nFlagStick = 64\nFlagReserved = 256\n# and same for FlagGrid::CellType enum names:\nTypeFluid = 1\nTypeObstacle = 2\nTypeEmpty = 4\nTypeInflow = 8\nTypeOutflow = 16\nTypeStick = 64\nTypeReserved = 256\n\n# integration mode\nIntEuler = 0\nIntRK2 = 1\nIntRK4 = 2\n\n# CG preconditioner\nPcNone = 0\nPcMIC = 1\nPcMGDynamic = 2\nPcMGStatic = 3\n\n# particles\nPtypeSpray = 2\nPtypeBubble = 4\nPtypeFoam = 8\nPtypeTracer = 16\n\n\n\n\n");
+extern "C" {
+void PbRegister_file_0()
+{
+ KEEP_UNUSED(_reg);
+}
+} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/registration.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/registration.cpp
new file mode 100644
index 00000000000..211de7c79be
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/registration.cpp
@@ -0,0 +1,406 @@
+extern "C" {
+ extern void PbRegister_mantaMsg() ;
+ extern void PbRegister_printBuildInfo() ;
+ extern void PbRegister_setDebugLevel() ;
+ extern void PbRegister_assertNumpy() ;
+ extern void PbRegister_cgSolveDiffusion() ;
+ extern void PbRegister_gridMaxDiff() ;
+ extern void PbRegister_gridMaxDiffInt() ;
+ extern void PbRegister_gridMaxDiffVec3() ;
+ extern void PbRegister_copyMacToVec3() ;
+ extern void PbRegister_convertMacToVec3() ;
+ extern void PbRegister_resampleVec3ToMac() ;
+ extern void PbRegister_resampleMacToVec3() ;
+ extern void PbRegister_copyLevelsetToReal() ;
+ extern void PbRegister_copyVec3ToReal() ;
+ extern void PbRegister_copyRealToVec3() ;
+ extern void PbRegister_convertLevelsetToReal() ;
+ extern void PbRegister_swapComponents() ;
+ extern void PbRegister_getUvWeight() ;
+ extern void PbRegister_resetUvGrid() ;
+ extern void PbRegister_updateUvWeight() ;
+ extern void PbRegister_getGridAvg() ;
+ extern void PbRegister_getComponent() ;
+ extern void PbRegister_setComponent() ;
+ extern void PbRegister_markIsolatedFluidCell() ;
+ extern void PbRegister_copyMACData() ;
+ extern void PbRegister_getComp4d() ;
+ extern void PbRegister_setComp4d() ;
+ extern void PbRegister_grid4dMaxDiff() ;
+ extern void PbRegister_grid4dMaxDiffInt() ;
+ extern void PbRegister_grid4dMaxDiffVec3() ;
+ extern void PbRegister_grid4dMaxDiffVec4() ;
+ extern void PbRegister_setRegion4d() ;
+ extern void PbRegister_setRegion4dVec4() ;
+ extern void PbRegister_getSliceFrom4d() ;
+ extern void PbRegister_getSliceFrom4dVec() ;
+ extern void PbRegister_interpolateGrid4d() ;
+ extern void PbRegister_interpolateGrid4dVec() ;
+ extern void PbRegister_extrapolateMACSimple() ;
+ extern void PbRegister_extrapolateMACFromWeight() ;
+ extern void PbRegister_extrapolateLsSimple() ;
+ extern void PbRegister_extrapolateVec3Simple() ;
+ extern void PbRegister_getUniFileSize() ;
+ extern void PbRegister_printUniFileInfoString() ;
+ extern void PbRegister_getNpzFileSize() ;
+ extern void PbRegister_quantizeGrid() ;
+ extern void PbRegister_quantizeGridVec3() ;
+ extern void PbRegister_resetPhiInObs() ;
+ extern void PbRegister_advectSemiLagrange() ;
+ extern void PbRegister_addGravity() ;
+ extern void PbRegister_addGravityNoScale() ;
+ extern void PbRegister_addBuoyancy() ;
+ extern void PbRegister_setOpenBound() ;
+ extern void PbRegister_resetOutflow() ;
+ extern void PbRegister_setInflowBcs() ;
+ extern void PbRegister_setWallBcs() ;
+ extern void PbRegister_setInitialVelocity() ;
+ extern void PbRegister_vorticityConfinement() ;
+ extern void PbRegister_addForceField() ;
+ extern void PbRegister_setForceField() ;
+ extern void PbRegister_dissolveSmoke() ;
+ extern void PbRegister_apicMapPartsToMAC() ;
+ extern void PbRegister_apicMapMACGridToParts() ;
+ extern void PbRegister_sampleFlagsWithParticles() ;
+ extern void PbRegister_sampleLevelsetWithParticles() ;
+ extern void PbRegister_sampleShapeWithParticles() ;
+ extern void PbRegister_markFluidCells() ;
+ extern void PbRegister_testInitGridWithPos() ;
+ extern void PbRegister_adjustNumber() ;
+ extern void PbRegister_debugIntToReal() ;
+ extern void PbRegister_gridParticleIndex() ;
+ extern void PbRegister_unionParticleLevelset() ;
+ extern void PbRegister_averagedParticleLevelset() ;
+ extern void PbRegister_improvedParticleLevelset() ;
+ extern void PbRegister_pushOutofObs() ;
+ extern void PbRegister_mapPartsToMAC() ;
+ extern void PbRegister_mapPartsToGrid() ;
+ extern void PbRegister_mapPartsToGridVec3() ;
+ extern void PbRegister_mapGridToParts() ;
+ extern void PbRegister_mapGridToPartsVec3() ;
+ extern void PbRegister_mapMACToParts() ;
+ extern void PbRegister_flipVelocityUpdate() ;
+ extern void PbRegister_combineGridVel() ;
+ extern void PbRegister_getLaplacian() ;
+ extern void PbRegister_getCurvature() ;
+ extern void PbRegister_processBurn() ;
+ extern void PbRegister_updateFlame() ;
+ extern void PbRegister_getSpiralVelocity() ;
+ extern void PbRegister_setGradientYWeight() ;
+ extern void PbRegister_PD_fluid_guiding() ;
+ extern void PbRegister_releaseBlurPrecomp() ;
+ extern void PbRegister_KEpsilonComputeProduction() ;
+ extern void PbRegister_KEpsilonSources() ;
+ extern void PbRegister_KEpsilonBcs() ;
+ extern void PbRegister_KEpsilonGradientDiffusion() ;
+ extern void PbRegister_densityInflow() ;
+ extern void PbRegister_addNoise() ;
+ extern void PbRegister_setNoisePdata() ;
+ extern void PbRegister_setNoisePdataVec3() ;
+ extern void PbRegister_setNoisePdataInt() ;
+ extern void PbRegister_obstacleGradient() ;
+ extern void PbRegister_obstacleLevelset() ;
+ extern void PbRegister_applyEmission() ;
+ extern void PbRegister_densityInflowMeshNoise() ;
+ extern void PbRegister_densityInflowMesh() ;
+ extern void PbRegister_checkSymmetry() ;
+ extern void PbRegister_checkSymmetryVec3() ;
+ extern void PbRegister_projectPpmFull() ;
+ extern void PbRegister_addTestParts() ;
+ extern void PbRegister_pdataMaxDiff() ;
+ extern void PbRegister_calcCenterOfMass() ;
+ extern void PbRegister_updateFractions() ;
+ extern void PbRegister_setObstacleFlags() ;
+ extern void PbRegister_initVortexVelocity() ;
+ extern void PbRegister_blurMacGrid() ;
+ extern void PbRegister_blurRealGrid() ;
+ extern void PbRegister_smoothMesh() ;
+ extern void PbRegister_subdivideMesh() ;
+ extern void PbRegister_killSmallComponents() ;
+ extern void PbRegister_releaseMG() ;
+ extern void PbRegister_computePressureRhs() ;
+ extern void PbRegister_solvePressureSystem() ;
+ extern void PbRegister_correctVelocity() ;
+ extern void PbRegister_solvePressure() ;
+ extern void PbRegister_flipComputeSecondaryParticlePotentials() ;
+ extern void PbRegister_flipSampleSecondaryParticles() ;
+ extern void PbRegister_flipUpdateSecondaryParticles() ;
+ extern void PbRegister_flipDeleteParticlesInObstacle() ;
+ extern void PbRegister_debugGridInfo() ;
+ extern void PbRegister_setFlagsFromLevelset() ;
+ extern void PbRegister_setMACFromLevelset() ;
+ extern void PbRegister_flipComputePotentialTrappedAir() ;
+ extern void PbRegister_flipComputePotentialKineticEnergy() ;
+ extern void PbRegister_flipComputePotentialWaveCrest() ;
+ extern void PbRegister_flipComputeSurfaceNormals() ;
+ extern void PbRegister_flipUpdateNeighborRatio() ;
+ extern void PbRegister_addForcePvel() ;
+ extern void PbRegister_updateVelocityFromDeltaPos() ;
+ extern void PbRegister_eulerStep() ;
+ extern void PbRegister_setPartType() ;
+ extern void PbRegister_flipComputeSecondaryParticlePotentials() ;
+ extern void PbRegister_flipSampleSecondaryParticles() ;
+ extern void PbRegister_flipUpdateSecondaryParticles() ;
+ extern void PbRegister_flipDeleteParticlesInObstacle() ;
+ extern void PbRegister_debugGridInfo() ;
+ extern void PbRegister_setFlagsFromLevelset() ;
+ extern void PbRegister_setMACFromLevelset() ;
+ extern void PbRegister_flipComputePotentialTrappedAir() ;
+ extern void PbRegister_flipComputePotentialKineticEnergy() ;
+ extern void PbRegister_flipComputePotentialWaveCrest() ;
+ extern void PbRegister_flipComputeSurfaceNormals() ;
+ extern void PbRegister_flipUpdateNeighborRatio() ;
+ extern void PbRegister_particleSurfaceTurbulence() ;
+ extern void PbRegister_debugCheckParts() ;
+ extern void PbRegister_markAsFixed() ;
+ extern void PbRegister_texcoordInflow() ;
+ extern void PbRegister_meshSmokeInflow() ;
+ extern void PbRegister_vorticitySource() ;
+ extern void PbRegister_smoothVorticity() ;
+ extern void PbRegister_VPseedK41() ;
+ extern void PbRegister_VICintegration() ;
+ extern void PbRegister_densityFromLevelset() ;
+ extern void PbRegister_interpolateGrid() ;
+ extern void PbRegister_interpolateGridVec3() ;
+ extern void PbRegister_interpolateMACGrid() ;
+ extern void PbRegister_applySimpleNoiseVec3() ;
+ extern void PbRegister_applySimpleNoiseReal() ;
+ extern void PbRegister_applyNoiseVec3() ;
+ extern void PbRegister_computeEnergy() ;
+ extern void PbRegister_computeWaveletCoeffs() ;
+ extern void PbRegister_computeVorticity() ;
+ extern void PbRegister_computeStrainRateMag() ;
+ extern void PbRegister_extrapolateSimpleFlags() ;
+ extern void PbRegister_getCurl() ;
+ extern void PbRegister_calcSecDeriv2d() ;
+ extern void PbRegister_totalSum() ;
+ extern void PbRegister_normalizeSumTo() ;
+ extern void PbRegister_cgSolveWE() ;
+ extern void PbRegister_file_0();
+ extern void PbRegister_file_1();
+ extern void PbRegister_file_2();
+ extern void PbRegister_file_3();
+ extern void PbRegister_file_4();
+ extern void PbRegister_file_5();
+ extern void PbRegister_file_6();
+ extern void PbRegister_file_7();
+ extern void PbRegister_file_8();
+ extern void PbRegister_file_9();
+ extern void PbRegister_file_10();
+ extern void PbRegister_file_11();
+ extern void PbRegister_file_12();
+ extern void PbRegister_file_13();
+ extern void PbRegister_file_14();
+ extern void PbRegister_file_15();
+ extern void PbRegister_file_16();
+ extern void PbRegister_file_17();
+ extern void PbRegister_file_18();
+ extern void PbRegister_file_19();
+ extern void PbRegister_file_20();
+ extern void PbRegister_file_21();
+}
+
+namespace Pb {
+ void MantaEnsureRegistration()
+ {
+ PbRegister_mantaMsg() ;
+ PbRegister_printBuildInfo() ;
+ PbRegister_setDebugLevel() ;
+ PbRegister_assertNumpy() ;
+ PbRegister_cgSolveDiffusion() ;
+ PbRegister_gridMaxDiff() ;
+ PbRegister_gridMaxDiffInt() ;
+ PbRegister_gridMaxDiffVec3() ;
+ PbRegister_copyMacToVec3() ;
+ PbRegister_convertMacToVec3() ;
+ PbRegister_resampleVec3ToMac() ;
+ PbRegister_resampleMacToVec3() ;
+ PbRegister_copyLevelsetToReal() ;
+ PbRegister_copyVec3ToReal() ;
+ PbRegister_copyRealToVec3() ;
+ PbRegister_convertLevelsetToReal() ;
+ PbRegister_swapComponents() ;
+ PbRegister_getUvWeight() ;
+ PbRegister_resetUvGrid() ;
+ PbRegister_updateUvWeight() ;
+ PbRegister_getGridAvg() ;
+ PbRegister_getComponent() ;
+ PbRegister_setComponent() ;
+ PbRegister_markIsolatedFluidCell() ;
+ PbRegister_copyMACData() ;
+ PbRegister_getComp4d() ;
+ PbRegister_setComp4d() ;
+ PbRegister_grid4dMaxDiff() ;
+ PbRegister_grid4dMaxDiffInt() ;
+ PbRegister_grid4dMaxDiffVec3() ;
+ PbRegister_grid4dMaxDiffVec4() ;
+ PbRegister_setRegion4d() ;
+ PbRegister_setRegion4dVec4() ;
+ PbRegister_getSliceFrom4d() ;
+ PbRegister_getSliceFrom4dVec() ;
+ PbRegister_interpolateGrid4d() ;
+ PbRegister_interpolateGrid4dVec() ;
+ PbRegister_extrapolateMACSimple() ;
+ PbRegister_extrapolateMACFromWeight() ;
+ PbRegister_extrapolateLsSimple() ;
+ PbRegister_extrapolateVec3Simple() ;
+ PbRegister_getUniFileSize() ;
+ PbRegister_printUniFileInfoString() ;
+ PbRegister_getNpzFileSize() ;
+ PbRegister_quantizeGrid() ;
+ PbRegister_quantizeGridVec3() ;
+ PbRegister_resetPhiInObs() ;
+ PbRegister_advectSemiLagrange() ;
+ PbRegister_addGravity() ;
+ PbRegister_addGravityNoScale() ;
+ PbRegister_addBuoyancy() ;
+ PbRegister_setOpenBound() ;
+ PbRegister_resetOutflow() ;
+ PbRegister_setInflowBcs() ;
+ PbRegister_setWallBcs() ;
+ PbRegister_setInitialVelocity() ;
+ PbRegister_vorticityConfinement() ;
+ PbRegister_addForceField() ;
+ PbRegister_setForceField() ;
+ PbRegister_dissolveSmoke() ;
+ PbRegister_apicMapPartsToMAC() ;
+ PbRegister_apicMapMACGridToParts() ;
+ PbRegister_sampleFlagsWithParticles() ;
+ PbRegister_sampleLevelsetWithParticles() ;
+ PbRegister_sampleShapeWithParticles() ;
+ PbRegister_markFluidCells() ;
+ PbRegister_testInitGridWithPos() ;
+ PbRegister_adjustNumber() ;
+ PbRegister_debugIntToReal() ;
+ PbRegister_gridParticleIndex() ;
+ PbRegister_unionParticleLevelset() ;
+ PbRegister_averagedParticleLevelset() ;
+ PbRegister_improvedParticleLevelset() ;
+ PbRegister_pushOutofObs() ;
+ PbRegister_mapPartsToMAC() ;
+ PbRegister_mapPartsToGrid() ;
+ PbRegister_mapPartsToGridVec3() ;
+ PbRegister_mapGridToParts() ;
+ PbRegister_mapGridToPartsVec3() ;
+ PbRegister_mapMACToParts() ;
+ PbRegister_flipVelocityUpdate() ;
+ PbRegister_combineGridVel() ;
+ PbRegister_getLaplacian() ;
+ PbRegister_getCurvature() ;
+ PbRegister_processBurn() ;
+ PbRegister_updateFlame() ;
+ PbRegister_getSpiralVelocity() ;
+ PbRegister_setGradientYWeight() ;
+ PbRegister_PD_fluid_guiding() ;
+ PbRegister_releaseBlurPrecomp() ;
+ PbRegister_KEpsilonComputeProduction() ;
+ PbRegister_KEpsilonSources() ;
+ PbRegister_KEpsilonBcs() ;
+ PbRegister_KEpsilonGradientDiffusion() ;
+ PbRegister_densityInflow() ;
+ PbRegister_addNoise() ;
+ PbRegister_setNoisePdata() ;
+ PbRegister_setNoisePdataVec3() ;
+ PbRegister_setNoisePdataInt() ;
+ PbRegister_obstacleGradient() ;
+ PbRegister_obstacleLevelset() ;
+ PbRegister_applyEmission() ;
+ PbRegister_densityInflowMeshNoise() ;
+ PbRegister_densityInflowMesh() ;
+ PbRegister_checkSymmetry() ;
+ PbRegister_checkSymmetryVec3() ;
+ PbRegister_projectPpmFull() ;
+ PbRegister_addTestParts() ;
+ PbRegister_pdataMaxDiff() ;
+ PbRegister_calcCenterOfMass() ;
+ PbRegister_updateFractions() ;
+ PbRegister_setObstacleFlags() ;
+ PbRegister_initVortexVelocity() ;
+ PbRegister_blurMacGrid() ;
+ PbRegister_blurRealGrid() ;
+ PbRegister_smoothMesh() ;
+ PbRegister_subdivideMesh() ;
+ PbRegister_killSmallComponents() ;
+ PbRegister_releaseMG() ;
+ PbRegister_computePressureRhs() ;
+ PbRegister_solvePressureSystem() ;
+ PbRegister_correctVelocity() ;
+ PbRegister_solvePressure() ;
+ PbRegister_flipComputeSecondaryParticlePotentials() ;
+ PbRegister_flipSampleSecondaryParticles() ;
+ PbRegister_flipUpdateSecondaryParticles() ;
+ PbRegister_flipDeleteParticlesInObstacle() ;
+ PbRegister_debugGridInfo() ;
+ PbRegister_setFlagsFromLevelset() ;
+ PbRegister_setMACFromLevelset() ;
+ PbRegister_flipComputePotentialTrappedAir() ;
+ PbRegister_flipComputePotentialKineticEnergy() ;
+ PbRegister_flipComputePotentialWaveCrest() ;
+ PbRegister_flipComputeSurfaceNormals() ;
+ PbRegister_flipUpdateNeighborRatio() ;
+ PbRegister_addForcePvel() ;
+ PbRegister_updateVelocityFromDeltaPos() ;
+ PbRegister_eulerStep() ;
+ PbRegister_setPartType() ;
+ PbRegister_flipComputeSecondaryParticlePotentials() ;
+ PbRegister_flipSampleSecondaryParticles() ;
+ PbRegister_flipUpdateSecondaryParticles() ;
+ PbRegister_flipDeleteParticlesInObstacle() ;
+ PbRegister_debugGridInfo() ;
+ PbRegister_setFlagsFromLevelset() ;
+ PbRegister_setMACFromLevelset() ;
+ PbRegister_flipComputePotentialTrappedAir() ;
+ PbRegister_flipComputePotentialKineticEnergy() ;
+ PbRegister_flipComputePotentialWaveCrest() ;
+ PbRegister_flipComputeSurfaceNormals() ;
+ PbRegister_flipUpdateNeighborRatio() ;
+ PbRegister_particleSurfaceTurbulence() ;
+ PbRegister_debugCheckParts() ;
+ PbRegister_markAsFixed() ;
+ PbRegister_texcoordInflow() ;
+ PbRegister_meshSmokeInflow() ;
+ PbRegister_vorticitySource() ;
+ PbRegister_smoothVorticity() ;
+ PbRegister_VPseedK41() ;
+ PbRegister_VICintegration() ;
+ PbRegister_densityFromLevelset() ;
+ PbRegister_interpolateGrid() ;
+ PbRegister_interpolateGridVec3() ;
+ PbRegister_interpolateMACGrid() ;
+ PbRegister_applySimpleNoiseVec3() ;
+ PbRegister_applySimpleNoiseReal() ;
+ PbRegister_applyNoiseVec3() ;
+ PbRegister_computeEnergy() ;
+ PbRegister_computeWaveletCoeffs() ;
+ PbRegister_computeVorticity() ;
+ PbRegister_computeStrainRateMag() ;
+ PbRegister_extrapolateSimpleFlags() ;
+ PbRegister_getCurl() ;
+ PbRegister_calcSecDeriv2d() ;
+ PbRegister_totalSum() ;
+ PbRegister_normalizeSumTo() ;
+ PbRegister_cgSolveWE() ;
+ PbRegister_file_0();
+ PbRegister_file_1();
+ PbRegister_file_2();
+ PbRegister_file_3();
+ PbRegister_file_4();
+ PbRegister_file_5();
+ PbRegister_file_6();
+ PbRegister_file_7();
+ PbRegister_file_8();
+ PbRegister_file_9();
+ PbRegister_file_10();
+ PbRegister_file_11();
+ PbRegister_file_12();
+ PbRegister_file_13();
+ PbRegister_file_14();
+ PbRegister_file_15();
+ PbRegister_file_16();
+ PbRegister_file_17();
+ PbRegister_file_18();
+ PbRegister_file_19();
+ PbRegister_file_20();
+ PbRegister_file_21();
+ }
+}
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.cpp
new file mode 100644
index 00000000000..3d8bc4c299f
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.cpp
@@ -0,0 +1,694 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Shape classes
+ *
+ ******************************************************************************/
+
+#include "shapes.h"
+#include "commonkernels.h"
+#include "mesh.h"
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// Shape class members
+
+Shape::Shape (FluidSolver* parent)
+ : PbClass(parent), mType(TypeNone)
+{
+}
+
+LevelsetGrid Shape::computeLevelset() {
+ // note - 3d check deactivated! TODO double check...
+ LevelsetGrid phi(getParent());
+ generateLevelset(phi);
+ return phi;
+}
+
+bool Shape::isInside(const Vec3& pos) const {
+ return false;
+}
+
+//! Kernel: Apply a shape to a grid, setting value inside
+
+template <class T> struct ApplyShapeToGrid : public KernelBase {
+ ApplyShapeToGrid(Grid<T>* grid, Shape* shape, T value, FlagGrid* respectFlags) : KernelBase(grid,0) ,grid(grid),shape(shape),value(value),respectFlags(respectFlags) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>* grid, Shape* shape, T value, FlagGrid* respectFlags ) {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ if (shape->isInsideGrid(i,j,k))
+ (*grid)(i,j,k) = value;
+} inline Grid<T>* getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline Shape* getArg1() {
+ return shape; }
+ typedef Shape type1;inline T& getArg2() {
+ return value; }
+ typedef T type2;inline FlagGrid* getArg3() {
+ return respectFlags; }
+ typedef FlagGrid type3; void runMessage() { debMsg("Executing kernel ApplyShapeToGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,shape,value,respectFlags); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,shape,value,respectFlags); }
+ }
+ }
+ Grid<T>* grid; Shape* shape; T value; FlagGrid* respectFlags; }
+;
+
+//! Kernel: Apply a shape to a grid, setting value inside (scaling by SDF value)
+
+template <class T> struct ApplyShapeToGridSmooth : public KernelBase {
+ ApplyShapeToGridSmooth(Grid<T>* grid, Grid<Real>& phi, Real sigma, Real shift, T value, FlagGrid* respectFlags) : KernelBase(grid,0) ,grid(grid),phi(phi),sigma(sigma),shift(shift),value(value),respectFlags(respectFlags) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>* grid, Grid<Real>& phi, Real sigma, Real shift, T value, FlagGrid* respectFlags ) {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ const Real p = phi(i,j,k) - shift;
+ if (p < -sigma)
+ (*grid)(i,j,k) = value;
+ else if (p < sigma)
+ (*grid)(i,j,k) = value*(0.5f*(1.0f-p/sigma));
+} inline Grid<T>* getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline Grid<Real>& getArg1() {
+ return phi; }
+ typedef Grid<Real> type1;inline Real& getArg2() {
+ return sigma; }
+ typedef Real type2;inline Real& getArg3() {
+ return shift; }
+ typedef Real type3;inline T& getArg4() {
+ return value; }
+ typedef T type4;inline FlagGrid* getArg5() {
+ return respectFlags; }
+ typedef FlagGrid type5; void runMessage() { debMsg("Executing kernel ApplyShapeToGridSmooth ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,phi,sigma,shift,value,respectFlags); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,phi,sigma,shift,value,respectFlags); }
+ }
+ }
+ Grid<T>* grid; Grid<Real>& phi; Real sigma; Real shift; T value; FlagGrid* respectFlags; }
+;
+
+//! Kernel: Apply a shape to a MAC grid, setting value inside
+
+ struct ApplyShapeToMACGrid : public KernelBase {
+ ApplyShapeToMACGrid(MACGrid* grid, Shape* shape, Vec3 value, FlagGrid* respectFlags) : KernelBase(grid,0) ,grid(grid),shape(shape),value(value),respectFlags(respectFlags) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid* grid, Shape* shape, Vec3 value, FlagGrid* respectFlags ) {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ if (shape->isInside(Vec3(i,j+0.5,k+0.5))) (*grid)(i,j,k).x = value.x;
+ if (shape->isInside(Vec3(i+0.5,j,k+0.5))) (*grid)(i,j,k).y = value.y;
+ if (shape->isInside(Vec3(i+0.5,j+0.5,k))) (*grid)(i,j,k).z = value.z;
+} inline MACGrid* getArg0() {
+ return grid; }
+ typedef MACGrid type0;inline Shape* getArg1() {
+ return shape; }
+ typedef Shape type1;inline Vec3& getArg2() {
+ return value; }
+ typedef Vec3 type2;inline FlagGrid* getArg3() {
+ return respectFlags; }
+ typedef FlagGrid type3; void runMessage() { debMsg("Executing kernel ApplyShapeToMACGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,shape,value,respectFlags); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,grid,shape,value,respectFlags); }
+ }
+ }
+ MACGrid* grid; Shape* shape; Vec3 value; FlagGrid* respectFlags; }
+;
+
+void Shape::applyToGrid(GridBase* grid, FlagGrid* respectFlags) {
+# if NOPYTHON!=1
+ if (grid->getType() & GridBase::TypeInt)
+ ApplyShapeToGrid<int> ((Grid<int>*)grid, this, _args.get<int>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeReal)
+ ApplyShapeToGrid<Real> ((Grid<Real>*)grid, this, _args.get<Real>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeMAC)
+ ApplyShapeToMACGrid ((MACGrid*)grid, this, _args.get<Vec3>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeVec3)
+ ApplyShapeToGrid<Vec3> ((Grid<Vec3>*)grid, this, _args.get<Vec3>("value"), respectFlags);
+ else
+ errMsg("Shape::applyToGrid(): unknown grid type");
+# else
+ errMsg("Not yet supported...");
+# endif
+}
+
+void Shape::applyToGridSmooth(GridBase* grid, Real sigma, Real shift, FlagGrid* respectFlags) {
+ Grid<Real> phi(grid->getParent());
+ generateLevelset(phi);
+
+# if NOPYTHON!=1
+ if (grid->getType() & GridBase::TypeInt)
+ ApplyShapeToGridSmooth<int> ((Grid<int>*)grid, phi, sigma, shift, _args.get<int>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeReal)
+ ApplyShapeToGridSmooth<Real> ((Grid<Real>*)grid, phi, sigma, shift, _args.get<Real>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeVec3)
+ ApplyShapeToGridSmooth<Vec3> ((Grid<Vec3>*)grid, phi, sigma, shift, _args.get<Vec3>("value"), respectFlags);
+ else
+ errMsg("Shape::applyToGridSmooth(): unknown grid type");
+# else
+ errMsg("Not yet supported...");
+# endif
+}
+
+void Shape::collideMesh(Mesh& mesh) {
+ const Real margin = 0.2;
+
+ Grid<Real> phi(getParent());
+ Grid<Vec3> grad(getParent());
+ generateLevelset(phi);
+ GradientOp(grad, phi);
+
+ const int num=mesh.numNodes();
+ for(int i=0; i<num; i++) {
+ const Vec3& p = mesh.nodes(i).pos;
+ mesh.nodes(i).flags &= ~(Mesh::NfCollide | Mesh::NfMarked);
+ if (!phi.isInBounds(p,1)) continue;
+
+ for (int iter=0; iter<10; iter++) {
+ const Real dist= phi.getInterpolated(p);
+ if (dist<margin) {
+ Vec3 n = grad.getInterpolated(p);
+ normalize(n);
+ mesh.nodes(i).pos += (margin-dist) * n;
+ mesh.nodes(i).flags |= Mesh::NfCollide | Mesh::NfMarked;
+ }
+ else break;
+ }
+ }
+}
+
+//******************************************************************************
+// Derived shape class members
+
+Box::Box(FluidSolver* parent, Vec3 center, Vec3 p0, Vec3 p1, Vec3 size)
+ : Shape(parent)
+{
+ mType = TypeBox;
+ if (center.isValid() && size.isValid()) {
+ mP0 = center - size;
+ mP1 = center + size;
+ } else if (p0.isValid() && p1.isValid()) {
+ mP0 = p0;
+ mP1 = p1;
+ } else
+ errMsg("Box: specify either p0,p1 or size,center");
+
+}
+
+bool Box::isInside(const Vec3& pos) const {
+ return (pos.x >= mP0.x && pos.y >= mP0.y && pos.z >= mP0.z &&
+ pos.x <= mP1.x && pos.y <= mP1.y && pos.z <= mP1.z);
+}
+
+void Box::generateMesh(Mesh* mesh) {
+ const int quadidx[24] = { 0,4,6,2, 3,7,5,1, 0,1,5,4, 6,7,3,2, 0,2,3,1, 5,7,6,4 };
+ const int nodebase = mesh->numNodes();
+ int oldtri = mesh->numTris();
+ for (int i=0; i<8; i++) {
+ Node p;
+ p.flags = 0;
+ p.pos = mP0;
+ if (i&1) p.pos.x=mP1.x;
+ if (i&2) p.pos.y=mP1.y;
+ if (i&4) p.pos.z=mP1.z;
+ mesh->addNode(p);
+ }
+ for (int i=0; i<6; i++) {
+ mesh->addTri(Triangle(nodebase + quadidx[i*4+0], nodebase + quadidx[i*4+1], nodebase + quadidx[i*4+3]));
+ mesh->addTri(Triangle(nodebase + quadidx[i*4+1], nodebase + quadidx[i*4+2], nodebase + quadidx[i*4+3]));
+ }
+ mesh->rebuildCorners(oldtri,-1);
+ mesh->rebuildLookup(oldtri,-1);
+}
+
+//! Kernel: Analytic SDF for box shape
+ struct BoxSDF : public KernelBase {
+ BoxSDF(Grid<Real>& phi, const Vec3& p1, const Vec3& p2) : KernelBase(&phi,0) ,phi(phi),p1(p1),p2(p2) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& phi, const Vec3& p1, const Vec3& p2 ) {
+ const Vec3 p(i+0.5, j+0.5, k+0.5);
+ if (p.x <= p2.x && p.x >= p1.x && p.y <= p2.y && p.y >= p1.y && p.z <= p2.z && p.z >= p1.z) {
+ // inside: minimal surface distance
+ Real mx = max(p.x-p2.x, p1.x-p.x);
+ Real my = max(p.y-p2.y, p1.y-p.y);
+ Real mz = max(p.z-p2.z, p1.z-p.z);
+ if(!phi.is3D()) mz = mx; // skip for 2d...
+ phi(i,j,k) = max(mx,max(my,mz));
+ } else if (p.y <= p2.y && p.y >= p1.y && p.z <= p2.z && p.z >= p1.z) {
+ // outside plane X
+ phi(i,j,k) = max(p.x-p2.x, p1.x-p.x);
+ } else if (p.x <= p2.x && p.x >= p1.x && p.z <= p2.z && p.z >= p1.z) {
+ // outside plane Y
+ phi(i,j,k) = max(p.y-p2.y, p1.y-p.y);
+ } else if (p.x <= p2.x && p.x >= p1.x && p.y <= p2.y && p.y >= p1.y) {
+ // outside plane Z
+ phi(i,j,k) = max(p.z-p2.z, p1.z-p.z);
+ } else if (p.x > p1.x && p.x < p2.x) {
+ // lines X
+ Real m1 = sqrt(square(p1.y-p.y)+square(p1.z-p.z));
+ Real m2 = sqrt(square(p2.y-p.y)+square(p1.z-p.z));
+ Real m3 = sqrt(square(p1.y-p.y)+square(p2.z-p.z));
+ Real m4 = sqrt(square(p2.y-p.y)+square(p2.z-p.z));
+ phi(i,j,k) = min(m1,min(m2,min(m3,m4)));
+ } else if (p.y > p1.y && p.y < p2.y) {
+ // lines Y
+ Real m1 = sqrt(square(p1.x-p.x)+square(p1.z-p.z));
+ Real m2 = sqrt(square(p2.x-p.x)+square(p1.z-p.z));
+ Real m3 = sqrt(square(p1.x-p.x)+square(p2.z-p.z));
+ Real m4 = sqrt(square(p2.x-p.x)+square(p2.z-p.z));
+ phi(i,j,k) = min(m1,min(m2,min(m3,m4)));
+ } else if (p.z > p1.x && p.z < p2.z) {
+ // lines Z
+ Real m1 = sqrt(square(p1.y-p.y)+square(p1.x-p.x));
+ Real m2 = sqrt(square(p2.y-p.y)+square(p1.x-p.x));
+ Real m3 = sqrt(square(p1.y-p.y)+square(p2.x-p.x));
+ Real m4 = sqrt(square(p2.y-p.y)+square(p2.x-p.x));
+ phi(i,j,k) = min(m1,min(m2,min(m3,m4)));
+ } else {
+ // points
+ Real m = norm(p-Vec3(p1.x,p1.y,p1.z));
+ m = min(m, norm(p-Vec3(p1.x,p1.y,p2.z)));
+ m = min(m, norm(p-Vec3(p1.x,p2.y,p1.z)));
+ m = min(m, norm(p-Vec3(p1.x,p2.y,p2.z)));
+ m = min(m, norm(p-Vec3(p2.x,p1.y,p1.z)));
+ m = min(m, norm(p-Vec3(p2.x,p1.y,p2.z)));
+ m = min(m, norm(p-Vec3(p2.x,p2.y,p1.z)));
+ m = min(m, norm(p-Vec3(p2.x,p2.y,p2.z)));
+ phi(i,j,k) = m;
+ }
+} inline Grid<Real>& getArg0() {
+ return phi; }
+ typedef Grid<Real> type0;inline const Vec3& getArg1() {
+ return p1; }
+ typedef Vec3 type1;inline const Vec3& getArg2() {
+ return p2; }
+ typedef Vec3 type2; void runMessage() { debMsg("Executing kernel BoxSDF ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,phi,p1,p2); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,phi,p1,p2); }
+ }
+ }
+ Grid<Real>& phi; const Vec3& p1; const Vec3& p2; }
+;
+void Box::generateLevelset(Grid<Real>& phi) {
+ BoxSDF(phi, mP0, mP1);
+}
+
+Sphere::Sphere (FluidSolver* parent, Vec3 center, Real radius, Vec3 scale)
+ : Shape(parent), mCenter(center), mScale(scale), mRadius(radius)
+{
+ mType = TypeSphere;
+}
+
+bool Sphere::isInside(const Vec3& pos) const {
+ return normSquare((pos - mCenter) / mScale) <= mRadius * mRadius;
+}
+
+struct Tri { Vec3 t[3]; int i[3]; Tri(Vec3 a,Vec3 b, Vec3 c) {t[0]=a;t[1]=b;t[2]=c;}};
+void Sphere::generateMesh(Mesh* mesh) {
+ vector<Tri> tris;
+ const int iterations = 3;
+ int oldtri = mesh->numTris();
+
+ // start with octahedron
+ const Real d = sqrt(0.5);
+ Vec3 p[6] = {Vec3(0,1,0), Vec3(0,-1,0), Vec3(-d,0,-d), Vec3(d,0,-d), Vec3(d,0,d), Vec3(-d,0,d)};
+ tris.push_back(Tri(p[0],p[4],p[3]));
+ tris.push_back(Tri(p[0],p[5],p[4]));
+ tris.push_back(Tri(p[0],p[2],p[5]));
+ tris.push_back(Tri(p[0],p[3],p[2]));
+ tris.push_back(Tri(p[1],p[3],p[4]));
+ tris.push_back(Tri(p[1],p[4],p[5]));
+ tris.push_back(Tri(p[1],p[5],p[2]));
+ tris.push_back(Tri(p[1],p[2],p[3]));
+
+ // Bisect each edge and move to the surface of a unit sphere
+ for (int it=0; it<iterations; it++) {
+ int ntold = tris.size();
+ for (int i=0; i<ntold; i++) {
+ Vec3 pa = 0.5 * (tris[i].t[0] + tris[i].t[1]);
+ Vec3 pb = 0.5 * (tris[i].t[1] + tris[i].t[2]);
+ Vec3 pc = 0.5 * (tris[i].t[2] + tris[i].t[0]);
+ normalize(pa); normalize(pb); normalize(pc);
+
+ tris.push_back(Tri(tris[i].t[0], pa, pc));
+ tris.push_back(Tri(pa, tris[i].t[1], pb));
+ tris.push_back(Tri(pb, tris[i].t[2], pc));
+ tris[i].t[0] = pa;
+ tris[i].t[1] = pb;
+ tris[i].t[2] = pc;
+ }
+ }
+
+ // index + scale
+ vector<Vec3> nodes;
+ for (size_t i=0; i<tris.size(); i++) {
+ for (int t=0; t<3; t++) {
+ Vec3 p = mCenter + tris[i].t[t] * mRadius * mScale;
+ // vector already there ?
+ int idx=nodes.size();
+ for (size_t j=0; j<nodes.size(); j++) {
+ if (p==nodes[j]) {
+ idx = j; break;
+ }
+ }
+ if (idx == (int)nodes.size())
+ nodes.push_back(p);
+ tris[i].i[t] = idx;
+ }
+ }
+
+ // add the to mesh
+ const int ni = mesh->numNodes();
+ for (size_t i=0; i<nodes.size(); i++) {
+ mesh->addNode(Node(nodes[i]));}
+ for (size_t t=0; t<tris.size(); t++)
+ mesh->addTri(Triangle(tris[t].i[0]+ni, tris[t].i[1]+ni, tris[t].i[2]+ni));
+
+ mesh->rebuildCorners(oldtri,-1);
+ mesh->rebuildLookup(oldtri,-1);
+}
+
+ struct SphereSDF : public KernelBase {
+ SphereSDF(Grid<Real>& phi, Vec3 center, Real radius, Vec3 scale) : KernelBase(&phi,0) ,phi(phi),center(center),radius(radius),scale(scale) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& phi, Vec3 center, Real radius, Vec3 scale ) {
+ phi(i,j,k) = norm((Vec3(i+0.5,j+0.5,k+0.5)-center)/scale)-radius;
+} inline Grid<Real>& getArg0() {
+ return phi; }
+ typedef Grid<Real> type0;inline Vec3& getArg1() {
+ return center; }
+ typedef Vec3 type1;inline Real& getArg2() {
+ return radius; }
+ typedef Real type2;inline Vec3& getArg3() {
+ return scale; }
+ typedef Vec3 type3; void runMessage() { debMsg("Executing kernel SphereSDF ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,phi,center,radius,scale); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,phi,center,radius,scale); }
+ }
+ }
+ Grid<Real>& phi; Vec3 center; Real radius; Vec3 scale; }
+;
+void Sphere::generateLevelset(Grid<Real>& phi) {
+ SphereSDF(phi, mCenter, mRadius, mScale);
+}
+
+Cylinder::Cylinder(FluidSolver* parent, Vec3 center, Real radius, Vec3 z)
+ : Shape(parent), mCenter(center), mRadius(radius)
+{
+ mType = TypeCylinder;
+ mZDir = z;
+ mZ = normalize(mZDir);
+}
+
+bool Cylinder::isInside(const Vec3& pos) const {
+ Real z = dot(pos-mCenter, mZDir);
+ if (fabs(z) > mZ) return false;
+ Real r2 = normSquare(pos-mCenter)-square(z);
+ return r2 < square(mRadius);
+}
+
+void Cylinder::generateMesh(Mesh* mesh) {
+ // generate coordinate system
+ Vec3 x = getOrthogonalVector(mZDir)*mRadius;
+ Vec3 y = cross(x, mZDir);
+ Vec3 z = mZDir*mZ;
+ int oldtri = mesh->numTris();
+
+ // construct node ring
+ const int N = 20;
+ const int base = mesh->numNodes();
+ for (int i=0;i<N;i++) {
+ const Real phi = 2.0*M_PI*(Real)i/(Real)N;
+ Vec3 r = x*cos(phi) + y*sin(phi) + mCenter;
+ mesh->addNode(Node(r+z));
+ mesh->addNode(Node(r-z));
+ }
+ // top/bottom center
+ mesh->addNode(Node(mCenter+z));
+ mesh->addNode(Node(mCenter-z));
+
+ // connect with tris
+ for (int i=0;i<N;i++) {
+ int cur = base+2*i;
+ int next = base+2*((i+1)%N);
+ // outside
+ mesh->addTri(Triangle(cur, next, cur+1));
+ mesh->addTri(Triangle(next, next+1, cur+1));
+ // upper / lower
+ mesh->addTri(Triangle(cur,base+2*N,next));
+ mesh->addTri(Triangle(cur+1,next+1,base+2*N+1));
+ }
+
+ mesh->rebuildCorners(oldtri, -1);
+ mesh->rebuildLookup(oldtri,-1);
+}
+
+
+ struct CylinderSDF : public KernelBase {
+ CylinderSDF(Grid<Real>& phi, Vec3 center, Real radius, Vec3 zaxis, Real maxz) : KernelBase(&phi,0) ,phi(phi),center(center),radius(radius),zaxis(zaxis),maxz(maxz) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& phi, Vec3 center, Real radius, Vec3 zaxis, Real maxz ) {
+ Vec3 p=Vec3(i+0.5,j+0.5,k+0.5)-center;
+ Real z = fabs(dot(p, zaxis));
+ Real r = sqrt(normSquare(p)-z*z);
+ if (z < maxz) {
+ // cylinder z area
+ if (r < radius)
+ phi(i,j,k) = max(r-radius,z-maxz);
+ else
+ phi(i,j,k) = r-radius;
+ } else if (r < radius) {
+ // cylinder top area
+ phi(i,j,k) = fabs(z-maxz);
+ } else {
+ // edge
+ phi(i,j,k) = sqrt(square(z-maxz)+square(r-radius));
+ }
+} inline Grid<Real>& getArg0() {
+ return phi; }
+ typedef Grid<Real> type0;inline Vec3& getArg1() {
+ return center; }
+ typedef Vec3 type1;inline Real& getArg2() {
+ return radius; }
+ typedef Real type2;inline Vec3& getArg3() {
+ return zaxis; }
+ typedef Vec3 type3;inline Real& getArg4() {
+ return maxz; }
+ typedef Real type4; void runMessage() { debMsg("Executing kernel CylinderSDF ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,phi,center,radius,zaxis,maxz); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,phi,center,radius,zaxis,maxz); }
+ }
+ }
+ Grid<Real>& phi; Vec3 center; Real radius; Vec3 zaxis; Real maxz; }
+;
+void Cylinder::generateLevelset(Grid<Real>& phi) {
+ CylinderSDF(phi, mCenter, mRadius, mZDir, mZ);
+}
+
+Slope::Slope(FluidSolver* parent, Real anglexy, Real angleyz, Real origin, Vec3 gs)
+ : Shape(parent), mAnglexy(anglexy), mAngleyz(angleyz), mOrigin(origin), mGs(gs)
+{
+ mType = TypeSlope;
+}
+
+void Slope::generateMesh(Mesh* mesh) {
+
+ const int oldtri = mesh->numTris();
+
+ Vec3 v1(0.,mOrigin,0.);
+ mesh->addNode(Node(v1));
+
+ Real dy1 = mGs.z * std::tan(mAngleyz);
+ Vec3 v2(0., mOrigin - dy1, mGs.z);
+ mesh->addNode(Node(v2));
+
+ Real dy2 = mGs.x * std::tan(mAnglexy);
+ Vec3 v3(mGs.x, v2.y - dy2, mGs.z);
+ mesh->addNode(Node(v3));
+
+ Vec3 v4(mGs.x, mOrigin - dy2, 0.);
+ mesh->addNode(Node(v4));
+
+ mesh->addTri(Triangle(0, 1, 2));
+ mesh->addTri(Triangle(2, 3, 0));
+
+ mesh->rebuildCorners(oldtri, -1);
+ mesh->rebuildLookup(oldtri,-1);
+
+}
+
+bool Slope::isInside(const Vec3& pos) const {
+
+ const Real alpha = -mAnglexy * M_PI / 180.;
+ const Real beta = -mAngleyz * M_PI / 180.;
+
+ Vec3 n(0,1,0);
+
+ n.x = std::sin(alpha)*std::cos(beta);
+ n.y = std::cos(alpha)*std::cos(beta);
+ n.z = std::sin(beta);
+
+ normalize(n);
+
+ const Real fac = std::sqrt(n.x*n.x + n.y*n.y + n.z*n.z);
+
+ return ((n.x*(double)pos.x + n.y*(double)pos.y + n.z*(double)pos.z - mOrigin) / fac) <= 0.;
+
+
+}
+
+ struct SlopeSDF : public KernelBase {
+ SlopeSDF(const Vec3 &n, Grid<Real> &phiObs, const Real &fac, const Real &origin) : KernelBase(&phiObs,0) ,n(n),phiObs(phiObs),fac(fac),origin(origin) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Vec3 &n, Grid<Real> &phiObs, const Real &fac, const Real &origin ) {
+
+ phiObs(i,j,k) = (n.x*(double)i + n.y*(double)j + n.z*(double)k - origin) * fac;
+
+} inline const Vec3& getArg0() {
+ return n; }
+ typedef Vec3 type0;inline Grid<Real> & getArg1() {
+ return phiObs; }
+ typedef Grid<Real> type1;inline const Real& getArg2() {
+ return fac; }
+ typedef Real type2;inline const Real& getArg3() {
+ return origin; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel SlopeSDF ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) {
+
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int k=minZ; k < maxZ; k++) for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,n,phiObs,fac,origin); }
+ }
+ else {
+ const int k=0;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (int j=0; j < _maxY; j++) for (int i=0; i < _maxX; i++) op(i,j,k,n,phiObs,fac,origin); }
+ }
+ }
+ const Vec3& n; Grid<Real> & phiObs; const Real& fac; const Real& origin; }
+;
+
+void Slope::generateLevelset(Grid<Real>& phi) {
+
+ const Real alpha = -mAnglexy * M_PI / 180.;
+ const Real beta = -mAngleyz * M_PI / 180.;
+
+ Vec3 n(0,1,0);
+
+ n.x = std::sin(alpha)*std::cos(beta);
+ n.y = std::cos(alpha)*std::cos(beta);
+ n.z = std::sin(beta);
+
+ normalize(n);
+
+ const Real fac = 1. / std::sqrt(n.x*n.x + n.y*n.y + n.z*n.z);
+
+ SlopeSDF(n, phi, fac, mOrigin);
+
+}
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h
new file mode 100644
index 00000000000..f36c7ec232b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h
@@ -0,0 +1,285 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * shapes classes
+ *
+ ******************************************************************************/
+
+#ifndef _SHAPES_H
+#define _SHAPES_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "levelset.h"
+
+namespace Manta {
+
+// forward declaration
+class Mesh;
+
+//! Base class for all shapes
+class Shape : public PbClass {public:
+ enum GridType { TypeNone = 0, TypeBox = 1, TypeSphere = 2, TypeCylinder = 3, TypeSlope = 4 };
+
+ Shape(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Shape::Shape" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new Shape(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Shape::Shape" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Shape::Shape",e.what()); return -1; }
+ }
+
+
+ //! Get the type of grid
+ inline GridType getType() const { return mType; }
+
+ //! Apply shape to flag grid, set inside cells to <value>
+ void applyToGrid(GridBase* grid, FlagGrid* respectFlags=0); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::applyToGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; GridBase* grid = _args.getPtr<GridBase >("grid",0,&_lock); FlagGrid* respectFlags = _args.getPtrOpt<FlagGrid >("respectFlags",1,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->applyToGrid(grid,respectFlags); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::applyToGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::applyToGrid",e.what()); return 0; }
+ }
+
+ void applyToGridSmooth(GridBase* grid, Real sigma=1.0, Real shift=0, FlagGrid* respectFlags=0); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::applyToGridSmooth" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; GridBase* grid = _args.getPtr<GridBase >("grid",0,&_lock); Real sigma = _args.getOpt<Real >("sigma",1,1.0,&_lock); Real shift = _args.getOpt<Real >("shift",2,0,&_lock); FlagGrid* respectFlags = _args.getPtrOpt<FlagGrid >("respectFlags",3,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->applyToGridSmooth(grid,sigma,shift,respectFlags); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::applyToGridSmooth" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::applyToGridSmooth",e.what()); return 0; }
+ }
+
+ LevelsetGrid computeLevelset(); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::computeLevelset" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->computeLevelset()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::computeLevelset" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::computeLevelset",e.what()); return 0; }
+ }
+
+ void collideMesh(Mesh& mesh); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::collideMesh" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->collideMesh(mesh); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::collideMesh" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::collideMesh",e.what()); return 0; }
+ }
+
+ virtual Vec3 getCenter() const { return Vec3::Zero; } static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::getCenter" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getCenter()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::getCenter" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::getCenter",e.what()); return 0; }
+ }
+
+ virtual void setCenter(const Vec3& center) {} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::setCenter" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Vec3& center = _args.get<Vec3 >("center",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setCenter(center); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::setCenter" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::setCenter",e.what()); return 0; }
+ }
+
+ virtual Vec3 getExtent() const { return Vec3::Zero; } static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::getExtent" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getExtent()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::getExtent" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::getExtent",e.what()); return 0; }
+ }
+
+
+ //! Inside test of the shape
+ virtual bool isInside(const Vec3& pos) const;
+ inline bool isInsideGrid(int i, int j, int k) const { return isInside(Vec3(i+0.5,j+0.5,k+0.5)); };
+
+ virtual void generateMesh(Mesh* mesh) {} ;
+ virtual void generateLevelset(Grid<Real>& phi) {};
+
+protected: GridType mType; public: PbArgs _args; }
+#define _C_Shape
+;
+
+//! Dummy shape
+class NullShape : public Shape {
+public:
+ NullShape(FluidSolver* parent) :Shape(parent){} static int _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "NullShape::NullShape" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new NullShape(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"NullShape::NullShape" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("NullShape::NullShape",e.what()); return -1; }
+ }
+
+
+ virtual bool isInside(const Vec3& pos) const { return false; }
+ virtual void generateMesh(Mesh* mesh) {}
+
+protected: virtual void generateLevelset(Grid<Real>& phi) { gridSetConst<Real>( phi , 1000.0f ); } public: PbArgs _args; }
+#define _C_NullShape
+;
+
+//! Box shape
+class Box : public Shape {
+public:
+ Box(FluidSolver* parent, Vec3 center = Vec3::Invalid, Vec3 p0 = Vec3::Invalid, Vec3 p1 = Vec3::Invalid, Vec3 size = Vec3::Invalid); static int _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Box::Box" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); Vec3 center = _args.getOpt<Vec3 >("center",1,Vec3::Invalid,&_lock); Vec3 p0 = _args.getOpt<Vec3 >("p0",2,Vec3::Invalid,&_lock); Vec3 p1 = _args.getOpt<Vec3 >("p1",3,Vec3::Invalid,&_lock); Vec3 size = _args.getOpt<Vec3 >("size",4,Vec3::Invalid,&_lock); obj = new Box(parent,center,p0,p1,size); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Box::Box" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Box::Box",e.what()); return -1; }
+ }
+
+
+ inline Vec3 getSize() const { return mP1-mP0; }
+ inline Vec3 getP0() const { return mP0; }
+ inline Vec3 getP1() const { return mP1; }
+ virtual void setCenter(const Vec3& center) { Vec3 dh=0.5*(mP1-mP0); mP0 = center-dh; mP1 = center+dh;}
+ virtual Vec3 getCenter() const { return 0.5*(mP1+mP0); }
+ virtual Vec3 getExtent() const { return getSize(); }
+ virtual bool isInside(const Vec3& pos) const;
+ virtual void generateMesh(Mesh* mesh);
+ virtual void generateLevelset(Grid<Real>& phi);
+
+protected: Vec3 mP0, mP1; public: PbArgs _args; }
+#define _C_Box
+;
+
+//! Spherical shape
+class Sphere : public Shape {
+public:
+ Sphere(FluidSolver* parent, Vec3 center, Real radius, Vec3 scale=Vec3(1,1,1)); static int _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Sphere::Sphere" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); Vec3 center = _args.get<Vec3 >("center",1,&_lock); Real radius = _args.get<Real >("radius",2,&_lock); Vec3 scale = _args.getOpt<Vec3 >("scale",3,Vec3(1,1,1),&_lock); obj = new Sphere(parent,center,radius,scale); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Sphere::Sphere" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Sphere::Sphere",e.what()); return -1; }
+ }
+
+
+ virtual void setCenter(const Vec3& center) { mCenter = center; }
+ virtual Vec3 getCenter() const { return mCenter; }
+ inline Real getRadius() const { return mRadius; }
+ virtual Vec3 getExtent() const { return Vec3(2.0*mRadius); }
+ virtual bool isInside(const Vec3& pos) const;
+ virtual void generateMesh(Mesh* mesh);
+ virtual void generateLevelset(Grid<Real>& phi);
+
+protected:
+ Vec3 mCenter, mScale; Real mRadius; public: PbArgs _args; }
+#define _C_Sphere
+;
+
+//! Cylindrical shape
+class Cylinder : public Shape {
+public:
+ Cylinder(FluidSolver* parent, Vec3 center, Real radius, Vec3 z); static int _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Cylinder::Cylinder" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); Vec3 center = _args.get<Vec3 >("center",1,&_lock); Real radius = _args.get<Real >("radius",2,&_lock); Vec3 z = _args.get<Vec3 >("z",3,&_lock); obj = new Cylinder(parent,center,radius,z); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Cylinder::Cylinder" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Cylinder::Cylinder",e.what()); return -1; }
+ }
+
+
+ void setRadius(Real r) { mRadius = r; } static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Cylinder* pbo = dynamic_cast<Cylinder*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Cylinder::setRadius" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real r = _args.get<Real >("r",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setRadius(r); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Cylinder::setRadius" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Cylinder::setRadius",e.what()); return 0; }
+ }
+
+ void setZ(Vec3 z) { mZDir=z; mZ=normalize(mZDir); } static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Cylinder* pbo = dynamic_cast<Cylinder*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Cylinder::setZ" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 z = _args.get<Vec3 >("z",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setZ(z); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Cylinder::setZ" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Cylinder::setZ",e.what()); return 0; }
+ }
+
+
+ virtual void setCenter(const Vec3& center) { mCenter=center; }
+ virtual Vec3 getCenter() const { return mCenter; }
+ inline Real getRadius() const { return mRadius; }
+ inline Vec3 getZ() const { return mZ*mZDir; }
+ virtual Vec3 getExtent() const { return Vec3(2.0*sqrt(square(mZ)+square(mRadius))); }
+ virtual bool isInside(const Vec3& pos) const;
+ virtual void generateMesh(Mesh* mesh);
+ virtual void generateLevelset(Grid<Real>& phi);
+
+protected:
+ Vec3 mCenter, mZDir; Real mRadius, mZ; public: PbArgs _args; }
+#define _C_Cylinder
+;
+
+//! Slope shape
+// generates a levelset based on a plane
+// plane is specified by two angles and an offset on the y axis in (offset vector would be ( 0, offset, 0) )
+// the two angles are specified in degrees, between: y-axis and x-axis
+// y-axis and z-axis
+class Slope : public Shape {public:
+ Slope(FluidSolver* parent, Real anglexy, Real angleyz, Real origin, Vec3 gs); static int _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Slope::Slope" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); Real anglexy = _args.get<Real >("anglexy",1,&_lock); Real angleyz = _args.get<Real >("angleyz",2,&_lock); Real origin = _args.get<Real >("origin",3,&_lock); Vec3 gs = _args.get<Vec3 >("gs",4,&_lock); obj = new Slope(parent,anglexy,angleyz,origin,gs); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Slope::Slope" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Slope::Slope",e.what()); return -1; }
+ }
+
+
+ virtual void setOrigin (const Real& origin) { mOrigin=origin; }
+ virtual void setAnglexy(const Real& anglexy) { mAnglexy=anglexy; }
+ virtual void setAngleyz(const Real& angleyz) { mAnglexy=angleyz; }
+
+ inline Real getOrigin() const { return mOrigin; }
+ inline Real getmAnglexy() const { return mAnglexy; }
+ inline Real getmAngleyz() const { return mAngleyz; }
+ virtual bool isInside(const Vec3& pos) const;
+ virtual void generateMesh(Mesh* mesh);
+ virtual void generateLevelset(Grid<Real>& phi);
+
+protected:
+ Real mAnglexy, mAngleyz;
+ Real mOrigin; Vec3 mGs; public: PbArgs _args; }
+#define _C_Slope
+;
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h.reg
new file mode 100644
index 00000000000..31a77644b43
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h.reg
@@ -0,0 +1,28 @@
+#include "shapes.h"
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","Shape","PbClass"); template<> const char* Namify<Shape >::S = "Shape";
+>Shape^
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","Shape",Shape::_W_0);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","applyToGrid",Shape::_W_1);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","applyToGridSmooth",Shape::_W_2);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","computeLevelset",Shape::_W_3);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","collideMesh",Shape::_W_4);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","getCenter",Shape::_W_5);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","setCenter",Shape::_W_6);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","getExtent",Shape::_W_7);
++NullShape^ static const Pb::Register _R_$IDX$ ("NullShape","NullShape","Shape"); template<> const char* Namify<NullShape >::S = "NullShape";
+>NullShape^
++NullShape^ static const Pb::Register _R_$IDX$ ("NullShape","NullShape",NullShape::_W_8);
++Box^ static const Pb::Register _R_$IDX$ ("Box","Box","Shape"); template<> const char* Namify<Box >::S = "Box";
+>Box^
++Box^ static const Pb::Register _R_$IDX$ ("Box","Box",Box::_W_9);
++Sphere^ static const Pb::Register _R_$IDX$ ("Sphere","Sphere","Shape"); template<> const char* Namify<Sphere >::S = "Sphere";
+>Sphere^
++Sphere^ static const Pb::Register _R_$IDX$ ("Sphere","Sphere",Sphere::_W_10);
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","Cylinder","Shape"); template<> const char* Namify<Cylinder >::S = "Cylinder";
+>Cylinder^
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","Cylinder",Cylinder::_W_11);
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","setRadius",Cylinder::_W_12);
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","setZ",Cylinder::_W_13);
++Slope^ static const Pb::Register _R_$IDX$ ("Slope","Slope","Shape"); template<> const char* Namify<Slope >::S = "Slope";
+>Slope^
++Slope^ static const Pb::Register _R_$IDX$ ("Slope","Slope",Slope::_W_14);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h.reg.cpp
new file mode 100644
index 00000000000..719de2e65e6
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/shapes.h.reg.cpp
@@ -0,0 +1,72 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "shapes.h"
+namespace Manta {
+#ifdef _C_Box
+ static const Pb::Register _R_12 ("Box","Box","Shape"); template<> const char* Namify<Box >::S = "Box";
+ static const Pb::Register _R_13 ("Box","Box",Box::_W_9);
+#endif
+#ifdef _C_Cylinder
+ static const Pb::Register _R_14 ("Cylinder","Cylinder","Shape"); template<> const char* Namify<Cylinder >::S = "Cylinder";
+ static const Pb::Register _R_15 ("Cylinder","Cylinder",Cylinder::_W_11);
+ static const Pb::Register _R_16 ("Cylinder","setRadius",Cylinder::_W_12);
+ static const Pb::Register _R_17 ("Cylinder","setZ",Cylinder::_W_13);
+#endif
+#ifdef _C_NullShape
+ static const Pb::Register _R_18 ("NullShape","NullShape","Shape"); template<> const char* Namify<NullShape >::S = "NullShape";
+ static const Pb::Register _R_19 ("NullShape","NullShape",NullShape::_W_8);
+#endif
+#ifdef _C_Shape
+ static const Pb::Register _R_20 ("Shape","Shape","PbClass"); template<> const char* Namify<Shape >::S = "Shape";
+ static const Pb::Register _R_21 ("Shape","Shape",Shape::_W_0);
+ static const Pb::Register _R_22 ("Shape","applyToGrid",Shape::_W_1);
+ static const Pb::Register _R_23 ("Shape","applyToGridSmooth",Shape::_W_2);
+ static const Pb::Register _R_24 ("Shape","computeLevelset",Shape::_W_3);
+ static const Pb::Register _R_25 ("Shape","collideMesh",Shape::_W_4);
+ static const Pb::Register _R_26 ("Shape","getCenter",Shape::_W_5);
+ static const Pb::Register _R_27 ("Shape","setCenter",Shape::_W_6);
+ static const Pb::Register _R_28 ("Shape","getExtent",Shape::_W_7);
+#endif
+#ifdef _C_Slope
+ static const Pb::Register _R_29 ("Slope","Slope","Shape"); template<> const char* Namify<Slope >::S = "Slope";
+ static const Pb::Register _R_30 ("Slope","Slope",Slope::_W_14);
+#endif
+#ifdef _C_Sphere
+ static const Pb::Register _R_31 ("Sphere","Sphere","Shape"); template<> const char* Namify<Sphere >::S = "Sphere";
+ static const Pb::Register _R_32 ("Sphere","Sphere",Sphere::_W_10);
+#endif
+extern "C" {
+void PbRegister_file_12()
+{
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/test.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/test.cpp
new file mode 100644
index 00000000000..2b3d9a1f593
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/test.cpp
@@ -0,0 +1,97 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Use this file to test new functionality
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include <cmath>
+
+using namespace std;
+
+namespace Manta {
+
+// two simple example kernels
+
+
+
+ struct reductionTest : public KernelBase {
+ reductionTest(const Grid<Real>& v) : KernelBase(&v,0) ,v(v) ,sum(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& v ,double& sum) {
+ sum += v[idx];
+} inline operator double () {
+ return sum; }
+ inline double & getRet() {
+ return sum; }
+ inline const Grid<Real>& getArg0() {
+ return v; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel reductionTest ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ double sum = 0;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,v,sum);
+#pragma omp critical
+{this->sum += sum; } }
+ }
+ const Grid<Real>& v; double sum; }
+;
+
+
+
+ struct minReduction : public KernelBase {
+ minReduction(const Grid<Real>& v) : KernelBase(&v,0) ,v(v) ,sum(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& v ,double& sum) {
+ if (sum < v[idx])
+ sum = v[idx];
+} inline operator double () {
+ return sum; }
+ inline double & getRet() {
+ return sum; }
+ inline const Grid<Real>& getArg0() {
+ return v; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel minReduction ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+ double sum = 0;
+#pragma omp for nowait
+ for (IndexInt i = 0; i < _sz; i++) op(i,v,sum);
+#pragma omp critical
+{this->sum = min(sum, this->sum); } }
+ }
+ const Grid<Real>& v; double sum; }
+;
+
+
+
+
+// ... add more test code here if necessary ...
+
+} //namespace
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.cpp
new file mode 100644
index 00000000000..b7fc69d4875
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.cpp
@@ -0,0 +1,128 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugin timing
+ *
+ ******************************************************************************/
+
+#include "timing.h"
+#include <fstream>
+
+using namespace std;
+namespace Manta {
+
+TimingData::TimingData() : updated(false), num(0) {
+}
+
+void TimingData::start(FluidSolver* parent, const string& name) {
+ mLastPlugin = name;
+ mPluginTimer.get();
+}
+
+void TimingData::stop(FluidSolver* parent, const string& name) {
+ if (mLastPlugin == name && name != "FluidSolver::step") {
+ updated = true;
+ const string parentName = parent ? parent->getName() : "";
+ MuTime diff = mPluginTimer.update();
+ vector<TimingSet>& cur = mData[name];
+ for (vector<TimingSet>::iterator it = cur.begin(); it != cur.end(); it++) {
+ if (it->solver == parentName) {
+ it->cur += diff;
+ it->updated = true;
+ return;
+ }
+ }
+ TimingSet s;
+ s.solver = parentName;
+ s.cur = diff;
+ s.updated = true;
+ cur.push_back(s);
+ }
+}
+
+void TimingData::step() {
+ if (updated)
+ num++;
+ std::map<std::string, std::vector<TimingSet> >::iterator it;
+ for (it = mData.begin(); it != mData.end(); it++) {
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) {
+ if (it2->updated) {
+ it2->total += it2->cur;
+ it2->num++;
+ }
+ it2->cur.clear();
+ it2->updated = false;
+ }
+ }
+ updated = false;
+}
+
+void TimingData::print() {
+ MuTime total;
+ total.clear();
+ std::map<std::string, std::vector<TimingSet> >::iterator it;
+ for (it = mData.begin(); it != mData.end(); it++)
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++)
+ total += it2->cur;
+
+ printf("\n-- STEP %3d ----------------------------\n", num);
+ for (it = mData.begin(); it != mData.end(); it++) {
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) {
+ if (!it2->updated) continue;
+ string name = it->first;
+ if (it->second.size() > 1 && !it2->solver.empty())
+ name += "[" + it2->solver + "]";
+ printf("[%4.1f%%] %s (%s)\n", 100.0*((Real)it2->cur.time / (Real)total.time),
+ name.c_str(), it2->cur.toString().c_str());
+ }
+ }
+ step();
+
+ printf("----------------------------------------\n");
+ printf("Total : %s\n\n", total.toString().c_str());
+}
+
+void TimingData::saveMean(const string& filename) {
+ ofstream ofs(filename.c_str());
+ step();
+ if (!ofs.good())
+ errMsg("can't open " + filename + " as timing log");
+ ofs << "Mean timings of " << num << " steps :" <<endl <<endl;
+ MuTime total;
+ total.clear();
+ std::map<std::string, std::vector<TimingSet> >::iterator it;
+ for (it = mData.begin(); it != mData.end(); it++)
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) {
+ total += it2->cur;
+ string name = it->first;
+ if (it->second.size() > 1)
+ name += "[" + it2->solver + "]";
+
+ ofs << name << " " << (it2->total / it2->num) << endl;
+ }
+
+ ofs << endl << "Total : " << total << " (mean " << total/num << ")" << endl;
+ ofs.close();
+}
+
+}
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h
new file mode 100644
index 00000000000..092377cdcdc
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h
@@ -0,0 +1,96 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugin timing
+ *
+ ******************************************************************************/
+
+#ifndef _TIMING_H
+#define _TIMING_H
+
+#include "manta.h"
+#include <map>
+namespace Manta {
+
+
+class TimingData {
+private:
+ TimingData();
+public:
+ static TimingData& instance() { static TimingData a; return a; }
+
+ void print();
+ void saveMean(const std::string& filename);
+ void start(FluidSolver* parent, const std::string& name);
+ void stop(FluidSolver* parent, const std::string& name);
+protected:
+ void step();
+ struct TimingSet {
+ TimingSet() : num(0),updated(false) { cur.clear(); total.clear(); }
+ MuTime cur, total;
+ int num;
+ bool updated;
+ std::string solver;
+ };
+ bool updated;
+
+ int num;
+ MuTime mPluginTimer;
+ std::string mLastPlugin;
+ std::map<std::string, std::vector<TimingSet> > mData;
+};
+
+// Python interface
+class Timings : public PbClass {public:
+ Timings() :PbClass(0){} static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Timings::Timings" , !noTiming ); {
+ ArgLocker _lock; obj = new Timings(); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Timings::Timings" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Timings::Timings",e.what()); return -1; }
+ }
+
+
+ void display() { TimingData::instance().print(); } static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Timings* pbo = dynamic_cast<Timings*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Timings::display" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->display(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Timings::display" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Timings::display",e.what()); return 0; }
+ }
+ void saveMean(std::string file) { TimingData::instance().saveMean(file); } static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Timings* pbo = dynamic_cast<Timings*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Timings::saveMean" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string file = _args.get<std::string >("file",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->saveMean(file); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Timings::saveMean" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Timings::saveMean",e.what()); return 0; }
+ }
+ public: PbArgs _args; }
+#define _C_Timings
+;
+
+}
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h.reg
new file mode 100644
index 00000000000..4a653bf381d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h.reg
@@ -0,0 +1,6 @@
+#include "timing.h"
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","Timings","PbClass"); template<> const char* Namify<Timings >::S = "Timings";
+>Timings^
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","Timings",Timings::_W_0);
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","display",Timings::_W_1);
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","saveMean",Timings::_W_2);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h.reg.cpp
new file mode 100644
index 00000000000..2217b5188f4
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/timing.h.reg.cpp
@@ -0,0 +1,28 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "timing.h"
+namespace Manta {
+#ifdef _C_Timings
+ static const Pb::Register _R_16 ("Timings","Timings","PbClass"); template<> const char* Namify<Timings >::S = "Timings";
+ static const Pb::Register _R_17 ("Timings","Timings",Timings::_W_0);
+ static const Pb::Register _R_18 ("Timings","display",Timings::_W_1);
+ static const Pb::Register _R_19 ("Timings","saveMean",Timings::_W_2);
+#endif
+extern "C" {
+void PbRegister_file_16()
+{
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.cpp
new file mode 100644
index 00000000000..09d853ceb53
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.cpp
@@ -0,0 +1,186 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.ynu.org/licenses
+ *
+ * Turbulence particles
+ *
+ ******************************************************************************/
+
+#include "turbulencepart.h"
+#include "shapes.h"
+#include "randomstream.h"
+
+using namespace std;
+namespace Manta {
+
+TurbulenceParticleSystem::TurbulenceParticleSystem(FluidSolver* parent, WaveletNoiseField& noise) :
+ ParticleSystem<TurbulenceParticleData>(parent), noise(noise)
+{
+}
+
+ParticleBase* TurbulenceParticleSystem::clone() {
+ TurbulenceParticleSystem* nm = new TurbulenceParticleSystem(getParent(), noise);
+ compress();
+
+ nm->mData = mData;
+ nm->setName(getName());
+ return nm;
+}
+
+inline Vec3 hsv2rgb(Real h, Real s, Real v){
+ Real r=0, g=0, b=0;
+
+ int i = (int)(h * 6);
+ Real f = h * 6 - i;
+ Real p = v * (1 - s);
+ Real q = v * (1 - f * s);
+ Real t = v * (1 - (1 - f) * s);
+
+ switch(i % 6){
+ case 0: r = v, g = t, b = p; break;
+ case 1: r = q, g = v, b = p; break;
+ case 2: r = p, g = v, b = t; break;
+ case 3: r = p, g = q, b = v; break;
+ case 4: r = t, g = p, b = v; break;
+ case 5: r = v, g = p, b = q; break;
+ default: break;
+ }
+
+ return Vec3(r,g,b);
+}
+
+void TurbulenceParticleSystem::seed(Shape* shape, int num) {
+ static RandomStream rand(34894231);
+ Vec3 sz = shape->getExtent(), p0 = shape->getCenter() - sz*0.5;
+ for (int i=0; i<num; i++) {
+ Vec3 p;
+ do {
+ p = rand.getVec3() * sz + p0;
+ } while(!shape->isInside(p));
+ Real z = (p.z - p0.z)/sz.z;
+ add(TurbulenceParticleData(p,hsv2rgb(z,0.75,1.0)));
+ }
+}
+
+void TurbulenceParticleSystem::resetTexCoords(int num, const Vec3& inflow ) {
+ if (num==0) {
+ for (int i=0; i<size(); i++) mData[i].tex0 = mData[i].pos - inflow;
+ } else {
+ for (int i=0; i<size(); i++) mData[i].tex1 = mData[i].pos - inflow;
+ }
+}
+
+
+
+
+ struct KnSynthesizeTurbulence : public KernelBase {
+ KnSynthesizeTurbulence(TurbulenceParticleSystem& p, FlagGrid& flags, WaveletNoiseField& noise, Grid<Real>& kGrid, Real alpha, Real dt, int octaves, Real scale, Real invL0, Real kmin) : KernelBase(p.size()) ,p(p),flags(flags),noise(noise),kGrid(kGrid),alpha(alpha),dt(dt),octaves(octaves),scale(scale),invL0(invL0),kmin(kmin) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, TurbulenceParticleSystem& p, FlagGrid& flags, WaveletNoiseField& noise, Grid<Real>& kGrid, Real alpha, Real dt, int octaves, Real scale, Real invL0, Real kmin ) {
+ const Real PERSISTENCE = 0.56123f;
+
+ const Vec3 pos(p[idx].pos);
+ if (flags.isInBounds(pos)) { // && !flags.isObstacle(pos)) {
+ Real k2 = kGrid.getInterpolated(pos)-kmin;
+ Real ks = k2<0 ? 0.0 : sqrt(k2);
+
+ // Wavelet noise lookup
+ Real amplitude = scale * ks;
+ Real multiplier = invL0;
+ Vec3 vel(0.);
+ for (int o=0; o<octaves; o++) {
+ //Vec3 ns = noise.evaluateCurl(p[i].pos * multiplier) * amplitude;
+ Vec3 n0 = noise.evaluateCurl(p[idx].tex0 * multiplier) * amplitude;
+ Vec3 n1 = noise.evaluateCurl(p[idx].tex1 * multiplier) * amplitude;
+ vel += alpha * n0 + (1.0f-alpha) * n1;
+
+ // next scale
+ amplitude *= PERSISTENCE;
+ multiplier *= 2.0f;
+ }
+
+ // advection
+ Vec3 dx = vel*dt;
+ p[idx].pos += dx;
+ p[idx].tex0 += dx;
+ p[idx].tex1 += dx;
+ }
+} inline TurbulenceParticleSystem& getArg0() {
+ return p; }
+ typedef TurbulenceParticleSystem type0;inline FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Grid<Real>& getArg3() {
+ return kGrid; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return alpha; }
+ typedef Real type4;inline Real& getArg5() {
+ return dt; }
+ typedef Real type5;inline int& getArg6() {
+ return octaves; }
+ typedef int type6;inline Real& getArg7() {
+ return scale; }
+ typedef Real type7;inline Real& getArg8() {
+ return invL0; }
+ typedef Real type8;inline Real& getArg9() {
+ return kmin; }
+ typedef Real type9; void runMessage() { debMsg("Executing kernel KnSynthesizeTurbulence ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,p,flags,noise,kGrid,alpha,dt,octaves,scale,invL0,kmin); }
+ }
+ TurbulenceParticleSystem& p; FlagGrid& flags; WaveletNoiseField& noise; Grid<Real>& kGrid; Real alpha; Real dt; int octaves; Real scale; Real invL0; Real kmin; }
+;
+
+void TurbulenceParticleSystem::synthesize(FlagGrid& flags, Grid<Real>& k, int octaves, Real switchLength, Real L0, Real scale, Vec3 inflowBias) {
+ static Real ctime = 0;
+ static Vec3 inflow(0.);
+ Real dt = getParent()->getDt();
+
+ // collect inflow bias
+ inflow += inflowBias * dt;
+
+ // alpha: hat function over time
+ Real oldAlpha = 2.0f*nmod(ctime/switchLength, Real(1.0) );
+ ctime += dt;
+ Real alpha = 2.0f*nmod(ctime/switchLength, Real(1.0) );
+
+ if (oldAlpha < 1.0f && alpha >= 1.0f) resetTexCoords(0, inflow);
+ if (oldAlpha > alpha) resetTexCoords(1, inflow);
+ if (alpha>1.0f) alpha=2.0f-alpha;
+ alpha = 1.0;
+
+ KnSynthesizeTurbulence(*this, flags, noise, k, alpha, dt, octaves, scale, 1.0f/L0, 1.5*square(0.1));
+}
+
+void TurbulenceParticleSystem::deleteInObstacle(FlagGrid& flags) {
+ for (int i=0; i<size(); i++)
+ if (flags.isObstacle(mData[i].pos))
+ mData[i].flag |= PDELETE;
+ compress();
+}
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h
new file mode 100644
index 00000000000..5ef50b44fcb
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h
@@ -0,0 +1,105 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Turbulence particles
+ *
+ ******************************************************************************/
+
+#ifndef _TURBULENCEPART_H_
+#define _TURBULENCEPART_H_
+
+#include "particle.h"
+#include "noisefield.h"
+
+namespace Manta {
+class Shape;
+
+
+
+struct TurbulenceParticleData {
+ TurbulenceParticleData() : pos(0.0),color(1.),tex0(0.0),tex1(0.0),flag(0) {}
+ TurbulenceParticleData(const Vec3& p, const Vec3& color = Vec3(1.)) : pos(p),color(color),tex0(p),tex1(p),flag(0) {}
+ Vec3 pos, color;
+ Vec3 tex0, tex1;
+ int flag;
+ static ParticleBase::SystemType getType() { return ParticleBase::TURBULENCE; }
+};
+
+//! Turbulence particles
+class TurbulenceParticleSystem : public ParticleSystem<TurbulenceParticleData> {public:
+ TurbulenceParticleSystem(FluidSolver* parent, WaveletNoiseField& noise); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "TurbulenceParticleSystem::TurbulenceParticleSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",1,&_lock); obj = new TurbulenceParticleSystem(parent,noise); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"TurbulenceParticleSystem::TurbulenceParticleSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("TurbulenceParticleSystem::TurbulenceParticleSystem",e.what()); return -1; }
+ }
+
+
+ void resetTexCoords(int num, const Vec3& inflow); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); TurbulenceParticleSystem* pbo = dynamic_cast<TurbulenceParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::resetTexCoords" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int num = _args.get<int >("num",0,&_lock); const Vec3& inflow = _args.get<Vec3 >("inflow",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->resetTexCoords(num,inflow); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"TurbulenceParticleSystem::resetTexCoords" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("TurbulenceParticleSystem::resetTexCoords",e.what()); return 0; }
+ }
+
+ void seed(Shape* source, int num); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); TurbulenceParticleSystem* pbo = dynamic_cast<TurbulenceParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::seed" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Shape* source = _args.getPtr<Shape >("source",0,&_lock); int num = _args.get<int >("num",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->seed(source,num); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"TurbulenceParticleSystem::seed" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("TurbulenceParticleSystem::seed",e.what()); return 0; }
+ }
+
+ void synthesize(FlagGrid& flags, Grid<Real>& k, int octaves=2, Real switchLength=10.0, Real L0=0.1, Real scale=1.0, Vec3 inflowBias=0.0); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); TurbulenceParticleSystem* pbo = dynamic_cast<TurbulenceParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::synthesize" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& k = *_args.getPtr<Grid<Real> >("k",1,&_lock); int octaves = _args.getOpt<int >("octaves",2,2,&_lock); Real switchLength = _args.getOpt<Real >("switchLength",3,10.0,&_lock); Real L0 = _args.getOpt<Real >("L0",4,0.1,&_lock); Real scale = _args.getOpt<Real >("scale",5,1.0,&_lock); Vec3 inflowBias = _args.getOpt<Vec3 >("inflowBias",6,0.0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->synthesize(flags,k,octaves,switchLength,L0,scale,inflowBias); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"TurbulenceParticleSystem::synthesize" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("TurbulenceParticleSystem::synthesize",e.what()); return 0; }
+ }
+
+ void deleteInObstacle(FlagGrid& flags); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); TurbulenceParticleSystem* pbo = dynamic_cast<TurbulenceParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::deleteInObstacle" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->deleteInObstacle(flags); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"TurbulenceParticleSystem::deleteInObstacle" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("TurbulenceParticleSystem::deleteInObstacle",e.what()); return 0; }
+ }
+
+
+ virtual ParticleBase* clone();
+
+private: WaveletNoiseField& noise; public: PbArgs _args; }
+#define _C_TurbulenceParticleSystem
+;
+
+} // namespace
+
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h.reg
new file mode 100644
index 00000000000..f28cd70f4a3
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h.reg
@@ -0,0 +1,9 @@
+#include "turbulencepart.h"
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","TurbulenceParticleSystem","ParticleSystem<$BT$>"); template<> const char* Namify<TurbulenceParticleSystem >::S = "TurbulenceParticleSystem";
+>TurbulenceParticleSystem^
+@TurbulenceParticleSystem^^ParticleSystem^TurbulenceParticleData
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","TurbulenceParticleSystem",TurbulenceParticleSystem::_W_0);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","resetTexCoords",TurbulenceParticleSystem::_W_1);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","seed",TurbulenceParticleSystem::_W_2);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","synthesize",TurbulenceParticleSystem::_W_3);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","deleteInObstacle",TurbulenceParticleSystem::_W_4);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h.reg.cpp
new file mode 100644
index 00000000000..0cbdc53ed46
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/turbulencepart.h.reg.cpp
@@ -0,0 +1,56 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "turbulencepart.h"
+namespace Manta {
+#ifdef _C_ParticleSystem
+ static const Pb::Register _R_21 ("ParticleSystem<TurbulenceParticleData>","ParticleSystem<TurbulenceParticleData>","ParticleBase"); template<> const char* Namify<ParticleSystem<TurbulenceParticleData> >::S = "ParticleSystem<TurbulenceParticleData>";
+ static const Pb::Register _R_22 ("ParticleSystem<TurbulenceParticleData>","ParticleSystem",ParticleSystem<TurbulenceParticleData>::_W_2);
+ static const Pb::Register _R_23 ("ParticleSystem<TurbulenceParticleData>","pySize",ParticleSystem<TurbulenceParticleData>::_W_3);
+ static const Pb::Register _R_24 ("ParticleSystem<TurbulenceParticleData>","setPos",ParticleSystem<TurbulenceParticleData>::_W_4);
+ static const Pb::Register _R_25 ("ParticleSystem<TurbulenceParticleData>","getPos",ParticleSystem<TurbulenceParticleData>::_W_5);
+ static const Pb::Register _R_26 ("ParticleSystem<TurbulenceParticleData>","getPosPdata",ParticleSystem<TurbulenceParticleData>::_W_6);
+ static const Pb::Register _R_27 ("ParticleSystem<TurbulenceParticleData>","setPosPdata",ParticleSystem<TurbulenceParticleData>::_W_7);
+ static const Pb::Register _R_28 ("ParticleSystem<TurbulenceParticleData>","clear",ParticleSystem<TurbulenceParticleData>::_W_8);
+ static const Pb::Register _R_29 ("ParticleSystem<TurbulenceParticleData>","advectInGrid",ParticleSystem<TurbulenceParticleData>::_W_9);
+ static const Pb::Register _R_30 ("ParticleSystem<TurbulenceParticleData>","projectOutside",ParticleSystem<TurbulenceParticleData>::_W_10);
+ static const Pb::Register _R_31 ("ParticleSystem<TurbulenceParticleData>","projectOutOfBnd",ParticleSystem<TurbulenceParticleData>::_W_11);
+#endif
+#ifdef _C_TurbulenceParticleSystem
+ static const Pb::Register _R_32 ("TurbulenceParticleSystem","TurbulenceParticleSystem","ParticleSystem<TurbulenceParticleData>"); template<> const char* Namify<TurbulenceParticleSystem >::S = "TurbulenceParticleSystem";
+ static const Pb::Register _R_33 ("TurbulenceParticleSystem","TurbulenceParticleSystem",TurbulenceParticleSystem::_W_0);
+ static const Pb::Register _R_34 ("TurbulenceParticleSystem","resetTexCoords",TurbulenceParticleSystem::_W_1);
+ static const Pb::Register _R_35 ("TurbulenceParticleSystem","seed",TurbulenceParticleSystem::_W_2);
+ static const Pb::Register _R_36 ("TurbulenceParticleSystem","synthesize",TurbulenceParticleSystem::_W_3);
+ static const Pb::Register _R_37 ("TurbulenceParticleSystem","deleteInObstacle",TurbulenceParticleSystem::_W_4);
+#endif
+extern "C" {
+void PbRegister_file_21()
+{
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.cpp
new file mode 100644
index 00000000000..8307571b7c8
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.cpp
@@ -0,0 +1,152 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex particles
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#include "vortexpart.h"
+#include "integrator.h"
+#include "mesh.h"
+
+using namespace std;
+namespace Manta {
+
+// vortex particle effect: (cyl coord around wp)
+// u = -|wp|*rho*exp( (-rho^2-z^2)/(2sigma^2) ) e_phi
+inline Vec3 VortexKernel(const Vec3& p, const vector<VortexParticleData>& vp, Real scale) {
+ Vec3 u(0.0);
+ for (size_t i=0; i<vp.size(); i++) {
+ if (vp[i].flag & ParticleBase::PDELETE) continue;
+
+ // cutoff radius
+ const Vec3 r = p - vp[i].pos;
+ const Real rlen2 = normSquare(r);
+ const Real sigma2 = square(vp[i].sigma);
+ if (rlen2 > 6.0 * sigma2 || rlen2 < 1e-8) continue;
+
+ // split vortex strength
+ Vec3 vortNorm = vp[i].vorticity;
+ Real strength = normalize(vortNorm) * scale;
+
+ // transform in cylinder coordinate system
+ const Real rlen = sqrt(rlen2);
+ const Real z = dot(r, vortNorm);
+ const Vec3 ePhi = cross(r, vortNorm) / rlen;
+ const Real rho2 = rlen2 - z*z;
+
+ Real vortex = 0;
+ if (rho2 > 1e-10) {
+ // evaluate Kernel
+ vortex = strength * sqrt(rho2) * exp (rlen2 * -0.5/sigma2);
+ }
+ u += vortex * ePhi;
+ }
+ return u;
+}
+
+
+ struct KnVpAdvectMesh : public KernelBase {
+ KnVpAdvectMesh(vector<Node>& nodes, const vector<VortexParticleData>& vp, Real scale) : KernelBase(nodes.size()) ,nodes(nodes),vp(vp),scale(scale) ,u((size)) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, vector<Node>& nodes, const vector<VortexParticleData>& vp, Real scale ,vector<Vec3> & u) {
+ if (nodes[idx].flags & Mesh::NfFixed)
+ u[idx] = 0.0;
+ else
+ u[idx] = VortexKernel(nodes[idx].pos, vp, scale);
+} inline operator vector<Vec3> () {
+ return u; }
+ inline vector<Vec3> & getRet() {
+ return u; }
+ inline vector<Node>& getArg0() {
+ return nodes; }
+ typedef vector<Node> type0;inline const vector<VortexParticleData>& getArg1() {
+ return vp; }
+ typedef vector<VortexParticleData> type1;inline Real& getArg2() {
+ return scale; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel KnVpAdvectMesh ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,nodes,vp,scale,u); }
+ }
+ vector<Node>& nodes; const vector<VortexParticleData>& vp; Real scale; vector<Vec3> u; }
+;
+
+
+ struct KnVpAdvectSelf : public KernelBase {
+ KnVpAdvectSelf(vector<VortexParticleData>& vp, Real scale) : KernelBase(vp.size()) ,vp(vp),scale(scale) ,u((size)) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, vector<VortexParticleData>& vp, Real scale ,vector<Vec3> & u) {
+ if (vp[idx].flag & ParticleBase::PDELETE)
+ u[idx] = 0.0;
+ else
+ u[idx] = VortexKernel(vp[idx].pos, vp, scale);
+} inline operator vector<Vec3> () {
+ return u; }
+ inline vector<Vec3> & getRet() {
+ return u; }
+ inline vector<VortexParticleData>& getArg0() {
+ return vp; }
+ typedef vector<VortexParticleData> type0;inline Real& getArg1() {
+ return scale; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel KnVpAdvectSelf ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size;
+#pragma omp parallel
+ {
+
+#pragma omp for
+ for (IndexInt i = 0; i < _sz; i++) op(i,vp,scale,u); }
+ }
+ vector<VortexParticleData>& vp; Real scale; vector<Vec3> u; }
+;
+
+VortexParticleSystem::VortexParticleSystem(FluidSolver* parent) :
+ ParticleSystem<VortexParticleData>(parent)
+{
+}
+
+void VortexParticleSystem::advectSelf(Real scale, int integrationMode) {
+ KnVpAdvectSelf kernel(mData, scale* getParent()->getDt());
+ integratePointSet( kernel, integrationMode);
+}
+
+void VortexParticleSystem::applyToMesh(Mesh& mesh, Real scale, int integrationMode) {
+ KnVpAdvectMesh kernel(mesh.getNodeData(), mData, scale* getParent()->getDt());
+ integratePointSet( kernel, integrationMode);
+}
+
+ParticleBase* VortexParticleSystem::clone() {
+ VortexParticleSystem* nm = new VortexParticleSystem(getParent());
+ compress();
+
+ nm->mData = mData;
+ nm->setName(getName());
+ return nm;
+}
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h
new file mode 100644
index 00000000000..84b2cb22da4
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h
@@ -0,0 +1,82 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex particles
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#ifndef _VORTEXPART_H
+#define _VORTEXPART_H
+
+#include "particle.h"
+
+namespace Manta {
+class Mesh;
+
+struct VortexParticleData {
+ VortexParticleData() : pos(0.0),vorticity(0.0),sigma(0),flag(0) {}
+ VortexParticleData(const Vec3& p, const Vec3& v, Real sig) : pos(p),vorticity(v),sigma(sig),flag(0) {}
+ Vec3 pos, vorticity;
+ Real sigma;
+ int flag;
+ static ParticleBase::SystemType getType() { return ParticleBase::VORTEX; }
+};
+
+//! Vortex particles
+class VortexParticleSystem : public ParticleSystem<VortexParticleData> {public:
+ VortexParticleSystem(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "VortexParticleSystem::VortexParticleSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new VortexParticleSystem(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"VortexParticleSystem::VortexParticleSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("VortexParticleSystem::VortexParticleSystem",e.what()); return -1; }
+ }
+
+
+ void advectSelf(Real scale=1.0, int integrationMode=IntRK4); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); VortexParticleSystem* pbo = dynamic_cast<VortexParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "VortexParticleSystem::advectSelf" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real scale = _args.getOpt<Real >("scale",0,1.0,&_lock); int integrationMode = _args.getOpt<int >("integrationMode",1,IntRK4,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->advectSelf(scale,integrationMode); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"VortexParticleSystem::advectSelf" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VortexParticleSystem::advectSelf",e.what()); return 0; }
+ }
+
+ void applyToMesh(Mesh& mesh, Real scale=1.0, int integrationMode=IntRK4); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); VortexParticleSystem* pbo = dynamic_cast<VortexParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "VortexParticleSystem::applyToMesh" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); Real scale = _args.getOpt<Real >("scale",1,1.0,&_lock); int integrationMode = _args.getOpt<int >("integrationMode",2,IntRK4,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->applyToMesh(mesh,scale,integrationMode); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"VortexParticleSystem::applyToMesh" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VortexParticleSystem::applyToMesh",e.what()); return 0; }
+ }
+
+ virtual ParticleBase* clone(); public: PbArgs _args; }
+#define _C_VortexParticleSystem
+;
+
+} // namespace
+
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h.reg
new file mode 100644
index 00000000000..8d36d048fbd
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h.reg
@@ -0,0 +1,7 @@
+#include "vortexpart.h"
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","VortexParticleSystem","ParticleSystem<$BT$>"); template<> const char* Namify<VortexParticleSystem >::S = "VortexParticleSystem";
+>VortexParticleSystem^
+@VortexParticleSystem^^ParticleSystem^VortexParticleData
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","VortexParticleSystem",VortexParticleSystem::_W_0);
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","advectSelf",VortexParticleSystem::_W_1);
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","applyToMesh",VortexParticleSystem::_W_2);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h.reg.cpp
new file mode 100644
index 00000000000..f62b046c4c9
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexpart.h.reg.cpp
@@ -0,0 +1,52 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "vortexpart.h"
+namespace Manta {
+#ifdef _C_ParticleSystem
+ static const Pb::Register _R_20 ("ParticleSystem<VortexParticleData>","ParticleSystem<VortexParticleData>","ParticleBase"); template<> const char* Namify<ParticleSystem<VortexParticleData> >::S = "ParticleSystem<VortexParticleData>";
+ static const Pb::Register _R_21 ("ParticleSystem<VortexParticleData>","ParticleSystem",ParticleSystem<VortexParticleData>::_W_2);
+ static const Pb::Register _R_22 ("ParticleSystem<VortexParticleData>","pySize",ParticleSystem<VortexParticleData>::_W_3);
+ static const Pb::Register _R_23 ("ParticleSystem<VortexParticleData>","setPos",ParticleSystem<VortexParticleData>::_W_4);
+ static const Pb::Register _R_24 ("ParticleSystem<VortexParticleData>","getPos",ParticleSystem<VortexParticleData>::_W_5);
+ static const Pb::Register _R_25 ("ParticleSystem<VortexParticleData>","getPosPdata",ParticleSystem<VortexParticleData>::_W_6);
+ static const Pb::Register _R_26 ("ParticleSystem<VortexParticleData>","setPosPdata",ParticleSystem<VortexParticleData>::_W_7);
+ static const Pb::Register _R_27 ("ParticleSystem<VortexParticleData>","clear",ParticleSystem<VortexParticleData>::_W_8);
+ static const Pb::Register _R_28 ("ParticleSystem<VortexParticleData>","advectInGrid",ParticleSystem<VortexParticleData>::_W_9);
+ static const Pb::Register _R_29 ("ParticleSystem<VortexParticleData>","projectOutside",ParticleSystem<VortexParticleData>::_W_10);
+ static const Pb::Register _R_30 ("ParticleSystem<VortexParticleData>","projectOutOfBnd",ParticleSystem<VortexParticleData>::_W_11);
+#endif
+#ifdef _C_VortexParticleSystem
+ static const Pb::Register _R_31 ("VortexParticleSystem","VortexParticleSystem","ParticleSystem<VortexParticleData>"); template<> const char* Namify<VortexParticleSystem >::S = "VortexParticleSystem";
+ static const Pb::Register _R_32 ("VortexParticleSystem","VortexParticleSystem",VortexParticleSystem::_W_0);
+ static const Pb::Register _R_33 ("VortexParticleSystem","advectSelf",VortexParticleSystem::_W_1);
+ static const Pb::Register _R_34 ("VortexParticleSystem","applyToMesh",VortexParticleSystem::_W_2);
+#endif
+extern "C" {
+void PbRegister_file_20()
+{
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.cpp
new file mode 100644
index 00000000000..fa77901a9a6
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.cpp
@@ -0,0 +1,106 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex sheets
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#include "vortexsheet.h"
+#include "solvana.h"
+
+using namespace std;
+namespace Manta {
+
+// *****************************************************************************
+// VorticityChannel class members
+
+
+
+// *****************************************************************************
+// VortexSheet Mesh class members
+
+VortexSheetMesh::VortexSheetMesh(FluidSolver* parent) : Mesh(parent), mTexOffset(0.0f) {
+ addTriChannel(&mVorticity);
+ addNodeChannel(&mTex1);
+ addNodeChannel(&mTex2);
+ addNodeChannel(&mTurb);
+}
+
+
+Mesh* VortexSheetMesh::clone() {
+ VortexSheetMesh* nm = new VortexSheetMesh(mParent);
+ *nm = *this;
+ nm->setName(getName());
+ return nm;
+}
+
+
+void VortexSheetMesh::calcVorticity() {
+ for (size_t tri = 0; tri < mTris.size(); tri++) {
+ VortexSheetInfo& v = mVorticity.data[tri];
+ Vec3 e0 = getEdge(tri,0), e1 = getEdge(tri,1), e2 = getEdge(tri,2);
+ Real area = getFaceArea(tri);
+
+ if (area < 1e-10) {
+ v.smokeAmount = 0;
+ v.vorticity = 0;
+ } else {
+ v.smokeAmount = 0;
+ v.vorticity = (v.circulation[0]*e0 + v.circulation[1]*e1 + v.circulation[2]*e2) / area;
+ }
+ }
+}
+
+void VortexSheetMesh::calcCirculation() {
+ for (size_t tri = 0; tri < mTris.size(); tri++) {
+ VortexSheetInfo& v = mVorticity.data[tri];
+ Vec3 e0 = getEdge(tri,0), e1 = getEdge(tri,1), e2 = getEdge(tri,2);
+ Real area = getFaceArea(tri);
+
+ if (area < 1e-10 || normSquare(v.vorticity) < 1e-10) {
+ v.circulation = 0;
+ continue;
+ }
+
+ float cx, cy, cz;
+ SolveOverconstraint34(e0.x, e0.y, e0.z, e1.x, e1.y, e1.z, e2.x, e2.y, e2.z, v.vorticity.x, v.vorticity.y, v.vorticity.z, cx, cy, cz);
+ v.circulation = Vec3(cx, cy, cz) * area;
+ }
+}
+
+void VortexSheetMesh::resetTex1() {
+ for (size_t i=0; i<mNodes.size(); i++)
+ mTex1.data[i] = mNodes[i].pos + mTexOffset;
+}
+
+void VortexSheetMesh::resetTex2() {
+ for (size_t i=0; i<mNodes.size(); i++)
+ mTex2.data[i] = mNodes[i].pos + mTexOffset;
+}
+
+void VortexSheetMesh::reinitTexCoords() {
+ resetTex1();
+ resetTex2();
+}
+
+}; // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h
new file mode 100644
index 00000000000..3883f8e0149
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h
@@ -0,0 +1,132 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex sheets
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#ifndef _VORTEXSHEET_H
+#define _VORTEXSHEET_H
+
+#include "mesh.h"
+
+namespace Manta {
+
+//! Stores vortex sheet info
+struct VortexSheetInfo {
+ VortexSheetInfo() : vorticity(0.0), vorticitySmoothed(0.0), circulation(0.0), smokeAmount(1.0), smokeParticles(0.0) {}
+
+ Vec3 vorticity;
+ Vec3 vorticitySmoothed;
+ Vec3 circulation;
+ Real smokeAmount, smokeParticles;
+};
+
+//! Manages vortex sheet info
+struct VorticityChannel : public SimpleTriChannel<VortexSheetInfo> {
+ virtual TriChannel* clone() { VorticityChannel* vc = new VorticityChannel(); *vc = *this; return vc;}
+};
+
+//! Manages 3D texture coordinates
+struct TexCoord3Channel : public SimpleNodeChannel<Vec3> {
+ virtual NodeChannel* clone() { TexCoord3Channel* tc = new TexCoord3Channel(); *tc = *this; return tc; }
+
+ void addInterpol(int a, int b, Real alpha) { data.push_back((1.0-alpha)*data[a] + alpha*data[b]);}
+ void mergeWith(int node, int delnode, Real alpha) { data[node] = 0.5*(data[node]+data[delnode]); }
+};
+
+struct TurbulenceInfo {
+ TurbulenceInfo() : k(0.0), epsilon(0.0) {}
+ TurbulenceInfo(const TurbulenceInfo& a, const TurbulenceInfo& b, Real alpha) : k((1.0-alpha)*a.k+alpha*b.k), epsilon((1.0-alpha)*a.epsilon+alpha*b.epsilon) {}
+ Real k, epsilon;
+};
+
+//! Manages k-epsilon information
+struct TurbulenceChannel : public SimpleNodeChannel<TurbulenceInfo> {
+ virtual NodeChannel* clone() { TurbulenceChannel* tc = new TurbulenceChannel(); *tc = *this; return tc; }
+
+ void addInterpol(int a, int b, Real alpha) { data.push_back(TurbulenceInfo(data[a], data[b], alpha)); }
+ void mergeWith(int node, int delnode, Real alpha) { data[node] = TurbulenceInfo(data[node], data[delnode], 0.5); }
+};
+
+//! Typed Mesh with a vorticity and 2 texcoord3 channels
+class VortexSheetMesh : public Mesh {public:
+ VortexSheetMesh(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "VortexSheetMesh::VortexSheetMesh" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new VortexSheetMesh(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"VortexSheetMesh::VortexSheetMesh" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("VortexSheetMesh::VortexSheetMesh",e.what()); return -1; }
+ }
+
+ virtual Mesh* clone();
+
+ virtual MeshType getType() { return TypeVortexSheet; }
+
+ inline VortexSheetInfo& sheet(int i) { return mVorticity.data[i]; };
+ inline Vec3& tex1(int i) { return mTex1.data[i]; }
+ inline Vec3& tex2(int i) { return mTex2.data[i]; }
+ inline TurbulenceInfo& turb(int i) { return mTurb.data[i]; }
+ void setReferenceTexOffset(const Vec3& ref) { mTexOffset = ref; }
+ void resetTex1();
+ void resetTex2();
+
+ void calcCirculation(); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); VortexSheetMesh* pbo = dynamic_cast<VortexSheetMesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::calcCirculation" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->calcCirculation(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"VortexSheetMesh::calcCirculation" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VortexSheetMesh::calcCirculation",e.what()); return 0; }
+ }
+
+ void calcVorticity(); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); VortexSheetMesh* pbo = dynamic_cast<VortexSheetMesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::calcVorticity" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->calcVorticity(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"VortexSheetMesh::calcVorticity" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VortexSheetMesh::calcVorticity",e.what()); return 0; }
+ }
+
+ void reinitTexCoords(); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); VortexSheetMesh* pbo = dynamic_cast<VortexSheetMesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::reinitTexCoords" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->reinitTexCoords(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"VortexSheetMesh::reinitTexCoords" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VortexSheetMesh::reinitTexCoords",e.what()); return 0; }
+ }
+
+
+protected:
+ Vec3 mTexOffset;
+ VorticityChannel mVorticity;
+ TexCoord3Channel mTex1, mTex2; TurbulenceChannel mTurb; public: PbArgs _args; }
+#define _C_VortexSheetMesh
+;
+
+}; // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h.reg
new file mode 100644
index 00000000000..d5ad6b64113
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h.reg
@@ -0,0 +1,7 @@
+#include "vortexsheet.h"
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","VortexSheetMesh","Mesh"); template<> const char* Namify<VortexSheetMesh >::S = "VortexSheetMesh";
+>VortexSheetMesh^
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","VortexSheetMesh",VortexSheetMesh::_W_0);
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","calcCirculation",VortexSheetMesh::_W_1);
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","calcVorticity",VortexSheetMesh::_W_2);
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","reinitTexCoords",VortexSheetMesh::_W_3);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h.reg.cpp
new file mode 100644
index 00000000000..57a61c01ecd
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/omp/vortexsheet.h.reg.cpp
@@ -0,0 +1,30 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "vortexsheet.h"
+namespace Manta {
+#ifdef _C_VortexSheetMesh
+ static const Pb::Register _R_14 ("VortexSheetMesh","VortexSheetMesh","Mesh"); template<> const char* Namify<VortexSheetMesh >::S = "VortexSheetMesh";
+ static const Pb::Register _R_15 ("VortexSheetMesh","VortexSheetMesh",VortexSheetMesh::_W_0);
+ static const Pb::Register _R_16 ("VortexSheetMesh","calcCirculation",VortexSheetMesh::_W_1);
+ static const Pb::Register _R_17 ("VortexSheetMesh","calcVorticity",VortexSheetMesh::_W_2);
+ static const Pb::Register _R_18 ("VortexSheetMesh","reinitTexCoords",VortexSheetMesh::_W_3);
+#endif
+extern "C" {
+void PbRegister_file_14()
+{
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h
new file mode 100644
index 00000000000..4bd1b44244d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h
@@ -0,0 +1,558 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Common grid kernels
+ *
+ ******************************************************************************/
+
+#ifndef _COMMONKERNELS_H
+#define _COMMONKERNELS_H
+
+#include "general.h"
+#include "kernel.h"
+#include "grid.h"
+
+namespace Manta {
+
+//! Kernel: Invert real values, if positive and fluid
+
+
+ struct InvertCheckFluid : public KernelBase {
+ InvertCheckFluid(const FlagGrid& flags, Grid<Real>& grid) : KernelBase(&flags,0) ,flags(flags),grid(grid) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags, Grid<Real>& grid ) const {
+ if (flags.isFluid(idx) && grid[idx] > 0)
+ grid[idx] = 1.0 / grid[idx];
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel InvertCheckFluid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, flags,grid); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const FlagGrid& flags; Grid<Real>& grid; }
+;
+
+//! Kernel: Squared sum over grid
+
+ struct GridSumSqr : public KernelBase {
+ GridSumSqr(const Grid<Real>& grid) : KernelBase(&grid,0) ,grid(grid) ,sum(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& grid ,double& sum) {
+ sum += square((double)grid[idx]);
+} inline operator double () {
+ return sum; }
+ inline double & getRet() {
+ return sum; }
+ inline const Grid<Real>& getArg0() {
+ return grid; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel GridSumSqr ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, grid,sum); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ GridSumSqr (GridSumSqr& o, tbb::split) : KernelBase(o) ,grid(o.grid) ,sum(0) {
+}
+ void join(const GridSumSqr & o) {
+ sum += o.sum; }
+ const Grid<Real>& grid; double sum; }
+;
+
+//! Kernel: rotation operator \nabla x v for centered vector fields
+
+ struct CurlOp : public KernelBase {
+ CurlOp(const Grid<Vec3>& grid, Grid<Vec3>& dst) : KernelBase(&grid,1) ,grid(grid),dst(dst) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Vec3>& grid, Grid<Vec3>& dst ) const {
+ Vec3 v = Vec3(0. , 0. ,
+ 0.5*((grid(i+1,j,k).y - grid(i-1,j,k).y) - (grid(i,j+1,k).x - grid(i,j-1,k).x)) );
+ if(dst.is3D()) {
+ v[0] = 0.5*((grid(i,j+1,k).z - grid(i,j-1,k).z) - (grid(i,j,k+1).y - grid(i,j,k-1).y));
+ v[1] = 0.5*((grid(i,j,k+1).x - grid(i,j,k-1).x) - (grid(i+1,j,k).z - grid(i-1,j,k).z));
+ }
+ dst(i,j,k) = v;
+} inline const Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Grid<Vec3>& getArg1() {
+ return dst; }
+ typedef Grid<Vec3> type1; void runMessage() { debMsg("Executing kernel CurlOp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,grid,dst); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,grid,dst); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const Grid<Vec3>& grid; Grid<Vec3>& dst; }
+;;
+
+//! Kernel: divergence operator (from MAC grid)
+
+ struct DivergenceOpMAC : public KernelBase {
+ DivergenceOpMAC(Grid<Real>& div, const MACGrid& grid) : KernelBase(&div,1) ,div(div),grid(grid) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& div, const MACGrid& grid ) const {
+ Vec3 del = Vec3(grid(i+1,j,k).x, grid(i,j+1,k).y, 0.) - grid(i,j,k);
+ if(grid.is3D()) del[2] += grid(i,j,k+1).z;
+ else del[2] = 0.;
+ div(i,j,k) = del.x + del.y + del.z;
+} inline Grid<Real>& getArg0() {
+ return div; }
+ typedef Grid<Real> type0;inline const MACGrid& getArg1() {
+ return grid; }
+ typedef MACGrid type1; void runMessage() { debMsg("Executing kernel DivergenceOpMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,div,grid); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,div,grid); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<Real>& div; const MACGrid& grid; }
+;
+
+//! Kernel: gradient operator for MAC grid
+ struct GradientOpMAC : public KernelBase {
+ GradientOpMAC(MACGrid& gradient, const Grid<Real>& grid) : KernelBase(&gradient,1) ,gradient(gradient),grid(grid) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& gradient, const Grid<Real>& grid ) const {
+ Vec3 grad = (Vec3(grid(i,j,k)) - Vec3(grid(i-1,j,k), grid(i,j-1,k), 0. ));
+ if(grid.is3D()) grad[2] -= grid(i,j,k-1);
+ else grad[2] = 0.;
+ gradient(i,j,k) = grad;
+} inline MACGrid& getArg0() {
+ return gradient; }
+ typedef MACGrid type0;inline const Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel GradientOpMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,gradient,grid); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,gradient,grid); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ MACGrid& gradient; const Grid<Real>& grid; }
+;
+
+//! Kernel: centered gradient operator
+ struct GradientOp : public KernelBase {
+ GradientOp(Grid<Vec3>& gradient, const Grid<Real>& grid) : KernelBase(&gradient,1) ,gradient(gradient),grid(grid) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& gradient, const Grid<Real>& grid ) const {
+ Vec3 grad = 0.5 * Vec3( grid(i+1,j,k)-grid(i-1,j,k),
+ grid(i,j+1,k)-grid(i,j-1,k), 0.);
+ if(grid.is3D()) grad[2]= 0.5*( grid(i,j,k+1)-grid(i,j,k-1) );
+ gradient(i,j,k) = grad;
+} inline Grid<Vec3>& getArg0() {
+ return gradient; }
+ typedef Grid<Vec3> type0;inline const Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel GradientOp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,gradient,grid); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,gradient,grid); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<Vec3>& gradient; const Grid<Real>& grid; }
+;
+
+//! Kernel: Laplace operator
+ struct LaplaceOp : public KernelBase {
+ LaplaceOp(Grid<Real>& laplace, const Grid<Real>& grid) : KernelBase(&laplace,1) ,laplace(laplace),grid(grid) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& laplace, const Grid<Real>& grid ) const {
+ laplace(i, j, k) = grid(i+1, j, k) - 2.0*grid(i, j, k) + grid(i-1, j, k);
+ laplace(i, j, k) += grid(i, j+1, k) - 2.0*grid(i, j, k) + grid(i, j-1, k);
+ if(grid.is3D()) {
+ laplace(i, j, k) += grid(i, j, k+1) - 2.0*grid(i, j, k) + grid(i, j, k-1); }
+} inline Grid<Real>& getArg0() {
+ return laplace; }
+ typedef Grid<Real> type0;inline const Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel LaplaceOp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,laplace,grid); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,laplace,grid); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<Real>& laplace; const Grid<Real>& grid; }
+;
+
+//! Kernel: Curvature operator
+ struct CurvatureOp : public KernelBase {
+ CurvatureOp(Grid<Real>& curv, const Grid<Real>& grid, const Real h) : KernelBase(&curv,1) ,curv(curv),grid(grid),h(h) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& curv, const Grid<Real>& grid, const Real h ) const {
+ const Real over_h = 1.0/h;
+ const Real x = 0.5*(grid(i+1, j, k) - grid(i-1, j, k))*over_h;
+ const Real y = 0.5*(grid(i, j+1, k) - grid(i, j-1, k))*over_h;
+ const Real xx = (grid(i+1, j, k) - 2.0*grid(i, j, k) + grid(i-1, j, k))*over_h*over_h;
+ const Real yy = (grid(i, j+1, k) - 2.0*grid(i, j, k) + grid(i, j-1, k))*over_h*over_h;
+ const Real xy = 0.25*(grid(i+1, j+1, k)+grid(i-1, j-1, k)-grid(i-1, j+1, k)-grid(i+1, j-1, k))*over_h*over_h;
+ curv(i, j, k) = x*x*yy + y*y*xx - 2.0*x*y*xy;
+ Real denom = x*x + y*y;
+ if(grid.is3D()) {
+ const Real z = 0.5*(grid(i, j, k+1) - grid(i, j, k-1))*over_h;
+ const Real zz = (grid(i, j, k+1) - 2.0*grid(i, j, k) + grid(i, j, k-1))*over_h*over_h;
+ const Real xz = 0.25*(grid(i+1, j, k+1)+grid(i-1, j, k-1)-grid(i-1, j, k+1)-grid(i+1, j, k-1))*over_h*over_h;
+ const Real yz = 0.25*(grid(i, j+1, k+1)+grid(i, j-1, k-1)-grid(i, j+1, k-1)-grid(i, j-1, k+1))*over_h*over_h;
+ curv(i, j, k) += x*x*zz + z*z*xx + y*y*zz + z*z*yy - 2.0*(x*z*xz + y*z*yz);
+ denom += z*z;
+ }
+ curv(i, j, k) /= std::pow(std::max(denom, VECTOR_EPSILON), 1.5);
+} inline Grid<Real>& getArg0() {
+ return curv; }
+ typedef Grid<Real> type0;inline const Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1;inline const Real& getArg2() {
+ return h; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel CurvatureOp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,curv,grid,h); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,curv,grid,h); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<Real>& curv; const Grid<Real>& grid; const Real h; }
+;
+
+//! Kernel: get component at MAC positions
+ struct GetShiftedComponent : public KernelBase {
+ GetShiftedComponent(const Grid<Vec3>& grid, Grid<Real>& comp, int dim) : KernelBase(&grid,1) ,grid(grid),comp(comp),dim(dim) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Vec3>& grid, Grid<Real>& comp, int dim ) const {
+ Vec3i ishift(i,j,k);
+ ishift[dim]--;
+ comp(i,j,k) = 0.5*(grid(i,j,k)[dim] + grid(ishift)[dim]);
+} inline const Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Grid<Real>& getArg1() {
+ return comp; }
+ typedef Grid<Real> type1;inline int& getArg2() {
+ return dim; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel GetShiftedComponent ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,grid,comp,dim); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,grid,comp,dim); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const Grid<Vec3>& grid; Grid<Real>& comp; int dim; }
+;;
+
+//! Kernel: get component (not shifted)
+ struct GetComponent : public KernelBase {
+ GetComponent(const Grid<Vec3>& grid, Grid<Real>& comp, int dim) : KernelBase(&grid,0) ,grid(grid),comp(comp),dim(dim) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Vec3>& grid, Grid<Real>& comp, int dim ) const {
+ comp[idx] = grid[idx][dim];
+} inline const Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Grid<Real>& getArg1() {
+ return comp; }
+ typedef Grid<Real> type1;inline int& getArg2() {
+ return dim; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel GetComponent ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, grid,comp,dim); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const Grid<Vec3>& grid; Grid<Real>& comp; int dim; }
+;;
+
+//! Kernel: get norm of centered grid
+ struct GridNorm : public KernelBase {
+ GridNorm(Grid<Real>& n, const Grid<Vec3>& grid) : KernelBase(&n,0) ,n(n),grid(grid) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& n, const Grid<Vec3>& grid ) const {
+ n[idx] = norm(grid[idx]);
+} inline Grid<Real>& getArg0() {
+ return n; }
+ typedef Grid<Real> type0;inline const Grid<Vec3>& getArg1() {
+ return grid; }
+ typedef Grid<Vec3> type1; void runMessage() { debMsg("Executing kernel GridNorm ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, n,grid); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<Real>& n; const Grid<Vec3>& grid; }
+;;
+
+//! Kernel: set component (not shifted)
+ struct SetComponent : public KernelBase {
+ SetComponent(Grid<Vec3>& grid, const Grid<Real>& comp, int dim) : KernelBase(&grid,0) ,grid(grid),comp(comp),dim(dim) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Vec3>& grid, const Grid<Real>& comp, int dim ) const {
+ grid[idx][dim] = comp[idx];
+} inline Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline const Grid<Real>& getArg1() {
+ return comp; }
+ typedef Grid<Real> type1;inline int& getArg2() {
+ return dim; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel SetComponent ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, grid,comp,dim); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<Vec3>& grid; const Grid<Real>& comp; int dim; }
+;;
+
+//! Kernel: compute centered velocity field from MAC
+ struct GetCentered : public KernelBase {
+ GetCentered(Grid<Vec3>& center, const MACGrid& vel) : KernelBase(&center,1) ,center(center),vel(vel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& center, const MACGrid& vel ) const {
+ Vec3 v = 0.5 * ( vel(i,j,k) + Vec3(vel(i+1,j,k).x, vel(i,j+1,k).y, 0. ) );
+ if(vel.is3D()) v[2] += 0.5 * vel(i,j,k+1).z;
+ else v[2] = 0.;
+ center(i,j,k) = v;
+} inline Grid<Vec3>& getArg0() {
+ return center; }
+ typedef Grid<Vec3> type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1; void runMessage() { debMsg("Executing kernel GetCentered ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,center,vel); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,center,vel); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<Vec3>& center; const MACGrid& vel; }
+;;
+
+//! Kernel: compute MAC from centered velocity field
+ struct GetMAC : public KernelBase {
+ GetMAC(MACGrid& vel, const Grid<Vec3>& center) : KernelBase(&vel,1) ,vel(vel),center(center) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& vel, const Grid<Vec3>& center ) const {
+ Vec3 v = 0.5*(center(i,j,k) + Vec3(center(i-1,j,k).x, center(i,j-1,k).y, 0. ));
+ if(vel.is3D()) v[2] += 0.5 * center(i,j,k-1).z;
+ else v[2] = 0.;
+ vel(i,j,k) = v;
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const Grid<Vec3>& getArg1() {
+ return center; }
+ typedef Grid<Vec3> type1; void runMessage() { debMsg("Executing kernel GetMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,center); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,center); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ MACGrid& vel; const Grid<Vec3>& center; }
+;;
+
+//! Fill in the domain boundary cells (i,j,k=0/size-1) from the neighboring cells
+ struct FillInBoundary : public KernelBase {
+ FillInBoundary(Grid<Vec3>& grid, int g) : KernelBase(&grid,0) ,grid(grid),g(g) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& grid, int g ) const {
+ if (i==0) grid(i,j,k) = grid(i+1,j,k);
+ if (j==0) grid(i,j,k) = grid(i,j+1,k);
+ if (k==0) grid(i,j,k) = grid(i,j,k+1);
+ if (i==grid.getSizeX()-1) grid(i,j,k) = grid(i-1,j,k);
+ if (j==grid.getSizeY()-1) grid(i,j,k) = grid(i,j-1,k);
+ if (k==grid.getSizeZ()-1) grid(i,j,k) = grid(i,j,k-1);
+} inline Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline int& getArg1() {
+ return g; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel FillInBoundary ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,g); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,g); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<Vec3>& grid; int g; }
+;
+
+
+// ****************************************************************************
+
+// helper functions for converting mex data to manta grids and back (for matlab integration)
+
+// MAC grids
+
+ struct kn_conv_mex_in_to_MAC : public KernelBase {
+ kn_conv_mex_in_to_MAC(const double *p_lin_array, MACGrid *p_result) : KernelBase(p_result,0) ,p_lin_array(p_lin_array),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const double *p_lin_array, MACGrid *p_result ) const {
+ int ijk = i+j*p_result->getSizeX()+k*p_result->getSizeX()*p_result->getSizeY();
+ const int n = p_result->getSizeX() * p_result->getSizeY()*p_result->getSizeZ();
+
+ p_result->get(i,j,k).x = p_lin_array[ijk];
+ p_result->get(i,j,k).y = p_lin_array[ijk+n];
+ p_result->get(i,j,k).z = p_lin_array[ijk+2*n];
+} inline const double* getArg0() {
+ return p_lin_array; }
+ typedef double type0;inline MACGrid* getArg1() {
+ return p_result; }
+ typedef MACGrid type1; void runMessage() { debMsg("Executing kernel kn_conv_mex_in_to_MAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const double* p_lin_array; MACGrid* p_result; }
+;
+
+
+ struct kn_conv_MAC_to_mex_out : public KernelBase {
+ kn_conv_MAC_to_mex_out(const MACGrid *p_mac, double *p_result) : KernelBase(p_mac,0) ,p_mac(p_mac),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid *p_mac, double *p_result ) const {
+ int ijk = i+j*p_mac->getSizeX()+k*p_mac->getSizeX()*p_mac->getSizeY();
+ const int n = p_mac->getSizeX() * p_mac->getSizeY()*p_mac->getSizeZ();
+
+ p_result[ijk] = p_mac->get(i,j,k).x;
+ p_result[ijk+n] = p_mac->get(i,j,k).y;
+ p_result[ijk+2*n] = p_mac->get(i,j,k).z;
+} inline const MACGrid* getArg0() {
+ return p_mac; }
+ typedef MACGrid type0;inline double* getArg1() {
+ return p_result; }
+ typedef double type1; void runMessage() { debMsg("Executing kernel kn_conv_MAC_to_mex_out ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_mac,p_result); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_mac,p_result); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const MACGrid* p_mac; double* p_result; }
+;
+
+// Vec3 Grids
+
+ struct kn_conv_mex_in_to_Vec3 : public KernelBase {
+ kn_conv_mex_in_to_Vec3(const double *p_lin_array, Grid<Vec3> *p_result) : KernelBase(p_result,0) ,p_lin_array(p_lin_array),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const double *p_lin_array, Grid<Vec3> *p_result ) const {
+ int ijk = i+j*p_result->getSizeX()+k*p_result->getSizeX()*p_result->getSizeY();
+ const int n = p_result->getSizeX() * p_result->getSizeY()*p_result->getSizeZ();
+
+ p_result->get(i,j,k).x = p_lin_array[ijk];
+ p_result->get(i,j,k).y = p_lin_array[ijk+n];
+ p_result->get(i,j,k).z = p_lin_array[ijk+2*n];
+} inline const double* getArg0() {
+ return p_lin_array; }
+ typedef double type0;inline Grid<Vec3> * getArg1() {
+ return p_result; }
+ typedef Grid<Vec3> type1; void runMessage() { debMsg("Executing kernel kn_conv_mex_in_to_Vec3 ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const double* p_lin_array; Grid<Vec3> * p_result; }
+;
+
+
+ struct kn_conv_Vec3_to_mex_out : public KernelBase {
+ kn_conv_Vec3_to_mex_out(const Grid<Vec3> *p_Vec3, double *p_result) : KernelBase(p_Vec3,0) ,p_Vec3(p_Vec3),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Vec3> *p_Vec3, double *p_result ) const {
+ int ijk = i+j*p_Vec3->getSizeX()+k*p_Vec3->getSizeX()*p_Vec3->getSizeY();
+ const int n = p_Vec3->getSizeX() * p_Vec3->getSizeY()*p_Vec3->getSizeZ();
+
+ p_result[ijk] = p_Vec3->get(i,j,k).x;
+ p_result[ijk+n] = p_Vec3->get(i,j,k).y;
+ p_result[ijk+2*n] = p_Vec3->get(i,j,k).z;
+} inline const Grid<Vec3> * getArg0() {
+ return p_Vec3; }
+ typedef Grid<Vec3> type0;inline double* getArg1() {
+ return p_result; }
+ typedef double type1; void runMessage() { debMsg("Executing kernel kn_conv_Vec3_to_mex_out ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_Vec3,p_result); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_Vec3,p_result); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const Grid<Vec3> * p_Vec3; double* p_result; }
+;
+
+// Real Grids
+
+ struct kn_conv_mex_in_to_Real : public KernelBase {
+ kn_conv_mex_in_to_Real(const double *p_lin_array, Grid<Real> *p_result) : KernelBase(p_result,0) ,p_lin_array(p_lin_array),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const double *p_lin_array, Grid<Real> *p_result ) const {
+ int ijk = i+j*p_result->getSizeX()+k*p_result->getSizeX()*p_result->getSizeY();
+
+ p_result->get(i,j,k) = p_lin_array[ijk];
+} inline const double* getArg0() {
+ return p_lin_array; }
+ typedef double type0;inline Grid<Real> * getArg1() {
+ return p_result; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel kn_conv_mex_in_to_Real ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_lin_array,p_result); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const double* p_lin_array; Grid<Real> * p_result; }
+;
+
+
+ struct kn_conv_Real_to_mex_out : public KernelBase {
+ kn_conv_Real_to_mex_out(const Grid<Real> *p_grid, double *p_result) : KernelBase(p_grid,0) ,p_grid(p_grid),p_result(p_result) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Real> *p_grid, double *p_result ) const {
+ int ijk = i+j*p_grid->getSizeX()+k*p_grid->getSizeX()*p_grid->getSizeY();
+
+ p_result[ijk] = p_grid->get(i,j,k);
+} inline const Grid<Real> * getArg0() {
+ return p_grid; }
+ typedef Grid<Real> type0;inline double* getArg1() {
+ return p_result; }
+ typedef double type1; void runMessage() { debMsg("Executing kernel kn_conv_Real_to_mex_out ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_grid,p_result); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,p_grid,p_result); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const Grid<Real> * p_grid; double* p_result; }
+;
+
+
+} // namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h.reg
new file mode 100644
index 00000000000..2609f03504f
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h.reg
@@ -0,0 +1 @@
+#include "commonkernels.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h.reg.cpp
new file mode 100644
index 00000000000..c0487570968
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/commonkernels.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "commonkernels.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_2()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.cpp
new file mode 100644
index 00000000000..86dc7987848
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.cpp
@@ -0,0 +1,513 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Conjugate gradient solver, for pressure and viscosity
+ *
+ ******************************************************************************/
+
+#include "conjugategrad.h"
+#include "commonkernels.h"
+
+using namespace std;
+namespace Manta {
+
+const int CG_DEBUGLEVEL = 3;
+
+//*****************************************************************************
+// Precondition helpers
+
+//! Preconditioning a la Wavelet Turbulence (needs 4 add. grids)
+void InitPreconditionIncompCholesky(const FlagGrid& flags,
+ Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak,
+ Grid<Real>& orgA0, Grid<Real>& orgAi, Grid<Real>& orgAj, Grid<Real>& orgAk)
+{
+ // compute IC according to Golub and Van Loan
+ A0.copyFrom( orgA0 );
+ Ai.copyFrom( orgAi );
+ Aj.copyFrom( orgAj );
+ Ak.copyFrom( orgAk );
+
+ FOR_IJK(A0) {
+ if (flags.isFluid(i,j,k)) {
+ const IndexInt idx = A0.index(i,j,k);
+ A0[idx] = sqrt(A0[idx]);
+
+ // correct left and top stencil in other entries
+ // for i = k+1:n
+ // if (A(i,k) != 0)
+ // A(i,k) = A(i,k) / A(k,k)
+ Real invDiagonal = 1.0f / A0[idx];
+ Ai[idx] *= invDiagonal;
+ Aj[idx] *= invDiagonal;
+ Ak[idx] *= invDiagonal;
+
+ // correct the right and bottom stencil in other entries
+ // for j = k+1:n
+ // for i = j:n
+ // if (A(i,j) != 0)
+ // A(i,j) = A(i,j) - A(i,k) * A(j,k)
+ A0(i+1,j,k) -= square(Ai[idx]);
+ A0(i,j+1,k) -= square(Aj[idx]);
+ A0(i,j,k+1) -= square(Ak[idx]);
+ }
+ }
+
+ // invert A0 for faster computation later
+ InvertCheckFluid (flags, A0);
+};
+
+//! Preconditioning using modified IC ala Bridson (needs 1 add. grid)
+void InitPreconditionModifiedIncompCholesky2(const FlagGrid& flags,
+ Grid<Real>&Aprecond,
+ Grid<Real>&A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak)
+{
+ // compute IC according to Golub and Van Loan
+ Aprecond.clear();
+
+ FOR_IJK(flags) {
+ if (!flags.isFluid(i,j,k)) continue;
+
+ const Real tau = 0.97;
+ const Real sigma = 0.25;
+
+ // compute modified incomplete cholesky
+ Real e = 0.;
+ e = A0(i,j,k)
+ - square(Ai(i-1,j,k) * Aprecond(i-1,j,k) )
+ - square(Aj(i,j-1,k) * Aprecond(i,j-1,k) )
+ - square(Ak(i,j,k-1) * Aprecond(i,j,k-1) ) ;
+ e -= tau * (
+ Ai(i-1,j,k) * ( Aj(i-1,j,k) + Ak(i-1,j,k) )* square( Aprecond(i-1,j,k) ) +
+ Aj(i,j-1,k) * ( Ai(i,j-1,k) + Ak(i,j-1,k) )* square( Aprecond(i,j-1,k) ) +
+ Ak(i,j,k-1) * ( Ai(i,j,k-1) + Aj(i,j,k-1) )* square( Aprecond(i,j,k-1) ) +
+ 0. );
+
+ // stability cutoff
+ if(e < sigma * A0(i,j,k))
+ e = A0(i,j,k);
+
+ Aprecond(i,j,k) = 1. / sqrt( e );
+ }
+};
+
+//! Preconditioning using multigrid ala Dick et al.
+void InitPreconditionMultigrid(GridMg* MG, Grid<Real>&A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak, Real mAccuracy)
+{
+ // build multigrid hierarchy if necessary
+ if (!MG->isASet()) MG->setA(&A0, &Ai, &Aj, &Ak);
+ MG->setCoarsestLevelAccuracy(mAccuracy * 1E-4);
+ MG->setSmoothing(1,1);
+};
+
+//! Apply WT-style ICP
+void ApplyPreconditionIncompCholesky(Grid<Real>& dst, Grid<Real>& Var1, const FlagGrid& flags,
+ Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak,
+ Grid<Real>& orgA0, Grid<Real>& orgAi, Grid<Real>& orgAj, Grid<Real>& orgAk)
+{
+
+ // forward substitution
+ FOR_IJK(dst) {
+ if (!flags.isFluid(i,j,k)) continue;
+ dst(i,j,k) = A0(i,j,k) * (Var1(i,j,k)
+ - dst(i-1,j,k) * Ai(i-1,j,k)
+ - dst(i,j-1,k) * Aj(i,j-1,k)
+ - dst(i,j,k-1) * Ak(i,j,k-1));
+ }
+
+ // backward substitution
+ FOR_IJK_REVERSE(dst) {
+ const IndexInt idx = A0.index(i,j,k);
+ if (!flags.isFluid(idx)) continue;
+ dst[idx] = A0[idx] * ( dst[idx]
+ - dst(i+1,j,k) * Ai[idx]
+ - dst(i,j+1,k) * Aj[idx]
+ - dst(i,j,k+1) * Ak[idx]);
+ }
+}
+
+//! Apply Bridson-style mICP
+void ApplyPreconditionModifiedIncompCholesky2(Grid<Real>& dst, Grid<Real>& Var1, const FlagGrid& flags,
+ Grid<Real>& Aprecond,
+ Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak)
+{
+ // forward substitution
+ FOR_IJK(dst) {
+ if (!flags.isFluid(i,j,k)) continue;
+ const Real p = Aprecond(i,j,k);
+ dst(i,j,k) = p * (Var1(i,j,k)
+ - dst(i-1,j,k) * Ai(i-1,j,k) * Aprecond(i-1,j,k)
+ - dst(i,j-1,k) * Aj(i,j-1,k) * Aprecond(i,j-1,k)
+ - dst(i,j,k-1) * Ak(i,j,k-1) * Aprecond(i,j,k-1) );
+ }
+
+ // backward substitution
+ FOR_IJK_REVERSE(dst) {
+ const IndexInt idx = A0.index(i,j,k);
+ if (!flags.isFluid(idx)) continue;
+ const Real p = Aprecond[idx];
+ dst[idx] = p * ( dst[idx]
+ - dst(i+1,j,k) * Ai[idx] * p
+ - dst(i,j+1,k) * Aj[idx] * p
+ - dst(i,j,k+1) * Ak[idx] * p);
+ }
+}
+
+//! Perform one Multigrid VCycle
+void ApplyPreconditionMultigrid(GridMg* pMG, Grid<Real>& dst, Grid<Real>& Var1)
+{
+ // one VCycle on "A*dst = Var1" with initial guess dst=0
+ pMG->setRhs(Var1);
+ pMG->doVCycle(dst);
+}
+
+
+//*****************************************************************************
+// Kernels
+
+//! Kernel: Compute the dot product between two Real grids
+/*! Uses double precision internally */
+
+ struct GridDotProduct : public KernelBase {
+ GridDotProduct(const Grid<Real>& a, const Grid<Real>& b) : KernelBase(&a,0) ,a(a),b(b) ,result(0.0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& a, const Grid<Real>& b ,double& result) {
+ result += (a[idx] * b[idx]);
+} inline operator double () {
+ return result; }
+ inline double & getRet() {
+ return result; }
+ inline const Grid<Real>& getArg0() {
+ return a; }
+ typedef Grid<Real> type0;inline const Grid<Real>& getArg1() {
+ return b; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel GridDotProduct ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, a,b,result); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ GridDotProduct (GridDotProduct& o, tbb::split) : KernelBase(o) ,a(o.a),b(o.b) ,result(0.0) {
+}
+ void join(const GridDotProduct & o) {
+ result += o.result; }
+ const Grid<Real>& a; const Grid<Real>& b; double result; }
+;;
+
+//! Kernel: compute residual (init) and add to sigma
+
+
+ struct InitSigma : public KernelBase {
+ InitSigma(const FlagGrid& flags, Grid<Real>& dst, Grid<Real>& rhs, Grid<Real>& temp) : KernelBase(&flags,0) ,flags(flags),dst(dst),rhs(rhs),temp(temp) ,sigma(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags, Grid<Real>& dst, Grid<Real>& rhs, Grid<Real>& temp ,double& sigma) {
+ const double res = rhs[idx] - temp[idx];
+ dst[idx] = (Real)res;
+
+ // only compute residual in fluid region
+ if(flags.isFluid(idx))
+ sigma += res*res;
+} inline operator double () {
+ return sigma; }
+ inline double & getRet() {
+ return sigma; }
+ inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return dst; }
+ typedef Grid<Real> type1;inline Grid<Real>& getArg2() {
+ return rhs; }
+ typedef Grid<Real> type2;inline Grid<Real>& getArg3() {
+ return temp; }
+ typedef Grid<Real> type3; void runMessage() { debMsg("Executing kernel InitSigma ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, flags,dst,rhs,temp,sigma); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ InitSigma (InitSigma& o, tbb::split) : KernelBase(o) ,flags(o.flags),dst(o.dst),rhs(o.rhs),temp(o.temp) ,sigma(0) {
+}
+ void join(const InitSigma & o) {
+ sigma += o.sigma; }
+ const FlagGrid& flags; Grid<Real>& dst; Grid<Real>& rhs; Grid<Real>& temp; double sigma; }
+;;
+
+//! Kernel: update search vector
+
+ struct UpdateSearchVec : public KernelBase {
+ UpdateSearchVec(Grid<Real>& dst, Grid<Real>& src, Real factor) : KernelBase(&dst,0) ,dst(dst),src(src),factor(factor) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& dst, Grid<Real>& src, Real factor ) const {
+ dst[idx] = src[idx] + factor * dst[idx];
+} inline Grid<Real>& getArg0() {
+ return dst; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return src; }
+ typedef Grid<Real> type1;inline Real& getArg2() {
+ return factor; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel UpdateSearchVec ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, dst,src,factor); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<Real>& dst; Grid<Real>& src; Real factor; }
+;
+
+//*****************************************************************************
+// CG class
+
+template<class APPLYMAT>
+GridCg<APPLYMAT>::GridCg(Grid<Real>& dst, Grid<Real>& rhs, Grid<Real>& residual, Grid<Real>& search, const FlagGrid& flags, Grid<Real>& tmp,
+ Grid<Real>* pA0, Grid<Real>* pAi, Grid<Real>* pAj, Grid<Real>* pAk) :
+ GridCgInterface(), mInited(false), mIterations(0), mDst(dst), mRhs(rhs), mResidual(residual),
+ mSearch(search), mFlags(flags), mTmp(tmp), mpA0(pA0), mpAi(pAi), mpAj(pAj), mpAk(pAk),
+ mPcMethod(PC_None), mpPCA0(nullptr), mpPCAi(nullptr), mpPCAj(nullptr), mpPCAk(nullptr), mMG(nullptr), mSigma(0.), mAccuracy(VECTOR_EPSILON), mResNorm(1e20)
+{ }
+
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::doInit() {
+ mInited = true;
+ mIterations = 0;
+
+ mDst.clear();
+ mResidual.copyFrom( mRhs ); // p=0, residual = b
+
+ if (mPcMethod == PC_ICP) {
+ assertMsg(mDst.is3D(), "ICP only supports 3D grids so far");
+ InitPreconditionIncompCholesky(mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
+ ApplyPreconditionIncompCholesky(mTmp, mResidual, mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
+ } else if (mPcMethod == PC_mICP) {
+ assertMsg(mDst.is3D(), "mICP only supports 3D grids so far");
+ InitPreconditionModifiedIncompCholesky2(mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
+ ApplyPreconditionModifiedIncompCholesky2(mTmp, mResidual, mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
+ } else if (mPcMethod == PC_MGP) {
+ InitPreconditionMultigrid(mMG, *mpA0, *mpAi, *mpAj, *mpAk, mAccuracy);
+ ApplyPreconditionMultigrid(mMG, mTmp, mResidual);
+ } else {
+ mTmp.copyFrom( mResidual );
+ }
+
+ mSearch.copyFrom( mTmp );
+
+ mSigma = GridDotProduct(mTmp, mResidual);
+}
+
+template<class APPLYMAT>
+bool GridCg<APPLYMAT>::iterate() {
+ if(!mInited) doInit();
+
+ mIterations++;
+
+ // create matrix application operator passed as template argument,
+ // this could reinterpret the mpA pointers (not so clean right now)
+ // tmp = applyMat(search)
+
+ APPLYMAT (mFlags, mTmp, mSearch, *mpA0, *mpAi, *mpAj, *mpAk);
+
+ // alpha = sigma/dot(tmp, search)
+ Real dp = GridDotProduct(mTmp, mSearch);
+ Real alpha = 0.;
+ if(fabs(dp)>0.) alpha = mSigma / (Real)dp;
+
+ gridScaledAdd<Real,Real>(mDst, mSearch, alpha); // dst += search * alpha
+ gridScaledAdd<Real,Real>(mResidual, mTmp, -alpha); // residual += tmp * -alpha
+
+ if (mPcMethod == PC_ICP)
+ ApplyPreconditionIncompCholesky(mTmp, mResidual, mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
+ else if (mPcMethod == PC_mICP)
+ ApplyPreconditionModifiedIncompCholesky2(mTmp, mResidual, mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
+ else if (mPcMethod == PC_MGP)
+ ApplyPreconditionMultigrid(mMG, mTmp, mResidual);
+ else
+ mTmp.copyFrom( mResidual );
+
+ // use the l2 norm of the residual for convergence check? (usually max norm is recommended instead)
+ if(this->mUseL2Norm) {
+ mResNorm = GridSumSqr(mResidual).sum;
+ } else {
+ mResNorm = mResidual.getMaxAbs();
+ }
+
+ // abort here to safe some work...
+ if(mResNorm<mAccuracy) {
+ mSigma = mResNorm; // this will be returned later on to the caller...
+ return false;
+ }
+
+ Real sigmaNew = GridDotProduct(mTmp, mResidual);
+ Real beta = sigmaNew / mSigma;
+
+ // search = tmp + beta * search
+ UpdateSearchVec (mSearch, mTmp, beta);
+
+ debMsg("GridCg::iterate i="<<mIterations<<" sigmaNew="<<sigmaNew<<" sigmaLast="<<mSigma<<" alpha="<<alpha<<" beta="<<beta<<" ", CG_DEBUGLEVEL);
+ mSigma = sigmaNew;
+
+ if(!(mResNorm<1e35)) {
+ if(mPcMethod == PC_MGP) {
+ // diverging solves can be caused by the static multigrid mode, we cannot detect this here, though
+ // only the pressure solve call "knows" whether the MG is static or dynamics...
+ debMsg("GridCg::iterate: Warning - this diverging solve can be caused by the 'static' mode of the MG preconditioner. If the static mode is active, try switching to dynamic.", 1);
+ }
+ errMsg("GridCg::iterate: The CG solver diverged, residual norm > 1e30, stopping.");
+ }
+
+ //debMsg("PB-CG-Norms::p"<<sqrt( GridOpNormNosqrt(mpDst, mpFlags).getValue() ) <<" search"<<sqrt( GridOpNormNosqrt(mpSearch, mpFlags).getValue(), CG_DEBUGLEVEL ) <<" res"<<sqrt( GridOpNormNosqrt(mpResidual, mpFlags).getValue() ) <<" tmp"<<sqrt( GridOpNormNosqrt(mpTmp, mpFlags).getValue() ), CG_DEBUGLEVEL ); // debug
+ return true;
+}
+
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::solve(int maxIter) {
+ for (int iter=0; iter<maxIter; iter++) {
+ if (!iterate()) iter=maxIter;
+ }
+ return;
+}
+
+static bool gPrint2dWarning = true;
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::setICPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) {
+ assertMsg(method==PC_ICP || method==PC_mICP, "GridCg<APPLYMAT>::setICPreconditioner: Invalid method specified.");
+
+ mPcMethod = method;
+ if( (!A0->is3D())) {
+ if(gPrint2dWarning) {
+ debMsg("ICP/mICP pre-conditioning only supported in 3D for now, disabling it.", 1);
+ gPrint2dWarning = false;
+ }
+ mPcMethod=PC_None;
+ }
+ mpPCA0 = A0;
+ mpPCAi = Ai;
+ mpPCAj = Aj;
+ mpPCAk = Ak;
+}
+
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::setMGPreconditioner(PreconditionType method, GridMg* MG) {
+ assertMsg(method==PC_MGP, "GridCg<APPLYMAT>::setMGPreconditioner: Invalid method specified.");
+
+ mPcMethod = method;
+
+ mMG = MG;
+}
+
+// explicit instantiation
+template class GridCg<ApplyMatrix>;
+template class GridCg<ApplyMatrix2D>;
+
+
+
+//*****************************************************************************
+// diffusion for real and vec grids, e.g. for viscosity
+
+
+//! do a CG solve for diffusion; note: diffusion coefficient alpha given in grid space,
+// rescale in python file for discretization independence (or physical correspondence)
+// see lidDrivenCavity.py for an example
+
+
+void cgSolveDiffusion(const FlagGrid& flags, GridBase& grid, Real alpha = 0.25, Real cgMaxIterFac = 1.0, Real cgAccuracy = 1e-4 ) {
+ // reserve temp grids
+ FluidSolver* parent = flags.getParent();
+ Grid<Real> rhs(parent);
+ Grid<Real> residual(parent), search(parent), tmp(parent);
+ Grid<Real> A0(parent), Ai(parent), Aj(parent), Ak(parent);
+
+ // setup matrix and boundaries
+ FlagGrid flagsDummy(parent);
+ flagsDummy.setConst(FlagGrid::TypeFluid);
+ MakeLaplaceMatrix (flagsDummy, A0, Ai, Aj, Ak);
+
+ FOR_IJK(flags) {
+ if(flags.isObstacle(i,j,k)) {
+ Ai(i,j,k) = Aj(i,j,k) = Ak(i,j,k) = 0.0;
+ A0(i,j,k) = 1.0;
+ } else {
+ Ai(i,j,k) *= alpha;
+ Aj(i,j,k) *= alpha;
+ Ak(i,j,k) *= alpha;
+ A0(i,j,k) *= alpha;
+ A0(i,j,k) += 1.;
+ }
+ }
+
+ GridCgInterface *gcg;
+ // note , no preconditioning for now...
+ const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
+
+ if (grid.getType() & GridBase::TypeReal) {
+ Grid<Real>& u = ((Grid<Real>&) grid);
+ rhs.copyFrom(u);
+ if (flags.is3D())
+ gcg = new GridCg<ApplyMatrix >(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+ else
+ gcg = new GridCg<ApplyMatrix2D>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+
+ gcg->setAccuracy( cgAccuracy );
+ gcg->solve(maxIter);
+
+ debMsg("FluidSolver::solveDiffusion iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma(), CG_DEBUGLEVEL);
+ }
+ else
+ if( (grid.getType() & GridBase::TypeVec3) || (grid.getType() & GridBase::TypeVec3) )
+ {
+ Grid<Vec3>& vec = ((Grid<Vec3>&) grid);
+ Grid<Real> u(parent);
+
+ // core solve is same as for a regular real grid
+ if (flags.is3D())
+ gcg = new GridCg<ApplyMatrix >(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+ else
+ gcg = new GridCg<ApplyMatrix2D>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+ gcg->setAccuracy( cgAccuracy );
+
+ // diffuse every component separately
+ for(int component = 0; component< (grid.is3D() ? 3:2); ++component) {
+ getComponent( vec, u, component );
+ gcg->forceReinit();
+
+ rhs.copyFrom(u);
+ gcg->solve(maxIter);
+ debMsg("FluidSolver::solveDiffusion vec3, iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma(), CG_DEBUGLEVEL);
+
+ setComponent( u, vec, component );
+ }
+ } else {
+ errMsg("cgSolveDiffusion: Grid Type is not supported (only Real, Vec3, MAC, or Levelset)");
+ }
+
+ delete gcg;
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "cgSolveDiffusion" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); GridBase& grid = *_args.getPtr<GridBase >("grid",1,&_lock); Real alpha = _args.getOpt<Real >("alpha",2,0.25,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",3,1.0,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",4,1e-4 ,&_lock); _retval = getPyNone(); cgSolveDiffusion(flags,grid,alpha,cgMaxIterFac,cgAccuracy); _args.check(); }
+ pbFinalizePlugin(parent,"cgSolveDiffusion", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("cgSolveDiffusion",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_cgSolveDiffusion ("","cgSolveDiffusion",_W_0);
+extern "C" {
+ void PbRegister_cgSolveDiffusion() {
+ KEEP_UNUSED(_RP_cgSolveDiffusion); }
+ }
+
+
+
+
+
+
+}; // DDF
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h
new file mode 100644
index 00000000000..e47c7534987
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h
@@ -0,0 +1,275 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Conjugate gradient solver
+ *
+ ******************************************************************************/
+
+#ifndef _CONJUGATEGRADIENT_H
+#define _CONJUGATEGRADIENT_H
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+#include "multigrid.h"
+
+namespace Manta {
+
+static const bool CG_DEBUG = false;
+
+//! Basic CG interface
+class GridCgInterface {
+ public:
+ enum PreconditionType { PC_None=0, PC_ICP, PC_mICP, PC_MGP };
+
+ GridCgInterface() : mUseL2Norm(true) {};
+ virtual ~GridCgInterface() {};
+
+ // solving functions
+ virtual bool iterate() = 0;
+ virtual void solve(int maxIter) = 0;
+
+ // precond
+ virtual void setICPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) = 0;
+ virtual void setMGPreconditioner(PreconditionType method, GridMg* MG) = 0;
+
+ // access
+ virtual Real getSigma() const = 0;
+ virtual Real getIterations() const = 0;
+ virtual Real getResNorm() const = 0;
+ virtual void setAccuracy(Real set) = 0;
+ virtual Real getAccuracy() const = 0;
+
+ //! force reinit upon next iterate() call, can be used for doing multiple solves
+ virtual void forceReinit() = 0;
+
+ void setUseL2Norm(bool set) { mUseL2Norm = set; }
+
+ protected:
+
+ // use l2 norm of residualfor threshold? (otherwise uses max norm)
+ bool mUseL2Norm;
+};
+
+
+//! Run single iteration of the cg solver
+/*! the template argument determines the type of matrix multiplication,
+ typically a ApplyMatrix kernel, another one is needed e.g. for the
+ mesh-based wave equation solver */
+template<class APPLYMAT>
+class GridCg : public GridCgInterface {
+ public:
+ //! constructor
+ GridCg(Grid<Real>& dst, Grid<Real>& rhs, Grid<Real>& residual, Grid<Real>& search, const FlagGrid& flags, Grid<Real>& tmp,
+ Grid<Real>* A0, Grid<Real>* pAi, Grid<Real>* pAj, Grid<Real>* pAk);
+ ~GridCg() {}
+
+ void doInit();
+ bool iterate();
+ void solve(int maxIter);
+ //! init pointers, and copy values from "normal" matrix
+ void setICPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak);
+ void setMGPreconditioner(PreconditionType method, GridMg* MG);
+ void forceReinit() { mInited = false; }
+
+ // Accessors
+ Real getSigma() const { return mSigma; }
+ Real getIterations() const { return mIterations; }
+
+ Real getResNorm() const { return mResNorm; }
+
+ void setAccuracy(Real set) { mAccuracy=set; }
+ Real getAccuracy() const { return mAccuracy; }
+
+ protected:
+ bool mInited;
+ int mIterations;
+ // grids
+ Grid<Real>& mDst;
+ Grid<Real>& mRhs;
+ Grid<Real>& mResidual;
+ Grid<Real>& mSearch;
+ const FlagGrid& mFlags;
+ Grid<Real>& mTmp;
+
+ Grid<Real> *mpA0, *mpAi, *mpAj, *mpAk;
+
+ PreconditionType mPcMethod;
+ //! preconditioning grids
+ Grid<Real> *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk;
+ GridMg* mMG;
+
+ //! sigma / residual
+ Real mSigma;
+ //! accuracy of solver (max. residuum)
+ Real mAccuracy;
+ //! norm of the residual
+ Real mResNorm;
+}; // GridCg
+
+
+//! Kernel: Apply symmetric stored Matrix
+
+
+
+ struct ApplyMatrix : public KernelBase {
+ ApplyMatrix(const FlagGrid& flags, Grid<Real>& dst, const Grid<Real>& src, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak) : KernelBase(&flags,0) ,flags(flags),dst(dst),src(src),A0(A0),Ai(Ai),Aj(Aj),Ak(Ak) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags, Grid<Real>& dst, const Grid<Real>& src, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak ) const {
+ if (!flags.isFluid(idx)) {
+ dst[idx] = src[idx]; return;
+ }
+
+ dst[idx] = src[idx] * A0[idx]
+ + src[idx-X] * Ai[idx-X]
+ + src[idx+X] * Ai[idx]
+ + src[idx-Y] * Aj[idx-Y]
+ + src[idx+Y] * Aj[idx]
+ + src[idx-Z] * Ak[idx-Z]
+ + src[idx+Z] * Ak[idx];
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return dst; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return src; }
+ typedef Grid<Real> type2;inline Grid<Real>& getArg3() {
+ return A0; }
+ typedef Grid<Real> type3;inline Grid<Real>& getArg4() {
+ return Ai; }
+ typedef Grid<Real> type4;inline Grid<Real>& getArg5() {
+ return Aj; }
+ typedef Grid<Real> type5;inline Grid<Real>& getArg6() {
+ return Ak; }
+ typedef Grid<Real> type6; void runMessage() { debMsg("Executing kernel ApplyMatrix ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, flags,dst,src,A0,Ai,Aj,Ak); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const FlagGrid& flags; Grid<Real>& dst; const Grid<Real>& src; Grid<Real>& A0; Grid<Real>& Ai; Grid<Real>& Aj; Grid<Real>& Ak; }
+;
+
+//! Kernel: Apply symmetric stored Matrix. 2D version
+
+
+
+ struct ApplyMatrix2D : public KernelBase {
+ ApplyMatrix2D(const FlagGrid& flags, Grid<Real>& dst, const Grid<Real>& src, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak) : KernelBase(&flags,0) ,flags(flags),dst(dst),src(src),A0(A0),Ai(Ai),Aj(Aj),Ak(Ak) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags, Grid<Real>& dst, const Grid<Real>& src, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak ) const {
+ unusedParameter(Ak); // only there for parameter compatibility with ApplyMatrix
+
+ if (!flags.isFluid(idx)) {
+ dst[idx] = src[idx]; return;
+ }
+
+ dst[idx] = src[idx] * A0[idx]
+ + src[idx-X] * Ai[idx-X]
+ + src[idx+X] * Ai[idx]
+ + src[idx-Y] * Aj[idx-Y]
+ + src[idx+Y] * Aj[idx];
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return dst; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return src; }
+ typedef Grid<Real> type2;inline Grid<Real>& getArg3() {
+ return A0; }
+ typedef Grid<Real> type3;inline Grid<Real>& getArg4() {
+ return Ai; }
+ typedef Grid<Real> type4;inline Grid<Real>& getArg5() {
+ return Aj; }
+ typedef Grid<Real> type5;inline Grid<Real>& getArg6() {
+ return Ak; }
+ typedef Grid<Real> type6; void runMessage() { debMsg("Executing kernel ApplyMatrix2D ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, flags,dst,src,A0,Ai,Aj,Ak); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const FlagGrid& flags; Grid<Real>& dst; const Grid<Real>& src; Grid<Real>& A0; Grid<Real>& Ai; Grid<Real>& Aj; Grid<Real>& Ak; }
+;
+
+//! Kernel: Construct the matrix for the poisson equation
+
+ struct MakeLaplaceMatrix : public KernelBase {
+ MakeLaplaceMatrix(const FlagGrid& flags, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak, const MACGrid* fractions = 0) : KernelBase(&flags,1) ,flags(flags),A0(A0),Ai(Ai),Aj(Aj),Ak(Ak),fractions(fractions) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak, const MACGrid* fractions = 0 ) const {
+ if (!flags.isFluid(i,j,k))
+ return;
+
+ if(!fractions) {
+ // diagonal, A0
+ if (!flags.isObstacle(i-1,j,k)) A0(i,j,k) += 1.;
+ if (!flags.isObstacle(i+1,j,k)) A0(i,j,k) += 1.;
+ if (!flags.isObstacle(i,j-1,k)) A0(i,j,k) += 1.;
+ if (!flags.isObstacle(i,j+1,k)) A0(i,j,k) += 1.;
+ if (flags.is3D() && !flags.isObstacle(i,j,k-1)) A0(i,j,k) += 1.;
+ if (flags.is3D() && !flags.isObstacle(i,j,k+1)) A0(i,j,k) += 1.;
+
+ // off-diagonal entries
+ if (flags.isFluid(i+1,j,k)) Ai(i,j,k) = -1.;
+ if (flags.isFluid(i,j+1,k)) Aj(i,j,k) = -1.;
+ if (flags.is3D() && flags.isFluid(i,j,k+1)) Ak(i,j,k) = -1.;
+ } else {
+ // diagonal
+ A0(i,j,k) += fractions->get(i ,j,k).x;
+ A0(i,j,k) += fractions->get(i+1,j,k).x;
+ A0(i,j,k) += fractions->get(i,j ,k).y;
+ A0(i,j,k) += fractions->get(i,j+1,k).y;
+ if (flags.is3D()) A0(i,j,k) += fractions->get(i,j,k ).z;
+ if (flags.is3D()) A0(i,j,k) += fractions->get(i,j,k+1).z;
+
+ // off-diagonal entries
+ if (flags.isFluid(i+1,j,k)) Ai(i,j,k) = -fractions->get(i+1,j,k).x;
+ if (flags.isFluid(i,j+1,k)) Aj(i,j,k) = -fractions->get(i,j+1,k).y;
+ if (flags.is3D() && flags.isFluid(i,j,k+1)) Ak(i,j,k) = -fractions->get(i,j,k+1).z;
+ }
+
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return A0; }
+ typedef Grid<Real> type1;inline Grid<Real>& getArg2() {
+ return Ai; }
+ typedef Grid<Real> type2;inline Grid<Real>& getArg3() {
+ return Aj; }
+ typedef Grid<Real> type3;inline Grid<Real>& getArg4() {
+ return Ak; }
+ typedef Grid<Real> type4;inline const MACGrid* getArg5() {
+ return fractions; }
+ typedef MACGrid type5; void runMessage() { debMsg("Executing kernel MakeLaplaceMatrix ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,A0,Ai,Aj,Ak,fractions); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,A0,Ai,Aj,Ak,fractions); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; Grid<Real>& A0; Grid<Real>& Ai; Grid<Real>& Aj; Grid<Real>& Ak; const MACGrid* fractions; }
+;
+
+
+
+
+} // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h.reg
new file mode 100644
index 00000000000..90e55a88da4
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h.reg
@@ -0,0 +1 @@
+#include "conjugategrad.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h.reg.cpp
new file mode 100644
index 00000000000..1f7a40cc672
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/conjugategrad.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "conjugategrad.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_3()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.cpp
new file mode 100644
index 00000000000..cef9a155e1e
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.cpp
@@ -0,0 +1,679 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Mesh edge collapse and subdivision
+ *
+ ******************************************************************************/
+
+/******************************************************************************/
+// Copyright note:
+//
+// These functions (C) Chris Wojtan
+// Long-term goal is to unify with his split&merge codebase
+//
+/******************************************************************************/
+
+#include "edgecollapse.h"
+#include <queue>
+
+using namespace std;
+
+namespace Manta {
+
+// 8-point butterfly subdivision scheme (as described by Brochu&Bridson 2009)
+Vec3 ButterflySubdivision(Mesh& m, const Corner &ca, const Corner &cb)
+{
+ Vec3 p = m.nodes(m.corners(ca.prev).node).pos + m.nodes(m.corners(ca.next).node).pos;
+ Vec3 q = m.nodes(ca.node).pos + m.nodes(cb.node).pos;
+ Vec3 r = m.nodes(m.corners(m.corners(ca.next).opposite).node).pos
+ + m.nodes(m.corners(m.corners(ca.prev).opposite).node).pos
+ + m.nodes(m.corners(m.corners(cb.next).opposite).node).pos
+ + m.nodes(m.corners(m.corners(cb.prev).opposite).node).pos;
+ return ( 8*p + 2*q - r)/16.0;
+}
+
+// Modified Butterfly Subdivision Scheme from:
+// Interpolating Subdivision for Meshes with Arbitrary Topology
+// Denis Zorin, Peter Schroder, and Wim Sweldens
+// input the Corner that satisfies the following:
+// c.prev.node is the extraordinary vertex,
+// and c.next.node is the other vertex involved in the subdivision
+Vec3 OneSidedButterflySubdivision(Mesh& m, const int valence, const Corner &c) {
+ Vec3 out;
+ Vec3 p0 = m.nodes(m.corners(c.prev).node).pos;
+ Vec3 p1 = m.nodes(m.corners(c.next).node).pos;
+
+ if(valence==3) {
+ Vec3 p2 = m.nodes(c.node).pos;
+ Vec3 p3 = m.nodes(m.corners(m.corners(c.next).opposite).node).pos;
+ out = (5.0/12.0)*p1 - (1.0/12.0)*(p2+p3) + 0.75*p0;
+ }
+ else if(valence==4) {
+ Vec3 p2 = m.nodes(m.corners(m.corners(c.next).opposite).node).pos;
+ out = 0.375*p1 - 0.125*p2 + 0.75*p0;
+ }
+ else {
+ // rotate around extraordinary vertex,
+ // calculate subdivision weights,
+ // and interpolate vertex position
+ double rv = 1.0/(double)valence;
+ out = 0.0;
+ int current = c.prev;
+ for(int j=0; j<valence; j++) {
+ double s = (0.25 + cos(2*M_PI*j*rv) + 0.5*cos(4*M_PI*j*rv))*rv;
+ Vec3 p = m.nodes(m.corners(m.corners(current).prev).node).pos;
+
+ out += s*p;
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ }
+ out += 0.75* m.nodes(m.corners(c.prev).node).pos;
+ }
+ return out;
+}
+
+// Modified Butterfly Subdivision Scheme from:
+// Interpolating Subdivision for Meshes with Arbitrary Topology
+// Denis Zorin, Peter Schroder, and Wim Sweldens
+Vec3 ModifiedButterflySubdivision(Mesh& m, const Corner &ca, const Corner &cb, const Vec3& fallback)
+{
+ // calculate the valence of the two parent vertices
+ int start = ca.prev;
+ int current = start;
+ int valenceA = 0;
+ do {
+ valenceA++;
+ int op = m.corners(m.corners(current).next).opposite;
+ if (op < 0) return fallback;
+ current = m.corners(op).next;
+ }
+ while(current != start);
+ start = ca.next;
+ current = start;
+ int valenceB = 0;
+ do {
+ valenceB++;
+ int op = m.corners(m.corners(current).next).opposite;
+ if (op < 0) return fallback;
+ current = m.corners(op).next;
+ }
+ while(current != start);
+
+ // if both vertices have valence 6, use butterfly subdivision
+ if(valenceA==6 && valenceB==6) {
+ return ButterflySubdivision(m, ca,cb);
+ }
+ else if(valenceA==6) // use a one-sided scheme
+ {
+ return OneSidedButterflySubdivision(m, valenceB,cb);
+ }
+ else if(valenceB==6) // use a one-sided scheme
+ {
+ return OneSidedButterflySubdivision(m, valenceA,ca);
+ }
+ else // average the results from two one-sided schemes
+ {
+ return 0.5*( OneSidedButterflySubdivision(m, valenceA,ca)
+ + OneSidedButterflySubdivision(m, valenceB,cb) );
+ }
+}
+
+bool gAbort = false;
+
+// collapse an edge on triangle "trinum".
+// "which" is 0,1, or 2,
+// where which==0 is the triangle edge from p0 to p1,
+// which==1 is the triangle edge from p1 to p2,
+// and which==2 is the triangle edge from p2 to p0,
+void CollapseEdge(Mesh& m, const int trinum, const int which, const Vec3 &edgevect, const Vec3 &endpoint,
+ vector<int> &deletedNodes, std::map<int,bool> &taintedTris, int &numCollapses, bool doTubeCutting)
+{
+ if (gAbort) return;
+ // I wanted to draw a pretty picture of an edge collapse,
+ // but I don't know how to make wacky angled lines in ASCII.
+ // Instead, I will show the before case and tell you what needs to be done.
+
+ // BEFORE:
+ // *
+ // / \.
+ // /C0 \.
+ // / \.
+ // / \.
+ // / B \.
+ // / \.
+ // /C1 C2 \.
+ // P0 *---------------* P1
+ // \C2 C1 /
+ // \ /
+ // \ A /
+ // \ /
+ // \ /
+ // \C0 /
+ // \ /
+ // *
+ //
+ // We are going to collapse the edge between P0 and P1
+ // by deleting P1,
+ // and taking all references to P1,
+ // and rerouting them to P0 instead
+ //
+ // What we need to do:
+ // Move position of P0
+ // Preserve connectivity in both triangles:
+ // (C1.opposite).opposite = C2.o
+ // (C2.opposite).opposite = C1.o
+ // Delete references to Corners of deleted triangles in both P0 and P1's Corner list
+ // Reassign references to P1:
+ // loop through P1 triangles:
+ // rename P1 references to P0 in p lists.
+ // rename Corner.v references
+ // Copy P1's list of Corners over to P0's list of Corners
+ // Delete P1
+
+ Corner ca_old[3], cb_old[3];
+ ca_old[0] = m.corners(trinum, which);
+ ca_old[1] = m.corners(ca_old[0].next);
+ ca_old[2] = m.corners(ca_old[0].prev);
+ bool haveB = false;
+ if (ca_old[0].opposite>=0) {
+ cb_old[0] = m.corners(ca_old[0].opposite);
+ cb_old[1] = m.corners(cb_old[0].next);
+ cb_old[2] = m.corners(cb_old[0].prev);
+ haveB = true;
+ }
+ if (!haveB) {
+ // for now, don't collapse
+ return;
+ }
+
+ int P0 = ca_old[2].node;
+ int P1 = ca_old[1].node;
+
+ ///////////////
+ // avoid creating nonmanifold edges
+ bool nonmanifold = false;
+ bool nonmanifold2 = false;
+
+ set<int>& ring0 = m.get1Ring(P0).nodes;
+ set<int>& ring1 = m.get1Ring(P1).nodes;
+
+ // check for intersections of the 1-rings of P0,P1
+ int cl=0, commonVert=-1;
+ for(set<int>::iterator it=ring1.begin(); it != ring1.end(); ++it)
+ if (ring0.find(*it) != ring0.end()) {
+ cl++;
+ if (*it != ca_old[0].node && *it != cb_old[0].node) commonVert = *it;
+ }
+
+ nonmanifold = cl>2;
+ nonmanifold2 = cl>3;
+
+ if(nonmanifold &&
+ ca_old[1].opposite>=0 && cb_old[1].opposite>=0 &&
+ ca_old[2].opposite>=0 && cb_old[2].opposite>=0 ) // collapsing this edge would create a non-manifold edge
+ {
+ if(nonmanifold2)
+ return;
+
+ bool topTet = false;
+ bool botTet = false;
+ // check if collapsing this edge will collapse a tet.
+ if(m.corners(ca_old[1].opposite).node == m.corners(ca_old[2].opposite).node)
+ botTet = true;
+
+ if(m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node)
+ topTet = true;
+
+ if(topTet^botTet) {
+
+ // safe pyramid case.
+ // collapse the whole tet!
+ // First collapse the top of the pyramid,
+ // then carry on collapsing the original verts.
+ Corner cc_old[3],cd_old[3];
+ if(botTet)
+ cc_old[0] = m.corners(ca_old[1].opposite);
+ else // topTet
+ cc_old[0] = cb_old[2];
+ cc_old[1] = m.corners(cc_old[0].next);
+ cc_old[2] = m.corners(cc_old[0].prev);
+ if (cc_old[0].opposite<0) return;
+ cd_old[0] = m.corners(cc_old[0].opposite);
+ cd_old[1] = m.corners(cd_old[0].next);
+ cd_old[2] = m.corners(cd_old[0].prev);
+ int P2 = cc_old[2].node;
+ int P3 = cc_old[1].node;
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ for (int i=0; i<m.numTriChannels(); i++)
+ {};//TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]);
+
+ m.mergeNode(P2, P3);
+
+ // Preserve connectivity in both triangles
+ if (cc_old[1].opposite>=0)
+ m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite;
+ if (cc_old[2].opposite>=0)
+ m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite;
+ if (cd_old[1].opposite>=0)
+ m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite;
+ if (cd_old[2].opposite>=0)
+ m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ int tmpTrinum = cc_old[0].tri;
+ int tmpOthertri = cd_old[0].tri;
+ m.removeTriFromLookup(tmpTrinum);
+ m.removeTriFromLookup(tmpOthertri);
+ taintedTris[tmpTrinum] = true;
+ taintedTris[tmpOthertri] = true;
+ deletedNodes.push_back(P3);
+
+ numCollapses++;
+
+ // recompute Corners for triangles A and B
+ if(botTet)
+ ca_old[0] = m.corners(ca_old[2].opposite);
+ else
+ ca_old[0] = m.corners(ca_old[1].prev);
+ ca_old[1] = m.corners(ca_old[0].next);
+ ca_old[2] = m.corners(ca_old[0].prev);
+ cb_old[0] = m.corners(ca_old[0].opposite);
+ cb_old[1] = m.corners(cb_old[0].next);
+ cb_old[2] = m.corners(cb_old[0].prev);
+
+ ///////////////
+ // avoid creating nonmanifold edges... again
+ ring0 = m.get1Ring(ca_old[2].node).nodes;
+ ring1 = m.get1Ring(ca_old[1].node).nodes;
+
+ // check for intersections of the 1-rings of P0,P1
+ cl=0;
+ for(set<int>::iterator it=ring1.begin(); it != ring1.end(); ++it)
+ if (*it != ca_old[0].node && ring0.find(*it) != ring0.end())
+ cl++;
+
+ if(cl>2) { // nonmanifold
+ // this can happen if collapsing the first tet leads to another similar collapse that requires the collapse of a tet.
+ // for now, just move on and pick this up later.
+
+ // if the original component was very small, this first collapse could have led to a tiny piece of nonmanifold geometry.
+ // in this case, just delete everything that remains.
+ if(m.corners(ca_old[0].opposite).tri==cb_old[0].tri && m.corners(ca_old[1].opposite).tri==cb_old[0].tri && m.corners(ca_old[2].opposite).tri==cb_old[0].tri) {
+ taintedTris[ca_old[0].tri] = true;
+ taintedTris[cb_old[0].tri] = true;
+ m.removeTriFromLookup(ca_old[0].tri);
+ m.removeTriFromLookup(cb_old[0].tri);
+ deletedNodes.push_back(ca_old[0].node);
+ deletedNodes.push_back(ca_old[1].node);
+ deletedNodes.push_back(ca_old[2].node);
+ }
+ return;
+ }
+ } else if(topTet && botTet && ca_old[1].opposite>=0 && ca_old[2].opposite>=0 && cb_old[1].opposite>=0 && cb_old[2].opposite>=0)
+ {
+ if(!(m.corners(ca_old[1].opposite).node == m.corners(ca_old[2].opposite).node &&
+ m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node &&
+ (m.corners(ca_old[1].opposite).node == m.corners(cb_old[1].opposite).node ||
+ (m.corners(ca_old[1].opposite).node == cb_old[0].node &&
+ m.corners(cb_old[1].opposite).node == ca_old[0].node) )))
+ {
+ // just collapse one for now.
+
+ // collapse the whole tet!
+ // First collapse the top of the pyramid,
+ // then carry on collapsing the original verts.
+ Corner cc_old[3],cd_old[3];
+
+ // collapse top
+ {
+ cc_old[0] = m.corners(ca_old[1].opposite);
+ cc_old[1] = m.corners(cc_old[0].next);
+ cc_old[2] = m.corners(cc_old[0].prev);
+ if (cc_old[0].opposite<0) return;
+ cd_old[0] = m.corners(cc_old[0].opposite);
+ cd_old[1] = m.corners(cd_old[0].next);
+ cd_old[2] = m.corners(cd_old[0].prev);
+ int P2 = cc_old[2].node;
+ int P3 = cc_old[1].node;
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ // TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]);
+
+ m.mergeNode(P2, P3);
+
+ // Preserve connectivity in both triangles
+ if (cc_old[1].opposite>=0)
+ m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite;
+ if (cc_old[2].opposite>=0)
+ m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite;
+ if (cd_old[1].opposite>=0)
+ m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite;
+ if (cd_old[2].opposite>=0)
+ m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ int tmpTrinum = cc_old[0].tri;
+ int tmpOthertri = cd_old[0].tri;
+ taintedTris[tmpTrinum] = true;
+ taintedTris[tmpOthertri] = true;
+ m.removeTriFromLookup(tmpTrinum);
+ m.removeTriFromLookup(tmpOthertri);
+ deletedNodes.push_back(P3);
+
+ numCollapses++;
+ }
+ // then collapse bottom
+ {
+ //cc_old[0] = [ca_old[1].opposite;
+ cc_old[0] = cb_old[2];
+ cc_old[1] = m.corners(cc_old[0].next);
+ cc_old[2] = m.corners(cc_old[0].prev);
+ if (cc_old[0].opposite<0) return;
+ cd_old[0] = m.corners(cc_old[0].opposite);
+ cd_old[1] = m.corners(cd_old[0].next);
+ cd_old[2] = m.corners(cd_old[0].prev);
+ int P2 = cc_old[2].node;
+ int P3 = cc_old[1].node;
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ // TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]);
+
+ m.mergeNode(P2, P3);
+
+ // Preserve connectivity in both triangles
+ if (cc_old[1].opposite>=0)
+ m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite;
+ if (cc_old[2].opposite>=0)
+ m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite;
+ if (cd_old[1].opposite>=0)
+ m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite;
+ if (cd_old[2].opposite>=0)
+ m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ int tmpTrinum = cc_old[0].tri;
+ int tmpOthertri = cd_old[0].tri;
+ taintedTris[tmpTrinum] = true;
+ taintedTris[tmpOthertri] = true;
+ deletedNodes.push_back(P3);
+
+ numCollapses++;
+ }
+
+ // Though we've collapsed a lot of stuff, we still haven't collapsed the original edge.
+ // At this point we still haven't guaranteed that this original collapse weill be safe.
+ // quit for now, and we'll catch the remaining short edges the next time this function is called.
+ return;
+ }
+ }
+ else if (doTubeCutting)
+ {
+ // tube case
+ //cout<<"CollapseEdge:tube case" << endl;
+
+ // find the edges that touch the common vert
+ int P2 = commonVert;
+ int P1P2=-1, P2P1, P2P0=-1, P0P2=-1; // corners across from the cutting seam
+ int start = ca_old[0].next;
+ int end = cb_old[0].prev;
+ int current = start;
+ do {
+ // rotate around vertex P1 counter-clockwise
+ int op = m.corners(m.corners(current).next).opposite;
+ if (op < 0) errMsg("tube cutting failed, no opposite");
+ current = m.corners(op).next;
+
+ if(m.corners(m.corners(current).prev).node==commonVert)
+ P1P2 = m.corners(current).next;
+ }
+ while(current != end);
+
+ start = ca_old[0].prev;
+ end = cb_old[0].next;
+ current = start;
+ do {
+ // rotate around vertex P0 clockwise
+ int op = m.corners(m.corners(current).prev).opposite;
+ if (op < 0) errMsg("tube cutting failed, no opposite");
+
+ current = m.corners(op).prev;
+ if(m.corners(m.corners(current).next).node==commonVert)
+ P2P0 = m.corners(current).prev;
+ } while(current != end);
+
+ if (P1P2 < 0 || P2P0 < 0)
+ errMsg("tube cutting failed, ill geometry");
+
+ P2P1 = m.corners(P1P2).opposite;
+ P0P2 = m.corners(P2P0).opposite;
+
+ // duplicate vertices on the top half of the cut,
+ // and use them to split the tube at this seam
+ int P0b = m.addNode(Node(m.nodes(P0).pos));
+ int P1b = m.addNode(Node(m.nodes(P1).pos));
+ int P2b = m.addNode(Node(m.nodes(P2).pos));
+ for (int i=0; i<m.numNodeChannels(); i++) {
+ m.nodeChannel(i)->addInterpol(P0, P0, 0.5);
+ m.nodeChannel(i)->addInterpol(P1, P1, 0.5);
+ m.nodeChannel(i)->addInterpol(P2, P2, 0.5);
+ }
+
+ // offset the verts in the normal directions to avoid self intersections
+ Vec3 offsetVec = cross(m.nodes(P1).pos-m.nodes(P0).pos, m.nodes(P2).pos-m.nodes(P0).pos);
+ normalize(offsetVec);
+ offsetVec *= 0.01; // HACK:
+ m.nodes(P0).pos -= offsetVec;
+ m.nodes(P1).pos -= offsetVec;
+ m.nodes(P2).pos -= offsetVec;
+ m.nodes(P0b).pos += offsetVec;
+ m.nodes(P1b).pos += offsetVec;
+ m.nodes(P2b).pos += offsetVec;
+
+ // create a list of all triangles which touch P0, P1, and P2 from the top,
+ map<int,bool> topTris;
+ start = cb_old[0].next;
+ end = m.corners(P0P2).prev;
+ current = start;
+ topTris[start/3]=true;
+ do {
+ // rotate around vertex P0 counter-clockwise
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ topTris[current/3]=true;
+ } while(current != end);
+ start = m.corners(P0P2).next;
+ end = m.corners(P2P1).prev;
+ current = start;
+ topTris[start/3]=true;
+ do {
+ // rotate around vertex P0 counter-clockwise
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ topTris[current/3]=true;
+ } while(current != end);
+ start = m.corners(P2P1).next;
+ end = cb_old[0].prev;
+ current = start;
+ topTris[start/3]=true;
+ do {
+ // rotate around vertex P0 counter-clockwise
+ current = m.corners(m.corners(m.corners(current).next).opposite).next;
+ topTris[current/3]=true;
+ } while(current != end);
+
+ // create two new triangles,
+ int Ta = m.addTri(Triangle(P0,P1,P2));
+ int Tb = m.addTri(Triangle(P1b,P0b,P2b));
+ for (int i=0; i<m.numTriChannels(); i++) {
+ m.triChannel(i)->addNew();
+ m.triChannel(i)->addNew();
+ }
+
+ // sew the tris to close the cut on each side
+ for(int c=0; c<3; c++) m.addCorner(Corner(Ta, m.tris(Ta).c[c]));
+ for(int c=0; c<3; c++) m.addCorner(Corner(Tb, m.tris(Tb).c[c]));
+ for(int c=0; c<3; c++) {
+ m.corners(Ta,c).next = 3*Ta+((c+1)%3);
+ m.corners(Ta,c).prev = 3*Ta+((c+2)%3);
+ m.corners(Tb,c).next = 3*Tb+((c+1)%3);
+ m.corners(Tb,c).prev = 3*Tb+((c+2)%3);
+ }
+ m.corners(Ta,0).opposite = P1P2;
+ m.corners(Ta,1).opposite = P2P0;
+ m.corners(Ta,2).opposite = ca_old[1].prev;
+ m.corners(Tb,0).opposite = P0P2;
+ m.corners(Tb,1).opposite = P2P1;
+ m.corners(Tb,2).opposite = cb_old[1].prev;
+ for (int c=0; c<3; c++) {
+ m.corners(m.corners(Ta,c).opposite).opposite = 3*Ta+c;
+ m.corners(m.corners(Tb,c).opposite).opposite = 3*Tb+c;
+ }
+ // replace P0,P1,P2 on the top with P0b,P1b,P2b.
+ for(map<int,bool>::iterator tti=topTris.begin(); tti!=topTris.end(); tti++) {
+ //cout << "H " << tti->first << " : " << m.tris(tti->first).c[0] << " " << m.tris(tti->first).c[1] << " " << m.tris(tti->first).c[2] << " " << endl;
+ for(int i=0; i<3; i++) {
+ int cn = m.tris(tti->first).c[i];
+ set<int>& ring = m.get1Ring(cn).nodes;
+
+ if (ring.find(P0) != ring.end() && cn!=P0 && cn!=P1 && cn!=P2 && cn!=P0b && cn!=P1b && cn!=P2b) {
+ ring.erase(P0);
+ ring.insert(P0b);
+ m.get1Ring(P0).nodes.erase(cn);
+ m.get1Ring(P0b).nodes.insert(cn);
+ }
+ if (ring.find(P1) != ring.end() && cn!=P0 && cn!=P1 && cn!=P2 && cn!=P0b && cn!=P1b && cn!=P2b) {
+ ring.erase(P1);
+ ring.insert(P1b);
+ m.get1Ring(P1).nodes.erase(cn);
+ m.get1Ring(P1b).nodes.insert(cn);
+ }
+ if (ring.find(P2) != ring.end() && cn!=P0 && cn!=P1 && cn!=P2 && cn!=P0b && cn!=P1b && cn!=P2b) {
+ ring.erase(P2);
+ ring.insert(P2b);
+ m.get1Ring(P2).nodes.erase(cn);
+ m.get1Ring(P2b).nodes.insert(cn);
+ }
+ if(cn==P0) {
+ m.tris(tti->first).c[i]=P0b;
+ m.corners(tti->first,i).node = P0b;
+ m.get1Ring(P0).tris.erase(tti->first);
+ m.get1Ring(P0b).tris.insert(tti->first);
+ }
+ else if(cn==P1) {
+ m.tris(tti->first).c[i]=P1b;
+ m.corners(tti->first,i).node = P1b;
+ m.get1Ring(P1).tris.erase(tti->first);
+ m.get1Ring(P1b).tris.insert(tti->first);
+ }
+ else if(cn==P2) {
+ m.tris(tti->first).c[i]=P2b;
+ m.corners(tti->first,i).node = P2b;
+ m.get1Ring(P2).tris.erase(tti->first);
+ m.get1Ring(P2b).tris.insert(tti->first);
+ }
+ }
+ }
+
+ //m.sanityCheck(true, &deletedNodes, &taintedTris);
+
+ return;
+ }
+ return;
+ }
+ if(ca_old[1].opposite>=0 && ca_old[2].opposite>=0 && cb_old[1].opposite>=0 && cb_old[2].opposite>=0 && ca_old[0].opposite>=0 && cb_old[0].opposite>=0 &&
+ ((m.corners(ca_old[1].opposite).node == m.corners(ca_old[2].opposite).node && // two-pyramid tubey case (6 tris, 5 verts)
+ m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node &&
+ (m.corners(ca_old[1].opposite).node == m.corners(cb_old[1].opposite).node ||
+ (m.corners(ca_old[1].opposite).node==cb_old[0].node && // single tetrahedron case
+ m.corners(cb_old[1].opposite).node==ca_old[0].node) ))
+ ||
+ (m.corners(ca_old[0].opposite).tri==m.corners(cb_old[0].opposite).tri && m.corners(ca_old[1].opposite).tri==m.corners(cb_old[0].opposite).tri && m.corners(ca_old[2].opposite).tri==m.corners(cb_old[0].opposite).tri // nonmanifold: 2 tris, 3 verts
+ && m.corners(cb_old[0].opposite).tri==m.corners(ca_old[0].opposite).tri && m.corners(cb_old[1].opposite).tri==m.corners(ca_old[0].opposite).tri && m.corners(cb_old[2].opposite).tri==m.corners(ca_old[0].opposite).tri)
+ ))
+ {
+ // both top and bottom are closed pyramid caps, or it is a single tet
+ // delete the whole component!
+ // flood fill to mark all triangles in the component
+ map<int,bool> markedTris;
+ queue<int> triQ;
+ triQ.push(trinum);
+ markedTris[trinum] = true;
+ int iters = 0;
+ while(!triQ.empty()) {
+ int trival = triQ.front();
+ triQ.pop();
+ for(int i=0; i<3; i++) {
+ int newtri = m.corners(m.corners(trival,i).opposite).tri;
+ if(markedTris.find(newtri)==markedTris.end()) {
+ triQ.push(newtri);
+ markedTris[newtri] = true;
+ }
+ }
+ iters++;
+ }
+ map<int,bool> markedverts;
+ for(map<int,bool>::iterator mit=markedTris.begin(); mit!=markedTris.end(); mit++) {
+ taintedTris[mit->first] = true;
+ markedverts[m.tris(mit->first).c[0]] = true;
+ markedverts[m.tris(mit->first).c[1]] = true;
+ markedverts[m.tris(mit->first).c[2]] = true;
+ }
+ for(map<int,bool>::iterator mit=markedverts.begin(); mit!=markedverts.end(); mit++)
+ deletedNodes.push_back(mit->first);
+ return;
+ }
+
+ //////////////////////////
+ // begin original edge collapse
+
+ // update tri props of all adjacent triangles of P0,P1 (do before CT updates!)
+ // TODO: handleTriPropertyEdgeCollapse(trinum, P0,P1, ca_old[0], cb_old[0]);
+
+ m.mergeNode(P0, P1);
+
+ // Move position of P0
+ m.nodes(P0).pos = endpoint + 0.5*edgevect;
+
+ // Preserve connectivity in both triangles
+ if (ca_old[1].opposite>=0)
+ m.corners(ca_old[1].opposite).opposite = ca_old[2].opposite;
+ if (ca_old[2].opposite>=0)
+ m.corners(ca_old[2].opposite).opposite = ca_old[1].opposite;
+ if (haveB && cb_old[1].opposite>=0)
+ m.corners(cb_old[1].opposite).opposite = cb_old[2].opposite;
+ if (haveB && cb_old[2].opposite>=0)
+ m.corners(cb_old[2].opposite).opposite = cb_old[1].opposite;
+
+ ////////////////////
+ // mark the two triangles and the one node for deletion
+ taintedTris[ca_old[0].tri] = true;
+ m.removeTriFromLookup(ca_old[0].tri);
+ if (haveB) {
+ taintedTris[cb_old[0].tri] = true;
+ m.removeTriFromLookup(cb_old[0].tri);
+ }
+ deletedNodes.push_back(P1);
+ numCollapses++;
+}
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h
new file mode 100644
index 00000000000..9e831d3a630
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h
@@ -0,0 +1,48 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Mesh edge collapse and subdivision
+ *
+ ******************************************************************************/
+
+/******************************************************************************/
+// Copyright note:
+//
+// These functions (C) Chris Wojtan
+// Long-term goal is to unify with his split&merge codebase
+//
+/******************************************************************************/
+
+#ifndef _EDGECOLLAPSE_H
+#define _EDGECOLLAPSE_H
+
+#include "mesh.h"
+
+namespace Manta {
+
+void CollapseEdge(Mesh& mesh, const int trinum, const int which, const Vec3 &edgevect, const Vec3 &endpoint,
+ std::vector<int> &deletedNodes, std::map<int,bool> &taintedTris, int &numCollapses, bool doTubeCutting);
+
+Vec3 ModifiedButterflySubdivision(Mesh& mesh, const Corner& ca, const Corner& cb, const Vec3& fallback);
+
+}
+
+#endif
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h.reg
new file mode 100644
index 00000000000..9869b6a5c7d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h.reg
@@ -0,0 +1 @@
+#include "edgecollapse.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h.reg.cpp
new file mode 100644
index 00000000000..9c63706d623
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/edgecollapse.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "edgecollapse.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_19()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.cpp
new file mode 100644
index 00000000000..4e9627e65b6
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.cpp
@@ -0,0 +1,747 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Fast marching and extrapolation
+ *
+ ******************************************************************************/
+
+#include "fastmarch.h"
+#include "levelset.h"
+#include "kernel.h"
+#include <algorithm>
+
+using namespace std;
+
+namespace Manta {
+
+template<class COMP, int TDIR>
+FastMarch<COMP,TDIR>::FastMarch(const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& levelset, Real maxTime, MACGrid* velTransport )
+ : mLevelset(levelset), mFlags(flags), mFmFlags(fmFlags)
+{
+ if (velTransport)
+ mVelTransport.initMarching(velTransport, &flags);
+
+ mMaxTime = maxTime * TDIR;
+}
+
+// helper for individual components to calculateDistance
+template<class COMP, int TDIR> template<int C>
+Real FastMarch<COMP,TDIR>::calcWeights(int& okcnt, int& invcnt, Real* v, const Vec3i& idx) {
+ Real val = 0.;
+ Vec3i idxPlus(idx), idxMinus(idx);
+ idxPlus[C]++;
+ idxMinus[C]--;
+
+ mWeights[C*2] = mWeights[C*2+1] = 0.;
+ if (mFmFlags(idxPlus)==FlagInited) {
+ // somewhat arbitrary - choose +1 value over -1 ...
+ val = mLevelset(idxPlus);
+ v[okcnt] = val; okcnt++;
+ mWeights[C*2] = 1.;
+ } else if (mFmFlags(idxMinus)==FlagInited) {
+ val = mLevelset(idxMinus);
+ v[okcnt] = val; okcnt++;
+ mWeights[C*2+1] = 1.;
+ }
+ else {
+ invcnt++;
+ }
+ return val;
+}
+
+template<class COMP, int TDIR>
+inline Real FastMarch<COMP,TDIR>::calculateDistance(const Vec3i& idx) {
+ //int invflag = 0;
+ int invcnt = 0;
+ Real v[3];
+ int okcnt = 0;
+
+ Real aVal = calcWeights<0>(okcnt, invcnt, v, idx);
+ Real bVal = calcWeights<1>(okcnt, invcnt, v, idx);
+ Real cVal = 0.;
+ if (mLevelset.is3D()) cVal = calcWeights<2>(okcnt, invcnt, v, idx);
+ else { invcnt++; mWeights[4] = mWeights[5] = 0.; }
+
+ Real ret = InvalidTime();
+ switch(invcnt) {
+ case 0: {
+ // take all values
+ const Real ca=v[0], cb=v[1], cc=v[2];
+ const Real csqrt = max(0. ,
+ -2.*(ca*ca+cb*cb- cb*cc + cc*cc - ca*(cb+cc)) + 3 );
+ // clamp to make sure the sqrt is valid
+ ret = 0.333333*( ca+cb+cc+ TDIR*sqrt(csqrt) );
+
+ // weights needed for transport (transpTouch)
+ mWeights[0] *= fabs(ret-ca);
+ mWeights[1] *= fabs(ret-ca);
+ mWeights[2] *= fabs(ret-cb);
+ mWeights[3] *= fabs(ret-cb);
+ mWeights[4] *= fabs(ret-cc);
+ mWeights[5] *= fabs(ret-cc);
+
+ Real norm = 0.0; // try to force normalization
+ for(int i=0;i<6;i++) {
+ norm += mWeights[i];
+ }
+ norm = 1.0/norm;
+ for(int i=0;i<6;i++) { mWeights[i] *= norm; }
+
+ } break;
+ case 1: {
+ // take just the 2 ok values
+ // t=0.5*( a+b+ (2*g*g-(b-a)*(b-a))^0.5)
+ const Real csqrt = max(0. , 2.-(v[1]-v[0])*(v[1]-v[0]) );
+ // clamp to make sure the sqrt is valid
+ ret = 0.5*( v[0]+v[1]+ TDIR*sqrt(csqrt) );
+
+ // weights needed for transport (transpTouch)
+ mWeights[0] *= fabs(ret-aVal);
+ mWeights[1] *= fabs(ret-aVal);
+ mWeights[2] *= fabs(ret-bVal);
+ mWeights[3] *= fabs(ret-bVal);
+ mWeights[4] *= fabs(ret-cVal);
+ mWeights[5] *= fabs(ret-cVal);
+
+ Real norm = 0.0; // try to force normalization
+ for(int i=0;i<6;i++) {
+ norm += mWeights[i];
+ }
+ norm = 1.0/norm;
+ for(int i=0;i<6;i++) { mWeights[i] *= norm; }
+ // */
+
+ } break;
+ case 2: {
+ // just use the one remaining value
+ ret = v[0]+ (Real)(TDIR) ; // direction = +- 1
+ } break;
+ default:
+ errMsg("FastMarch :: Invalid invcnt");
+ break;
+ }
+ return ret;
+}
+
+template<class COMP, int TDIR>
+void FastMarch<COMP,TDIR>::addToList(const Vec3i& p, const Vec3i& src) {
+ if (!mLevelset.isInBounds(p,1)) return;
+ const IndexInt idx = mLevelset.index(p);
+
+ // already known value, value alreay set to valid value? skip cell...
+ if(mFmFlags[idx] == FlagInited) return;
+
+ // discard by source time now , TODO do instead before calling all addtolists?
+ Real srct = mLevelset(src);
+ if(COMP::compare(srct, mMaxTime)) return;
+
+ Real ttime = calculateDistance(p);
+
+ // remove old entry if larger
+ bool found=false;
+
+ Real oldt = mLevelset[idx];
+ if (mFmFlags[idx] == FlagIsOnHeap) {
+ found = true;
+ // is old time better?
+ if(COMP::compare(ttime,oldt)) return;
+ }
+
+ // update field
+ mFmFlags[idx] = FlagIsOnHeap;
+ mLevelset[idx] = ttime;
+ // debug info std::cout<<"set "<< idx <<","<< ttime <<"\n";
+
+ if (mVelTransport.isInitialized())
+ mVelTransport.transpTouch(p.x, p.y, p.z, mWeights, ttime);
+
+ // the following adds entries to the heap of active cells
+ // current: (!found) , previous: always add, might lead to duplicate
+ // entries, but the earlier will be handled earlier, the second one will skip to the FlagInited check above
+ if(!found)
+ {
+ // add list entry with source value
+ COMP entry;
+ entry.p = p;
+ entry.time = mLevelset[idx];
+
+ mHeap.push( entry );
+ // debug info std::cout<<"push "<< entry.p <<","<< entry.time <<"\n";
+ }
+
+}
+
+//! Enforce delta_phi = 0 on boundaries
+
+ struct SetLevelsetBoundaries : public KernelBase {
+ SetLevelsetBoundaries(Grid<Real>& phi) : KernelBase(&phi,0) ,phi(phi) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& phi ) {
+ if (i==0) phi(i,j,k) = phi(1,j,k);
+ if (i==maxX-1) phi(i,j,k) = phi(i-1,j,k);
+
+ if (j==0) phi(i,j,k) = phi(i,1,k);
+ if (j==maxY-1) phi(i,j,k) = phi(i,j-1,k);
+
+ if(phi.is3D()) {
+ if (k==0) phi(i,j,k) = phi(i,j,1);
+ if (k==maxZ-1) phi(i,j,k) = phi(i,j,k-1);
+ }
+} inline Grid<Real>& getArg0() {
+ return phi; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel SetLevelsetBoundaries ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=0; j< _maxY; j++) for (int i=0; i< _maxX; i++) op(i,j,k, phi); }
+ Grid<Real>& phi; }
+;
+
+/*****************************************************************************/
+//! Walk...
+template<class COMP, int TDIR>
+void FastMarch<COMP,TDIR>::performMarching() {
+ mReheapVal = 0.0;
+ while(mHeap.size() > 0) {
+
+ const COMP& ce = mHeap.top();
+ Vec3i p = ce.p;
+ mFmFlags(p) = FlagInited;
+ mHeap.pop();
+ // debug info std::cout<<"pop "<< ce.p <<","<< ce.time <<"\n";
+
+ addToList(Vec3i(p.x-1,p.y,p.z), p);
+ addToList(Vec3i(p.x+1,p.y,p.z), p);
+ addToList(Vec3i(p.x,p.y-1,p.z), p);
+ addToList(Vec3i(p.x,p.y+1,p.z), p);
+ if(mLevelset.is3D()) {
+ addToList(Vec3i(p.x,p.y,p.z-1), p);
+ addToList(Vec3i(p.x,p.y,p.z+1), p);
+ }
+ }
+
+ // set boundary for plain array
+ SetLevelsetBoundaries setls(mLevelset);
+ setls.getArg0(); // get rid of compiler warning...
+}
+
+// explicit instantiation
+template class FastMarch<FmHeapEntryIn, -1>;
+template class FastMarch<FmHeapEntryOut, +1>;
+
+
+/*****************************************************************************/
+// simpler extrapolation functions (primarily for FLIP)
+
+
+
+ struct knExtrapolateMACSimple : public KernelBase {
+ knExtrapolateMACSimple(MACGrid& vel, int distance , Grid<int>& tmp , const int d , const int c ) : KernelBase(&vel,1) ,vel(vel),distance(distance),tmp(tmp),d(d),c(c) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& vel, int distance , Grid<int>& tmp , const int d , const int c ) const {
+ static const Vec3i nb[6] = {
+ Vec3i(1 ,0,0), Vec3i(-1,0,0),
+ Vec3i(0,1 ,0), Vec3i(0,-1,0),
+ Vec3i(0,0,1 ), Vec3i(0,0,-1) };
+ const int dim = (vel.is3D() ? 3:2);
+
+ if (tmp(i,j,k) != 0) return;
+
+ // copy from initialized neighbors
+ Vec3i p(i,j,k);
+ int nbs = 0;
+ Real avgVel = 0.;
+ for (int n=0; n<2*dim; ++n) {
+ if (tmp(p+nb[n]) == d) {
+ //vel(p)[c] = (c+1.)*0.1;
+ avgVel += vel(p+nb[n])[c];
+ nbs++;
+ }
+ }
+
+ if(nbs>0) {
+ tmp(p) = d+1;
+ vel(p)[c] = avgVel / nbs;
+ }
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline int& getArg1() {
+ return distance; }
+ typedef int type1;inline Grid<int>& getArg2() {
+ return tmp; }
+ typedef Grid<int> type2;inline const int& getArg3() {
+ return d; }
+ typedef int type3;inline const int& getArg4() {
+ return c; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel knExtrapolateMACSimple ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,distance,tmp,d,c); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,distance,tmp,d,c); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ MACGrid& vel; int distance; Grid<int>& tmp; const int d; const int c; }
+;
+//! copy velocity into domain side, note - don't read & write same grid, hence velTmp copy
+
+
+ struct knExtrapolateIntoBnd : public KernelBase {
+ knExtrapolateIntoBnd(FlagGrid& flags, MACGrid& vel, const MACGrid& velTmp) : KernelBase(&flags,0) ,flags(flags),vel(vel),velTmp(velTmp) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, const MACGrid& velTmp ) const {
+ int c=0;
+ Vec3 v(0,0,0);
+ const bool isObs = flags.isObstacle(i,j,k);
+ if( i==0 ) {
+ v = velTmp(i+1,j,k);
+ if(isObs && v[0] < 0.) v[0] = 0.;
+ c++;
+ }
+ else if( i==(flags.getSizeX()-1) ) {
+ v = velTmp(i-1,j,k);
+ if(isObs && v[0] > 0.) v[0] = 0.;
+ c++;
+ }
+ if( j==0 ) {
+ v = velTmp(i,j+1,k);
+ if(isObs && v[1] < 0.) v[1] = 0.;
+ c++;
+ }
+ else if( j==(flags.getSizeY()-1) ) {
+ v = velTmp(i,j-1,k);
+ if(isObs && v[1] > 0.) v[1] = 0.;
+ c++;
+ }
+ if(flags.is3D()) {
+ if( k==0 ) {
+ v = velTmp(i,j,k+1);
+ if(isObs && v[2] < 0.) v[2] = 0.;
+ c++;
+ }
+ else if( k==(flags.getSizeZ()-1) ) {
+ v = velTmp(i,j,k-1);
+ if(isObs && v[2] > 0.) v[2] = 0.;
+ c++;
+ } }
+ if(c>0) {
+ vel(i,j,k) = v/(Real)c;
+ }
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const MACGrid& getArg2() {
+ return velTmp; }
+ typedef MACGrid type2; void runMessage() { debMsg("Executing kernel knExtrapolateIntoBnd ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,vel,velTmp); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,vel,velTmp); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ FlagGrid& flags; MACGrid& vel; const MACGrid& velTmp; }
+;
+
+// todo - use getGradient instead?
+inline Vec3 getNormal(const Grid<Real>& data, int i, int j, int k) {
+ if (i > data.getSizeX()-2) i= data.getSizeX()-2;
+ if (i < 1) i = 1;
+ if (j > data.getSizeY()-2) j= data.getSizeY()-2;
+ if (j < 1) j = 1;
+
+ int kd = 1;
+ if(data.is3D()) {
+ if (k > data.getSizeZ()-2) k= data.getSizeZ()-2;
+ if (k < 1) k = 1;
+ } else { kd=0; }
+
+ return Vec3( data(i+1,j ,k ) - data(i-1,j ,k ) ,
+ data(i ,j+1,k ) - data(i ,j-1,k ) ,
+ data(i ,j ,k+kd) - data(i ,j ,k-kd) );
+}
+
+
+ struct knUnprojectNormalComp : public KernelBase {
+ knUnprojectNormalComp(FlagGrid& flags, MACGrid& vel, Grid<Real>& phi, Real maxDist) : KernelBase(&flags,1) ,flags(flags),vel(vel),phi(phi),maxDist(maxDist) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, Grid<Real>& phi, Real maxDist ) const {
+ // apply inside, within range near obstacle surface
+ if(phi(i,j,k)>0. || phi(i,j,k)<-maxDist) return;
+
+ Vec3 n = getNormal(phi, i,j,k);
+ Vec3 v = vel(i,j,k);
+ if(dot(n,v) < 0.) {
+ normalize(n);
+ Real l = dot(n,v);
+ vel(i,j,k) -= n*l;
+ }
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline Grid<Real>& getArg2() {
+ return phi; }
+ typedef Grid<Real> type2;inline Real& getArg3() {
+ return maxDist; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel knUnprojectNormalComp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,phi,maxDist); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,phi,maxDist); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ FlagGrid& flags; MACGrid& vel; Grid<Real>& phi; Real maxDist; }
+;
+// a simple extrapolation step , used for cases where there's no levelset
+// (note, less accurate than fast marching extrapolation.)
+// into obstacle is a special mode for second order obstable boundaries (extrapolating
+// only fluid velocities, not those at obstacles)
+
+
+void extrapolateMACSimple(FlagGrid& flags, MACGrid& vel, int distance = 4, LevelsetGrid* phiObs=NULL , bool intoObs = false ) {
+ Grid<int> tmp( flags.getParent() );
+ int dim = (flags.is3D() ? 3:2);
+
+ for(int c=0; c<dim; ++c) {
+ Vec3i dir = 0;
+ dir[c] = 1;
+ tmp.clear();
+
+ // remove all fluid cells (not touching obstacles)
+ FOR_IJK_BND(flags,1) {
+ Vec3i p(i,j,k);
+ bool mark = false;
+ if(!intoObs) {
+ if( flags.isFluid(p) || flags.isFluid(p-dir) ) mark = true;
+ } else {
+ if( (flags.isFluid(p) || flags.isFluid(p-dir) ) &&
+ (!flags.isObstacle(p)) && (!flags.isObstacle(p-dir)) ) mark = true;
+ }
+
+ if(mark) tmp(p) = 1;
+ }
+
+ // extrapolate for distance
+ for(int d=1; d<1+distance; ++d) {
+ knExtrapolateMACSimple(vel, distance, tmp, d, c);
+ } // d
+ }
+
+ if(phiObs) {
+ knUnprojectNormalComp( flags, vel, *phiObs, distance );
+ }
+
+ // copy tangential values into sides of domain
+ MACGrid velTmp( flags.getParent() ); velTmp.copyFrom(vel);
+ knExtrapolateIntoBnd(flags, vel, velTmp);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "extrapolateMACSimple" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); int distance = _args.getOpt<int >("distance",2,4,&_lock); LevelsetGrid* phiObs = _args.getPtrOpt<LevelsetGrid >("phiObs",3,NULL ,&_lock); bool intoObs = _args.getOpt<bool >("intoObs",4,false ,&_lock); _retval = getPyNone(); extrapolateMACSimple(flags,vel,distance,phiObs,intoObs); _args.check(); }
+ pbFinalizePlugin(parent,"extrapolateMACSimple", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("extrapolateMACSimple",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_extrapolateMACSimple ("","extrapolateMACSimple",_W_0);
+extern "C" {
+ void PbRegister_extrapolateMACSimple() {
+ KEEP_UNUSED(_RP_extrapolateMACSimple); }
+ }
+
+
+
+
+
+ struct knExtrapolateMACFromWeight : public KernelBase {
+ knExtrapolateMACFromWeight( MACGrid& vel, Grid<Vec3>& weight, int distance , const int d, const int c ) : KernelBase(&vel,1) ,vel(vel),weight(weight),distance(distance),d(d),c(c) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& vel, Grid<Vec3>& weight, int distance , const int d, const int c ) const {
+ static const Vec3i nb[6] = {
+ Vec3i(1 ,0,0), Vec3i(-1,0,0),
+ Vec3i(0,1 ,0), Vec3i(0,-1,0),
+ Vec3i(0,0,1 ), Vec3i(0,0,-1) };
+ const int dim = (vel.is3D() ? 3:2);
+
+ if (weight(i,j,k)[c] != 0) return;
+
+ // copy from initialized neighbors
+ Vec3i p(i,j,k);
+ int nbs = 0;
+ Real avgVel = 0.;
+ for (int n=0; n<2*dim; ++n) {
+ if (weight(p+nb[n])[c] == d) {
+ avgVel += vel(p+nb[n])[c];
+ nbs++;
+ }
+ }
+
+ if(nbs>0) {
+ weight(p)[c] = d+1;
+ vel(p)[c] = avgVel / nbs;
+ }
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline Grid<Vec3>& getArg1() {
+ return weight; }
+ typedef Grid<Vec3> type1;inline int& getArg2() {
+ return distance; }
+ typedef int type2;inline const int& getArg3() {
+ return d; }
+ typedef int type3;inline const int& getArg4() {
+ return c; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel knExtrapolateMACFromWeight ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,weight,distance,d,c); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,weight,distance,d,c); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ MACGrid& vel; Grid<Vec3>& weight; int distance; const int d; const int c; }
+;
+
+// same as extrapolateMACSimple, but uses weight vec3 grid instead of flags to check
+// for valid values (to be used in combination with mapPartsToMAC)
+// note - the weight grid values are destroyed! the function is necessary due to discrepancies
+// between velocity mapping on surface-levelset / fluid-flag creation. With this
+// extrapolation we make sure the fluid region is covered by initial velocities
+
+void extrapolateMACFromWeight( MACGrid& vel, Grid<Vec3>& weight, int distance = 2) {
+ const int dim = (vel.is3D() ? 3:2);
+
+ for(int c=0; c<dim; ++c) {
+ Vec3i dir = 0;
+ dir[c] = 1;
+
+ // reset weight values to 0 (uninitialized), and 1 (initialized inner values)
+ FOR_IJK_BND(vel,1) {
+ Vec3i p(i,j,k);
+ if(weight(p)[c]>0.) weight(p)[c] = 1.0;
+ }
+
+ // extrapolate for distance
+ for(int d=1; d<1+distance; ++d) {
+ knExtrapolateMACFromWeight(vel, weight, distance, d, c);
+ } // d
+
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "extrapolateMACFromWeight" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Vec3>& weight = *_args.getPtr<Grid<Vec3> >("weight",1,&_lock); int distance = _args.getOpt<int >("distance",2,2,&_lock); _retval = getPyNone(); extrapolateMACFromWeight(vel,weight,distance); _args.check(); }
+ pbFinalizePlugin(parent,"extrapolateMACFromWeight", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("extrapolateMACFromWeight",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_extrapolateMACFromWeight ("","extrapolateMACFromWeight",_W_1);
+extern "C" {
+ void PbRegister_extrapolateMACFromWeight() {
+ KEEP_UNUSED(_RP_extrapolateMACFromWeight); }
+ }
+
+
+
+// simple extrapolation functions for levelsets
+
+static const Vec3i nb[6] = {
+ Vec3i(1 ,0,0), Vec3i(-1,0,0),
+ Vec3i(0,1 ,0), Vec3i(0,-1,0),
+ Vec3i(0,0,1 ), Vec3i(0,0,-1) };
+
+
+
+template <class S> struct knExtrapolateLsSimple : public KernelBase {
+ knExtrapolateLsSimple(Grid<S>& val, int distance , Grid<int>& tmp , const int d , S direction ) : KernelBase(&val,1) ,val(val),distance(distance),tmp(tmp),d(d),direction(direction) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<S>& val, int distance , Grid<int>& tmp , const int d , S direction ) const {
+ const int dim = (val.is3D() ? 3:2);
+ if (tmp(i,j,k) != 0) return;
+
+ // copy from initialized neighbors
+ Vec3i p(i,j,k);
+ int nbs = 0;
+ S avg(0.);
+ for (int n=0; n<2*dim; ++n) {
+ if (tmp(p+nb[n]) == d) {
+ avg += val(p+nb[n]);
+ nbs++;
+ }
+ }
+
+ if(nbs>0) {
+ tmp(p) = d+1;
+ val(p) = avg / nbs + direction;
+ }
+} inline Grid<S>& getArg0() {
+ return val; }
+ typedef Grid<S> type0;inline int& getArg1() {
+ return distance; }
+ typedef int type1;inline Grid<int>& getArg2() {
+ return tmp; }
+ typedef Grid<int> type2;inline const int& getArg3() {
+ return d; }
+ typedef int type3;inline S& getArg4() {
+ return direction; }
+ typedef S type4; void runMessage() { debMsg("Executing kernel knExtrapolateLsSimple ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,val,distance,tmp,d,direction); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,val,distance,tmp,d,direction); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<S>& val; int distance; Grid<int>& tmp; const int d; S direction; }
+;
+
+
+
+
+template <class S> struct knSetRemaining : public KernelBase {
+ knSetRemaining(Grid<S>& phi, Grid<int>& tmp, S distance ) : KernelBase(&phi,1) ,phi(phi),tmp(tmp),distance(distance) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<S>& phi, Grid<int>& tmp, S distance ) const {
+ if (tmp(i,j,k) != 0) return;
+ phi(i,j,k) = distance;
+} inline Grid<S>& getArg0() {
+ return phi; }
+ typedef Grid<S> type0;inline Grid<int>& getArg1() {
+ return tmp; }
+ typedef Grid<int> type1;inline S& getArg2() {
+ return distance; }
+ typedef S type2; void runMessage() { debMsg("Executing kernel knSetRemaining ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,phi,tmp,distance); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,phi,tmp,distance); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<S>& phi; Grid<int>& tmp; S distance; }
+;
+
+
+void extrapolateLsSimple(Grid<Real>& phi, int distance = 4, bool inside=false ) {
+ Grid<int> tmp( phi.getParent() );
+ tmp.clear();
+ const int dim = (phi.is3D() ? 3:2);
+
+ // by default, march outside
+ Real direction = 1.;
+ if(!inside) {
+ // mark all inside
+ FOR_IJK_BND(phi,1) {
+ if ( phi(i,j,k) < 0. ) { tmp(i,j,k) = 1; }
+ }
+ } else {
+ direction = -1.;
+ FOR_IJK_BND(phi,1) {
+ if ( phi(i,j,k) > 0. ) { tmp(i,j,k) = 1; }
+ }
+ }
+ // + first layer around
+ FOR_IJK_BND(phi,1) {
+ Vec3i p(i,j,k);
+ if ( tmp(p) ) continue;
+ for (int n=0; n<2*dim; ++n) {
+ if (tmp(p+nb[n])==1) {
+ tmp(i,j,k) = 2; n=2*dim;
+ }
+ }
+ }
+
+ // extrapolate for distance
+ for(int d=2; d<1+distance; ++d) {
+ knExtrapolateLsSimple<Real>(phi, distance, tmp, d, direction );
+ }
+
+ // set all remaining cells to max
+ knSetRemaining<Real>(phi, tmp, Real(direction * (distance+2)) );
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "extrapolateLsSimple" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& phi = *_args.getPtr<Grid<Real> >("phi",0,&_lock); int distance = _args.getOpt<int >("distance",1,4,&_lock); bool inside = _args.getOpt<bool >("inside",2,false ,&_lock); _retval = getPyNone(); extrapolateLsSimple(phi,distance,inside); _args.check(); }
+ pbFinalizePlugin(parent,"extrapolateLsSimple", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("extrapolateLsSimple",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_extrapolateLsSimple ("","extrapolateLsSimple",_W_2);
+extern "C" {
+ void PbRegister_extrapolateLsSimple() {
+ KEEP_UNUSED(_RP_extrapolateLsSimple); }
+ }
+
+
+
+// extrapolate centered vec3 values from marked fluid cells
+
+void extrapolateVec3Simple(Grid<Vec3>& vel, Grid<Real>& phi, int distance = 4, bool inside=false) {
+ Grid<int> tmp( vel.getParent() );
+ tmp.clear();
+ const int dim = (vel.is3D() ? 3:2);
+
+ // mark initial cells, by default, march outside
+ if(!inside) {
+ // mark all inside
+ FOR_IJK_BND(phi,1) {
+ if ( phi(i,j,k) < 0. ) { tmp(i,j,k) = 1; }
+ }
+ } else {
+ FOR_IJK_BND(phi,1) {
+ if ( phi(i,j,k) > 0. ) { tmp(i,j,k) = 1; }
+ }
+ }
+ // + first layer next to initial cells
+ FOR_IJK_BND(vel,1) {
+ Vec3i p(i,j,k);
+ if ( tmp(p) ) continue;
+ for (int n=0; n<2*dim; ++n) {
+ if (tmp(p+nb[n])==1) {
+ tmp(i,j,k) = 2; n=2*dim;
+ }
+ }
+ }
+
+ for(int d=2; d<1+distance; ++d) {
+ knExtrapolateLsSimple<Vec3>(vel, distance, tmp, d, Vec3(0.) );
+ }
+ knSetRemaining<Vec3>(vel, tmp, Vec3(0.) );
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "extrapolateVec3Simple" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& vel = *_args.getPtr<Grid<Vec3> >("vel",0,&_lock); Grid<Real>& phi = *_args.getPtr<Grid<Real> >("phi",1,&_lock); int distance = _args.getOpt<int >("distance",2,4,&_lock); bool inside = _args.getOpt<bool >("inside",3,false,&_lock); _retval = getPyNone(); extrapolateVec3Simple(vel,phi,distance,inside); _args.check(); }
+ pbFinalizePlugin(parent,"extrapolateVec3Simple", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("extrapolateVec3Simple",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_extrapolateVec3Simple ("","extrapolateVec3Simple",_W_3);
+extern "C" {
+ void PbRegister_extrapolateVec3Simple() {
+ KEEP_UNUSED(_RP_extrapolateVec3Simple); }
+ }
+
+
+
+
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h
new file mode 100644
index 00000000000..b82a8947f31
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h
@@ -0,0 +1,195 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Fast marching
+ *
+ ******************************************************************************/
+
+#ifndef _FASTMARCH_H
+#define _FASTMARCH_H
+
+#include <queue>
+#include "levelset.h"
+
+namespace Manta {
+
+//! Fast marching. Transport certain values
+// This class exists in two versions: for scalar, and for vector values - the only difference are
+// flag checks i transpTouch (for simplicity in separate classes)
+
+template<class GRID, class T>
+inline T fmInterpolateNeighbors(GRID* mpVal, int x,int y,int z, Real *weights) {
+ T val(0.);
+ if(weights[0]>0.0) val += mpVal->get(x+1, y+0, z+0) * weights[0];
+ if(weights[1]>0.0) val += mpVal->get(x-1, y+0, z+0) * weights[1];
+ if(weights[2]>0.0) val += mpVal->get(x+0, y+1, z+0) * weights[2];
+ if(weights[3]>0.0) val += mpVal->get(x+0, y-1, z+0) * weights[3];
+ if(mpVal->is3D()) {
+ if(weights[4]>0.0) val += mpVal->get(x+0, y+0, z+1) * weights[4];
+ if(weights[5]>0.0) val += mpVal->get(x+0, y+0, z-1) * weights[5];
+ }
+ return val;
+}
+
+template<class GRID, class T>
+class FmValueTransportScalar {
+public:
+ FmValueTransportScalar() : mpVal(0),mpFlags(0) { };
+ ~FmValueTransportScalar() { };
+ void initMarching(GRID* val, FlagGrid* flags) {
+ mpVal = val;
+ mpFlags = flags;
+ }
+ inline bool isInitialized() { return mpVal != 0; }
+
+ //! cell is touched by marching from source cell
+ inline void transpTouch(int x,int y,int z, Real *weights, Real time) {
+ if(!mpVal || !mpFlags->isEmpty(x,y,z)) return;
+ T val = fmInterpolateNeighbors<GRID,T>(mpVal,x,y,z,weights);
+ (*mpVal)(x,y,z) = val;
+ };
+protected:
+ GRID* mpVal;
+ FlagGrid* mpFlags;
+};
+
+template<class GRID, class T>
+class FmValueTransportVec3 {
+public:
+ FmValueTransportVec3() : mpVal(0), mpFlags(0) { };
+ ~FmValueTransportVec3() { };
+ inline bool isInitialized() { return mpVal != 0; }
+ void initMarching(GRID* val, const FlagGrid* flags) {
+ mpVal = val;
+ mpFlags = flags;
+ }
+
+ //! cell is touched by marching from source cell
+ inline void transpTouch(int x,int y,int z, Real *weights, Real time) {
+ if(!mpVal || !mpFlags->isEmpty(x,y,z)) return;
+
+ T val = fmInterpolateNeighbors<GRID,T>(mpVal,x,y,z,weights);
+
+ // set velocity components if adjacent is empty
+ if (mpFlags->isEmpty(x-1,y,z)) (*mpVal)(x,y,z).x = val.x;
+ if (mpFlags->isEmpty(x,y-1,z)) (*mpVal)(x,y,z).y = val.y;
+ if(mpVal->is3D()) { if (mpFlags->isEmpty(x,y,z-1)) (*mpVal)(x,y,z).z = val.z; }
+ };
+
+protected:
+ GRID* mpVal;
+ const FlagGrid* mpFlags;
+};
+
+class FmHeapEntryOut {
+public:
+ Vec3i p;
+ // quick time access for sorting
+ Real time;
+ static inline bool compare(const Real x, const Real y) {
+ return x > y;
+ }
+
+ inline bool operator< (const FmHeapEntryOut& o) const {
+ const Real d = fabs((time) - ((o.time)));
+ if (d > 0.) return (time) > ((o.time));
+ if (p.z != o.p.z) return p.z > o.p.z;
+ if (p.y != o.p.y) return p.y > o.p.y;
+ return p.x > o.p.x;
+ };
+
+};
+
+class FmHeapEntryIn {
+public:
+ Vec3i p;
+ // quick time access for sorting
+ Real time;
+ static inline bool compare(const Real x, const Real y) {
+ return x < y;
+ }
+
+ inline bool operator< (const FmHeapEntryIn& o) const {
+ const Real d = fabs((time) - ((o.time)));
+ if (d > 0.) return (time) < ((o.time));
+ if (p.z != o.p.z) return p.z < o.p.z;
+ if (p.y != o.p.y) return p.y < o.p.y;
+ return p.x < o.p.x;
+ };
+};
+
+
+//! fast marching algorithm wrapper class
+template<class T, int TDIR>
+class FastMarch {
+
+public:
+ // MSVC doesn't allow static const variables in template classes
+ static inline Real InvalidTime() { return -1000; }
+ static inline Real InvtOffset() { return 500; }
+
+ enum SpecialValues { FlagInited = 1, FlagIsOnHeap = 2};
+
+ FastMarch(const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& levelset, Real maxTime, MACGrid* velTransport = NULL);
+ ~FastMarch() {}
+
+ //! advect level set function with given velocity */
+ void performMarching();
+
+ //! test value for invalidity
+ inline bool isInvalid(Real v) const { return (v <= InvalidTime()); }
+
+ void addToList(const Vec3i& p, const Vec3i& src);
+
+ //! convert phi to time value
+ inline Real phi2time(Real phival) { return (phival-InvalidTime()+ InvtOffset()) * -1.0; }
+
+ //! ... and back
+ inline Real time2phi(Real tval) { return (InvalidTime() - InvtOffset() - tval); }
+
+ inline Real _phi(int i, int j, int k) { return mLevelset(i,j,k); }
+protected:
+ Grid<Real>& mLevelset;
+ const FlagGrid& mFlags;
+ Grid<int>& mFmFlags;
+
+ //! velocity extrpolation
+ FmValueTransportVec3<MACGrid , Vec3> mVelTransport;
+
+ //! maximal time to march for
+ Real mMaxTime;
+
+ //! fast marching list
+ std::priority_queue<T, std::vector<T>, std::less<T> > mHeap;
+ Real mReheapVal;
+
+ //! weights for touching points
+ Real mWeights[6];
+
+ template<int C> inline Real calcWeights(int& okCnt, int& invcnt, Real* v, const Vec3i& idx);
+
+ inline Real calculateDistance(const Vec3i& pos);
+};
+
+} // namespace
+#endif
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h.reg
new file mode 100644
index 00000000000..7b9296f3580
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h.reg
@@ -0,0 +1 @@
+#include "fastmarch.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h.reg.cpp
new file mode 100644
index 00000000000..919d0fe6c82
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fastmarch.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "fastmarch.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_5()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/iogrids.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/iogrids.cpp
new file mode 100644
index 00000000000..8bdf6a13158
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/iogrids.cpp
@@ -0,0 +1,1229 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <cstring>
+
+#if NO_ZLIB!=1
+extern "C" {
+#include <zlib.h>
+}
+#endif
+
+#if OPENVDB==1
+#include "openvdb/openvdb.h"
+#endif
+
+#include "cnpy.h"
+#include "mantaio.h"
+#include "grid.h"
+#include "vector4d.h"
+#include "grid4d.h"
+
+using namespace std;
+
+namespace Manta {
+
+static const int STR_LEN_GRID = 252;
+
+//! uni file header, v4
+typedef struct {
+ int dimX, dimY, dimZ; // grid size
+ int gridType, elementType, bytesPerElement; // data type info
+ char info[STR_LEN_GRID]; // mantaflow build information
+ int dimT; // optionally store forth dimension for 4d grids
+ unsigned long long timestamp; // creation time
+} UniHeader;
+
+// note: header v4 only uses 4 bytes of the info string to store the fourth dimension, not needed for pdata
+
+
+//*****************************************************************************
+// conversion functions for double precision
+// (note - uni files always store single prec. values)
+//*****************************************************************************
+
+#if NO_ZLIB!=1
+template <class GRIDT>
+void gridConvertWrite(gzFile& gzf, GRIDT& grid, void* ptr, UniHeader& head) {
+ errMsg("gridConvertWrite: unknown type, not yet supported");
+}
+
+template <>
+void gridConvertWrite(gzFile& gzf, Grid<int>& grid, void* ptr, UniHeader& head) {
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, &grid[0], sizeof(int)*head.dimX*head.dimY*head.dimZ);
+}
+template <>
+void gridConvertWrite(gzFile& gzf, Grid<double>& grid, void* ptr, UniHeader& head) {
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i,++ptrf) {
+ *ptrf = (float)grid[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float)* head.dimX*head.dimY*head.dimZ);
+}
+template <>
+void gridConvertWrite(gzFile& gzf, Grid<Vector3D<double> >& grid, void* ptr, UniHeader& head) {
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i) {
+ for(int c=0; c<3; ++c) { *ptrf = (float)grid[i][c]; ptrf++; }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) *head.dimX*head.dimY*head.dimZ);
+}
+
+template <>
+void gridConvertWrite(gzFile& gzf, Grid4d<int>& grid, void* ptr, UniHeader& head) {
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, &grid[0], sizeof(int)*head.dimX*head.dimY*head.dimZ*head.dimT);
+}
+template <>
+void gridConvertWrite(gzFile& gzf, Grid4d<double>& grid, void* ptr, UniHeader& head) {
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float* ptrf = (float*)ptr;
+ IndexInt s = grid.getStrideT()*grid.getSizeT();
+ for(IndexInt i=0; i<s; ++i,++ptrf) {
+ *ptrf = (float)grid[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float)* s );
+}
+template <>
+void gridConvertWrite(gzFile& gzf, Grid4d<Vector3D<double> >& grid, void* ptr, UniHeader& head) {
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float* ptrf = (float*)ptr;
+ IndexInt s = grid.getStrideT()*grid.getSizeT();
+ for(IndexInt i=0; i<s; ++i) {
+ for(int c=0; c<3; ++c) { *ptrf = (float)grid[i][c]; ptrf++; }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) *s);
+}
+template <>
+void gridConvertWrite(gzFile& gzf, Grid4d<Vector4D<double> >& grid, void* ptr, UniHeader& head) {
+ head.bytesPerElement = sizeof(Vector4D<float>);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ float* ptrf = (float*)ptr;
+ IndexInt s = grid.getStrideT()*grid.getSizeT();
+ for(IndexInt i=0; i<s; ++i) {
+ for(int c=0; c<4; ++c) { *ptrf = (float)grid[i][c]; ptrf++; }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector4D<float>) *s);
+}
+
+template <class T>
+void gridReadConvert(gzFile& gzf, Grid<T>& grid, void* ptr, int bytesPerElement) {
+ errMsg("gridReadConvert: unknown type, not yet supported");
+}
+
+template <>
+void gridReadConvert<int>(gzFile& gzf, Grid<int>& grid, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(int)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ assertMsg (bytesPerElement == sizeof(int), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(int) );
+ // easy, nothing to do for ints
+ memcpy(&(grid[0]), ptr, sizeof(int) * grid.getSizeX()*grid.getSizeY()*grid.getSizeZ() );
+}
+
+template <>
+void gridReadConvert<double>(gzFile& gzf, Grid<double>& grid, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(float)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ assertMsg (bytesPerElement == sizeof(float), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i,++ptrf) {
+ grid[i] = (double)(*ptrf);
+ }
+}
+
+template <>
+void gridReadConvert<Vec3>(gzFile& gzf, Grid<Vec3>& grid, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(Vector3D<float>)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ assertMsg (bytesPerElement == sizeof(Vector3D<float>), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(Vector3D<float>) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i) {
+ Vec3 v;
+ for(int c=0; c<3; ++c) { v[c] = double(*ptrf); ptrf++; }
+ grid[i] = v;
+ }
+}
+
+template <class T>
+void gridReadConvert4d(gzFile& gzf, Grid4d<T>& grid, void* ptr, int bytesPerElement, int t) {
+ errMsg("gridReadConvert4d: unknown type, not yet supported");
+}
+
+template <>
+void gridReadConvert4d<int>(gzFile& gzf, Grid4d<int>& grid, void* ptr, int bytesPerElement, int t) {
+ gzread(gzf, ptr, sizeof(int)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ() );
+ assertMsg (bytesPerElement == sizeof(int), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(int) );
+ // nothing to do for ints
+ memcpy(&(grid[grid.getSizeX()*grid.getSizeY()*grid.getSizeZ() *t]), ptr, sizeof(int) * grid.getSizeX()*grid.getSizeY()*grid.getSizeZ() );
+}
+
+template <>
+void gridReadConvert4d<double>(gzFile& gzf, Grid4d<double>& grid, void* ptr, int bytesPerElement, int t) {
+ assertMsg (bytesPerElement == sizeof(float), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+
+ float* ptrf = (float*)ptr;
+ gzread(gzf, ptr, sizeof(float)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ for(IndexInt i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i , ++ptrf ) {
+ grid[ grid.getSizeX()*grid.getSizeY()*grid.getSizeZ()*t + i] = (double)(*ptrf);
+ }
+}
+
+template <>
+void gridReadConvert4d<Vec3>(gzFile& gzf, Grid4d<Vec3>& grid, void* ptr, int bytesPerElement, int t) {
+ assertMsg (bytesPerElement == sizeof(Vector3D<float>), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+
+ gzread(gzf, ptr, sizeof(Vector3D<float>)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ float* ptrf = (float*)ptr;
+ for(IndexInt i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i) {
+ Vec3 v;
+ for(int c=0; c<3; ++c) { v[c] = double(*ptrf); ptrf++; }
+ grid[grid.getSizeX()*grid.getSizeY()*grid.getSizeZ()*t + i] = v;
+ }
+}
+
+template <>
+void gridReadConvert4d<Vec4>(gzFile& gzf, Grid4d<Vec4>& grid, void* ptr, int bytesPerElement, int t) {
+ assertMsg (bytesPerElement == sizeof(Vector4D<float>), "grid element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+
+ gzread(gzf, ptr, sizeof(Vector4D<float>)*grid.getSizeX()*grid.getSizeY()*grid.getSizeZ());
+ float* ptrf = (float*)ptr;
+ for(IndexInt i=0; i<grid.getSizeX()*grid.getSizeY()*grid.getSizeZ(); ++i) {
+ Vec4 v;
+ for(int c=0; c<4; ++c) { v[c] = double(*ptrf); ptrf++; }
+ grid[grid.getSizeX()*grid.getSizeY()*grid.getSizeZ()*t + i] = v;
+ }
+}
+
+
+
+// make sure compatible grid types dont lead to errors...
+static int unifyGridType(int type) {
+ // real <> levelset
+ if(type & GridBase::TypeReal) type |= GridBase::TypeLevelset;
+ if(type & GridBase::TypeLevelset) type |= GridBase::TypeReal;
+ // vec3 <> mac
+ if(type & GridBase::TypeVec3) type |= GridBase::TypeMAC;
+ if(type & GridBase::TypeMAC) type |= GridBase::TypeVec3;
+ return type;
+}
+
+#endif // NO_ZLIB!=1
+
+//*****************************************************************************
+// grid data
+//*****************************************************************************
+
+template<class T>
+void writeGridTxt(const string& name, Grid<T>* grid) {
+ debMsg( "writing grid " << grid->getName() << " to text file " << name ,1);
+
+ ofstream ofs(name.c_str());
+ if (!ofs.good())
+ errMsg("writeGridTxt: can't open file " << name);
+ FOR_IJK(*grid) {
+ ofs << Vec3i(i,j,k) <<" = "<< (*grid)(i,j,k) <<"\n";
+ }
+ ofs.close();
+}
+
+template<class T>
+void writeGridRaw(const string& name, Grid<T>* grid) {
+ debMsg( "writing grid " << grid->getName() << " to raw file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("writeGridRaw: can't open file " << name);
+ gzwrite(gzf, &((*grid)[0]), sizeof(T)*grid->getSizeX()*grid->getSizeY()*grid->getSizeZ());
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+template<class T>
+void readGridRaw(const string& name, Grid<T>* grid) {
+ debMsg( "reading grid " << grid->getName() << " from raw file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("readGridRaw: can't open file " << name);
+
+ IndexInt bytes = sizeof(T)*grid->getSizeX()*grid->getSizeY()*grid->getSizeZ();
+ IndexInt readBytes = gzread(gzf, &((*grid)[0]), bytes);
+ assertMsg(bytes==readBytes, "can't read raw file, stream length does not match, "<<bytes<<" vs "<<readBytes);
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+//! legacy headers for reading old files
+typedef struct {
+ int dimX, dimY, dimZ;
+ int frames, elements, elementType, bytesPerElement, bytesPerFrame;
+} UniLegacyHeader;
+
+typedef struct {
+ int dimX, dimY, dimZ;
+ int gridType, elementType, bytesPerElement;
+} UniLegacyHeader2;
+
+typedef struct {
+ int dimX, dimY, dimZ;
+ int gridType, elementType, bytesPerElement;
+ char info[256];
+ unsigned long long timestamp;
+} UniLegacyHeader3;
+
+//! for auto-init & check of results of test runs , optionally returns info string of header
+void getUniFileSize(const string& name, int& x, int& y, int& z, int* t, std::string* info) {
+ x = y = z = 0;
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (gzf) {
+ char ID[5]={0,0,0,0,0};
+ gzread(gzf, ID, 4);
+
+ // v3
+ if ( (!strcmp(ID, "MNT2")) || (!strcmp(ID, "M4T2")) ) {
+ UniLegacyHeader3 head;
+ assertMsg (gzread(gzf, &head, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3), "can't read file, no header present");
+ x = head.dimX;
+ y = head.dimY;
+ z = head.dimZ;
+
+ // optionally , read fourth dim
+ if ((!strcmp(ID, "M4T2")) && t) {
+ int dimT = 0;
+ gzread(gzf, &dimT, sizeof(int) );
+ (*t) = dimT;
+ }
+ }
+
+ // v4
+ if ( (!strcmp(ID, "MNT3")) || (!strcmp(ID, "M4T3")) ) {
+ UniHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader), "can't read file, no header present");
+ x = head.dimX;
+ y = head.dimY;
+ z = head.dimZ;
+ if(t) (*t) = head.dimT;
+ }
+
+ gzclose(gzf);
+ }
+# endif
+ if(info) {
+ std::ostringstream out;
+ out << x <<","<< y <<","<< z ;
+ if(t && (*t)>0 ) out << ","<< (*t);
+ *info = out.str();
+ }
+}
+Vec3 getUniFileSize(const string& name) {
+ int x,y,z;
+ getUniFileSize(name, x,y,z);
+ return Vec3( Real(x), Real(y), Real(z) );
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getUniFileSize" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const string& name = _args.get<string >("name",0,&_lock); _retval = toPy(getUniFileSize(name)); _args.check(); }
+ pbFinalizePlugin(parent,"getUniFileSize", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getUniFileSize",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getUniFileSize ("","getUniFileSize",_W_0);
+extern "C" {
+ void PbRegister_getUniFileSize() {
+ KEEP_UNUSED(_RP_getUniFileSize); }
+ }
+
+
+
+//! for test run debugging
+void printUniFileInfoString(const string& name) {
+ std::string info("<file not found>");
+ int x=-1,y=-1,z=-1,t=-1;
+ // use getUniFileSize to parse the different headers
+ getUniFileSize(name, x,y,z,&t, &info);
+ debMsg("File '"<<name<<"' info: "<< info ,1);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "printUniFileInfoString" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const string& name = _args.get<string >("name",0,&_lock); _retval = getPyNone(); printUniFileInfoString(name); _args.check(); }
+ pbFinalizePlugin(parent,"printUniFileInfoString", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("printUniFileInfoString",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_printUniFileInfoString ("","printUniFileInfoString",_W_1);
+extern "C" {
+ void PbRegister_printUniFileInfoString() {
+ KEEP_UNUSED(_RP_printUniFileInfoString); }
+ }
+
+
+
+
+// actual read/write functions
+
+template <class T>
+void writeGridUni(const string& name, Grid<T>* grid) {
+ debMsg( "Writing grid " << grid->getName() << " to uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ char ID[5] = "MNT3";
+ UniHeader head;
+ head.dimX = grid->getSizeX();
+ head.dimY = grid->getSizeY();
+ head.dimZ = grid->getSizeZ();
+ head.dimT = 0;
+ head.gridType = grid->getType();
+ head.bytesPerElement = sizeof(T);
+ snprintf( head.info, STR_LEN_GRID, "%s", buildInfoString().c_str() );
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ if (grid->getType() & GridBase::TypeInt)
+ head.elementType = 0;
+ else if (grid->getType() & GridBase::TypeReal)
+ head.elementType = 1;
+ else if (grid->getType() & GridBase::TypeVec3)
+ head.elementType = 2;
+ else
+ errMsg("writeGridUni: unknown element type");
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("writeGridUni: can't open file " << name);
+
+ gzwrite(gzf, ID, 4);
+# if FLOATINGPOINT_PRECISION!=1
+ // always write float values, even if compiled with double precision...
+ Grid<T> temp(grid->getParent());
+ // "misuse" temp grid as storage for floating point values (we have double, so it will always fit)
+ gridConvertWrite( gzf, *grid, &(temp[0]), head);
+# else
+ void* ptr = &((*grid)[0]);
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, ptr, sizeof(T)*head.dimX*head.dimY*head.dimZ);
+# endif
+ gzclose(gzf);
+
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+
+template <class T>
+void readGridUni(const string& name, Grid<T>* grid) {
+ debMsg( "Reading grid " << grid->getName() << " from uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("readGridUni: can't open file " << name);
+
+ char ID[5]={0,0,0,0,0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "DDF2")) {
+ // legacy file format
+ UniLegacyHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniLegacyHeader)) == sizeof(UniLegacyHeader), "can't read file, no header present");
+ assertMsg (head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() && head.dimZ == grid->getSizeZ(), "grid dim doesn't match");
+ assertMsg (head.bytesPerElement * head.elements == sizeof(T), "grid type doesn't match");
+ // skip flags
+ int numEl = head.dimX*head.dimY*head.dimZ;
+ gzseek(gzf, numEl, SEEK_CUR);
+ // actual grid read
+ gzread(gzf, &((*grid)[0]), sizeof(T)*numEl);
+ }
+ else if (!strcmp(ID, "MNT1")) {
+ // legacy file format 2
+ UniLegacyHeader2 head;
+ assertMsg (gzread(gzf, &head, sizeof(UniLegacyHeader2)) == sizeof(UniLegacyHeader2), "can't read file, no header present");
+ assertMsg (head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() && head.dimZ == grid->getSizeZ(), "grid dim doesn't match, "<< Vec3(head.dimX,head.dimY,head.dimZ)<<" vs "<< grid->getSize() );
+ assertMsg (head.gridType == grid->getType(), "grid type doesn't match "<< head.gridType<<" vs "<< grid->getType() );
+ assertMsg (head.bytesPerElement == sizeof(T), "grid element size doesn't match "<< head.bytesPerElement <<" vs "<< sizeof(T) );
+ gzread(gzf, &((*grid)[0]), sizeof(T)*head.dimX*head.dimY*head.dimZ);
+ }
+ else if (!strcmp(ID, "MNT2")) {
+ // a bit ugly, almost identical to MNT3
+ UniLegacyHeader3 head;
+ assertMsg (gzread(gzf, &head, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3), "can't read file, no header present");
+ assertMsg (head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() && head.dimZ == grid->getSizeZ(), "grid dim doesn't match, "<< Vec3(head.dimX,head.dimY,head.dimZ)<<" vs "<< grid->getSize() );
+ assertMsg (unifyGridType(head.gridType)==unifyGridType(grid->getType()) , "grid type doesn't match "<< head.gridType<<" vs "<< grid->getType() );
+# if FLOATINGPOINT_PRECISION!=1
+ Grid<T> temp(grid->getParent());
+ void* ptr = &(temp[0]);
+ gridReadConvert<T>(gzf, *grid, ptr, head.bytesPerElement);
+# else
+ assertMsg (head.bytesPerElement == sizeof(T), "grid element size doesn't match "<< head.bytesPerElement <<" vs "<< sizeof(T) );
+ gzread(gzf, &((*grid)[0]), sizeof(T)*head.dimX*head.dimY*head.dimZ);
+# endif
+ }
+ else if (!strcmp(ID, "MNT3")) {
+ // current file format
+ UniHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader), "can't read file, no header present");
+ assertMsg (head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() && head.dimZ == grid->getSizeZ(), "grid dim doesn't match, "<< Vec3(head.dimX,head.dimY,head.dimZ)<<" vs "<< grid->getSize() );
+ assertMsg (unifyGridType(head.gridType)==unifyGridType(grid->getType()) , "grid type doesn't match "<< head.gridType<<" vs "<< grid->getType() );
+# if FLOATINGPOINT_PRECISION!=1
+ // convert float to double
+ Grid<T> temp(grid->getParent());
+ void* ptr = &(temp[0]);
+ gridReadConvert<T>(gzf, *grid, ptr, head.bytesPerElement);
+# else
+ assertMsg (head.bytesPerElement == sizeof(T), "grid element size doesn't match "<< head.bytesPerElement <<" vs "<< sizeof(T) );
+ gzread(gzf, &((*grid)[0]), sizeof(T)*head.dimX*head.dimY*head.dimZ);
+# endif
+ } else {
+ errMsg( "readGridUni: Unknown header '"<<ID<<"' " );
+ }
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+template <class T>
+void writeGridVol(const string& name, Grid<T>* grid) {
+ debMsg( "writing grid " << grid->getName() << " to vol file " << name ,1);
+ errMsg("writeGridVol: Type not yet supported!");
+}
+
+struct volHeader {
+ char ID[3];
+ char version;
+ int encoding;
+ int dimX, dimY, dimZ;
+ int channels;
+ Vec3 bboxMin, bboxMax;
+};
+
+template <>
+void writeGridVol<Real>(const string& name, Grid<Real>* grid) {
+ debMsg( "writing real grid " << grid->getName() << " to vol file " << name ,1);
+
+ volHeader header;
+ header.ID[0] = 'V';
+ header.ID[1] = 'O';
+ header.ID[2] = 'L';
+ header.version = 3;
+ header.encoding = 1; // float32 precision
+ header.dimX = grid->getSizeX();
+ header.dimY = grid->getSizeY();
+ header.dimZ = grid->getSizeZ();
+ header.channels = 1; // only 1 channel
+ header.bboxMin = Vec3(-0.5);
+ header.bboxMax = Vec3( 0.5);
+
+ FILE* fp = fopen( name.c_str(), "wb" );
+ if (fp == NULL) {
+ errMsg("writeGridVol: Cannot open '" << name << "'");
+ return;
+ }
+
+ fwrite( &header, sizeof(volHeader), 1, fp );
+
+# if FLOATINGPOINT_PRECISION==1
+ // for float, write one big chunk
+ fwrite( &(*grid)[0], sizeof(float), grid->getSizeX()*grid->getSizeY()*grid->getSizeZ(), fp );
+# else
+ // explicitly convert each entry to float - we might have double precision in mantaflow
+ FOR_IDX(*grid) {
+ float value = (*grid)[idx];
+ fwrite( &value, sizeof(float), 1, fp );
+ }
+# endif
+
+ fclose(fp);
+};
+
+
+template <class T>
+void readGridVol(const string& name, Grid<T>* grid) {
+ debMsg( "writing grid " << grid->getName() << " to vol file " << name ,1);
+ errMsg("readGridVol: Type not yet supported!");
+}
+
+template <>
+void readGridVol<Real>(const string& name, Grid<Real>* grid) {
+ debMsg( "reading real grid " << grid->getName() << " from vol file " << name ,1);
+
+ volHeader header;
+ FILE* fp = fopen( name.c_str(), "rb" );
+ if (fp == NULL) {
+ errMsg("readGridVol: Cannot open '" << name << "'");
+ return;
+ }
+
+ // note, only very basic file format checks here!
+ assertMsg( fread( &header, 1, sizeof(volHeader) , fp) == sizeof(volHeader), "can't read file, no header present");
+ if( header.dimX != grid->getSizeX() || header.dimY != grid->getSizeY() || header.dimZ != grid->getSizeZ()) errMsg( "grid dim doesn't match, "<< Vec3(header.dimX,header.dimY,header.dimZ)<<" vs "<< grid->getSize() );
+# if FLOATINGPOINT_PRECISION!=1
+ errMsg("readGridVol: Double precision not yet supported");
+# else
+ const unsigned int s = sizeof(float)*header.dimX*header.dimY*header.dimZ;
+ assertMsg( fread( &((*grid)[0]), 1, s, fp) == s, "can't read file, no / not enough data");
+# endif
+
+ fclose(fp);
+};
+
+// 4d grids IO
+
+template <class T>
+void writeGrid4dUni(const string& name, Grid4d<T>* grid) {
+ debMsg( "writing grid4d " << grid->getName() << " to uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ char ID[5] = "M4T3";
+ UniHeader head;
+ head.dimX = grid->getSizeX();
+ head.dimY = grid->getSizeY();
+ head.dimZ = grid->getSizeZ();
+ head.dimT = grid->getSizeT();
+ head.gridType = grid->getType();
+ head.bytesPerElement = sizeof(T);
+ snprintf( head.info, STR_LEN_GRID, "%s", buildInfoString().c_str() );
+ MuTime stamp; stamp.get();
+ head.timestamp = stamp.time;
+
+ if (grid->getType() & Grid4dBase::TypeInt)
+ head.elementType = 0;
+ else if (grid->getType() & Grid4dBase::TypeReal)
+ head.elementType = 1;
+ else if (grid->getType() & Grid4dBase::TypeVec3)
+ head.elementType = 2;
+ else if (grid->getType() & Grid4dBase::TypeVec4)
+ head.elementType = 2;
+ else
+ errMsg("writeGrid4dUni: unknown element type");
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("writeGrid4dUni: can't open file " << name);
+
+ gzwrite(gzf, ID, 4);
+# if FLOATINGPOINT_PRECISION!=1
+ Grid4d<T> temp(grid->getParent());
+ gridConvertWrite< Grid4d<T> >( gzf, *grid, &(temp[0]), head);
+# else
+ gzwrite(gzf, &head, sizeof(UniHeader));
+
+ // can be too large - write in chunks
+ for(int t=0; t<head.dimT; ++t) {
+ void* ptr = &((*grid)[ head.dimX*head.dimY*head.dimZ* t ]);
+ gzwrite(gzf, ptr, sizeof(T)*head.dimX*head.dimY*head.dimZ* 1);
+ }
+# endif
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+//! note, reading 4d uni grids is slightly more complicated than 3d ones
+//! as it optionally supports sliced reading
+template <class T>
+void readGrid4dUni(const string& name, Grid4d<T>* grid, int readTslice, Grid4d<T>* slice, void** fileHandle )
+{
+ if(grid) debMsg( "reading grid " << grid->getName() << " from uni file " << name ,1);
+ if(slice) debMsg( "reading slice " << slice->getName() << ",t="<<readTslice<<" from uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = NULL;
+ char ID[5]={0,0,0,0,0};
+
+ // optionally - reuse file handle, if valid one is passed in fileHandle pointer...
+ if( (!fileHandle) || (fileHandle && (*fileHandle == NULL)) ) {
+ gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("readGrid4dUni: can't open file "<<name);
+
+ gzread(gzf, ID, 4);
+ if( fileHandle) { *fileHandle = gzf; }
+ } else {
+ // optimized read - reduced sanity checks
+ gzf = (gzFile)(*fileHandle);
+ void* ptr = &( (*slice)[ 0 ] );
+ gzread(gzf, ptr, sizeof(T)* slice->getStrideT()* 1); // quick and dirty...
+ return;
+ }
+
+ if( (!strcmp(ID, "M4T2")) || (!strcmp(ID, "M4T3")) ) {
+ int headerSize = -1;
+
+ // current file format
+ UniHeader head;
+ if(!strcmp(ID, "M4T3")) {
+ headerSize = sizeof(UniHeader);
+ assertMsg (gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader), "can't read file, no 4d header present");
+ if(FLOATINGPOINT_PRECISION==1) assertMsg (head.bytesPerElement == sizeof(T), "4d grid element size doesn't match "<< head.bytesPerElement <<" vs "<< sizeof(T) );
+ }
+ // old header
+ if(!strcmp(ID, "M4T2")) {
+ UniLegacyHeader3 lhead;
+ headerSize = sizeof(UniLegacyHeader3) + sizeof(int);
+ assertMsg (gzread(gzf, &lhead, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3), "can't read file, no 4dl header present");
+ if(FLOATINGPOINT_PRECISION==1) assertMsg (lhead.bytesPerElement == sizeof(T), "4d grid element size doesn't match "<< lhead.bytesPerElement <<" vs "<< sizeof(T) );
+
+ int fourthDim = 0;
+ gzread(gzf, &fourthDim, sizeof(fourthDim));
+
+ head.dimX = lhead.dimX;
+ head.dimY = lhead.dimY;
+ head.dimZ = lhead.dimZ;
+ head.dimT = fourthDim;
+ head.gridType = lhead.gridType;
+ }
+
+ if(readTslice<0) {
+ assertMsg (head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() && head.dimZ == grid->getSizeZ(), "grid dim doesn't match, "<< Vec3(head.dimX,head.dimY,head.dimZ)<<" vs "<< grid->getSize() );
+ assertMsg ( unifyGridType(head.gridType)==unifyGridType(grid->getType()) , "grid type doesn't match "<< head.gridType<<" vs "<< grid->getType() );
+
+ // read full 4d grid
+ assertMsg (head.dimT == grid->getSizeT(), "grid dim4 doesn't match, "<< head.dimT <<" vs "<< grid->getSize() );
+
+ // can be too large - read in chunks
+# if FLOATINGPOINT_PRECISION!=1
+ Grid4d<T> temp(grid->getParent());
+ void* ptr = &(temp[0]);
+ for(int t=0; t<head.dimT; ++t) {
+ gridReadConvert4d<T>(gzf, *grid, ptr, head.bytesPerElement, t);
+ }
+# else
+ for(int t=0; t<head.dimT; ++t) {
+ void* ptr = &((*grid)[ head.dimX*head.dimY*head.dimZ* t ] );
+ gzread(gzf, ptr, sizeof(T)* head.dimX*head.dimY*head.dimZ* 1);
+ }
+# endif
+ } else {
+ // read chosen slice only
+ assertMsg (head.dimX == slice->getSizeX() && head.dimY == slice->getSizeY() && head.dimZ == slice->getSizeZ(), "grid dim doesn't match, "<< Vec3(head.dimX,head.dimY,head.dimZ)<<" vs "<< slice->getSize() );
+ assertMsg ( unifyGridType(head.gridType)==unifyGridType(slice->getType()) , "grid type doesn't match "<< head.gridType<<" vs "<< slice->getType() );
+
+# if FLOATINGPOINT_PRECISION!=1
+ errMsg( "readGrid4dUni: NYI (2)" ); // slice read not yet supported for double
+# else
+ assertMsg( slice, "No 3d slice grid data given" );
+ assertMsg (readTslice < head.dimT, "grid dim4 slice too large "<< readTslice <<" vs "<< head.dimT );
+ void* ptr = &( (*slice)[ 0 ] );
+ gzseek(gzf, sizeof(T)*head.dimX*head.dimY*head.dimZ* readTslice + headerSize + 4 , SEEK_SET );
+ gzread(gzf, ptr, sizeof(T)*head.dimX*head.dimY*head.dimZ* 1);
+# endif
+ }
+ } else {
+ debMsg( "Unknown header!" ,1);
+ }
+
+ if( !fileHandle) {
+ gzclose(gzf);
+ }
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+void readGrid4dUniCleanup(void** fileHandle) {
+ gzFile gzf = NULL;
+ if( fileHandle) {
+ gzf = (gzFile)(*fileHandle);
+ gzclose(gzf);
+ *fileHandle = NULL;
+ }
+}
+
+template<class T>
+void writeGrid4dRaw(const string& name, Grid4d<T>* grid) {
+ debMsg( "writing grid4d " << grid->getName() << " to raw file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("writeGrid4dRaw: can't open file " << name);
+ gzwrite(gzf, &((*grid)[0]), sizeof(T)*grid->getSizeX()*grid->getSizeY()*grid->getSizeZ()*grid->getSizeT());
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+template<class T>
+void readGrid4dRaw(const string& name, Grid4d<T>* grid) {
+ debMsg( "reading grid4d " << grid->getName() << " from raw file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("readGrid4dRaw: can't open file " << name);
+
+ IndexInt bytes = sizeof(T)*grid->getSizeX()*grid->getSizeY()*grid->getSizeZ()*grid->getSizeT();
+ IndexInt readBytes = gzread(gzf, &((*grid)[0]), bytes);
+ assertMsg(bytes==readBytes, "can't read raw file, stream length does not match, "<<bytes<<" vs "<<readBytes);
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+
+//*****************************************************************************
+// optional openvdb export
+
+#if OPENVDB==1
+
+template <class T>
+void writeGridVDB(const string& name, Grid<T>* grid) {
+ debMsg("Writing grid " << grid->getName() << " to vdb file " << name << " not yet supported!", 1);
+}
+
+template <class T>
+void readGridVDB(const string& name, Grid<T>* grid) {
+ debMsg("Reading grid " << grid->getName() << " from vdb file " << name << " not yet supported!", 1);
+}
+
+template <>
+void writeGridVDB(const string& name, Grid<Real>* grid) {
+ debMsg("Writing real grid " << grid->getName() << " to vdb file " << name, 1);
+
+ // Create an empty floating-point grid with background value 0.
+ openvdb::initialize();
+ openvdb::FloatGrid::Ptr gridVDB = openvdb::FloatGrid::create();
+ gridVDB->setTransform( openvdb::math::Transform::createLinearTransform( 1./grid->getSizeX() )); //voxel size
+
+ // Get an accessor for coordinate-based access to voxels.
+ openvdb::FloatGrid::Accessor accessor = gridVDB->getAccessor();
+
+ // Identify the grid as a level set.
+ gridVDB->setGridClass(openvdb::GRID_FOG_VOLUME);
+
+ // Name the grid "density".
+ gridVDB->setName( grid->getName() );
+
+ openvdb::io::File file(name);
+
+ FOR_IJK(*grid) {
+ openvdb::Coord xyz(i, j, k);
+ accessor.setValue(xyz, (*grid)(i, j, k));
+ }
+
+ // Add the grid pointer to a container.
+ openvdb::GridPtrVec gridsVDB;
+ gridsVDB.push_back(gridVDB);
+
+ // Write out the contents of the container.
+ file.write(gridsVDB);
+ file.close();
+};
+
+template <>
+void readGridVDB(const string& name, Grid<Real>* grid) {
+ debMsg("Reading real grid " << grid->getName() << " from vdb file " << name, 1);
+
+ openvdb::initialize();
+ openvdb::io::File file(name);
+ file.open();
+
+ openvdb::GridBase::Ptr baseGrid;
+ for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName(); ++nameIter)
+ {
+ #ifndef BLENDER
+ // Read in only the grid we are interested in.
+ if (nameIter.gridName() == grid->getName()) {
+ baseGrid = file.readGrid(nameIter.gridName());
+ } else {
+ debMsg("skipping grid " << nameIter.gridName(), 1);
+ }
+ #else
+ // For Blender, skip name check and pick first grid from loop
+ baseGrid = file.readGrid(nameIter.gridName());
+ break;
+ #endif
+ }
+ file.close();
+ openvdb::FloatGrid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::FloatGrid>(baseGrid);
+
+ openvdb::FloatGrid::Accessor accessor = gridVDB->getAccessor();
+
+ FOR_IJK(*grid) {
+ openvdb::Coord xyz(i, j, k);
+ float v = accessor.getValue(xyz);
+ (*grid)(i, j, k) = v;
+ }
+};
+
+template <>
+void writeGridVDB(const string& name, Grid<Vec3>* grid) {
+ debMsg("Writing vec3 grid " << grid->getName() << " to vdb file " << name, 1);
+
+ openvdb::initialize();
+ openvdb::Vec3SGrid::Ptr gridVDB = openvdb::Vec3SGrid::create();
+ // note , warning - velocity content currently not scaled...
+ gridVDB->setTransform( openvdb::math::Transform::createLinearTransform( 1./grid->getSizeX() )); //voxel size
+ openvdb::Vec3SGrid::Accessor accessor = gridVDB->getAccessor();
+
+ // MAC or regular vec grid?
+ if(grid->getType() & GridBase::TypeMAC) gridVDB->setGridClass(openvdb::GRID_STAGGERED);
+ else gridVDB->setGridClass(openvdb::GRID_UNKNOWN);
+
+ gridVDB->setName( grid->getName() );
+
+ openvdb::io::File file(name);
+ FOR_IJK(*grid) {
+ openvdb::Coord xyz(i, j, k);
+ Vec3 v = (*grid)(i, j, k);
+ openvdb::Vec3f vo( (float)v[0] , (float)v[1] , (float)v[2] );
+ accessor.setValue(xyz, vo);
+ }
+
+ openvdb::GridPtrVec gridsVDB;
+ gridsVDB.push_back(gridVDB);
+
+ file.write(gridsVDB);
+ file.close();
+};
+
+template <>
+void readGridVDB(const string& name, Grid<Vec3>* grid) {
+ debMsg("Reading vec3 grid " << grid->getName() << " from vdb file " << name, 1);
+
+ openvdb::initialize();
+ openvdb::io::File file(name);
+ file.open();
+
+ openvdb::GridBase::Ptr baseGrid;
+ for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName(); ++nameIter)
+ {
+ #ifndef BLENDER
+ // Read in only the grid we are interested in.
+ if (nameIter.gridName() == grid->getName()) {
+ baseGrid = file.readGrid(nameIter.gridName());
+ } else {
+ debMsg("skipping grid " << nameIter.gridName(), 1);
+ }
+ #else
+ // For Blender, skip name check and pick first grid from loop
+ baseGrid = file.readGrid(nameIter.gridName());
+ break;
+ #endif
+ }
+ file.close();
+ openvdb::Vec3SGrid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::Vec3SGrid>(baseGrid);
+
+ openvdb::Vec3SGrid::Accessor accessor = gridVDB->getAccessor();
+
+ FOR_IJK(*grid) {
+ openvdb::Coord xyz(i, j, k);
+ openvdb::Vec3f v = accessor.getValue(xyz);
+ (*grid)(i, j, k).x = (float)v[0];
+ (*grid)(i, j, k).y = (float)v[1];
+ (*grid)(i, j, k).z = (float)v[2];
+ }
+};
+
+#endif // OPENVDB==1
+
+
+//*****************************************************************************
+// npz file support (warning - read works, but write generates uncompressed npz; i.e. not recommended for large volumes)
+
+template <class T>
+void writeGridNumpy(const string& name, Grid<T>* grid) {
+# if NO_ZLIB==1
+ debMsg( "file format not supported without zlib" ,1);
+ return;
+# endif
+# if FLOATINGPOINT_PRECISION!=1
+ errMsg("writeGridNumpy: Double precision not yet supported");
+# endif
+
+ // find suffix to differentiate between npy <-> npz , TODO: check for actual "npy" string
+ std::string::size_type idx;
+ bool bUseNpz = false;
+ idx = name.rfind('.');
+ if(idx != std::string::npos) {
+ bUseNpz = name.substr(idx+1) == "npz";
+ debMsg( "Writing grid " << grid->getName() << " to npz file " << name ,1);
+ } else {
+ debMsg( "Writing grid " << grid->getName() << " to npy file " << name ,1);
+ }
+
+ // storage code
+ size_t uDim = 1;
+ if (grid->getType() & GridBase::TypeInt || grid->getType() & GridBase::TypeReal || grid->getType() & GridBase::TypeLevelset)
+ uDim = 1;
+ else if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC)
+ uDim = 3;
+ else
+ errMsg("writeGridNumpy: unknown element type");
+
+ const std::vector<size_t> shape = {static_cast<size_t>(grid->getSizeZ()), static_cast<size_t>(grid->getSizeY()), static_cast<size_t>(grid->getSizeX()), uDim};
+
+ if(bUseNpz){
+ // note, the following generates a zip file without compression
+ if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC) {
+ // cast to float* for export!
+ float* ptr = (float*)&((*grid)[0]);
+ cnpy::npz_save(name, "arr_0", ptr, shape, "w");
+ } else {
+ T* ptr = &((*grid)[0]);
+ cnpy::npz_save(name, "arr_0", ptr, shape, "w");
+ }
+ } else {
+ cnpy::npy_save(name, &grid[0], shape, "w");
+ }
+};
+
+template <class T>
+void readGridNumpy(const string& name, Grid<T>* grid) {
+# if NO_ZLIB==1
+ debMsg( "file format not supported without zlib" ,1);
+ return;
+# endif
+# if FLOATINGPOINT_PRECISION!=1
+ errMsg("readGridNumpy: Double precision not yet supported");
+# endif
+
+ // find suffix to differentiate between npy <-> npz
+ std::string::size_type idx;
+ bool bUseNpz = false;
+ idx = name.rfind('.');
+ if(idx != std::string::npos) {
+ bUseNpz = name.substr(idx+1) == "npz";
+ debMsg( "Reading grid " << grid->getName() << " as npz file " << name ,1);
+ } else {
+ debMsg( "Reading grid " << grid->getName() << " as npy file " << name ,1);
+ }
+
+ cnpy::NpyArray gridArr;
+ if(bUseNpz) {
+ cnpy::npz_t fNpz = cnpy::npz_load(name);
+ gridArr = fNpz["arr_0"];
+ } else {
+ gridArr = cnpy::npy_load(name);
+ }
+
+ // Check the file meta information
+ assertMsg (gridArr.shape[2] == grid->getSizeX() && gridArr.shape[1] == grid->getSizeY() && gridArr.shape[0] == grid->getSizeZ(), "grid dim doesn't match, " << Vec3(gridArr.shape[2], gridArr.shape[1], gridArr.shape[0]) << " vs " << grid->getSize() );
+ size_t uDim = 1;
+ if (grid->getType() & GridBase::TypeInt || grid->getType() & GridBase::TypeReal || grid->getType() & GridBase::TypeLevelset)
+ uDim = 1;
+ else if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC)
+ uDim = 3;
+ else
+ errMsg("readGridNumpy: unknown element type");
+ assertMsg (gridArr.shape[3] == uDim, "grid data dim doesn't match, " << gridArr.shape[3] << " vs " << uDim );
+
+ if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC) {
+ // treated as float* for export , thus consider 3 elements
+ assertMsg (3*gridArr.word_size == sizeof(T), "vec3 grid data size doesn't match, " << 3*gridArr.word_size << " vs " << sizeof(T));
+ } else {
+ assertMsg (gridArr.word_size == sizeof(T), "grid data size doesn't match, " << gridArr.word_size << " vs " << sizeof(T));
+ }
+
+ // copy back, TODO: beautify...
+ memcpy(&((*grid)[0]), gridArr.data<T>(), sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ() );
+};
+
+// adopted from getUniFileSize
+void getNpzFileSize(const string& name, int& x, int& y, int& z, int* t = NULL, std::string* info = NULL) {
+ x = y = z = 0;
+# if NO_ZLIB!=1
+ debMsg( "file format not supported without zlib" ,1);
+ return;
+# endif
+# if FLOATINGPOINT_PRECISION!=1
+ errMsg("getNpzFileSize: Double precision not yet supported");
+# endif
+ // find suffix to differentiate between npy <-> npz
+ cnpy::NpyArray gridArr;
+ cnpy::npz_t fNpz = cnpy::npz_load(name);
+ gridArr = fNpz["arr_0"];
+
+ z = gridArr.shape[0];
+ y = gridArr.shape[1];
+ x = gridArr.shape[2];
+ if(t) (*t) = 0; // unused for now
+}
+Vec3 getNpzFileSize(const string& name) {
+ int x,y,z;
+ getNpzFileSize(name, x,y,z);
+ return Vec3( Real(x), Real(y), Real(z) );
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getNpzFileSize" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const string& name = _args.get<string >("name",0,&_lock); _retval = toPy(getNpzFileSize(name)); _args.check(); }
+ pbFinalizePlugin(parent,"getNpzFileSize", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getNpzFileSize",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getNpzFileSize ("","getNpzFileSize",_W_2);
+extern "C" {
+ void PbRegister_getNpzFileSize() {
+ KEEP_UNUSED(_RP_getNpzFileSize); }
+ }
+
+
+
+
+//*****************************************************************************
+// helper functions
+
+
+void quantizeReal(Real& v, const Real step) {
+ int q = int(v / step + step*0.5);
+ double qd = q * (double)step;
+ v = (Real)qd;
+}
+ struct knQuantize : public KernelBase {
+ knQuantize(Grid<Real>& grid, Real step) : KernelBase(&grid,0) ,grid(grid),step(step) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& grid, Real step ) const {
+ quantizeReal( grid(idx), step );
+} inline Grid<Real>& getArg0() {
+ return grid; }
+ typedef Grid<Real> type0;inline Real& getArg1() {
+ return step; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knQuantize ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, grid,step); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<Real>& grid; Real step; }
+;
+void quantizeGrid(Grid<Real>& grid, Real step) { knQuantize(grid,step); } static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "quantizeGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& grid = *_args.getPtr<Grid<Real> >("grid",0,&_lock); Real step = _args.get<Real >("step",1,&_lock); _retval = getPyNone(); quantizeGrid(grid,step); _args.check(); }
+ pbFinalizePlugin(parent,"quantizeGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("quantizeGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_quantizeGrid ("","quantizeGrid",_W_3);
+extern "C" {
+ void PbRegister_quantizeGrid() {
+ KEEP_UNUSED(_RP_quantizeGrid); }
+ }
+
+
+
+ struct knQuantizeVec3 : public KernelBase {
+ knQuantizeVec3(Grid<Vec3>& grid, Real step) : KernelBase(&grid,0) ,grid(grid),step(step) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Vec3>& grid, Real step ) const {
+ for(int c=0; c<3; ++c) quantizeReal( grid(idx)[c], step );
+} inline Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Real& getArg1() {
+ return step; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knQuantizeVec3 ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, grid,step); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<Vec3>& grid; Real step; }
+;
+void quantizeGridVec3(Grid<Vec3>& grid, Real step) { knQuantizeVec3(grid,step); } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "quantizeGridVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& grid = *_args.getPtr<Grid<Vec3> >("grid",0,&_lock); Real step = _args.get<Real >("step",1,&_lock); _retval = getPyNone(); quantizeGridVec3(grid,step); _args.check(); }
+ pbFinalizePlugin(parent,"quantizeGridVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("quantizeGridVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_quantizeGridVec3 ("","quantizeGridVec3",_W_4);
+extern "C" {
+ void PbRegister_quantizeGridVec3() {
+ KEEP_UNUSED(_RP_quantizeGridVec3); }
+ }
+
+
+
+
+
+// explicit instantiation
+template void writeGridRaw<int> (const string& name, Grid<int>* grid);
+template void writeGridRaw<Real>(const string& name, Grid<Real>* grid);
+template void writeGridRaw<Vec3>(const string& name, Grid<Vec3>* grid);
+template void writeGridUni<int> (const string& name, Grid<int>* grid);
+template void writeGridUni<Real>(const string& name, Grid<Real>* grid);
+template void writeGridUni<Vec3>(const string& name, Grid<Vec3>* grid);
+template void writeGridVol<int> (const string& name, Grid<int>* grid);
+template void writeGridVol<Vec3>(const string& name, Grid<Vec3>* grid);
+template void writeGridTxt<int> (const string& name, Grid<int>* grid);
+template void writeGridTxt<Real>(const string& name, Grid<Real>* grid);
+template void writeGridTxt<Vec3>(const string& name, Grid<Vec3>* grid);
+
+template void readGridRaw<int> (const string& name, Grid<int>* grid);
+template void readGridRaw<Real> (const string& name, Grid<Real>* grid);
+template void readGridRaw<Vec3> (const string& name, Grid<Vec3>* grid);
+template void readGridUni<int> (const string& name, Grid<int>* grid);
+template void readGridUni<Real> (const string& name, Grid<Real>* grid);
+template void readGridUni<Vec3> (const string& name, Grid<Vec3>* grid);
+template void readGridVol<int> (const string& name, Grid<int>* grid);
+template void readGridVol<Vec3> (const string& name, Grid<Vec3>* grid);
+
+template void readGrid4dUni<int> (const string& name, Grid4d<int>* grid, int readTslice, Grid4d<int>* slice, void** fileHandle);
+template void readGrid4dUni<Real> (const string& name, Grid4d<Real>* grid, int readTslice, Grid4d<Real>* slice, void** fileHandle);
+template void readGrid4dUni<Vec3> (const string& name, Grid4d<Vec3>* grid, int readTslice, Grid4d<Vec3>* slice, void** fileHandle);
+template void readGrid4dUni<Vec4> (const string& name, Grid4d<Vec4>* grid, int readTslice, Grid4d<Vec4>* slice, void** fileHandle);
+template void writeGrid4dUni<int> (const string& name, Grid4d<int>* grid);
+template void writeGrid4dUni<Real>(const string& name, Grid4d<Real>* grid);
+template void writeGrid4dUni<Vec3>(const string& name, Grid4d<Vec3>* grid);
+template void writeGrid4dUni<Vec4>(const string& name, Grid4d<Vec4>* grid);
+
+template void readGrid4dRaw<int> (const string& name, Grid4d<int>* grid);
+template void readGrid4dRaw<Real> (const string& name, Grid4d<Real>* grid);
+template void readGrid4dRaw<Vec3> (const string& name, Grid4d<Vec3>* grid);
+template void readGrid4dRaw<Vec4> (const string& name, Grid4d<Vec4>* grid);
+template void writeGrid4dRaw<int> (const string& name, Grid4d<int>* grid);
+template void writeGrid4dRaw<Real>(const string& name, Grid4d<Real>* grid);
+template void writeGrid4dRaw<Vec3>(const string& name, Grid4d<Vec3>* grid);
+template void writeGrid4dRaw<Vec4>(const string& name, Grid4d<Vec4>* grid);
+
+template void writeGridNumpy<int> (const string& name, Grid<int>* grid);
+template void writeGridNumpy<Real>(const string& name, Grid<Real>* grid);
+template void writeGridNumpy<Vec3>(const string& name, Grid<Vec3>* grid);
+template void readGridNumpy<int> (const string& name, Grid<int>* grid);
+template void readGridNumpy<Real> (const string& name, Grid<Real>* grid);
+template void readGridNumpy<Vec3> (const string& name, Grid<Vec3>* grid);
+
+#if OPENVDB==1
+template void writeGridVDB<int>(const string& name, Grid<int>* grid);
+template void writeGridVDB<Vec3>(const string& name, Grid<Vec3>* grid);
+template void writeGridVDB<Real>(const string& name, Grid<Real>* grid);
+
+template void readGridVDB<int>(const string& name, Grid<int>* grid);
+template void readGridVDB<Vec3>(const string& name, Grid<Vec3>* grid);
+template void readGridVDB<Real>(const string& name, Grid<Real>* grid);
+#endif // OPENVDB==1
+
+} //namespace
+
+namespace Manta {
+
+}
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/iomeshes.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/iomeshes.cpp
new file mode 100644
index 00000000000..4bd336c8d48
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/iomeshes.cpp
@@ -0,0 +1,459 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#if NO_ZLIB!=1
+extern "C" {
+#include <zlib.h>
+}
+#endif
+
+#include "mantaio.h"
+#include "grid.h"
+#include "mesh.h"
+#include "vortexsheet.h"
+#include <cstring>
+
+using namespace std;
+
+namespace Manta {
+
+static const int STR_LEN_PDATA = 256;
+
+//! mdata uni header, v3 (similar to grid header and mdata header)
+typedef struct {
+ int dim; // number of vertices
+ int dimX, dimY, dimZ; // underlying solver resolution (all data in local coordinates!)
+ int elementType, bytesPerElement; // type id and byte size
+ char info[STR_LEN_PDATA]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+} UniMeshHeader;
+
+//*****************************************************************************
+// conversion functions for double precision
+// (note - uni files always store single prec. values)
+//*****************************************************************************
+
+#if NO_ZLIB!=1
+
+template <class T>
+void mdataConvertWrite( gzFile& gzf, MeshDataImpl<T>& mdata, void* ptr, UniMeshHeader& head) {
+ errMsg("mdataConvertWrite: unknown type, not yet supported");
+}
+
+template <>
+void mdataConvertWrite( gzFile& gzf, MeshDataImpl<int>& mdata, void* ptr, UniMeshHeader& head) {
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ gzwrite(gzf, &mdata[0], sizeof(int)*head.dim);
+}
+template <>
+void mdataConvertWrite( gzFile& gzf, MeshDataImpl<double>& mdata, void* ptr, UniMeshHeader& head) {
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<mdata.size(); ++i,++ptrf) {
+ *ptrf = (float)mdata[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float)* head.dim);
+}
+template <>
+void mdataConvertWrite( gzFile& gzf, MeshDataImpl<Vec3>& mdata, void* ptr, UniMeshHeader& head) {
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<mdata.size(); ++i) {
+ for(int c=0; c<3; ++c) { *ptrf = (float)mdata[i][c]; ptrf++; }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) *head.dim);
+}
+
+
+template <class T>
+void mdataReadConvert(gzFile& gzf, MeshDataImpl<T>& grid, void* ptr, int bytesPerElement) {
+ errMsg("mdataReadConvert: unknown mdata type, not yet supported");
+}
+
+template <>
+void mdataReadConvert<int>(gzFile& gzf, MeshDataImpl<int>& mdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(int)*mdata.size());
+ assertMsg (bytesPerElement == sizeof(int), "mdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(int) );
+ // int dont change in double precision mode - copy over
+ memcpy(&(mdata[0]), ptr, sizeof(int) * mdata.size() );
+}
+
+template <>
+void mdataReadConvert<double>(gzFile& gzf, MeshDataImpl<double>& mdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(float)*mdata.size());
+ assertMsg (bytesPerElement == sizeof(float), "mdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<mdata.size(); ++i,++ptrf) {
+ mdata[i] = double(*ptrf);
+ }
+}
+
+template <>
+void mdataReadConvert<Vec3>(gzFile& gzf, MeshDataImpl<Vec3>& mdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(Vector3D<float>)*mdata.size());
+ assertMsg (bytesPerElement == sizeof(Vector3D<float>), "mdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(Vector3D<float>) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<mdata.size(); ++i) {
+ Vec3 v;
+ for(int c=0; c<3; ++c) { v[c] = double(*ptrf); ptrf++; }
+ mdata[i] = v;
+ }
+}
+
+
+#endif // NO_ZLIB!=1
+
+//*****************************************************************************
+// mesh data
+//*****************************************************************************
+
+void readBobjFile(const string& name, Mesh* mesh, bool append) {
+ debMsg( "reading mesh file " << name ,1);
+ if (!append)
+ mesh->clear();
+ else
+ errMsg("readBobj: append not yet implemented!");
+
+# if NO_ZLIB!=1
+ const Real dx = mesh->getParent()->getDx();
+ const Vec3 gs = toVec3( mesh->getParent()->getGridSize() );
+
+ gzFile gzf = gzopen(name.c_str(), "rb1"); // do some compression
+ if (!gzf)
+ errMsg("readBobj: unable to open file");
+
+ // read vertices
+ int num = 0;
+ gzread(gzf, &num, sizeof(int));
+ mesh->resizeNodes(num);
+ debMsg( "read mesh , verts "<<num,1);
+ for (int i=0; i<num; i++) {
+ Vector3D<float> pos;
+ gzread(gzf, &pos.value[0], sizeof(float)*3);
+ mesh->nodes(i).pos = toVec3(pos);
+
+ // convert to grid space
+ mesh->nodes(i).pos /= dx;
+ mesh->nodes(i).pos += gs*0.5;
+ }
+
+ // normals
+ num = 0;
+ gzread(gzf, &num, sizeof(int));
+ for (int i=0; i<num; i++) {
+ Vector3D<float> pos;
+ gzread(gzf, &pos.value[0], sizeof(float)*3);
+ mesh->nodes(i).normal = toVec3(pos);
+ }
+
+ // read tris
+ num = 0;
+ gzread(gzf, &num, sizeof(int));
+ mesh->resizeTris( num );
+ for(int t=0; t<num; t++) {
+ for(int j=0; j<3; j++) {
+ int trip = 0;
+ gzread(gzf, &trip, sizeof(int));
+ mesh->tris(t).c[j] = trip;
+ }
+ }
+ // note - vortex sheet info ignored for now... (see writeBobj)
+ gzclose( gzf );
+ debMsg( "read mesh , triangles "<<mesh->numTris()<<", vertices "<<mesh->numNodes()<<" ",1 );
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+void writeBobjFile(const string& name, Mesh* mesh) {
+ debMsg( "writing mesh file " << name ,1);
+# if NO_ZLIB!=1
+ const Real dx = mesh->getParent()->getDx();
+ const Vec3i gs = mesh->getParent()->getGridSize();
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf)
+ errMsg("writeBobj: unable to open file");
+
+ // write vertices
+ int numVerts = mesh->numNodes();
+ gzwrite(gzf, &numVerts, sizeof(int));
+ for (int i=0; i<numVerts; i++) {
+ Vector3D<float> pos = toVec3f(mesh->nodes(i).pos);
+ // normalize to unit cube around 0
+ pos -= toVec3f(gs)*0.5;
+ pos *= dx;
+ gzwrite(gzf, &pos.value[0], sizeof(float)*3);
+ }
+
+ // normals
+ mesh->computeVertexNormals();
+ gzwrite(gzf, &numVerts, sizeof(int));
+ for (int i=0; i<numVerts; i++) {
+ Vector3D<float> pos = toVec3f(mesh->nodes(i).normal);
+ gzwrite(gzf, &pos.value[0], sizeof(float)*3);
+ }
+
+ // write tris
+ int numTris = mesh->numTris();
+ gzwrite(gzf, &numTris, sizeof(int));
+ for(int t=0; t<numTris; t++) {
+ for(int j=0; j<3; j++) {
+ int trip = mesh->tris(t).c[j];
+ gzwrite(gzf, &trip, sizeof(int));
+ }
+ }
+
+ // per vertex smoke densities
+ if (mesh->getType() == Mesh::TypeVortexSheet) {
+ VortexSheetMesh* vmesh = (VortexSheetMesh*) mesh;
+ int densId[4] = {0, 'v','d','e'};
+ gzwrite(gzf, &densId[0], sizeof(int) * 4);
+
+ // compute densities
+ vector<float> triDensity(numTris);
+ for (int tri=0; tri < numTris; tri++) {
+ Real area = vmesh->getFaceArea(tri);
+ if (area>0)
+ triDensity[tri] = vmesh->sheet(tri).smokeAmount;
+ }
+
+ // project triangle data to vertex
+ vector<int> triPerVertex(numVerts);
+ vector<float> density(numVerts);
+ for (int tri=0; tri < numTris; tri++) {
+ for (int c=0; c<3; c++) {
+ int vertex = mesh->tris(tri).c[c];
+ density[vertex] += triDensity[tri];
+ triPerVertex[vertex]++;
+ }
+ }
+
+ // averaged smoke densities
+ for(int point=0; point<numVerts; point++) {
+ float dens = 0;
+ if (triPerVertex[point]>0)
+ dens = density[point] / triPerVertex[point];
+ gzwrite(gzf, &dens, sizeof(float));
+ }
+ }
+
+ // vertex flags
+ if (mesh->getType() == Mesh::TypeVortexSheet) {
+ int Id[4] = {0, 'v','x','f'};
+ gzwrite(gzf, &Id[0], sizeof(int) * 4);
+
+ // averaged smoke densities
+ for(int point=0; point<numVerts; point++) {
+ float alpha = (mesh->nodes(point).flags & Mesh::NfMarked) ? 1: 0;
+ gzwrite(gzf, &alpha, sizeof(float));
+ }
+ }
+
+ gzclose( gzf );
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+void readObjFile(const std::string& name, Mesh* mesh, bool append) {
+ ifstream ifs (name.c_str());
+
+ if (!ifs.good())
+ errMsg("can't open file '" + name + "'");
+
+ if (!append)
+ mesh->clear();
+ int nodebase = mesh->numNodes();
+ int cnt = nodebase;
+ while(ifs.good() && !ifs.eof()) {
+ string id;
+ ifs >> id;
+
+ if (id[0] == '#') {
+ // comment
+ getline(ifs, id);
+ continue;
+ }
+ if (id == "vt") {
+ // tex coord, ignore
+ } else if (id == "vn") {
+ // normals
+ if (!mesh->numNodes())
+ errMsg("invalid amount of nodes");
+ Node n = mesh->nodes(cnt);
+ ifs >> n.normal.x >> n.normal.y >> n.normal.z;
+ cnt++;
+ } else if (id == "v") {
+ // vertex
+ Node n;
+ ifs >> n.pos.x >> n.pos.y >> n.pos.z;
+ mesh->addNode(n);
+ } else if (id == "g") {
+ // group
+ string group;
+ ifs >> group;
+ } else if (id == "f") {
+ // face
+ string face;
+ Triangle t;
+ for (int i=0; i<3; i++) {
+ ifs >> face;
+ if (face.find('/') != string::npos)
+ face = face.substr(0, face.find('/')); // ignore other indices
+ int idx = atoi(face.c_str()) - 1;
+ if (idx < 0)
+ errMsg("invalid face encountered");
+ idx += nodebase;
+ t.c[i] = idx;
+ }
+ mesh->addTri(t);
+ } else {
+ // whatever, ignore
+ }
+ // kill rest of line
+ getline(ifs, id);
+ }
+ ifs.close();
+}
+
+// write regular .obj file, in line with bobj.gz output (but only verts & tris for now)
+void writeObjFile(const string& name, Mesh* mesh) {
+ const Real dx = mesh->getParent()->getDx();
+ const Vec3i gs = mesh->getParent()->getGridSize();
+
+ ofstream ofs(name.c_str());
+ if (!ofs.good())
+ errMsg("writeObjFile: can't open file " << name);
+
+ ofs << "o MantaMesh\n";
+
+ // write vertices
+ int numVerts = mesh->numNodes();
+ for (int i=0; i<numVerts; i++) {
+ Vector3D<float> pos = toVec3f(mesh->nodes(i).pos);
+ // normalize to unit cube around 0
+ pos -= toVec3f(gs)*0.5;
+ pos *= dx;
+ ofs << "v "<< pos.value[0] <<" "<< pos.value[1] <<" "<< pos.value[2] <<" "<< "\n";
+ }
+
+ // write normals
+ for (int i=0; i<numVerts; i++) {
+ Vector3D<float> n = toVec3f(mesh->nodes(i).normal);
+ // normalize to unit cube around 0
+ ofs << "vn "<< n.value[0] <<" "<< n.value[1] <<" "<< n.value[2] <<" "<< "\n";
+ }
+
+ // write tris
+ int numTris = mesh->numTris();
+ for(int t=0; t<numTris; t++) {
+ ofs << "f "<< (mesh->tris(t).c[0]+1) <<" "<< (mesh->tris(t).c[1]+1) <<" "<< (mesh->tris(t).c[2]+1) <<" "<< "\n";
+ }
+
+ ofs.close();
+}
+
+template <class T>
+void readMdataUni(const std::string& name, MeshDataImpl<T>* mdata ) {
+ debMsg( "reading mesh data " << mdata->getName() << " from uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("can't open file " << name );
+
+ char ID[5]={0,0,0,0,0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "MD01")) {
+ UniMeshHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniMeshHeader)) == sizeof(UniMeshHeader), "can't read file, no header present");
+ assertMsg (head.dim == mdata->size() , "mdata size doesn't match");
+# if FLOATINGPOINT_PRECISION!=1
+ MeshDataImpl<T> temp(mdata->getParent());
+ temp.resize( mdata->size() );
+ mdataReadConvert<T>(gzf, *mdata, &(temp[0]), head.bytesPerElement);
+# else
+ assertMsg ( ((head.bytesPerElement == sizeof(T)) && (head.elementType==1) ), "mdata type doesn't match");
+ IndexInt bytes = sizeof(T)*head.dim;
+ IndexInt readBytes = gzread(gzf, &(mdata->get(0)), sizeof(T)*head.dim);
+ assertMsg(bytes==readBytes, "can't read uni file, stream length does not match, "<<bytes<<" vs "<<readBytes );
+# endif
+ }
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+template <class T>
+void writeMdataUni(const std::string& name, MeshDataImpl<T>* mdata ) {
+ debMsg( "writing mesh data " << mdata->getName() << " to uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ char ID[5] = "MD01";
+ UniMeshHeader head;
+ head.dim = mdata->size();
+ head.bytesPerElement = sizeof(T);
+ head.elementType = 1; // 1 for mesh data, todo - add sub types?
+ snprintf( head.info, STR_LEN_PDATA, "%s", buildInfoString().c_str() );
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file " << name);
+ gzwrite(gzf, ID, 4);
+
+# if FLOATINGPOINT_PRECISION!=1
+ // always write float values, even if compiled with double precision (as for grids)
+ MeshDataImpl<T> temp(mdata->getParent());
+ temp.resize( mdata->size() );
+ mdataConvertWrite( gzf, *mdata, &(temp[0]), head);
+# else
+ gzwrite(gzf, &head, sizeof(UniMeshHeader));
+ gzwrite(gzf, &(mdata->get(0)), sizeof(T)*head.dim);
+# endif
+ gzclose(gzf);
+
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+// explicit instantiation
+template void writeMdataUni<int> (const std::string& name, MeshDataImpl<int>* mdata );
+template void writeMdataUni<Real>(const std::string& name, MeshDataImpl<Real>* mdata );
+template void writeMdataUni<Vec3>(const std::string& name, MeshDataImpl<Vec3>* mdata );
+template void readMdataUni<int> (const std::string& name, MeshDataImpl<int>* mdata );
+template void readMdataUni<Real> (const std::string& name, MeshDataImpl<Real>* mdata );
+template void readMdataUni<Vec3> (const std::string& name, MeshDataImpl<Vec3>* mdata );
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/ioparticles.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/ioparticles.cpp
new file mode 100644
index 00000000000..20c89aabe90
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/ioparticles.cpp
@@ -0,0 +1,310 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <cstring>
+#if NO_ZLIB!=1
+extern "C" {
+#include <zlib.h>
+}
+#endif
+
+#include "mantaio.h"
+#include "grid.h"
+#include "particle.h"
+#include "vector4d.h"
+#include "grid4d.h"
+
+using namespace std;
+
+namespace Manta {
+
+static const int STR_LEN_PDATA = 256;
+
+//! pdata uni header, v3 (similar to grid header)
+typedef struct {
+ int dim; // number of partilces
+ int dimX, dimY, dimZ; // underlying solver resolution (all data in local coordinates!)
+ int elementType, bytesPerElement; // type id and byte size
+ char info[STR_LEN_PDATA]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+} UniPartHeader;
+
+
+//*****************************************************************************
+// conversion functions for double precision
+// (note - uni files always store single prec. values)
+//*****************************************************************************
+
+#if NO_ZLIB!=1
+
+template <class T>
+void pdataConvertWrite( gzFile& gzf, ParticleDataImpl<T>& pdata, void* ptr, UniPartHeader& head) {
+ errMsg("pdataConvertWrite: unknown type, not yet supported");
+}
+
+template <>
+void pdataConvertWrite( gzFile& gzf, ParticleDataImpl<int>& pdata, void* ptr, UniPartHeader& head) {
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &pdata[0], sizeof(int)*head.dim);
+}
+template <>
+void pdataConvertWrite( gzFile& gzf, ParticleDataImpl<double>& pdata, void* ptr, UniPartHeader& head) {
+ head.bytesPerElement = sizeof(float);
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<pdata.size(); ++i,++ptrf) {
+ *ptrf = (float)pdata[i];
+ }
+ gzwrite(gzf, ptr, sizeof(float)* head.dim);
+}
+template <>
+void pdataConvertWrite( gzFile& gzf, ParticleDataImpl<Vec3>& pdata, void* ptr, UniPartHeader& head) {
+ head.bytesPerElement = sizeof(Vector3D<float>);
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<pdata.size(); ++i) {
+ for(int c=0; c<3; ++c) { *ptrf = (float)pdata[i][c]; ptrf++; }
+ }
+ gzwrite(gzf, ptr, sizeof(Vector3D<float>) *head.dim);
+}
+
+
+template <class T>
+void pdataReadConvert(gzFile& gzf, ParticleDataImpl<T>& grid, void* ptr, int bytesPerElement) {
+ errMsg("pdataReadConvert: unknown pdata type, not yet supported");
+}
+
+template <>
+void pdataReadConvert<int>(gzFile& gzf, ParticleDataImpl<int>& pdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(int)*pdata.size());
+ assertMsg (bytesPerElement == sizeof(int), "pdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(int) );
+ // int dont change in double precision mode - copy over
+ memcpy(&(pdata[0]), ptr, sizeof(int) * pdata.size() );
+}
+
+template <>
+void pdataReadConvert<double>(gzFile& gzf, ParticleDataImpl<double>& pdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(float)*pdata.size());
+ assertMsg (bytesPerElement == sizeof(float), "pdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(float) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<pdata.size(); ++i,++ptrf) {
+ pdata[i] = double(*ptrf);
+ }
+}
+
+template <>
+void pdataReadConvert<Vec3>(gzFile& gzf, ParticleDataImpl<Vec3>& pdata, void* ptr, int bytesPerElement) {
+ gzread(gzf, ptr, sizeof(Vector3D<float>)*pdata.size());
+ assertMsg (bytesPerElement == sizeof(Vector3D<float>), "pdata element size doesn't match "<< bytesPerElement <<" vs "<< sizeof(Vector3D<float>) );
+ float* ptrf = (float*)ptr;
+ for(int i=0; i<pdata.size(); ++i) {
+ Vec3 v;
+ for(int c=0; c<3; ++c) { v[c] = double(*ptrf); ptrf++; }
+ pdata[i] = v;
+ }
+}
+
+
+#endif // NO_ZLIB!=1
+
+
+//*****************************************************************************
+// particles and particle data
+//*****************************************************************************
+
+static const int PartSysSize = sizeof(Vector3D<float>)+sizeof(int);
+
+void writeParticlesUni(const std::string& name, const BasicParticleSystem* parts ) {
+ debMsg( "writing particles " << parts->getName() << " to uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ char ID[5] = "PB02";
+ UniPartHeader head;
+ head.dim = parts->size();
+ Vec3i gridSize = parts->getParent()->getGridSize();
+ head.dimX = gridSize.x;
+ head.dimY = gridSize.y;
+ head.dimZ = gridSize.z;
+ head.bytesPerElement = PartSysSize;
+ head.elementType = 0; // 0 for base data
+ snprintf( head.info, STR_LEN_PDATA, "%s", buildInfoString().c_str() );
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file " << name);
+
+ gzwrite(gzf, ID, 4);
+# if FLOATINGPOINT_PRECISION!=1
+ // warning - hard coded conversion of byte size here...
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ for(int i=0; i<parts->size(); ++i) {
+ Vector3D<float> pos = toVec3f( (*parts)[i].pos );
+ int flag = (*parts)[i].flag;
+ gzwrite(gzf, &pos , sizeof(Vector3D<float>) );
+ gzwrite(gzf, &flag, sizeof(int) );
+ }
+# else
+ assertMsg( sizeof(BasicParticleData) == PartSysSize, "particle data size doesn't match" );
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &((*parts)[0]), PartSysSize*head.dim);
+# endif
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+void readParticlesUni(const std::string& name, BasicParticleSystem* parts ) {
+ debMsg( "reading particles " << parts->getName() << " from uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("can't open file " << name);
+
+ char ID[5]={0,0,0,0,0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "PB01")) {
+ errMsg("particle uni file format v01 not supported anymore");
+ } else if (!strcmp(ID, "PB02")) {
+ // current file format
+ UniPartHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniPartHeader)) == sizeof(UniPartHeader), "can't read file, no header present");
+ assertMsg ( ((head.bytesPerElement == PartSysSize) && (head.elementType==0) ), "particle type doesn't match");
+
+ // re-allocate all data
+ parts->resizeAll( head.dim );
+
+ assertMsg (head.dim == parts->size() , "particle size doesn't match");
+# if FLOATINGPOINT_PRECISION!=1
+ for(int i=0; i<parts->size(); ++i) {
+ Vector3D<float> pos; int flag;
+ gzread(gzf, &pos , sizeof(Vector3D<float>) );
+ gzread(gzf, &flag, sizeof(int) );
+ (*parts)[i].pos = toVec3d(pos);
+ (*parts)[i].flag = flag;
+ }
+# else
+ assertMsg( sizeof(BasicParticleData) == PartSysSize, "particle data size doesn't match" );
+ IndexInt bytes = PartSysSize*head.dim;
+ IndexInt readBytes = gzread(gzf, &(parts->getData()[0]), bytes);
+ assertMsg( bytes==readBytes, "can't read uni file, stream length does not match, "<<bytes<<" vs "<<readBytes );
+# endif
+
+ parts->transformPositions( Vec3i(head.dimX,head.dimY,head.dimZ), parts->getParent()->getGridSize() );
+ }
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+template <class T>
+void writePdataUni(const std::string& name, ParticleDataImpl<T>* pdata ) {
+ debMsg( "writing particle data " << pdata->getName() << " to uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ char ID[5] = "PD01";
+ UniPartHeader head;
+ head.dim = pdata->size();
+ Vec3i gridSize = pdata->getParent()->getGridSize();
+ head.dimX = gridSize.x;
+ head.dimY = gridSize.y;
+ head.dimZ = gridSize.z;
+ head.bytesPerElement = sizeof(T);
+ head.elementType = 1; // 1 for particle data, todo - add sub types?
+ snprintf( head.info, STR_LEN_PDATA, "%s", buildInfoString().c_str() );
+ MuTime stamp;
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file " << name);
+ gzwrite(gzf, ID, 4);
+
+# if FLOATINGPOINT_PRECISION!=1
+ // always write float values, even if compiled with double precision (as for grids)
+ ParticleDataImpl<T> temp(pdata->getParent());
+ temp.resize( pdata->size() );
+ pdataConvertWrite( gzf, *pdata, &(temp[0]), head);
+# else
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &(pdata->get(0)), sizeof(T)*head.dim);
+# endif
+ gzclose(gzf);
+
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+template <class T>
+void readPdataUni(const std::string& name, ParticleDataImpl<T>* pdata ) {
+ debMsg( "reading particle data " << pdata->getName() << " from uni file " << name ,1);
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("can't open file " << name );
+
+ char ID[5]={0,0,0,0,0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "PD01")) {
+ UniPartHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniPartHeader)) == sizeof(UniPartHeader), "can't read file, no header present");
+ assertMsg (head.dim == pdata->size() , "pdata size doesn't match");
+# if FLOATINGPOINT_PRECISION!=1
+ ParticleDataImpl<T> temp(pdata->getParent());
+ temp.resize( pdata->size() );
+ pdataReadConvert<T>(gzf, *pdata, &(temp[0]), head.bytesPerElement);
+# else
+ assertMsg ( ((head.bytesPerElement == sizeof(T)) && (head.elementType==1) ), "pdata type doesn't match");
+ IndexInt bytes = sizeof(T)*head.dim;
+ IndexInt readBytes = gzread(gzf, &(pdata->get(0)), sizeof(T)*head.dim);
+ assertMsg(bytes==readBytes, "can't read uni file, stream length does not match, "<<bytes<<" vs "<<readBytes );
+# endif
+ }
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+
+
+
+// explicit instantiation
+template void writePdataUni<int> (const std::string& name, ParticleDataImpl<int>* pdata );
+template void writePdataUni<Real>(const std::string& name, ParticleDataImpl<Real>* pdata );
+template void writePdataUni<Vec3>(const std::string& name, ParticleDataImpl<Vec3>* pdata );
+template void readPdataUni<int> (const std::string& name, ParticleDataImpl<int>* pdata );
+template void readPdataUni<Real> (const std::string& name, ParticleDataImpl<Real>* pdata );
+template void readPdataUni<Vec3> (const std::string& name, ParticleDataImpl<Vec3>* pdata );
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h
new file mode 100644
index 00000000000..bac0c46e948
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h
@@ -0,0 +1,83 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and meshes to disk
+ *
+ ******************************************************************************/
+
+#ifndef _FILEIO_H
+#define _FILEIO_H
+
+#include <string>
+
+namespace Manta {
+
+// forward decl.
+class Mesh;
+class FlagGrid;
+template<class T> class Grid;
+template<class T> class Grid4d;
+class BasicParticleSystem;
+template<class T> class ParticleDataImpl;
+template<class T> class MeshDataImpl;
+
+void writeObjFile(const std::string& name, Mesh* mesh);
+void writeBobjFile(const std::string& name, Mesh* mesh);
+void readObjFile(const std::string& name, Mesh* mesh, bool append);
+void readBobjFile(const std::string& name, Mesh* mesh, bool append);
+
+template<class T> void writeGridRaw(const std::string& name, Grid<T>* grid);
+template<class T> void writeGridUni(const std::string& name, Grid<T>* grid);
+template<class T> void writeGridVol(const std::string& name, Grid<T>* grid);
+template<class T> void writeGridTxt(const std::string& name, Grid<T>* grid);
+
+#if OPENVDB==1
+template<class T> void writeGridVDB(const std::string& name, Grid<T>* grid);
+template<class T> void readGridVDB(const std::string& name, Grid<T>* grid);
+#endif // OPENVDB==1
+template<class T> void writeGridNumpy(const std::string& name, Grid<T>* grid);
+template<class T> void readGridNumpy (const std::string& name, Grid<T>* grid);
+
+template<class T> void readGridUni (const std::string& name, Grid<T>* grid);
+template<class T> void readGridRaw (const std::string& name, Grid<T>* grid);
+template<class T> void readGridVol (const std::string& name, Grid<T>* grid);
+
+template<class T> void writeGrid4dUni(const std::string& name, Grid4d<T>* grid);
+template<class T> void readGrid4dUni (const std::string& name, Grid4d<T>* grid, int readTslice=-1, Grid4d<T>* slice=NULL, void** fileHandle=NULL);
+void readGrid4dUniCleanup(void** fileHandle);
+template<class T> void writeGrid4dRaw(const std::string& name, Grid4d<T>* grid);
+template<class T> void readGrid4dRaw (const std::string& name, Grid4d<T>* grid);
+
+void writeParticlesUni(const std::string& name, const BasicParticleSystem* parts );
+void readParticlesUni (const std::string& name, BasicParticleSystem* parts );
+
+template <class T> void writePdataUni(const std::string& name, ParticleDataImpl<T>* pdata );
+template <class T> void readPdataUni (const std::string& name, ParticleDataImpl<T>* pdata );
+
+template <class T> void writeMdataUni(const std::string& name, MeshDataImpl<T>* mdata );
+template <class T> void readMdataUni (const std::string& name, MeshDataImpl<T>* mdata );
+
+void getUniFileSize(const std::string& name, int& x, int& y, int& z, int* t = NULL, std::string* info = NULL);
+
+} // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h.reg
new file mode 100644
index 00000000000..874b2834685
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h.reg
@@ -0,0 +1 @@
+#include "fileio/mantaio.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h.reg.cpp
new file mode 100644
index 00000000000..b87835606f7
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fileio/mantaio.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "fileio/mantaio.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_18()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.cpp
new file mode 100644
index 00000000000..aae4a03196d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.cpp
@@ -0,0 +1,296 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Main class for the fluid solver
+ *
+ ******************************************************************************/
+
+#include "fluidsolver.h"
+#include "grid.h"
+#include <sstream>
+#include <fstream>
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// Gridstorage-related members
+
+template<class T>
+void FluidSolver::GridStorage<T>::free() {
+ if (used != 0)
+ errMsg("can't clean grid cache, some grids are still in use");
+ for(size_t i = 0; i<grids.size(); i++)
+ delete[] grids[i];
+ grids.clear();
+}
+template<class T>
+T* FluidSolver::GridStorage<T>::get(Vec3i size) {
+ if ((int)grids.size() <= used) {
+ debMsg("FluidSolver::GridStorage::get Allocating new "<<size.x<<","<<size.y<<","<<size.z<<" ",3);
+ grids.push_back( new T[(long long)(size.x) * size.y * size.z] );
+ }
+ if (used > 200)
+ errMsg("too many temp grids used -- are they released properly ?");
+ return grids[used++];
+}
+template<class T>
+void FluidSolver::GridStorage<T>::release(T* ptr) {
+ // rewrite pointer, as it may have changed due to swap operations
+ used--;
+ if (used < 0)
+ errMsg("temp grid inconsistency");
+ grids[used] = ptr;
+}
+
+template<> int* FluidSolver::getGridPointer<int>() {
+ return mGridsInt.get(mGridSize);
+}
+template<> Real* FluidSolver::getGridPointer<Real>() {
+ return mGridsReal.get(mGridSize);
+}
+template<> Vec3* FluidSolver::getGridPointer<Vec3>() {
+ return mGridsVec.get(mGridSize);
+}
+template<> Vec4* FluidSolver::getGridPointer<Vec4>() {
+ return mGridsVec4.get(mGridSize);
+}
+template<> void FluidSolver::freeGridPointer<int>(int *ptr) {
+ mGridsInt.release(ptr);
+}
+template<> void FluidSolver::freeGridPointer<Real>(Real* ptr) {
+ mGridsReal.release(ptr);
+}
+template<> void FluidSolver::freeGridPointer<Vec3>(Vec3* ptr) {
+ mGridsVec.release(ptr);
+}
+template<> void FluidSolver::freeGridPointer<Vec4>(Vec4* ptr) {
+ mGridsVec4.release(ptr);
+}
+
+// 4d data (work around for now, convert to 1d length)
+
+template<> int* FluidSolver::getGrid4dPointer<int>() {
+ return mGrids4dInt.get( Vec3i(mGridSize[0]*mGridSize[1],mGridSize[2],mFourthDim) );
+}
+template<> Real* FluidSolver::getGrid4dPointer<Real>() {
+ return mGrids4dReal.get( Vec3i(mGridSize[0]*mGridSize[1],mGridSize[2],mFourthDim) );
+}
+template<> Vec3* FluidSolver::getGrid4dPointer<Vec3>() {
+ return mGrids4dVec.get( Vec3i(mGridSize[0]*mGridSize[1],mGridSize[2],mFourthDim) );
+}
+template<> Vec4* FluidSolver::getGrid4dPointer<Vec4>() {
+ return mGrids4dVec4.get( Vec3i(mGridSize[0]*mGridSize[1],mGridSize[2],mFourthDim) );
+}
+template<> void FluidSolver::freeGrid4dPointer<int>(int *ptr) {
+ mGrids4dInt.release(ptr);
+}
+template<> void FluidSolver::freeGrid4dPointer<Real>(Real* ptr) {
+ mGrids4dReal.release(ptr);
+}
+template<> void FluidSolver::freeGrid4dPointer<Vec3>(Vec3* ptr) {
+ mGrids4dVec.release(ptr);
+}
+template<> void FluidSolver::freeGrid4dPointer<Vec4>(Vec4* ptr) {
+ mGrids4dVec4.release(ptr);
+}
+
+//******************************************************************************
+// FluidSolver members
+
+FluidSolver::FluidSolver(Vec3i gridsize, int dim, int fourthDim)
+ : PbClass(this), mDt(1.0), mTimeTotal(0.), mFrame(0),
+ mCflCond(1000), mDtMin(1.), mDtMax(1.), mFrameLength(1.),
+ mGridSize(gridsize), mDim(dim) , mTimePerFrame(0.), mLockDt(false), mFourthDim(fourthDim)
+{
+ if(dim==4 && mFourthDim>0) errMsg("Don't create 4D solvers, use 3D with fourth-dim parameter >0 instead.");
+ assertMsg(dim==2 || dim==3, "Only 2D and 3D solvers allowed.");
+ assertMsg(dim!=2 || gridsize.z == 1, "Trying to create 2D solver with size.z != 1");
+}
+
+FluidSolver::~FluidSolver() {
+ mGridsInt.free();
+ mGridsReal.free();
+ mGridsVec.free();
+ mGridsVec4.free();
+
+ mGrids4dInt.free();
+ mGrids4dReal.free();
+ mGrids4dVec.free();
+ mGrids4dVec4.free();
+}
+
+PbClass* FluidSolver::create(PbType t, PbTypeVec T, const string& name) {
+# if NOPYTHON!=1
+ _args.add("nocheck",true);
+ if (t.str() == "")
+ errMsg("Need to specify object type. Use e.g. Solver.create(FlagGrid, ...) or Solver.create(type=FlagGrid, ...)");
+
+ PbClass* ret = PbClass::createPyObject(t.str() + T.str(), name, _args, this);
+# else
+ PbClass* ret = NULL;
+# endif
+ return ret;
+}
+
+void FluidSolver::step() {
+ // update simulation time with adaptive time stepping
+ // (use eps value to prevent roundoff errors)
+ mTimePerFrame += mDt;
+ mTimeTotal += mDt;
+
+ if( (mTimePerFrame+VECTOR_EPSILON) >mFrameLength) {
+ mFrame++;
+
+ // re-calc total time, prevent drift...
+ mTimeTotal = (double)mFrame * mFrameLength;
+ mTimePerFrame = 0.;
+ mLockDt = false;
+ }
+
+ updateQtGui(true, mFrame,mTimeTotal, "FluidSolver::step");
+}
+
+void FluidSolver::printMemInfo() {
+ std::ostringstream msg;
+ msg << "Allocated grids: int " << mGridsInt.used <<"/"<< mGridsInt.grids.size() <<", ";
+ msg << " real "<< mGridsReal.used <<"/"<< mGridsReal.grids.size() <<", ";
+ msg << " vec3 "<< mGridsVec.used <<"/"<< mGridsVec.grids.size() <<". ";
+ msg << " vec4 "<< mGridsVec4.used <<"/"<< mGridsVec4.grids.size() <<". ";
+ if( supports4D() ) {
+ msg << "Allocated 4d grids: int " << mGrids4dInt.used <<"/"<< mGrids4dInt.grids.size() <<", ";
+ msg << " real "<< mGrids4dReal.used <<"/"<< mGrids4dReal.grids.size() <<", ";
+ msg << " vec3 "<< mGrids4dVec.used <<"/"<< mGrids4dVec.grids.size() <<". ";
+ msg << " vec4 "<< mGrids4dVec4.used <<"/"<< mGrids4dVec4.grids.size() <<". "; }
+ printf("%s\n", msg.str().c_str() );
+}
+
+//! warning, uses 10^-4 epsilon values, thus only use around "regular" FPS time scales, e.g. 30 frames per time unit
+//! pass max magnitude of current velocity as maxvel, not yet scaled by dt!
+void FluidSolver::adaptTimestep(Real maxVel)
+{
+ const Real mvt = maxVel * mDt;
+ if (!mLockDt) {
+ // calculate current timestep from maxvel, clamp range
+ mDt = std::max( std::min( mDt * (Real)(mCflCond/(mvt+1e-05)), mDtMax) , mDtMin );
+ if( (mTimePerFrame+mDt*1.05) > mFrameLength ) {
+ // within 5% of full step? add epsilon to prevent roundoff errors...
+ mDt = ( mFrameLength - mTimePerFrame ) + 1e-04;
+ }
+ else if ( (mTimePerFrame+mDt + mDtMin) > mFrameLength || (mTimePerFrame+(mDt*1.25)) > mFrameLength ) {
+ // avoid tiny timesteps and strongly varying ones, do 2 medium size ones if necessary...
+ mDt = (mFrameLength-mTimePerFrame+ 1e-04)*0.5;
+ mLockDt = true;
+ }
+ }
+ debMsg( "Frame "<<mFrame<<", max vel per step: "<<mvt<<" , dt: "<<mDt<<", frame time "<<mTimePerFrame<<"/"<<mFrameLength<<"; lock:"<<mLockDt , 2);
+
+ // sanity check
+ assertMsg( (mDt > (mDtMin/2.) ) , "Invalid dt encountered! Shouldnt happen..." );
+}
+
+//******************************************************************************
+// Generic helpers (no PYTHON funcs in general.cpp, thus they're here...)
+
+//! helper to unify printing from python scripts and printing internal messages (optionally pass debug level to control amount of output)
+void mantaMsg(const std::string& out, int level=1) {
+ debMsg( out, level );
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mantaMsg" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string& out = _args.get<std::string >("out",0,&_lock); int level = _args.getOpt<int >("level",1,1,&_lock); _retval = getPyNone(); mantaMsg(out,level); _args.check(); }
+ pbFinalizePlugin(parent,"mantaMsg", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mantaMsg",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mantaMsg ("","mantaMsg",_W_0);
+extern "C" {
+ void PbRegister_mantaMsg() {
+ KEEP_UNUSED(_RP_mantaMsg); }
+ }
+
+
+
+std::string printBuildInfo() {
+ string infoString = buildInfoString();
+ debMsg( "Build info: "<<infoString.c_str()<<" ",1);
+ return infoString;
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "printBuildInfo" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; _retval = toPy(printBuildInfo()); _args.check(); }
+ pbFinalizePlugin(parent,"printBuildInfo", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("printBuildInfo",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_printBuildInfo ("","printBuildInfo",_W_1);
+extern "C" {
+ void PbRegister_printBuildInfo() {
+ KEEP_UNUSED(_RP_printBuildInfo); }
+ }
+
+
+
+//! set debug level for messages (0 off, 1 regular, higher = more, up to 10)
+void setDebugLevel(int level=1) {
+ gDebugLevel = level;
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setDebugLevel" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; int level = _args.getOpt<int >("level",0,1,&_lock); _retval = getPyNone(); setDebugLevel(level); _args.check(); }
+ pbFinalizePlugin(parent,"setDebugLevel", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setDebugLevel",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setDebugLevel ("","setDebugLevel",_W_2);
+extern "C" {
+ void PbRegister_setDebugLevel() {
+ KEEP_UNUSED(_RP_setDebugLevel); }
+ }
+
+
+
+//! helper function to check for numpy compilation
+void assertNumpy() {
+#if NUMPY==1
+ // all good, nothing to do...
+#else
+ errMsg("This scene requires numpy support. Enable compilation in cmake with \"-DNUMPY=1\" ");
+#endif
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "assertNumpy" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; _retval = getPyNone(); assertNumpy(); _args.check(); }
+ pbFinalizePlugin(parent,"assertNumpy", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("assertNumpy",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_assertNumpy ("","assertNumpy",_W_3);
+extern "C" {
+ void PbRegister_assertNumpy() {
+ KEEP_UNUSED(_RP_assertNumpy); }
+ }
+
+
+
+} // manta
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h
new file mode 100644
index 00000000000..a89a3ed5ccf
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h
@@ -0,0 +1,220 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Main class for the fluid solver
+ *
+ ******************************************************************************/
+
+#ifndef _FLUIDSOLVER_H
+#define _FLUIDSOLVER_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "vector4d.h"
+#include <vector>
+#include <map>
+
+namespace Manta {
+
+//! Encodes grid size, timstep etc.
+
+class FluidSolver : public PbClass {public:
+ FluidSolver(Vec3i gridSize, int dim=3, int fourthDim=-1); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "FluidSolver::FluidSolver" , !noTiming ); {
+ ArgLocker _lock; Vec3i gridSize = _args.get<Vec3i >("gridSize",0,&_lock); int dim = _args.getOpt<int >("dim",1,3,&_lock); int fourthDim = _args.getOpt<int >("fourthDim",2,-1,&_lock); obj = new FluidSolver(gridSize,dim,fourthDim); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"FluidSolver::FluidSolver" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::FluidSolver",e.what()); return -1; }
+ }
+
+ virtual ~FluidSolver();
+
+ // accessors
+ Vec3i getGridSize() { return mGridSize; } static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FluidSolver::getGridSize" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getGridSize()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FluidSolver::getGridSize" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::getGridSize",e.what()); return 0; }
+ }
+
+ inline Real getDt() { return mDt; }
+ inline Real getDx() { return 1.0 / mGridSize.max(); }
+ inline Real getTime() { return mTimeTotal; }
+ inline Real getFrameLength() { return mFrameLength; }
+
+ //! Check dimensionality
+ inline bool is2D() const { return mDim==2; }
+ //! Check dimensionality (3d or above)
+ inline bool is3D() const { return mDim==3; }
+
+ void printMemInfo(); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FluidSolver::printMemInfo" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->printMemInfo(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FluidSolver::printMemInfo" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::printMemInfo",e.what()); return 0; }
+ }
+
+
+ //! Advance the solver one timestep, update GUI if present
+ void step(); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FluidSolver::step" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->step(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FluidSolver::step" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::step",e.what()); return 0; }
+ }
+
+
+ //! Update the timestep size based on given maximal velocity magnitude
+ void adaptTimestep(Real maxVel); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FluidSolver::adaptTimestep" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real maxVel = _args.get<Real >("maxVel",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->adaptTimestep(maxVel); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FluidSolver::adaptTimestep" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::adaptTimestep",e.what()); return 0; }
+ }
+
+
+ //! create a object with the solver as its parent
+ PbClass* create(PbType type, PbTypeVec T=PbTypeVec(),const std::string& name = ""); static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FluidSolver::create" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; PbType type = _args.get<PbType >("type",0,&_lock); PbTypeVec T = _args.getOpt<PbTypeVec >("T",1,PbTypeVec(),&_lock); const std::string& name = _args.getOpt<std::string >("name",2,"",&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->create(type,T,name)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FluidSolver::create" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FluidSolver::create",e.what()); return 0; }
+ }
+
+
+ // temp grid and plugin functions: you shouldn't call this manually
+ template<class T> T* getGridPointer();
+ template<class T> void freeGridPointer(T* ptr);
+
+ //! expose animation time to python
+ Real mDt;static PyObject* _GET_mDt(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mDt); }
+ static int _SET_mDt(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mDt = fromPy<Real >(val); return 0; }
+
+ Real mTimeTotal;static PyObject* _GET_mTimeTotal(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mTimeTotal); }
+ static int _SET_mTimeTotal(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mTimeTotal = fromPy<Real >(val); return 0; }
+
+ int mFrame;static PyObject* _GET_mFrame(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mFrame); }
+ static int _SET_mFrame(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mFrame = fromPy<int >(val); return 0; }
+
+ //! parameters for adaptive time stepping
+ Real mCflCond;static PyObject* _GET_mCflCond(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mCflCond); }
+ static int _SET_mCflCond(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mCflCond = fromPy<Real >(val); return 0; }
+
+ Real mDtMin;static PyObject* _GET_mDtMin(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mDtMin); }
+ static int _SET_mDtMin(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mDtMin = fromPy<Real >(val); return 0; }
+
+ Real mDtMax;static PyObject* _GET_mDtMax(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mDtMax); }
+ static int _SET_mDtMax(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mDtMax = fromPy<Real >(val); return 0; }
+
+ Real mFrameLength;static PyObject* _GET_mFrameLength(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mFrameLength); }
+ static int _SET_mFrameLength(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mFrameLength = fromPy<Real >(val); return 0; }
+
+#ifdef BLENDER
+ //! Blender needs access in order to restore value in new solver object
+ Real mTimePerFrame;static PyObject* _GET_mTimePerFrame(PyObject* self, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); return toPy(pbo->mTimePerFrame); }
+ static int _SET_mTimePerFrame(PyObject* self, PyObject* val, void* cl) {
+ FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(self)); pbo->mTimePerFrame = fromPy<Real >(val); return 0; }
+
+#endif
+
+protected:
+ Vec3i mGridSize;
+ const int mDim;
+ bool mLockDt;
+#ifndef BLENDER
+ //! Blender needs public access to this field, see above
+ Real mTimePerFrame;
+#endif
+
+ //! subclass for managing grid memory
+ //! stored as a stack to allow fast allocation
+ template<class T> struct GridStorage {
+ GridStorage() : used(0) {}
+ T* get(Vec3i size);
+ void free();
+ void release(T* ptr);
+
+ std::vector<T*> grids;
+ int used;
+ };
+
+ //! memory for regular (3d) grids
+ GridStorage<int> mGridsInt;
+ GridStorage<Real> mGridsReal;
+ GridStorage<Vec3> mGridsVec;
+
+
+ //! 4d data section, only required for simulations working with space-time data
+
+public:
+ //! 4D enabled? note, there's intentionally no "is4D" function, there are only 3D solvers that also support 4D of a certain size
+ inline bool supports4D() const { return mFourthDim>0; }
+ //! fourth dimension size
+ inline int getFourthDim() const { return mFourthDim; }
+ //! 4d data allocation
+ template<class T> T* getGrid4dPointer();
+ template<class T> void freeGrid4dPointer(T* ptr);
+
+protected:
+
+ //! 4d size. Note - 4d is not treated like going from 2d to 3d! 4D grids are a separate data type. Normally all
+ //! grids are forced to have the same size. In contrast, a solver can create and work with 3D as
+ //! well as 4D grids, when fourth-dim is >0.
+ int mFourthDim;
+
+ //! 4d grid storage
+ GridStorage<Vec4> mGridsVec4;
+ GridStorage<int> mGrids4dInt;
+ GridStorage<Real> mGrids4dReal;
+ GridStorage<Vec3> mGrids4dVec; GridStorage<Vec4> mGrids4dVec4; public: PbArgs _args; }
+#define _C_FluidSolver
+;
+
+}
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h.reg
new file mode 100644
index 00000000000..68ed956e40d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h.reg
@@ -0,0 +1,17 @@
+#include "fluidsolver.h"
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","Solver","PbClass"); template<> const char* Namify<FluidSolver >::S = "FluidSolver";
+>FluidSolver^
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","FluidSolver",FluidSolver::_W_0);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","getGridSize",FluidSolver::_W_1);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","printMemInfo",FluidSolver::_W_2);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","step",FluidSolver::_W_3);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","adaptTimestep",FluidSolver::_W_4);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","create",FluidSolver::_W_5);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","timestep",FluidSolver::_GET_mDt,FluidSolver::_SET_mDt);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","timeTotal",FluidSolver::_GET_mTimeTotal,FluidSolver::_SET_mTimeTotal);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","frame",FluidSolver::_GET_mFrame,FluidSolver::_SET_mFrame);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","cfl",FluidSolver::_GET_mCflCond,FluidSolver::_SET_mCflCond);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","timestepMin",FluidSolver::_GET_mDtMin,FluidSolver::_SET_mDtMin);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","timestepMax",FluidSolver::_GET_mDtMax,FluidSolver::_SET_mDtMax);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","frameLength",FluidSolver::_GET_mFrameLength,FluidSolver::_SET_mFrameLength);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","timePerFrame",FluidSolver::_GET_mTimePerFrame,FluidSolver::_SET_mTimePerFrame);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h.reg.cpp
new file mode 100644
index 00000000000..9ad461fb974
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/fluidsolver.h.reg.cpp
@@ -0,0 +1,50 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "fluidsolver.h"
+namespace Manta {
+#ifdef _C_FluidSolver
+ static const Pb::Register _R_6 ("FluidSolver","Solver","PbClass"); template<> const char* Namify<FluidSolver >::S = "FluidSolver";
+ static const Pb::Register _R_7 ("FluidSolver","FluidSolver",FluidSolver::_W_0);
+ static const Pb::Register _R_8 ("FluidSolver","getGridSize",FluidSolver::_W_1);
+ static const Pb::Register _R_9 ("FluidSolver","printMemInfo",FluidSolver::_W_2);
+ static const Pb::Register _R_10 ("FluidSolver","step",FluidSolver::_W_3);
+ static const Pb::Register _R_11 ("FluidSolver","adaptTimestep",FluidSolver::_W_4);
+ static const Pb::Register _R_12 ("FluidSolver","create",FluidSolver::_W_5);
+ static const Pb::Register _R_13 ("FluidSolver","timestep",FluidSolver::_GET_mDt,FluidSolver::_SET_mDt);
+ static const Pb::Register _R_14 ("FluidSolver","timeTotal",FluidSolver::_GET_mTimeTotal,FluidSolver::_SET_mTimeTotal);
+ static const Pb::Register _R_15 ("FluidSolver","frame",FluidSolver::_GET_mFrame,FluidSolver::_SET_mFrame);
+ static const Pb::Register _R_16 ("FluidSolver","cfl",FluidSolver::_GET_mCflCond,FluidSolver::_SET_mCflCond);
+ static const Pb::Register _R_17 ("FluidSolver","timestepMin",FluidSolver::_GET_mDtMin,FluidSolver::_SET_mDtMin);
+ static const Pb::Register _R_18 ("FluidSolver","timestepMax",FluidSolver::_GET_mDtMax,FluidSolver::_SET_mDtMax);
+ static const Pb::Register _R_19 ("FluidSolver","frameLength",FluidSolver::_GET_mFrameLength,FluidSolver::_SET_mFrameLength);
+ static const Pb::Register _R_20 ("FluidSolver","timePerFrame",FluidSolver::_GET_mTimePerFrame,FluidSolver::_SET_mTimePerFrame);
+#endif
+extern "C" {
+void PbRegister_file_6()
+{
+ KEEP_UNUSED(_R_6);
+ KEEP_UNUSED(_R_7);
+ KEEP_UNUSED(_R_8);
+ KEEP_UNUSED(_R_9);
+ KEEP_UNUSED(_R_10);
+ KEEP_UNUSED(_R_11);
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.cpp
new file mode 100644
index 00000000000..c165533c898
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.cpp
@@ -0,0 +1,165 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Globally used macros and functions (e.g. time measurements),
+ * and doxygen documentation collection.
+ *
+ ******************************************************************************/
+
+
+/*! \mainpage Welcome to mantaflow!
+ *
+ * Here you can find the auto-generated documentation of the mantaflow framework.
+ *
+ * One of the most useful parts is probably the list of python functions, classes and the C++ kernels.
+ * Those can be found found in the ''Modules'' section. For python functions the parameters (e.g. Grids, Real or int values)
+ * are automatically transferred to and from python. Thus, this list is a good reference how to call the functions used in the
+ * example scenes.
+ *
+ */
+
+// Define plugin documentation group
+// all kernels, plugin functions and classes will automatically be added to this group
+//! @defgroup Plugins Functions callable from Python
+//! @defgroup PyClasses Classes exposed to Python
+//! @defgroup Kernels Computation Kernels
+
+#include "general.h"
+#if defined(WIN32) || defined(_WIN32)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+# undef NOMINMAX
+#else
+# include <sys/time.h>
+# include "gitinfo.h"
+#endif
+
+using namespace std;
+
+namespace Manta {
+
+int gDebugLevel = 1;
+
+void MuTime::get() {
+#if defined(WIN32) || defined(_WIN32)
+ LARGE_INTEGER liTimerFrequency;
+ QueryPerformanceFrequency(&liTimerFrequency);
+ LARGE_INTEGER liLastTime;
+ QueryPerformanceCounter(&liLastTime);
+ time = (INT)( ((double)liLastTime.QuadPart / liTimerFrequency.QuadPart)*1000 );
+#else
+ struct timeval tv;
+ struct timezone tz;
+ tz.tz_minuteswest = 0;
+ tz.tz_dsttime = 0;
+ gettimeofday(&tv,&tz);
+ time = (tv.tv_sec*1000)+(tv.tv_usec/1000);
+#endif
+}
+
+MuTime MuTime::update() {
+ MuTime o = *this;
+ get();
+ return *this - o;
+}
+
+string MuTime::toString() {
+ stringstream ss;
+ ss << *this;
+ return ss.str();
+}
+
+ostream& operator<<(ostream& os, const MuTime& t) {
+ unsigned long ms = (unsigned long)( (double)t.time / (60.0*1000.0) );
+ unsigned long ss = (unsigned long)( ((double)t.time / 1000.0) - ((double)ms*60.0) );
+ int ps = (int)( ((double)t.time - (double)ss*1000.0)/1.0 );
+
+ if(ms>0) {
+ os << ms<<"m"<< ss<<"s" ;
+ } else {
+ if(ps>0) {
+ os << ss<<".";
+ if(ps<10) { os <<"0"; }
+ if(ps<100) { os <<"0"; }
+ os <<ps<<"s" ;
+ } else {
+ os << ss<<"s" ;
+ }
+ }
+ return os;
+}
+
+//! print info about this mantaflow build, used eg by printBuildInfo in fluidsolver.cpp
+std::string buildInfoString() {
+ std::ostringstream infoStr;
+# ifndef MANTAVERSION
+# define MANTAVERSION "<unknown-version>"
+# endif
+ infoStr << "mantaflow " << MANTAVERSION;
+
+ // os
+#if defined(WIN32) || defined(_WIN32)
+ infoStr << " win";
+# endif
+# ifdef __APPLE__
+ infoStr << " mac";
+# endif
+# ifdef LINUX
+ infoStr << " linux";
+# endif
+
+ // 32/64 bit
+ if (sizeof(size_t) == 8)
+ infoStr << " 64bit";
+ else
+ infoStr << " 32bit";
+
+ // fp precision
+# if FLOATINGPOINT_PRECISION==2
+ infoStr << " fp2";
+# else
+ infoStr << " fp1";
+# endif
+
+ // other compile switches
+# ifdef DEBUG
+ infoStr << " debug";
+# endif
+# ifdef OPENMP
+ infoStr << " omp";
+# endif
+
+ // repository info (git commit id)
+# ifndef MANTA_GIT_VERSION
+# define MANTA_GIT_VERSION "<unknown-commit>"
+# endif
+ infoStr << " "<< MANTA_GIT_VERSION;
+
+ infoStr << " from "<< __DATE__<<", "<<__TIME__;
+ return infoStr.str();
+}
+
+//! note - generic PYTHON helpers in fluidsolver.cpp , no python bindings here
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h
new file mode 100644
index 00000000000..71f453a6128
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h
@@ -0,0 +1,173 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Globally used macros and functions
+ *
+ ******************************************************************************/
+
+#ifndef _GENERAL_H
+#define _GENERAL_H
+
+#include <iostream>
+#include <sstream>
+#include <cmath>
+#include <algorithm>
+
+namespace Manta {
+
+// ui data exchange
+#ifdef GUI
+ // defined in qtmain.cpp
+ extern void updateQtGui(bool full, int frame, float time, const std::string& curPlugin);
+#else
+ // dummy function if GUI is not enabled
+ inline void updateQtGui(bool full, int frame, float time, const std::string& curPlugin) {}
+#endif
+
+
+// activate debug mode if _DEBUG is defined (eg for windows)
+#ifndef DEBUG
+#ifdef _DEBUG
+#define DEBUG 1
+#endif // _DEBUG
+#endif // DEBUG
+
+// Standard exception
+class Error : public std::exception
+{
+public:
+ Error(const std::string& s) : mS(s) {
+# ifdef DEBUG
+ // print error
+ std::cerr << "Aborting: "<< s <<" \n";
+ // then force immedieate crash in debug mode
+ *(volatile int*)(0) = 1;
+# endif
+ }
+ virtual ~Error() throw() {}
+ virtual const char* what() const throw() { return mS.c_str(); }
+private:
+ std::string mS;
+};
+
+// mark unused parameter variables
+#define unusedParameter(x) ((void)x)
+
+// Debug output functions and macros
+extern int gDebugLevel;
+
+#define MSGSTREAM std::ostringstream msg; msg.precision(7); msg.width(9);
+#define debMsg(mStr, level) if (_chklevel(level)) { MSGSTREAM; msg << mStr; std::cout << msg.str() << std::endl; }
+inline bool _chklevel(int level=0) { return gDebugLevel >= level; }
+
+// error and assertation macros
+#ifdef DEBUG
+# define DEBUG_ONLY(a) a
+#else
+# define DEBUG_ONLY(a)
+#endif
+#define throwError(msg) { std::ostringstream __s; __s << msg << std::endl << "Error raised in " << __FILE__ << ":" << __LINE__; throw Manta::Error(__s.str()); }
+#define errMsg(msg) throwError(msg);
+#define assertMsg(cond,msg) if(!(cond)) throwError(msg)
+#define assertDeb(cond,msg) DEBUG_ONLY( assertMsg(cond,msg) )
+
+// for compatibility with blender, blender only defines WITH_MANTA, make sure we have "BLENDER"
+#ifndef BLENDER
+#ifdef WITH_MANTA
+#define BLENDER 1
+#endif
+#endif
+
+// common type for indexing large grids
+typedef long long IndexInt;
+
+// template tricks
+template<typename T>
+struct remove_pointers {
+ typedef T type;
+};
+
+template<typename T>
+struct remove_pointers<T*> {
+ typedef T type;
+};
+
+template<typename T>
+struct remove_pointers<T&> {
+ typedef T type;
+};
+
+// Commonly used enums and types
+//! Timing class for preformance measuring
+struct MuTime {
+ MuTime() { get(); }
+ MuTime operator-(const MuTime& a) { MuTime b; b.time = time - a.time; return b; };
+ MuTime operator+(const MuTime& a) { MuTime b; b.time = time + a.time; return b; };
+ MuTime operator/(unsigned long a) { MuTime b; b.time = time / a; return b; };
+ MuTime& operator+=(const MuTime& a) { time += a.time; return *this; }
+ MuTime& operator-=(const MuTime& a) { time -= a.time; return *this; }
+ MuTime& operator/=(unsigned long a) { time /= a; return *this; }
+ std::string toString();
+
+ void clear() { time = 0; }
+ void get();
+ MuTime update();
+
+ unsigned long time;
+};
+std::ostream& operator<< (std::ostream& os, const MuTime& t);
+
+//! generate a string with infos about the current mantaflow build
+std::string buildInfoString();
+
+// Some commonly used math helpers
+template<class T> inline T square(T a) {
+ return a*a;
+}
+template<class T> inline T cubed(T a) {
+ return a*a*a;
+}
+
+template<class T> inline T clamp(const T& val, const T& vmin, const T& vmax) {
+ if (val < vmin) return vmin;
+ if (val > vmax) return vmax;
+ return val;
+}
+
+template<class T> inline T nmod(const T& a, const T& b);
+template<> inline int nmod(const int& a, const int& b) { int c=a%b; return (c<0) ? (c+b) : c; }
+template<> inline float nmod(const float& a, const float& b) { float c=std::fmod(a,b); return (c<0) ? (c+b) : c; }
+template<> inline double nmod(const double& a, const double& b) { double c=std::fmod(a,b); return (c<0) ? (c+b) : c; }
+
+template<class T> inline T safeDivide(const T& a, const T& b);
+template<> inline int safeDivide<int>(const int &a, const int& b) { return (b) ? (a/b) : a; }
+template<> inline float safeDivide<float>(const float &a, const float& b) { return (b) ? (a/b) : a; }
+template<> inline double safeDivide<double>(const double &a, const double& b) { return (b) ? (a/b) : a; }
+
+inline bool c_isnan(float c) {
+ volatile float d=c;
+ return d != d;
+}
+
+} // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h.reg
new file mode 100644
index 00000000000..65a276295d5
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h.reg
@@ -0,0 +1 @@
+#include "general.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h.reg.cpp
new file mode 100644
index 00000000000..44b2155020f
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/general.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "general.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_1()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/gitinfo.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/gitinfo.h
new file mode 100644
index 00000000000..b696431ac9e
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/gitinfo.h
@@ -0,0 +1,4 @@
+
+
+#define MANTA_GIT_VERSION "commit 0793c3c5f60deedee26289afcc135a0c15de96a3"
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.cpp
new file mode 100644
index 00000000000..bac8300ebdb
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.cpp
@@ -0,0 +1,1522 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#include "grid.h"
+#include "levelset.h"
+#include "kernel.h"
+#include "mantaio.h"
+#include <limits>
+#include <sstream>
+#include <cstring>
+
+#include "commonkernels.h"
+
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// GridBase members
+
+GridBase::GridBase (FluidSolver* parent)
+ : PbClass(parent), mType(TypeNone)
+{
+ checkParent();
+ m3D = getParent()->is3D();
+}
+
+//******************************************************************************
+// Grid<T> members
+
+// helpers to set type
+template<class T> inline GridBase::GridType typeList() { return GridBase::TypeNone; }
+template<> inline GridBase::GridType typeList<Real>() { return GridBase::TypeReal; }
+template<> inline GridBase::GridType typeList<int>() { return GridBase::TypeInt; }
+template<> inline GridBase::GridType typeList<Vec3>() { return GridBase::TypeVec3; }
+
+template<class T>
+Grid<T>::Grid(FluidSolver* parent, bool show)
+ : GridBase(parent), externalData(false)
+{
+ mType = typeList<T>();
+ mSize = parent->getGridSize();
+ mData = parent->getGridPointer<T>();
+
+ mStrideZ = parent->is2D() ? 0 : (mSize.x * mSize.y);
+ mDx = 1.0 / mSize.max();
+ clear();
+ setHidden(!show);
+}
+
+template<class T>
+Grid<T>::Grid(FluidSolver* parent, T* data, bool show)
+ : GridBase(parent), mData(data), externalData(true)
+{
+ mType = typeList<T>();
+ mSize = parent->getGridSize();
+
+ mStrideZ = parent->is2D() ? 0 : (mSize.x * mSize.y);
+ mDx = 1.0 / mSize.max();
+
+ setHidden(!show);
+}
+
+template<class T>
+Grid<T>::Grid(const Grid<T>& a)
+ : GridBase(a.getParent()), externalData(false) {
+ mSize = a.mSize;
+ mType = a.mType;
+ mStrideZ = a.mStrideZ;
+ mDx = a.mDx;
+ FluidSolver *gp = a.getParent();
+ mData = gp->getGridPointer<T>();
+ memcpy(mData, a.mData, sizeof(T) * a.mSize.x * a.mSize.y * a.mSize.z);
+}
+
+template<class T>
+Grid<T>::~Grid() {
+ if(!externalData) {
+ mParent->freeGridPointer<T>(mData);
+ }
+}
+
+template<class T>
+void Grid<T>::clear() {
+ memset(mData, 0, sizeof(T) * mSize.x * mSize.y * mSize.z);
+}
+
+template<class T>
+void Grid<T>::swap(Grid<T>& other) {
+ if (other.getSizeX() != getSizeX() || other.getSizeY() != getSizeY() || other.getSizeZ() != getSizeZ())
+ errMsg("Grid::swap(): Grid dimensions mismatch.");
+
+ if(externalData || other.externalData)
+ errMsg("Grid::swap(): Cannot swap if one grid stores externalData.");
+
+ T* dswap = other.mData;
+ other.mData = mData;
+ mData = dswap;
+
+}
+
+template<class T>
+void Grid<T>::load(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".raw")
+ readGridRaw(name, this);
+ else if (ext == ".uni")
+ readGridUni(name, this);
+ else if (ext == ".vol")
+ readGridVol(name, this);
+ else if (ext == ".npz")
+ readGridNumpy(name, this);
+# if OPENVDB==1
+ else if (ext == ".vdb")
+ readGridVDB(name, this);
+# endif // OPENVDB==1
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+template<class T>
+void Grid<T>::save(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".raw")
+ writeGridRaw(name, this);
+ else if (ext == ".uni")
+ writeGridUni(name, this);
+ else if (ext == ".vol")
+ writeGridVol(name, this);
+# if OPENVDB==1
+ else if (ext == ".vdb")
+ writeGridVDB(name, this);
+# endif // OPENVDB==1
+ else if (ext == ".npz")
+ writeGridNumpy(name, this);
+ else if (ext == ".txt")
+ writeGridTxt(name, this);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+//******************************************************************************
+// Grid<T> operators
+
+//! Kernel: Compute min value of Real grid
+
+ struct CompMinReal : public KernelBase {
+ CompMinReal(const Grid<Real>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& val ,Real& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const Grid<Real>& getArg0() {
+ return val; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel CompMinReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,minVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompMinReal (CompMinReal& o, tbb::split) : KernelBase(o) ,val(o.val) ,minVal(std::numeric_limits<Real>::max()) {
+}
+ void join(const CompMinReal & o) {
+ minVal = min(minVal,o.minVal); }
+ const Grid<Real>& val; Real minVal; }
+;
+
+//! Kernel: Compute max value of Real grid
+
+ struct CompMaxReal : public KernelBase {
+ CompMaxReal(const Grid<Real>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& val ,Real& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const Grid<Real>& getArg0() {
+ return val; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel CompMaxReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,maxVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompMaxReal (CompMaxReal& o, tbb::split) : KernelBase(o) ,val(o.val) ,maxVal(-std::numeric_limits<Real>::max()) {
+}
+ void join(const CompMaxReal & o) {
+ maxVal = max(maxVal,o.maxVal); }
+ const Grid<Real>& val; Real maxVal; }
+;
+
+//! Kernel: Compute min value of int grid
+
+ struct CompMinInt : public KernelBase {
+ CompMinInt(const Grid<int>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<int>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<int>& val ,int& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator int () {
+ return minVal; }
+ inline int & getRet() {
+ return minVal; }
+ inline const Grid<int>& getArg0() {
+ return val; }
+ typedef Grid<int> type0; void runMessage() { debMsg("Executing kernel CompMinInt ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,minVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompMinInt (CompMinInt& o, tbb::split) : KernelBase(o) ,val(o.val) ,minVal(std::numeric_limits<int>::max()) {
+}
+ void join(const CompMinInt & o) {
+ minVal = min(minVal,o.minVal); }
+ const Grid<int>& val; int minVal; }
+;
+
+//! Kernel: Compute max value of int grid
+
+ struct CompMaxInt : public KernelBase {
+ CompMaxInt(const Grid<int>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<int>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<int>& val ,int& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator int () {
+ return maxVal; }
+ inline int & getRet() {
+ return maxVal; }
+ inline const Grid<int>& getArg0() {
+ return val; }
+ typedef Grid<int> type0; void runMessage() { debMsg("Executing kernel CompMaxInt ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,maxVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompMaxInt (CompMaxInt& o, tbb::split) : KernelBase(o) ,val(o.val) ,maxVal(-std::numeric_limits<int>::max()) {
+}
+ void join(const CompMaxInt & o) {
+ maxVal = max(maxVal,o.maxVal); }
+ const Grid<int>& val; int maxVal; }
+;
+
+//! Kernel: Compute min norm of vec grid
+
+ struct CompMinVec : public KernelBase {
+ CompMinVec(const Grid<Vec3>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Vec3>& val ,Real& minVal) {
+ const Real s = normSquare(val[idx]);
+ if (s < minVal)
+ minVal = s;
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const Grid<Vec3>& getArg0() {
+ return val; }
+ typedef Grid<Vec3> type0; void runMessage() { debMsg("Executing kernel CompMinVec ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,minVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompMinVec (CompMinVec& o, tbb::split) : KernelBase(o) ,val(o.val) ,minVal(std::numeric_limits<Real>::max()) {
+}
+ void join(const CompMinVec & o) {
+ minVal = min(minVal,o.minVal); }
+ const Grid<Vec3>& val; Real minVal; }
+;
+
+//! Kernel: Compute max norm of vec grid
+
+ struct CompMaxVec : public KernelBase {
+ CompMaxVec(const Grid<Vec3>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Vec3>& val ,Real& maxVal) {
+ const Real s = normSquare(val[idx]);
+ if (s > maxVal)
+ maxVal = s;
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const Grid<Vec3>& getArg0() {
+ return val; }
+ typedef Grid<Vec3> type0; void runMessage() { debMsg("Executing kernel CompMaxVec ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,maxVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompMaxVec (CompMaxVec& o, tbb::split) : KernelBase(o) ,val(o.val) ,maxVal(-std::numeric_limits<Real>::max()) {
+}
+ void join(const CompMaxVec & o) {
+ maxVal = max(maxVal,o.maxVal); }
+ const Grid<Vec3>& val; Real maxVal; }
+;
+
+template<class T> Grid<T>& Grid<T>::copyFrom (const Grid<T>& a, bool copyType ) {
+ assertMsg (a.mSize.x == mSize.x && a.mSize.y == mSize.y && a.mSize.z == mSize.z, "different grid resolutions "<<a.mSize<<" vs "<<this->mSize );
+ memcpy(mData, a.mData, sizeof(T) * mSize.x * mSize.y * mSize.z);
+ if(copyType) mType = a.mType; // copy type marker
+ return *this;
+}
+/*template<class T> Grid<T>& Grid<T>::operator= (const Grid<T>& a) {
+ note: do not use , use copyFrom instead
+}*/
+
+template <class T> struct knGridSetConstReal : public KernelBase {
+ knGridSetConstReal(Grid<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, T val ) const { me[idx] = val; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knGridSetConstReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,val); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; T val; }
+;
+template <class T> struct knGridAddConstReal : public KernelBase {
+ knGridAddConstReal(Grid<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, T val ) const { me[idx] += val; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knGridAddConstReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,val); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; T val; }
+;
+template <class T> struct knGridMultConst : public KernelBase {
+ knGridMultConst(Grid<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, T val ) const { me[idx] *= val; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knGridMultConst ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,val); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; T val; }
+;
+
+template <class T> struct knGridSafeDiv : public KernelBase {
+ knGridSafeDiv(Grid<T>& me, const Grid<T>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<T>& other ) const { me[idx] = safeDivide(me[idx], other[idx]); } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<T>& getArg1() {
+ return other; }
+ typedef Grid<T> type1; void runMessage() { debMsg("Executing kernel knGridSafeDiv ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; const Grid<T>& other; }
+;
+//KERNEL(idx) template<class T> void gridSafeDiv (Grid<T>& me, const Grid<T>& other) { me[idx] = safeDivide(me[idx], other[idx]); }
+
+template <class T> struct knGridClamp : public KernelBase {
+ knGridClamp(Grid<T>& me, const T& min, const T& max) : KernelBase(&me,0) ,me(me),min(min),max(max) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const T& min, const T& max ) const { me[idx] = clamp(me[idx], min, max); } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const T& getArg1() {
+ return min; }
+ typedef T type1;inline const T& getArg2() {
+ return max; }
+ typedef T type2; void runMessage() { debMsg("Executing kernel knGridClamp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,min,max); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; const T& min; const T& max; }
+;
+
+template<typename T> inline void stomp(T &v, const T &th) { if(v<th) v=0; }
+template<> inline void stomp<Vec3>(Vec3 &v, const Vec3 &th) { if(v[0]<th[0]) v[0]=0; if(v[1]<th[1]) v[1]=0; if(v[2]<th[2]) v[2]=0; }
+template <class T> struct knGridStomp : public KernelBase {
+ knGridStomp(Grid<T>& me, const T& threshold) : KernelBase(&me,0) ,me(me),threshold(threshold) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const T& threshold ) const { stomp(me[idx], threshold); } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const T& getArg1() {
+ return threshold; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knGridStomp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,threshold); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; const T& threshold; }
+;
+
+template<class T> Grid<T>& Grid<T>::safeDivide (const Grid<T>& a) {
+ knGridSafeDiv<T> (*this, a);
+ return *this;
+}
+
+template<class T> int Grid<T>::getGridType() {
+ return static_cast<int>(mType);
+}
+
+template<class T> void Grid<T>::add(const Grid<T>& a) {
+ gridAdd<T,T>(*this, a);
+}
+template<class T> void Grid<T>::sub(const Grid<T>& a) {
+ gridSub<T,T>(*this, a);
+}
+template<class T> void Grid<T>::addScaled(const Grid<T>& a, const T& factor) {
+ gridScaledAdd<T,T> (*this, a, factor);
+}
+template<class T> void Grid<T>::setConst(T a) {
+ knGridSetConstReal<T>( *this, T(a) );
+}
+template<class T> void Grid<T>::addConst(T a) {
+ knGridAddConstReal<T>( *this, T(a) );
+}
+template<class T> void Grid<T>::multConst(T a) {
+ knGridMultConst<T>( *this, a );
+}
+
+template<class T> void Grid<T>::mult(const Grid<T>& a) {
+ gridMult<T,T> (*this, a);
+}
+
+template<class T> void Grid<T>::clamp(Real min, Real max) {
+ knGridClamp<T> (*this, T(min), T(max) );
+}
+template<class T> void Grid<T>::stomp(const T& threshold) {
+ knGridStomp<T>(*this, threshold);
+}
+
+template<> Real Grid<Real>::getMax() const {
+ return CompMaxReal (*this);
+}
+template<> Real Grid<Real>::getMin() const {
+ return CompMinReal (*this);
+}
+template<> Real Grid<Real>::getMaxAbs() const {
+ Real amin = CompMinReal (*this);
+ Real amax = CompMaxReal (*this);
+ return max( fabs(amin), fabs(amax));
+}
+template<> Real Grid<Vec3>::getMax() const {
+ return sqrt(CompMaxVec (*this));
+}
+template<> Real Grid<Vec3>::getMin() const {
+ return sqrt(CompMinVec (*this));
+}
+template<> Real Grid<Vec3>::getMaxAbs() const {
+ return sqrt(CompMaxVec (*this));
+}
+template<> Real Grid<int>::getMax() const {
+ return (Real) CompMaxInt (*this);
+}
+template<> Real Grid<int>::getMin() const {
+ return (Real) CompMinInt (*this);
+}
+template<> Real Grid<int>::getMaxAbs() const {
+ int amin = CompMinInt (*this);
+ int amax = CompMaxInt (*this);
+ return max( fabs((Real)amin), fabs((Real)amax));
+}
+template<class T> std::string Grid<T>::getDataPointer() {
+ std::ostringstream out;
+ out << mData ;
+ return out.str();
+}
+
+// L1 / L2 functions
+
+//! calculate L1 norm for whole grid with non-parallelized loop
+template<class GRID>
+Real loop_calcL1Grid (const GRID &grid, int bnd)
+{
+ double accu = 0.;
+ FOR_IJKT_BND(grid, bnd) { accu += norm(grid(i,j,k,t)); }
+ return (Real)accu;
+}
+
+//! calculate L2 norm for whole grid with non-parallelized loop
+// note - kernels "could" be used here, but they can't be templated at the moment (also, that would
+// mean the bnd parameter is fixed)
+template<class GRID>
+Real loop_calcL2Grid(const GRID &grid, int bnd)
+{
+ double accu = 0.;
+ FOR_IJKT_BND(grid, bnd) {
+ accu += normSquare(grid(i,j,k,t)); // supported for real and vec3,4 types
+ }
+ return (Real)sqrt(accu);
+}
+
+//! compute L1 norm of whole grid content (note, not parallel at the moment)
+template<class T> Real Grid<T>::getL1(int bnd) {
+ return loop_calcL1Grid<Grid<T> >(*this, bnd);
+}
+//! compute L2 norm of whole grid content (note, not parallel at the moment)
+template<class T> Real Grid<T>::getL2(int bnd) {
+ return loop_calcL2Grid<Grid<T> >(*this, bnd);
+}
+
+
+ struct knCountCells : public KernelBase {
+ knCountCells(const FlagGrid& flags, int flag, int bnd, Grid<Real>* mask) : KernelBase(&flags,0) ,flags(flags),flag(flag),bnd(bnd),mask(mask) ,cnt(0) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, int flag, int bnd, Grid<Real>* mask ,int& cnt) {
+ if(mask) (*mask)(i,j,k) = 0.;
+ if( bnd>0 && (!flags.isInBounds(Vec3i(i,j,k))) ) return;
+ if (flags(i,j,k) & flag ) {
+ cnt++;
+ if(mask) (*mask)(i,j,k) = 1.;
+ }
+} inline operator int () {
+ return cnt; }
+ inline int & getRet() {
+ return cnt; }
+ inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline int& getArg1() {
+ return flag; }
+ typedef int type1;inline int& getArg2() {
+ return bnd; }
+ typedef int type2;inline Grid<Real>* getArg3() {
+ return mask; }
+ typedef Grid<Real> type3; void runMessage() { debMsg("Executing kernel knCountCells ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,flag,bnd,mask,cnt); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,flag,bnd,mask,cnt); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_reduce (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ knCountCells (knCountCells& o, tbb::split) : KernelBase(o) ,flags(o.flags),flag(o.flag),bnd(o.bnd),mask(o.mask) ,cnt(0) {
+}
+ void join(const knCountCells & o) {
+ cnt += o.cnt; }
+ const FlagGrid& flags; int flag; int bnd; Grid<Real>* mask; int cnt; }
+;
+
+//! count number of cells of a certain type flag (can contain multiple bits, checks if any one of them is set - not all!)
+int FlagGrid::countCells(int flag, int bnd, Grid<Real>* mask) {
+ return knCountCells(*this, flag, bnd, mask);
+}
+
+// compute maximal diference of two cells in the grid
+// used for testing system
+
+Real gridMaxDiff(Grid<Real>& g1, Grid<Real>& g2) {
+ double maxVal = 0.;
+ FOR_IJK(g1) {
+ maxVal = std::max(maxVal, (double)fabs(g1(i, j, k) - g2(i, j, k)));
+ }
+ return maxVal;
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "gridMaxDiff" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& g1 = *_args.getPtr<Grid<Real> >("g1",0,&_lock); Grid<Real>& g2 = *_args.getPtr<Grid<Real> >("g2",1,&_lock); _retval = toPy(gridMaxDiff(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"gridMaxDiff", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("gridMaxDiff",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_gridMaxDiff ("","gridMaxDiff",_W_0);
+extern "C" {
+ void PbRegister_gridMaxDiff() {
+ KEEP_UNUSED(_RP_gridMaxDiff); }
+ }
+
+
+
+Real gridMaxDiffInt(Grid<int>& g1, Grid<int>& g2) {
+ double maxVal = 0.;
+ FOR_IJK(g1) {
+ maxVal = std::max(maxVal, (double)fabs((double)g1(i, j, k) - g2(i, j, k)));
+ }
+ return maxVal;
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "gridMaxDiffInt" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<int>& g1 = *_args.getPtr<Grid<int> >("g1",0,&_lock); Grid<int>& g2 = *_args.getPtr<Grid<int> >("g2",1,&_lock); _retval = toPy(gridMaxDiffInt(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"gridMaxDiffInt", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("gridMaxDiffInt",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_gridMaxDiffInt ("","gridMaxDiffInt",_W_1);
+extern "C" {
+ void PbRegister_gridMaxDiffInt() {
+ KEEP_UNUSED(_RP_gridMaxDiffInt); }
+ }
+
+
+
+Real gridMaxDiffVec3(Grid<Vec3>& g1, Grid<Vec3>& g2) {
+ double maxVal = 0.;
+ FOR_IJK(g1) {
+ // accumulate differences with double precision
+ // note - don't use norm here! should be as precise as possible...
+ double d = 0.;
+ for (int c = 0; c<3; ++c) {
+ d += fabs((double)g1(i, j, k)[c] - (double)g2(i, j, k)[c]);
+ }
+ maxVal = std::max(maxVal, d);
+ //maxVal = std::max(maxVal, (double)fabs( norm(g1(i,j,k)-g2(i,j,k)) ));
+ }
+ return maxVal;
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "gridMaxDiffVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& g1 = *_args.getPtr<Grid<Vec3> >("g1",0,&_lock); Grid<Vec3>& g2 = *_args.getPtr<Grid<Vec3> >("g2",1,&_lock); _retval = toPy(gridMaxDiffVec3(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"gridMaxDiffVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("gridMaxDiffVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_gridMaxDiffVec3 ("","gridMaxDiffVec3",_W_2);
+extern "C" {
+ void PbRegister_gridMaxDiffVec3() {
+ KEEP_UNUSED(_RP_gridMaxDiffVec3); }
+ }
+
+
+
+// simple helper functions to copy (convert) mac to vec3 , and levelset to real grids
+// (are assumed to be the same for running the test cases - in general they're not!)
+
+void copyMacToVec3(MACGrid &source, Grid<Vec3>& target) {
+ FOR_IJK(target) {
+ target(i,j,k) = source(i,j,k);
+ }
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "copyMacToVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& source = *_args.getPtr<MACGrid >("source",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); _retval = getPyNone(); copyMacToVec3(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"copyMacToVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("copyMacToVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_copyMacToVec3 ("","copyMacToVec3",_W_3);
+extern "C" {
+ void PbRegister_copyMacToVec3() {
+ KEEP_UNUSED(_RP_copyMacToVec3); }
+ }
+
+
+
+void convertMacToVec3(MACGrid &source , Grid<Vec3> &target) { debMsg("Deprecated - do not use convertMacToVec3... use copyMacToVec3 instead",1); copyMacToVec3(source,target); } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "convertMacToVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& source = *_args.getPtr<MACGrid >("source",0,&_lock); Grid<Vec3> & target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); _retval = getPyNone(); convertMacToVec3(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"convertMacToVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("convertMacToVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_convertMacToVec3 ("","convertMacToVec3",_W_4);
+extern "C" {
+ void PbRegister_convertMacToVec3() {
+ KEEP_UNUSED(_RP_convertMacToVec3); }
+ }
+
+
+
+//! vec3->mac grid conversion , but with full resampling
+void resampleVec3ToMac(Grid<Vec3>& source, MACGrid &target ) {
+ FOR_IJK_BND(target,1) {
+ target(i,j,k)[0] = 0.5*(source(i-1,j,k)[0]+source(i,j,k))[0];
+ target(i,j,k)[1] = 0.5*(source(i,j-1,k)[1]+source(i,j,k))[1];
+ if(target.is3D()) {
+ target(i,j,k)[2] = 0.5*(source(i,j,k-1)[2]+source(i,j,k))[2]; }
+ }
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "resampleVec3ToMac" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& source = *_args.getPtr<Grid<Vec3> >("source",0,&_lock); MACGrid& target = *_args.getPtr<MACGrid >("target",1,&_lock); _retval = getPyNone(); resampleVec3ToMac(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"resampleVec3ToMac", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("resampleVec3ToMac",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_resampleVec3ToMac ("","resampleVec3ToMac",_W_5);
+extern "C" {
+ void PbRegister_resampleVec3ToMac() {
+ KEEP_UNUSED(_RP_resampleVec3ToMac); }
+ }
+
+
+//! mac->vec3 grid conversion , with full resampling
+void resampleMacToVec3(MACGrid &source, Grid<Vec3>& target ) {
+ FOR_IJK_BND(target,1) {
+ target(i,j,k) = source.getCentered(i,j,k);
+ }
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "resampleMacToVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& source = *_args.getPtr<MACGrid >("source",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); _retval = getPyNone(); resampleMacToVec3(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"resampleMacToVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("resampleMacToVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_resampleMacToVec3 ("","resampleMacToVec3",_W_6);
+extern "C" {
+ void PbRegister_resampleMacToVec3() {
+ KEEP_UNUSED(_RP_resampleMacToVec3); }
+ }
+
+
+
+
+void copyLevelsetToReal(LevelsetGrid &source , Grid<Real> &target) {
+ FOR_IJK(target) {
+ target(i,j,k) = source(i,j,k);
+ }
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "copyLevelsetToReal" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; LevelsetGrid& source = *_args.getPtr<LevelsetGrid >("source",0,&_lock); Grid<Real> & target = *_args.getPtr<Grid<Real> >("target",1,&_lock); _retval = getPyNone(); copyLevelsetToReal(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"copyLevelsetToReal", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("copyLevelsetToReal",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_copyLevelsetToReal ("","copyLevelsetToReal",_W_7);
+extern "C" {
+ void PbRegister_copyLevelsetToReal() {
+ KEEP_UNUSED(_RP_copyLevelsetToReal); }
+ }
+
+
+
+void copyVec3ToReal(Grid<Vec3> &source, Grid<Real> &targetX, Grid<Real> &targetY, Grid<Real> &targetZ) {
+ FOR_IJK(source) {
+ targetX(i,j,k) = source(i,j,k).x;
+ targetY(i,j,k) = source(i,j,k).y;
+ targetZ(i,j,k) = source(i,j,k).z;
+ }
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "copyVec3ToReal" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3> & source = *_args.getPtr<Grid<Vec3> >("source",0,&_lock); Grid<Real> & targetX = *_args.getPtr<Grid<Real> >("targetX",1,&_lock); Grid<Real> & targetY = *_args.getPtr<Grid<Real> >("targetY",2,&_lock); Grid<Real> & targetZ = *_args.getPtr<Grid<Real> >("targetZ",3,&_lock); _retval = getPyNone(); copyVec3ToReal(source,targetX,targetY,targetZ); _args.check(); }
+ pbFinalizePlugin(parent,"copyVec3ToReal", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("copyVec3ToReal",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_copyVec3ToReal ("","copyVec3ToReal",_W_8);
+extern "C" {
+ void PbRegister_copyVec3ToReal() {
+ KEEP_UNUSED(_RP_copyVec3ToReal); }
+ }
+
+
+
+
+void copyRealToVec3(Grid<Real> &sourceX, Grid<Real> &sourceY, Grid<Real> &sourceZ, Grid<Vec3> &target) {
+ FOR_IJK(target) {
+ target(i,j,k).x = sourceX(i,j,k);
+ target(i,j,k).y = sourceY(i,j,k);
+ target(i,j,k).z = sourceZ(i,j,k);
+ }
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "copyRealToVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & sourceX = *_args.getPtr<Grid<Real> >("sourceX",0,&_lock); Grid<Real> & sourceY = *_args.getPtr<Grid<Real> >("sourceY",1,&_lock); Grid<Real> & sourceZ = *_args.getPtr<Grid<Real> >("sourceZ",2,&_lock); Grid<Vec3> & target = *_args.getPtr<Grid<Vec3> >("target",3,&_lock); _retval = getPyNone(); copyRealToVec3(sourceX,sourceY,sourceZ,target); _args.check(); }
+ pbFinalizePlugin(parent,"copyRealToVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("copyRealToVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_copyRealToVec3 ("","copyRealToVec3",_W_9);
+extern "C" {
+ void PbRegister_copyRealToVec3() {
+ KEEP_UNUSED(_RP_copyRealToVec3); }
+ }
+
+
+void convertLevelsetToReal(LevelsetGrid &source , Grid<Real> &target) { debMsg("Deprecated - do not use convertLevelsetToReal... use copyLevelsetToReal instead",1); copyLevelsetToReal(source,target); } static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "convertLevelsetToReal" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; LevelsetGrid& source = *_args.getPtr<LevelsetGrid >("source",0,&_lock); Grid<Real> & target = *_args.getPtr<Grid<Real> >("target",1,&_lock); _retval = getPyNone(); convertLevelsetToReal(source,target); _args.check(); }
+ pbFinalizePlugin(parent,"convertLevelsetToReal", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("convertLevelsetToReal",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_convertLevelsetToReal ("","convertLevelsetToReal",_W_10);
+extern "C" {
+ void PbRegister_convertLevelsetToReal() {
+ KEEP_UNUSED(_RP_convertLevelsetToReal); }
+ }
+
+
+
+template<class T> void Grid<T>::printGrid(int zSlice, bool printIndex, int bnd) {
+ std::ostringstream out;
+ out << std::endl;
+ FOR_IJK_BND(*this,bnd) {
+ IndexInt idx = (*this).index(i,j,k);
+ if((zSlice>=0 && k==zSlice) || (zSlice<0)) {
+ out << " ";
+ if(printIndex && this->is3D()) out << " "<<i<<","<<j<<","<<k <<":";
+ if(printIndex && !this->is3D()) out << " "<<i<<","<<j<<":";
+ out << (*this)[idx];
+ if(i==(*this).getSizeX()-1 -bnd) out << std::endl;
+ }
+ }
+ out << endl; debMsg("Printing " << this->getName() << out.str().c_str() , 1);
+}
+
+//! helper to swap components of a grid (eg for data import)
+void swapComponents(Grid<Vec3>& vel, int c1=0, int c2=1, int c3=2) {
+ FOR_IJK(vel) {
+ Vec3 v = vel(i,j,k);
+ vel(i,j,k)[0] = v[c1];
+ vel(i,j,k)[1] = v[c2];
+ vel(i,j,k)[2] = v[c3];
+ }
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "swapComponents" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& vel = *_args.getPtr<Grid<Vec3> >("vel",0,&_lock); int c1 = _args.getOpt<int >("c1",1,0,&_lock); int c2 = _args.getOpt<int >("c2",2,1,&_lock); int c3 = _args.getOpt<int >("c3",3,2,&_lock); _retval = getPyNone(); swapComponents(vel,c1,c2,c3); _args.check(); }
+ pbFinalizePlugin(parent,"swapComponents", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("swapComponents",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_swapComponents ("","swapComponents",_W_11);
+extern "C" {
+ void PbRegister_swapComponents() {
+ KEEP_UNUSED(_RP_swapComponents); }
+ }
+
+
+
+// helper functions for UV grid data (stored grid coordinates as Vec3 values, and uv weight in entry zero)
+
+// make uv weight accesible in python
+Real getUvWeight(Grid<Vec3> &uv) { return uv[0][0]; } static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getUvWeight" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3> & uv = *_args.getPtr<Grid<Vec3> >("uv",0,&_lock); _retval = toPy(getUvWeight(uv)); _args.check(); }
+ pbFinalizePlugin(parent,"getUvWeight", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getUvWeight",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getUvWeight ("","getUvWeight",_W_12);
+extern "C" {
+ void PbRegister_getUvWeight() {
+ KEEP_UNUSED(_RP_getUvWeight); }
+ }
+
+
+
+// note - right now the UV grids have 0 values at the border after advection... could be fixed with an extrapolation step...
+
+// compute normalized modulo interval
+static inline Real computeUvGridTime(Real t, Real resetTime) {
+ return fmod( (t / resetTime), (Real)1. );
+}
+// create ramp function in 0..1 range with half frequency
+static inline Real computeUvRamp(Real t) {
+ Real uvWeight = 2. * t;
+ if (uvWeight>1.) uvWeight=2.-uvWeight;
+ return uvWeight;
+}
+
+ struct knResetUvGrid : public KernelBase {
+ knResetUvGrid(Grid<Vec3>& target, const Vec3* offset) : KernelBase(&target,0) ,target(target),offset(offset) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& target, const Vec3* offset ) const {
+ Vec3 coord = Vec3((Real)i,(Real)j,(Real)k);
+ if (offset) coord += (*offset);
+ target(i,j,k) = coord;
+} inline Grid<Vec3>& getArg0() {
+ return target; }
+ typedef Grid<Vec3> type0;inline const Vec3* getArg1() {
+ return offset; }
+ typedef Vec3 type1; void runMessage() { debMsg("Executing kernel knResetUvGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,target,offset); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,target,offset); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<Vec3>& target; const Vec3* offset; }
+;
+
+
+void resetUvGrid(Grid<Vec3> &target, const Vec3* offset=NULL) {
+ knResetUvGrid reset(target, offset); // note, llvm complains about anonymous declaration here... ?
+} static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "resetUvGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3> & target = *_args.getPtr<Grid<Vec3> >("target",0,&_lock); const Vec3* offset = _args.getPtrOpt<Vec3 >("offset",1,NULL,&_lock); _retval = getPyNone(); resetUvGrid(target,offset); _args.check(); }
+ pbFinalizePlugin(parent,"resetUvGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("resetUvGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_resetUvGrid ("","resetUvGrid",_W_13);
+extern "C" {
+ void PbRegister_resetUvGrid() {
+ KEEP_UNUSED(_RP_resetUvGrid); }
+ }
+
+
+
+void updateUvWeight(Real resetTime, int index, int numUvs, Grid<Vec3> &uv, const Vec3* offset=NULL) {
+ const Real t = uv.getParent()->getTime();
+ Real timeOff = resetTime/(Real)numUvs;
+
+ Real lastt = computeUvGridTime(t +(Real)index*timeOff - uv.getParent()->getDt(), resetTime);
+ Real currt = computeUvGridTime(t +(Real)index*timeOff , resetTime);
+ Real uvWeight = computeUvRamp(currt);
+
+ // normalize the uvw weights , note: this is a bit wasteful...
+ Real uvWTotal = 0.;
+ for(int i=0; i<numUvs; ++i) {
+ uvWTotal += computeUvRamp( computeUvGridTime(t +(Real)i*timeOff , resetTime) );
+ }
+ if(uvWTotal<=VECTOR_EPSILON) { uvWeight = uvWTotal = 1.; }
+ else uvWeight /= uvWTotal;
+
+ // check for reset
+ if( currt < lastt )
+ knResetUvGrid reset(uv, offset);
+
+ // write new weight value to grid
+ uv[0] = Vec3( uvWeight, 0.,0.);
+
+ // print info about uv weights?
+ debMsg("Uv grid "<<index<<"/"<<numUvs<< " t="<<currt<<" w="<<uvWeight<<", reset:"<<(int)(currt<lastt) , 2);
+} static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "updateUvWeight" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Real resetTime = _args.get<Real >("resetTime",0,&_lock); int index = _args.get<int >("index",1,&_lock); int numUvs = _args.get<int >("numUvs",2,&_lock); Grid<Vec3> & uv = *_args.getPtr<Grid<Vec3> >("uv",3,&_lock); const Vec3* offset = _args.getPtrOpt<Vec3 >("offset",4,NULL,&_lock); _retval = getPyNone(); updateUvWeight(resetTime,index,numUvs,uv,offset); _args.check(); }
+ pbFinalizePlugin(parent,"updateUvWeight", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("updateUvWeight",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_updateUvWeight ("","updateUvWeight",_W_14);
+extern "C" {
+ void PbRegister_updateUvWeight() {
+ KEEP_UNUSED(_RP_updateUvWeight); }
+ }
+
+
+
+template <class T> struct knSetBoundary : public KernelBase {
+ knSetBoundary(Grid<T>& grid, T value, int w) : KernelBase(&grid,0) ,grid(grid),value(value),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>& grid, T value, int w ) const {
+ bool bnd = (i<=w || i>=grid.getSizeX()-1-w || j<=w || j>=grid.getSizeY()-1-w || (grid.is3D() && (k<=w || k>=grid.getSizeZ()-1-w)));
+ if (bnd)
+ grid(i,j,k) = value;
+} inline Grid<T>& getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1;inline int& getArg2() {
+ return w; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetBoundary ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,value,w); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,value,w); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<T>& grid; T value; int w; }
+;
+
+template<class T> void Grid<T>::setBound(T value, int boundaryWidth) {
+ knSetBoundary<T>( *this, value, boundaryWidth );
+}
+
+
+template <class T> struct knSetBoundaryNeumann : public KernelBase {
+ knSetBoundaryNeumann(Grid<T>& grid, int w) : KernelBase(&grid,0) ,grid(grid),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>& grid, int w ) const {
+ bool set = false;
+ int si=i, sj=j, sk=k;
+ if( i<=w) {
+ si = w+1; set=true;
+ }
+ if( i>=grid.getSizeX()-1-w){
+ si = grid.getSizeX()-1-w-1; set=true;
+ }
+ if( j<=w){
+ sj = w+1; set=true;
+ }
+ if( j>=grid.getSizeY()-1-w){
+ sj = grid.getSizeY()-1-w-1; set=true;
+ }
+ if( grid.is3D() ){
+ if( k<=w ) {
+ sk = w+1; set=true;
+ }
+ if( k>=grid.getSizeZ()-1-w ) {
+ sk = grid.getSizeZ()-1-w-1; set=true;
+ }
+ }
+ if(set)
+ grid(i,j,k) = grid(si, sj, sk);
+} inline Grid<T>& getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline int& getArg1() {
+ return w; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel knSetBoundaryNeumann ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,w); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,w); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<T>& grid; int w; }
+;
+
+template<class T> void Grid<T>::setBoundNeumann(int boundaryWidth) {
+ knSetBoundaryNeumann<T>( *this, boundaryWidth );
+}
+
+//! kernel to set velocity components of mac grid to value for a boundary of w cells
+ struct knSetBoundaryMAC : public KernelBase {
+ knSetBoundaryMAC(Grid<Vec3>& grid, Vec3 value, int w) : KernelBase(&grid,0) ,grid(grid),value(value),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& grid, Vec3 value, int w ) const {
+ if (i<=w || i>=grid.getSizeX() -w || j<=w-1 || j>=grid.getSizeY()-1-w || (grid.is3D() && (k<=w-1 || k>=grid.getSizeZ()-1-w)))
+ grid(i,j,k).x = value.x;
+ if (i<=w-1 || i>=grid.getSizeX()-1-w || j<=w || j>=grid.getSizeY() -w || (grid.is3D() && (k<=w-1 || k>=grid.getSizeZ()-1-w)))
+ grid(i,j,k).y = value.y;
+ if (i<=w-1 || i>=grid.getSizeX()-1-w || j<=w-1 || j>=grid.getSizeY()-1-w || (grid.is3D() && (k<=w || k>=grid.getSizeZ() -w)))
+ grid(i,j,k).z = value.z;
+} inline Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Vec3& getArg1() {
+ return value; }
+ typedef Vec3 type1;inline int& getArg2() {
+ return w; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetBoundaryMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,value,w); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,value,w); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<Vec3>& grid; Vec3 value; int w; }
+;
+
+//! only set normal velocity components of mac grid to value for a boundary of w cells
+ struct knSetBoundaryMACNorm : public KernelBase {
+ knSetBoundaryMACNorm(Grid<Vec3>& grid, Vec3 value, int w) : KernelBase(&grid,0) ,grid(grid),value(value),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& grid, Vec3 value, int w ) const {
+ if (i<=w || i>=grid.getSizeX() -w ) grid(i,j,k).x = value.x;
+ if (j<=w || j>=grid.getSizeY() -w ) grid(i,j,k).y = value.y;
+ if ( (grid.is3D() && (k<=w || k>=grid.getSizeZ() -w))) grid(i,j,k).z = value.z;
+} inline Grid<Vec3>& getArg0() {
+ return grid; }
+ typedef Grid<Vec3> type0;inline Vec3& getArg1() {
+ return value; }
+ typedef Vec3 type1;inline int& getArg2() {
+ return w; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetBoundaryMACNorm ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,value,w); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,value,w); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<Vec3>& grid; Vec3 value; int w; }
+;
+
+//! set velocity components of mac grid to value for a boundary of w cells (optionally only normal values)
+void MACGrid::setBoundMAC(Vec3 value, int boundaryWidth, bool normalOnly) {
+ if(!normalOnly) knSetBoundaryMAC ( *this, value, boundaryWidth );
+ else knSetBoundaryMACNorm( *this, value, boundaryWidth );
+}
+
+
+//! helper kernels for getGridAvg
+
+ struct knGridTotalSum : public KernelBase {
+ knGridTotalSum(const Grid<Real>& a, FlagGrid* flags) : KernelBase(&a,0) ,a(a),flags(flags) ,result(0.0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& a, FlagGrid* flags ,double& result) {
+ if(flags) { if(flags->isFluid(idx)) result += a[idx]; }
+ else { result += a[idx]; }
+} inline operator double () {
+ return result; }
+ inline double & getRet() {
+ return result; }
+ inline const Grid<Real>& getArg0() {
+ return a; }
+ typedef Grid<Real> type0;inline FlagGrid* getArg1() {
+ return flags; }
+ typedef FlagGrid type1; void runMessage() { debMsg("Executing kernel knGridTotalSum ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, a,flags,result); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ knGridTotalSum (knGridTotalSum& o, tbb::split) : KernelBase(o) ,a(o.a),flags(o.flags) ,result(0.0) {
+}
+ void join(const knGridTotalSum & o) {
+ result += o.result; }
+ const Grid<Real>& a; FlagGrid* flags; double result; }
+;
+
+
+ struct knCountFluidCells : public KernelBase {
+ knCountFluidCells(FlagGrid& flags) : KernelBase(&flags,0) ,flags(flags) ,numEmpty(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, FlagGrid& flags ,int& numEmpty) { if (flags.isFluid(idx) ) numEmpty++; } inline operator int () {
+ return numEmpty; }
+ inline int & getRet() {
+ return numEmpty; }
+ inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0; void runMessage() { debMsg("Executing kernel knCountFluidCells ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, flags,numEmpty); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ knCountFluidCells (knCountFluidCells& o, tbb::split) : KernelBase(o) ,flags(o.flags) ,numEmpty(0) {
+}
+ void join(const knCountFluidCells & o) {
+ numEmpty += o.numEmpty; }
+ FlagGrid& flags; int numEmpty; }
+;
+
+//! averaged value for all cells (if flags are given, only for fluid cells)
+
+Real getGridAvg(Grid<Real>& source, FlagGrid* flags=NULL) {
+ double sum = knGridTotalSum(source, flags);
+
+ double cells;
+ if(flags) { cells = knCountFluidCells(*flags); }
+ else { cells = source.getSizeX()*source.getSizeY()*source.getSizeZ(); }
+
+ if(cells>0.) sum *= 1./cells;
+ else sum = -1.;
+ return sum;
+} static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getGridAvg" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",0,&_lock); FlagGrid* flags = _args.getPtrOpt<FlagGrid >("flags",1,NULL,&_lock); _retval = toPy(getGridAvg(source,flags)); _args.check(); }
+ pbFinalizePlugin(parent,"getGridAvg", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getGridAvg",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getGridAvg ("","getGridAvg",_W_15);
+extern "C" {
+ void PbRegister_getGridAvg() {
+ KEEP_UNUSED(_RP_getGridAvg); }
+ }
+
+
+
+//! transfer data between real and vec3 grids
+
+ struct knGetComponent : public KernelBase {
+ knGetComponent(const Grid<Vec3>& source, Grid<Real>& target, int component) : KernelBase(&source,0) ,source(source),target(target),component(component) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Vec3>& source, Grid<Real>& target, int component ) const {
+ target[idx] = source[idx][component];
+} inline const Grid<Vec3>& getArg0() {
+ return source; }
+ typedef Grid<Vec3> type0;inline Grid<Real>& getArg1() {
+ return target; }
+ typedef Grid<Real> type1;inline int& getArg2() {
+ return component; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knGetComponent ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, source,target,component); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const Grid<Vec3>& source; Grid<Real>& target; int component; }
+;
+void getComponent(const Grid<Vec3>& source, Grid<Real>& target, int component) { knGetComponent(source, target, component); } static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getComponent" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Vec3>& source = *_args.getPtr<Grid<Vec3> >("source",0,&_lock); Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",1,&_lock); int component = _args.get<int >("component",2,&_lock); _retval = getPyNone(); getComponent(source,target,component); _args.check(); }
+ pbFinalizePlugin(parent,"getComponent", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getComponent",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getComponent ("","getComponent",_W_16);
+extern "C" {
+ void PbRegister_getComponent() {
+ KEEP_UNUSED(_RP_getComponent); }
+ }
+
+
+
+ struct knSetComponent : public KernelBase {
+ knSetComponent(const Grid<Real>& source, Grid<Vec3>& target, int component) : KernelBase(&source,0) ,source(source),target(target),component(component) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& source, Grid<Vec3>& target, int component ) const {
+ target[idx][component] = source[idx];
+} inline const Grid<Real>& getArg0() {
+ return source; }
+ typedef Grid<Real> type0;inline Grid<Vec3>& getArg1() {
+ return target; }
+ typedef Grid<Vec3> type1;inline int& getArg2() {
+ return component; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetComponent ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, source,target,component); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const Grid<Real>& source; Grid<Vec3>& target; int component; }
+;
+void setComponent(const Grid<Real>& source, Grid<Vec3>& target, int component) { knSetComponent(source, target, component); } static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setComponent" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); int component = _args.get<int >("component",2,&_lock); _retval = getPyNone(); setComponent(source,target,component); _args.check(); }
+ pbFinalizePlugin(parent,"setComponent", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setComponent",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setComponent ("","setComponent",_W_17);
+extern "C" {
+ void PbRegister_setComponent() {
+ KEEP_UNUSED(_RP_setComponent); }
+ }
+
+
+
+//******************************************************************************
+// Specialization classes
+
+void FlagGrid::InitMinXWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(i - w - .5, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::InitMaxXWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(mSize.x-i-1.5-w, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::InitMinYWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(j - w - .5, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::InitMaxYWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(mSize.y-j-1.5-w, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::InitMinZWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(k - w - .5, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::InitMaxZWall(const int &boundaryWidth, Grid<Real>& phiWalls) {
+ const int w = boundaryWidth;
+ FOR_IJK(phiWalls) {
+ phiWalls(i,j,k) = std::min(mSize.z-k-1.5-w, (double)phiWalls(i,j,k));
+ }
+}
+
+void FlagGrid::initDomain( const int &boundaryWidth
+ , const string &wallIn
+ , const string &openIn
+ , const string &inflowIn
+ , const string &outflowIn
+ , Grid<Real>* phiWalls ) {
+
+ int types[6] = {0};
+ bool set [6] = {false};
+ // make sure we have at least 6 entries
+ string wall = wallIn; wall.append(" ");
+ string open = openIn; open.append(" ");
+ string inflow = inflowIn; inflow.append(" ");
+ string outflow = outflowIn; outflow.append(" ");
+
+ if(phiWalls) phiWalls->setConst(1000000000);
+
+ for (int i = 0; i<6; ++i) {
+ //min x-direction
+ if(!set[0]) {
+ if(open[i]=='x') {types[0] = TypeOpen;set[0] = true;}
+ else if(inflow[i]=='x') {types[0] = TypeInflow;set[0] = true;}
+ else if(outflow[i]=='x') {types[0] = TypeOutflow;set[0] = true;}
+ else if(wall[i]=='x') {
+ types[0] = TypeObstacle;
+ if(phiWalls) InitMinXWall(boundaryWidth, *phiWalls);
+ set[0] = true;
+ }
+ }
+ //max x-direction
+ if(!set[1]) {
+ if(open[i]=='X') {types[1] = TypeOpen;set[1] = true;}
+ else if(inflow[i]=='X') {types[1] = TypeInflow;set[1] = true;}
+ else if(outflow[i]=='X') {types[1] = TypeOutflow;set[1] = true;}
+ else if(wall[i]=='X') {
+ types[1] = TypeObstacle;
+ if(phiWalls) InitMaxXWall(boundaryWidth, *phiWalls);
+ set[1] = true;
+ }
+ }
+ //min y-direction
+ if(!set[2]) {
+ if(open[i]=='y') {types[2] = TypeOpen;set[2] = true;}
+ else if(inflow[i]=='y') {types[2] = TypeInflow;set[2] = true;}
+ else if(outflow[i]=='y') {types[2] = TypeOutflow;set[2] = true;}
+ else if(wall[i]=='y') {
+ types[2] = TypeObstacle;
+ if(phiWalls) InitMinYWall(boundaryWidth, *phiWalls);
+ set[2] = true;
+ }
+ }
+ //max y-direction
+ if(!set[3]) {
+ if(open[i]=='Y') {types[3] = TypeOpen;set[3] = true;}
+ else if(inflow[i]=='Y') {types[3] = TypeInflow;set[3] = true;}
+ else if(outflow[i]=='Y') {types[3] = TypeOutflow;set[3] = true;}
+ else if(wall[i]=='Y') {
+ types[3] = TypeObstacle;
+ if(phiWalls) InitMaxYWall(boundaryWidth, *phiWalls);
+ set[3] = true;
+ }
+ }
+ if(this->is3D()) {
+ //min z-direction
+ if(!set[4]) {
+ if(open[i]=='z') {types[4] = TypeOpen;set[4] = true;}
+ else if(inflow[i]=='z') {types[4] = TypeInflow;set[4] = true;}
+ else if(outflow[i]=='z') {types[4] = TypeOutflow;set[4] = true;}
+ else if(wall[i]=='z') {
+ types[4] = TypeObstacle;
+ if(phiWalls) InitMinZWall(boundaryWidth, *phiWalls);
+ set[4] = true;
+ }
+ }
+ //max z-direction
+ if(!set[5]) {
+ if(open[i]=='Z') {types[5] = TypeOpen;set[5] = true;}
+ else if(inflow[i]=='Z') {types[5] = TypeInflow;set[5] = true;}
+ else if(outflow[i]=='Z') {types[5] = TypeOutflow;set[5] = true;}
+ else if(wall[i]=='Z') {
+ types[5] = TypeObstacle;
+ if(phiWalls) InitMaxZWall(boundaryWidth, *phiWalls);
+ set[5] = true;
+ }
+ }
+ }
+ }
+
+ setConst(TypeEmpty);
+ initBoundaries(boundaryWidth, types);
+}
+
+void FlagGrid::initBoundaries(const int &boundaryWidth, const int *types) {
+ const int w = boundaryWidth;
+ FOR_IJK(*this) {
+ bool bnd = (i <= w);
+ if (bnd) mData[index(i,j,k)] = types[0];
+ bnd = (i >= mSize.x-1-w);
+ if (bnd) mData[index(i,j,k)] = types[1];
+ bnd = (j <= w);
+ if (bnd) mData[index(i,j,k)] = types[2];
+ bnd = (j >= mSize.y-1-w);
+ if (bnd) mData[index(i,j,k)] = types[3];
+ if(is3D()) {
+ bnd = (k <= w);
+ if (bnd) mData[index(i,j,k)] = types[4];
+ bnd = (k >= mSize.z-1-w);
+ if (bnd) mData[index(i,j,k)] = types[5];
+ }
+ }
+}
+
+void FlagGrid::updateFromLevelset(LevelsetGrid& levelset, LevelsetGrid* obsLevelset) {
+ FOR_IDX(*this) {
+ if (!isObstacle(idx) && !isOutflow(idx)) {
+ const Real phi = levelset[idx];
+ if (phi <= levelset.invalidTimeValue()) continue;
+
+ mData[idx] &= ~(TypeEmpty | TypeFluid); // clear empty/fluid flags
+ mData[idx] |= (phi <= 0) ? TypeFluid : TypeEmpty; // set resepctive flag
+ }
+ if (obsLevelset && isOutflow(idx)) {
+ const Real phiObs = (*obsLevelset)[idx];
+ if (phiObs <= 0) mData[idx] = TypeObstacle; // enforce obstacle flag
+ }
+ }
+}
+
+void FlagGrid::fillGrid(int type) {
+ FOR_IDX(*this) {
+ if ((mData[idx] & TypeObstacle)==0 && (mData[idx] & TypeInflow)==0&& (mData[idx] & TypeOutflow)==0&& (mData[idx] & TypeOpen)==0)
+ mData[idx] = (mData[idx] & ~(TypeEmpty | TypeFluid)) | type;
+ }
+}
+
+// flag grid helper
+
+bool isIsolatedFluidCell(const IndexInt idx, const FlagGrid &flags)
+{
+ if(!flags.isFluid(idx)) return false;
+ if(flags.isFluid(idx-flags.getStrideX())) return false;
+ if(flags.isFluid(idx+flags.getStrideX())) return false;
+ if(flags.isFluid(idx-flags.getStrideY())) return false;
+ if(flags.isFluid(idx+flags.getStrideY())) return false;
+ if(!flags.is3D()) return true;
+ if(flags.isFluid(idx-flags.getStrideZ())) return false;
+ if(flags.isFluid(idx+flags.getStrideZ())) return false;
+ return true;
+}
+
+
+
+ struct knMarkIsolatedFluidCell : public KernelBase {
+ knMarkIsolatedFluidCell(FlagGrid &flags, const int mark) : KernelBase(&flags,0) ,flags(flags),mark(mark) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, FlagGrid &flags, const int mark ) const {
+ if(isIsolatedFluidCell(idx, flags)) flags[idx] = mark;
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const int& getArg1() {
+ return mark; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel knMarkIsolatedFluidCell ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, flags,mark); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ FlagGrid& flags; const int mark; }
+;
+
+
+
+void markIsolatedFluidCell(FlagGrid &flags, const int mark) {
+ knMarkIsolatedFluidCell(flags, mark);
+} static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "markIsolatedFluidCell" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const int mark = _args.get<int >("mark",1,&_lock); _retval = getPyNone(); markIsolatedFluidCell(flags,mark); _args.check(); }
+ pbFinalizePlugin(parent,"markIsolatedFluidCell", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("markIsolatedFluidCell",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_markIsolatedFluidCell ("","markIsolatedFluidCell",_W_18);
+extern "C" {
+ void PbRegister_markIsolatedFluidCell() {
+ KEEP_UNUSED(_RP_markIsolatedFluidCell); }
+ }
+
+
+
+
+
+void copyMACData(const MACGrid &source, MACGrid &target, const FlagGrid& flags, const int flag, const int bnd) {
+ assertMsg (source.getSize().x == target.getSize().x && source.getSize().y == target.getSize().y && source.getSize().z == target.getSize().z, "different grid resolutions " << source.getSize() << " vs " << target.getSize() );
+
+ // Grid<Real> divGrid(target.getParent());
+ // DivergenceOpMAC(divGrid, target);
+ // Real fDivOrig = GridSumSqr(divGrid);
+
+ FOR_IJK_BND(target, bnd)
+ {
+ if(flags.get(i,j,k) & flag)
+ {
+ target(i,j,k) = source(i,j,k);
+ }
+ }
+
+ // DivergenceOpMAC(divGrid, target);
+ // Real fDivTransfer = GridSumSqr(divGrid);
+ // std::cout << "Divergence: " << fDivOrig << " -> " << fDivTransfer << std::endl;
+} static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "copyMACData" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const MACGrid& source = *_args.getPtr<MACGrid >("source",0,&_lock); MACGrid& target = *_args.getPtr<MACGrid >("target",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); const int flag = _args.get<int >("flag",3,&_lock); const int bnd = _args.get<int >("bnd",4,&_lock); _retval = getPyNone(); copyMACData(source,target,flags,flag,bnd); _args.check(); }
+ pbFinalizePlugin(parent,"copyMACData", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("copyMACData",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_copyMACData ("","copyMACData",_W_19);
+extern "C" {
+ void PbRegister_copyMACData() {
+ KEEP_UNUSED(_RP_copyMACData); }
+ }
+
+
+
+
+// explicit instantiation
+template class Grid<int>;
+template class Grid<Real>;
+template class Grid<Vec3>;
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h
new file mode 100644
index 00000000000..6e980e0b6fa
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h
@@ -0,0 +1,983 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#ifndef _GRID_H
+#define _GRID_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "interpol.h"
+#include "interpolHigh.h"
+#include "kernel.h"
+
+namespace Manta {
+class LevelsetGrid;
+
+//! Base class for all grids
+class GridBase : public PbClass {public:
+ enum GridType {TypeNone=0,TypeReal=1,TypeInt=2,TypeVec3=4,TypeMAC=8,TypeLevelset=16,TypeFlags=32}
+;
+
+ GridBase(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "GridBase::GridBase" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new GridBase(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"GridBase::GridBase" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::GridBase",e.what()); return -1; }
+ }
+
+
+ //! Get the grids X dimension
+ inline int getSizeX() const { return mSize.x; } static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getSizeX" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeX()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getSizeX" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getSizeX",e.what()); return 0; }
+ }
+
+ //! Get the grids Y dimension
+ inline int getSizeY() const { return mSize.y; } static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getSizeY" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeY()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getSizeY" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getSizeY",e.what()); return 0; }
+ }
+
+ //! Get the grids Z dimension
+ inline int getSizeZ() const { return mSize.z; } static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getSizeZ" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeZ()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getSizeZ" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getSizeZ",e.what()); return 0; }
+ }
+
+ //! Get the grids dimensions
+ inline Vec3i getSize() const { return mSize; } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getSize" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSize()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getSize" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getSize",e.what()); return 0; }
+ }
+
+
+ //! Get Stride in X dimension
+ inline IndexInt getStrideX() const { return 1; }
+ //! Get Stride in Y dimension
+ inline IndexInt getStrideY() const { return mSize.x; }
+ //! Get Stride in Z dimension
+ inline IndexInt getStrideZ() const { return mStrideZ; }
+
+ inline Real getDx() const { return mDx; }
+
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(int i, int j, int k) const;
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(IndexInt idx) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec3i& p, int bnd) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec3i& p) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec3& p, int bnd = 0) const { return isInBounds(toVec3i(p), bnd); }
+ //! Check if linear index is in the range of the array
+ inline bool isInBounds(IndexInt idx) const;
+
+ //! Get the type of grid
+ inline GridType getType() const { return mType; }
+ //! Check dimensionality
+ inline bool is3D() const { return m3D; } static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::is3D" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->is3D()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::is3D" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::is3D",e.what()); return 0; }
+ }
+
+
+ //! Get index into the data
+ inline IndexInt index(int i, int j, int k) const { DEBUG_ONLY(checkIndex(i,j,k)); return (IndexInt)i + (IndexInt)mSize.x * j + (IndexInt)mStrideZ * k; }
+ //! Get index into the data
+ inline IndexInt index(const Vec3i& pos) const { DEBUG_ONLY(checkIndex(pos.x,pos.y,pos.z)); return (IndexInt)pos.x + (IndexInt)mSize.x * pos.y + (IndexInt)mStrideZ * pos.z; }
+
+ //! grid4d compatibility functions
+ inline bool is4D() const { return false; } static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::is4D" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->is4D()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::is4D" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::is4D",e.what()); return 0; }
+ }
+
+ inline int getSizeT() const { return 1; } static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getSizeT" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeT()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getSizeT" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getSizeT",e.what()); return 0; }
+ }
+
+ inline int getStrideT() const { return 0; } static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); GridBase* pbo = dynamic_cast<GridBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "GridBase::getStrideT" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getStrideT()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"GridBase::getStrideT" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("GridBase::getStrideT",e.what()); return 0; }
+ }
+
+ inline int index(int i, int j, int k, int unused) const { return index(i,j,k); }
+ inline bool isInBounds(int i,int j, int k, int t, int bnd) const { if(t!=0) return false; return isInBounds( Vec3i(i,j,k), bnd ); }
+
+protected:
+
+ GridType mType;
+ Vec3i mSize;
+ Real mDx;
+ bool m3D; // precomputed Z shift: to ensure 2D compatibility, always use this instead of sx*sy !
+ IndexInt mStrideZ; public: PbArgs _args; }
+#define _C_GridBase
+;
+
+//! Grid class
+
+template<class T> class Grid : public GridBase {public:
+ //! init new grid, values are set to zero
+ Grid(FluidSolver* parent, bool show = true); static int _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Grid::Grid" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); bool show = _args.getOpt<bool >("show",1,true,&_lock); obj = new Grid(parent,show); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Grid::Grid" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Grid::Grid",e.what()); return -1; }
+ }
+
+ //! init new grid with an existing array
+ Grid(FluidSolver* parent, T* data, bool show = true);
+ //! create new & copy content from another grid
+ Grid(const Grid<T>& a);
+ //! return memory to solver
+ virtual ~Grid();
+
+ typedef T BASETYPE;
+ typedef GridBase BASETYPE_GRID;
+
+ void save(std::string name); static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::save",e.what()); return 0; }
+ }
+
+ void load(std::string name); static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::load",e.what()); return 0; }
+ }
+
+
+ //! set all cells to zero
+ void clear(); static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::clear",e.what()); return 0; }
+ }
+
+
+ //! all kinds of access functions, use grid(), grid[] or grid.get()
+ //! access data
+ inline T get(int i,int j, int k) const { return mData[index(i,j,k)]; }
+ //! access data
+ inline T& get(int i,int j, int k) { return mData[index(i,j,k)]; }
+ //! access data
+ inline T get(IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T get(const Vec3i& pos) const { return mData[index(pos)]; }
+ //! access data
+ inline T& operator()(int i, int j, int k) { return mData[index(i, j, k)]; }
+ //! access data
+ inline T operator()(int i, int j, int k) const { return mData[index(i, j, k)]; }
+ //! access data
+ inline T& operator()(IndexInt idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T operator()(IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T& operator()(const Vec3i& pos) { return mData[index(pos)]; }
+ //! access data
+ inline T operator()(const Vec3i& pos) const { return mData[index(pos)]; }
+ //! access data
+ inline T& operator[](IndexInt idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline const T operator[](IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+
+ // interpolated access
+ inline T getInterpolated(const Vec3& pos) const { return interpol<T>(mData, mSize, mStrideZ, pos); }
+ inline void setInterpolated(const Vec3& pos, const T& val, Grid<Real>& sumBuffer) const { setInterpol<T>(mData, mSize, mStrideZ, pos, val, &sumBuffer[0]); }
+ // higher order interpolation (1=linear, 2=cubic)
+ inline T getInterpolatedHi(const Vec3& pos, int order) const {
+ switch(order) {
+ case 1: return interpol <T>(mData, mSize, mStrideZ, pos);
+ case 2: return interpolCubic<T>(mData, mSize, mStrideZ, pos);
+ default: assertMsg(false, "Unknown interpolation order "<<order); }
+ return T(0.); // should never be reached, just to prevent compiler warnings
+ }
+
+ // assignment / copy
+
+ //! warning - do not use "=" for grids in python, this copies the reference! not the grid content...
+ //Grid<T>& operator=(const Grid<T>& a);
+ //! copy content from other grid (use this one instead of operator= !)
+ Grid<T>& copyFrom(const Grid<T>& a, bool copyType=true ); static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::copyFrom" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<T>& a = *_args.getPtr<Grid<T> >("a",0,&_lock); bool copyType = _args.getOpt<bool >("copyType",1,true ,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->copyFrom(a,copyType)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::copyFrom" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::copyFrom",e.what()); return 0; }
+ }
+ // old: { *this = a; }
+
+ // helper functions to work with grids in scene files
+
+ //! get grid type
+ int getGridType(); static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getGridType" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getGridType()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getGridType" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getGridType",e.what()); return 0; }
+ }
+
+
+ //! add/subtract other grid
+ void add(const Grid<T>& a); static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::add" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<T>& a = *_args.getPtr<Grid<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->add(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::add" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::add",e.what()); return 0; }
+ }
+
+ void sub(const Grid<T>& a); static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::sub" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<T>& a = *_args.getPtr<Grid<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->sub(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::sub" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::sub",e.what()); return 0; }
+ }
+
+ //! set all cells to constant value
+ void setConst(T s); static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::setConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::setConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::setConst",e.what()); return 0; }
+ }
+
+ //! add constant to all grid cells
+ void addConst(T s); static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::addConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::addConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::addConst",e.what()); return 0; }
+ }
+
+ //! add scaled other grid to current one (note, only "Real" factor, "T" type not supported here!)
+ void addScaled(const Grid<T>& a, const T& factor); static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::addScaled" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<T>& a = *_args.getPtr<Grid<T> >("a",0,&_lock); const T& factor = *_args.getPtr<T >("factor",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addScaled(a,factor); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::addScaled" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::addScaled",e.what()); return 0; }
+ }
+
+ //! multiply contents of grid
+ void mult( const Grid<T>& a); static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::mult" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<T>& a = *_args.getPtr<Grid<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->mult(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::mult" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::mult",e.what()); return 0; }
+ }
+
+ //! multiply each cell by a constant scalar value
+ void multConst(T s); static PyObject* _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::multConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->multConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::multConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::multConst",e.what()); return 0; }
+ }
+
+ //! clamp content to range (for vec3, clamps each component separately)
+ void clamp(Real min, Real max); static PyObject* _W_22 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::clamp" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real min = _args.get<Real >("min",0,&_lock); Real max = _args.get<Real >("max",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clamp(min,max); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::clamp" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::clamp",e.what()); return 0; }
+ }
+
+ //! reduce small values to zero
+ void stomp(const T& threshold); static PyObject* _W_23 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::stomp" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& threshold = *_args.getPtr<T >("threshold",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->stomp(threshold); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::stomp" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::stomp",e.what()); return 0; }
+ }
+
+
+ // common compound operators
+ //! get absolute max value in grid
+ Real getMaxAbs() const ; static PyObject* _W_24 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getMaxAbs" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxAbs()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getMaxAbs" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getMaxAbs",e.what()); return 0; }
+ }
+
+ //! get max value in grid
+ Real getMax() const ; static PyObject* _W_25 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMax()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getMax",e.what()); return 0; }
+ }
+
+ //! get min value in grid
+ Real getMin() const ; static PyObject* _W_26 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMin()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getMin",e.what()); return 0; }
+ }
+
+ //! calculate L1 norm of grid content
+ Real getL1(int bnd=0); static PyObject* _W_27 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getL1" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int bnd = _args.getOpt<int >("bnd",0,0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->getL1(bnd)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getL1" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getL1",e.what()); return 0; }
+ }
+
+ //! calculate L2 norm of grid content
+ Real getL2(int bnd=0); static PyObject* _W_28 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getL2" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int bnd = _args.getOpt<int >("bnd",0,0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->getL2(bnd)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getL2" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getL2",e.what()); return 0; }
+ }
+
+
+ //! set all boundary cells to constant value (Dirichlet)
+ void setBound(T value, int boundaryWidth=1); static PyObject* _W_29 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::setBound" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T value = _args.get<T >("value",0,&_lock); int boundaryWidth = _args.getOpt<int >("boundaryWidth",1,1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setBound(value,boundaryWidth); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::setBound" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::setBound",e.what()); return 0; }
+ }
+
+ //! set all boundary cells to last inner value (Neumann)
+ void setBoundNeumann(int boundaryWidth=1); static PyObject* _W_30 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::setBoundNeumann" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int boundaryWidth = _args.getOpt<int >("boundaryWidth",0,1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setBoundNeumann(boundaryWidth); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::setBoundNeumann" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::setBoundNeumann",e.what()); return 0; }
+ }
+
+
+ //! get data pointer of grid
+ std::string getDataPointer(); static PyObject* _W_31 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::getDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::getDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::getDataPointer",e.what()); return 0; }
+ }
+
+
+ //! debugging helper, print grid from python. skip boundary of width bnd
+ void printGrid(int zSlice=-1, bool printIndex=false, int bnd=1); static PyObject* _W_32 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid::printGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int zSlice = _args.getOpt<int >("zSlice",0,-1,&_lock); bool printIndex = _args.getOpt<bool >("printIndex",1,false,&_lock); int bnd = _args.getOpt<int >("bnd",2,1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->printGrid(zSlice,printIndex,bnd); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid::printGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid::printGrid",e.what()); return 0; }
+ }
+
+
+ // c++ only operators
+ template<class S> Grid<T>& operator+=(const Grid<S>& a);
+ template<class S> Grid<T>& operator+=(const S& a);
+ template<class S> Grid<T>& operator-=(const Grid<S>& a);
+ template<class S> Grid<T>& operator-=(const S& a);
+ template<class S> Grid<T>& operator*=(const Grid<S>& a);
+ template<class S> Grid<T>& operator*=(const S& a);
+ template<class S> Grid<T>& operator/=(const Grid<S>& a);
+ template<class S> Grid<T>& operator/=(const S& a);
+ Grid<T>& safeDivide(const Grid<T>& a);
+
+ //! Swap data with another grid (no actual data is moved)
+ void swap(Grid<T>& other);
+
+ //! grid4d compatibility functions
+ inline T& operator()(int i, int j, int k, int unused) { return mData[index(i, j, k)]; }
+ inline T operator() (int i, int j, int k, int unused) const { return mData[index(i, j, k)]; }
+
+protected: T* mData; bool externalData; // True if mData is managed outside of the Fluidsolver
+public: PbArgs _args; }
+#define _C_Grid
+;
+
+// Python doesn't know about templates: explicit aliases needed
+
+
+
+
+//! Special function for staggered grids
+class MACGrid : public Grid<Vec3> {public:
+ MACGrid(FluidSolver* parent, bool show=true) :Grid<Vec3>(parent,show){
+ mType = (GridType)(TypeMAC | TypeVec3); } static int _W_33 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "MACGrid::MACGrid" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); bool show = _args.getOpt<bool >("show",1,true,&_lock); obj = new MACGrid(parent,show); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"MACGrid::MACGrid" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("MACGrid::MACGrid",e.what()); return -1; }
+ }
+
+ MACGrid(FluidSolver* parent, Vec3* data, bool show=true) : Grid<Vec3>(parent, data, show) {
+ mType = (GridType)(TypeMAC | TypeVec3); }
+
+ // specialized functions for interpolating MAC information
+ inline Vec3 getCentered(int i, int j, int k) const;
+ inline Vec3 getCentered(const Vec3i& pos) const { return getCentered(pos.x, pos.y, pos.z); }
+ inline Vec3 getAtMACX(int i, int j, int k) const;
+ inline Vec3 getAtMACY(int i, int j, int k) const;
+ inline Vec3 getAtMACZ(int i, int j, int k) const;
+ // interpolation
+ inline Vec3 getInterpolated(const Vec3& pos) const { return interpolMAC(mData, mSize, mStrideZ, pos); }
+ inline void setInterpolated(const Vec3& pos, const Vec3& val, Vec3* tmp) const { return setInterpolMAC(mData, mSize, mStrideZ, pos, val, tmp); }
+ inline Vec3 getInterpolatedHi(const Vec3& pos, int order) const {
+ switch(order) {
+ case 1: return interpolMAC (mData, mSize, mStrideZ, pos);
+ case 2: return interpolCubicMAC(mData, mSize, mStrideZ, pos);
+ default: assertMsg(false, "Unknown interpolation order "<<order); }
+ return Vec3(0.); // should never be reached, just to prevent compiler warnings
+ }
+ // specials for mac grid:
+ template<int comp> inline Real getInterpolatedComponent(Vec3 pos) const { return interpolComponent<comp>(mData, mSize, mStrideZ, pos); }
+ template<int comp> inline Real getInterpolatedComponentHi(const Vec3& pos, int order) const {
+ switch(order) {
+ case 1: return interpolComponent<comp>(mData, mSize, mStrideZ, pos);
+ case 2: return interpolCubicMAC(mData, mSize, mStrideZ, pos)[comp]; // warning - not yet optimized
+ default: assertMsg(false, "Unknown interpolation order "<<order); }
+ return 0.; // should never be reached, just to prevent compiler warnings
+ }
+
+ //! set all boundary cells of a MAC grid to certain value (Dirchlet). Respects staggered grid locations
+ //! optionally, only set normal components
+ void setBoundMAC(Vec3 value, int boundaryWidth, bool normalOnly=false); static PyObject* _W_34 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MACGrid* pbo = dynamic_cast<MACGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MACGrid::setBoundMAC" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 value = _args.get<Vec3 >("value",0,&_lock); int boundaryWidth = _args.get<int >("boundaryWidth",1,&_lock); bool normalOnly = _args.getOpt<bool >("normalOnly",2,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setBoundMAC(value,boundaryWidth,normalOnly); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MACGrid::setBoundMAC" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MACGrid::setBoundMAC",e.what()); return 0; }
+ }
+
+ protected: public: PbArgs _args; }
+#define _C_MACGrid
+;
+
+//! Special functions for FlagGrid
+class FlagGrid : public Grid<int> {public:
+ FlagGrid(FluidSolver* parent, int dim=3, bool show=true) :Grid<int>(parent,show){
+ mType = (GridType)(TypeFlags | TypeInt); } static int _W_35 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "FlagGrid::FlagGrid" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); int dim = _args.getOpt<int >("dim",1,3,&_lock); bool show = _args.getOpt<bool >("show",2,true,&_lock); obj = new FlagGrid(parent,dim,show); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"FlagGrid::FlagGrid" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("FlagGrid::FlagGrid",e.what()); return -1; }
+ }
+
+ FlagGrid(FluidSolver* parent, int* data, int dim = 3, bool show=true) : Grid<int>(parent, data, show) {
+ mType = (GridType)(TypeFlags | TypeInt); }
+
+ //! types of cells, in/outflow can be combined, e.g., TypeFluid|TypeInflow
+ enum CellType {TypeNone=0,TypeFluid=1,TypeObstacle=2,TypeEmpty=4,TypeInflow=8,TypeOutflow=16,TypeOpen=32,TypeStick=64,TypeReserved=256}
+;
+
+ //! access for particles
+ inline int getAt(const Vec3& pos) const { return mData[index((int)pos.x, (int)pos.y, (int)pos.z)]; }
+
+ //! check for different flag types
+ inline bool isObstacle(IndexInt idx) const { return get(idx) & TypeObstacle; }
+ inline bool isObstacle(int i, int j, int k) const { return get(i,j,k) & TypeObstacle; }
+ inline bool isObstacle(const Vec3i& pos) const { return get(pos) & TypeObstacle; }
+ inline bool isObstacle(const Vec3& pos) const { return getAt(pos) & TypeObstacle; }
+ inline bool isFluid(IndexInt idx) const { return get(idx) & TypeFluid; }
+ inline bool isFluid(int i, int j, int k) const { return get(i,j,k) & TypeFluid; }
+ inline bool isFluid(const Vec3i& pos) const { return get(pos) & TypeFluid; }
+ inline bool isFluid(const Vec3& pos) const { return getAt(pos) & TypeFluid; }
+ inline bool isInflow(IndexInt idx) const { return get(idx) & TypeInflow; }
+ inline bool isInflow(int i, int j, int k) const { return get(i,j,k) & TypeInflow; }
+ inline bool isInflow(const Vec3i& pos) const { return get(pos) & TypeInflow; }
+ inline bool isInflow(const Vec3& pos) const { return getAt(pos) & TypeInflow; }
+ inline bool isEmpty(IndexInt idx) const { return get(idx) & TypeEmpty; }
+ inline bool isEmpty(int i, int j, int k) const { return get(i,j,k) & TypeEmpty; }
+ inline bool isEmpty(const Vec3i& pos) const { return get(pos) & TypeEmpty; }
+ inline bool isEmpty(const Vec3& pos) const { return getAt(pos) & TypeEmpty; }
+ inline bool isOutflow(IndexInt idx) const { return get(idx) & TypeOutflow; }
+ inline bool isOutflow(int i, int j, int k) const { return get(i, j, k) & TypeOutflow; }
+ inline bool isOutflow(const Vec3i& pos) const { return get(pos) & TypeOutflow; }
+ inline bool isOutflow(const Vec3& pos) const { return getAt(pos) & TypeOutflow; }
+ inline bool isOpen(IndexInt idx) const { return get(idx) & TypeOpen; }
+ inline bool isOpen(int i, int j, int k) const { return get(i, j, k) & TypeOpen; }
+ inline bool isOpen(const Vec3i& pos) const { return get(pos) & TypeOpen; }
+ inline bool isOpen(const Vec3& pos) const { return getAt(pos) & TypeOpen; }
+ inline bool isStick(IndexInt idx) const { return get(idx) & TypeStick; }
+ inline bool isStick(int i, int j, int k) const { return get(i,j,k) & TypeStick; }
+ inline bool isStick(const Vec3i& pos) const { return get(pos) & TypeStick; }
+ inline bool isStick(const Vec3& pos) const { return getAt(pos) & TypeStick; }
+
+
+ void InitMinXWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ void InitMaxXWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ void InitMinYWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ void InitMaxYWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ void InitMinZWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ void InitMaxZWall(const int &boundaryWidth, Grid<Real>& phiWalls);
+ // Python callables
+
+
+
+
+
+void initDomain( const int &boundaryWidth = 0 , const std::string &wall = "xXyYzZ" , const std::string &open = " " , const std::string &inflow = " " , const std::string &outflow = " " , Grid<Real>* phiWalls = 0x00 ); static PyObject* _W_36 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FlagGrid::initDomain" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const int& boundaryWidth = _args.getOpt<int >("boundaryWidth",0,0 ,&_lock); const std::string& wall = _args.getOpt<std::string >("wall",1,"xXyYzZ" ,&_lock); const std::string& open = _args.getOpt<std::string >("open",2," " ,&_lock); const std::string& inflow = _args.getOpt<std::string >("inflow",3," " ,&_lock); const std::string& outflow = _args.getOpt<std::string >("outflow",4," " ,&_lock); Grid<Real>* phiWalls = _args.getPtrOpt<Grid<Real> >("phiWalls",5,0x00 ,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->initDomain(boundaryWidth,wall,open,inflow,outflow,phiWalls); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FlagGrid::initDomain" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FlagGrid::initDomain",e.what()); return 0; }
+ }
+
+
+ void initBoundaries( const int &boundaryWidth, const int *types );
+
+ //! set fluid flags inside levelset (liquids)
+ void updateFromLevelset(LevelsetGrid& levelset, LevelsetGrid* obsLevelset=NULL); static PyObject* _W_37 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FlagGrid::updateFromLevelset" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; LevelsetGrid& levelset = *_args.getPtr<LevelsetGrid >("levelset",0,&_lock); LevelsetGrid* obsLevelset = _args.getPtrOpt<LevelsetGrid >("obsLevelset",1,NULL,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->updateFromLevelset(levelset,obsLevelset); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FlagGrid::updateFromLevelset" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FlagGrid::updateFromLevelset",e.what()); return 0; }
+ }
+
+ //! set all cells (except obs/in/outflow) to type (fluid by default)
+ void fillGrid(int type=TypeFluid); static PyObject* _W_38 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FlagGrid::fillGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int type = _args.getOpt<int >("type",0,TypeFluid,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->fillGrid(type); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FlagGrid::fillGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FlagGrid::fillGrid",e.what()); return 0; }
+ }
+
+ //! count no. of cells matching flags via "AND"
+ //! warning for large grids! only regular int returned (due to python interface)
+ //! optionally creates mask in RealGrid (1 where flag matches, 0 otherwise)
+ int countCells(int flag, int bnd=0, Grid<Real>* mask=NULL); static PyObject* _W_39 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "FlagGrid::countCells" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int flag = _args.get<int >("flag",0,&_lock); int bnd = _args.getOpt<int >("bnd",1,0,&_lock); Grid<Real>* mask = _args.getPtrOpt<Grid<Real> >("mask",2,NULL,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->countCells(flag,bnd,mask)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"FlagGrid::countCells" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("FlagGrid::countCells",e.what()); return 0; }
+ }
+ public: PbArgs _args; }
+#define _C_FlagGrid
+;
+
+//! helper to compute grid conversion factor between local coordinates of two grids
+inline Vec3 calcGridSizeFactor(Vec3i s1, Vec3i s2) {
+ return Vec3( Real(s1[0])/s2[0], Real(s1[1])/s2[1], Real(s1[2])/s2[2] );
+}
+
+// prototypes for grid plugins
+void copyMacToVec3(MACGrid &source, Grid<Vec3>& target);
+void convertMacToVec3(MACGrid &source, Grid<Vec3>& target);
+void resampleVec3ToMac(Grid<Vec3>& source, MACGrid &target);
+void resampleMacToVec3 (MACGrid &source, Grid<Vec3>& target );
+
+void getComponent(const Grid<Vec3>& source, Grid<Real>& target, int component);
+void setComponent(const Grid<Real>& source, Grid<Vec3>& target, int component);
+
+
+
+
+//******************************************************************************
+// Implementation of inline functions
+
+inline void GridBase::checkIndex(int i, int j, int k) const {
+ if (i<0 || j<0 || k<0 || i>=mSize.x || j>=mSize.y || k>=mSize.z) {
+ std::ostringstream s;
+ s << "Grid " << mName << " dim " << mSize << " : index " << i << "," << j << "," << k << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+inline void GridBase::checkIndex(IndexInt idx) const {
+ if (idx<0 || idx >= mSize.x * mSize.y * mSize.z) {
+ std::ostringstream s;
+ s << "Grid " << mName << " dim " << mSize << " : index " << idx << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+bool GridBase::isInBounds(const Vec3i& p) const {
+ return (p.x >= 0 && p.y >= 0 && p.z >= 0 && p.x < mSize.x && p.y < mSize.y && p.z < mSize.z);
+}
+
+bool GridBase::isInBounds(const Vec3i& p, int bnd) const {
+ bool ret = (p.x >= bnd && p.y >= bnd && p.x < mSize.x-bnd && p.y < mSize.y-bnd);
+ if(this->is3D()) {
+ ret &= (p.z >= bnd && p.z < mSize.z-bnd);
+ } else {
+ ret &= (p.z == 0);
+ }
+ return ret;
+}
+//! Check if linear index is in the range of the array
+bool GridBase::isInBounds(IndexInt idx) const {
+ if (idx<0 || idx >= mSize.x * mSize.y * mSize.z) {
+ return false;
+ }
+ return true;
+}
+
+inline Vec3 MACGrid::getCentered(int i, int j, int k) const {
+ DEBUG_ONLY(checkIndex(i+1,j+1,k));
+ const IndexInt idx = index(i,j,k);
+ Vec3 v = Vec3(0.5* (mData[idx].x + mData[idx+1].x),
+ 0.5* (mData[idx].y + mData[idx+mSize.x].y),
+ 0.);
+ if( this->is3D() ) {
+ DEBUG_ONLY(checkIndex(idx+mStrideZ));
+ v[2] = 0.5* (mData[idx].z + mData[idx+mStrideZ].z);
+ }
+ return v;
+}
+
+inline Vec3 MACGrid::getAtMACX(int i, int j, int k) const {
+ DEBUG_ONLY(checkIndex(i-1,j+1,k));
+ const IndexInt idx = index(i,j,k);
+ Vec3 v = Vec3( (mData[idx].x),
+ 0.25* (mData[idx].y + mData[idx-1].y + mData[idx+mSize.x].y + mData[idx+mSize.x-1].y),
+ 0.);
+ if( this->is3D() ) {
+ DEBUG_ONLY(checkIndex(idx+mStrideZ-1));
+ v[2] = 0.25* (mData[idx].z + mData[idx-1].z + mData[idx+mStrideZ].z + mData[idx+mStrideZ-1].z);
+ }
+ return v;
+}
+
+inline Vec3 MACGrid::getAtMACY(int i, int j, int k) const {
+ DEBUG_ONLY(checkIndex(i+1,j-1,k));
+ const IndexInt idx = index(i,j,k);
+ Vec3 v = Vec3(0.25* (mData[idx].x + mData[idx-mSize.x].x + mData[idx+1].x + mData[idx+1-mSize.x].x),
+ (mData[idx].y), 0. );
+ if( this->is3D() ) {
+ DEBUG_ONLY(checkIndex(idx+mStrideZ-mSize.x));
+ v[2] = 0.25* (mData[idx].z + mData[idx-mSize.x].z + mData[idx+mStrideZ].z + mData[idx+mStrideZ-mSize.x].z);
+ }
+ return v;
+}
+
+inline Vec3 MACGrid::getAtMACZ(int i, int j, int k) const {
+ const IndexInt idx = index(i,j,k);
+ DEBUG_ONLY(checkIndex(idx-mStrideZ));
+ DEBUG_ONLY(checkIndex(idx+mSize.x-mStrideZ));
+ Vec3 v = Vec3(0.25* (mData[idx].x + mData[idx-mStrideZ].x + mData[idx+1].x + mData[idx+1-mStrideZ].x),
+ 0.25* (mData[idx].y + mData[idx-mStrideZ].y + mData[idx+mSize.x].y + mData[idx+mSize.x-mStrideZ].y),
+ (mData[idx].z) );
+ return v;
+}
+
+template <class T, class S> struct gridAdd : public KernelBase {
+ gridAdd(Grid<T>& me, const Grid<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<S>& other ) const { me[idx] += other[idx]; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<S>& getArg1() {
+ return other; }
+ typedef Grid<S> type1; void runMessage() { debMsg("Executing kernel gridAdd ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; const Grid<S>& other; }
+;
+template <class T, class S> struct gridSub : public KernelBase {
+ gridSub(Grid<T>& me, const Grid<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<S>& other ) const { me[idx] -= other[idx]; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<S>& getArg1() {
+ return other; }
+ typedef Grid<S> type1; void runMessage() { debMsg("Executing kernel gridSub ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; const Grid<S>& other; }
+;
+template <class T, class S> struct gridMult : public KernelBase {
+ gridMult(Grid<T>& me, const Grid<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<S>& other ) const { me[idx] *= other[idx]; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<S>& getArg1() {
+ return other; }
+ typedef Grid<S> type1; void runMessage() { debMsg("Executing kernel gridMult ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; const Grid<S>& other; }
+;
+template <class T, class S> struct gridDiv : public KernelBase {
+ gridDiv(Grid<T>& me, const Grid<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<S>& other ) const { me[idx] /= other[idx]; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<S>& getArg1() {
+ return other; }
+ typedef Grid<S> type1; void runMessage() { debMsg("Executing kernel gridDiv ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; const Grid<S>& other; }
+;
+template <class T, class S> struct gridAddScalar : public KernelBase {
+ gridAddScalar(Grid<T>& me, const S& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const S& other ) const { me[idx] += other; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel gridAddScalar ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; const S& other; }
+;
+template <class T, class S> struct gridMultScalar : public KernelBase {
+ gridMultScalar(Grid<T>& me, const S& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const S& other ) const { me[idx] *= other; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel gridMultScalar ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; const S& other; }
+;
+template <class T, class S> struct gridScaledAdd : public KernelBase {
+ gridScaledAdd(Grid<T>& me, const Grid<T>& other, const S& factor) : KernelBase(&me,0) ,me(me),other(other),factor(factor) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<T>& other, const S& factor ) const { me[idx] += factor * other[idx]; } inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<T>& getArg1() {
+ return other; }
+ typedef Grid<T> type1;inline const S& getArg2() {
+ return factor; }
+ typedef S type2; void runMessage() { debMsg("Executing kernel gridScaledAdd ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other,factor); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; const Grid<T>& other; const S& factor; }
+;
+
+template <class T> struct gridSetConst : public KernelBase {
+ gridSetConst(Grid<T>& grid, T value) : KernelBase(&grid,0) ,grid(grid),value(value) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& grid, T value ) const { grid[idx] = value; } inline Grid<T>& getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel gridSetConst ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, grid,value); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& grid; T value; }
+;
+
+template<class T> template<class S> Grid<T>& Grid<T>::operator+= (const Grid<S>& a) {
+ gridAdd<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator+= (const S& a) {
+ gridAddScalar<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator-= (const Grid<S>& a) {
+ gridSub<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator-= (const S& a) {
+ gridAddScalar<T,S> (*this, -a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator*= (const Grid<S>& a) {
+ gridMult<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator*= (const S& a) {
+ gridMultScalar<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator/= (const Grid<S>& a) {
+ gridDiv<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid<T>& Grid<T>::operator/= (const S& a) {
+ S rez((S)1.0 / a);
+ gridMultScalar<T,S> (*this, rez);
+ return *this;
+}
+
+//******************************************************************************
+// Other helper functions
+
+// compute gradient of a scalar grid
+inline Vec3 getGradient(const Grid<Real>& data, int i, int j, int k) {
+ Vec3 v;
+
+ if (i > data.getSizeX()-2) i= data.getSizeX()-2;
+ if (j > data.getSizeY()-2) j= data.getSizeY()-2;
+ if (i < 1) i = 1;
+ if (j < 1) j = 1;
+ v = Vec3( data(i+1,j ,k ) - data(i-1,j ,k ) ,
+ data(i ,j+1,k ) - data(i ,j-1,k ) , 0. );
+
+ if(data.is3D()) {
+ if (k > data.getSizeZ()-2) k= data.getSizeZ()-2;
+ if (k < 1) k = 1;
+ v[2]= data(i ,j ,k+1) - data(i ,j ,k-1);
+ }
+
+ return v;
+}
+
+// interpolate grid from one size to another size
+
+template <class S> struct knInterpolateGridTempl : public KernelBase {
+ knInterpolateGridTempl(Grid<S>& target, const Grid<S>& source, const Vec3& sourceFactor , Vec3 offset, int orderSpace=1 ) : KernelBase(&target,0) ,target(target),source(source),sourceFactor(sourceFactor),offset(offset),orderSpace(orderSpace) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<S>& target, const Grid<S>& source, const Vec3& sourceFactor , Vec3 offset, int orderSpace=1 ) const {
+ Vec3 pos = Vec3(i,j,k) * sourceFactor + offset;
+ if(!source.is3D()) pos[2] = 0; // allow 2d -> 3d
+ target(i,j,k) = source.getInterpolatedHi(pos, orderSpace);
+} inline Grid<S>& getArg0() {
+ return target; }
+ typedef Grid<S> type0;inline const Grid<S>& getArg1() {
+ return source; }
+ typedef Grid<S> type1;inline const Vec3& getArg2() {
+ return sourceFactor; }
+ typedef Vec3 type2;inline Vec3& getArg3() {
+ return offset; }
+ typedef Vec3 type3;inline int& getArg4() {
+ return orderSpace; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel knInterpolateGridTempl ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,target,source,sourceFactor,offset,orderSpace); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,target,source,sourceFactor,offset,orderSpace); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<S>& target; const Grid<S>& source; const Vec3& sourceFactor; Vec3 offset; int orderSpace; }
+;
+// template glue code - choose interpolation based on template arguments
+template<class GRID>
+void interpolGridTempl( GRID& target, GRID& source ) {
+ errMsg("interpolGridTempl - Only valid for specific instantiations");
+}
+
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h.reg
new file mode 100644
index 00000000000..85eade2f2d9
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h.reg
@@ -0,0 +1,72 @@
+#include "grid.h"
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","GridBase","PbClass"); template<> const char* Namify<GridBase >::S = "GridBase";
+>GridBase^
+&static const Pb::Register _R_$IDX$ ("GridType_TypeNone",0);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeReal",1);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeInt",2);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeVec3",4);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeMAC",8);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeLevelset",16);
+&static const Pb::Register _R_$IDX$ ("GridType_TypeFlags",32);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","GridBase",GridBase::_W_0);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getSizeX",GridBase::_W_1);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getSizeY",GridBase::_W_2);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getSizeZ",GridBase::_W_3);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getSize",GridBase::_W_4);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","is3D",GridBase::_W_5);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","is4D",GridBase::_W_6);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getSizeT",GridBase::_W_7);
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","getStrideT",GridBase::_W_8);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","Grid<$CT$>","GridBase"); template<> const char* Namify<Grid<$CT$> >::S = "Grid<$CT$>";
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","Grid",Grid<$CT$>::_W_9);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","save",Grid<$CT$>::_W_10);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","load",Grid<$CT$>::_W_11);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","clear",Grid<$CT$>::_W_12);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","copyFrom",Grid<$CT$>::_W_13);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getGridType",Grid<$CT$>::_W_14);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","add",Grid<$CT$>::_W_15);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","sub",Grid<$CT$>::_W_16);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","setConst",Grid<$CT$>::_W_17);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","addConst",Grid<$CT$>::_W_18);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","addScaled",Grid<$CT$>::_W_19);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","mult",Grid<$CT$>::_W_20);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","multConst",Grid<$CT$>::_W_21);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","clamp",Grid<$CT$>::_W_22);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","stomp",Grid<$CT$>::_W_23);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getMaxAbs",Grid<$CT$>::_W_24);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getMax",Grid<$CT$>::_W_25);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getMin",Grid<$CT$>::_W_26);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getL1",Grid<$CT$>::_W_27);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getL2",Grid<$CT$>::_W_28);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","setBound",Grid<$CT$>::_W_29);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","setBoundNeumann",Grid<$CT$>::_W_30);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getDataPointer",Grid<$CT$>::_W_31);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","printGrid",Grid<$CT$>::_W_32);
+>Grid^int
+&static const Pb::Register _R_$IDX$ ("Grid<int>","IntGrid","");
+>Grid^Real
+&static const Pb::Register _R_$IDX$ ("Grid<Real>","RealGrid","");
+>Grid^Vec3
+&static const Pb::Register _R_$IDX$ ("Grid<Vec3>","VecGrid","");
++MACGrid^ static const Pb::Register _R_$IDX$ ("MACGrid","MACGrid","Grid<$BT$>"); template<> const char* Namify<MACGrid >::S = "MACGrid";
+>MACGrid^
+@MACGrid^^Grid^Vec3
++MACGrid^ static const Pb::Register _R_$IDX$ ("MACGrid","MACGrid",MACGrid::_W_33);
++MACGrid^ static const Pb::Register _R_$IDX$ ("MACGrid","setBoundMAC",MACGrid::_W_34);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","FlagGrid","Grid<$BT$>"); template<> const char* Namify<FlagGrid >::S = "FlagGrid";
+>FlagGrid^
+@FlagGrid^^Grid^int
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","FlagGrid",FlagGrid::_W_35);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeNone",0);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeFluid",1);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeObstacle",2);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeEmpty",4);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeInflow",8);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeOutflow",16);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeOpen",32);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeStick",64);
+&static const Pb::Register _R_$IDX$ ("CellType_TypeReserved",256);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","initDomain",FlagGrid::_W_36);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","updateFromLevelset",FlagGrid::_W_37);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","fillGrid",FlagGrid::_W_38);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","countCells",FlagGrid::_W_39);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h.reg.cpp
new file mode 100644
index 00000000000..c4a104fa03a
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid.h.reg.cpp
@@ -0,0 +1,233 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "grid.h"
+namespace Manta {
+#ifdef _C_FlagGrid
+ static const Pb::Register _R_26 ("FlagGrid","FlagGrid","Grid<int>"); template<> const char* Namify<FlagGrid >::S = "FlagGrid";
+ static const Pb::Register _R_27 ("FlagGrid","FlagGrid",FlagGrid::_W_35);
+ static const Pb::Register _R_28 ("FlagGrid","initDomain",FlagGrid::_W_36);
+ static const Pb::Register _R_29 ("FlagGrid","updateFromLevelset",FlagGrid::_W_37);
+ static const Pb::Register _R_30 ("FlagGrid","fillGrid",FlagGrid::_W_38);
+ static const Pb::Register _R_31 ("FlagGrid","countCells",FlagGrid::_W_39);
+#endif
+#ifdef _C_Grid
+ static const Pb::Register _R_32 ("Grid<int>","Grid<int>","GridBase"); template<> const char* Namify<Grid<int> >::S = "Grid<int>";
+ static const Pb::Register _R_33 ("Grid<int>","Grid",Grid<int>::_W_9);
+ static const Pb::Register _R_34 ("Grid<int>","save",Grid<int>::_W_10);
+ static const Pb::Register _R_35 ("Grid<int>","load",Grid<int>::_W_11);
+ static const Pb::Register _R_36 ("Grid<int>","clear",Grid<int>::_W_12);
+ static const Pb::Register _R_37 ("Grid<int>","copyFrom",Grid<int>::_W_13);
+ static const Pb::Register _R_38 ("Grid<int>","getGridType",Grid<int>::_W_14);
+ static const Pb::Register _R_39 ("Grid<int>","add",Grid<int>::_W_15);
+ static const Pb::Register _R_40 ("Grid<int>","sub",Grid<int>::_W_16);
+ static const Pb::Register _R_41 ("Grid<int>","setConst",Grid<int>::_W_17);
+ static const Pb::Register _R_42 ("Grid<int>","addConst",Grid<int>::_W_18);
+ static const Pb::Register _R_43 ("Grid<int>","addScaled",Grid<int>::_W_19);
+ static const Pb::Register _R_44 ("Grid<int>","mult",Grid<int>::_W_20);
+ static const Pb::Register _R_45 ("Grid<int>","multConst",Grid<int>::_W_21);
+ static const Pb::Register _R_46 ("Grid<int>","clamp",Grid<int>::_W_22);
+ static const Pb::Register _R_47 ("Grid<int>","stomp",Grid<int>::_W_23);
+ static const Pb::Register _R_48 ("Grid<int>","getMaxAbs",Grid<int>::_W_24);
+ static const Pb::Register _R_49 ("Grid<int>","getMax",Grid<int>::_W_25);
+ static const Pb::Register _R_50 ("Grid<int>","getMin",Grid<int>::_W_26);
+ static const Pb::Register _R_51 ("Grid<int>","getL1",Grid<int>::_W_27);
+ static const Pb::Register _R_52 ("Grid<int>","getL2",Grid<int>::_W_28);
+ static const Pb::Register _R_53 ("Grid<int>","setBound",Grid<int>::_W_29);
+ static const Pb::Register _R_54 ("Grid<int>","setBoundNeumann",Grid<int>::_W_30);
+ static const Pb::Register _R_55 ("Grid<int>","getDataPointer",Grid<int>::_W_31);
+ static const Pb::Register _R_56 ("Grid<int>","printGrid",Grid<int>::_W_32);
+ static const Pb::Register _R_57 ("Grid<Real>","Grid<Real>","GridBase"); template<> const char* Namify<Grid<Real> >::S = "Grid<Real>";
+ static const Pb::Register _R_58 ("Grid<Real>","Grid",Grid<Real>::_W_9);
+ static const Pb::Register _R_59 ("Grid<Real>","save",Grid<Real>::_W_10);
+ static const Pb::Register _R_60 ("Grid<Real>","load",Grid<Real>::_W_11);
+ static const Pb::Register _R_61 ("Grid<Real>","clear",Grid<Real>::_W_12);
+ static const Pb::Register _R_62 ("Grid<Real>","copyFrom",Grid<Real>::_W_13);
+ static const Pb::Register _R_63 ("Grid<Real>","getGridType",Grid<Real>::_W_14);
+ static const Pb::Register _R_64 ("Grid<Real>","add",Grid<Real>::_W_15);
+ static const Pb::Register _R_65 ("Grid<Real>","sub",Grid<Real>::_W_16);
+ static const Pb::Register _R_66 ("Grid<Real>","setConst",Grid<Real>::_W_17);
+ static const Pb::Register _R_67 ("Grid<Real>","addConst",Grid<Real>::_W_18);
+ static const Pb::Register _R_68 ("Grid<Real>","addScaled",Grid<Real>::_W_19);
+ static const Pb::Register _R_69 ("Grid<Real>","mult",Grid<Real>::_W_20);
+ static const Pb::Register _R_70 ("Grid<Real>","multConst",Grid<Real>::_W_21);
+ static const Pb::Register _R_71 ("Grid<Real>","clamp",Grid<Real>::_W_22);
+ static const Pb::Register _R_72 ("Grid<Real>","stomp",Grid<Real>::_W_23);
+ static const Pb::Register _R_73 ("Grid<Real>","getMaxAbs",Grid<Real>::_W_24);
+ static const Pb::Register _R_74 ("Grid<Real>","getMax",Grid<Real>::_W_25);
+ static const Pb::Register _R_75 ("Grid<Real>","getMin",Grid<Real>::_W_26);
+ static const Pb::Register _R_76 ("Grid<Real>","getL1",Grid<Real>::_W_27);
+ static const Pb::Register _R_77 ("Grid<Real>","getL2",Grid<Real>::_W_28);
+ static const Pb::Register _R_78 ("Grid<Real>","setBound",Grid<Real>::_W_29);
+ static const Pb::Register _R_79 ("Grid<Real>","setBoundNeumann",Grid<Real>::_W_30);
+ static const Pb::Register _R_80 ("Grid<Real>","getDataPointer",Grid<Real>::_W_31);
+ static const Pb::Register _R_81 ("Grid<Real>","printGrid",Grid<Real>::_W_32);
+ static const Pb::Register _R_82 ("Grid<Vec3>","Grid<Vec3>","GridBase"); template<> const char* Namify<Grid<Vec3> >::S = "Grid<Vec3>";
+ static const Pb::Register _R_83 ("Grid<Vec3>","Grid",Grid<Vec3>::_W_9);
+ static const Pb::Register _R_84 ("Grid<Vec3>","save",Grid<Vec3>::_W_10);
+ static const Pb::Register _R_85 ("Grid<Vec3>","load",Grid<Vec3>::_W_11);
+ static const Pb::Register _R_86 ("Grid<Vec3>","clear",Grid<Vec3>::_W_12);
+ static const Pb::Register _R_87 ("Grid<Vec3>","copyFrom",Grid<Vec3>::_W_13);
+ static const Pb::Register _R_88 ("Grid<Vec3>","getGridType",Grid<Vec3>::_W_14);
+ static const Pb::Register _R_89 ("Grid<Vec3>","add",Grid<Vec3>::_W_15);
+ static const Pb::Register _R_90 ("Grid<Vec3>","sub",Grid<Vec3>::_W_16);
+ static const Pb::Register _R_91 ("Grid<Vec3>","setConst",Grid<Vec3>::_W_17);
+ static const Pb::Register _R_92 ("Grid<Vec3>","addConst",Grid<Vec3>::_W_18);
+ static const Pb::Register _R_93 ("Grid<Vec3>","addScaled",Grid<Vec3>::_W_19);
+ static const Pb::Register _R_94 ("Grid<Vec3>","mult",Grid<Vec3>::_W_20);
+ static const Pb::Register _R_95 ("Grid<Vec3>","multConst",Grid<Vec3>::_W_21);
+ static const Pb::Register _R_96 ("Grid<Vec3>","clamp",Grid<Vec3>::_W_22);
+ static const Pb::Register _R_97 ("Grid<Vec3>","stomp",Grid<Vec3>::_W_23);
+ static const Pb::Register _R_98 ("Grid<Vec3>","getMaxAbs",Grid<Vec3>::_W_24);
+ static const Pb::Register _R_99 ("Grid<Vec3>","getMax",Grid<Vec3>::_W_25);
+ static const Pb::Register _R_100 ("Grid<Vec3>","getMin",Grid<Vec3>::_W_26);
+ static const Pb::Register _R_101 ("Grid<Vec3>","getL1",Grid<Vec3>::_W_27);
+ static const Pb::Register _R_102 ("Grid<Vec3>","getL2",Grid<Vec3>::_W_28);
+ static const Pb::Register _R_103 ("Grid<Vec3>","setBound",Grid<Vec3>::_W_29);
+ static const Pb::Register _R_104 ("Grid<Vec3>","setBoundNeumann",Grid<Vec3>::_W_30);
+ static const Pb::Register _R_105 ("Grid<Vec3>","getDataPointer",Grid<Vec3>::_W_31);
+ static const Pb::Register _R_106 ("Grid<Vec3>","printGrid",Grid<Vec3>::_W_32);
+#endif
+#ifdef _C_GridBase
+ static const Pb::Register _R_107 ("GridBase","GridBase","PbClass"); template<> const char* Namify<GridBase >::S = "GridBase";
+ static const Pb::Register _R_108 ("GridBase","GridBase",GridBase::_W_0);
+ static const Pb::Register _R_109 ("GridBase","getSizeX",GridBase::_W_1);
+ static const Pb::Register _R_110 ("GridBase","getSizeY",GridBase::_W_2);
+ static const Pb::Register _R_111 ("GridBase","getSizeZ",GridBase::_W_3);
+ static const Pb::Register _R_112 ("GridBase","getSize",GridBase::_W_4);
+ static const Pb::Register _R_113 ("GridBase","is3D",GridBase::_W_5);
+ static const Pb::Register _R_114 ("GridBase","is4D",GridBase::_W_6);
+ static const Pb::Register _R_115 ("GridBase","getSizeT",GridBase::_W_7);
+ static const Pb::Register _R_116 ("GridBase","getStrideT",GridBase::_W_8);
+#endif
+#ifdef _C_MACGrid
+ static const Pb::Register _R_117 ("MACGrid","MACGrid","Grid<Vec3>"); template<> const char* Namify<MACGrid >::S = "MACGrid";
+ static const Pb::Register _R_118 ("MACGrid","MACGrid",MACGrid::_W_33);
+ static const Pb::Register _R_119 ("MACGrid","setBoundMAC",MACGrid::_W_34);
+#endif
+static const Pb::Register _R_7 ("GridType_TypeNone",0);
+static const Pb::Register _R_8 ("GridType_TypeReal",1);
+static const Pb::Register _R_9 ("GridType_TypeInt",2);
+static const Pb::Register _R_10 ("GridType_TypeVec3",4);
+static const Pb::Register _R_11 ("GridType_TypeMAC",8);
+static const Pb::Register _R_12 ("GridType_TypeLevelset",16);
+static const Pb::Register _R_13 ("GridType_TypeFlags",32);
+static const Pb::Register _R_14 ("Grid<int>","IntGrid","");
+static const Pb::Register _R_15 ("Grid<Real>","RealGrid","");
+static const Pb::Register _R_16 ("Grid<Vec3>","VecGrid","");
+static const Pb::Register _R_17 ("CellType_TypeNone",0);
+static const Pb::Register _R_18 ("CellType_TypeFluid",1);
+static const Pb::Register _R_19 ("CellType_TypeObstacle",2);
+static const Pb::Register _R_20 ("CellType_TypeEmpty",4);
+static const Pb::Register _R_21 ("CellType_TypeInflow",8);
+static const Pb::Register _R_22 ("CellType_TypeOutflow",16);
+static const Pb::Register _R_23 ("CellType_TypeOpen",32);
+static const Pb::Register _R_24 ("CellType_TypeStick",64);
+static const Pb::Register _R_25 ("CellType_TypeReserved",256);
+extern "C" {
+void PbRegister_file_7()
+{
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+ KEEP_UNUSED(_R_101);
+ KEEP_UNUSED(_R_102);
+ KEEP_UNUSED(_R_103);
+ KEEP_UNUSED(_R_104);
+ KEEP_UNUSED(_R_105);
+ KEEP_UNUSED(_R_106);
+ KEEP_UNUSED(_R_107);
+ KEEP_UNUSED(_R_108);
+ KEEP_UNUSED(_R_109);
+ KEEP_UNUSED(_R_110);
+ KEEP_UNUSED(_R_111);
+ KEEP_UNUSED(_R_112);
+ KEEP_UNUSED(_R_113);
+ KEEP_UNUSED(_R_114);
+ KEEP_UNUSED(_R_115);
+ KEEP_UNUSED(_R_116);
+ KEEP_UNUSED(_R_117);
+ KEEP_UNUSED(_R_118);
+ KEEP_UNUSED(_R_119);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.cpp
new file mode 100644
index 00000000000..18ed43a6441
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.cpp
@@ -0,0 +1,947 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#include <limits>
+#include <sstream>
+#include <cstring>
+
+#include "grid4d.h"
+#include "levelset.h"
+#include "kernel.h"
+#include "mantaio.h"
+
+using namespace std;
+namespace Manta {
+
+
+//******************************************************************************
+// GridBase members
+
+Grid4dBase::Grid4dBase (FluidSolver* parent)
+ : PbClass(parent), mType(TypeNone)
+{
+ checkParent();
+}
+
+
+//******************************************************************************
+// Grid4d<T> members
+
+// helpers to set type
+template<class T> inline Grid4dBase::Grid4dType typeList() { return Grid4dBase::TypeNone; }
+template<> inline Grid4dBase::Grid4dType typeList<Real>() { return Grid4dBase::TypeReal; }
+template<> inline Grid4dBase::Grid4dType typeList<int>() { return Grid4dBase::TypeInt; }
+template<> inline Grid4dBase::Grid4dType typeList<Vec3>() { return Grid4dBase::TypeVec3; }
+template<> inline Grid4dBase::Grid4dType typeList<Vec4>() { return Grid4dBase::TypeVec4; }
+
+
+template<class T>
+Grid4d<T>::Grid4d(FluidSolver* parent, bool show)
+ : Grid4dBase(parent)
+{
+ assertMsg( parent->is3D() && parent->supports4D(), "To use 4d grids create a 3d solver with fourthDim>0");
+
+ mType = typeList<T>();
+ Vec3i s = parent->getGridSize();
+ mSize = Vec4i(s.x, s.y, s.z, parent->getFourthDim() );
+ mData = parent->getGrid4dPointer<T>();
+ assertMsg( mData, "Couldnt allocate data pointer!");
+
+ mStrideZ = (mSize.x * mSize.y);
+ mStrideT = (mStrideZ * mSize.z);
+
+ Real sizemax = (Real)mSize[0];
+ for(int c=1; c<3; ++c) if(mSize[c]>sizemax) sizemax = mSize[c];
+ // note - the 4d component is ignored for dx! keep same scaling as for 3d...
+ mDx = 1.0 / sizemax;
+
+ clear();
+ setHidden(!show);
+}
+
+template<class T>
+Grid4d<T>::Grid4d(const Grid4d<T>& a) : Grid4dBase(a.getParent()) {
+ mSize = a.mSize;
+ mType = a.mType;
+ mStrideZ = a.mStrideZ;
+ mStrideT = a.mStrideT;
+ mDx = a.mDx;
+ FluidSolver *gp = a.getParent();
+ mData = gp->getGrid4dPointer<T>();
+ assertMsg( mData, "Couldnt allocate data pointer!");
+
+ memcpy(mData, a.mData, sizeof(T) * a.mSize.x * a.mSize.y * a.mSize.z * a.mSize.t);
+}
+
+template<class T>
+Grid4d<T>::~Grid4d() {
+ mParent->freeGrid4dPointer<T>(mData);
+}
+
+template<class T>
+void Grid4d<T>::clear() {
+ memset(mData, 0, sizeof(T) * mSize.x * mSize.y * mSize.z * mSize.t);
+}
+
+template<class T>
+void Grid4d<T>::swap(Grid4d<T>& other) {
+ if (other.getSizeX() != getSizeX() || other.getSizeY() != getSizeY() || other.getSizeZ() != getSizeZ() || other.getSizeT() != getSizeT())
+ errMsg("Grid4d::swap(): Grid4d dimensions mismatch.");
+
+ T* dswap = other.mData;
+ other.mData = mData;
+ mData = dswap;
+}
+
+template<class T>
+void Grid4d<T>::load(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ readGrid4dUni(name, this);
+ else if (ext == ".raw")
+ readGrid4dRaw(name, this);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+template<class T>
+void Grid4d<T>::save(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ writeGrid4dUni(name, this);
+ else if (ext == ".raw")
+ writeGrid4dRaw(name, this);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+//******************************************************************************
+// Grid4d<T> operators
+
+//! Kernel: Compute min value of Real Grid4d
+
+ struct kn4dMinReal : public KernelBase {
+ kn4dMinReal(Grid4d<Real>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<Real>& val ,Real& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline Grid4d<Real>& getArg0() {
+ return val; }
+ typedef Grid4d<Real> type0; void runMessage() { debMsg("Executing kernel kn4dMinReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,minVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ kn4dMinReal (kn4dMinReal& o, tbb::split) : KernelBase(o) ,val(o.val) ,minVal(std::numeric_limits<Real>::max()) {
+}
+ void join(const kn4dMinReal & o) {
+ minVal = min(minVal,o.minVal); }
+ Grid4d<Real>& val; Real minVal; }
+;
+
+//! Kernel: Compute max value of Real Grid4d
+
+ struct kn4dMaxReal : public KernelBase {
+ kn4dMaxReal(Grid4d<Real>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<Real>& val ,Real& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline Grid4d<Real>& getArg0() {
+ return val; }
+ typedef Grid4d<Real> type0; void runMessage() { debMsg("Executing kernel kn4dMaxReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,maxVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ kn4dMaxReal (kn4dMaxReal& o, tbb::split) : KernelBase(o) ,val(o.val) ,maxVal(-std::numeric_limits<Real>::max()) {
+}
+ void join(const kn4dMaxReal & o) {
+ maxVal = max(maxVal,o.maxVal); }
+ Grid4d<Real>& val; Real maxVal; }
+;
+
+//! Kernel: Compute min value of int Grid4d
+
+ struct kn4dMinInt : public KernelBase {
+ kn4dMinInt(Grid4d<int>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<int>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<int>& val ,int& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator int () {
+ return minVal; }
+ inline int & getRet() {
+ return minVal; }
+ inline Grid4d<int>& getArg0() {
+ return val; }
+ typedef Grid4d<int> type0; void runMessage() { debMsg("Executing kernel kn4dMinInt ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,minVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ kn4dMinInt (kn4dMinInt& o, tbb::split) : KernelBase(o) ,val(o.val) ,minVal(std::numeric_limits<int>::max()) {
+}
+ void join(const kn4dMinInt & o) {
+ minVal = min(minVal,o.minVal); }
+ Grid4d<int>& val; int minVal; }
+;
+
+//! Kernel: Compute max value of int Grid4d
+
+ struct kn4dMaxInt : public KernelBase {
+ kn4dMaxInt(Grid4d<int>& val) : KernelBase(&val,0) ,val(val) ,maxVal(std::numeric_limits<int>::min()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<int>& val ,int& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator int () {
+ return maxVal; }
+ inline int & getRet() {
+ return maxVal; }
+ inline Grid4d<int>& getArg0() {
+ return val; }
+ typedef Grid4d<int> type0; void runMessage() { debMsg("Executing kernel kn4dMaxInt ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,maxVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ kn4dMaxInt (kn4dMaxInt& o, tbb::split) : KernelBase(o) ,val(o.val) ,maxVal(std::numeric_limits<int>::min()) {
+}
+ void join(const kn4dMaxInt & o) {
+ maxVal = max(maxVal,o.maxVal); }
+ Grid4d<int>& val; int maxVal; }
+;
+
+//! Kernel: Compute min norm of vec Grid4d
+
+template <class VEC> struct kn4dMinVec : public KernelBase {
+ kn4dMinVec(Grid4d<VEC>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<VEC>& val ,Real& minVal) {
+ const Real s = normSquare(val[idx]);
+ if (s < minVal)
+ minVal = s;
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline Grid4d<VEC>& getArg0() {
+ return val; }
+ typedef Grid4d<VEC> type0; void runMessage() { debMsg("Executing kernel kn4dMinVec ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,minVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ kn4dMinVec (kn4dMinVec& o, tbb::split) : KernelBase(o) ,val(o.val) ,minVal(std::numeric_limits<Real>::max()) {
+}
+ void join(const kn4dMinVec & o) {
+ minVal = min(minVal,o.minVal); }
+ Grid4d<VEC>& val; Real minVal; }
+;
+
+//! Kernel: Compute max norm of vec Grid4d
+
+template <class VEC> struct kn4dMaxVec : public KernelBase {
+ kn4dMaxVec(Grid4d<VEC>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<VEC>& val ,Real& maxVal) {
+ const Real s = normSquare(val[idx]);
+ if (s > maxVal)
+ maxVal = s;
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline Grid4d<VEC>& getArg0() {
+ return val; }
+ typedef Grid4d<VEC> type0; void runMessage() { debMsg("Executing kernel kn4dMaxVec ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,maxVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ kn4dMaxVec (kn4dMaxVec& o, tbb::split) : KernelBase(o) ,val(o.val) ,maxVal(-std::numeric_limits<Real>::max()) {
+}
+ void join(const kn4dMaxVec & o) {
+ maxVal = max(maxVal,o.maxVal); }
+ Grid4d<VEC>& val; Real maxVal; }
+;
+
+
+template<class T> Grid4d<T>& Grid4d<T>::safeDivide (const Grid4d<T>& a) {
+ Grid4dSafeDiv<T> (*this, a);
+ return *this;
+}
+template<class T> Grid4d<T>& Grid4d<T>::copyFrom (const Grid4d<T>& a, bool copyType ) {
+ assertMsg (a.mSize.x == mSize.x && a.mSize.y == mSize.y && a.mSize.z == mSize.z && a.mSize.t == mSize.t, "different Grid4d resolutions "<<a.mSize<<" vs "<<this->mSize );
+ memcpy(mData, a.mData, sizeof(T) * mSize.x * mSize.y * mSize.z * mSize.t);
+ if(copyType) mType = a.mType; // copy type marker
+ return *this;
+}
+/*template<class T> Grid4d<T>& Grid4d<T>::operator= (const Grid4d<T>& a) {
+ note: do not use , use copyFrom instead
+}*/
+
+template <class T> struct kn4dSetConstReal : public KernelBase {
+ kn4dSetConstReal(Grid4d<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, T val ) const { me[idx] = val; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel kn4dSetConstReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,val); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; T val; }
+;
+template <class T> struct kn4dAddConstReal : public KernelBase {
+ kn4dAddConstReal(Grid4d<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, T val ) const { me[idx] += val; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel kn4dAddConstReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,val); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; T val; }
+;
+template <class T> struct kn4dMultConst : public KernelBase {
+ kn4dMultConst(Grid4d<T>& me, T val) : KernelBase(&me,0) ,me(me),val(val) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, T val ) const { me[idx] *= val; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return val; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel kn4dMultConst ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,val); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; T val; }
+;
+template <class T> struct kn4dClamp : public KernelBase {
+ kn4dClamp(Grid4d<T>& me, T min, T max) : KernelBase(&me,0) ,me(me),min(min),max(max) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, T min, T max ) const { me[idx] = clamp( me[idx], min, max); } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return min; }
+ typedef T type1;inline T& getArg2() {
+ return max; }
+ typedef T type2; void runMessage() { debMsg("Executing kernel kn4dClamp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,min,max); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; T min; T max; }
+;
+
+template<class T> void Grid4d<T>::add(const Grid4d<T>& a) {
+ Grid4dAdd<T,T>(*this, a);
+}
+template<class T> void Grid4d<T>::sub(const Grid4d<T>& a) {
+ Grid4dSub<T,T>(*this, a);
+}
+template<class T> void Grid4d<T>::addScaled(const Grid4d<T>& a, const T& factor) {
+ Grid4dScaledAdd<T,T> (*this, a, factor);
+}
+template<class T> void Grid4d<T>::setConst(T a) {
+ kn4dSetConstReal<T>( *this, T(a) );
+}
+template<class T> void Grid4d<T>::addConst(T a) {
+ kn4dAddConstReal<T>( *this, T(a) );
+}
+template<class T> void Grid4d<T>::multConst(T a) {
+ kn4dMultConst<T>( *this, a );
+}
+
+template<class T> void Grid4d<T>::mult(const Grid4d<T>& a) {
+ Grid4dMult<T,T> (*this, a);
+}
+
+template<class T> void Grid4d<T>::clamp(Real min, Real max) {
+ kn4dClamp<T> (*this, T(min), T(max) );
+}
+
+template<> Real Grid4d<Real>::getMax() {
+ return kn4dMaxReal (*this);
+}
+template<> Real Grid4d<Real>::getMin() {
+ return kn4dMinReal (*this);
+}
+template<> Real Grid4d<Real>::getMaxAbs() {
+ Real amin = kn4dMinReal (*this);
+ Real amax = kn4dMaxReal (*this);
+ return max( fabs(amin), fabs(amax));
+}
+template<> Real Grid4d<Vec4>::getMax() {
+ return sqrt(kn4dMaxVec<Vec4> (*this));
+}
+template<> Real Grid4d<Vec4>::getMin() {
+ return sqrt(kn4dMinVec<Vec4> (*this));
+}
+template<> Real Grid4d<Vec4>::getMaxAbs() {
+ return sqrt(kn4dMaxVec<Vec4> (*this));
+}
+template<> Real Grid4d<int>::getMax() {
+ return (Real) kn4dMaxInt (*this);
+}
+template<> Real Grid4d<int>::getMin() {
+ return (Real) kn4dMinInt (*this);
+}
+template<> Real Grid4d<int>::getMaxAbs() {
+ int amin = kn4dMinInt (*this);
+ int amax = kn4dMaxInt (*this);
+ return max( fabs((Real)amin), fabs((Real)amax));
+}
+template<> Real Grid4d<Vec3>::getMax() {
+ return sqrt(kn4dMaxVec<Vec3> (*this));
+}
+template<> Real Grid4d<Vec3>::getMin() {
+ return sqrt(kn4dMinVec<Vec3> (*this));
+}
+template<> Real Grid4d<Vec3>::getMaxAbs() {
+ return sqrt(kn4dMaxVec<Vec3> (*this));
+}
+
+
+template<class T> void Grid4d<T>::printGrid(int zSlice, int tSlice, bool printIndex, int bnd) {
+ std::ostringstream out;
+ out << std::endl;
+ FOR_IJKT_BND(*this,bnd) {
+ IndexInt idx = (*this).index(i,j,k,t);
+ if ( ( (zSlice>=0 && k==zSlice) || (zSlice<0) ) &&
+ ( (tSlice>=0 && t==tSlice) || (tSlice<0) ) ) {
+ out << " ";
+ if(printIndex) out << " "<<i<<","<<j<<","<<k<<","<<t <<":";
+ out << (*this)[idx];
+ if(i==(*this).getSizeX()-1 -bnd) {
+ out << std::endl;
+ if(j==(*this).getSizeY()-1 -bnd) {
+ out << std::endl;
+ if(k==(*this).getSizeZ()-1 -bnd) { out << std::endl; }
+ } }
+ }
+ }
+ out << endl; debMsg("Printing '" << this->getName() <<"' "<< out.str().c_str()<<" " , 1);
+}
+
+
+// helper to set/get components of vec4 Grids
+ struct knGetComp4d : public KernelBase {
+ knGetComp4d(const Grid4d<Vec4>& src, Grid4d<Real>& dst, int c) : KernelBase(&src,0) ,src(src),dst(dst),c(c) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid4d<Vec4>& src, Grid4d<Real>& dst, int c ) const { dst[idx] = src[idx][c]; } inline const Grid4d<Vec4>& getArg0() {
+ return src; }
+ typedef Grid4d<Vec4> type0;inline Grid4d<Real>& getArg1() {
+ return dst; }
+ typedef Grid4d<Real> type1;inline int& getArg2() {
+ return c; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knGetComp4d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, src,dst,c); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const Grid4d<Vec4>& src; Grid4d<Real>& dst; int c; }
+;;
+ struct knSetComp4d : public KernelBase {
+ knSetComp4d(const Grid4d<Real>& src, Grid4d<Vec4>& dst, int c) : KernelBase(&src,0) ,src(src),dst(dst),c(c) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid4d<Real>& src, Grid4d<Vec4>& dst, int c ) const { dst[idx][c] = src[idx]; } inline const Grid4d<Real>& getArg0() {
+ return src; }
+ typedef Grid4d<Real> type0;inline Grid4d<Vec4>& getArg1() {
+ return dst; }
+ typedef Grid4d<Vec4> type1;inline int& getArg2() {
+ return c; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetComp4d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, src,dst,c); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const Grid4d<Real>& src; Grid4d<Vec4>& dst; int c; }
+;;
+void getComp4d(const Grid4d<Vec4>& src, Grid4d<Real>& dst, int c) { knGetComp4d(src,dst,c); } static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getComp4d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<Vec4>& src = *_args.getPtr<Grid4d<Vec4> >("src",0,&_lock); Grid4d<Real>& dst = *_args.getPtr<Grid4d<Real> >("dst",1,&_lock); int c = _args.get<int >("c",2,&_lock); _retval = getPyNone(); getComp4d(src,dst,c); _args.check(); }
+ pbFinalizePlugin(parent,"getComp4d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getComp4d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getComp4d ("","getComp4d",_W_0);
+extern "C" {
+ void PbRegister_getComp4d() {
+ KEEP_UNUSED(_RP_getComp4d); }
+ }
+
+;
+void setComp4d(const Grid4d<Real>& src, Grid4d<Vec4>& dst, int c) { knSetComp4d(src,dst,c); } static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setComp4d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<Real>& src = *_args.getPtr<Grid4d<Real> >("src",0,&_lock); Grid4d<Vec4>& dst = *_args.getPtr<Grid4d<Vec4> >("dst",1,&_lock); int c = _args.get<int >("c",2,&_lock); _retval = getPyNone(); setComp4d(src,dst,c); _args.check(); }
+ pbFinalizePlugin(parent,"setComp4d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setComp4d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setComp4d ("","setComp4d",_W_1);
+extern "C" {
+ void PbRegister_setComp4d() {
+ KEEP_UNUSED(_RP_setComp4d); }
+ }
+
+;
+
+
+template <class T> struct knSetBnd4d : public KernelBase {
+ knSetBnd4d(Grid4d<T>& grid, T value, int w) : KernelBase(&grid,0) ,grid(grid),value(value),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, int t, Grid4d<T>& grid, T value, int w ) const {
+ bool bnd =
+ (i<=w || i>=grid.getSizeX()-1-w ||
+ j<=w || j>=grid.getSizeY()-1-w ||
+ k<=w || k>=grid.getSizeZ()-1-w ||
+ t<=w || t>=grid.getSizeT()-1-w );
+ if (bnd)
+ grid(i,j,k,t) = value;
+} inline Grid4d<T>& getArg0() {
+ return grid; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1;inline int& getArg2() {
+ return w; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel knSetBnd4d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " " t "<< minT<<" - "<< maxT , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ if (maxT>1) {
+ for (int t=__r.begin(); t!=(int)__r.end(); t++) for (int k=0; k<maxZ; k++) for (int j=0; j<maxY; j++) for (int i=0; i<maxX; i++) op(i,j,k,t,grid,value,w); }
+ else if (maxZ>1) {
+ const int t=0; for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<maxY; j++) for (int i=0; i<maxX; i++) op(i,j,k,t,grid,value,w); }
+ else {
+ const int t=0; const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<maxX; i++) op(i,j,k,t,grid,value,w); }
+ }
+ void run() {
+ if (maxT>1) {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(minT, maxT), *this); }
+ else if (maxZ>1) {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); }
+ else {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ }
+ Grid4d<T>& grid; T value; int w; }
+;
+
+template<class T> void Grid4d<T>::setBound(T value, int boundaryWidth) {
+ knSetBnd4d<T>( *this, value, boundaryWidth );
+}
+
+template <class T> struct knSetBnd4dNeumann : public KernelBase {
+ knSetBnd4dNeumann(Grid4d<T>& grid, int w) : KernelBase(&grid,0) ,grid(grid),w(w) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, int t, Grid4d<T>& grid, int w ) const {
+ bool set = false;
+ int si=i, sj=j, sk=k, st=t;
+ if( i<=w) {
+ si = w+1; set=true;
+ }
+ if( i>=grid.getSizeX()-1-w){
+ si = grid.getSizeX()-1-w-1; set=true;
+ }
+ if( j<=w){
+ sj = w+1; set=true;
+ }
+ if( j>=grid.getSizeY()-1-w){
+ sj = grid.getSizeY()-1-w-1; set=true;
+ }
+ if( k<=w ) {
+ sk = w+1; set=true;
+ }
+ if( k>=grid.getSizeZ()-1-w ) {
+ sk = grid.getSizeZ()-1-w-1; set=true;
+ }
+ if( t<=w ) {
+ st = w+1; set=true;
+ }
+ if( t>=grid.getSizeT()-1-w ) {
+ st = grid.getSizeT()-1-w-1; set=true;
+ }
+ if(set)
+ grid(i,j,k,t) = grid(si, sj, sk, st);
+} inline Grid4d<T>& getArg0() {
+ return grid; }
+ typedef Grid4d<T> type0;inline int& getArg1() {
+ return w; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel knSetBnd4dNeumann ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " " t "<< minT<<" - "<< maxT , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ if (maxT>1) {
+ for (int t=__r.begin(); t!=(int)__r.end(); t++) for (int k=0; k<maxZ; k++) for (int j=0; j<maxY; j++) for (int i=0; i<maxX; i++) op(i,j,k,t,grid,w); }
+ else if (maxZ>1) {
+ const int t=0; for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<maxY; j++) for (int i=0; i<maxX; i++) op(i,j,k,t,grid,w); }
+ else {
+ const int t=0; const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<maxX; i++) op(i,j,k,t,grid,w); }
+ }
+ void run() {
+ if (maxT>1) {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(minT, maxT), *this); }
+ else if (maxZ>1) {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); }
+ else {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ }
+ Grid4d<T>& grid; int w; }
+;
+
+template<class T> void Grid4d<T>::setBoundNeumann(int boundaryWidth) {
+ knSetBnd4dNeumann<T>( *this, boundaryWidth );
+}
+
+//******************************************************************************
+// testing helpers
+
+//! compute maximal diference of two cells in the grid, needed for testing system
+
+Real grid4dMaxDiff(Grid4d<Real>& g1, Grid4d<Real>& g2 ) {
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1,0) {
+ maxVal = std::max(maxVal, (double)fabs( g1(i,j,k,t)-g2(i,j,k,t) ));
+ }
+ return maxVal;
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "grid4dMaxDiff" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Real>& g1 = *_args.getPtr<Grid4d<Real> >("g1",0,&_lock); Grid4d<Real>& g2 = *_args.getPtr<Grid4d<Real> >("g2",1,&_lock); _retval = toPy(grid4dMaxDiff(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"grid4dMaxDiff", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("grid4dMaxDiff",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_grid4dMaxDiff ("","grid4dMaxDiff",_W_2);
+extern "C" {
+ void PbRegister_grid4dMaxDiff() {
+ KEEP_UNUSED(_RP_grid4dMaxDiff); }
+ }
+
+
+
+Real grid4dMaxDiffInt(Grid4d<int>& g1, Grid4d<int>& g2 ) {
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1,0) {
+ maxVal = std::max(maxVal, (double)fabs( (double)g1(i,j,k,t)-g2(i,j,k,t) ));
+ }
+ return maxVal;
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "grid4dMaxDiffInt" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<int>& g1 = *_args.getPtr<Grid4d<int> >("g1",0,&_lock); Grid4d<int>& g2 = *_args.getPtr<Grid4d<int> >("g2",1,&_lock); _retval = toPy(grid4dMaxDiffInt(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"grid4dMaxDiffInt", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("grid4dMaxDiffInt",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_grid4dMaxDiffInt ("","grid4dMaxDiffInt",_W_3);
+extern "C" {
+ void PbRegister_grid4dMaxDiffInt() {
+ KEEP_UNUSED(_RP_grid4dMaxDiffInt); }
+ }
+
+
+
+Real grid4dMaxDiffVec3(Grid4d<Vec3>& g1, Grid4d<Vec3>& g2 ) {
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1,0) {
+ double d = 0.;
+ for(int c=0; c<3; ++c) {
+ d += fabs( (double)g1(i,j,k,t)[c] - (double)g2(i,j,k,t)[c] );
+ }
+ maxVal = std::max(maxVal, d );
+ }
+ return maxVal;
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "grid4dMaxDiffVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Vec3>& g1 = *_args.getPtr<Grid4d<Vec3> >("g1",0,&_lock); Grid4d<Vec3>& g2 = *_args.getPtr<Grid4d<Vec3> >("g2",1,&_lock); _retval = toPy(grid4dMaxDiffVec3(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"grid4dMaxDiffVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("grid4dMaxDiffVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_grid4dMaxDiffVec3 ("","grid4dMaxDiffVec3",_W_4);
+extern "C" {
+ void PbRegister_grid4dMaxDiffVec3() {
+ KEEP_UNUSED(_RP_grid4dMaxDiffVec3); }
+ }
+
+
+
+Real grid4dMaxDiffVec4(Grid4d<Vec4>& g1, Grid4d<Vec4>& g2 ) {
+ double maxVal = 0.;
+ FOR_IJKT_BND(g1,0) {
+ double d = 0.;
+ for(int c=0; c<4; ++c) {
+ d += fabs( (double)g1(i,j,k,t)[c] - (double)g2(i,j,k,t)[c] );
+ }
+ maxVal = std::max(maxVal, d );
+ }
+ return maxVal;
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "grid4dMaxDiffVec4" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Vec4>& g1 = *_args.getPtr<Grid4d<Vec4> >("g1",0,&_lock); Grid4d<Vec4>& g2 = *_args.getPtr<Grid4d<Vec4> >("g2",1,&_lock); _retval = toPy(grid4dMaxDiffVec4(g1,g2)); _args.check(); }
+ pbFinalizePlugin(parent,"grid4dMaxDiffVec4", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("grid4dMaxDiffVec4",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_grid4dMaxDiffVec4 ("","grid4dMaxDiffVec4",_W_5);
+extern "C" {
+ void PbRegister_grid4dMaxDiffVec4() {
+ KEEP_UNUSED(_RP_grid4dMaxDiffVec4); }
+ }
+
+
+
+// set a region to some value
+
+
+template <class S> struct knSetRegion4d : public KernelBase {
+ knSetRegion4d(Grid4d<S>& dst, Vec4 start, Vec4 end, S value ) : KernelBase(&dst,0) ,dst(dst),start(start),end(end),value(value) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, int t, Grid4d<S>& dst, Vec4 start, Vec4 end, S value ) const {
+ Vec4 p(i,j,k,t);
+ for(int c=0; c<4; ++c) if(p[c]<start[c] || p[c]>end[c]) return;
+ dst(i,j,k,t) = value;
+} inline Grid4d<S>& getArg0() {
+ return dst; }
+ typedef Grid4d<S> type0;inline Vec4& getArg1() {
+ return start; }
+ typedef Vec4 type1;inline Vec4& getArg2() {
+ return end; }
+ typedef Vec4 type2;inline S& getArg3() {
+ return value; }
+ typedef S type3; void runMessage() { debMsg("Executing kernel knSetRegion4d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " " t "<< minT<<" - "<< maxT , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ if (maxT>1) {
+ for (int t=__r.begin(); t!=(int)__r.end(); t++) for (int k=0; k<maxZ; k++) for (int j=0; j<maxY; j++) for (int i=0; i<maxX; i++) op(i,j,k,t,dst,start,end,value); }
+ else if (maxZ>1) {
+ const int t=0; for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<maxY; j++) for (int i=0; i<maxX; i++) op(i,j,k,t,dst,start,end,value); }
+ else {
+ const int t=0; const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<maxX; i++) op(i,j,k,t,dst,start,end,value); }
+ }
+ void run() {
+ if (maxT>1) {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(minT, maxT), *this); }
+ else if (maxZ>1) {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); }
+ else {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ }
+ Grid4d<S>& dst; Vec4 start; Vec4 end; S value; }
+;
+//! simple init functions in 4d
+void setRegion4d(Grid4d<Real>& dst, Vec4 start, Vec4 end, Real value) { knSetRegion4d<Real>(dst,start,end,value); } static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setRegion4d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Real>& dst = *_args.getPtr<Grid4d<Real> >("dst",0,&_lock); Vec4 start = _args.get<Vec4 >("start",1,&_lock); Vec4 end = _args.get<Vec4 >("end",2,&_lock); Real value = _args.get<Real >("value",3,&_lock); _retval = getPyNone(); setRegion4d(dst,start,end,value); _args.check(); }
+ pbFinalizePlugin(parent,"setRegion4d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setRegion4d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setRegion4d ("","setRegion4d",_W_6);
+extern "C" {
+ void PbRegister_setRegion4d() {
+ KEEP_UNUSED(_RP_setRegion4d); }
+ }
+
+
+//! simple init functions in 4d, vec4
+void setRegion4dVec4(Grid4d<Vec4>& dst, Vec4 start, Vec4 end, Vec4 value) { knSetRegion4d<Vec4>(dst,start,end,value); } static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setRegion4dVec4" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Vec4>& dst = *_args.getPtr<Grid4d<Vec4> >("dst",0,&_lock); Vec4 start = _args.get<Vec4 >("start",1,&_lock); Vec4 end = _args.get<Vec4 >("end",2,&_lock); Vec4 value = _args.get<Vec4 >("value",3,&_lock); _retval = getPyNone(); setRegion4dVec4(dst,start,end,value); _args.check(); }
+ pbFinalizePlugin(parent,"setRegion4dVec4", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setRegion4dVec4",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setRegion4dVec4 ("","setRegion4dVec4",_W_7);
+extern "C" {
+ void PbRegister_setRegion4dVec4() {
+ KEEP_UNUSED(_RP_setRegion4dVec4); }
+ }
+
+
+
+//! slow helper to visualize tests, get a 3d slice of a 4d grid
+void getSliceFrom4d(Grid4d<Real>& src, int srct, Grid<Real>& dst) {
+ const int bnd = 0;
+ if(! src.isInBounds(Vec4i(bnd,bnd,bnd,srct)) ) return;
+
+ for(int k=bnd; k<src.getSizeZ()-bnd; k++)
+ for(int j=bnd; j<src.getSizeY()-bnd; j++)
+ for(int i=bnd; i<src.getSizeX()-bnd; i++)
+ {
+ if(!dst.isInBounds(Vec3i(i,j,k))) continue;
+ dst(i,j,k) = src(i,j,k,srct);
+ }
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getSliceFrom4d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Real>& src = *_args.getPtr<Grid4d<Real> >("src",0,&_lock); int srct = _args.get<int >("srct",1,&_lock); Grid<Real>& dst = *_args.getPtr<Grid<Real> >("dst",2,&_lock); _retval = getPyNone(); getSliceFrom4d(src,srct,dst); _args.check(); }
+ pbFinalizePlugin(parent,"getSliceFrom4d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getSliceFrom4d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getSliceFrom4d ("","getSliceFrom4d",_W_8);
+extern "C" {
+ void PbRegister_getSliceFrom4d() {
+ KEEP_UNUSED(_RP_getSliceFrom4d); }
+ }
+
+
+//! slow helper to visualize tests, get a 3d slice of a 4d vec4 grid
+void getSliceFrom4dVec(Grid4d<Vec4>& src, int srct, Grid<Vec3>& dst, Grid<Real>* dstt=NULL) {
+ const int bnd = 0;
+ if(! src.isInBounds(Vec4i(bnd,bnd,bnd,srct)) ) return;
+
+ for(int k=bnd; k<src.getSizeZ()-bnd; k++)
+ for(int j=bnd; j<src.getSizeY()-bnd; j++)
+ for(int i=bnd; i<src.getSizeX()-bnd; i++)
+ {
+ if(!dst.isInBounds(Vec3i(i,j,k))) continue;
+ for(int c=0; c<3; ++c)
+ dst(i,j,k)[c] = src(i,j,k,srct)[c];
+ if(dstt) (*dstt)(i,j,k) = src(i,j,k,srct)[3];
+ }
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getSliceFrom4dVec" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Vec4>& src = *_args.getPtr<Grid4d<Vec4> >("src",0,&_lock); int srct = _args.get<int >("srct",1,&_lock); Grid<Vec3>& dst = *_args.getPtr<Grid<Vec3> >("dst",2,&_lock); Grid<Real>* dstt = _args.getPtrOpt<Grid<Real> >("dstt",3,NULL,&_lock); _retval = getPyNone(); getSliceFrom4dVec(src,srct,dst,dstt); _args.check(); }
+ pbFinalizePlugin(parent,"getSliceFrom4dVec", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getSliceFrom4dVec",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getSliceFrom4dVec ("","getSliceFrom4dVec",_W_9);
+extern "C" {
+ void PbRegister_getSliceFrom4dVec() {
+ KEEP_UNUSED(_RP_getSliceFrom4dVec); }
+ }
+
+
+
+
+//******************************************************************************
+// interpolation
+
+//! same as in grid.h , but takes an additional optional "desired" size
+static inline void gridFactor4d(Vec4 s1, Vec4 s2, Vec4 optSize, Vec4 scale, Vec4& srcFac, Vec4& retOff ) {
+ for(int c=0; c<4; c++) { if(optSize[c] > 0.){ s2[c] = optSize[c]; } }
+ srcFac = calcGridSizeFactor4d( s1, s2) / scale;
+ retOff = -retOff * srcFac + srcFac*0.5;
+}
+
+//! interpolate 4d grid from one size to another size
+// real valued offsets & scale
+
+
+template <class S> struct knInterpol4d : public KernelBase {
+ knInterpol4d(Grid4d<S>& target, Grid4d<S>& source, const Vec4& srcFac, const Vec4& offset) : KernelBase(&target,0) ,target(target),source(source),srcFac(srcFac),offset(offset) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, int t, Grid4d<S>& target, Grid4d<S>& source, const Vec4& srcFac, const Vec4& offset ) const {
+ Vec4 pos = Vec4(i,j,k,t) * srcFac + offset;
+ target(i,j,k,t) = source.getInterpolated(pos);
+} inline Grid4d<S>& getArg0() {
+ return target; }
+ typedef Grid4d<S> type0;inline Grid4d<S>& getArg1() {
+ return source; }
+ typedef Grid4d<S> type1;inline const Vec4& getArg2() {
+ return srcFac; }
+ typedef Vec4 type2;inline const Vec4& getArg3() {
+ return offset; }
+ typedef Vec4 type3; void runMessage() { debMsg("Executing kernel knInterpol4d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " " t "<< minT<<" - "<< maxT , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ if (maxT>1) {
+ for (int t=__r.begin(); t!=(int)__r.end(); t++) for (int k=0; k<maxZ; k++) for (int j=0; j<maxY; j++) for (int i=0; i<maxX; i++) op(i,j,k,t,target,source,srcFac,offset); }
+ else if (maxZ>1) {
+ const int t=0; for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<maxY; j++) for (int i=0; i<maxX; i++) op(i,j,k,t,target,source,srcFac,offset); }
+ else {
+ const int t=0; const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<maxX; i++) op(i,j,k,t,target,source,srcFac,offset); }
+ }
+ void run() {
+ if (maxT>1) {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(minT, maxT), *this); }
+ else if (maxZ>1) {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); }
+ else {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ }
+ Grid4d<S>& target; Grid4d<S>& source; const Vec4& srcFac; const Vec4& offset; }
+;
+//! linearly interpolate data of a 4d grid
+
+void interpolateGrid4d( Grid4d<Real>& target, Grid4d<Real>& source , Vec4 offset=Vec4(0.), Vec4 scale=Vec4(1.), Vec4 size=Vec4(-1.) ) {
+ Vec4 srcFac(1.), off2 = offset;
+ gridFactor4d( toVec4(source.getSize()), toVec4(target.getSize()), size,scale, srcFac,off2 );
+ knInterpol4d<Real> (target, source, srcFac, off2 );
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "interpolateGrid4d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Real>& target = *_args.getPtr<Grid4d<Real> >("target",0,&_lock); Grid4d<Real>& source = *_args.getPtr<Grid4d<Real> >("source",1,&_lock); Vec4 offset = _args.getOpt<Vec4 >("offset",2,Vec4(0.),&_lock); Vec4 scale = _args.getOpt<Vec4 >("scale",3,Vec4(1.),&_lock); Vec4 size = _args.getOpt<Vec4 >("size",4,Vec4(-1.) ,&_lock); _retval = getPyNone(); interpolateGrid4d(target,source,offset,scale,size); _args.check(); }
+ pbFinalizePlugin(parent,"interpolateGrid4d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("interpolateGrid4d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_interpolateGrid4d ("","interpolateGrid4d",_W_10);
+extern "C" {
+ void PbRegister_interpolateGrid4d() {
+ KEEP_UNUSED(_RP_interpolateGrid4d); }
+ }
+
+
+//! linearly interpolate vec4 data of a 4d grid
+
+void interpolateGrid4dVec( Grid4d<Vec4>& target, Grid4d<Vec4>& source, Vec4 offset=Vec4(0.), Vec4 scale=Vec4(1.), Vec4 size=Vec4(-1.) ) {
+ Vec4 srcFac(1.), off2 = offset;
+ gridFactor4d( toVec4(source.getSize()), toVec4(target.getSize()), size,scale, srcFac,off2 );
+ knInterpol4d<Vec4> (target, source, srcFac, off2 );
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "interpolateGrid4dVec" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid4d<Vec4>& target = *_args.getPtr<Grid4d<Vec4> >("target",0,&_lock); Grid4d<Vec4>& source = *_args.getPtr<Grid4d<Vec4> >("source",1,&_lock); Vec4 offset = _args.getOpt<Vec4 >("offset",2,Vec4(0.),&_lock); Vec4 scale = _args.getOpt<Vec4 >("scale",3,Vec4(1.),&_lock); Vec4 size = _args.getOpt<Vec4 >("size",4,Vec4(-1.) ,&_lock); _retval = getPyNone(); interpolateGrid4dVec(target,source,offset,scale,size); _args.check(); }
+ pbFinalizePlugin(parent,"interpolateGrid4dVec", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("interpolateGrid4dVec",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_interpolateGrid4dVec ("","interpolateGrid4dVec",_W_11);
+extern "C" {
+ void PbRegister_interpolateGrid4dVec() {
+ KEEP_UNUSED(_RP_interpolateGrid4dVec); }
+ }
+
+
+
+
+// explicit instantiation
+template class Grid4d<int>;
+template class Grid4d<Real>;
+template class Grid4d<Vec3>;
+template class Grid4d<Vec4>;
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h
new file mode 100644
index 00000000000..daeadff1c09
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h
@@ -0,0 +1,700 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#ifndef _GRID4D_H
+#define _GRID4D_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "vector4d.h"
+#include "kernel.h"
+
+
+namespace Manta {
+
+
+//! Base class for all grids
+class Grid4dBase : public PbClass {public:
+ enum Grid4dType { TypeNone = 0, TypeReal = 1, TypeInt = 2, TypeVec3 = 4, TypeVec4 = 8 };
+
+ Grid4dBase(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Grid4dBase::Grid4dBase" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new Grid4dBase(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Grid4dBase::Grid4dBase" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::Grid4dBase",e.what()); return -1; }
+ }
+
+
+ //! Get the grids X dimension
+ inline int getSizeX() const { return mSize.x; } static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeX" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeX()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::getSizeX" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::getSizeX",e.what()); return 0; }
+ }
+
+ //! Get the grids Y dimension
+ inline int getSizeY() const { return mSize.y; } static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeY" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeY()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::getSizeY" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::getSizeY",e.what()); return 0; }
+ }
+
+ //! Get the grids Z dimension
+ inline int getSizeZ() const { return mSize.z; } static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeZ" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeZ()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::getSizeZ" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::getSizeZ",e.what()); return 0; }
+ }
+
+ //! Get the grids T dimension
+ inline int getSizeT() const { return mSize.t; } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSizeT" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSizeT()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::getSizeT" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::getSizeT",e.what()); return 0; }
+ }
+
+ //! Get the grids dimensions
+ inline Vec4i getSize() const { return mSize; } static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::getSize" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getSize()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::getSize" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::getSize",e.what()); return 0; }
+ }
+
+
+ //! Get Stride in X dimension
+ inline IndexInt getStrideX() const { return 1; }
+ //! Get Stride in Y dimension
+ inline IndexInt getStrideY() const { return mSize.x; }
+ //! Get Stride in Z dimension
+ inline IndexInt getStrideZ() const { return mStrideZ; }
+ //! Get Stride in T dimension
+ inline IndexInt getStrideT() const { return mStrideT; }
+
+ inline Real getDx() { return mDx; }
+
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(int i, int j, int k, int t) const;
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(IndexInt idx) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec4i& p, int bnd) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec4i& p) const;
+ //! Check if index is within given boundaries
+ inline bool isInBounds(const Vec4& p, int bnd = 0) const { return isInBounds(toVec4i(p), bnd); }
+ //! Check if linear index is in the range of the array
+ inline bool isInBounds(IndexInt idx) const;
+
+ //! Get the type of grid
+ inline Grid4dType getType() const { return mType; }
+ //! Check dimensionality
+ inline bool is3D() const { return true; } static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::is3D" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->is3D()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::is3D" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::is3D",e.what()); return 0; }
+ }
+
+ inline bool is4D() const { return true; } static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4dBase* pbo = dynamic_cast<Grid4dBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4dBase::is4D" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->is4D()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4dBase::is4D" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4dBase::is4D",e.what()); return 0; }
+ }
+
+
+ //! 3d compatibility
+ inline bool isInBounds(int i,int j, int k, int t, int bnd) const { return isInBounds( Vec4i(i,j,k,t), bnd ); }
+
+ //! Get index into the data
+ inline IndexInt index(int i, int j, int k, int t) const { DEBUG_ONLY(checkIndex(i,j,k,t)); return (IndexInt)i + (IndexInt)mSize.x * j + (IndexInt)mStrideZ * k + (IndexInt)mStrideT * t; }
+ //! Get index into the data
+ inline IndexInt index(const Vec4i& pos) const { DEBUG_ONLY(checkIndex(pos.x,pos.y,pos.z,pos.t)); return (IndexInt)pos.x + (IndexInt)mSize.x * pos.y + (IndexInt)mStrideZ * pos.z + (IndexInt)mStrideT * pos.t; }
+protected:
+
+ Grid4dType mType;
+ Vec4i mSize;
+ Real mDx;
+ // precomputed Z,T shift: to ensure 2D compatibility, always use this instead of sx*sy !
+ IndexInt mStrideZ; IndexInt mStrideT; public: PbArgs _args; }
+#define _C_Grid4dBase
+;
+
+//! Grid class
+
+template<class T> class Grid4d : public Grid4dBase {public:
+ //! init new grid, values are set to zero
+ Grid4d(FluidSolver* parent, bool show = true); static int _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Grid4d::Grid4d" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); bool show = _args.getOpt<bool >("show",1,true,&_lock); obj = new Grid4d(parent,show); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Grid4d::Grid4d" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::Grid4d",e.what()); return -1; }
+ }
+
+ //! create new & copy content from another grid
+ Grid4d(const Grid4d<T>& a);
+ //! return memory to solver
+ virtual ~Grid4d();
+
+ typedef T BASETYPE;
+ typedef Grid4dBase BASETYPE_GRID;
+
+ void save(std::string name); static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::save",e.what()); return 0; }
+ }
+
+ void load(std::string name); static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::load",e.what()); return 0; }
+ }
+
+
+ //! set all cells to zero
+ void clear(); static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::clear",e.what()); return 0; }
+ }
+
+
+ //! all kinds of access functions, use grid(), grid[] or grid.get()
+ //! access data
+ inline T get(int i,int j, int k, int t) const { return mData[index(i,j,k,t)]; }
+ //! access data
+ inline T& get(int i,int j, int k, int t) { return mData[index(i,j,k,t)]; }
+ //! access data
+ inline T get(IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T get(const Vec4i& pos) const { return mData[index(pos)]; }
+ //! access data
+ inline T& operator()(int i, int j, int k, int t) { return mData[index(i, j, k,t)]; }
+ //! access data
+ inline T operator()(int i, int j, int k, int t) const { return mData[index(i, j, k,t)]; }
+ //! access data
+ inline T& operator()(IndexInt idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T operator()(IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T& operator()(const Vec4i& pos) { return mData[index(pos)]; }
+ //! access data
+ inline T operator()(const Vec4i& pos) const { return mData[index(pos)]; }
+ //! access data
+ inline T& operator[](IndexInt idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline const T operator[](IndexInt idx) const { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+
+ // interpolated access
+ inline T getInterpolated(const Vec4& pos) const { return interpol4d<T>(mData, mSize, mStrideZ, mStrideT, pos); }
+
+ // assignment / copy
+
+ //! warning - do not use "=" for grids in python, this copies the reference! not the grid content...
+ //Grid4d<T>& operator=(const Grid4d<T>& a);
+ //! copy content from other grid (use this one instead of operator= !)
+ Grid4d<T>& copyFrom(const Grid4d<T>& a, bool copyType=true ); static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::copyFrom" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<T>& a = *_args.getPtr<Grid4d<T> >("a",0,&_lock); bool copyType = _args.getOpt<bool >("copyType",1,true ,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->copyFrom(a,copyType)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::copyFrom" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::copyFrom",e.what()); return 0; }
+ }
+ // old: { *this = a; }
+
+ // helper functions to work with grids in scene files
+
+ //! add/subtract other grid
+ void add(const Grid4d<T>& a); static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::add" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<T>& a = *_args.getPtr<Grid4d<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->add(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::add" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::add",e.what()); return 0; }
+ }
+
+ void sub(const Grid4d<T>& a); static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::sub" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<T>& a = *_args.getPtr<Grid4d<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->sub(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::sub" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::sub",e.what()); return 0; }
+ }
+
+ //! set all cells to constant value
+ void setConst(T s); static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::setConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::setConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::setConst",e.what()); return 0; }
+ }
+
+ //! add constant to all grid cells
+ void addConst(T s); static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::addConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::addConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::addConst",e.what()); return 0; }
+ }
+
+ //! add scaled other grid to current one (note, only "Real" factor, "T" type not supported here!)
+ void addScaled(const Grid4d<T>& a, const T& factor); static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::addScaled" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<T>& a = *_args.getPtr<Grid4d<T> >("a",0,&_lock); const T& factor = *_args.getPtr<T >("factor",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addScaled(a,factor); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::addScaled" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::addScaled",e.what()); return 0; }
+ }
+
+ //! multiply contents of grid
+ void mult( const Grid4d<T>& a); static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::mult" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid4d<T>& a = *_args.getPtr<Grid4d<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->mult(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::mult" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::mult",e.what()); return 0; }
+ }
+
+ //! multiply each cell by a constant scalar value
+ void multConst(T s); static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::multConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->multConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::multConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::multConst",e.what()); return 0; }
+ }
+
+ //! clamp content to range (for vec3, clamps each component separately)
+ void clamp(Real min, Real max); static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::clamp" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real min = _args.get<Real >("min",0,&_lock); Real max = _args.get<Real >("max",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clamp(min,max); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::clamp" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::clamp",e.what()); return 0; }
+ }
+
+
+ // common compound operators
+ //! get absolute max value in grid
+ Real getMaxAbs(); static PyObject* _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::getMaxAbs" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxAbs()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::getMaxAbs" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::getMaxAbs",e.what()); return 0; }
+ }
+
+ //! get max value in grid
+ Real getMax(); static PyObject* _W_22 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::getMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMax()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::getMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::getMax",e.what()); return 0; }
+ }
+
+ //! get min value in grid
+ Real getMin(); static PyObject* _W_23 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::getMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMin()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::getMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::getMin",e.what()); return 0; }
+ }
+
+ //! set all boundary cells to constant value (Dirichlet)
+ void setBound(T value, int boundaryWidth=1); static PyObject* _W_24 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::setBound" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T value = _args.get<T >("value",0,&_lock); int boundaryWidth = _args.getOpt<int >("boundaryWidth",1,1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setBound(value,boundaryWidth); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::setBound" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::setBound",e.what()); return 0; }
+ }
+
+ //! set all boundary cells to last inner value (Neumann)
+ void setBoundNeumann(int boundaryWidth=1); static PyObject* _W_25 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::setBoundNeumann" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int boundaryWidth = _args.getOpt<int >("boundaryWidth",0,1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setBoundNeumann(boundaryWidth); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::setBoundNeumann" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::setBoundNeumann",e.what()); return 0; }
+ }
+
+
+ //! debugging helper, print grid from Python
+ void printGrid(int zSlice=-1, int tSlice=-1, bool printIndex=false, int bnd=0); static PyObject* _W_26 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Grid4d* pbo = dynamic_cast<Grid4d*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Grid4d::printGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int zSlice = _args.getOpt<int >("zSlice",0,-1,&_lock); int tSlice = _args.getOpt<int >("tSlice",1,-1,&_lock); bool printIndex = _args.getOpt<bool >("printIndex",2,false,&_lock); int bnd = _args.getOpt<int >("bnd",3,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->printGrid(zSlice,tSlice,printIndex,bnd); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Grid4d::printGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Grid4d::printGrid",e.what()); return 0; }
+ }
+
+
+ // c++ only operators
+ template<class S> Grid4d<T>& operator+=(const Grid4d<S>& a);
+ template<class S> Grid4d<T>& operator+=(const S& a);
+ template<class S> Grid4d<T>& operator-=(const Grid4d<S>& a);
+ template<class S> Grid4d<T>& operator-=(const S& a);
+ template<class S> Grid4d<T>& operator*=(const Grid4d<S>& a);
+ template<class S> Grid4d<T>& operator*=(const S& a);
+ template<class S> Grid4d<T>& operator/=(const Grid4d<S>& a);
+ template<class S> Grid4d<T>& operator/=(const S& a);
+ Grid4d<T>& safeDivide(const Grid4d<T>& a);
+
+ //! Swap data with another grid (no actual data is moved)
+ void swap(Grid4d<T>& other);
+
+protected: T* mData; public: PbArgs _args; }
+#define _C_Grid4d
+;
+
+// Python doesn't know about templates: explicit aliases needed
+
+
+
+
+
+
+//! helper to compute grid conversion factor between local coordinates of two grids
+inline Vec4 calcGridSizeFactor4d(Vec4i s1, Vec4i s2) {
+ return Vec4( Real(s1[0])/s2[0], Real(s1[1])/s2[1], Real(s1[2])/s2[2] , Real(s1[3])/s2[3] );
+}
+inline Vec4 calcGridSizeFactor4d(Vec4 s1, Vec4 s2) {
+ return Vec4( s1[0]/s2[0], s1[1]/s2[1], s1[2]/s2[2] , s1[3]/s2[3] );
+}
+
+// prototypes for grid plugins
+void getComponent4d(const Grid4d<Vec4>& src, Grid4d<Real>& dst, int c);
+void setComponent4d(const Grid4d<Real>& src, Grid4d<Vec4>& dst, int c);
+
+
+//******************************************************************************
+// Implementation of inline functions
+
+inline void Grid4dBase::checkIndex(int i, int j, int k, int t) const {
+ if ( i<0 || j<0 || i>=mSize.x || j>=mSize.y || k<0|| k>= mSize.z ||
+ t<0|| t>= mSize.t ) {
+ std::ostringstream s;
+ s << "Grid4d " << mName << " dim " << mSize << " : index " << i << "," << j << "," << k << ","<<t<<" out of bound ";
+ errMsg(s.str());
+ }
+}
+
+inline void Grid4dBase::checkIndex(IndexInt idx) const {
+ if (idx<0 || idx >= mSize.x * mSize.y * mSize.z * mSize.t) {
+ std::ostringstream s;
+ s << "Grid4d " << mName << " dim " << mSize << " : index " << idx << " out of bound ";
+ errMsg(s.str());
+ }
+}
+
+bool Grid4dBase::isInBounds(const Vec4i& p) const {
+ return (p.x >= 0 && p.y >= 0 && p.z >= 0 && p.t >= 0 &&
+ p.x < mSize.x && p.y < mSize.y && p.z < mSize.z && p.t < mSize.t);
+}
+
+bool Grid4dBase::isInBounds(const Vec4i& p, int bnd) const {
+ bool ret = (p.x >= bnd && p.y >= bnd && p.x < mSize.x-bnd && p.y < mSize.y-bnd);
+ ret &= (p.z >= bnd && p.z < mSize.z-bnd);
+ ret &= (p.t >= bnd && p.t < mSize.t-bnd);
+ return ret;
+}
+//! Check if linear index is in the range of the array
+bool Grid4dBase::isInBounds(IndexInt idx) const {
+ if (idx<0 || idx >= mSize.x * mSize.y * mSize.z * mSize.t) {
+ return false;
+ }
+ return true;
+}
+
+// note - ugly, mostly copied from normal GRID!
+
+template <class T, class S> struct Grid4dAdd : public KernelBase {
+ Grid4dAdd(Grid4d<T>& me, const Grid4d<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<S>& other ) const { me[idx] += other[idx]; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<S>& getArg1() {
+ return other; }
+ typedef Grid4d<S> type1; void runMessage() { debMsg("Executing kernel Grid4dAdd ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; const Grid4d<S>& other; }
+;
+template <class T, class S> struct Grid4dSub : public KernelBase {
+ Grid4dSub(Grid4d<T>& me, const Grid4d<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<S>& other ) const { me[idx] -= other[idx]; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<S>& getArg1() {
+ return other; }
+ typedef Grid4d<S> type1; void runMessage() { debMsg("Executing kernel Grid4dSub ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; const Grid4d<S>& other; }
+;
+template <class T, class S> struct Grid4dMult : public KernelBase {
+ Grid4dMult(Grid4d<T>& me, const Grid4d<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<S>& other ) const { me[idx] *= other[idx]; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<S>& getArg1() {
+ return other; }
+ typedef Grid4d<S> type1; void runMessage() { debMsg("Executing kernel Grid4dMult ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; const Grid4d<S>& other; }
+;
+template <class T, class S> struct Grid4dDiv : public KernelBase {
+ Grid4dDiv(Grid4d<T>& me, const Grid4d<S>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<S>& other ) const { me[idx] /= other[idx]; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<S>& getArg1() {
+ return other; }
+ typedef Grid4d<S> type1; void runMessage() { debMsg("Executing kernel Grid4dDiv ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; const Grid4d<S>& other; }
+;
+template <class T, class S> struct Grid4dAddScalar : public KernelBase {
+ Grid4dAddScalar(Grid4d<T>& me, const S& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const S& other ) const { me[idx] += other; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel Grid4dAddScalar ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; const S& other; }
+;
+template <class T, class S> struct Grid4dMultScalar : public KernelBase {
+ Grid4dMultScalar(Grid4d<T>& me, const S& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const S& other ) const { me[idx] *= other; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel Grid4dMultScalar ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; const S& other; }
+;
+template <class T, class S> struct Grid4dScaledAdd : public KernelBase {
+ Grid4dScaledAdd(Grid4d<T>& me, const Grid4d<T>& other, const S& factor) : KernelBase(&me,0) ,me(me),other(other),factor(factor) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<T>& other, const S& factor ) const { me[idx] += factor * other[idx]; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<T>& getArg1() {
+ return other; }
+ typedef Grid4d<T> type1;inline const S& getArg2() {
+ return factor; }
+ typedef S type2; void runMessage() { debMsg("Executing kernel Grid4dScaledAdd ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other,factor); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; const Grid4d<T>& other; const S& factor; }
+;
+
+template <class T> struct Grid4dSafeDiv : public KernelBase {
+ Grid4dSafeDiv(Grid4d<T>& me, const Grid4d<T>& other) : KernelBase(&me,0) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, const Grid4d<T>& other ) const { me[idx] = safeDivide(me[idx], other[idx]); } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline const Grid4d<T>& getArg1() {
+ return other; }
+ typedef Grid4d<T> type1; void runMessage() { debMsg("Executing kernel Grid4dSafeDiv ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; const Grid4d<T>& other; }
+;
+template <class T> struct Grid4dSetConst : public KernelBase {
+ Grid4dSetConst(Grid4d<T>& me, T value) : KernelBase(&me,0) ,me(me),value(value) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid4d<T>& me, T value ) const { me[idx] = value; } inline Grid4d<T>& getArg0() {
+ return me; }
+ typedef Grid4d<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel Grid4dSetConst ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,value); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid4d<T>& me; T value; }
+;
+
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator+= (const Grid4d<S>& a) {
+ Grid4dAdd<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator+= (const S& a) {
+ Grid4dAddScalar<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator-= (const Grid4d<S>& a) {
+ Grid4dSub<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator-= (const S& a) {
+ Grid4dAddScalar<T,S> (*this, -a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator*= (const Grid4d<S>& a) {
+ Grid4dMult<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator*= (const S& a) {
+ Grid4dMultScalar<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator/= (const Grid4d<S>& a) {
+ Grid4dDiv<T,S> (*this, a);
+ return *this;
+}
+template<class T> template<class S> Grid4d<T>& Grid4d<T>::operator/= (const S& a) {
+ S rez((S)1.0 / a);
+ Grid4dMultScalar<T,S> (*this, rez);
+ return *this;
+}
+
+
+//******************************************************************************
+// Other helper functions
+
+inline Vec4 getGradient4d(const Grid4d<Real>& data, int i, int j, int k, int t) {
+ Vec4 v;
+ if (i > data.getSizeX()-2) i= data.getSizeX()-2;
+ if (j > data.getSizeY()-2) j= data.getSizeY()-2;
+ if (k > data.getSizeZ()-2) k= data.getSizeZ()-2;
+ if (t > data.getSizeT()-2) t= data.getSizeT()-2;
+ if (i < 1) i = 1;
+ if (j < 1) j = 1;
+ if (k < 1) k = 1;
+ if (t < 1) t = 1;
+ v = Vec4( data(i+1,j ,k ,t ) - data(i-1,j ,k ,t ) ,
+ data(i ,j+1,k ,t ) - data(i ,j-1,k ,t ) ,
+ data(i ,j ,k+1,t ) - data(i ,j ,k-1,t ) ,
+ data(i ,j ,k ,t+1) - data(i ,j ,k ,t-1) );
+ return v;
+}
+
+
+
+template <class S> struct KnInterpolateGrid4dTempl : public KernelBase {
+ KnInterpolateGrid4dTempl(Grid4d<S>& target, Grid4d<S>& source, const Vec4& sourceFactor , Vec4 offset) : KernelBase(&target,0) ,target(target),source(source),sourceFactor(sourceFactor),offset(offset) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, int t, Grid4d<S>& target, Grid4d<S>& source, const Vec4& sourceFactor , Vec4 offset ) const {
+ Vec4 pos = Vec4(i,j,k,t) * sourceFactor + offset;
+ if(!source.is3D()) pos[2] = 0.; // allow 2d -> 3d
+ if(!source.is4D()) pos[3] = 0.; // allow 3d -> 4d
+ target(i,j,k,t) = source.getInterpolated(pos);
+} inline Grid4d<S>& getArg0() {
+ return target; }
+ typedef Grid4d<S> type0;inline Grid4d<S>& getArg1() {
+ return source; }
+ typedef Grid4d<S> type1;inline const Vec4& getArg2() {
+ return sourceFactor; }
+ typedef Vec4 type2;inline Vec4& getArg3() {
+ return offset; }
+ typedef Vec4 type3; void runMessage() { debMsg("Executing kernel KnInterpolateGrid4dTempl ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " " t "<< minT<<" - "<< maxT , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ if (maxT>1) {
+ for (int t=__r.begin(); t!=(int)__r.end(); t++) for (int k=0; k<maxZ; k++) for (int j=0; j<maxY; j++) for (int i=0; i<maxX; i++) op(i,j,k,t,target,source,sourceFactor,offset); }
+ else if (maxZ>1) {
+ const int t=0; for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<maxY; j++) for (int i=0; i<maxX; i++) op(i,j,k,t,target,source,sourceFactor,offset); }
+ else {
+ const int t=0; const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<maxX; i++) op(i,j,k,t,target,source,sourceFactor,offset); }
+ }
+ void run() {
+ if (maxT>1) {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(minT, maxT), *this); }
+ else if (maxZ>1) {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); }
+ else {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ }
+ Grid4d<S>& target; Grid4d<S>& source; const Vec4& sourceFactor; Vec4 offset; }
+;
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h.reg
new file mode 100644
index 00000000000..874c3d6670d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h.reg
@@ -0,0 +1,39 @@
+#include "grid4d.h"
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","Grid4dBase","PbClass"); template<> const char* Namify<Grid4dBase >::S = "Grid4dBase";
+>Grid4dBase^
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","Grid4dBase",Grid4dBase::_W_0);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","getSizeX",Grid4dBase::_W_1);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","getSizeY",Grid4dBase::_W_2);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","getSizeZ",Grid4dBase::_W_3);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","getSizeT",Grid4dBase::_W_4);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","getSize",Grid4dBase::_W_5);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","is3D",Grid4dBase::_W_6);
++Grid4dBase^ static const Pb::Register _R_$IDX$ ("Grid4dBase","is4D",Grid4dBase::_W_7);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","Grid4d<$CT$>","Grid4dBase"); template<> const char* Namify<Grid4d<$CT$> >::S = "Grid4d<$CT$>";
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","Grid4d",Grid4d<$CT$>::_W_8);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","save",Grid4d<$CT$>::_W_9);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","load",Grid4d<$CT$>::_W_10);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","clear",Grid4d<$CT$>::_W_11);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","copyFrom",Grid4d<$CT$>::_W_12);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","add",Grid4d<$CT$>::_W_13);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","sub",Grid4d<$CT$>::_W_14);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","setConst",Grid4d<$CT$>::_W_15);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","addConst",Grid4d<$CT$>::_W_16);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","addScaled",Grid4d<$CT$>::_W_17);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","mult",Grid4d<$CT$>::_W_18);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","multConst",Grid4d<$CT$>::_W_19);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","clamp",Grid4d<$CT$>::_W_20);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","getMaxAbs",Grid4d<$CT$>::_W_21);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","getMax",Grid4d<$CT$>::_W_22);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","getMin",Grid4d<$CT$>::_W_23);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","setBound",Grid4d<$CT$>::_W_24);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","setBoundNeumann",Grid4d<$CT$>::_W_25);
++Grid4d^ static const Pb::Register _R_$IDX$ ("Grid4d<$CT$>","printGrid",Grid4d<$CT$>::_W_26);
+>Grid4d^int
+&static const Pb::Register _R_$IDX$ ("Grid4d<int>","Grid4Int","");
+>Grid4d^Real
+&static const Pb::Register _R_$IDX$ ("Grid4d<Real>","Grid4Real","");
+>Grid4d^Vec3
+&static const Pb::Register _R_$IDX$ ("Grid4d<Vec3>","Grid4Vec3","");
+>Grid4d^Vec4
+&static const Pb::Register _R_$IDX$ ("Grid4d<Vec4>","Grid4Vec4","");
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h.reg.cpp
new file mode 100644
index 00000000000..9304610a2d1
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/grid4d.h.reg.cpp
@@ -0,0 +1,204 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "grid4d.h"
+namespace Manta {
+#ifdef _C_Grid4d
+ static const Pb::Register _R_12 ("Grid4d<int>","Grid4d<int>","Grid4dBase"); template<> const char* Namify<Grid4d<int> >::S = "Grid4d<int>";
+ static const Pb::Register _R_13 ("Grid4d<int>","Grid4d",Grid4d<int>::_W_8);
+ static const Pb::Register _R_14 ("Grid4d<int>","save",Grid4d<int>::_W_9);
+ static const Pb::Register _R_15 ("Grid4d<int>","load",Grid4d<int>::_W_10);
+ static const Pb::Register _R_16 ("Grid4d<int>","clear",Grid4d<int>::_W_11);
+ static const Pb::Register _R_17 ("Grid4d<int>","copyFrom",Grid4d<int>::_W_12);
+ static const Pb::Register _R_18 ("Grid4d<int>","add",Grid4d<int>::_W_13);
+ static const Pb::Register _R_19 ("Grid4d<int>","sub",Grid4d<int>::_W_14);
+ static const Pb::Register _R_20 ("Grid4d<int>","setConst",Grid4d<int>::_W_15);
+ static const Pb::Register _R_21 ("Grid4d<int>","addConst",Grid4d<int>::_W_16);
+ static const Pb::Register _R_22 ("Grid4d<int>","addScaled",Grid4d<int>::_W_17);
+ static const Pb::Register _R_23 ("Grid4d<int>","mult",Grid4d<int>::_W_18);
+ static const Pb::Register _R_24 ("Grid4d<int>","multConst",Grid4d<int>::_W_19);
+ static const Pb::Register _R_25 ("Grid4d<int>","clamp",Grid4d<int>::_W_20);
+ static const Pb::Register _R_26 ("Grid4d<int>","getMaxAbs",Grid4d<int>::_W_21);
+ static const Pb::Register _R_27 ("Grid4d<int>","getMax",Grid4d<int>::_W_22);
+ static const Pb::Register _R_28 ("Grid4d<int>","getMin",Grid4d<int>::_W_23);
+ static const Pb::Register _R_29 ("Grid4d<int>","setBound",Grid4d<int>::_W_24);
+ static const Pb::Register _R_30 ("Grid4d<int>","setBoundNeumann",Grid4d<int>::_W_25);
+ static const Pb::Register _R_31 ("Grid4d<int>","printGrid",Grid4d<int>::_W_26);
+ static const Pb::Register _R_32 ("Grid4d<Real>","Grid4d<Real>","Grid4dBase"); template<> const char* Namify<Grid4d<Real> >::S = "Grid4d<Real>";
+ static const Pb::Register _R_33 ("Grid4d<Real>","Grid4d",Grid4d<Real>::_W_8);
+ static const Pb::Register _R_34 ("Grid4d<Real>","save",Grid4d<Real>::_W_9);
+ static const Pb::Register _R_35 ("Grid4d<Real>","load",Grid4d<Real>::_W_10);
+ static const Pb::Register _R_36 ("Grid4d<Real>","clear",Grid4d<Real>::_W_11);
+ static const Pb::Register _R_37 ("Grid4d<Real>","copyFrom",Grid4d<Real>::_W_12);
+ static const Pb::Register _R_38 ("Grid4d<Real>","add",Grid4d<Real>::_W_13);
+ static const Pb::Register _R_39 ("Grid4d<Real>","sub",Grid4d<Real>::_W_14);
+ static const Pb::Register _R_40 ("Grid4d<Real>","setConst",Grid4d<Real>::_W_15);
+ static const Pb::Register _R_41 ("Grid4d<Real>","addConst",Grid4d<Real>::_W_16);
+ static const Pb::Register _R_42 ("Grid4d<Real>","addScaled",Grid4d<Real>::_W_17);
+ static const Pb::Register _R_43 ("Grid4d<Real>","mult",Grid4d<Real>::_W_18);
+ static const Pb::Register _R_44 ("Grid4d<Real>","multConst",Grid4d<Real>::_W_19);
+ static const Pb::Register _R_45 ("Grid4d<Real>","clamp",Grid4d<Real>::_W_20);
+ static const Pb::Register _R_46 ("Grid4d<Real>","getMaxAbs",Grid4d<Real>::_W_21);
+ static const Pb::Register _R_47 ("Grid4d<Real>","getMax",Grid4d<Real>::_W_22);
+ static const Pb::Register _R_48 ("Grid4d<Real>","getMin",Grid4d<Real>::_W_23);
+ static const Pb::Register _R_49 ("Grid4d<Real>","setBound",Grid4d<Real>::_W_24);
+ static const Pb::Register _R_50 ("Grid4d<Real>","setBoundNeumann",Grid4d<Real>::_W_25);
+ static const Pb::Register _R_51 ("Grid4d<Real>","printGrid",Grid4d<Real>::_W_26);
+ static const Pb::Register _R_52 ("Grid4d<Vec3>","Grid4d<Vec3>","Grid4dBase"); template<> const char* Namify<Grid4d<Vec3> >::S = "Grid4d<Vec3>";
+ static const Pb::Register _R_53 ("Grid4d<Vec3>","Grid4d",Grid4d<Vec3>::_W_8);
+ static const Pb::Register _R_54 ("Grid4d<Vec3>","save",Grid4d<Vec3>::_W_9);
+ static const Pb::Register _R_55 ("Grid4d<Vec3>","load",Grid4d<Vec3>::_W_10);
+ static const Pb::Register _R_56 ("Grid4d<Vec3>","clear",Grid4d<Vec3>::_W_11);
+ static const Pb::Register _R_57 ("Grid4d<Vec3>","copyFrom",Grid4d<Vec3>::_W_12);
+ static const Pb::Register _R_58 ("Grid4d<Vec3>","add",Grid4d<Vec3>::_W_13);
+ static const Pb::Register _R_59 ("Grid4d<Vec3>","sub",Grid4d<Vec3>::_W_14);
+ static const Pb::Register _R_60 ("Grid4d<Vec3>","setConst",Grid4d<Vec3>::_W_15);
+ static const Pb::Register _R_61 ("Grid4d<Vec3>","addConst",Grid4d<Vec3>::_W_16);
+ static const Pb::Register _R_62 ("Grid4d<Vec3>","addScaled",Grid4d<Vec3>::_W_17);
+ static const Pb::Register _R_63 ("Grid4d<Vec3>","mult",Grid4d<Vec3>::_W_18);
+ static const Pb::Register _R_64 ("Grid4d<Vec3>","multConst",Grid4d<Vec3>::_W_19);
+ static const Pb::Register _R_65 ("Grid4d<Vec3>","clamp",Grid4d<Vec3>::_W_20);
+ static const Pb::Register _R_66 ("Grid4d<Vec3>","getMaxAbs",Grid4d<Vec3>::_W_21);
+ static const Pb::Register _R_67 ("Grid4d<Vec3>","getMax",Grid4d<Vec3>::_W_22);
+ static const Pb::Register _R_68 ("Grid4d<Vec3>","getMin",Grid4d<Vec3>::_W_23);
+ static const Pb::Register _R_69 ("Grid4d<Vec3>","setBound",Grid4d<Vec3>::_W_24);
+ static const Pb::Register _R_70 ("Grid4d<Vec3>","setBoundNeumann",Grid4d<Vec3>::_W_25);
+ static const Pb::Register _R_71 ("Grid4d<Vec3>","printGrid",Grid4d<Vec3>::_W_26);
+ static const Pb::Register _R_72 ("Grid4d<Vec4>","Grid4d<Vec4>","Grid4dBase"); template<> const char* Namify<Grid4d<Vec4> >::S = "Grid4d<Vec4>";
+ static const Pb::Register _R_73 ("Grid4d<Vec4>","Grid4d",Grid4d<Vec4>::_W_8);
+ static const Pb::Register _R_74 ("Grid4d<Vec4>","save",Grid4d<Vec4>::_W_9);
+ static const Pb::Register _R_75 ("Grid4d<Vec4>","load",Grid4d<Vec4>::_W_10);
+ static const Pb::Register _R_76 ("Grid4d<Vec4>","clear",Grid4d<Vec4>::_W_11);
+ static const Pb::Register _R_77 ("Grid4d<Vec4>","copyFrom",Grid4d<Vec4>::_W_12);
+ static const Pb::Register _R_78 ("Grid4d<Vec4>","add",Grid4d<Vec4>::_W_13);
+ static const Pb::Register _R_79 ("Grid4d<Vec4>","sub",Grid4d<Vec4>::_W_14);
+ static const Pb::Register _R_80 ("Grid4d<Vec4>","setConst",Grid4d<Vec4>::_W_15);
+ static const Pb::Register _R_81 ("Grid4d<Vec4>","addConst",Grid4d<Vec4>::_W_16);
+ static const Pb::Register _R_82 ("Grid4d<Vec4>","addScaled",Grid4d<Vec4>::_W_17);
+ static const Pb::Register _R_83 ("Grid4d<Vec4>","mult",Grid4d<Vec4>::_W_18);
+ static const Pb::Register _R_84 ("Grid4d<Vec4>","multConst",Grid4d<Vec4>::_W_19);
+ static const Pb::Register _R_85 ("Grid4d<Vec4>","clamp",Grid4d<Vec4>::_W_20);
+ static const Pb::Register _R_86 ("Grid4d<Vec4>","getMaxAbs",Grid4d<Vec4>::_W_21);
+ static const Pb::Register _R_87 ("Grid4d<Vec4>","getMax",Grid4d<Vec4>::_W_22);
+ static const Pb::Register _R_88 ("Grid4d<Vec4>","getMin",Grid4d<Vec4>::_W_23);
+ static const Pb::Register _R_89 ("Grid4d<Vec4>","setBound",Grid4d<Vec4>::_W_24);
+ static const Pb::Register _R_90 ("Grid4d<Vec4>","setBoundNeumann",Grid4d<Vec4>::_W_25);
+ static const Pb::Register _R_91 ("Grid4d<Vec4>","printGrid",Grid4d<Vec4>::_W_26);
+#endif
+#ifdef _C_Grid4dBase
+ static const Pb::Register _R_92 ("Grid4dBase","Grid4dBase","PbClass"); template<> const char* Namify<Grid4dBase >::S = "Grid4dBase";
+ static const Pb::Register _R_93 ("Grid4dBase","Grid4dBase",Grid4dBase::_W_0);
+ static const Pb::Register _R_94 ("Grid4dBase","getSizeX",Grid4dBase::_W_1);
+ static const Pb::Register _R_95 ("Grid4dBase","getSizeY",Grid4dBase::_W_2);
+ static const Pb::Register _R_96 ("Grid4dBase","getSizeZ",Grid4dBase::_W_3);
+ static const Pb::Register _R_97 ("Grid4dBase","getSizeT",Grid4dBase::_W_4);
+ static const Pb::Register _R_98 ("Grid4dBase","getSize",Grid4dBase::_W_5);
+ static const Pb::Register _R_99 ("Grid4dBase","is3D",Grid4dBase::_W_6);
+ static const Pb::Register _R_100 ("Grid4dBase","is4D",Grid4dBase::_W_7);
+#endif
+static const Pb::Register _R_8 ("Grid4d<int>","Grid4Int","");
+static const Pb::Register _R_9 ("Grid4d<Real>","Grid4Real","");
+static const Pb::Register _R_10 ("Grid4d<Vec3>","Grid4Vec3","");
+static const Pb::Register _R_11 ("Grid4d<Vec4>","Grid4Vec4","");
+extern "C" {
+void PbRegister_file_8()
+{
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.cpp
new file mode 100644
index 00000000000..1418905083a
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.cpp
@@ -0,0 +1,64 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Function and macros for defining compution kernels over grids
+ *
+ ******************************************************************************/
+
+#include "kernel.h"
+#include "grid.h"
+#include "grid4d.h"
+#include "particle.h"
+
+namespace Manta {
+
+KernelBase::KernelBase(const GridBase* base, int bnd) :
+ maxX (base->getSizeX()-bnd),
+ maxY (base->getSizeY()-bnd),
+ maxZ (base->is3D() ? (base->getSizeZ()-bnd) : 1),
+ minZ (base->is3D() ? bnd : 0), maxT(1), minT(0),
+ X (base->getStrideX()),
+ Y (base->getStrideY()),
+ Z (base->getStrideZ()), dimT (0),
+ size (base->getSizeX() * base->getSizeY() * (IndexInt)base->getSizeZ())
+ {}
+
+KernelBase::KernelBase(IndexInt num) :
+ maxX (0), maxY (0), maxZ (0), minZ (0), maxT(0),
+ X (0), Y (0), Z (0), dimT (0),
+ size(num)
+ {}
+
+KernelBase::KernelBase(const Grid4dBase* base, int bnd) :
+ maxX (base->getSizeX()-bnd),
+ maxY (base->getSizeY()-bnd),
+ maxZ (base->getSizeZ()-bnd), minZ (bnd),
+ maxT (base->getSizeT()-bnd), minT (bnd),
+ X (base->getStrideX()),
+ Y (base->getStrideY()),
+ Z (base->getStrideZ()),
+ dimT (base->getStrideT()),
+ size (base->getSizeX() * base->getSizeY() * base->getSizeZ() * (IndexInt)base->getSizeT())
+ {}
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h
new file mode 100644
index 00000000000..98fb2719288
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h
@@ -0,0 +1,102 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Function and macros for defining compution kernels over grids
+ *
+ ******************************************************************************/
+
+#ifndef _KERNEL_H
+#define _KERNEL_H
+
+#if TBB==1
+# include <tbb/blocked_range3d.h>
+# include <tbb/blocked_range.h>
+# include <tbb/parallel_for.h>
+# include <tbb/parallel_reduce.h>
+#endif
+
+#if OPENMP==1
+# include <omp.h>
+#endif
+
+#include "general.h"
+
+namespace Manta {
+
+// fwd decl
+class GridBase;
+class Grid4dBase;
+class ParticleBase;
+
+
+// simple iteration
+#define FOR_IJK_BND(grid, bnd) \
+ for(int k=((grid).is3D() ? bnd : 0),__kmax=((grid).is3D() ? ((grid).getSizeZ()-bnd) : 1); k<__kmax; k++) \
+ for(int j=bnd; j<(grid).getSizeY()-bnd; j++) \
+ for(int i=bnd; i<(grid).getSizeX()-bnd; i++)
+
+#define FOR_IJK_REVERSE(grid) \
+ for(int k=(grid).getSizeZ()-1; k>=0; k--) \
+ for(int j=(grid).getSizeY()-1; j>=0; j--) \
+ for(int i=(grid).getSizeX()-1; i>=0; i--)
+
+#define FOR_IDX(grid) \
+ for(IndexInt idx=0, total=(grid).getSizeX()*(grid).getSizeY()*(grid).getSizeZ(); idx<total; idx++)
+
+#define FOR_IJK(grid) FOR_IJK_BND(grid, 0)
+
+#define FOR_PARTS(parts) \
+ for(IndexInt idx=0, total=(parts).size(); idx<total; idx++)
+
+// simple loop over 4d grids
+#define FOR_IJKT_BND(grid, bnd) \
+ for(int t=((grid).is4D() ? bnd : 0); t<((grid).is4D() ? ((grid).getSizeT()-bnd) : 1); ++t) \
+ for(int k=((grid).is3D() ? bnd : 0); k<((grid).is3D() ? ((grid).getSizeZ()-bnd) : 1); ++k) \
+ for(int j=bnd; j<(grid).getSizeY()-bnd; ++j) \
+ for(int i=bnd; i<(grid).getSizeX()-bnd; ++i)
+
+//! Basic data structure for kernel data, initialized based on kernel type (e.g. single, idx, etc).
+struct KernelBase {
+ int maxX, maxY, maxZ, minZ, maxT, minT;
+ int X, Y, Z, dimT;
+ IndexInt size;
+
+ KernelBase(IndexInt num);
+ KernelBase(const GridBase* base, int bnd);
+ KernelBase(const Grid4dBase* base, int bnd);
+
+ // specify in your derived classes:
+
+ // kernel operators
+ // ijk mode: void operator() (int i, int j, int k)
+ // idx mode: void operator() (IndexInt idx)
+
+ // reduce mode:
+ // void join(classname& other)
+ // void setup()
+};
+
+} // namespace
+
+// all kernels will automatically be added to the "Kernels" group in doxygen
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h.reg
new file mode 100644
index 00000000000..6457157c184
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h.reg
@@ -0,0 +1 @@
+#include "kernel.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h.reg.cpp
new file mode 100644
index 00000000000..195a25409a2
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/kernel.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "kernel.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_15()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.cpp
new file mode 100644
index 00000000000..180448c15db
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.cpp
@@ -0,0 +1,503 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Levelset
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "fastmarch.h"
+#include "kernel.h"
+#include "mcubes.h"
+#include "mesh.h"
+#include <stack>
+
+using namespace std;
+namespace Manta {
+
+//************************************************************************
+// Helper functions and kernels for marching
+
+static const int FlagInited = FastMarch<FmHeapEntryOut, +1>::FlagInited;
+
+// neighbor lookup vectors
+static const Vec3i neighbors[6] = { Vec3i(-1,0,0), Vec3i(1,0,0), Vec3i(0,-1,0), Vec3i(0,1,0), Vec3i(0,0,-1), Vec3i(0,0,1) };
+
+
+ struct InitFmIn : public KernelBase {
+ InitFmIn(const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& phi, bool ignoreWalls, int obstacleType) : KernelBase(&flags,1) ,flags(flags),fmFlags(fmFlags),phi(phi),ignoreWalls(ignoreWalls),obstacleType(obstacleType) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& phi, bool ignoreWalls, int obstacleType ) const {
+ const IndexInt idx = flags.index(i,j,k);
+ const Real v = phi[idx];
+ if (ignoreWalls) {
+ if (v>=0. && ((flags[idx] & obstacleType) == 0) )
+ fmFlags[idx] = FlagInited;
+ else
+ fmFlags[idx] = 0;
+ } else {
+ if (v>=0) fmFlags[idx] = FlagInited;
+ else fmFlags[idx] = 0;
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<int>& getArg1() {
+ return fmFlags; }
+ typedef Grid<int> type1;inline Grid<Real>& getArg2() {
+ return phi; }
+ typedef Grid<Real> type2;inline bool& getArg3() {
+ return ignoreWalls; }
+ typedef bool type3;inline int& getArg4() {
+ return obstacleType; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel InitFmIn ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,fmFlags,phi,ignoreWalls,obstacleType); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,fmFlags,phi,ignoreWalls,obstacleType); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; Grid<int>& fmFlags; Grid<Real>& phi; bool ignoreWalls; int obstacleType; }
+;
+
+
+ struct InitFmOut : public KernelBase {
+ InitFmOut(const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& phi, bool ignoreWalls, int obstacleType) : KernelBase(&flags,1) ,flags(flags),fmFlags(fmFlags),phi(phi),ignoreWalls(ignoreWalls),obstacleType(obstacleType) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<int>& fmFlags, Grid<Real>& phi, bool ignoreWalls, int obstacleType ) const {
+ const IndexInt idx = flags.index(i,j,k);
+ const Real v = phi[idx];
+ if (ignoreWalls) {
+ fmFlags[idx] = (v<0) ? FlagInited : 0;
+ if ((flags[idx] & obstacleType) != 0) {
+ fmFlags[idx] = 0;
+ phi[idx] = 0;
+ }
+ } else {
+ fmFlags[idx] = (v<0) ? FlagInited : 0;
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<int>& getArg1() {
+ return fmFlags; }
+ typedef Grid<int> type1;inline Grid<Real>& getArg2() {
+ return phi; }
+ typedef Grid<Real> type2;inline bool& getArg3() {
+ return ignoreWalls; }
+ typedef bool type3;inline int& getArg4() {
+ return obstacleType; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel InitFmOut ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,fmFlags,phi,ignoreWalls,obstacleType); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,fmFlags,phi,ignoreWalls,obstacleType); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; Grid<int>& fmFlags; Grid<Real>& phi; bool ignoreWalls; int obstacleType; }
+;
+
+
+ struct SetUninitialized : public KernelBase {
+ SetUninitialized(const Grid<int>& flags, Grid<int>& fmFlags, Grid<Real>& phi, const Real val, int ignoreWalls, int obstacleType) : KernelBase(&flags,1) ,flags(flags),fmFlags(fmFlags),phi(phi),val(val),ignoreWalls(ignoreWalls),obstacleType(obstacleType) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<int>& flags, Grid<int>& fmFlags, Grid<Real>& phi, const Real val, int ignoreWalls, int obstacleType ) const {
+ if(ignoreWalls) {
+ if ( (fmFlags(i,j,k) != FlagInited) && ((flags(i,j,k) & obstacleType) == 0) ) {
+ phi(i,j,k) = val; }
+ } else {
+ if ( (fmFlags(i,j,k) != FlagInited) ) phi(i,j,k) = val;
+ }
+} inline const Grid<int>& getArg0() {
+ return flags; }
+ typedef Grid<int> type0;inline Grid<int>& getArg1() {
+ return fmFlags; }
+ typedef Grid<int> type1;inline Grid<Real>& getArg2() {
+ return phi; }
+ typedef Grid<Real> type2;inline const Real& getArg3() {
+ return val; }
+ typedef Real type3;inline int& getArg4() {
+ return ignoreWalls; }
+ typedef int type4;inline int& getArg5() {
+ return obstacleType; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel SetUninitialized ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,fmFlags,phi,val,ignoreWalls,obstacleType); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,fmFlags,phi,val,ignoreWalls,obstacleType); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const Grid<int>& flags; Grid<int>& fmFlags; Grid<Real>& phi; const Real val; int ignoreWalls; int obstacleType; }
+;
+
+template<bool inward>
+inline bool isAtInterface(const Grid<int>& fmFlags, Grid<Real>& phi, const Vec3i& p) {
+ // check for interface
+ int max = phi.is3D() ? 6 : 4;
+ for (int nb=0; nb<max; nb++) {
+ const Vec3i pn(p + neighbors[nb]);
+ if (!fmFlags.isInBounds(pn)) continue;
+
+ if (fmFlags(pn) != FlagInited) continue;
+ if (( inward && phi(pn) >= 0.) ||
+ (!inward && phi(pn) < 0.)) return true;
+ }
+ return false;
+}
+
+
+//************************************************************************
+// Levelset class def
+
+LevelsetGrid::LevelsetGrid(FluidSolver* parent, bool show)
+ : Grid<Real>(parent, show)
+{
+ mType = (GridType)(TypeLevelset | TypeReal);
+}
+
+LevelsetGrid::LevelsetGrid(FluidSolver* parent, Real* data, bool show)
+ : Grid<Real>(parent, data, show)
+{
+ mType = (GridType)(TypeLevelset | TypeReal);
+}
+
+Real LevelsetGrid::invalidTimeValue() {
+ return FastMarch<FmHeapEntryOut, 1>::InvalidTime();
+}
+
+//! Kernel: perform levelset union
+ struct KnJoin : public KernelBase {
+ KnJoin(Grid<Real>& a, const Grid<Real>& b) : KernelBase(&a,0) ,a(a),b(b) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& a, const Grid<Real>& b ) const {
+ a[idx] = min(a[idx], b[idx]);
+} inline Grid<Real>& getArg0() {
+ return a; }
+ typedef Grid<Real> type0;inline const Grid<Real>& getArg1() {
+ return b; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel KnJoin ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, a,b); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<Real>& a; const Grid<Real>& b; }
+;
+void LevelsetGrid::join(const LevelsetGrid& o) { KnJoin(*this, o); }
+
+//! subtract b, note does not preserve SDF!
+ struct KnSubtract : public KernelBase {
+ KnSubtract(Grid<Real>& a, const Grid<Real>& b) : KernelBase(&a,0) ,a(a),b(b) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& a, const Grid<Real>& b ) const {
+ if(b[idx]<0.) a[idx] = b[idx] * -1.;
+} inline Grid<Real>& getArg0() {
+ return a; }
+ typedef Grid<Real> type0;inline const Grid<Real>& getArg1() {
+ return b; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel KnSubtract ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, a,b); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<Real>& a; const Grid<Real>& b; }
+;
+void LevelsetGrid::subtract(const LevelsetGrid& o) { KnSubtract(*this, o); }
+
+//! re-init levelset and extrapolate velocities (in & out)
+// note - uses flags to identify border (could also be done based on ls values)
+static void doReinitMarch( Grid<Real>& phi,
+ const FlagGrid& flags, Real maxTime, MACGrid* velTransport,
+ bool ignoreWalls, bool correctOuterLayer, int obstacleType )
+{
+ const int dim = (phi.is3D() ? 3 : 2);
+ Grid<int> fmFlags( phi.getParent() );
+
+ FastMarch<FmHeapEntryIn, -1> marchIn (flags, fmFlags, phi, maxTime, NULL );
+
+ // march inside
+ InitFmIn (flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FOR_IJK_BND(flags, 1) {
+ if (fmFlags(i,j,k) == FlagInited) continue;
+ if (ignoreWalls && ((flags(i,j,k) & obstacleType) != 0)) continue;
+ const Vec3i p(i,j,k);
+
+ if(isAtInterface<true>(fmFlags, phi, p)) {
+ // set value
+ fmFlags(p) = FlagInited;
+
+ // add neighbors that are not at the interface
+ for (int nb=0; nb<2*dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+ if (ignoreWalls && ((flags.get(pn) & obstacleType) != 0)) continue;
+
+ // check neighbors of neighbor
+ if (phi(pn) < 0. && !isAtInterface<true>(fmFlags, phi, pn)) {
+ marchIn.addToList(pn, p);
+ }
+ }
+ }
+ }
+ marchIn.performMarching();
+ // done with inwards marching
+
+ // now march out...
+
+ // set un initialized regions
+ SetUninitialized (flags, fmFlags, phi, -maxTime - 1., ignoreWalls, obstacleType);
+
+ InitFmOut (flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FastMarch<FmHeapEntryOut, +1> marchOut(flags, fmFlags, phi, maxTime, velTransport );
+
+ // by default, correctOuterLayer is on
+ if (correctOuterLayer) {
+ // normal version, inwards march is done, now add all outside values (0..2] to list
+ // note, this might move the interface a bit! but keeps a nice signed distance field...
+ FOR_IJK_BND(flags, 1) {
+ if (ignoreWalls && ((flags(i,j,k) & obstacleType) != 0)) continue;
+ const Vec3i p(i,j,k);
+
+ // check nbs
+ for (int nb=0; nb<2*dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+
+ if (fmFlags(pn) != FlagInited) continue;
+ if (ignoreWalls && ((flags.get(pn) & obstacleType)) != 0) continue;
+
+ const Real nbPhi = phi(pn);
+
+ // only add nodes near interface, not e.g. outer boundary vs. invalid region
+ if (nbPhi < 0 && nbPhi >= -2)
+ marchOut.addToList(p, pn);
+ }
+ }
+ } else {
+ // alternative version, keep interface, do not distort outer cells
+ // add all ouside values, but not those at the IF layer
+ FOR_IJK_BND(flags, 1) {
+ if (ignoreWalls && ((flags(i,j,k) & obstacleType) != 0)) continue;
+
+ // only look at ouside values
+ const Vec3i p(i,j,k);
+ if (phi(p) < 0) continue;
+
+ if (isAtInterface<false>(fmFlags, phi, p)) {
+ // now add all non, interface neighbors
+ fmFlags(p) = FlagInited;
+
+ // add neighbors that are not at the interface
+ for (int nb=0; nb<2*dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+ if (ignoreWalls && ((flags.get(pn) & obstacleType) != 0)) continue;
+
+ // check neighbors of neighbor
+ if (phi(pn) > 0. && !isAtInterface<false>(fmFlags, phi, pn)) {
+ marchOut.addToList(pn, p);
+ }
+ }
+ }
+ }
+ }
+ marchOut.performMarching();
+
+ // set un initialized regions
+ SetUninitialized (flags, fmFlags, phi, +maxTime + 1., ignoreWalls, obstacleType);
+}
+
+//! call for levelset grids & external real grids
+
+void LevelsetGrid::reinitMarching( const FlagGrid& flags, Real maxTime, MACGrid* velTransport,
+ bool ignoreWalls, bool correctOuterLayer, int obstacleType )
+{
+ doReinitMarch( *this, flags, maxTime, velTransport, ignoreWalls, correctOuterLayer, obstacleType );
+}
+
+
+void LevelsetGrid::initFromFlags(const FlagGrid& flags, bool ignoreWalls) {
+ FOR_IDX(*this) {
+ if (flags.isFluid(idx) || (ignoreWalls && flags.isObstacle(idx)))
+ mData[idx] = -0.5;
+ else
+ mData[idx] = 0.5;
+ }
+}
+
+void LevelsetGrid::fillHoles(int maxsize) {
+ Real cur, i1, i2, j1, j2, k1, k2;
+ Vec3i c, cTmp;
+ std::stack<Vec3i> undo;
+ std::stack<Vec3i> todo;
+
+ FOR_IJK_BND(*this, 1) {
+
+ cur = mData[index(i,j,k)];
+ i1 = mData[index(i-1,j,k)];
+ i2 = mData[index(i+1,j,k)];
+ j1 = mData[index(i,j-1,k)];
+ j2 = mData[index(i,j+1,k)];
+ k1 = mData[index(i,j,k-1)];
+ k2 = mData[index(i,j,k+1)];
+
+ /* Skip cells inside and cells outside with no inside neighbours early */
+ if (cur < 0.) continue;
+ if (cur > 0. && i1 > 0. && i2 > 0. && j1 > 0. && j2 > 0. && k1 > 0. && k2 > 0.) continue;
+
+ /* Current cell is outside and has inside neighbour(s) */
+ undo.push(Vec3i(i,j,k));
+ todo.push(Vec3i(i,j,k));
+
+ /* Cell at c is positive (outside) and has at least one negative (inside) neighbour cell */
+ c = Vec3i(i,j,k);
+
+ /* Enforce negative cell - if search depth gets exceeded this will be reverted to +0.5 */
+ mData[index(c.x, c.y, c.z)] = -0.5;
+
+ while(!todo.empty()) {
+
+ todo.pop();
+
+ /* Add neighbouring positive (inside) cells to stacks */
+ if (c.x > 0 && mData[index(c.x-1, c.y, c.z)] > 0.) { cTmp = Vec3i(c.x-1, c.y, c.z); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5;}
+ if (c.y > 0 && mData[index(c.x, c.y-1, c.z)] > 0.) { cTmp = Vec3i(c.x, c.y-1, c.z); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5; }
+ if (c.z > 0 && mData[index(c.x, c.y, c.z-1)] > 0.) { cTmp = Vec3i(c.x, c.y, c.z-1); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5; }
+ if (c.x < (*this).getSizeX()-1 && mData[index(c.x+1, c.y, c.z)] > 0.) { cTmp = Vec3i(c.x+1, c.y, c.z); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5; }
+ if (c.y < (*this).getSizeY()-1 && mData[index(c.x, c.y+1, c.z)] > 0.) { cTmp = Vec3i(c.x, c.y+1, c.z); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5; }
+ if (c.z < (*this).getSizeZ()-1 && mData[index(c.x, c.y, c.z+1)] > 0.) { cTmp = Vec3i(c.x, c.y, c.z+1); undo.push(cTmp); todo.push(cTmp); mData[index(cTmp)] = -0.5; }
+
+ /* Restore original value in cells if undo needed ie once cell undo count exceeds given limit */
+ if (undo.size() > maxsize) {
+ /* Clear todo stack */
+ while (!todo.empty()) {
+ todo.pop();
+ }
+ /* Clear undo stack and revert value */
+ while (!undo.empty()) {
+ c = undo.top();
+ undo.pop();
+ mData[index(c.x, c.y, c.z)] = 0.5;
+ }
+ break;
+ }
+
+ /* Ensure that undo stack is cleared at the end if no more items in todo stack left */
+ if (todo.empty()) {
+ while (!undo.empty()) {
+ undo.pop();
+ }
+ }
+ /* Pop value for next while iteration */
+ else {
+ c = todo.top();
+ }
+ }
+ }
+}
+
+//! run marching cubes to create a mesh for the 0-levelset
+void LevelsetGrid::createMesh(Mesh& mesh) {
+ assertMsg(is3D(), "Only 3D grids supported so far");
+
+ mesh.clear();
+
+ const Real invalidTime = invalidTimeValue();
+ const Real isoValue = 1e-4;
+
+ // create some temp grids
+ Grid<int> edgeVX(mParent);
+ Grid<int> edgeVY(mParent);
+ Grid<int> edgeVZ(mParent);
+
+ for(int i=0; i<mSize.x-1; i++)
+ for(int j=0; j<mSize.y-1; j++)
+ for(int k=0; k<mSize.z-1; k++) {
+ Real value[8] = { get(i,j,k), get(i+1,j,k), get(i+1,j+1,k), get(i,j+1,k),
+ get(i,j,k+1), get(i+1,j,k+1), get(i+1,j+1,k+1), get(i,j+1,k+1) };
+
+ // build lookup index, check for invalid times
+ bool skip = false;
+ int cubeIdx = 0;
+ for (int l=0;l<8;l++) {
+ value[l] *= -1;
+ if (-value[l] <= invalidTime)
+ skip = true;
+ if (value[l] < isoValue)
+ cubeIdx |= 1<<l;
+ }
+ if (skip || (mcEdgeTable[cubeIdx] == 0)) continue;
+
+ // where to look up if this point already exists
+ int triIndices[12];
+ int *eVert[12] = { &edgeVX(i,j,k), &edgeVY(i+1,j,k), &edgeVX(i,j+1,k), &edgeVY(i,j,k),
+ &edgeVX(i,j,k+1), &edgeVY(i+1,j,k+1), &edgeVX(i,j+1,k+1), &edgeVY(i,j,k+1),
+ &edgeVZ(i,j,k), &edgeVZ(i+1,j,k), &edgeVZ(i+1,j+1,k), &edgeVZ(i,j+1,k) };
+
+ const Vec3 pos[9] = { Vec3(i,j,k), Vec3(i+1,j,k), Vec3(i+1,j+1,k), Vec3(i,j+1,k),
+ Vec3(i,j,k+1), Vec3(i+1,j,k+1), Vec3(i+1,j+1,k+1), Vec3(i,j+1,k+1) };
+
+ for (int e=0; e<12; e++) {
+ if (mcEdgeTable[cubeIdx] & (1<<e)) {
+ // vertex already calculated ?
+ if (*eVert[e] == 0) {
+ // interpolate edge
+ const int e1 = mcEdges[e*2 ];
+ const int e2 = mcEdges[e*2+1];
+ const Vec3 p1 = pos[ e1 ]; // scalar field pos 1
+ const Vec3 p2 = pos[ e2 ]; // scalar field pos 2
+ const float valp1 = value[ e1 ]; // scalar field val 1
+ const float valp2 = value[ e2 ]; // scalar field val 2
+ const float mu = (isoValue - valp1) / (valp2 - valp1);
+
+ // init isolevel vertex
+ Node vertex;
+ vertex.pos = p1 + (p2-p1)*mu + Vec3(Real(0.5));
+ vertex.normal = getNormalized(
+ getGradient( *this, i+cubieOffsetX[e1], j+cubieOffsetY[e1], k+cubieOffsetZ[e1]) * (1.0-mu) +
+ getGradient( *this, i+cubieOffsetX[e2], j+cubieOffsetY[e2], k+cubieOffsetZ[e2]) * ( mu)) ;
+
+ triIndices[e] = mesh.addNode(vertex) + 1;
+
+ // store vertex
+ *eVert[e] = triIndices[e];
+ } else {
+ // retrieve from vert array
+ triIndices[e] = *eVert[e];
+ }
+ }
+ }
+
+ // Create the triangles...
+ for(int e=0; mcTriTable[cubeIdx][e]!=-1; e+=3) {
+ mesh.addTri( Triangle( triIndices[ mcTriTable[cubeIdx][e+0]] - 1,
+ triIndices[ mcTriTable[cubeIdx][e+1]] - 1,
+ triIndices[ mcTriTable[cubeIdx][e+2]] - 1));
+ }
+ }
+
+ //mesh.rebuildCorners();
+ //mesh.rebuildLookup();
+
+ // Update mdata fields
+ mesh.updateDataFields();
+}
+
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h
new file mode 100644
index 00000000000..8f168c36a79
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h
@@ -0,0 +1,118 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Levelset
+ *
+ ******************************************************************************/
+
+#ifndef _LEVELSET_H_
+#define _LEVELSET_H_
+
+#include "grid.h"
+
+namespace Manta {
+class Mesh;
+
+//! Special function for levelsets
+class LevelsetGrid : public Grid<Real> {public:
+ LevelsetGrid(FluidSolver* parent, bool show = true); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "LevelsetGrid::LevelsetGrid" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); bool show = _args.getOpt<bool >("show",1,true,&_lock); obj = new LevelsetGrid(parent,show); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"LevelsetGrid::LevelsetGrid" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::LevelsetGrid",e.what()); return -1; }
+ }
+
+
+ LevelsetGrid(FluidSolver* parent, Real* data, bool show = true);
+
+ //! reconstruct the levelset using fast marching
+
+
+void reinitMarching(const FlagGrid& flags, Real maxTime=4.0, MACGrid* velTransport=NULL, bool ignoreWalls=false, bool correctOuterLayer=true, int obstacleType = FlagGrid::TypeObstacle ); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::reinitMarching" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Real maxTime = _args.getOpt<Real >("maxTime",1,4.0,&_lock); MACGrid* velTransport = _args.getPtrOpt<MACGrid >("velTransport",2,NULL,&_lock); bool ignoreWalls = _args.getOpt<bool >("ignoreWalls",3,false,&_lock); bool correctOuterLayer = _args.getOpt<bool >("correctOuterLayer",4,true,&_lock); int obstacleType = _args.getOpt<int >("obstacleType",5,FlagGrid::TypeObstacle ,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->reinitMarching(flags,maxTime,velTransport,ignoreWalls,correctOuterLayer,obstacleType); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::reinitMarching" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::reinitMarching",e.what()); return 0; }
+ }
+
+
+ //! create a triangle mesh from the levelset isosurface
+ void createMesh(Mesh& mesh); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::createMesh" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->createMesh(mesh); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::createMesh" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::createMesh",e.what()); return 0; }
+ }
+
+
+ //! union with another levelset
+ void join(const LevelsetGrid& o); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::join" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const LevelsetGrid& o = *_args.getPtr<LevelsetGrid >("o",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->join(o); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::join" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::join",e.what()); return 0; }
+ }
+
+ void subtract(const LevelsetGrid& o); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::subtract" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const LevelsetGrid& o = *_args.getPtr<LevelsetGrid >("o",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->subtract(o); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::subtract" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::subtract",e.what()); return 0; }
+ }
+
+
+ //! initialize levelset from flags (+/- 0.5 heaviside)
+ void initFromFlags(const FlagGrid& flags, bool ignoreWalls=false); static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::initFromFlags" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); bool ignoreWalls = _args.getOpt<bool >("ignoreWalls",1,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->initFromFlags(flags,ignoreWalls); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::initFromFlags" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::initFromFlags",e.what()); return 0; }
+ }
+
+ //! fill holes (pos cells enclosed by neg ones) up to given size with -0.5 (ie not preserving sdf)
+ void fillHoles(int maxsize=10); static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::fillHoles" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int maxsize = _args.getOpt<int >("maxsize",0,10,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->fillHoles(maxsize); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::fillHoles" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("LevelsetGrid::fillHoles",e.what()); return 0; }
+ }
+
+ static Real invalidTimeValue(); public: PbArgs _args; }
+#define _C_LevelsetGrid
+;
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h.reg
new file mode 100644
index 00000000000..8a0c337db06
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h.reg
@@ -0,0 +1,11 @@
+#include "levelset.h"
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","LevelsetGrid","Grid<$BT$>"); template<> const char* Namify<LevelsetGrid >::S = "LevelsetGrid";
+>LevelsetGrid^
+@LevelsetGrid^^Grid^Real
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","LevelsetGrid",LevelsetGrid::_W_0);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","reinitMarching",LevelsetGrid::_W_1);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","createMesh",LevelsetGrid::_W_2);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","join",LevelsetGrid::_W_3);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","subtract",LevelsetGrid::_W_4);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","initFromFlags",LevelsetGrid::_W_5);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","fillHoles",LevelsetGrid::_W_6);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h.reg.cpp
new file mode 100644
index 00000000000..15642f878e6
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/levelset.h.reg.cpp
@@ -0,0 +1,36 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "levelset.h"
+namespace Manta {
+#ifdef _C_LevelsetGrid
+ static const Pb::Register _R_11 ("LevelsetGrid","LevelsetGrid","Grid<Real>"); template<> const char* Namify<LevelsetGrid >::S = "LevelsetGrid";
+ static const Pb::Register _R_12 ("LevelsetGrid","LevelsetGrid",LevelsetGrid::_W_0);
+ static const Pb::Register _R_13 ("LevelsetGrid","reinitMarching",LevelsetGrid::_W_1);
+ static const Pb::Register _R_14 ("LevelsetGrid","createMesh",LevelsetGrid::_W_2);
+ static const Pb::Register _R_15 ("LevelsetGrid","join",LevelsetGrid::_W_3);
+ static const Pb::Register _R_16 ("LevelsetGrid","subtract",LevelsetGrid::_W_4);
+ static const Pb::Register _R_17 ("LevelsetGrid","initFromFlags",LevelsetGrid::_W_5);
+ static const Pb::Register _R_18 ("LevelsetGrid","fillHoles",LevelsetGrid::_W_6);
+#endif
+extern "C" {
+void PbRegister_file_11()
+{
+ KEEP_UNUSED(_R_11);
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.cpp
new file mode 100644
index 00000000000..bf99a7b027f
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.cpp
@@ -0,0 +1,1781 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Meshes
+ *
+ * note: this is only a temporary solution, details are bound to change
+ * long term goal is integration with Split&Merge code by Wojtan et al.
+ *
+ ******************************************************************************/
+
+#include "mesh.h"
+#include "integrator.h"
+#include "mantaio.h"
+#include "kernel.h"
+#include "shapes.h"
+#include "noisefield.h"
+//#include "grid.h"
+#include <stack>
+#include <cstring>
+
+using namespace std;
+namespace Manta {
+
+Mesh::Mesh(FluidSolver* parent) : PbClass(parent) {
+}
+
+Mesh::~Mesh()
+{
+ for(IndexInt i=0; i<(IndexInt)mMeshData.size(); ++i)
+ mMeshData[i]->setMesh(NULL);
+
+ if(mFreeMdata) {
+ for(IndexInt i=0; i<(IndexInt)mMeshData.size(); ++i)
+ delete mMeshData[i];
+ }
+}
+
+Mesh* Mesh::clone() {
+ Mesh* nm = new Mesh(mParent);
+ *nm = *this;
+ nm->setName(getName());
+ return nm;
+}
+
+void Mesh::deregister(MeshDataBase* mdata) {
+ bool done = false;
+ // remove pointer from mesh data list
+ for(IndexInt i=0; i<(IndexInt)mMeshData.size(); ++i) {
+ if(mMeshData[i] == mdata) {
+ if(i<(IndexInt)mMeshData.size()-1)
+ mMeshData[i] = mMeshData[mMeshData.size()-1];
+ mMeshData.pop_back();
+ done = true;
+ }
+ }
+ if(!done)
+ errMsg("Invalid pointer given, not registered!");
+}
+
+// create and attach a new mdata field to this mesh
+PbClass* Mesh::create(PbType t, PbTypeVec T, const string& name) {
+# if NOPYTHON!=1
+ _args.add("nocheck",true);
+ if (t.str() == "")
+ errMsg("Specify mesh data type to create");
+ //debMsg( "Mdata creating '"<< t.str <<" with size "<< this->getSizeSlow(), 5 );
+
+ PbClass* pyObj = PbClass::createPyObject(t.str() + T.str(), name, _args, this->getParent() );
+
+ MeshDataBase* mdata = dynamic_cast<MeshDataBase*>(pyObj);
+ if(!mdata) {
+ errMsg("Unable to get mesh data pointer from newly created object. Only create MeshData type with a Mesh.creat() call, eg, MdataReal, MdataVec3 etc.");
+ delete pyObj;
+ return NULL;
+ } else {
+ this->registerMdata(mdata);
+ }
+
+ // directly init size of new mdata field:
+ mdata->resize( this->getSizeSlow() );
+# else
+ PbClass* pyObj = NULL;
+# endif
+ return pyObj;
+}
+
+void Mesh::registerMdata(MeshDataBase* mdata) {
+ mdata->setMesh(this);
+ mMeshData.push_back(mdata);
+
+ if( mdata->getType() == MeshDataBase::TypeReal ) {
+ MeshDataImpl<Real>* pd = dynamic_cast< MeshDataImpl<Real>* >(mdata);
+ if(!pd) errMsg("Invalid mdata object posing as real!");
+ this->registerMdataReal(pd);
+ }
+ else if( mdata->getType() == MeshDataBase::TypeInt ) {
+ MeshDataImpl<int>* pd = dynamic_cast< MeshDataImpl<int>* >(mdata);
+ if(!pd) errMsg("Invalid mdata object posing as int!");
+ this->registerMdataInt(pd);
+ }
+ else if( mdata->getType() == MeshDataBase::TypeVec3 ) {
+ MeshDataImpl<Vec3>* pd = dynamic_cast< MeshDataImpl<Vec3>* >(mdata);
+ if(!pd) errMsg("Invalid mdata object posing as vec3!");
+ this->registerMdataVec3(pd);
+ }
+}
+void Mesh::registerMdataReal(MeshDataImpl<Real>* pd) { mMdataReal.push_back(pd); }
+void Mesh::registerMdataVec3(MeshDataImpl<Vec3>* pd) { mMdataVec3.push_back(pd); }
+void Mesh::registerMdataInt (MeshDataImpl<int >* pd) { mMdataInt .push_back(pd); }
+
+void Mesh::addAllMdata() {
+ for(IndexInt i=0; i<(IndexInt)mMeshData.size(); ++i) {
+ mMeshData[i]->addEntry();
+ }
+}
+
+Real Mesh::computeCenterOfMass(Vec3& cm) const {
+
+ // use double precision for summation, otherwise too much error accumulation
+ double vol=0;
+ Vector3D<double> cmd(0.0);
+ for(size_t tri=0; tri < mTris.size(); tri++) {
+ Vector3D<double> p1(toVec3d(getNode(tri,0)));
+ Vector3D<double> p2(toVec3d(getNode(tri,1)));
+ Vector3D<double> p3(toVec3d(getNode(tri,2)));
+
+ double cvol = dot(cross(p1,p2),p3) / 6.0;
+ cmd += (p1+p2+p3) * (cvol/4.0);
+ vol += cvol;
+ }
+ if (vol != 0.0) cmd /= vol;
+
+ cm = toVec3(cmd);
+ return (Real) vol;
+}
+
+void Mesh::clear() {
+ mNodes.clear();
+ mTris.clear();
+ mCorners.clear();
+ m1RingLookup.clear();
+ for(size_t i=0; i<mNodeChannels.size(); i++)
+ mNodeChannels[i]->resize(0);
+ for(size_t i=0; i<mTriChannels.size(); i++)
+ mTriChannels[i]->resize(0);
+
+ // clear mdata fields as well
+ for (size_t i=0; i<mMdataReal.size(); i++)
+ mMdataReal[i]->resize(0);
+ for (size_t i=0; i<mMdataVec3.size(); i++)
+ mMdataVec3[i]->resize(0);
+ for (size_t i=0; i<mMdataInt.size(); i++)
+ mMdataInt[i]->resize(0);
+}
+
+Mesh& Mesh::operator=(const Mesh& o) {
+ // wipe current data
+ clear();
+ if (mNodeChannels.size() != o.mNodeChannels.size() ||
+ mTriChannels.size() != o.mTriChannels.size())
+ errMsg("can't copy mesh, channels not identical");
+ mNodeChannels.clear();
+ mTriChannels.clear();
+
+ // copy corner, nodes, tris
+ mCorners = o.mCorners;
+ mNodes = o.mNodes;
+ mTris = o.mTris;
+ m1RingLookup = o.m1RingLookup;
+
+ // copy channels
+ for(size_t i=0; i<mNodeChannels.size(); i++)
+ mNodeChannels[i] = o.mNodeChannels[i];
+ for(size_t i=0; i<o.mTriChannels.size(); i++)
+ mTriChannels[i] = o.mTriChannels[i];
+
+ return *this;
+}
+
+void Mesh::load(string name, bool append) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".gz") // assume bobj gz
+ readBobjFile(name, this, append);
+ else if (ext == ".obj")
+ readObjFile(name, this, append);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+
+
+ // dont always rebuild...
+ //rebuildCorners();
+ //rebuildLookup();
+}
+
+void Mesh::save(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".obj")
+ writeObjFile(name, this);
+ else if (ext == ".gz")
+ writeBobjFile(name, this);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+void Mesh::fromShape(Shape& shape, bool append) {
+ if (!append)
+ clear();
+ shape.generateMesh(this);
+}
+
+void Mesh::resizeTris(int numTris) {
+ mTris .resize(numTris );
+ rebuildChannels();
+}
+void Mesh::resizeNodes(int numNodes) {
+ mNodes.resize(numNodes);
+ rebuildChannels();
+}
+
+//! do a quick check whether a rebuild is necessary, and if yes do rebuild
+void Mesh::rebuildQuickCheck() {
+ if(mCorners.size() != 3*mTris.size())
+ rebuildCorners();
+ if(m1RingLookup.size() != mNodes.size())
+ rebuildLookup();
+}
+
+void Mesh::rebuildCorners(int from, int to) {
+ mCorners.resize(3*mTris.size());
+ if (to < 0) to = mTris.size();
+
+ // fill in basic info
+ for (int tri=from; tri<to; tri++) {
+ for (int c=0; c<3; c++) {
+ const int idx = tri*3+c;
+ mCorners[idx].tri = tri;
+ mCorners[idx].node = mTris[tri].c[c];
+ mCorners[idx].next = 3*tri+((c+1)%3);
+ mCorners[idx].prev = 3*tri+((c+2)%3);
+ mCorners[idx].opposite = -1;
+ }
+ }
+
+ // set opposite info
+ int maxc = to*3;
+ for (int c=from*3; c<maxc; c++) {
+ int next = mCorners[mCorners[c].next].node;
+ int prev = mCorners[mCorners[c].prev].node;
+
+ // find corner with same next/prev nodes
+ for (int c2=c+1; c2<maxc; c2++) {
+ int next2 = mCorners[mCorners[c2].next].node;
+ if (next2 != next && next2 != prev) continue;
+ int prev2 = mCorners[mCorners[c2].prev].node;
+ if (prev2 != next && prev2 != prev) continue;
+
+ // found
+ mCorners[c].opposite = c2;
+ mCorners[c2].opposite = c;
+ break;
+ }
+ if (mCorners[c].opposite < 0) {
+ // didn't find opposite
+ errMsg("can't rebuild corners, index without an opposite");
+ }
+ }
+
+ rebuildChannels();
+}
+
+void Mesh::rebuildLookup(int from, int to) {
+ if (from==0 && to<0) m1RingLookup.clear();
+ m1RingLookup.resize(mNodes.size());
+ if (to<0) to = mTris.size();
+ from *=3; to *= 3;
+ for (int i=from; i< to; i++) {
+ const int node = mCorners[i].node;
+ m1RingLookup[node].nodes.insert(mCorners[mCorners[i].next].node);
+ m1RingLookup[node].nodes.insert(mCorners[mCorners[i].prev].node);
+ m1RingLookup[node].tris.insert(mCorners[i].tri);
+ }
+}
+
+void Mesh::rebuildChannels() {
+ for(size_t i=0; i<mTriChannels.size(); i++)
+ mTriChannels[i]->resize(mTris.size());
+ for(size_t i=0; i<mNodeChannels.size(); i++)
+ mNodeChannels[i]->resize(mNodes.size());
+}
+
+
+ struct _KnAdvectMeshInGrid : public KernelBase {
+ _KnAdvectMeshInGrid(const KernelBase& base, vector<Node>& nodes, const FlagGrid& flags, const MACGrid& vel, const Real dt ,vector<Vec3> & u) : KernelBase(base) ,nodes(nodes),flags(flags),vel(vel),dt(dt) ,u(u){
+}
+ inline void op(IndexInt idx, vector<Node>& nodes, const FlagGrid& flags, const MACGrid& vel, const Real dt ,vector<Vec3> & u) const {
+ if (nodes[idx].flags & Mesh::NfFixed)
+ u[idx] = 0.0;
+ else if (!flags.isInBounds(nodes[idx].pos,1))
+ u[idx] = 0.0;
+ else
+ u[idx] = vel.getInterpolated(nodes[idx].pos) * dt;
+} void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, nodes,flags,vel,dt,u); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ vector<Node>& nodes; const FlagGrid& flags; const MACGrid& vel; const Real dt; vector<Vec3> & u; }
+; struct KnAdvectMeshInGrid : public KernelBase {
+ KnAdvectMeshInGrid(vector<Node>& nodes, const FlagGrid& flags, const MACGrid& vel, const Real dt) : KernelBase(nodes.size()) , _inner(KernelBase(nodes.size()),nodes,flags,vel,dt,u) ,nodes(nodes),flags(flags),vel(vel),dt(dt) ,u((size)) {
+ runMessage(); run(); }
+ void run() {
+ _inner.run(); }
+ inline operator vector<Vec3> () {
+ return u; }
+ inline vector<Vec3> & getRet() {
+ return u; }
+ inline vector<Node>& getArg0() {
+ return nodes; }
+ typedef vector<Node> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline const Real& getArg3() {
+ return dt; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel KnAdvectMeshInGrid ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; _KnAdvectMeshInGrid _inner; vector<Node>& nodes; const FlagGrid& flags; const MACGrid& vel; const Real dt; vector<Vec3> u; }
+;
+
+// advection plugin
+void Mesh::advectInGrid(FlagGrid& flags, MACGrid& vel, int integrationMode) {
+ KnAdvectMeshInGrid kernel(mNodes, flags, vel, getParent()->getDt());
+ integratePointSet( kernel, integrationMode);
+}
+
+void Mesh::scale(Vec3 s) {
+ for (size_t i=0; i<mNodes.size(); i++)
+ mNodes[i].pos *= s;
+}
+
+void Mesh::offset(Vec3 o) {
+ for (size_t i=0; i<mNodes.size(); i++)
+ mNodes[i].pos += o;
+}
+
+void Mesh::rotate(Vec3 thetas) {
+ // rotation thetas are in radians (e.g. pi is equal to 180 degrees)
+ auto rotate = [&](Real theta, unsigned int first_axis, unsigned int second_axis)
+ {
+ if (theta == 0.0f)
+ return;
+
+ Real sin_t = sin(theta);
+ Real cos_t = cos(theta);
+
+ Real sin_sign = first_axis == 0u && second_axis == 2u ? -1.0f : 1.0f;
+ sin_t *= sin_sign;
+
+ size_t length = mNodes.size();
+ for (size_t n = 0; n < length; ++n)
+ {
+ Vec3& node = mNodes[n].pos;
+ Real first_axis_val = node[first_axis];
+ Real second_axis_val = node[second_axis];
+ node[first_axis] = first_axis_val * cos_t - second_axis_val * sin_t;
+ node[second_axis] = second_axis_val * cos_t + first_axis_val * sin_t;
+ }
+ };
+
+ // rotate x
+ rotate(thetas[0], 1u, 2u);
+ // rotate y
+ rotate(thetas[1], 0u, 2u);
+ // rotate z
+ rotate(thetas[2], 0u, 1u);
+}
+
+void Mesh::computeVelocity(Mesh& oldMesh, MACGrid& vel) {
+ // Early return if sizes do not match
+ if(oldMesh.mNodes.size() != mNodes.size())
+ return;
+
+ // temp grid
+ Grid<Vec3> veloMeanCounter(getParent());
+ veloMeanCounter.setConst(0.0f);
+
+ bool bIs2D = getParent()->is2D();
+
+ // calculate velocities from previous to current frame (per vertex)
+ for (size_t i=0; i<mNodes.size(); ++i)
+ {
+ Vec3 velo = mNodes[i].pos - oldMesh.mNodes[i].pos;
+ if(bIs2D && (mNodes[i].pos.z > -0.5f && mNodes[i].pos.z < 0.5f))
+ {
+ vel.setInterpolated(mNodes[i].pos, velo, &(veloMeanCounter[0]));
+ }
+ }
+
+ // discretize the vertex velocities by averaging them on the grid
+ vel.safeDivide(veloMeanCounter);
+}
+
+void Mesh::removeTri(int tri) {
+ // delete triangles by overwriting them with elements from the end of the array.
+ if(tri!=(int)mTris.size()-1) {
+ // if this is the last element, and it is marked for deletion,
+ // don't waste cycles transfering data to itself,
+ // and DEFINITELY don't transfer .opposite data to other, untainted triangles.
+
+ // old corners hold indices on the end of the corners array
+ // new corners holds indices in the new spot in the middle of the array
+ Corner* oldcorners[3];
+ Corner* newcorners[3];
+ int oldtri = mTris.size()-1;
+ for (int c=0; c<3; c++) {
+ oldcorners[c] = &corners(oldtri,c);
+ newcorners[c] = &corners(tri, c);
+ }
+
+ // move the position of the triangle
+ mTris[tri] = mTris[oldtri];
+
+ // 1) update c.node, c.opposite (c.next and c.prev should be fine as they are)
+ for (int c=0; c<3; c++) {
+ newcorners[c]->node = mTris[tri].c[c];
+ newcorners[c]->opposite = oldcorners[c]->opposite;
+ }
+
+ // 2) c.opposite.opposite = c
+ for (int c=0; c<3; c++) {
+ if (newcorners[c]->opposite>=0)
+ mCorners[newcorners[c]->opposite].opposite = 3*tri+c;
+ }
+
+ // update tri lookup
+ for (int c=0; c<3; c++) {
+ int node = mTris[tri].c[c];
+ m1RingLookup[node].tris.erase(oldtri);
+ m1RingLookup[node].tris.insert(tri);
+ }
+ }
+
+ // transfer tri props
+ for(size_t p=0; p < mTriChannels.size(); p++)
+ mTriChannels[p]->remove(tri);
+
+ // pop the triangle and corners out of the vector
+ mTris.pop_back();
+ mCorners.resize(mTris.size()*3);
+}
+
+void Mesh::removeNodes(const vector<int>& deletedNodes) {
+ // After we delete the nodes that are marked for removal,
+ // the size of mNodes will be the current size - the size of the deleted array.
+ // We are going to move the elements at the end of the array
+ // (everything with an index >= newsize)
+ // to the deleted spots.
+ // We have to map all references to the last few nodes to their new locations.
+ int newsize = (int)(mNodes.size() - deletedNodes.size());
+
+ vector<int> new_index (deletedNodes.size());
+ int di,ni;
+ for(ni=0; ni<(int)new_index.size(); ni++)
+ new_index[ni] = 0;
+ for(di=0; di<(int)deletedNodes.size(); di++) {
+ if(deletedNodes[di] >= newsize)
+ new_index[deletedNodes[di]-newsize] = -1; // tag this node as invalid
+ }
+ for(di=0,ni=0; ni<(int)new_index.size(); ni++,di++) {
+ // we need to find a valid node to move
+ // we marked invalid nodes in the earlier loop with a (-1),
+ // so pick anything but those
+ while(ni<(int)new_index.size() && new_index[ni]==-1)
+ ni++;
+
+ if(ni>=(int)new_index.size())
+ break;
+
+ // next we need to find a valid spot to move the node to.
+ // we iterate through deleted[] until we find a valid spot
+ while(di<(int)new_index.size() && deletedNodes[di]>=newsize)
+ di++;
+
+ // now we assign the valid node to the valid spot
+ new_index[ni] = deletedNodes[di];
+ }
+
+ // Now we have a map of valid indices.
+ // we move node[newsize+i] to location new_index[i].
+ // We ignore the nodes with a -1 index, because they should not be moved.
+ for(int i=0; i<(int)new_index.size(); i++) {
+ if(new_index[i]!=-1)
+ mNodes[ new_index[i] ] = mNodes[ newsize+i ];
+ }
+ mNodes.resize(newsize);
+
+ // handle vertex properties
+ for (size_t i=0; i<mNodeChannels.size(); i++)
+ mNodeChannels[i]->renumber(new_index, newsize);
+
+ // finally, we reconnect everything that used to point to this vertex.
+ for(size_t tri=0, n=0; tri<mTris.size(); tri++) {
+ for (int c=0; c<3; c++,n++) {
+ if (mCorners[n].node >= newsize) {
+ int newindex = new_index[mCorners[n].node - newsize];
+ mCorners[n].node = newindex;
+ mTris[mCorners[n].tri].c[c] = newindex;
+ }
+ }
+ }
+
+ // renumber 1-ring
+ for(int i=0; i<(int)new_index.size(); i++) {
+ if(new_index[i]!=-1) {
+ m1RingLookup[new_index[i]].nodes.swap(m1RingLookup[newsize+i].nodes);
+ m1RingLookup[new_index[i]].tris.swap(m1RingLookup[newsize+i].tris);
+ }
+ }
+ m1RingLookup.resize(newsize);
+ vector<int> reStack(new_index.size());
+ for(int i=0; i<newsize; i++) {
+ set<int>& cs = m1RingLookup[i].nodes;
+ int reNum = 0;
+ // find all nodes > newsize
+ set<int>::reverse_iterator itend = cs.rend();
+ for (set<int>::reverse_iterator it = cs.rbegin(); it != itend; ++it) {
+ if (*it < newsize) break;
+ reStack[reNum++] = *it;
+ }
+ // kill them and insert shifted values
+ if (reNum > 0) {
+ cs.erase(cs.find(reStack[reNum-1]), cs.end());
+ for (int j=0; j<reNum; j++) {
+ cs.insert(new_index[reStack[j]-newsize]);
+#ifdef DEBUG
+ if (new_index[reStack[j]-newsize] == -1)
+ errMsg("invalid node present in 1-ring set");
+#endif
+ }
+ }
+ }
+}
+
+void Mesh::mergeNode(int node, int delnode) {
+ set<int>& ring = m1RingLookup[delnode].nodes;
+ for(set<int>::iterator it = ring.begin(); it != ring.end(); ++it) {
+ m1RingLookup[*it].nodes.erase(delnode);
+ if (*it != node) {
+ m1RingLookup[*it].nodes.insert(node);
+ m1RingLookup[node].nodes.insert(*it);
+ }
+ }
+ set<int>& ringt = m1RingLookup[delnode].tris;
+ for(set<int>::iterator it = ringt.begin(); it != ringt.end(); ++it) {
+ const int t = *it;
+ for (int c=0; c<3; c++) {
+ if (mCorners[3*t+c].node == delnode) {
+ mCorners[3*t+c].node = node;
+ mTris[t].c[c] = node;
+ }
+ }
+ m1RingLookup[node].tris.insert(t);
+ }
+ for(size_t i=0; i<mNodeChannels.size(); i++) {
+ // weight is fixed to 1/2 for now
+ mNodeChannels[i]->mergeWith(node, delnode, 0.5);
+ }
+}
+
+void Mesh::removeTriFromLookup(int tri) {
+ for(int c=0; c<3; c++) {
+ int node = mTris[tri].c[c];
+ m1RingLookup[node].tris.erase(tri);
+ }
+}
+
+void Mesh::addCorner(Corner a) {
+ mCorners.push_back(a);
+}
+
+int Mesh::addTri(Triangle a) {
+ mTris.push_back(a);
+ for (int c=0;c<3;c++) {
+ int node = a.c[c];
+ int nextnode = a.c[(c+1)%3];
+ if ((int)m1RingLookup.size() <= node) m1RingLookup.resize(node+1);
+ if ((int)m1RingLookup.size() <= nextnode) m1RingLookup.resize(nextnode+1);
+ m1RingLookup[node].nodes.insert(nextnode);
+ m1RingLookup[nextnode].nodes.insert(node);
+ m1RingLookup[node].tris.insert(mTris.size()-1);
+ }
+ return mTris.size()-1;
+}
+
+int Mesh::addNode(Node a) {
+ mNodes.push_back(a);
+ if (m1RingLookup.size() < mNodes.size())
+ m1RingLookup.resize(mNodes.size());
+
+ // if mdata exists, add zero init for every node
+ addAllMdata();
+
+ return mNodes.size()-1;
+}
+
+void Mesh::computeVertexNormals() {
+ for (size_t i=0; i<mNodes.size(); i++) {
+ mNodes[i].normal = 0.0;
+ }
+ for (size_t t=0; t<mTris.size(); t++) {
+ Vec3 p0 = getNode(t,0), p1 = getNode(t,1), p2 = getNode(t,2);
+ Vec3 n0 = p0-p1, n1 = p1-p2, n2 = p2-p0;
+ Real l0 = normSquare(n0), l1 = normSquare(n1), l2 = normSquare(n2);
+
+ Vec3 nm = cross(n0,n1);
+
+ mNodes[mTris[t].c[0]].normal += nm * (1.0 / (l0*l2));
+ mNodes[mTris[t].c[1]].normal += nm * (1.0 / (l0*l1));
+ mNodes[mTris[t].c[2]].normal += nm * (1.0 / (l1*l2));
+ }
+ for (size_t i=0; i<mNodes.size(); i++) {
+ normalize(mNodes[i].normal);
+ }
+}
+
+void Mesh::fastNodeLookupRebuild(int corner) {
+ int node = mCorners[corner].node;
+ m1RingLookup[node].nodes.clear();
+ m1RingLookup[node].tris.clear();
+ int start = mCorners[corner].prev;
+ int current = start;
+ do {
+ m1RingLookup[node].nodes.insert(mCorners[current].node);
+ m1RingLookup[node].tris.insert(mCorners[current].tri);
+ current = mCorners[mCorners[current].opposite].next;
+ if (current < 0)
+ errMsg("Can't use fastNodeLookupRebuild on incomplete surfaces");
+ } while (current != start);
+}
+
+void Mesh::sanityCheck(bool strict, vector<int>* deletedNodes, map<int,bool>* taintedTris) {
+ const int nodes = numNodes(), tris = numTris(), corners = 3*tris;
+ for(size_t i=0; i<mNodeChannels.size(); i++) {
+ if (mNodeChannels[i]->size() != nodes)
+ errMsg("Node channel size mismatch");
+ }
+ for(size_t i=0; i<mTriChannels.size(); i++) {
+ if (mTriChannels[i]->size() != tris)
+ errMsg("Tri channel size mismatch");
+ }
+ if ((int)m1RingLookup.size() != nodes)
+ errMsg("1Ring size wrong");
+ for(size_t t=0; t<mTris.size(); t++) {
+ if (taintedTris && taintedTris->find(t) != taintedTris->end()) continue;
+ for (int c=0; c<3; c++) {
+ int corner = t*3+c;
+ int node = mTris[t].c[c];
+ int next = mTris[t].c[(c+1)%3];
+ int prev = mTris[t].c[(c+2)%3];
+ int rnext = mCorners[corner].next;
+ int rprev = mCorners[corner].prev;
+ int ro = mCorners[corner].opposite;
+ if (node < 0 || node >= nodes || next < 0 || next >= nodes || prev < 0 || prev >= nodes)
+ errMsg("invalid node entry");
+ if (mCorners[corner].node != node || mCorners[corner].tri != (int)t)
+ errMsg("invalid basic corner entry");
+ if (rnext < 0 || rnext >= corners || rprev < 0 || rprev >= corners || ro >= corners)
+ errMsg("invalid corner links");
+ if (mCorners[rnext].node != next || mCorners[rprev].node != prev)
+ errMsg("invalid corner next/prev");
+ if (strict && ro < 0)
+ errMsg("opposite missing");
+ if (mCorners[ro].opposite != corner)
+ errMsg("invalid opposite ref");
+ set<int>& rnodes = m1RingLookup[node].nodes;
+ set<int>& rtris = m1RingLookup[node].tris;
+ if (rnodes.find(next) == rnodes.end() || rnodes.find(prev) == rnodes.end()) {
+ debMsg("Tri "<< t << " " << node << " " << next << " " << prev , 1);
+ for(set<int>::iterator it= rnodes.begin(); it != rnodes.end(); ++it)
+ debMsg( *it , 1);
+ errMsg("node missing in 1ring");
+ }
+ if (rtris.find(t) == rtris.end()) {
+ debMsg("Tri "<< t << " " << node , 1);
+ errMsg("tri missing in 1ring");
+ }
+ }
+ }
+ for (int n=0; n<nodes; n++) {
+ bool docheck=true;
+ if (deletedNodes)
+ for (size_t e=0; e<deletedNodes->size(); e++)
+ if ((*deletedNodes)[e] == n) docheck=false;;
+
+ if (docheck) {
+ set<int>& sn = m1RingLookup[n].nodes;
+ set<int>& st = m1RingLookup[n].tris;
+ set<int> sn2;
+
+ for (set<int>::iterator it=st.begin(); it != st.end(); ++it) {
+ bool found = false;
+ for (int c=0; c<3; c++) {
+ if (mTris[*it].c[c] == n)
+ found = true;
+ else
+ sn2.insert(mTris[*it].c[c]);
+ }
+ if (!found) {
+ cout << *it << " " << n << endl;
+ for (int c=0; c<3; c++) cout << mTris[*it].c[c] << endl;
+ errMsg("invalid triangle in 1ring");
+ }
+ if (taintedTris && taintedTris->find(*it) != taintedTris->end()) {
+ cout << *it << endl;
+ errMsg("tainted tri still is use");
+ }
+ }
+ if (sn.size() != sn2.size())
+ errMsg("invalid nodes in 1ring");
+ for (set<int>::iterator it=sn.begin(), it2=sn2.begin(); it != sn.end(); ++it,++it2) {
+ if (*it != *it2) {
+ cout << "Node " << n << ": " << *it << " vs " << *it2 << endl;
+ errMsg("node ring mismatch");
+ }
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+// rasterization
+
+void meshSDF(Mesh& mesh, LevelsetGrid& levelset, Real sigma, Real cutoff = 0.);
+
+//! helper vec3 array container
+struct CVec3Ptr {
+ Real *x, *y, *z;
+ inline Vec3 get(int i) const { return Vec3(x[i],y[i],z[i]); };
+ inline void set(int i, const Vec3& v) { x[i]=v.x; y[i]=v.y; z[i]=v.z; };
+};
+//! helper vec3 array, for CUDA compatibility, remove at some point
+struct CVec3Array {
+ CVec3Array(int sz) {
+ x.resize(sz);
+ y.resize(sz);
+ z.resize(sz);
+ }
+ CVec3Array(const std::vector<Vec3>& v) {
+ x.resize(v.size());
+ y.resize(v.size());
+ z.resize(v.size());
+ for (size_t i=0; i<v.size(); i++) {
+ x[i] = v[i].x;
+ y[i] = v[i].y;
+ z[i] = v[i].z;
+ }
+ }
+ CVec3Ptr data() {
+ CVec3Ptr a = { x.data(), y.data(), z.data()};
+ return a;
+ }
+ inline const Vec3 operator[](int idx) const { return Vec3((Real)x[idx], (Real)y[idx], (Real)z[idx]); }
+ inline void set(int idx, const Vec3& v) { x[idx] = v.x; y[idx] = v.y; z[idx] = v.z; }
+ inline int size() { return x.size(); }
+ std::vector<Real> x, y, z;
+};
+
+
+//void SDFKernel(const int* partStart, const int* partLen, CVec3Ptr pos, CVec3Ptr normal, Real* sdf, Vec3i gridRes, int intRadius, Real safeRadius2, Real cutoff2, Real isigma2);
+//! helper for rasterization
+static void SDFKernel(Grid<int>& partStart, Grid<int>& partLen, CVec3Ptr pos, CVec3Ptr normal, LevelsetGrid& sdf, Vec3i gridRes, int intRadius, Real safeRadius2, Real cutoff2, Real isigma2)
+{
+ for (int cnt_x(0); cnt_x < gridRes[0]; ++cnt_x) {
+ for (int cnt_y(0); cnt_y < gridRes[1]; ++cnt_y) {
+ for (int cnt_z(0); cnt_z < gridRes[2]; ++cnt_z) {
+ // cell index, center
+ Vec3i cell = Vec3i(cnt_x, cnt_y, cnt_z);
+ if (cell.x >= gridRes.x || cell.y >= gridRes.y || cell.z >= gridRes.z) return;
+ Vec3 cpos = Vec3(cell.x + 0.5f, cell.y + 0.5f, cell.z + 0.5f);
+ Real sum = 0.0f;
+ Real dist = 0.0f;
+
+ // query cells within block radius
+ Vec3i minBlock = Vec3i(max(cell.x - intRadius,0), max(cell.y - intRadius,0), max(cell.z - intRadius,0));
+ Vec3i maxBlock = Vec3i(min(cell.x + intRadius, gridRes.x - 1), min(cell.y + intRadius, gridRes.y - 1), min(cell.z + intRadius, gridRes.z - 1));
+ for (int i=minBlock.x; i<=maxBlock.x; i++)
+ for (int j=minBlock.y; j<=maxBlock.y; j++)
+ for (int k=minBlock.z; k<=maxBlock.z; k++) {
+ // test if block is within radius
+ Vec3 d = Vec3(cell.x-i, cell.y-j, cell.z-k);
+ Real normSqr = d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
+ if (normSqr > safeRadius2) continue;
+
+ // find source cell, and divide it into thread blocks
+ int block = i + gridRes.x * (j + gridRes.y * k);
+ int slen = partLen[block];
+ if (slen == 0) continue;
+ int start = partStart[block];
+
+ // process sources
+ for(int s=0; s<slen; s++) {
+
+ // actual sdf kernel
+ Vec3 r = cpos - pos.get(start+s);
+ Real normSqr = r[0]*r[0] + r[1]*r[1] + r[2]*r[2];
+ Real r2 = normSqr;
+ if (r2 < cutoff2) {
+ Real w = expf(-r2*isigma2);
+ sum += w;
+ dist += dot(normal.get(start+s), r) * w;
+ }
+ }
+ }
+ // writeback
+ if (sum > 0.0f) {
+ //sdf[cell.x + gridRes.x * (cell.y + gridRes.y * cell.z)] = dist / sum;
+ sdf(cell.x ,cell.y ,cell.z) = dist / sum;
+ }
+ }
+ }
+ }
+}
+
+static inline IndexInt _cIndex(const Vec3& pos, const Vec3i& s) {
+ Vec3i p = toVec3i(pos);
+ if (p.x < 0 || p.y < 0 || p.z < 0 || p.x >= s.x || p.y >= s.y || p.z >= s.z) return -1;
+ return p.x + s.x * (p.y + s.y * p.z);
+}
+
+//! Kernel: Apply a shape to a grid, setting value inside
+
+template <class T> struct ApplyMeshToGrid : public KernelBase {
+ ApplyMeshToGrid(Grid<T>* grid, Grid<Real>& sdf, T value, FlagGrid* respectFlags) : KernelBase(grid,0) ,grid(grid),sdf(sdf),value(value),respectFlags(respectFlags) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>* grid, Grid<Real>& sdf, T value, FlagGrid* respectFlags ) const {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ if (sdf(i,j,k) < 0)
+ {
+ (*grid)(i,j,k) = value;
+ }
+} inline Grid<T>* getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline Grid<Real>& getArg1() {
+ return sdf; }
+ typedef Grid<Real> type1;inline T& getArg2() {
+ return value; }
+ typedef T type2;inline FlagGrid* getArg3() {
+ return respectFlags; }
+ typedef FlagGrid type3; void runMessage() { debMsg("Executing kernel ApplyMeshToGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,sdf,value,respectFlags); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,sdf,value,respectFlags); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<T>* grid; Grid<Real>& sdf; T value; FlagGrid* respectFlags; }
+;
+
+void Mesh::applyMeshToGrid(GridBase* grid, FlagGrid* respectFlags, Real cutoff) {
+ FluidSolver dummy(grid->getSize());
+ LevelsetGrid mesh_sdf(&dummy, false);
+ meshSDF(*this, mesh_sdf, 2., cutoff); // meshSigma=2 fixed here
+
+# if NOPYTHON!=1
+ if (grid->getType() & GridBase::TypeInt)
+ ApplyMeshToGrid<int> ((Grid<int>*)grid, mesh_sdf, _args.get<int>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeReal)
+ ApplyMeshToGrid<Real> ((Grid<Real>*)grid, mesh_sdf, _args.get<Real>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeVec3)
+ ApplyMeshToGrid<Vec3> ((Grid<Vec3>*)grid, mesh_sdf, _args.get<Vec3>("value"), respectFlags);
+ else
+ errMsg("Shape::applyToGrid(): unknown grid type");
+# else
+ errMsg("Not yet supported...");
+# endif
+}
+
+void Mesh::computeLevelset(LevelsetGrid& levelset, Real sigma, Real cutoff) {
+ meshSDF( *this, levelset, sigma, cutoff);
+}
+
+LevelsetGrid Mesh::getLevelset(Real sigma, Real cutoff) {
+ LevelsetGrid phi(getParent());
+ meshSDF(*this, phi, sigma, cutoff);
+ return phi;
+}
+
+void meshSDF(Mesh& mesh, LevelsetGrid& levelset, Real sigma, Real cutoff)
+{
+ if (cutoff<0) cutoff = 2*sigma;
+ Real maxEdgeLength = 0.75;
+ Real numSamplesPerCell = 0.75;
+
+ Vec3i gridRes = levelset.getSize();
+ Vec3 mult = toVec3(gridRes) / toVec3(mesh.getParent()->getGridSize());
+
+ // prepare center values
+ std::vector<Vec3> center;
+ std::vector<Vec3> normals;
+ short bigEdges(0);
+ std::vector<Vec3> samplePoints;
+ for(int i=0; i<mesh.numTris(); i++){
+ center.push_back(Vec3(mesh.getFaceCenter(i) * mult));
+ normals.push_back(mesh.getFaceNormal(i));
+ //count big, stretched edges
+ bigEdges = 0;
+ for (short edge(0); edge <3; ++edge){
+ if(norm(mesh.getEdge(i,edge)) > maxEdgeLength){
+ bigEdges += 1 << edge;
+ }
+ }
+ if(bigEdges > 0){
+ samplePoints.clear();
+ short iterA, pointA, iterB, pointB;
+ int numSamples0 = norm(mesh.getEdge(i,1)) * numSamplesPerCell;
+ int numSamples1 = norm(mesh.getEdge(i,2)) * numSamplesPerCell;
+ int numSamples2 = norm(mesh.getEdge(i,0)) * numSamplesPerCell;
+ if(! (bigEdges & (1 << 0))){
+ //loop through 0,1
+ iterA = numSamples1;
+ pointA = 0;
+ iterB = numSamples2;
+ pointB = 1;
+ }
+ else if(! (bigEdges & (1 << 1))){
+ //loop through 1,2
+ iterA = numSamples2;
+ pointA = 1;
+ iterB = numSamples0;
+ pointB = 2;
+
+ }
+ else{
+ //loop through 2,0
+ iterA = numSamples0;
+ pointA = 2;
+ iterB = numSamples1;
+ pointB = 0;
+ }
+
+ Real u(0.),v(0.),w(0.); // barycentric uvw coords
+ Vec3 samplePoint,normal;
+ for (int sample0(0); sample0 < iterA; ++sample0){
+ u = Real(1. * sample0 / iterA);
+ for (int sample1(0); sample1 < iterB; ++sample1){
+ v = Real(1. * sample1 / iterB);
+ w = 1 - u - v;
+ if (w < 0.)
+ continue;
+ samplePoint = mesh.getNode(i,pointA) * mult * u +
+ mesh.getNode(i,pointB) * mult * v +
+ mesh.getNode(i,(3 - pointA - pointB)) * mult * w;
+ samplePoints.push_back(samplePoint);
+ normal = mesh.getFaceNormal(i);
+ normals.push_back(normal);
+ }
+ }
+ center.insert(center.end(), samplePoints.begin(), samplePoints.end());
+ }
+ }
+
+ // prepare grid
+ levelset.setConst( -cutoff );
+
+ // 1. count sources per cell
+ Grid<int> srcPerCell(levelset.getParent());
+ for (size_t i=0; i<center.size(); i++) {
+ IndexInt idx = _cIndex(center[i], gridRes);
+ if (idx >= 0)
+ srcPerCell[idx]++;
+ }
+
+ // 2. create start index lookup
+ Grid<int> srcCellStart(levelset.getParent());
+ int cnt=0;
+ FOR_IJK(srcCellStart) {
+ IndexInt idx = srcCellStart.index(i,j,k);
+ srcCellStart[idx] = cnt;
+ cnt += srcPerCell[idx];
+ }
+
+ // 3. reorder nodes
+ CVec3Array reorderPos(center.size());
+ CVec3Array reorderNormal(center.size());
+ {
+ Grid<int> curSrcCell(levelset.getParent());
+ for (int i=0; i<(int)center.size(); i++) {
+ IndexInt idx = _cIndex(center[i], gridRes);
+ if (idx < 0) continue;
+ IndexInt idx2 = srcCellStart[idx] + curSrcCell[idx];
+ reorderPos.set(idx2, center[i]);
+ reorderNormal.set(idx2, normals[i]);
+ curSrcCell[idx]++;
+ }
+ }
+
+ // construct parameters
+ Real safeRadius = cutoff + sqrt(3.0)*0.5;
+ Real safeRadius2 = safeRadius*safeRadius;
+ Real cutoff2 = cutoff*cutoff;
+ Real isigma2 = 1.0/(sigma*sigma);
+ int intRadius = (int)(cutoff+0.5);
+
+ SDFKernel( srcCellStart, srcPerCell,
+ reorderPos.data(), reorderNormal.data(),
+ levelset, gridRes, intRadius, safeRadius2, cutoff2, isigma2);
+
+ // floodfill outside
+ std::stack<Vec3i> outside;
+ FOR_IJK(levelset) {
+ if (levelset(i,j,k) >= cutoff-1.0f)
+ outside.push(Vec3i(i,j,k));
+ }
+ while(!outside.empty()) {
+ Vec3i c = outside.top();
+ outside.pop();
+ levelset(c) = cutoff;
+ if (c.x > 0 && levelset(c.x-1, c.y, c.z) < 0) outside.push(Vec3i(c.x-1,c.y,c.z));
+ if (c.y > 0 && levelset(c.x, c.y-1, c.z) < 0) outside.push(Vec3i(c.x,c.y-1,c.z));
+ if (c.z > 0 && levelset(c.x, c.y, c.z-1) < 0) outside.push(Vec3i(c.x,c.y,c.z-1));
+ if (c.x < levelset.getSizeX()-1 && levelset(c.x+1, c.y, c.z) < 0) outside.push(Vec3i(c.x+1,c.y,c.z));
+ if (c.y < levelset.getSizeY()-1 && levelset(c.x, c.y+1, c.z) < 0) outside.push(Vec3i(c.x,c.y+1,c.z));
+ if (c.z < levelset.getSizeZ()-1 && levelset(c.x, c.y, c.z+1) < 0) outside.push(Vec3i(c.x,c.y,c.z+1));
+ };
+}
+
+// Blender data pointer accessors
+std::string Mesh::getNodesDataPointer() {
+ std::ostringstream out;
+ out << &mNodes;
+ return out.str();
+}
+std::string Mesh::getTrisDataPointer() {
+ std::ostringstream out;
+ out << &mTris;
+ return out.str();
+}
+
+// mesh data
+
+MeshDataBase::MeshDataBase(FluidSolver* parent) :
+ PbClass(parent) , mMesh(NULL) {
+}
+
+MeshDataBase::~MeshDataBase()
+{
+ // notify parent of deletion
+ if(mMesh)
+ mMesh->deregister(this);
+}
+
+// actual data implementation
+
+template<class T>
+MeshDataImpl<T>::MeshDataImpl(FluidSolver* parent) :
+ MeshDataBase(parent) , mpGridSource(NULL), mGridSourceMAC(false) {
+}
+
+template<class T>
+MeshDataImpl<T>::MeshDataImpl(FluidSolver* parent, MeshDataImpl<T>* other) :
+ MeshDataBase(parent) , mpGridSource(NULL), mGridSourceMAC(false) {
+ this->mData = other->mData;
+ setName(other->getName());
+}
+
+template<class T>
+MeshDataImpl<T>::~MeshDataImpl() {
+}
+
+template<class T>
+IndexInt MeshDataImpl<T>::getSizeSlow() const {
+ return mData.size();
+}
+template<class T>
+void MeshDataImpl<T>::addEntry() {
+ // add zero'ed entry
+ T tmp = T(0.);
+ // for debugging, force init:
+ //tmp = T(0.02 * mData.size()); // increasing
+ //tmp = T(1.); // constant 1
+ return mData.push_back(tmp);
+}
+template<class T>
+void MeshDataImpl<T>::resize(IndexInt s) {
+ mData.resize(s);
+}
+template<class T>
+void MeshDataImpl<T>::copyValueSlow(IndexInt from, IndexInt to) {
+ this->copyValue(from,to);
+}
+template<class T>
+MeshDataBase* MeshDataImpl<T>::clone() {
+ MeshDataImpl<T>* npd = new MeshDataImpl<T>( getParent(), this );
+ return npd;
+}
+
+template<class T>
+void MeshDataImpl<T>::setSource(Grid<T>* grid, bool isMAC ) {
+ mpGridSource = grid;
+ mGridSourceMAC = isMAC;
+ if(isMAC) assertMsg( dynamic_cast<MACGrid*>(grid) != NULL , "Given grid is not a valid MAC grid");
+}
+
+template<class T>
+void MeshDataImpl<T>::initNewValue(IndexInt idx, Vec3 pos) {
+ if(!mpGridSource)
+ mData[idx] = 0;
+ else {
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ }
+}
+
+// special handling needed for velocities
+template<>
+void MeshDataImpl<Vec3>::initNewValue(IndexInt idx, Vec3 pos) {
+ if(!mpGridSource)
+ mData[idx] = 0;
+ else {
+ if(!mGridSourceMAC)
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ else
+ mData[idx] = ((MACGrid*)mpGridSource)->getInterpolated(pos);
+ }
+}
+
+//! update additional mesh data
+void Mesh::updateDataFields() {
+ for(size_t i=0; i<mNodes.size(); ++i) {
+ Vec3 pos = mNodes[i].pos;
+ for(IndexInt md=0; md<(IndexInt)mMdataReal.size(); ++md)
+ mMdataReal[md]->initNewValue(i, mNodes[i].pos);
+ for(IndexInt md=0; md<(IndexInt)mMdataVec3.size(); ++md)
+ mMdataVec3[md]->initNewValue(i, mNodes[i].pos);
+ for(IndexInt md=0; md<(IndexInt)mMdataInt.size(); ++md)
+ mMdataInt[md]->initNewValue(i, mNodes[i].pos);
+ }
+}
+
+template<typename T>
+void MeshDataImpl<T>::load(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if ( ext == ".uni")
+ readMdataUni<T>(name, this);
+ else if ( ext == ".raw") // raw = uni for now
+ readMdataUni<T>(name, this);
+ else
+ errMsg("mesh data '" + name +"' filetype not supported for loading");
+}
+
+template<typename T>
+void MeshDataImpl<T>::save(string name) {
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if (ext == ".uni")
+ writeMdataUni<T>(name, this);
+ else if (ext == ".raw") // raw = uni for now
+ writeMdataUni<T>(name, this);
+ else
+ errMsg("mesh data '" + name +"' filetype not supported for saving");
+}
+
+// specializations
+
+template<>
+MeshDataBase::MdataType MeshDataImpl<Real>::getType() const {
+ return MeshDataBase::TypeReal;
+}
+template<>
+MeshDataBase::MdataType MeshDataImpl<int>::getType() const {
+ return MeshDataBase::TypeInt;
+}
+template<>
+MeshDataBase::MdataType MeshDataImpl<Vec3>::getType() const {
+ return MeshDataBase::TypeVec3;
+}
+
+template <class T> struct knSetMdataConst : public KernelBase {
+ knSetMdataConst(MeshDataImpl<T>& mdata, T value) : KernelBase(mdata.size()) ,mdata(mdata),value(value) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& mdata, T value ) const { mdata[idx] = value; } inline MeshDataImpl<T>& getArg0() {
+ return mdata; }
+ typedef MeshDataImpl<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knSetMdataConst ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, mdata,value); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& mdata; T value; }
+;
+
+template <class T, class S> struct knMdataSet : public KernelBase {
+ knMdataSet(MeshDataImpl<T>& me, const MeshDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<S>& other ) const { me[idx] += other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<S>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knMdataSet ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const MeshDataImpl<S>& other; }
+;
+template <class T, class S> struct knMdataAdd : public KernelBase {
+ knMdataAdd(MeshDataImpl<T>& me, const MeshDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<S>& other ) const { me[idx] += other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<S>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knMdataAdd ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const MeshDataImpl<S>& other; }
+;
+template <class T, class S> struct knMdataSub : public KernelBase {
+ knMdataSub(MeshDataImpl<T>& me, const MeshDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<S>& other ) const { me[idx] -= other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<S>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knMdataSub ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const MeshDataImpl<S>& other; }
+;
+template <class T, class S> struct knMdataMult : public KernelBase {
+ knMdataMult(MeshDataImpl<T>& me, const MeshDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<S>& other ) const { me[idx] *= other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<S>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knMdataMult ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const MeshDataImpl<S>& other; }
+;
+template <class T, class S> struct knMdataDiv : public KernelBase {
+ knMdataDiv(MeshDataImpl<T>& me, const MeshDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<S>& other ) const { me[idx] /= other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<S>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knMdataDiv ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const MeshDataImpl<S>& other; }
+;
+
+template <class T, class S> struct knMdataSetScalar : public KernelBase {
+ knMdataSetScalar(MeshDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const S& other ) const { me[idx] = other; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knMdataSetScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knMdataAddScalar : public KernelBase {
+ knMdataAddScalar(MeshDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const S& other ) const { me[idx] += other; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knMdataAddScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knMdataMultScalar : public KernelBase {
+ knMdataMultScalar(MeshDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const S& other ) const { me[idx] *= other; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knMdataMultScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knMdataScaledAdd : public KernelBase {
+ knMdataScaledAdd(MeshDataImpl<T>& me, const MeshDataImpl<T>& other, const S& factor) : KernelBase(me.size()) ,me(me),other(other),factor(factor) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<T>& other, const S& factor ) const { me[idx] += factor * other[idx]; } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<T>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<T> type1;inline const S& getArg2() {
+ return factor; }
+ typedef S type2; void runMessage() { debMsg("Executing kernel knMdataScaledAdd ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other,factor); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const MeshDataImpl<T>& other; const S& factor; }
+;
+
+template <class T> struct knMdataSafeDiv : public KernelBase {
+ knMdataSafeDiv(MeshDataImpl<T>& me, const MeshDataImpl<T>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const MeshDataImpl<T>& other ) const { me[idx] = safeDivide(me[idx], other[idx]); } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<T>& getArg1() {
+ return other; }
+ typedef MeshDataImpl<T> type1; void runMessage() { debMsg("Executing kernel knMdataSafeDiv ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const MeshDataImpl<T>& other; }
+;
+template <class T> struct knMdataSetConst : public KernelBase {
+ knMdataSetConst(MeshDataImpl<T>& mdata, T value) : KernelBase(mdata.size()) ,mdata(mdata),value(value) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& mdata, T value ) const { mdata[idx] = value; } inline MeshDataImpl<T>& getArg0() {
+ return mdata; }
+ typedef MeshDataImpl<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knMdataSetConst ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, mdata,value); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& mdata; T value; }
+;
+
+template <class T> struct knMdataClamp : public KernelBase {
+ knMdataClamp(MeshDataImpl<T>& me, T min, T max) : KernelBase(me.size()) ,me(me),min(min),max(max) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, T min, T max ) const { me[idx] = clamp( me[idx], min, max); } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline T& getArg1() {
+ return min; }
+ typedef T type1;inline T& getArg2() {
+ return max; }
+ typedef T type2; void runMessage() { debMsg("Executing kernel knMdataClamp ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,min,max); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; T min; T max; }
+;
+template <class T> struct knMdataClampMin : public KernelBase {
+ knMdataClampMin(MeshDataImpl<T>& me, const T vmin) : KernelBase(me.size()) ,me(me),vmin(vmin) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const T vmin ) const { me[idx] = std::max(vmin, me[idx]); } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const T& getArg1() {
+ return vmin; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knMdataClampMin ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,vmin); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const T vmin; }
+;
+template <class T> struct knMdataClampMax : public KernelBase {
+ knMdataClampMax(MeshDataImpl<T>& me, const T vmax) : KernelBase(me.size()) ,me(me),vmax(vmax) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const T vmax ) const { me[idx] = std::min(vmax, me[idx]); } inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const T& getArg1() {
+ return vmax; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knMdataClampMax ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,vmax); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const T vmax; }
+;
+ struct knMdataClampMinVec3 : public KernelBase {
+ knMdataClampMinVec3(MeshDataImpl<Vec3>& me, const Real vmin) : KernelBase(me.size()) ,me(me),vmin(vmin) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<Vec3>& me, const Real vmin ) const {
+ me[idx].x = std::max(vmin, me[idx].x);
+ me[idx].y = std::max(vmin, me[idx].y);
+ me[idx].z = std::max(vmin, me[idx].z);
+} inline MeshDataImpl<Vec3>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<Vec3> type0;inline const Real& getArg1() {
+ return vmin; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knMdataClampMinVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,vmin); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<Vec3>& me; const Real vmin; }
+;
+ struct knMdataClampMaxVec3 : public KernelBase {
+ knMdataClampMaxVec3(MeshDataImpl<Vec3>& me, const Real vmax) : KernelBase(me.size()) ,me(me),vmax(vmax) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<Vec3>& me, const Real vmax ) const {
+ me[idx].x = std::min(vmax, me[idx].x);
+ me[idx].y = std::min(vmax, me[idx].y);
+ me[idx].z = std::min(vmax, me[idx].z);
+} inline MeshDataImpl<Vec3>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<Vec3> type0;inline const Real& getArg1() {
+ return vmax; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knMdataClampMaxVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,vmax); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<Vec3>& me; const Real vmax; }
+;
+
+// python operators
+
+
+template<typename T>
+MeshDataImpl<T>& MeshDataImpl<T>::copyFrom(const MeshDataImpl<T>& a) {
+ assertMsg (a.mData.size() == mData.size() , "different mdata size "<<a.mData.size()<<" vs "<<this->mData.size() );
+ memcpy( &mData[0], &a.mData[0], sizeof(T) * mData.size() );
+ return *this;
+}
+
+template<typename T>
+void MeshDataImpl<T>::setConst(T s) {
+ knMdataSetScalar<T,T> op( *this, s );
+}
+
+template<typename T>
+void MeshDataImpl<T>::setConstRange(T s, const int begin, const int end) {
+ for(int i=begin; i<end; ++i) (*this)[i] = s;
+}
+
+// special set by flag
+template <class T, class S> struct knMdataSetScalarIntFlag : public KernelBase {
+ knMdataSetScalarIntFlag(MeshDataImpl<T>& me, const S& other, const MeshDataImpl<int>& t, const int itype) : KernelBase(me.size()) ,me(me),other(other),t(t),itype(itype) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MeshDataImpl<T>& me, const S& other, const MeshDataImpl<int>& t, const int itype ) const {
+ if(t[idx]&itype) me[idx] = other;
+} inline MeshDataImpl<T>& getArg0() {
+ return me; }
+ typedef MeshDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1;inline const MeshDataImpl<int>& getArg2() {
+ return t; }
+ typedef MeshDataImpl<int> type2;inline const int& getArg3() {
+ return itype; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel knMdataSetScalarIntFlag ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other,t,itype); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MeshDataImpl<T>& me; const S& other; const MeshDataImpl<int>& t; const int itype; }
+;
+template<typename T>
+void MeshDataImpl<T>::setConstIntFlag(T s, const MeshDataImpl<int>& t, const int itype) {
+ knMdataSetScalarIntFlag<T,T> op(*this, s, t, itype);
+}
+
+template<typename T>
+void MeshDataImpl<T>::add(const MeshDataImpl<T>& a) {
+ knMdataAdd<T,T> op( *this, a );
+}
+template<typename T>
+void MeshDataImpl<T>::sub(const MeshDataImpl<T>& a) {
+ knMdataSub<T,T> op( *this, a );
+}
+
+template<typename T>
+void MeshDataImpl<T>::addConst(T s) {
+ knMdataAddScalar<T,T> op( *this, s );
+}
+
+template<typename T>
+void MeshDataImpl<T>::addScaled(const MeshDataImpl<T>& a, const T& factor) {
+ knMdataScaledAdd<T,T> op( *this, a, factor );
+}
+
+template<typename T>
+void MeshDataImpl<T>::mult( const MeshDataImpl<T>& a) {
+ knMdataMult<T,T> op( *this, a );
+}
+
+template<typename T>
+void MeshDataImpl<T>::safeDiv(const MeshDataImpl<T>& a) {
+ knMdataSafeDiv<T> op( *this, a );
+}
+
+template<typename T>
+void MeshDataImpl<T>::multConst(T s) {
+ knMdataMultScalar<T,T> op( *this, s );
+}
+
+
+template<typename T>
+void MeshDataImpl<T>::clamp(Real vmin, Real vmax) {
+ knMdataClamp<T> op( *this, vmin, vmax );
+}
+
+template<typename T>
+void MeshDataImpl<T>::clampMin(Real vmin) {
+ knMdataClampMin<T> op( *this, vmin );
+}
+template<typename T>
+void MeshDataImpl<T>::clampMax(Real vmax) {
+ knMdataClampMax<T> op( *this, vmax );
+}
+
+template<>
+void MeshDataImpl<Vec3>::clampMin(Real vmin) {
+ knMdataClampMinVec3 op( *this, vmin );
+}
+template<>
+void MeshDataImpl<Vec3>::clampMax(Real vmax) {
+ knMdataClampMaxVec3 op( *this, vmax );
+}
+
+template<typename T> struct KnPtsSum : public KernelBase {
+ KnPtsSum(const MeshDataImpl<T>& val, const MeshDataImpl<int> *t, const int itype) : KernelBase(val.size()) ,val(val),t(t),itype(itype) ,result(T(0.)) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<T>& val, const MeshDataImpl<int> *t, const int itype ,T& result) { if(t && !((*t)[idx]&itype)) return; result += val[idx]; } inline operator T () {
+ return result; }
+ inline T & getRet() {
+ return result; }
+ inline const MeshDataImpl<T>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<T> type0;inline const MeshDataImpl<int> * getArg1() {
+ return t; }
+ typedef MeshDataImpl<int> type1;inline const int& getArg2() {
+ return itype; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel KnPtsSum ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,t,itype,result); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ KnPtsSum (KnPtsSum& o, tbb::split) : KernelBase(o) ,val(o.val),t(o.t),itype(o.itype) ,result(T(0.)) {
+}
+ void join(const KnPtsSum & o) {
+ result += o.result; }
+ const MeshDataImpl<T>& val; const MeshDataImpl<int> * t; const int itype; T result; }
+;
+template<typename T> struct KnPtsSumSquare : public KernelBase {
+ KnPtsSumSquare(const MeshDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,result(0.) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<T>& val ,Real& result) { result += normSquare(val[idx]); } inline operator Real () {
+ return result; }
+ inline Real & getRet() {
+ return result; }
+ inline const MeshDataImpl<T>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<T> type0; void runMessage() { debMsg("Executing kernel KnPtsSumSquare ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,result); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ KnPtsSumSquare (KnPtsSumSquare& o, tbb::split) : KernelBase(o) ,val(o.val) ,result(0.) {
+}
+ void join(const KnPtsSumSquare & o) {
+ result += o.result; }
+ const MeshDataImpl<T>& val; Real result; }
+;
+template<typename T> struct KnPtsSumMagnitude : public KernelBase {
+ KnPtsSumMagnitude(const MeshDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,result(0.) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<T>& val ,Real& result) { result += norm(val[idx]); } inline operator Real () {
+ return result; }
+ inline Real & getRet() {
+ return result; }
+ inline const MeshDataImpl<T>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<T> type0; void runMessage() { debMsg("Executing kernel KnPtsSumMagnitude ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,result); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ KnPtsSumMagnitude (KnPtsSumMagnitude& o, tbb::split) : KernelBase(o) ,val(o.val) ,result(0.) {
+}
+ void join(const KnPtsSumMagnitude & o) {
+ result += o.result; }
+ const MeshDataImpl<T>& val; Real result; }
+;
+
+template<typename T>
+T MeshDataImpl<T>::sum(const MeshDataImpl<int> *t, const int itype) const {
+ return KnPtsSum<T>(*this, t, itype);
+}
+template<typename T>
+Real MeshDataImpl<T>::sumSquare() const {
+ return KnPtsSumSquare<T>(*this);
+}
+template<typename T>
+Real MeshDataImpl<T>::sumMagnitude() const {
+ return KnPtsSumMagnitude<T>(*this);
+}
+
+template<typename T>
+
+ struct CompMdata_Min : public KernelBase {
+ CompMdata_Min(const MeshDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<T>& val ,Real& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const MeshDataImpl<T>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<T> type0; void runMessage() { debMsg("Executing kernel CompMdata_Min ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,minVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompMdata_Min (CompMdata_Min& o, tbb::split) : KernelBase(o) ,val(o.val) ,minVal(std::numeric_limits<Real>::max()) {
+}
+ void join(const CompMdata_Min & o) {
+ minVal = min(minVal,o.minVal); }
+ const MeshDataImpl<T>& val; Real minVal; }
+;
+
+template<typename T>
+
+ struct CompMdata_Max : public KernelBase {
+ CompMdata_Max(const MeshDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<T>& val ,Real& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const MeshDataImpl<T>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<T> type0; void runMessage() { debMsg("Executing kernel CompMdata_Max ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,maxVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompMdata_Max (CompMdata_Max& o, tbb::split) : KernelBase(o) ,val(o.val) ,maxVal(-std::numeric_limits<Real>::max()) {
+}
+ void join(const CompMdata_Max & o) {
+ maxVal = max(maxVal,o.maxVal); }
+ const MeshDataImpl<T>& val; Real maxVal; }
+;
+
+template<typename T>
+Real MeshDataImpl<T>::getMin() {
+ return CompMdata_Min<T> (*this);
+}
+
+template<typename T>
+Real MeshDataImpl<T>::getMaxAbs() {
+ Real amin = CompMdata_Min<T> (*this);
+ Real amax = CompMdata_Max<T> (*this);
+ return max( fabs(amin), fabs(amax));
+}
+
+template<typename T>
+Real MeshDataImpl<T>::getMax() {
+ return CompMdata_Max<T> (*this);
+}
+
+template<typename T>
+void MeshDataImpl<T>::printMdata(IndexInt start, IndexInt stop, bool printIndex)
+{
+ std::ostringstream sstr;
+ IndexInt s = (start>0 ? start : 0 );
+ IndexInt e = (stop>0 ? stop : (IndexInt)mData.size() );
+ s = Manta::clamp(s, (IndexInt)0, (IndexInt)mData.size());
+ e = Manta::clamp(e, (IndexInt)0, (IndexInt)mData.size());
+
+ for(IndexInt i=s; i<e; ++i) {
+ if(printIndex) sstr << i<<": ";
+ sstr<<mData[i]<<" "<<"\n";
+ }
+ debMsg( sstr.str() , 1 );
+}
+template<class T> std::string MeshDataImpl<T>::getDataPointer() {
+ std::ostringstream out;
+ out << &mData;
+ return out.str();
+}
+
+// specials for vec3
+// work on length values, ie, always positive (in contrast to scalar versions above)
+
+
+ struct CompMdata_MinVec3 : public KernelBase {
+ CompMdata_MinVec3(const MeshDataImpl<Vec3>& val) : KernelBase(val.size()) ,val(val) ,minVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<Vec3>& val ,Real& minVal) {
+ const Real s = normSquare(val[idx]);
+ if (s < minVal)
+ minVal = s;
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const MeshDataImpl<Vec3>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<Vec3> type0; void runMessage() { debMsg("Executing kernel CompMdata_MinVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,minVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompMdata_MinVec3 (CompMdata_MinVec3& o, tbb::split) : KernelBase(o) ,val(o.val) ,minVal(-std::numeric_limits<Real>::max()) {
+}
+ void join(const CompMdata_MinVec3 & o) {
+ minVal = min(minVal,o.minVal); }
+ const MeshDataImpl<Vec3>& val; Real minVal; }
+;
+
+
+ struct CompMdata_MaxVec3 : public KernelBase {
+ CompMdata_MaxVec3(const MeshDataImpl<Vec3>& val) : KernelBase(val.size()) ,val(val) ,maxVal(-std::numeric_limits<Real>::min()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const MeshDataImpl<Vec3>& val ,Real& maxVal) {
+ const Real s = normSquare(val[idx]);
+ if (s > maxVal)
+ maxVal = s;
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const MeshDataImpl<Vec3>& getArg0() {
+ return val; }
+ typedef MeshDataImpl<Vec3> type0; void runMessage() { debMsg("Executing kernel CompMdata_MaxVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,maxVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompMdata_MaxVec3 (CompMdata_MaxVec3& o, tbb::split) : KernelBase(o) ,val(o.val) ,maxVal(-std::numeric_limits<Real>::min()) {
+}
+ void join(const CompMdata_MaxVec3 & o) {
+ maxVal = max(maxVal,o.maxVal); }
+ const MeshDataImpl<Vec3>& val; Real maxVal; }
+;
+
+template<>
+Real MeshDataImpl<Vec3>::getMin() {
+ return sqrt(CompMdata_MinVec3 (*this));
+}
+
+template<>
+Real MeshDataImpl<Vec3>::getMaxAbs() {
+ return sqrt(CompMdata_MaxVec3 (*this)); // no minimum necessary here
+}
+
+template<>
+Real MeshDataImpl<Vec3>::getMax() {
+ return sqrt(CompMdata_MaxVec3 (*this));
+}
+
+
+// explicit instantiation
+template class MeshDataImpl<int>;
+template class MeshDataImpl<Real>;
+template class MeshDataImpl<Vec3>;
+
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h
new file mode 100644
index 00000000000..f7cbd416769
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h
@@ -0,0 +1,767 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Meshes
+ *
+ * note: this is only a temporary solution, details are bound to change
+ * long term goal is integration with Split&Merge code by Wojtan et al.
+ *
+ ******************************************************************************/
+
+#ifndef _MESH_H
+#define _MESH_H
+
+#include <vector>
+#include "manta.h"
+#include "vectorbase.h"
+#include <set>
+#include "levelset.h"
+
+namespace Manta {
+
+// fwd decl
+class GridBase;
+//class LevelsetGrid;
+class FlagGrid;
+class MACGrid;
+class Shape;
+class MeshDataBase;
+template<class T> class MeshDataImpl;
+
+
+//! Node position and flags
+struct Node {
+ Node() : flags(0), pos(Vec3::Zero), normal(Vec3::Zero) {}
+ Node(const Vec3& p) : flags(0), pos(p) {}
+ int flags;
+ Vec3 pos, normal;
+};
+
+//! Carries indices of its nodes
+struct Triangle {
+ Triangle() : flags(0) { c[0] = c[1] = c[2] = 0; }
+ Triangle(int n0, int n1, int n2) : flags(0) { c[0]=n0; c[1]=n1; c[2]=n2; }
+
+ int c[3];
+ int flags;
+};
+
+//! For fast access to nodes and neighboring triangles
+struct Corner {
+ Corner() : tri(-1), node(-1), opposite(-1), next(-1), prev(-1) {};
+ Corner(int t, int n) : tri(t), node(n), opposite(-1), next(-1), prev(-1) {}
+
+ int tri;
+ int node;
+ int opposite;
+ int next;
+ int prev;
+};
+
+//! Base class for mesh data channels (texture coords, vorticity, ...)
+struct NodeChannel {
+ virtual ~NodeChannel() {};
+ virtual void resize(int num) = 0;
+ virtual int size() = 0;
+ virtual NodeChannel* clone() = 0;
+
+ virtual void addInterpol(int a, int b, Real alpha) = 0;
+ virtual void mergeWith(int node, int delnode, Real alpha) = 0;
+ virtual void renumber(const std::vector<int>& newIndex, int newsize) = 0;
+};
+
+//! Node channel using only a vector
+template<class T>
+struct SimpleNodeChannel : public NodeChannel {
+ SimpleNodeChannel() {};
+ SimpleNodeChannel(const SimpleNodeChannel<T>& a) : data(a.data) {}
+ void resize(int num) { data.resize(num); }
+ virtual int size() { return data.size(); }
+ virtual void renumber(const std::vector<int>& newIndex, int newsize);
+
+ //virtual void addSplit(int from, Real alpha) { data.push_back(data[from]); }
+
+ std::vector<T> data;
+};
+
+//! Base class for mesh data channels (texture coords, vorticity, ...)
+struct TriChannel {
+ virtual ~TriChannel() {};
+ virtual void resize(int num) = 0;
+ virtual TriChannel* clone() = 0;
+ virtual int size() = 0;
+
+ virtual void addNew() = 0;
+ virtual void addSplit(int from, Real alpha) = 0;
+ virtual void remove(int tri) = 0;
+};
+
+//! Tri channel using only a vector
+template<class T>
+struct SimpleTriChannel : public TriChannel {
+ SimpleTriChannel() {};
+ SimpleTriChannel(const SimpleTriChannel<T>& a) : data(a.data) {}
+ void resize(int num) { data.resize(num); }
+ void remove(int tri) { if (tri!=(int)data.size()-1) data[tri] = *data.rbegin(); data.pop_back(); }
+ virtual int size() { return data.size(); }
+
+ virtual void addSplit(int from, Real alpha) { data.push_back(data[from]); }
+ virtual void addNew() { data.push_back(T()); }
+
+ std::vector<T> data;
+};
+
+struct OneRing {
+ OneRing() {}
+ std::set<int> nodes;
+ std::set<int> tris;
+};
+
+//! Triangle mesh class
+/*! note: this is only a temporary solution, details are bound to change
+ long term goal is integration with Split&Merge code by Wojtan et al.*/
+class Mesh : public PbClass {public:
+ Mesh(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Mesh::Mesh" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new Mesh(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Mesh::Mesh" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::Mesh",e.what()); return -1; }
+ }
+
+ virtual ~Mesh();
+ virtual Mesh* clone();
+
+ enum NodeFlags { NfNone = 0, NfFixed = 1, NfMarked = 2, NfKillme = 4, NfCollide = 8 };
+ enum FaceFlags { FfNone = 0, FfDoubled = 1, FfMarked = 2 };
+ enum MeshType { TypeNormal = 0, TypeVortexSheet };
+
+ virtual MeshType getType() { return TypeNormal; }
+
+ Real computeCenterOfMass(Vec3& cm) const;
+ void computeVertexNormals();
+
+ // plugins
+ void clear(); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::clear",e.what()); return 0; }
+ }
+
+ void load(std::string name, bool append = false); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); bool append = _args.getOpt<bool >("append",1,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name,append); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::load",e.what()); return 0; }
+ }
+
+ void fromShape(Shape& shape, bool append = false); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::fromShape" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Shape& shape = *_args.getPtr<Shape >("shape",0,&_lock); bool append = _args.getOpt<bool >("append",1,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->fromShape(shape,append); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::fromShape" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::fromShape",e.what()); return 0; }
+ }
+
+ void save(std::string name); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::save",e.what()); return 0; }
+ }
+
+ void advectInGrid(FlagGrid& flags, MACGrid& vel, int integrationMode); static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::advectInGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); int integrationMode = _args.get<int >("integrationMode",2,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->advectInGrid(flags,vel,integrationMode); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::advectInGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::advectInGrid",e.what()); return 0; }
+ }
+
+ void scale(Vec3 s); static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::scale" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 s = _args.get<Vec3 >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->scale(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::scale" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::scale",e.what()); return 0; }
+ }
+
+ void offset(Vec3 o); static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::offset" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 o = _args.get<Vec3 >("o",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->offset(o); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::offset" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::offset",e.what()); return 0; }
+ }
+
+ void rotate(Vec3 thetas); static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::rotate" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 thetas = _args.get<Vec3 >("thetas",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->rotate(thetas); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::rotate" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::rotate",e.what()); return 0; }
+ }
+
+ void computeVelocity(Mesh& oldMesh, MACGrid& vel); static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::computeVelocity" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& oldMesh = *_args.getPtr<Mesh >("oldMesh",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->computeVelocity(oldMesh,vel); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::computeVelocity" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::computeVelocity",e.what()); return 0; }
+ }
+
+
+ void computeLevelset(LevelsetGrid& levelset, Real sigma, Real cutoff=-1.); static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::computeLevelset" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; LevelsetGrid& levelset = *_args.getPtr<LevelsetGrid >("levelset",0,&_lock); Real sigma = _args.get<Real >("sigma",1,&_lock); Real cutoff = _args.getOpt<Real >("cutoff",2,-1.,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->computeLevelset(levelset,sigma,cutoff); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::computeLevelset" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::computeLevelset",e.what()); return 0; }
+ }
+
+ LevelsetGrid getLevelset(Real sigma, Real cutoff = -1.); static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::getLevelset" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real sigma = _args.get<Real >("sigma",0,&_lock); Real cutoff = _args.getOpt<Real >("cutoff",1,-1.,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->getLevelset(sigma,cutoff)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::getLevelset" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::getLevelset",e.what()); return 0; }
+ }
+
+
+ //! map mesh to grid with sdf
+ void applyMeshToGrid(GridBase* grid, FlagGrid* respectFlags=0, Real cutoff=-1.); static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::applyMeshToGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; GridBase* grid = _args.getPtr<GridBase >("grid",0,&_lock); FlagGrid* respectFlags = _args.getPtrOpt<FlagGrid >("respectFlags",1,0,&_lock); Real cutoff = _args.getOpt<Real >("cutoff",2,-1.,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->applyMeshToGrid(grid,respectFlags,cutoff); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::applyMeshToGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::applyMeshToGrid",e.what()); return 0; }
+ }
+
+
+ //! get data pointer of nodes
+ std::string getNodesDataPointer(); static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::getNodesDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getNodesDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::getNodesDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::getNodesDataPointer",e.what()); return 0; }
+ }
+
+ //! get data pointer of tris
+ std::string getTrisDataPointer(); static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::getTrisDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getTrisDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::getTrisDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::getTrisDataPointer",e.what()); return 0; }
+ }
+
+
+ // ops
+ Mesh& operator=(const Mesh& o);
+
+ // accessors
+ inline int numTris() const { return mTris.size(); }
+ inline int numNodes() const { return mNodes.size(); }
+ inline int numTriChannels() const { return mTriChannels.size(); }
+ inline int numNodeChannels() const { return mNodeChannels.size(); }
+
+ //! return size of container
+ //! note , python binding disabled for now! cannot yet deal with long-long types
+ inline IndexInt size() const { return mNodes.size(); }
+ //! slow virtual function of base class, also returns size
+ virtual IndexInt getSizeSlow() const { return size(); }
+
+ inline Triangle& tris(int i) { return mTris[i]; }
+ inline Node& nodes(int i) { return mNodes[i]; }
+ inline Corner& corners(int tri, int c) { return mCorners[tri*3+c]; }
+ inline Corner& corners(int c) { return mCorners[c]; }
+ inline NodeChannel* nodeChannel(int i) { return mNodeChannels[i]; }
+ inline TriChannel* triChannel(int i) { return mTriChannels[i]; }
+
+ // allocate memory (eg upon load)
+ void resizeTris(int numTris);
+ void resizeNodes(int numNodes);
+
+ inline bool isNodeFixed(int n) { return mNodes[n].flags & NfFixed; }
+ inline bool isTriangleFixed(int t) { return (mNodes[mTris[t].c[0]].flags & NfFixed) || (mNodes[mTris[t].c[1]].flags & NfFixed) || (mNodes[mTris[t].c[2]].flags & NfFixed); }
+
+ inline const Vec3 getNode(int tri, int c) const { return mNodes[mTris[tri].c[c]].pos; }
+ inline Vec3& getNode(int tri, int c) { return mNodes[mTris[tri].c[c]].pos; }
+ inline const Vec3 getEdge(int tri, int e) const { return getNode(tri,(e+1)%3) - getNode(tri,e); }
+ inline OneRing& get1Ring(int node) { return m1RingLookup[node]; }
+ inline Real getFaceArea(int t) const { Vec3 c0 = mNodes[mTris[t].c[0]].pos; return 0.5*norm(cross(mNodes[mTris[t].c[1]].pos - c0, mNodes[mTris[t].c[2]].pos - c0)); }
+ inline Vec3 getFaceNormal(int t) { Vec3 c0 = mNodes[mTris[t].c[0]].pos; return getNormalized(cross(mNodes[mTris[t].c[1]].pos - c0, mNodes[mTris[t].c[2]].pos - c0)); }
+ inline Vec3 getFaceCenter(int t) const { return (mNodes[mTris[t].c[0]].pos + mNodes[mTris[t].c[1]].pos + mNodes[mTris[t].c[2]].pos) / 3.0; }
+ inline std::vector<Node>& getNodeData() { return mNodes; }
+
+ void mergeNode(int node, int delnode);
+ int addNode(Node a);
+ int addTri(Triangle a);
+ void addCorner(Corner a);
+ void removeTri(int tri);
+ void removeTriFromLookup(int tri);
+ void removeNodes(const std::vector<int>& deletedNodes);
+ void rebuildCorners(int from=0, int to=-1);
+ void rebuildLookup(int from=0, int to=-1);
+ void rebuildQuickCheck();
+ void fastNodeLookupRebuild(int corner);
+ void sanityCheck(bool strict=true, std::vector<int>* deletedNodes=0, std::map<int,bool>* taintedTris=0);
+
+ void addTriChannel(TriChannel* c) { mTriChannels.push_back(c); rebuildChannels(); }
+ void addNodeChannel(NodeChannel* c) { mNodeChannels.push_back(c); rebuildChannels(); }
+
+ //! mesh data functions
+
+ //! create a mesh data object
+ PbClass* create(PbType type, PbTypeVec T=PbTypeVec(), const std::string& name = ""); static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Mesh::create" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; PbType type = _args.get<PbType >("type",0,&_lock); PbTypeVec T = _args.getOpt<PbTypeVec >("T",1,PbTypeVec(),&_lock); const std::string& name = _args.getOpt<std::string >("name",2,"",&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->create(type,T,name)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Mesh::create" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Mesh::create",e.what()); return 0; }
+ }
+
+ //! add a mesh data field, set its parent mesh pointer
+ void registerMdata(MeshDataBase* mdata);
+ void registerMdataReal(MeshDataImpl<Real>* mdata);
+ void registerMdataVec3(MeshDataImpl<Vec3>* mdata);
+ void registerMdataInt (MeshDataImpl<int >* mdata);
+ //! remove a mesh data entry
+ void deregister(MeshDataBase* mdata);
+ //! add one zero entry to all data fields
+ void addAllMdata();
+ // note - deletion of mdata is handled in compress function
+
+ //! how many are there?
+ IndexInt getNumMdata() const { return mMeshData.size(); }
+ //! access one of the fields
+ MeshDataBase* getMdata(int i) { return mMeshData[i]; }
+
+ //! update data fields
+ void updateDataFields();
+
+protected:
+ void rebuildChannels();
+
+ std::vector<Node> mNodes;
+ std::vector<Triangle> mTris;
+ std::vector<Corner> mCorners;
+ std::vector<NodeChannel*> mNodeChannels;
+ std::vector<TriChannel*> mTriChannels;
+ std::vector<OneRing> m1RingLookup;
+
+ //! store mesh data , each pointer has its own storage vector of a certain type (int, real, vec3)
+ std::vector<MeshDataBase*> mMeshData;
+ //! lists of different types, for fast operations w/o virtual function calls
+ std::vector< MeshDataImpl<Real> *> mMdataReal;
+ std::vector< MeshDataImpl<Vec3> *> mMdataVec3;
+ std::vector< MeshDataImpl<int> *> mMdataInt; //! indicate that mdata of this mesh is copied, and needs to be freed
+ bool mFreeMdata; public: PbArgs _args; }
+#define _C_Mesh
+;
+
+//******************************************************************************
+
+//! abstract interface for mesh data
+class MeshDataBase : public PbClass {public:
+ MeshDataBase(FluidSolver* parent); static int _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "MeshDataBase::MeshDataBase" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new MeshDataBase(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"MeshDataBase::MeshDataBase" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataBase::MeshDataBase",e.what()); return -1; }
+ }
+
+ virtual ~MeshDataBase();
+
+ //! data type IDs, in line with those for grids
+ enum MdataType { TypeNone = 0, TypeReal = 1, TypeInt = 2, TypeVec3 = 4 };
+
+ //! interface functions, using assert instead of pure virtual for python compatibility
+ virtual IndexInt getSizeSlow() const { assertMsg( false , "Dont use, override..."); return 0; }
+ virtual void addEntry() { assertMsg( false , "Dont use, override..."); return; }
+ virtual MeshDataBase* clone() { assertMsg( false , "Dont use, override..."); return NULL; }
+ virtual MdataType getType() const { assertMsg( false , "Dont use, override..."); return TypeNone; }
+ virtual void resize(IndexInt size) { assertMsg( false , "Dont use, override..."); return; }
+ virtual void copyValueSlow(IndexInt from, IndexInt to) { assertMsg( false , "Dont use, override..."); return; }
+
+ //! set base pointer
+ void setMesh(Mesh* set) { mMesh = set; }
+
+ //! debugging
+ inline void checkNodeIndex(IndexInt idx) const;
+
+protected: Mesh* mMesh; public: PbArgs _args; }
+#define _C_MeshDataBase
+;
+
+
+//! abstract interface for mesh data
+
+template<class T> class MeshDataImpl : public MeshDataBase {public:
+ MeshDataImpl(FluidSolver* parent); static int _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "MeshDataImpl::MeshDataImpl" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new MeshDataImpl(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"MeshDataImpl::MeshDataImpl" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::MeshDataImpl",e.what()); return -1; }
+ }
+
+ MeshDataImpl(FluidSolver* parent, MeshDataImpl<T>* other);
+ virtual ~MeshDataImpl();
+
+ //! access data
+ inline T& get(IndexInt idx) { DEBUG_ONLY(checkNodeIndex(idx)); return mData[idx]; }
+ inline const T& get(IndexInt idx) const { DEBUG_ONLY(checkNodeIndex(idx)); return mData[idx]; }
+ inline T& operator[](IndexInt idx) { DEBUG_ONLY(checkNodeIndex(idx)); return mData[idx]; }
+ inline const T& operator[](IndexInt idx) const { DEBUG_ONLY(checkNodeIndex(idx)); return mData[idx]; }
+
+ //! set all values to 0, note - different from meshSystem::clear! doesnt modify size of array (has to stay in sync with parent system)
+ void clear(); static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::clear",e.what()); return 0; }
+ }
+
+
+ //! set grid from which to get data...
+ void setSource(Grid<T>* grid, bool isMAC=false ); static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setSource" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<T>* grid = _args.getPtr<Grid<T> >("grid",0,&_lock); bool isMAC = _args.getOpt<bool >("isMAC",1,false ,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setSource(grid,isMAC); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::setSource" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::setSource",e.what()); return 0; }
+ }
+
+
+ //! mesh data base interface
+ virtual IndexInt getSizeSlow() const;
+ virtual void addEntry();
+ virtual MeshDataBase* clone();
+ virtual MdataType getType() const;
+ virtual void resize(IndexInt s);
+ virtual void copyValueSlow(IndexInt from, IndexInt to);
+
+ IndexInt size() const { return mData.size(); }
+
+ //! fast inlined functions for per mesh operations
+ inline void copyValue(IndexInt from, IndexInt to) { get(to) = get(from); }
+ void initNewValue(IndexInt idx, Vec3 pos);
+
+ //! python interface (similar to grid data)
+ void setConst(T s); static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::setConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::setConst",e.what()); return 0; }
+ }
+
+ void setConstRange(T s, const int begin, const int end); static PyObject* _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setConstRange" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); const int begin = _args.get<int >("begin",1,&_lock); const int end = _args.get<int >("end",2,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConstRange(s,begin,end); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::setConstRange" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::setConstRange",e.what()); return 0; }
+ }
+
+ MeshDataImpl<T>& copyFrom(const MeshDataImpl<T>& a); static PyObject* _W_22 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::copyFrom" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->copyFrom(a)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::copyFrom" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::copyFrom",e.what()); return 0; }
+ }
+
+ void add(const MeshDataImpl<T>& a); static PyObject* _W_23 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::add" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->add(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::add" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::add",e.what()); return 0; }
+ }
+
+ void sub(const MeshDataImpl<T>& a); static PyObject* _W_24 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sub" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->sub(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::sub" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::sub",e.what()); return 0; }
+ }
+
+ void addConst(T s); static PyObject* _W_25 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::addConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::addConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::addConst",e.what()); return 0; }
+ }
+
+ void addScaled(const MeshDataImpl<T>& a, const T& factor); static PyObject* _W_26 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::addScaled" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); const T& factor = *_args.getPtr<T >("factor",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addScaled(a,factor); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::addScaled" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::addScaled",e.what()); return 0; }
+ }
+
+ void mult( const MeshDataImpl<T>& a); static PyObject* _W_27 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::mult" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->mult(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::mult" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::mult",e.what()); return 0; }
+ }
+
+ void multConst(T s); static PyObject* _W_28 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::multConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->multConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::multConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::multConst",e.what()); return 0; }
+ }
+
+ void safeDiv(const MeshDataImpl<T>& a); static PyObject* _W_29 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::safeDiv" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<T>& a = *_args.getPtr<MeshDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->safeDiv(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::safeDiv" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::safeDiv",e.what()); return 0; }
+ }
+
+ void clamp(Real min, Real max); static PyObject* _W_30 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clamp" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real min = _args.get<Real >("min",0,&_lock); Real max = _args.get<Real >("max",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clamp(min,max); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::clamp" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::clamp",e.what()); return 0; }
+ }
+
+ void clampMin(Real vmin); static PyObject* _W_31 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clampMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real vmin = _args.get<Real >("vmin",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clampMin(vmin); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::clampMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::clampMin",e.what()); return 0; }
+ }
+
+ void clampMax(Real vmax); static PyObject* _W_32 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::clampMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real vmax = _args.get<Real >("vmax",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clampMax(vmax); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::clampMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::clampMax",e.what()); return 0; }
+ }
+
+
+ Real getMaxAbs(); static PyObject* _W_33 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getMaxAbs" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxAbs()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::getMaxAbs" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::getMaxAbs",e.what()); return 0; }
+ }
+
+ Real getMax(); static PyObject* _W_34 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMax()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::getMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::getMax",e.what()); return 0; }
+ }
+
+ Real getMin(); static PyObject* _W_35 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMin()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::getMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::getMin",e.what()); return 0; }
+ }
+
+
+ T sum(const MeshDataImpl<int> *t=NULL, const int itype=0) const ; static PyObject* _W_36 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sum" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const MeshDataImpl<int> * t = _args.getPtrOpt<MeshDataImpl<int> >("t",0,NULL,&_lock); const int itype = _args.getOpt<int >("itype",1,0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->sum(t,itype)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::sum" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::sum",e.what()); return 0; }
+ }
+
+ Real sumSquare() const ; static PyObject* _W_37 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sumSquare" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->sumSquare()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::sumSquare" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::sumSquare",e.what()); return 0; }
+ }
+
+ Real sumMagnitude() const ; static PyObject* _W_38 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::sumMagnitude" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->sumMagnitude()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::sumMagnitude" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::sumMagnitude",e.what()); return 0; }
+ }
+
+
+ //! special, set if int flag in t has "flag"
+ void setConstIntFlag(T s, const MeshDataImpl<int>& t, const int flag); static PyObject* _W_39 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::setConstIntFlag" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; T s = _args.get<T >("s",0,&_lock); const MeshDataImpl<int>& t = *_args.getPtr<MeshDataImpl<int> >("t",1,&_lock); const int flag = _args.get<int >("flag",2,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConstIntFlag(s,t,flag); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::setConstIntFlag" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::setConstIntFlag",e.what()); return 0; }
+ }
+
+
+ void printMdata(IndexInt start=-1, IndexInt stop=-1, bool printIndex=false); static PyObject* _W_40 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::printMdata" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; IndexInt start = _args.getOpt<IndexInt >("start",0,-1,&_lock); IndexInt stop = _args.getOpt<IndexInt >("stop",1,-1,&_lock); bool printIndex = _args.getOpt<bool >("printIndex",2,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->printMdata(start,stop,printIndex); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::printMdata" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::printMdata",e.what()); return 0; }
+ }
+
+
+ //! file io
+ void save(const std::string name); static PyObject* _W_41 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::save",e.what()); return 0; }
+ }
+
+ void load(const std::string name); static PyObject* _W_42 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::load",e.what()); return 0; }
+ }
+
+
+ //! get data pointer of mesh data
+ std::string getDataPointer(); static PyObject* _W_43 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MeshDataImpl* pbo = dynamic_cast<MeshDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MeshDataImpl::getDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MeshDataImpl::getDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MeshDataImpl::getDataPointer",e.what()); return 0; }
+ }
+
+protected:
+ //! data storage
+ std::vector<T> mData;
+
+ //! optionally , we might have an associated grid from which to grab new data
+ Grid<T>* mpGridSource; //! unfortunately , we need to distinguish mac vs regular vec3
+ bool mGridSourceMAC; public: PbArgs _args; }
+#define _C_MeshDataImpl
+;
+
+
+
+
+
+
+// ***************************************************************************************************************
+// Implementation
+
+template<class T>
+void SimpleNodeChannel<T>::renumber(const std::vector<int>& newIndex, int newsize) {
+ for(size_t i=0; i<newIndex.size(); i++) {
+ if(newIndex[i]!=-1)
+ data[newIndex[i]] = data[newsize+i];
+ }
+ data.resize(newsize);
+}
+
+inline void MeshDataBase::checkNodeIndex(IndexInt idx) const {
+ IndexInt mySize = this->getSizeSlow();
+ if (idx<0 || idx > mySize ) {
+ errMsg( "MeshData " << " size " << mySize << " : index " << idx << " out of bound " );
+ }
+ if ( mMesh && mMesh->getSizeSlow()!=mySize ) {
+ errMsg( "MeshData " << " size " << mySize << " does not match parent! (" << mMesh->getSizeSlow() << ") " );
+ }
+}
+
+template<class T>
+void MeshDataImpl<T>::clear() {
+ for(IndexInt i=0; i<(IndexInt)mData.size(); ++i) mData[i] = 0.;
+}
+
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h.reg
new file mode 100644
index 00000000000..41e012f5d5b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h.reg
@@ -0,0 +1,56 @@
+#include "mesh.h"
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","Mesh","PbClass"); template<> const char* Namify<Mesh >::S = "Mesh";
+>Mesh^
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","Mesh",Mesh::_W_0);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","clear",Mesh::_W_1);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","load",Mesh::_W_2);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","fromShape",Mesh::_W_3);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","save",Mesh::_W_4);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","advectInGrid",Mesh::_W_5);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","scale",Mesh::_W_6);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","offset",Mesh::_W_7);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","rotate",Mesh::_W_8);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","computeVelocity",Mesh::_W_9);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","computeLevelset",Mesh::_W_10);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","getLevelset",Mesh::_W_11);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","applyMeshToGrid",Mesh::_W_12);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","getNodesDataPointer",Mesh::_W_13);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","getTrisDataPointer",Mesh::_W_14);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","create",Mesh::_W_15);
++MeshDataBase^ static const Pb::Register _R_$IDX$ ("MeshDataBase","MeshDataBase","PbClass"); template<> const char* Namify<MeshDataBase >::S = "MeshDataBase";
+>MeshDataBase^
++MeshDataBase^ static const Pb::Register _R_$IDX$ ("MeshDataBase","MeshDataBase",MeshDataBase::_W_16);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","MeshDataImpl<$CT$>","MeshDataBase"); template<> const char* Namify<MeshDataImpl<$CT$> >::S = "MeshDataImpl<$CT$>";
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","MeshDataImpl",MeshDataImpl<$CT$>::_W_17);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","clear",MeshDataImpl<$CT$>::_W_18);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","setSource",MeshDataImpl<$CT$>::_W_19);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","setConst",MeshDataImpl<$CT$>::_W_20);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","setConstRange",MeshDataImpl<$CT$>::_W_21);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","copyFrom",MeshDataImpl<$CT$>::_W_22);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","add",MeshDataImpl<$CT$>::_W_23);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","sub",MeshDataImpl<$CT$>::_W_24);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","addConst",MeshDataImpl<$CT$>::_W_25);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","addScaled",MeshDataImpl<$CT$>::_W_26);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","mult",MeshDataImpl<$CT$>::_W_27);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","multConst",MeshDataImpl<$CT$>::_W_28);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","safeDiv",MeshDataImpl<$CT$>::_W_29);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","clamp",MeshDataImpl<$CT$>::_W_30);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","clampMin",MeshDataImpl<$CT$>::_W_31);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","clampMax",MeshDataImpl<$CT$>::_W_32);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","getMaxAbs",MeshDataImpl<$CT$>::_W_33);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","getMax",MeshDataImpl<$CT$>::_W_34);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","getMin",MeshDataImpl<$CT$>::_W_35);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","sum",MeshDataImpl<$CT$>::_W_36);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","sumSquare",MeshDataImpl<$CT$>::_W_37);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","sumMagnitude",MeshDataImpl<$CT$>::_W_38);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","setConstIntFlag",MeshDataImpl<$CT$>::_W_39);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","printMdata",MeshDataImpl<$CT$>::_W_40);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","save",MeshDataImpl<$CT$>::_W_41);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","load",MeshDataImpl<$CT$>::_W_42);
++MeshDataImpl^ static const Pb::Register _R_$IDX$ ("MeshDataImpl<$CT$>","getDataPointer",MeshDataImpl<$CT$>::_W_43);
+>MeshDataImpl^int
+&static const Pb::Register _R_$IDX$ ("MeshDataImpl<int>","MdataInt","");
+>MeshDataImpl^Real
+&static const Pb::Register _R_$IDX$ ("MeshDataImpl<Real>","MdataReal","");
+>MeshDataImpl^Vec3
+&static const Pb::Register _R_$IDX$ ("MeshDataImpl<Vec3>","MdataVec3","");
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h.reg.cpp
new file mode 100644
index 00000000000..74b3935f01b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/mesh.h.reg.cpp
@@ -0,0 +1,233 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "mesh.h"
+namespace Manta {
+#ifdef _C_Mesh
+ static const Pb::Register _R_12 ("Mesh","Mesh","PbClass"); template<> const char* Namify<Mesh >::S = "Mesh";
+ static const Pb::Register _R_13 ("Mesh","Mesh",Mesh::_W_0);
+ static const Pb::Register _R_14 ("Mesh","clear",Mesh::_W_1);
+ static const Pb::Register _R_15 ("Mesh","load",Mesh::_W_2);
+ static const Pb::Register _R_16 ("Mesh","fromShape",Mesh::_W_3);
+ static const Pb::Register _R_17 ("Mesh","save",Mesh::_W_4);
+ static const Pb::Register _R_18 ("Mesh","advectInGrid",Mesh::_W_5);
+ static const Pb::Register _R_19 ("Mesh","scale",Mesh::_W_6);
+ static const Pb::Register _R_20 ("Mesh","offset",Mesh::_W_7);
+ static const Pb::Register _R_21 ("Mesh","rotate",Mesh::_W_8);
+ static const Pb::Register _R_22 ("Mesh","computeVelocity",Mesh::_W_9);
+ static const Pb::Register _R_23 ("Mesh","computeLevelset",Mesh::_W_10);
+ static const Pb::Register _R_24 ("Mesh","getLevelset",Mesh::_W_11);
+ static const Pb::Register _R_25 ("Mesh","applyMeshToGrid",Mesh::_W_12);
+ static const Pb::Register _R_26 ("Mesh","getNodesDataPointer",Mesh::_W_13);
+ static const Pb::Register _R_27 ("Mesh","getTrisDataPointer",Mesh::_W_14);
+ static const Pb::Register _R_28 ("Mesh","create",Mesh::_W_15);
+#endif
+#ifdef _C_MeshDataBase
+ static const Pb::Register _R_29 ("MeshDataBase","MeshDataBase","PbClass"); template<> const char* Namify<MeshDataBase >::S = "MeshDataBase";
+ static const Pb::Register _R_30 ("MeshDataBase","MeshDataBase",MeshDataBase::_W_16);
+#endif
+#ifdef _C_MeshDataImpl
+ static const Pb::Register _R_31 ("MeshDataImpl<int>","MeshDataImpl<int>","MeshDataBase"); template<> const char* Namify<MeshDataImpl<int> >::S = "MeshDataImpl<int>";
+ static const Pb::Register _R_32 ("MeshDataImpl<int>","MeshDataImpl",MeshDataImpl<int>::_W_17);
+ static const Pb::Register _R_33 ("MeshDataImpl<int>","clear",MeshDataImpl<int>::_W_18);
+ static const Pb::Register _R_34 ("MeshDataImpl<int>","setSource",MeshDataImpl<int>::_W_19);
+ static const Pb::Register _R_35 ("MeshDataImpl<int>","setConst",MeshDataImpl<int>::_W_20);
+ static const Pb::Register _R_36 ("MeshDataImpl<int>","setConstRange",MeshDataImpl<int>::_W_21);
+ static const Pb::Register _R_37 ("MeshDataImpl<int>","copyFrom",MeshDataImpl<int>::_W_22);
+ static const Pb::Register _R_38 ("MeshDataImpl<int>","add",MeshDataImpl<int>::_W_23);
+ static const Pb::Register _R_39 ("MeshDataImpl<int>","sub",MeshDataImpl<int>::_W_24);
+ static const Pb::Register _R_40 ("MeshDataImpl<int>","addConst",MeshDataImpl<int>::_W_25);
+ static const Pb::Register _R_41 ("MeshDataImpl<int>","addScaled",MeshDataImpl<int>::_W_26);
+ static const Pb::Register _R_42 ("MeshDataImpl<int>","mult",MeshDataImpl<int>::_W_27);
+ static const Pb::Register _R_43 ("MeshDataImpl<int>","multConst",MeshDataImpl<int>::_W_28);
+ static const Pb::Register _R_44 ("MeshDataImpl<int>","safeDiv",MeshDataImpl<int>::_W_29);
+ static const Pb::Register _R_45 ("MeshDataImpl<int>","clamp",MeshDataImpl<int>::_W_30);
+ static const Pb::Register _R_46 ("MeshDataImpl<int>","clampMin",MeshDataImpl<int>::_W_31);
+ static const Pb::Register _R_47 ("MeshDataImpl<int>","clampMax",MeshDataImpl<int>::_W_32);
+ static const Pb::Register _R_48 ("MeshDataImpl<int>","getMaxAbs",MeshDataImpl<int>::_W_33);
+ static const Pb::Register _R_49 ("MeshDataImpl<int>","getMax",MeshDataImpl<int>::_W_34);
+ static const Pb::Register _R_50 ("MeshDataImpl<int>","getMin",MeshDataImpl<int>::_W_35);
+ static const Pb::Register _R_51 ("MeshDataImpl<int>","sum",MeshDataImpl<int>::_W_36);
+ static const Pb::Register _R_52 ("MeshDataImpl<int>","sumSquare",MeshDataImpl<int>::_W_37);
+ static const Pb::Register _R_53 ("MeshDataImpl<int>","sumMagnitude",MeshDataImpl<int>::_W_38);
+ static const Pb::Register _R_54 ("MeshDataImpl<int>","setConstIntFlag",MeshDataImpl<int>::_W_39);
+ static const Pb::Register _R_55 ("MeshDataImpl<int>","printMdata",MeshDataImpl<int>::_W_40);
+ static const Pb::Register _R_56 ("MeshDataImpl<int>","save",MeshDataImpl<int>::_W_41);
+ static const Pb::Register _R_57 ("MeshDataImpl<int>","load",MeshDataImpl<int>::_W_42);
+ static const Pb::Register _R_58 ("MeshDataImpl<int>","getDataPointer",MeshDataImpl<int>::_W_43);
+ static const Pb::Register _R_59 ("MeshDataImpl<Real>","MeshDataImpl<Real>","MeshDataBase"); template<> const char* Namify<MeshDataImpl<Real> >::S = "MeshDataImpl<Real>";
+ static const Pb::Register _R_60 ("MeshDataImpl<Real>","MeshDataImpl",MeshDataImpl<Real>::_W_17);
+ static const Pb::Register _R_61 ("MeshDataImpl<Real>","clear",MeshDataImpl<Real>::_W_18);
+ static const Pb::Register _R_62 ("MeshDataImpl<Real>","setSource",MeshDataImpl<Real>::_W_19);
+ static const Pb::Register _R_63 ("MeshDataImpl<Real>","setConst",MeshDataImpl<Real>::_W_20);
+ static const Pb::Register _R_64 ("MeshDataImpl<Real>","setConstRange",MeshDataImpl<Real>::_W_21);
+ static const Pb::Register _R_65 ("MeshDataImpl<Real>","copyFrom",MeshDataImpl<Real>::_W_22);
+ static const Pb::Register _R_66 ("MeshDataImpl<Real>","add",MeshDataImpl<Real>::_W_23);
+ static const Pb::Register _R_67 ("MeshDataImpl<Real>","sub",MeshDataImpl<Real>::_W_24);
+ static const Pb::Register _R_68 ("MeshDataImpl<Real>","addConst",MeshDataImpl<Real>::_W_25);
+ static const Pb::Register _R_69 ("MeshDataImpl<Real>","addScaled",MeshDataImpl<Real>::_W_26);
+ static const Pb::Register _R_70 ("MeshDataImpl<Real>","mult",MeshDataImpl<Real>::_W_27);
+ static const Pb::Register _R_71 ("MeshDataImpl<Real>","multConst",MeshDataImpl<Real>::_W_28);
+ static const Pb::Register _R_72 ("MeshDataImpl<Real>","safeDiv",MeshDataImpl<Real>::_W_29);
+ static const Pb::Register _R_73 ("MeshDataImpl<Real>","clamp",MeshDataImpl<Real>::_W_30);
+ static const Pb::Register _R_74 ("MeshDataImpl<Real>","clampMin",MeshDataImpl<Real>::_W_31);
+ static const Pb::Register _R_75 ("MeshDataImpl<Real>","clampMax",MeshDataImpl<Real>::_W_32);
+ static const Pb::Register _R_76 ("MeshDataImpl<Real>","getMaxAbs",MeshDataImpl<Real>::_W_33);
+ static const Pb::Register _R_77 ("MeshDataImpl<Real>","getMax",MeshDataImpl<Real>::_W_34);
+ static const Pb::Register _R_78 ("MeshDataImpl<Real>","getMin",MeshDataImpl<Real>::_W_35);
+ static const Pb::Register _R_79 ("MeshDataImpl<Real>","sum",MeshDataImpl<Real>::_W_36);
+ static const Pb::Register _R_80 ("MeshDataImpl<Real>","sumSquare",MeshDataImpl<Real>::_W_37);
+ static const Pb::Register _R_81 ("MeshDataImpl<Real>","sumMagnitude",MeshDataImpl<Real>::_W_38);
+ static const Pb::Register _R_82 ("MeshDataImpl<Real>","setConstIntFlag",MeshDataImpl<Real>::_W_39);
+ static const Pb::Register _R_83 ("MeshDataImpl<Real>","printMdata",MeshDataImpl<Real>::_W_40);
+ static const Pb::Register _R_84 ("MeshDataImpl<Real>","save",MeshDataImpl<Real>::_W_41);
+ static const Pb::Register _R_85 ("MeshDataImpl<Real>","load",MeshDataImpl<Real>::_W_42);
+ static const Pb::Register _R_86 ("MeshDataImpl<Real>","getDataPointer",MeshDataImpl<Real>::_W_43);
+ static const Pb::Register _R_87 ("MeshDataImpl<Vec3>","MeshDataImpl<Vec3>","MeshDataBase"); template<> const char* Namify<MeshDataImpl<Vec3> >::S = "MeshDataImpl<Vec3>";
+ static const Pb::Register _R_88 ("MeshDataImpl<Vec3>","MeshDataImpl",MeshDataImpl<Vec3>::_W_17);
+ static const Pb::Register _R_89 ("MeshDataImpl<Vec3>","clear",MeshDataImpl<Vec3>::_W_18);
+ static const Pb::Register _R_90 ("MeshDataImpl<Vec3>","setSource",MeshDataImpl<Vec3>::_W_19);
+ static const Pb::Register _R_91 ("MeshDataImpl<Vec3>","setConst",MeshDataImpl<Vec3>::_W_20);
+ static const Pb::Register _R_92 ("MeshDataImpl<Vec3>","setConstRange",MeshDataImpl<Vec3>::_W_21);
+ static const Pb::Register _R_93 ("MeshDataImpl<Vec3>","copyFrom",MeshDataImpl<Vec3>::_W_22);
+ static const Pb::Register _R_94 ("MeshDataImpl<Vec3>","add",MeshDataImpl<Vec3>::_W_23);
+ static const Pb::Register _R_95 ("MeshDataImpl<Vec3>","sub",MeshDataImpl<Vec3>::_W_24);
+ static const Pb::Register _R_96 ("MeshDataImpl<Vec3>","addConst",MeshDataImpl<Vec3>::_W_25);
+ static const Pb::Register _R_97 ("MeshDataImpl<Vec3>","addScaled",MeshDataImpl<Vec3>::_W_26);
+ static const Pb::Register _R_98 ("MeshDataImpl<Vec3>","mult",MeshDataImpl<Vec3>::_W_27);
+ static const Pb::Register _R_99 ("MeshDataImpl<Vec3>","multConst",MeshDataImpl<Vec3>::_W_28);
+ static const Pb::Register _R_100 ("MeshDataImpl<Vec3>","safeDiv",MeshDataImpl<Vec3>::_W_29);
+ static const Pb::Register _R_101 ("MeshDataImpl<Vec3>","clamp",MeshDataImpl<Vec3>::_W_30);
+ static const Pb::Register _R_102 ("MeshDataImpl<Vec3>","clampMin",MeshDataImpl<Vec3>::_W_31);
+ static const Pb::Register _R_103 ("MeshDataImpl<Vec3>","clampMax",MeshDataImpl<Vec3>::_W_32);
+ static const Pb::Register _R_104 ("MeshDataImpl<Vec3>","getMaxAbs",MeshDataImpl<Vec3>::_W_33);
+ static const Pb::Register _R_105 ("MeshDataImpl<Vec3>","getMax",MeshDataImpl<Vec3>::_W_34);
+ static const Pb::Register _R_106 ("MeshDataImpl<Vec3>","getMin",MeshDataImpl<Vec3>::_W_35);
+ static const Pb::Register _R_107 ("MeshDataImpl<Vec3>","sum",MeshDataImpl<Vec3>::_W_36);
+ static const Pb::Register _R_108 ("MeshDataImpl<Vec3>","sumSquare",MeshDataImpl<Vec3>::_W_37);
+ static const Pb::Register _R_109 ("MeshDataImpl<Vec3>","sumMagnitude",MeshDataImpl<Vec3>::_W_38);
+ static const Pb::Register _R_110 ("MeshDataImpl<Vec3>","setConstIntFlag",MeshDataImpl<Vec3>::_W_39);
+ static const Pb::Register _R_111 ("MeshDataImpl<Vec3>","printMdata",MeshDataImpl<Vec3>::_W_40);
+ static const Pb::Register _R_112 ("MeshDataImpl<Vec3>","save",MeshDataImpl<Vec3>::_W_41);
+ static const Pb::Register _R_113 ("MeshDataImpl<Vec3>","load",MeshDataImpl<Vec3>::_W_42);
+ static const Pb::Register _R_114 ("MeshDataImpl<Vec3>","getDataPointer",MeshDataImpl<Vec3>::_W_43);
+#endif
+static const Pb::Register _R_9 ("MeshDataImpl<int>","MdataInt","");
+static const Pb::Register _R_10 ("MeshDataImpl<Real>","MdataReal","");
+static const Pb::Register _R_11 ("MeshDataImpl<Vec3>","MdataVec3","");
+extern "C" {
+void PbRegister_file_9()
+{
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+ KEEP_UNUSED(_R_101);
+ KEEP_UNUSED(_R_102);
+ KEEP_UNUSED(_R_103);
+ KEEP_UNUSED(_R_104);
+ KEEP_UNUSED(_R_105);
+ KEEP_UNUSED(_R_106);
+ KEEP_UNUSED(_R_107);
+ KEEP_UNUSED(_R_108);
+ KEEP_UNUSED(_R_109);
+ KEEP_UNUSED(_R_110);
+ KEEP_UNUSED(_R_111);
+ KEEP_UNUSED(_R_112);
+ KEEP_UNUSED(_R_113);
+ KEEP_UNUSED(_R_114);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.cpp
new file mode 100644
index 00000000000..0dbd165cb50
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.cpp
@@ -0,0 +1,109 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Moving obstacles
+ *
+ ******************************************************************************/
+
+#include "movingobs.h"
+#include "commonkernels.h"
+#include "randomstream.h"
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// MovingObs class members
+
+int MovingObstacle::sIDcnt = 10;
+
+MovingObstacle::MovingObstacle (FluidSolver* parent, int emptyType)
+ : PbClass(parent), mEmptyType(emptyType)
+{
+ mID = 1<<sIDcnt;
+ sIDcnt++;
+ if (sIDcnt > 15)
+ errMsg ("currently only 5 separate moving obstacles supported (are you generating them in a loop?)");
+}
+
+void MovingObstacle::add(Shape* shape) {
+ mShapes.push_back(shape);
+}
+
+void MovingObstacle::projectOutside(FlagGrid& flags, BasicParticleSystem& parts) {
+ LevelsetGrid levelset(mParent,false);
+ Grid<Vec3> gradient(mParent);
+
+ // rebuild obstacle levelset
+ FOR_IDX(levelset) {
+ levelset[idx] = flags.isObstacle(idx) ? -0.5 : 0.5;
+ }
+ levelset.reinitMarching(flags, 6.0, 0, true, false, FlagGrid::TypeReserved);
+
+ // build levelset gradient
+ GradientOp(gradient, levelset);
+
+ parts.projectOutside(gradient);
+}
+
+void MovingObstacle::moveLinear(Real t, Real t0, Real t1, Vec3 p0, Vec3 p1, FlagGrid& flags, MACGrid& vel, bool smooth) {
+ Real alpha = (t-t0)/(t1-t0);
+ if (alpha >= 0 && alpha <= 1) {
+ Vec3 v = (p1-p0) / ((t1-t0)* getParent()->getDt() );
+
+ // ease in and out
+ if (smooth) {
+ v *= 6.0f*(alpha-square(alpha));
+ alpha = square(alpha)*(3.0f-2.0f*alpha);
+ }
+
+ Vec3 pos = alpha * p1 + (1.0f-alpha) * p0;
+ for (size_t i=0; i<mShapes.size(); i++)
+ mShapes[i]->setCenter(pos);
+
+ // reset flags
+ FOR_IDX(flags) {
+ if ((flags[idx] & mID) != 0)
+ flags[idx] = mEmptyType;
+ }
+ // apply new flags
+ for (size_t i=0; i<mShapes.size(); i++) {
+# if NOPYTHON!=1
+ mShapes[i]->_args.clear();
+ mShapes[i]->_args.add("value", FlagGrid::TypeObstacle | mID);
+ mShapes[i]->applyToGrid(&flags, 0);
+# else
+ errMsg("Not yet supported...");
+# endif
+ }
+ // apply velocities
+ FOR_IJK_BND(flags,1) {
+ bool cur = (flags(i,j,k) & mID) != 0;
+ if (cur || (flags(i-1,j,k) & mID) != 0) vel(i,j,k).x = v.x;
+ if (cur || (flags(i,j-1,k) & mID) != 0) vel(i,j,k).y = v.y;
+ if (cur || (flags(i,j,k-1) & mID) != 0) vel(i,j,k).z = v.z;
+ }
+ }
+}
+
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h
new file mode 100644
index 00000000000..c1bac5905ab
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h
@@ -0,0 +1,86 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * moving obstacles
+ *
+ ******************************************************************************/
+
+#ifndef _MOVINGOBS_H
+#define _MOVINGOBS_H
+
+#include "shapes.h"
+#include "particle.h"
+
+namespace Manta {
+
+//! Moving obstacle composed of basic shapes
+class MovingObstacle : public PbClass {public:
+ MovingObstacle(FluidSolver* parent, int emptyType=FlagGrid::TypeEmpty); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "MovingObstacle::MovingObstacle" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); int emptyType = _args.getOpt<int >("emptyType",1,FlagGrid::TypeEmpty,&_lock); obj = new MovingObstacle(parent,emptyType); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"MovingObstacle::MovingObstacle" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("MovingObstacle::MovingObstacle",e.what()); return -1; }
+ }
+
+
+ void add(Shape* shape); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MovingObstacle* pbo = dynamic_cast<MovingObstacle*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MovingObstacle::add" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Shape* shape = _args.getPtr<Shape >("shape",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->add(shape); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MovingObstacle::add" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MovingObstacle::add",e.what()); return 0; }
+ }
+
+ //! If t in [t0,t1], apply linear motion path from p0 to p1
+ void moveLinear(Real t, Real t0, Real t1, Vec3 p0, Vec3 p1, FlagGrid& flags, MACGrid& vel, bool smooth=true); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MovingObstacle* pbo = dynamic_cast<MovingObstacle*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MovingObstacle::moveLinear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real t = _args.get<Real >("t",0,&_lock); Real t0 = _args.get<Real >("t0",1,&_lock); Real t1 = _args.get<Real >("t1",2,&_lock); Vec3 p0 = _args.get<Vec3 >("p0",3,&_lock); Vec3 p1 = _args.get<Vec3 >("p1",4,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",5,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",6,&_lock); bool smooth = _args.getOpt<bool >("smooth",7,true,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->moveLinear(t,t0,t1,p0,p1,flags,vel,smooth); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MovingObstacle::moveLinear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MovingObstacle::moveLinear",e.what()); return 0; }
+ }
+
+ //! Compute levelset, and project FLIP particles outside obstacles
+ void projectOutside(FlagGrid& flags, BasicParticleSystem& flip); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); MovingObstacle* pbo = dynamic_cast<MovingObstacle*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "MovingObstacle::projectOutside" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); BasicParticleSystem& flip = *_args.getPtr<BasicParticleSystem >("flip",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->projectOutside(flags,flip); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"MovingObstacle::projectOutside" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("MovingObstacle::projectOutside",e.what()); return 0; }
+ }
+
+
+protected:
+ std::vector<Shape*> mShapes;
+ int mEmptyType;
+ int mID; static int sIDcnt; public: PbArgs _args; }
+#define _C_MovingObstacle
+;
+
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h.reg
new file mode 100644
index 00000000000..7c95949a6de
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h.reg
@@ -0,0 +1,7 @@
+#include "movingobs.h"
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","MovingObstacle","PbClass"); template<> const char* Namify<MovingObstacle >::S = "MovingObstacle";
+>MovingObstacle^
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","MovingObstacle",MovingObstacle::_W_0);
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","add",MovingObstacle::_W_1);
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","moveLinear",MovingObstacle::_W_2);
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","projectOutside",MovingObstacle::_W_3);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h.reg.cpp
new file mode 100644
index 00000000000..25a8528c7e5
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/movingobs.h.reg.cpp
@@ -0,0 +1,30 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "movingobs.h"
+namespace Manta {
+#ifdef _C_MovingObstacle
+ static const Pb::Register _R_17 ("MovingObstacle","MovingObstacle","PbClass"); template<> const char* Namify<MovingObstacle >::S = "MovingObstacle";
+ static const Pb::Register _R_18 ("MovingObstacle","MovingObstacle",MovingObstacle::_W_0);
+ static const Pb::Register _R_19 ("MovingObstacle","add",MovingObstacle::_W_1);
+ static const Pb::Register _R_20 ("MovingObstacle","moveLinear",MovingObstacle::_W_2);
+ static const Pb::Register _R_21 ("MovingObstacle","projectOutside",MovingObstacle::_W_3);
+#endif
+extern "C" {
+void PbRegister_file_17()
+{
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.cpp
new file mode 100644
index 00000000000..b8b361d7c2d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.cpp
@@ -0,0 +1,1196 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Multigrid solver
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Copyright 2016, by Florian Ferstl (florian.ferstl.ff@gmail.com)
+ *
+ * This is an implementation of the solver developed by Dick et al. [1]
+ * without topology awareness (= vertex duplication on coarser levels). This
+ * simplification allows us to use regular grids for all levels of the multigrid
+ * hierarchy and works well for moderately complex domains.
+ *
+ * [1] Solving the Fluid Pressure Poisson Equation Using Multigrid-Evaluation
+ * and Improvements, C. Dick, M. Rogowsky, R. Westermann, IEEE TVCG 2015
+ *
+ ******************************************************************************/
+
+#include "multigrid.h"
+
+#define FOR_LVL(IDX,LVL) \
+ for(int IDX=0; IDX<mb[LVL].size(); IDX++)
+
+#define FOR_VEC_MINMAX(VEC,MIN,MAX) Vec3i VEC; \
+ const Vec3i VEC##__min = (MIN), VEC##__max = (MAX); \
+ for(VEC.z=VEC##__min.z; VEC.z<=VEC##__max.z; VEC.z++) \
+ for(VEC.y=VEC##__min.y; VEC.y<=VEC##__max.y; VEC.y++) \
+ for(VEC.x=VEC##__min.x; VEC.x<=VEC##__max.x; VEC.x++)
+
+#define FOR_VECLIN_MINMAX(VEC,LIN,MIN,MAX) Vec3i VEC; int LIN = 0; \
+ const Vec3i VEC##__min = (MIN), VEC##__max = (MAX); \
+ for(VEC.z=VEC##__min.z; VEC.z<=VEC##__max.z; VEC.z++) \
+ for(VEC.y=VEC##__min.y; VEC.y<=VEC##__max.y; VEC.y++) \
+ for(VEC.x=VEC##__min.x; VEC.x<=VEC##__max.x; VEC.x++, LIN++)
+
+#define MG_TIMINGS(X)
+//#define MG_TIMINGS(X) X
+
+using namespace std;
+namespace Manta
+{
+
+// Helper class for calling mantaflow kernels with a specific number of threads
+class ThreadSize {
+ IndexInt s;
+public:
+ ThreadSize(IndexInt _s) {s=_s;}
+ IndexInt size() { return s; }
+};
+
+// ----------------------------------------------------------------------------
+// Efficient min heap for <ID, key> pairs with 0<=ID<N and 0<=key<K
+// (elements are stored in K buckets, where each bucket is a doubly linked list).
+// - if K<<N, all ops are O(1) on avg (worst case O(K)).
+// - memory usage O(K+N): (K+N) * 3 * sizeof(int).
+class NKMinHeap
+{
+private:
+ struct Entry {
+ int key, prev, next;
+ Entry() : key(-1), prev(-1), next(-1) {}
+ };
+
+ int mN, mK, mSize, mMinKey;
+
+ // Double linked lists of IDs, one for each bucket/key.
+ // The first K entries are the buckets' head pointers,
+ // and the last N entries correspond to the IDs.
+ std::vector<Entry> mEntries;
+
+public:
+ NKMinHeap(int N, int K) : mN(N), mK(K), mSize(0), mMinKey(-1), mEntries(N+K) {}
+
+ int size() { return mSize; }
+ int getKey(int ID) { return mEntries[mK+ID].key; }
+
+ // Insert, decrease or increase key (or delete by setting key to -1)
+ void setKey(int ID, int key);
+
+ // peek min key (returns ID/key pair)
+ std::pair<int,int> peekMin();
+
+ // pop min key (returns ID/key pair)
+ std::pair<int,int> popMin();
+
+ void print(); // for debugging
+};
+
+void NKMinHeap::setKey(int ID, int key)
+{
+ assertMsg(0 <=ID && ID <mN, "NKMinHeap::setKey: ID out of range");
+ assertMsg(-1<=key && key<mK, "NKMinHeap::setKey: key out of range");
+
+ const int kid = mK + ID;
+
+ if (mEntries[kid].key == key) return; // nothing changes
+
+ // remove from old key-list if ID existed previously
+ if (mEntries[kid].key != -1)
+ {
+ int pred = mEntries[kid].prev;
+ int succ = mEntries[kid].next; // can be -1
+
+ mEntries[pred].next = succ;
+ if (succ != -1) mEntries[succ].prev = pred;
+
+ // if removed key was minimum key, mMinKey may need to be updated
+ int removedKey = mEntries[kid].key;
+ if (removedKey==mMinKey)
+ {
+ if (mSize==1) { mMinKey = -1; }
+ else {
+ for (; mMinKey<mK; mMinKey++) {
+ if (mEntries[mMinKey].next != -1) break;
+ }
+ }
+ }
+
+ mSize--;
+ }
+
+ // set new key of ID
+ mEntries[kid].key = key;
+
+ if (key==-1) {
+ // finished if key was set to -1
+ mEntries[kid].next = mEntries[kid].prev = -1;
+ return;
+ }
+
+ // add key
+ mSize++;
+ if (mMinKey == -1) mMinKey = key;
+ else mMinKey = std::min(mMinKey, key);
+
+ // insert into new key-list (headed by mEntries[key])
+ int tmp = mEntries[key].next;
+
+ mEntries[key].next = kid;
+ mEntries[kid].prev = key;
+
+ mEntries[kid].next = tmp;
+ if (tmp != -1) mEntries[tmp].prev = kid;
+}
+
+std::pair<int,int> NKMinHeap::peekMin()
+{
+ if (mSize==0) return std::pair<int,int>(-1,-1); // error
+
+ const int ID = mEntries[mMinKey].next - mK;
+ return std::pair<int,int>(ID, mMinKey);
+}
+
+std::pair<int,int> NKMinHeap::popMin()
+{
+ if (mSize==0) return std::pair<int,int>(-1,-1); // error
+
+ const int kid = mEntries[mMinKey].next;
+ const int ID = kid - mK;
+ const int key = mMinKey;
+
+ // remove from key-list
+ int pred = mEntries[kid].prev;
+ int succ = mEntries[kid].next; // can be -1
+
+ mEntries[pred].next = succ;
+ if (succ != -1) mEntries[succ].prev = pred;
+
+ // remove entry
+ mEntries[kid] = Entry();
+ mSize--;
+
+ // update mMinKey
+ if (mSize==0) { mMinKey = -1; }
+ else {
+ for (; mMinKey<mK; mMinKey++) {
+ if (mEntries[mMinKey].next != -1) break;
+ }
+ }
+
+ // return result
+ return std::pair<int,int>(ID, key);
+}
+
+void NKMinHeap::print()
+{
+ std::cout << "Size: "<<mSize<<", MinKey: "<<mMinKey<< std::endl;
+ for (int key=0; key<mK; key++) {
+ if (mEntries[key].next != -1) {
+ std::cout << "Key "<<key<<": ";
+ int kid = mEntries[key].next;
+ while (kid != -1) {
+ std::cout << kid-mK<<" ";
+ kid = mEntries[kid].next;
+ }
+ std::cout << std::endl;
+ }
+ }
+ std::cout << std::endl;
+}
+
+// ----------------------------------------------------------------------------
+// GridMg methods
+//
+// Illustration of 27-point stencil indices
+// y | z = -1 z = 0 z = 1
+// ^ | 6 7 8, 15 16 17, 24 25 26
+// | | 3 4 5, 12 13 14, 21 22 23
+// o-> x | 0 1 2, 9 10 11, 18 19 20
+//
+// Symmetric storage with only 14 entries per vertex
+// y | z = -1 z = 0 z = 1
+// ^ | - - -, 2 3 4, 11 12 13
+// | | - - -, - 0 1, 8 9 10
+// o-> x | - - -, - - -, 5 6 7
+
+GridMg::GridMg(const Vec3i& gridSize)
+ : mNumPreSmooth(1),
+ mNumPostSmooth(1),
+ mCoarsestLevelAccuracy(Real(1E-8)),
+ mTrivialEquationScale(Real(1E-6)),
+ mIsASet(false),
+ mIsRhsSet(false)
+{
+ MG_TIMINGS(MuTime time;)
+
+ // 2D or 3D mode
+ mIs3D = (gridSize.z > 1);
+ mDim = mIs3D ? 3 : 2;
+ mStencilSize = mIs3D ? 14 : 5; // A has a full 27-point stencil on levels > 0
+ mStencilSize0 = mIs3D ? 4 : 3; // A has a 7-point stencil on level 0
+ mStencilMin = Vec3i(-1,-1, mIs3D ? -1:0);
+ mStencilMax = Vec3i( 1, 1, mIs3D ? 1:0);
+
+ // Create level 0 (=original grid)
+ mSize.push_back(gridSize);
+ mPitch.push_back(Vec3i(1, mSize.back().x, mSize.back().x*mSize.back().y));
+ int n = mSize.back().x * mSize.back().y * mSize.back().z;
+
+ mA.push_back(std::vector<Real>(n * mStencilSize0));
+ mx.push_back(std::vector<Real>(n));
+ mb.push_back(std::vector<Real>(n));
+ mr.push_back(std::vector<Real>(n));
+ mType.push_back(std::vector<VertexType>(n));
+ mCGtmp1.push_back(std::vector<double>());
+ mCGtmp2.push_back(std::vector<double>());
+ mCGtmp3.push_back(std::vector<double>());
+ mCGtmp4.push_back(std::vector<double>());
+
+ debMsg("GridMg::GridMg level 0: "<<mSize[0].x<<" x " << mSize[0].y << " x " << mSize[0].z << " x ", 2);
+
+ // Create coarse levels >0
+ for (int l=1; l<=100; l++)
+ {
+ if (mSize[l-1].x <= 5 && mSize[l-1].y <= 5 && mSize[l-1].z <= 5) break;
+ if (n <= 1000) break;
+
+ mSize.push_back((mSize[l-1] + 2) / 2);
+ mPitch.push_back(Vec3i(1, mSize.back().x, mSize.back().x*mSize.back().y));
+ n = mSize.back().x * mSize.back().y * mSize.back().z;
+
+ mA.push_back(std::vector<Real>(n * mStencilSize));
+ mx.push_back(std::vector<Real>(n));
+ mb.push_back(std::vector<Real>(n));
+ mr.push_back(std::vector<Real>(n));
+ mType.push_back(std::vector<VertexType>(n));
+ mCGtmp1.push_back(std::vector<double>());
+ mCGtmp2.push_back(std::vector<double>());
+ mCGtmp3.push_back(std::vector<double>());
+ mCGtmp4.push_back(std::vector<double>());
+
+ debMsg("GridMg::GridMg level "<<l<<": " << mSize[l].x << " x " << mSize[l].y << " x " << mSize[l].z << " x ", 2);
+ }
+
+ // Additional memory for CG on coarsest level
+ mCGtmp1.back() = std::vector<double>(n);
+ mCGtmp2.back() = std::vector<double>(n);
+ mCGtmp3.back() = std::vector<double>(n);
+ mCGtmp4.back() = std::vector<double>(n);
+
+ MG_TIMINGS(debMsg("GridMg: Allocation done in "<<time.update(), 1);)
+
+ // Precalculate coarsening paths:
+ // (V) <--restriction-- (U) <--A_{l-1}-- (W) <--interpolation-- (N)
+ Vec3i p7stencil[7] = { Vec3i(0,0,0), Vec3i(-1, 0, 0), Vec3i(1,0,0),
+ Vec3i( 0,-1, 0), Vec3i(0,1,0),
+ Vec3i( 0, 0,-1), Vec3i(0,0,1) };
+ Vec3i V (1,1,1); // reference coarse grid vertex at (1,1,1)
+ FOR_VEC_MINMAX(U, V*2+mStencilMin, V*2+mStencilMax) {
+ for (int i=0; i<1+2*mDim; i++) {
+ Vec3i W = U + p7stencil[i];
+ FOR_VEC_MINMAX(N, W/2, (W+1)/2) {
+ int s = dot(N,Vec3i(1,3,9));
+
+ if (s>=13) {
+ CoarseningPath path;
+ path.N = N-1; // offset of N on coarse grid
+ path.U = U-V*2; // offset of U on fine grid
+ path.W = W-V*2; // offset of W on fine grid
+ path.sc = s-13; // stencil index corresponding to V<-N on coarse grid
+ path.sf = (i+1)/2; // stencil index corresponding to U<-W on coarse grid
+ path.inUStencil = (i%2==0); // fine grid stencil entry stored at U or W?
+ path.rw = Real(1) / Real(1 << ((U.x % 2) + (U.y % 2) + (U.z % 2))); // restriction weight V<-U
+ path.iw = Real(1) / Real(1 << ((W.x % 2) + (W.y % 2) + (W.z % 2))); // interpolation weight W<-N
+ mCoarseningPaths0.push_back(path);
+ }
+ }
+ }
+ }
+
+ auto pathLess = [](const GridMg::CoarseningPath& p1, const GridMg::CoarseningPath& p2) {
+ if (p1.sc == p2.sc) return dot(p1.U+1,Vec3i(1,3,9)) < dot(p2.U+1,Vec3i(1,3,9));
+ return p1.sc < p2.sc;
+ };
+ std::sort(mCoarseningPaths0.begin(), mCoarseningPaths0.end(), pathLess);
+}
+
+void GridMg::analyzeStencil(int v, bool is3D, bool& isStencilSumNonZero, bool& isEquationTrivial) const {
+ Vec3i V = vecIdx(v,0);
+
+ // collect stencil entries
+ Real A[7];
+ A[0] = mA[0][v*mStencilSize0 + 0];
+ A[1] = mA[0][v*mStencilSize0 + 1];
+ A[2] = mA[0][v*mStencilSize0 + 2];
+ A[3] = is3D ? mA[0][v*mStencilSize0 + 3] : Real(0);
+ A[4] = V.x!=0 ? mA[0][(v-mPitch[0].x)*mStencilSize0 + 1] : Real(0);
+ A[5] = V.y!=0 ? mA[0][(v-mPitch[0].y)*mStencilSize0 + 2] : Real(0);
+ A[6] = V.z!=0 && is3D ? mA[0][(v-mPitch[0].z)*mStencilSize0 + 3] : Real(0);
+
+ // compute sum of stencil entries
+ Real stencilMax = Real(0), stencilSum = Real(0);
+ for (int i=0; i<7; i++) {
+ stencilSum += A[i];
+ stencilMax = max(stencilMax, std::abs(A[i]));
+ }
+
+ // check if sum is numerically zero
+ isStencilSumNonZero = std::abs(stencilSum / stencilMax) > Real(1E-6);
+
+ // check for trivial equation (exact comparisons)
+ isEquationTrivial = A[0]==Real(1)
+ && A[1]==Real(0) && A[2]==Real(0) && A[3]==Real(0)
+ && A[4]==Real(0) && A[5]==Real(0) && A[6]==Real(0);
+}
+
+
+
+
+ struct knCopyA : public KernelBase {
+ knCopyA(std::vector<Real>& sizeRef, std::vector<Real>& A0, int stencilSize0, bool is3D, const Grid<Real>* pA0, const Grid<Real>* pAi, const Grid<Real>* pAj, const Grid<Real>* pAk) : KernelBase(sizeRef.size()) ,sizeRef(sizeRef),A0(A0),stencilSize0(stencilSize0),is3D(is3D),pA0(pA0),pAi(pAi),pAj(pAj),pAk(pAk) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& sizeRef, std::vector<Real>& A0, int stencilSize0, bool is3D, const Grid<Real>* pA0, const Grid<Real>* pAi, const Grid<Real>* pAj, const Grid<Real>* pAk ) const {
+ A0[idx*stencilSize0 + 0] = (*pA0)[idx];
+ A0[idx*stencilSize0 + 1] = (*pAi)[idx];
+ A0[idx*stencilSize0 + 2] = (*pAj)[idx];
+ if (is3D) A0[idx*stencilSize0 + 3] = (*pAk)[idx];
+} inline std::vector<Real>& getArg0() {
+ return sizeRef; }
+ typedef std::vector<Real> type0;inline std::vector<Real>& getArg1() {
+ return A0; }
+ typedef std::vector<Real> type1;inline int& getArg2() {
+ return stencilSize0; }
+ typedef int type2;inline bool& getArg3() {
+ return is3D; }
+ typedef bool type3;inline const Grid<Real>* getArg4() {
+ return pA0; }
+ typedef Grid<Real> type4;inline const Grid<Real>* getArg5() {
+ return pAi; }
+ typedef Grid<Real> type5;inline const Grid<Real>* getArg6() {
+ return pAj; }
+ typedef Grid<Real> type6;inline const Grid<Real>* getArg7() {
+ return pAk; }
+ typedef Grid<Real> type7; void runMessage() { debMsg("Executing kernel knCopyA ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, sizeRef,A0,stencilSize0,is3D,pA0,pAi,pAj,pAk); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<Real>& sizeRef; std::vector<Real>& A0; int stencilSize0; bool is3D; const Grid<Real>* pA0; const Grid<Real>* pAi; const Grid<Real>* pAj; const Grid<Real>* pAk; }
+;
+
+
+
+
+ struct knActivateVertices : public KernelBase {
+ knActivateVertices(std::vector<GridMg::VertexType>& type_0, std::vector<Real>& A0, bool& nonZeroStencilSumFound, bool& trivialEquationsFound, const GridMg& mg) : KernelBase(type_0.size()) ,type_0(type_0),A0(A0),nonZeroStencilSumFound(nonZeroStencilSumFound),trivialEquationsFound(trivialEquationsFound),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<GridMg::VertexType>& type_0, std::vector<Real>& A0, bool& nonZeroStencilSumFound, bool& trivialEquationsFound, const GridMg& mg ) const {
+ // active vertices on level 0 are vertices with non-zero diagonal entry in A
+ type_0[idx] = GridMg::vtInactive;
+
+ if (mg.mA[0][idx*mg.mStencilSize0 + 0] != Real(0)) {
+ type_0[idx] = GridMg::vtActive;
+
+ bool isStencilSumNonZero = false, isEquationTrivial = false;
+ mg.analyzeStencil(int(idx), mg.mIs3D, isStencilSumNonZero, isEquationTrivial);
+
+ // Note: nonZeroStencilSumFound and trivialEquationsFound are only
+ // changed from false to true, and hence there are no race conditions.
+ if (isStencilSumNonZero) nonZeroStencilSumFound = true;
+
+ // scale down trivial equations
+ if (isEquationTrivial) {
+ type_0[idx] = GridMg::vtActiveTrivial;
+ A0[idx*mg.mStencilSize0 + 0] *= mg.mTrivialEquationScale;
+ trivialEquationsFound = true;
+ };
+ }
+} inline std::vector<GridMg::VertexType>& getArg0() {
+ return type_0; }
+ typedef std::vector<GridMg::VertexType> type0;inline std::vector<Real>& getArg1() {
+ return A0; }
+ typedef std::vector<Real> type1;inline bool& getArg2() {
+ return nonZeroStencilSumFound; }
+ typedef bool type2;inline bool& getArg3() {
+ return trivialEquationsFound; }
+ typedef bool type3;inline const GridMg& getArg4() {
+ return mg; }
+ typedef GridMg type4; void runMessage() { debMsg("Executing kernel knActivateVertices ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, type_0,A0,nonZeroStencilSumFound,trivialEquationsFound,mg); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<GridMg::VertexType>& type_0; std::vector<Real>& A0; bool& nonZeroStencilSumFound; bool& trivialEquationsFound; const GridMg& mg; }
+;
+
+void GridMg::setA(const Grid<Real>* pA0, const Grid<Real>* pAi, const Grid<Real>* pAj, const Grid<Real>* pAk)
+{
+ MG_TIMINGS(MuTime time;)
+
+ // Copy level 0
+ knCopyA(mx[0], mA[0], mStencilSize0, mIs3D, pA0, pAi, pAj, pAk);
+
+ // Determine active vertices and scale trivial equations
+ bool nonZeroStencilSumFound = false;
+ bool trivialEquationsFound = false;
+
+ knActivateVertices(mType[0], mA[0], nonZeroStencilSumFound, trivialEquationsFound, *this);
+
+ if (trivialEquationsFound) debMsg("GridMg::setA: Found at least one trivial equation", 2);
+
+ // Sanity check: if all rows of A sum up to 0 --> A doesn't have full rank (opposite direction isn't necessarily true)
+ if (!nonZeroStencilSumFound) debMsg("GridMg::setA: Found constant mode: A*1=0! A does not have full rank and multigrid may not converge. (forgot to fix a pressure value?)", 1);
+
+ // Create coarse grids and operators on levels >0
+ for (int l=1; l<mA.size(); l++) {
+ MG_TIMINGS(time.get();)
+ genCoarseGrid(l);
+ MG_TIMINGS(debMsg("GridMg: Generated level "<<l<<" in "<<time.update(), 1);)
+ genCoraseGridOperator(l);
+ MG_TIMINGS(debMsg("GridMg: Generated operator "<<l<<" in "<<time.update(), 1);)
+ }
+
+ mIsASet = true;
+ mIsRhsSet = false; // invalidate rhs
+}
+
+
+
+ struct knSetRhs : public KernelBase {
+ knSetRhs(std::vector<Real>& b, const Grid<Real>& rhs, const GridMg& mg) : KernelBase(b.size()) ,b(b),rhs(rhs),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& b, const Grid<Real>& rhs, const GridMg& mg ) const {
+ b[idx] = rhs[idx];
+
+ // scale down trivial equations
+ if (mg.mType[0][idx] == GridMg::vtActiveTrivial) { b[idx] *= mg.mTrivialEquationScale; };
+} inline std::vector<Real>& getArg0() {
+ return b; }
+ typedef std::vector<Real> type0;inline const Grid<Real>& getArg1() {
+ return rhs; }
+ typedef Grid<Real> type1;inline const GridMg& getArg2() {
+ return mg; }
+ typedef GridMg type2; void runMessage() { debMsg("Executing kernel knSetRhs ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, b,rhs,mg); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<Real>& b; const Grid<Real>& rhs; const GridMg& mg; }
+;
+
+void GridMg::setRhs(const Grid<Real>& rhs)
+{
+ assertMsg(mIsASet, "GridMg::setRhs Error: A has not been set.");
+
+ knSetRhs(mb[0], rhs, *this);
+
+ mIsRhsSet = true;
+}
+
+
+
+template <class T> struct knSet : public KernelBase {
+ knSet(std::vector<T>& data, T value) : KernelBase(data.size()) ,data(data),value(value) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<T>& data, T value ) const { data[idx] = value; } inline std::vector<T>& getArg0() {
+ return data; }
+ typedef std::vector<T> type0;inline T& getArg1() {
+ return value; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knSet ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, data,value); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<T>& data; T value; }
+;
+
+
+template <class T> struct knCopyToVector : public KernelBase {
+ knCopyToVector(std::vector<T>& dst, const Grid<T>& src) : KernelBase(dst.size()) ,dst(dst),src(src) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<T>& dst, const Grid<T>& src ) const { dst[idx] = src[idx]; } inline std::vector<T>& getArg0() {
+ return dst; }
+ typedef std::vector<T> type0;inline const Grid<T>& getArg1() {
+ return src; }
+ typedef Grid<T> type1; void runMessage() { debMsg("Executing kernel knCopyToVector ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, dst,src); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<T>& dst; const Grid<T>& src; }
+;
+
+
+template <class T> struct knCopyToGrid : public KernelBase {
+ knCopyToGrid(const std::vector<T>& src, Grid<T>& dst) : KernelBase(src.size()) ,src(src),dst(dst) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const std::vector<T>& src, Grid<T>& dst ) const { dst[idx] = src[idx]; } inline const std::vector<T>& getArg0() {
+ return src; }
+ typedef std::vector<T> type0;inline Grid<T>& getArg1() {
+ return dst; }
+ typedef Grid<T> type1; void runMessage() { debMsg("Executing kernel knCopyToGrid ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, src,dst); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const std::vector<T>& src; Grid<T>& dst; }
+;
+
+
+template <class T> struct knAddAssign : public KernelBase {
+ knAddAssign(std::vector<T>& dst, const std::vector<T>& src) : KernelBase(dst.size()) ,dst(dst),src(src) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<T>& dst, const std::vector<T>& src ) const { dst[idx] += src[idx]; } inline std::vector<T>& getArg0() {
+ return dst; }
+ typedef std::vector<T> type0;inline const std::vector<T>& getArg1() {
+ return src; }
+ typedef std::vector<T> type1; void runMessage() { debMsg("Executing kernel knAddAssign ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, dst,src); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<T>& dst; const std::vector<T>& src; }
+;
+
+Real GridMg::doVCycle(Grid<Real>& dst, const Grid<Real>* src)
+{
+ MG_TIMINGS(MuTime timeSmooth; MuTime timeCG; MuTime timeI; MuTime timeR; MuTime timeTotal; MuTime time;)
+ MG_TIMINGS(timeSmooth.clear(); timeCG.clear(); timeI.clear(); timeR.clear();)
+
+ assertMsg(mIsASet && mIsRhsSet, "GridMg::doVCycle Error: A and/or rhs have not been set.");
+
+ const int maxLevel = int(mA.size()) - 1;
+
+ if (src) { knCopyToVector<Real>(mx[0], *src); }
+ else { knSet<Real>(mx[0], Real(0)); }
+
+ for (int l=0; l<maxLevel; l++)
+ {
+ MG_TIMINGS(time.update();)
+ for (int i=0; i<mNumPreSmooth; i++) {
+ smoothGS(l, false);
+ }
+
+ MG_TIMINGS(timeSmooth += time.update();)
+
+ calcResidual(l);
+ restrict(l+1, mr[l], mb[l+1]);
+
+ knSet<Real>(mx[l+1], Real(0));
+
+ MG_TIMINGS(timeR += time.update();)
+ }
+
+ MG_TIMINGS(time.update();)
+ solveCG(maxLevel);
+ MG_TIMINGS(timeCG += time.update();)
+
+ for (int l=maxLevel-1; l>=0; l--)
+ {
+ MG_TIMINGS(time.update();)
+ interpolate(l, mx[l+1], mr[l]);
+
+ knAddAssign<Real>(mx[l], mr[l]);
+
+ MG_TIMINGS(timeI += time.update();)
+
+ for (int i=0; i<mNumPostSmooth; i++) {
+ smoothGS(l, true);
+ }
+ MG_TIMINGS(timeSmooth += time.update();)
+ }
+
+ calcResidual(0);
+ Real res = calcResidualNorm(0);
+
+ knCopyToGrid<Real>(mx[0], dst);
+
+ MG_TIMINGS(debMsg("GridMg: Finished VCycle in "<<timeTotal.update()<<" (smoothing: "<<timeSmooth<<", CG: "<<timeCG<<", R: "<<timeR<<", I: "<<timeI<<")", 1);)
+
+ return res;
+}
+
+
+
+
+ struct knActivateCoarseVertices : public KernelBase {
+ knActivateCoarseVertices(std::vector<GridMg::VertexType>& type, int unused) : KernelBase(type.size()) ,type(type),unused(unused) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<GridMg::VertexType>& type, int unused ) const {
+ // set all remaining 'free' vertices to 'removed',
+ if (type[idx] == GridMg::vtFree) type[idx] = GridMg::vtRemoved;
+
+ // then convert 'zero' vertices to 'active' and 'removed' vertices to 'inactive'
+ if (type[idx] == GridMg::vtZero ) type[idx] = GridMg::vtActive;
+ if (type[idx] == GridMg::vtRemoved) type[idx] = GridMg::vtInactive;
+} inline std::vector<GridMg::VertexType>& getArg0() {
+ return type; }
+ typedef std::vector<GridMg::VertexType> type0;inline int& getArg1() {
+ return unused; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel knActivateCoarseVertices ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, type,unused); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<GridMg::VertexType>& type; int unused; }
+;
+
+// Determine active cells on coarse level l from active cells on fine level l-1
+// while ensuring a full-rank interpolation operator (see Section 3.3 in [1]).
+void GridMg::genCoarseGrid(int l)
+{
+ // AF_Free: unused/untouched vertices
+ // AF_Zero: vertices selected for coarser level
+ // AF_Removed: vertices removed from coarser level
+ enum activeFlags : char {AF_Removed = 0, AF_Zero = 1, AF_Free = 2};
+
+ // initialize all coarse vertices with 'free'
+ knSet<VertexType>(mType[l], vtFree);
+
+ // initialize min heap of (ID: fine grid vertex, key: #free interpolation vertices) pairs
+ NKMinHeap heap(int(mb[l-1].size()), mIs3D ? 9 : 5); // max 8 (or 4 in 2D) free interpolation vertices
+
+ FOR_LVL(v,l-1) {
+ if (mType[l-1][v] != vtInactive) {
+ Vec3i V = vecIdx(v,l-1);
+ int fiv = 1 << ((V.x % 2) + (V.y % 2) + (V.z % 2));
+ heap.setKey(v, fiv);
+ }
+ }
+
+ // process fine vertices in heap consecutively, always choosing the vertex with
+ // the currently smallest number of free interpolation vertices
+ while (heap.size() > 0)
+ {
+ int v = heap.popMin().first;
+ Vec3i V = vecIdx(v,l-1);
+
+ // loop over associated interpolation vertices of V on coarse level l:
+ // the first encountered 'free' vertex is set to 'zero',
+ // all remaining 'free' vertices are set to 'removed'.
+ bool vdone = false;
+
+ FOR_VEC_MINMAX(I, V/2, (V+1)/2) {
+ int i = linIdx(I,l);
+
+ if (mType[l][i] == vtFree) {
+ if (vdone) {
+ mType[l][i] = vtRemoved;
+ } else {
+ mType[l][i] = vtZero;
+ vdone = true;
+ }
+
+ // update #free interpolation vertices in heap:
+ // loop over all associated restriction vertices of I on fine level l-1
+ FOR_VEC_MINMAX(R, vmax(0, I*2-1), vmin(mSize[l-1]-1, I*2+1)) {
+ int r = linIdx(R,l-1);
+ int key = heap.getKey(r);
+
+ if (key > 1) { heap.setKey(r, key-1); } // decrease key of r
+ else if (key >-1) { heap.setKey(r, -1); } // removes r from heap
+ }
+ }
+ }
+ }
+
+ knActivateCoarseVertices(mType[l],0);
+}
+
+
+
+ struct knGenCoarseGridOperator : public KernelBase {
+ knGenCoarseGridOperator(std::vector<Real>& sizeRef, std::vector<Real>& A, int l, const GridMg& mg) : KernelBase(sizeRef.size()) ,sizeRef(sizeRef),A(A),l(l),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& sizeRef, std::vector<Real>& A, int l, const GridMg& mg ) const {
+ if (mg.mType[l][idx] == GridMg::vtInactive) return;
+
+ for (int i=0; i<mg.mStencilSize; i++) { A[idx*mg.mStencilSize+i] = Real(0); } // clear stencil
+
+ Vec3i V = mg.vecIdx(int(idx),l);
+
+ // Calculate the stencil of A_l at V by considering all vertex paths of the form:
+ // (V) <--restriction-- (U) <--A_{l-1}-- (W) <--interpolation-- (N)
+ // V and N are vertices on the coarse grid level l,
+ // U and W are vertices on the fine grid level l-1.
+
+ if (l==1) {
+ // loop over precomputed paths
+ for (auto it = mg.mCoarseningPaths0.begin(); it != mg.mCoarseningPaths0.end(); it++) {
+ Vec3i N = V + it->N;
+ int n = mg.linIdx(N,l);
+ if (!mg.inGrid(N,l) || mg.mType[l][n]==GridMg::vtInactive) continue;
+
+ Vec3i U = V*2 + it->U;
+ int u = mg.linIdx(U,l-1);
+ if (!mg.inGrid(U,l-1) || mg.mType[l-1][u]==GridMg::vtInactive) continue;
+
+ Vec3i W = V*2 + it->W;
+ int w = mg.linIdx(W,l-1);
+ if (!mg.inGrid(W,l-1) || mg.mType[l-1][w]==GridMg::vtInactive) continue;
+
+ if (it->inUStencil) {
+ A[idx*mg.mStencilSize + it->sc] += it->rw * mg.mA[l-1][u*mg.mStencilSize0 + it->sf] *it->iw;
+ } else {
+ A[idx*mg.mStencilSize + it->sc] += it->rw * mg.mA[l-1][w*mg.mStencilSize0 + it->sf] *it->iw;
+ }
+ }
+ } else {
+ // l > 1:
+ // loop over restriction vertices U on level l-1 associated with V
+ FOR_VEC_MINMAX(U, vmax(0, V*2-1), vmin(mg.mSize[l-1]-1, V*2+1)) {
+ int u = mg.linIdx(U,l-1);
+ if (mg.mType[l-1][u] == GridMg::vtInactive) continue;
+
+ // restriction weight
+ Real rw = Real(1) / Real(1 << ((U.x % 2) + (U.y % 2) + (U.z % 2)));
+
+ // loop over all stencil neighbors N of V on level l that can be reached via restriction to U
+ FOR_VEC_MINMAX(N, (U-1)/2, vmin(mg.mSize[l]-1, (U+2)/2)) {
+ int n = mg.linIdx(N,l);
+ if (mg.mType[l][n] == GridMg::vtInactive) continue;
+
+ // stencil entry at V associated to N (coarse grid level l)
+ Vec3i SC = N - V + mg.mStencilMax;
+ int sc = SC.x + 3*SC.y + 9*SC.z;
+ if (sc < mg.mStencilSize-1) continue;
+
+ // loop over all vertices W which are in the stencil of A_{l-1} at U
+ // and which interpolate from N
+ FOR_VEC_MINMAX(W, vmax( 0, vmax(U-1,N*2-1)),
+ vmin(mg.mSize[l-1]-1, vmin(U+1,N*2+1))) {
+ int w = mg.linIdx(W,l-1);
+ if (mg.mType[l-1][w] == GridMg::vtInactive) continue;
+
+ // stencil entry at U associated to W (fine grid level l-1)
+ Vec3i SF = W - U + mg.mStencilMax;
+ int sf = SF.x + 3*SF.y + 9*SF.z;
+
+ Real iw = Real(1) / Real(1 << ((W.x % 2) + (W.y % 2) + (W.z % 2))); // interpolation weight
+
+ if (sf < mg.mStencilSize) {
+ A[idx*mg.mStencilSize + sc-mg.mStencilSize+1] += rw * mg.mA[l-1][w*mg.mStencilSize + mg.mStencilSize-1-sf] *iw;
+ } else {
+ A[idx*mg.mStencilSize + sc-mg.mStencilSize+1] += rw * mg.mA[l-1][u*mg.mStencilSize + sf-mg.mStencilSize+1] *iw;
+ }
+ }
+ }
+ }
+ }
+} inline std::vector<Real>& getArg0() {
+ return sizeRef; }
+ typedef std::vector<Real> type0;inline std::vector<Real>& getArg1() {
+ return A; }
+ typedef std::vector<Real> type1;inline int& getArg2() {
+ return l; }
+ typedef int type2;inline const GridMg& getArg3() {
+ return mg; }
+ typedef GridMg type3; void runMessage() { debMsg("Executing kernel knGenCoarseGridOperator ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, sizeRef,A,l,mg); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<Real>& sizeRef; std::vector<Real>& A; int l; const GridMg& mg; }
+;
+
+
+// Calculate A_l on coarse level l from A_{l-1} on fine level l-1 using
+// Galerkin-based coarsening, i.e., compute A_l = R * A_{l-1} * I.
+void GridMg::genCoraseGridOperator(int l)
+{
+ // for each coarse grid vertex V
+ knGenCoarseGridOperator(mx[l], mA[l], l, *this);
+}
+
+
+
+
+ struct knSmoothColor : public KernelBase {
+ knSmoothColor(ThreadSize& numBlocks, std::vector<Real>& x, const Vec3i& blockSize, const std::vector<Vec3i>& colorOffs, int l, const GridMg& mg) : KernelBase(numBlocks.size()) ,numBlocks(numBlocks),x(x),blockSize(blockSize),colorOffs(colorOffs),l(l),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ThreadSize& numBlocks, std::vector<Real>& x, const Vec3i& blockSize, const std::vector<Vec3i>& colorOffs, int l, const GridMg& mg ) const {
+ Vec3i blockOff (int(idx)%blockSize.x, (int(idx)%(blockSize.x*blockSize.y))/blockSize.x, int(idx)/(blockSize.x*blockSize.y));
+
+ for (int off = 0; off < colorOffs.size(); off++) {
+
+ Vec3i V = blockOff*2 + colorOffs[off];
+ if (!mg.inGrid(V,l)) continue;
+
+ const int v = mg.linIdx(V,l);
+ if (mg.mType[l][v] == GridMg::vtInactive) continue;
+
+ Real sum = mg.mb[l][v];
+
+ if (l==0) {
+ int n;
+ for (int d=0; d<mg.mDim; d++) {
+ if (V[d]>0) { n = v-mg.mPitch[0][d]; sum -= mg.mA[0][n*mg.mStencilSize0 + d+1] * mg.mx[0][n]; }
+ if (V[d]<mg.mSize[0][d]-1) { n = v+mg.mPitch[0][d]; sum -= mg.mA[0][v*mg.mStencilSize0 + d+1] * mg.mx[0][n]; }
+ }
+
+ x[v] = sum / mg.mA[0][v*mg.mStencilSize0 + 0];
+ } else {
+ FOR_VECLIN_MINMAX(S, s, mg.mStencilMin, mg.mStencilMax) {
+ if (s == mg.mStencilSize-1) continue;
+
+ Vec3i N = V + S;
+ int n = mg.linIdx(N,l);
+
+ if (mg.inGrid(N,l) && mg.mType[l][n]!=GridMg::vtInactive) {
+ if (s < mg.mStencilSize) {
+ sum -= mg.mA[l][n*mg.mStencilSize + mg.mStencilSize-1-s] * mg.mx[l][n];
+ } else {
+ sum -= mg.mA[l][v*mg.mStencilSize + s-mg.mStencilSize+1] * mg.mx[l][n];
+ }
+ }
+ }
+
+ x[v] = sum / mg.mA[l][v*mg.mStencilSize + 0];
+ }
+ }
+} inline ThreadSize& getArg0() {
+ return numBlocks; }
+ typedef ThreadSize type0;inline std::vector<Real>& getArg1() {
+ return x; }
+ typedef std::vector<Real> type1;inline const Vec3i& getArg2() {
+ return blockSize; }
+ typedef Vec3i type2;inline const std::vector<Vec3i>& getArg3() {
+ return colorOffs; }
+ typedef std::vector<Vec3i> type3;inline int& getArg4() {
+ return l; }
+ typedef int type4;inline const GridMg& getArg5() {
+ return mg; }
+ typedef GridMg type5; void runMessage() { debMsg("Executing kernel knSmoothColor ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, numBlocks,x,blockSize,colorOffs,l,mg); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ThreadSize& numBlocks; std::vector<Real>& x; const Vec3i& blockSize; const std::vector<Vec3i>& colorOffs; int l; const GridMg& mg; }
+;
+
+void GridMg::smoothGS(int l, bool reversedOrder)
+{
+ // Multicolor Gauss-Seidel with two colors for the 5/7-point stencil on level 0
+ // and with four/eight colors for the 9/27-point stencil on levels > 0
+ std::vector<std::vector<Vec3i>> colorOffs;
+ const Vec3i a[8] = {Vec3i(0,0,0), Vec3i(1,0,0), Vec3i(0,1,0), Vec3i(1,1,0),
+ Vec3i(0,0,1), Vec3i(1,0,1), Vec3i(0,1,1), Vec3i(1,1,1)};
+ if (mIs3D) {
+ if (l==0) colorOffs = {{a[0],a[3],a[5],a[6]}, {a[1],a[2],a[4],a[7]}};
+ else colorOffs = {{a[0]}, {a[1]}, {a[2]}, {a[3]}, {a[4]}, {a[5]}, {a[6]}, {a[7]}};
+ } else {
+ if (l==0) colorOffs = {{a[0],a[3]}, {a[1],a[2]}};
+ else colorOffs = {{a[0]}, {a[1]}, {a[2]}, {a[3]}};
+ }
+
+ // Divide grid into 2x2 blocks for parallelization
+ Vec3i blockSize = (mSize[l]+1)/2;
+ ThreadSize numBlocks(blockSize.x * blockSize.y * blockSize.z);
+
+ for (int c = 0; c < colorOffs.size(); c++) {
+ int color = reversedOrder ? int(colorOffs.size())-1-c : c;
+
+ knSmoothColor(numBlocks, mx[l], blockSize, colorOffs[color], l, *this);
+ }
+}
+
+
+
+ struct knCalcResidual : public KernelBase {
+ knCalcResidual(std::vector<Real>& r, int l, const GridMg& mg) : KernelBase(r.size()) ,r(r),l(l),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& r, int l, const GridMg& mg ) const {
+ if (mg.mType[l][idx] == GridMg::vtInactive) return;
+
+ Vec3i V = mg.vecIdx(int(idx),l);
+
+ Real sum = mg.mb[l][idx];
+
+ if (l==0) {
+ int n;
+ for (int d=0; d<mg.mDim; d++) {
+ if (V[d]>0) { n = int(idx)-mg.mPitch[0][d]; sum -= mg.mA[0][n *mg.mStencilSize0 + d+1] * mg.mx[0][n]; }
+ if (V[d]<mg.mSize[0][d]-1) { n = int(idx)+mg.mPitch[0][d]; sum -= mg.mA[0][idx*mg.mStencilSize0 + d+1] * mg.mx[0][n]; }
+ }
+ sum -= mg.mA[0][idx*mg.mStencilSize0 + 0] * mg.mx[0][idx];
+ } else {
+ FOR_VECLIN_MINMAX(S, s, mg.mStencilMin, mg.mStencilMax) {
+ Vec3i N = V + S;
+ int n = mg.linIdx(N,l);
+
+ if (mg.inGrid(N,l) && mg.mType[l][n]!=GridMg::vtInactive) {
+ if (s < mg.mStencilSize) {
+ sum -= mg.mA[l][n *mg.mStencilSize + mg.mStencilSize-1-s] * mg.mx[l][n];
+ } else {
+ sum -= mg.mA[l][idx*mg.mStencilSize + s-mg.mStencilSize+1] * mg.mx[l][n];
+ }
+ }
+ }
+ }
+
+ r[idx] = sum;
+} inline std::vector<Real>& getArg0() {
+ return r; }
+ typedef std::vector<Real> type0;inline int& getArg1() {
+ return l; }
+ typedef int type1;inline const GridMg& getArg2() {
+ return mg; }
+ typedef GridMg type2; void runMessage() { debMsg("Executing kernel knCalcResidual ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, r,l,mg); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<Real>& r; int l; const GridMg& mg; }
+;
+
+void GridMg::calcResidual(int l)
+{
+ knCalcResidual(mr[l], l, *this);
+}
+
+
+
+ struct knResidualNormSumSqr : public KernelBase {
+ knResidualNormSumSqr(const vector<Real>& r, int l, const GridMg& mg) : KernelBase(r.size()) ,r(r),l(l),mg(mg) ,result(Real(0)) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const vector<Real>& r, int l, const GridMg& mg ,Real& result) {
+ if (mg.mType[l][idx] == GridMg::vtInactive) return;
+
+ result += r[idx] * r[idx];
+} inline operator Real () {
+ return result; }
+ inline Real & getRet() {
+ return result; }
+ inline const vector<Real>& getArg0() {
+ return r; }
+ typedef vector<Real> type0;inline int& getArg1() {
+ return l; }
+ typedef int type1;inline const GridMg& getArg2() {
+ return mg; }
+ typedef GridMg type2; void runMessage() { debMsg("Executing kernel knResidualNormSumSqr ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, r,l,mg,result); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ knResidualNormSumSqr (knResidualNormSumSqr& o, tbb::split) : KernelBase(o) ,r(o.r),l(o.l),mg(o.mg) ,result(Real(0)) {
+}
+ void join(const knResidualNormSumSqr & o) {
+ result += o.result; }
+ const vector<Real>& r; int l; const GridMg& mg; Real result; }
+;;
+
+Real GridMg::calcResidualNorm(int l)
+{
+ Real res = knResidualNormSumSqr(mr[l], l, *this);
+
+ return std::sqrt(res);
+}
+
+// Standard conjugate gradients with Jacobi preconditioner
+// Notes: Always run at double precision. Not parallelized since
+// coarsest level is assumed to be small.
+void GridMg::solveCG(int l)
+{
+ auto applyAStencil = [this](int v, int l, const std::vector<double>& vec) -> double {
+ Vec3i V = vecIdx(v,l);
+
+ double sum = 0;
+
+ if (l==0) {
+ int n;
+ for (int d=0; d<mDim; d++) {
+ if (V[d]>0) { n = v-mPitch[0][d]; sum += mA[0][n*mStencilSize0 + d+1] * vec[n]; }
+ if (V[d]<mSize[0][d]-1) { n = v+mPitch[0][d]; sum += mA[0][v*mStencilSize0 + d+1] * vec[n]; }
+ }
+ sum += mA[0][v*mStencilSize0 + 0] * vec[v];
+ } else {
+ FOR_VECLIN_MINMAX(S, s, mStencilMin, mStencilMax) {
+ Vec3i N = V + S;
+ int n = linIdx(N,l);
+
+ if (inGrid(N,l) && mType[l][n]!=vtInactive) {
+ if (s < mStencilSize) {
+ sum += mA[l][n*mStencilSize + mStencilSize-1-s] * vec[n];
+ } else {
+ sum += mA[l][v*mStencilSize + s-mStencilSize+1] * vec[n];
+ }
+ }
+ }
+ }
+
+ return sum;
+ };
+
+ std::vector<double>& z = mCGtmp1[l];
+ std::vector<double>& p = mCGtmp2[l];
+ std::vector<double>& x = mCGtmp3[l];
+ std::vector<double>& r = mCGtmp4[l];
+
+ // Initialization:
+ double alphaTop = 0;
+ double initialResidual = 0;
+
+ FOR_LVL(v,l) { x[v] = mx[l][v]; }
+
+ FOR_LVL(v,l) {
+ if (mType[l][v] == vtInactive) continue;
+
+ r[v] = mb[l][v] - applyAStencil(v,l,x);
+ if (l==0) { z[v] = r[v] / mA[0][v*mStencilSize0 + 0]; }
+ else { z[v] = r[v] / mA[l][v*mStencilSize + 0]; }
+
+ initialResidual += r[v] * r[v];
+ p[v] = z[v];
+ alphaTop += r[v] * z[v];
+ }
+
+ initialResidual = std::sqrt(initialResidual);
+
+ int iter = 0;
+ const int maxIter = 10000;
+ double residual = -1;
+
+ // CG iterations
+ for (; iter<maxIter && initialResidual>1E-12; iter++)
+ {
+ double alphaBot = 0;
+
+ FOR_LVL(v,l) {
+ if (mType[l][v] == vtInactive) continue;
+
+ z[v] = applyAStencil(v,l,p);
+ alphaBot += p[v] * z[v];
+ }
+
+ double alpha = alphaTop / alphaBot;
+
+ double alphaTopNew = 0;
+ residual = 0;
+
+ FOR_LVL(v,l) {
+ if (mType[l][v] == vtInactive) continue;
+
+ x[v] += alpha * p[v];
+ r[v] -= alpha * z[v];
+ residual += r[v] * r[v];
+ if (l==0) z[v] = r[v] / mA[0][v*mStencilSize0 + 0];
+ else z[v] = r[v] / mA[l][v*mStencilSize + 0];
+ alphaTopNew += r[v] * z[v];
+ }
+
+ residual = std::sqrt(residual);
+
+ if (residual / initialResidual < mCoarsestLevelAccuracy) break;
+
+ double beta = alphaTopNew / alphaTop;
+ alphaTop = alphaTopNew;
+
+ FOR_LVL(v,l) {
+ p[v] = z[v] + beta * p[v];
+ }
+ debMsg("GridMg::solveCG i="<<iter<<" rel-residual="<< (residual / initialResidual) , 5);
+ }
+
+ FOR_LVL(v,l) { mx[l][v] = Real(x[v]); }
+
+ if (iter == maxIter) { debMsg("GridMg::solveCG Warning: Reached maximum number of CG iterations", 1); }
+ else { debMsg("GridMg::solveCG Info: Reached residual "<<residual<<" in "<<iter<<" iterations", 2); }
+}
+
+
+
+ struct knRestrict : public KernelBase {
+ knRestrict(std::vector<Real>& dst, const std::vector<Real>& src, int l_dst, const GridMg& mg) : KernelBase(dst.size()) ,dst(dst),src(src),l_dst(l_dst),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& dst, const std::vector<Real>& src, int l_dst, const GridMg& mg ) const {
+ if (mg.mType[l_dst][idx] == GridMg::vtInactive) return;
+
+ const int l_src = l_dst - 1;
+
+ // Coarse grid vertex
+ Vec3i V = mg.vecIdx(int(idx),l_dst);
+
+ Real sum = Real(0);
+
+ FOR_VEC_MINMAX(R, vmax(0, V*2-1), vmin(mg.mSize[l_src]-1, V*2+1)) {
+ int r = mg.linIdx(R,l_src);
+ if (mg.mType[l_src][r] == GridMg::vtInactive) continue;
+
+ // restriction weight
+ Real rw = Real(1) / Real(1 << ((R.x % 2) + (R.y % 2) + (R.z % 2)));
+
+ sum += rw * src[r];
+ }
+
+ dst[idx] = sum;
+} inline std::vector<Real>& getArg0() {
+ return dst; }
+ typedef std::vector<Real> type0;inline const std::vector<Real>& getArg1() {
+ return src; }
+ typedef std::vector<Real> type1;inline int& getArg2() {
+ return l_dst; }
+ typedef int type2;inline const GridMg& getArg3() {
+ return mg; }
+ typedef GridMg type3; void runMessage() { debMsg("Executing kernel knRestrict ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, dst,src,l_dst,mg); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<Real>& dst; const std::vector<Real>& src; int l_dst; const GridMg& mg; }
+;
+
+void GridMg::restrict(int l_dst, const std::vector<Real>& src, std::vector<Real>& dst) const
+{
+ knRestrict(dst, src, l_dst, *this);
+}
+
+
+
+ struct knInterpolate : public KernelBase {
+ knInterpolate(std::vector<Real>& dst, const std::vector<Real>& src, int l_dst, const GridMg& mg) : KernelBase(dst.size()) ,dst(dst),src(src),l_dst(l_dst),mg(mg) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<Real>& dst, const std::vector<Real>& src, int l_dst, const GridMg& mg ) const {
+ if (mg.mType[l_dst][idx] == GridMg::vtInactive) return;
+
+ const int l_src = l_dst + 1;
+
+ Vec3i V = mg.vecIdx(int(idx),l_dst);
+
+ Real sum = Real(0);
+
+ FOR_VEC_MINMAX(I, V/2, (V+1)/2) {
+ int i = mg.linIdx(I,l_src);
+ if (mg.mType[l_src][i] != GridMg::vtInactive) sum += src[i];
+ }
+
+ // interpolation weight
+ Real iw = Real(1) / Real(1 << ((V.x % 2) + (V.y % 2) + (V.z % 2)));
+
+ dst[idx] = iw * sum;
+} inline std::vector<Real>& getArg0() {
+ return dst; }
+ typedef std::vector<Real> type0;inline const std::vector<Real>& getArg1() {
+ return src; }
+ typedef std::vector<Real> type1;inline int& getArg2() {
+ return l_dst; }
+ typedef int type2;inline const GridMg& getArg3() {
+ return mg; }
+ typedef GridMg type3; void runMessage() { debMsg("Executing kernel knInterpolate ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, dst,src,l_dst,mg); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<Real>& dst; const std::vector<Real>& src; int l_dst; const GridMg& mg; }
+;
+
+void GridMg::interpolate(int l_dst, const std::vector<Real>& src, std::vector<Real>& dst) const
+{
+ knInterpolate(dst, src, l_dst, *this);
+}
+
+
+
+}; // DDF
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h
new file mode 100644
index 00000000000..a8d70033971
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h
@@ -0,0 +1,154 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Multigrid solver by Florian Ferstl (florian.ferstl.ff@gmail.com)
+ *
+ * This is an implementation of the solver developed by Dick et al. [1]
+ * without topology awareness (= vertex duplication on coarser levels). This
+ * simplification allows us to use regular grids for all levels of the multigrid
+ * hierarchy and works well for moderately complex domains.
+ *
+ * [1] Solving the Fluid Pressure Poisson Equation Using Multigrid-Evaluation
+ * and Improvements, C. Dick, M. Rogowsky, R. Westermann, IEEE TVCG 2015
+ *
+ ******************************************************************************/
+
+#ifndef _MULTIGRID_H
+#define _MULTIGRID_H
+
+#include "vectorbase.h"
+#include "grid.h"
+
+namespace Manta {
+
+//! Multigrid solver
+class GridMg {
+ public:
+ //! constructor: preallocates most of required memory for multigrid hierarchy
+ GridMg(const Vec3i& gridSize);
+ ~GridMg() {};
+
+ //! update system matrix A from symmetric 7-point stencil
+ void setA(const Grid<Real>* pA0, const Grid<Real>* pAi, const Grid<Real>* pAj, const Grid<Real>* pAk);
+
+ //! set right-hand side after setting A
+ void setRhs(const Grid<Real>& rhs);
+
+ bool isASet() const { return mIsASet; }
+ bool isRhsSet() const { return mIsRhsSet; }
+
+ //! perform VCycle iteration
+ // - if src is null, then a zero vector is used instead
+ // - returns norm of residual after VCylcle
+ Real doVCycle(Grid<Real>& dst, const Grid<Real>* src = nullptr);
+
+ // access
+ void setCoarsestLevelAccuracy(Real accuracy) { mCoarsestLevelAccuracy = accuracy; }
+ Real getCoarsestLevelAccuracy() const { return mCoarsestLevelAccuracy; }
+ void setSmoothing(int numPreSmooth, int numPostSmooth) { mNumPreSmooth = numPreSmooth; mNumPostSmooth = numPostSmooth; }
+ int getNumPreSmooth() const { return mNumPreSmooth; }
+ int getNumPostSmooth() const { return mNumPostSmooth; }
+
+ //! Set factor for automated downscaling of trivial equations:
+ // 1*x_i = b_i ---> trivialEquationScale*x_i = trivialEquationScale*b_i
+ // Factor should be significantly smaller than the scale of the entries in A.
+ // Info: Trivial equations of the form x_i = b_i can have a negative
+ // effect on the coarse grid operators of the multigrid hierarchy (due
+ // to scaling mismatches), which can lead to slow multigrid convergence.
+ // To avoid this, the solver checks for such equations when updating A
+ // (and rhs) and scales these equations by a fixed factor < 1.
+ void setTrivialEquationScale(Real scale) { mTrivialEquationScale = scale; }
+
+ private:
+ Vec3i vecIdx(int v, int l) const { return Vec3i(v%mSize[l].x, (v%(mSize[l].x*mSize[l].y))/mSize[l].x, v/(mSize[l].x*mSize[l].y)); }
+ int linIdx(Vec3i V, int l) const { return V.x + V.y*mPitch[l].y + V.z*mPitch[l].z; }
+ bool inGrid(Vec3i V, int l) const { return V.x>=0 && V.y>=0 && V.z>=0 && V.x<mSize[l].x && V.y<mSize[l].y && V.z<mSize[l].z; }
+
+ void analyzeStencil(int v, bool is3D, bool& isStencilSumNonZero, bool& isEquationTrivial) const;
+
+ void genCoarseGrid(int l);
+ void genCoraseGridOperator(int l);
+
+ void smoothGS(int l, bool reversedOrder);
+ void calcResidual(int l);
+ Real calcResidualNorm(int l);
+ void solveCG(int l);
+
+ void restrict(int l_dst, const std::vector<Real>& src, std::vector<Real>& dst) const;
+ void interpolate(int l_dst, const std::vector<Real>& src, std::vector<Real>& dst) const;
+
+ private:
+ enum VertexType : char {
+ vtInactive = 0,
+ vtActive = 1,
+ vtActiveTrivial = 2, // only on finest level 0
+ vtRemoved = 3, //-+
+ vtZero = 4, // +-- only during coarse grid generation
+ vtFree = 5 //-+
+ };
+
+ struct CoarseningPath {
+ Vec3i U, W, N;
+ int sc, sf;
+ Real rw, iw;
+ bool inUStencil;
+ };
+
+ int mNumPreSmooth;
+ int mNumPostSmooth;
+ Real mCoarsestLevelAccuracy;
+ Real mTrivialEquationScale;
+
+ std::vector<std::vector<Real>> mA;
+ std::vector<std::vector<Real>> mx;
+ std::vector<std::vector<Real>> mb;
+ std::vector<std::vector<Real>> mr;
+ std::vector<std::vector<VertexType>> mType;
+ std::vector<std::vector<double>> mCGtmp1, mCGtmp2, mCGtmp3, mCGtmp4;
+ std::vector<Vec3i> mSize, mPitch;
+ std::vector<CoarseningPath> mCoarseningPaths0;
+
+ bool mIs3D;
+ int mDim;
+ int mStencilSize;
+ int mStencilSize0;
+ Vec3i mStencilMin;
+ Vec3i mStencilMax;
+
+ bool mIsASet;
+ bool mIsRhsSet;
+
+ // provide kernels with access
+ friend struct knActivateVertices;
+ friend struct knActivateCoarseVertices;
+ friend struct knSetRhs;
+ friend struct knGenCoarseGridOperator;
+ friend struct knSmoothColor;
+ friend struct knCalcResidual;
+ friend struct knResidualNormSumSqr;
+ friend struct knRestrict;
+ friend struct knInterpolate;
+}; // GridMg
+
+} // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h.reg
new file mode 100644
index 00000000000..0dd8d785437
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h.reg
@@ -0,0 +1 @@
+#include "multigrid.h"
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h.reg.cpp
new file mode 100644
index 00000000000..5210d1aac28
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/multigrid.h.reg.cpp
@@ -0,0 +1,18 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "multigrid.h"
+namespace Manta {
+extern "C" {
+void PbRegister_file_4()
+{
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.cpp
new file mode 100644
index 00000000000..13effa9e89d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.cpp
@@ -0,0 +1,312 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Noise field
+ *
+ ******************************************************************************/
+
+#include "noisefield.h"
+#include "randomstream.h"
+#include "grid.h"
+
+using namespace std;
+
+//*****************************************************************************
+// Wavelet noise
+
+#if FLOATINGPOINT_PRECISION==1
+#define TILENAME "waveletNoiseTile.bin"
+#else
+#define TILENAME "waveletNoiseTileD.bin"
+#endif
+
+namespace Manta {
+
+int WaveletNoiseField::randomSeed = 13322223;
+Real* WaveletNoiseField::mNoiseTile = NULL;
+std::atomic<int> WaveletNoiseField::mNoiseReferenceCount(0);
+
+static Real _aCoeffs[32] = {
+ 0.000334,-0.001528, 0.000410, 0.003545,-0.000938,-0.008233, 0.002172, 0.019120,
+ -0.005040,-0.044412, 0.011655, 0.103311,-0.025936,-0.243780, 0.033979, 0.655340,
+ 0.655340, 0.033979,-0.243780,-0.025936, 0.103311, 0.011655,-0.044412,-0.005040,
+ 0.019120, 0.002172,-0.008233,-0.000938, 0.003546, 0.000410,-0.001528, 0.000334};
+
+void WaveletNoiseField::downsample(Real *from, Real *to, int n, int stride){
+ const Real *a = &_aCoeffs[16];
+ for (int i = 0; i < n / 2; i++) {
+ to[i * stride] = 0;
+ for (int k = 2 * i - 16; k < 2 * i + 16; k++) {
+ to[i * stride] += a[k - 2 * i] * from[modFast128(k) * stride];
+ }
+ }
+}
+
+static Real _pCoeffs[4] = {0.25, 0.75, 0.75, 0.25};
+
+void WaveletNoiseField::upsample(Real *from, Real *to, int n, int stride) {
+ const Real *pp = &_pCoeffs[1];
+
+ for (int i = 0; i < n; i++) {
+ to[i * stride] = 0;
+ for (int k = i / 2 - 1 ; k < i / 2 + 3; k++) {
+ to[i * stride] += 0.5 * pp[k - i / 2] * from[modSlow(k, n / 2) * stride];
+ } // new */
+ }
+}
+
+WaveletNoiseField::WaveletNoiseField(FluidSolver* parent, int fixedSeed, int loadFromFile) :
+ PbClass(parent), mPosOffset(0.), mPosScale(1.), mValOffset(0.), mValScale(1.), mClamp(false),
+ mClampNeg(0), mClampPos(1), mTimeAnim(0), mGsInvX(0), mGsInvY(0), mGsInvZ(0)
+{
+ Real scale = 1.0/parent->getGridSize().max();
+ mGsInvX = scale;
+ mGsInvY = scale;
+ mGsInvZ = parent->is3D() ? scale : 1;
+
+ // use global random seed with offset if none is given
+ if (fixedSeed==-1) {
+ fixedSeed = randomSeed + 123;
+ }
+ RandomStream randStreamPos(fixedSeed);
+ mSeedOffset = Vec3( randStreamPos.getVec3Norm() );
+
+ generateTile( loadFromFile );
+};
+
+string WaveletNoiseField::toString() {
+ std::ostringstream out;
+ out << "NoiseField: name '"<<mName<<"' "<<
+ " pos off="<<mPosOffset<<" scale="<<mPosScale<<
+ " val off="<<mValOffset<<" scale="<<mValScale<<
+ " clamp ="<<mClamp<<" val="<<mClampNeg<<" to "<<mClampPos<<
+ " timeAni ="<<mTimeAnim<<
+ " gridInv ="<<Vec3(mGsInvX,mGsInvY,mGsInvZ) ;
+ return out.str();
+}
+
+void WaveletNoiseField::generateTile( int loadFromFile) {
+ // generate tile
+ const int n = NOISE_TILE_SIZE;
+ const int n3 = n*n*n, n3d=n3*3;
+
+ if(mNoiseTile) { mNoiseReferenceCount++; return; }
+ Real *noise3 = new Real[n3d];
+ if(loadFromFile) {
+ FILE* fp = fopen(TILENAME,"rb");
+ if(fp) {
+ assertMsg( fread(noise3, sizeof(Real), n3d, fp) == n3d, "Failed to read wavelet noise tile, file invalid/corrupt? ("<<TILENAME<<") ");
+ fclose(fp);
+ debMsg("Noise tile loaded from file " TILENAME , 1);
+ mNoiseTile = noise3;
+ mNoiseReferenceCount++;
+ return;
+ }
+ }
+
+ debMsg("Generating 3x " << n << "^3 noise tile " , 1);
+ Real *temp13 = new Real[n3d];
+ Real *temp23 = new Real[n3d];
+
+ // initialize
+ for (int i = 0; i < n3d; i++) {
+ temp13[i] = temp23[i] =
+ noise3[i] = 0.;
+ }
+
+ // Step 1. Fill the tile with random numbers in the range -1 to 1.
+ RandomStream randStreamTile ( randomSeed );
+ for (int i = 0; i < n3d; i++) {
+ //noise3[i] = (randStream.getReal() + randStream2.getReal()) -1.; // produces repeated values??
+ noise3[i] = randStreamTile.getRandNorm(0,1);
+ }
+
+ // Steps 2 and 3. Downsample and upsample the tile
+ for (int tile=0; tile < 3; tile++) {
+ for (int iy = 0; iy < n; iy++)
+ for (int iz = 0; iz < n; iz++) {
+ const int i = iy * n + iz*n*n + tile*n3;
+ downsample(&noise3[i], &temp13[i], n, 1);
+ upsample (&temp13[i], &temp23[i], n, 1);
+ }
+ for (int ix = 0; ix < n; ix++)
+ for (int iz = 0; iz < n; iz++) {
+ const int i = ix + iz*n*n + tile*n3;
+ downsample(&temp23[i], &temp13[i], n, n);
+ upsample (&temp13[i], &temp23[i], n, n);
+ }
+ for (int ix = 0; ix < n; ix++)
+ for (int iy = 0; iy < n; iy++) {
+ const int i = ix + iy*n + tile*n3;
+ downsample(&temp23[i], &temp13[i], n, n*n);
+ upsample (&temp13[i], &temp23[i], n, n*n);
+ }
+ }
+
+ // Step 4. Subtract out the coarse-scale contribution
+ for (int i = 0; i < n3d; i++) {
+ noise3[i] -= temp23[i];
+ }
+
+ // Avoid even/odd variance difference by adding odd-offset version of noise to itself.
+ int offset = n / 2;
+ if (offset % 2 == 0) offset++;
+
+ if (n != 128) errMsg("WaveletNoise::Fast 128 mod used, change for non-128 resolution");
+
+ int icnt=0;
+ for (int tile=0; tile<3; tile++)
+ for (int ix = 0; ix < n; ix++)
+ for (int iy = 0; iy < n; iy++)
+ for (int iz = 0; iz < n; iz++) {
+ temp13[icnt] = noise3[modFast128(ix+offset) + modFast128(iy+offset)*n + modFast128(iz+offset)*n*n + tile*n3];
+ icnt++;
+ }
+
+
+ for (int i = 0; i < n3d; i++) {
+ noise3[i] += temp13[i];
+ }
+
+ mNoiseTile = noise3;
+ mNoiseReferenceCount++;
+ delete[] temp13;
+ delete[] temp23;
+
+ if(loadFromFile) {
+ FILE* fp = fopen(TILENAME,"wb");
+ if(fp) {
+ fwrite(noise3, sizeof(Real), n3d, fp);
+ fclose(fp);
+ debMsg( "Noise field saved to file " , 1);
+ }
+ }
+}
+
+
+
+void WaveletNoiseField::downsampleNeumann(const Real *from, Real *to, int n, int stride)
+{
+ // if these values are not local incorrect results are generated
+ static const Real *const aCoCenter= &_aCoeffs[16];
+ for (int i = 0; i < n / 2; i++) {
+ to[i * stride] = 0;
+ for (int k = 2 * i - 16; k < 2 * i + 16; k++) {
+ // handle boundary
+ Real fromval;
+ if (k < 0) {
+ fromval = from[0];
+ } else if(k > n - 1) {
+ fromval = from[(n - 1) * stride];
+ } else {
+ fromval = from[k * stride];
+ }
+ to[i * stride] += aCoCenter[k - 2 * i] * fromval;
+ }
+ }
+}
+
+void WaveletNoiseField::upsampleNeumann(const Real *from, Real *to, int n, int stride) {
+ static const Real *const pp = &_pCoeffs[1];
+ for (int i = 0; i < n; i++) {
+ to[i * stride] = 0;
+ for (int k = i / 2 - 1 ; k < i / 2 + 3; k++) {
+ Real fromval;
+ if(k>n/2-1) {
+ fromval = from[(n/2-1) * stride];
+ } else if(k < 0) {
+ fromval = from[0];
+ } else {
+ fromval = from[k * stride];
+ }
+ to[i * stride] += 0.5 * pp[k - i / 2] * fromval;
+ }
+ }
+}
+
+void WaveletNoiseField::computeCoefficients(Grid<Real>& input, Grid<Real>& tempIn1, Grid<Real>& tempIn2)
+{
+ // generate tile
+ const int sx = input.getSizeX();
+ const int sy = input.getSizeY();
+ const int sz = input.getSizeZ();
+ const int n3 = sx*sy*sz;
+ // just for compatibility with wavelet turb code
+ Real *temp13 = &tempIn1(0,0,0);
+ Real *temp23 = &tempIn2(0,0,0);
+ Real *noise3 = &input(0,0,0);
+
+ // clear grids
+ for (int i = 0; i < n3; i++) {
+ temp13[i] = temp23[i] = 0.f;
+ }
+
+ // Steps 2 and 3. Downsample and upsample the tile
+ for (int iz = 0; iz < sz; iz++)
+ for (int iy = 0; iy < sy; iy++)
+ {
+ const int i = iz*sx*sy + iy*sx;
+ downsampleNeumann(&noise3[i], &temp13[i], sx, 1 );
+ upsampleNeumann (&temp13[i], &temp23[i], sx, 1);
+ }
+
+ for (int iz = 0; iz < sz; iz++)
+ for (int ix = 0; ix < sx; ix++)
+ {
+ const int i = iz*sx*sy + ix;
+ downsampleNeumann(&temp23[i], &temp13[i], sy, sx );
+ upsampleNeumann (&temp13[i], &temp23[i], sy, sx );
+ }
+
+ if(input.is3D()) {
+ for (int iy = 0; iy < sy; iy++)
+ for (int ix = 0; ix < sx; ix++)
+ {
+ const int i = iy*sx+ix;
+ downsampleNeumann(&temp23[i], &temp13[i], sz, sy*sx );
+ upsampleNeumann (&temp13[i], &temp23[i], sz, sy*sx );
+ }
+ }
+
+ // Step 4. Subtract out the coarse-scale contribution
+ for (int i = 0; i < n3; i++) {
+ Real residual = noise3[i] - temp23[i];
+ temp13[i] = sqrtf( fabs(residual) );
+ }
+
+ // copy back, and compute actual weight for wavelet turbulence...
+ Real smoothingFactor = 1./6.;
+ if(!input.is3D()) smoothingFactor = 1./4.;
+ FOR_IJK_BND(input,1) {
+ // apply some brute force smoothing
+ Real res = temp13[k*sx*sy+j*sx+i-1] + temp13[k*sx*sy+j*sx+i+1];
+ res += temp13[k*sx*sy+j*sx+i-sx] + temp13[k*sx*sy+j*sx+i+sx];
+ if( input.is3D()) res += temp13[k*sx*sy+j*sx+i-sx*sy] + temp13[k*sx*sy+j*sx+i+sx*sy];
+ input(i,j,k) = res * smoothingFactor;
+ }
+}
+
+
+
+
+
+}
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h
new file mode 100644
index 00000000000..f85f3d440d0
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h
@@ -0,0 +1,450 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Wavelet noise field
+ *
+ ******************************************************************************/
+
+#ifndef _NOISEFIELD_H_
+#define _NOISEFIELD_H_
+
+#include "vectorbase.h"
+#include "manta.h"
+#include "grid.h"
+#include <atomic>
+
+namespace Manta {
+
+#define NOISE_TILE_SIZE 128
+
+// wrapper for a parametrized field of wavelet noise
+
+class WaveletNoiseField : public PbClass { public:
+ WaveletNoiseField( FluidSolver* parent, int fixedSeed=-1 , int loadFromFile=false ); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "WaveletNoiseField::WaveletNoiseField" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); int fixedSeed = _args.getOpt<int >("fixedSeed",1,-1 ,&_lock); int loadFromFile = _args.getOpt<int >("loadFromFile",2,false ,&_lock); obj = new WaveletNoiseField(parent,fixedSeed,loadFromFile); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"WaveletNoiseField::WaveletNoiseField" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("WaveletNoiseField::WaveletNoiseField",e.what()); return -1; }
+ }
+
+ ~WaveletNoiseField() {
+ if(mNoiseTile && !mNoiseReferenceCount) { delete mNoiseTile; mNoiseTile=NULL; }
+ };
+
+ //! evaluate noise
+ inline Real evaluate(Vec3 pos, int tile=0) const;
+ //! evaluate noise as a vector
+ inline Vec3 evaluateVec(Vec3 pos, int tile=0) const;
+ //! evaluate curl noise
+ inline Vec3 evaluateCurl(Vec3 pos) const;
+
+ //! direct data access
+ Real* data() { return mNoiseTile; }
+
+ //! compute wavelet decomposition of an input grid (stores residual coefficients)
+ static void computeCoefficients(Grid<Real>& input, Grid<Real>& tempIn1, Grid<Real>& tempIn2);
+
+ // helper
+ std::string toString();
+
+ // texcoord position and scale
+ Vec3 mPosOffset;static PyObject* _GET_mPosOffset(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mPosOffset); }
+ static int _SET_mPosOffset(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mPosOffset = fromPy<Vec3 >(val); return 0; }
+
+ Vec3 mPosScale;static PyObject* _GET_mPosScale(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mPosScale); }
+ static int _SET_mPosScale(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mPosScale = fromPy<Vec3 >(val); return 0; }
+
+ // value offset & scale
+ Real mValOffset;static PyObject* _GET_mValOffset(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mValOffset); }
+ static int _SET_mValOffset(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mValOffset = fromPy<Real >(val); return 0; }
+
+ Real mValScale;static PyObject* _GET_mValScale(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mValScale); }
+ static int _SET_mValScale(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mValScale = fromPy<Real >(val); return 0; }
+
+ // clamp? (default 0-1)
+ bool mClamp;static PyObject* _GET_mClamp(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mClamp); }
+ static int _SET_mClamp(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mClamp = fromPy<bool >(val); return 0; }
+
+ Real mClampNeg;static PyObject* _GET_mClampNeg(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mClampNeg); }
+ static int _SET_mClampNeg(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mClampNeg = fromPy<Real >(val); return 0; }
+
+ Real mClampPos;static PyObject* _GET_mClampPos(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mClampPos); }
+ static int _SET_mClampPos(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mClampPos = fromPy<Real >(val); return 0; }
+
+ // animated over time
+ Real mTimeAnim;static PyObject* _GET_mTimeAnim(PyObject* self, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); return toPy(pbo->mTimeAnim); }
+ static int _SET_mTimeAnim(PyObject* self, PyObject* val, void* cl) {
+ WaveletNoiseField* pbo = dynamic_cast<WaveletNoiseField*>(Pb::objFromPy(self)); pbo->mTimeAnim = fromPy<Real >(val); return 0; }
+
+
+ protected:
+ // noise evaluation functions
+ static inline Real WNoiseDx (const Vec3& p, Real *data);
+ static inline Vec3 WNoiseVec(const Vec3& p, Real *data);
+ static inline Real WNoise (const Vec3& p, Real *data);
+
+ // helpers for tile generation , for periodic 128 grids only
+ static void downsample(Real *from, Real *to, int n, int stride);
+ static void upsample (Real *from, Real *to, int n, int stride);
+
+ // for grids with arbitrary sizes, and neumann boundary conditions
+ static void downsampleNeumann(const Real *from, Real *to, int n, int stride);
+ static void upsampleNeumann (const Real *from, Real *to, int n, int stride);
+
+ static inline int modSlow(int x, int n) { int m = x % n; return (m<0) ? m+n : m; }
+ // warning - noiseTileSize has to be 128^3!
+ #define modFast128(x) ((x) & 127)
+
+ inline Real getTime() const { return mParent->getTime() * mParent->getDx() * mTimeAnim; }
+
+ // pre-compute tile data for wavelet noise
+ void generateTile( int loadFromFile );
+
+ // animation over time
+ // grid size normalization (inverse size)
+ Real mGsInvX, mGsInvY, mGsInvZ;
+ // random offset into tile to simulate different random seeds
+ Vec3 mSeedOffset;
+
+ static Real* mNoiseTile;
+ // global random seed storage
+ static int randomSeed;
+ // global reference count for noise tile
+ static std::atomic<int> mNoiseReferenceCount; public: PbArgs _args; }
+#define _C_WaveletNoiseField
+;
+
+
+
+// **************************************************************************
+// Implementation
+
+#define ADD_WEIGHTED(x,y,z)\
+ weight = 1.0f;\
+ xC = modFast128(midX + (x));\
+ weight *= w[0][(x) + 1];\
+ yC = modFast128(midY + (y));\
+ weight *= w[1][(y) + 1];\
+ zC = modFast128(midZ + (z));\
+ weight *= w[2][(z) + 1];\
+ result += weight * data[(zC * NOISE_TILE_SIZE + yC) * NOISE_TILE_SIZE + xC];
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// derivatives of 3D noise - unrolled for performance
+//////////////////////////////////////////////////////////////////////////////////////////
+inline Real WaveletNoiseField::WNoiseDx(const Vec3& p, Real *data) {
+ Real w[3][3], t, result = 0;
+
+ // Evaluate quadratic B-spline basis functions
+ int midX = (int)ceil(p[0] - 0.5f);
+ t = midX - (p[0] - 0.5f);
+ w[0][0] = -t;
+ w[0][2] = (1.f - t);
+ w[0][1] = 2.0f * t - 1.0f;
+
+ int midY = (int)ceil(p[1] - 0.5f);
+ t = midY - (p[1] - 0.5f);
+ w[1][0] = t * t * 0.5f;
+ w[1][2] = (1.f - t) * (1.f - t) *0.5f;
+ w[1][1] = 1.f - w[1][0] - w[1][2];
+
+ int midZ = (int)ceil(p[2] - 0.5f);
+ t = midZ - (p[2] - 0.5f);
+ w[2][0] = t * t * 0.5f;
+ w[2][2] = (1.f - t) * (1.f - t) *0.5f;
+ w[2][1] = 1.f - w[2][0] - w[2][2];
+
+ // Evaluate noise by weighting noise coefficients by basis function values
+ int xC, yC, zC;
+ Real weight = 1;
+
+ ADD_WEIGHTED(-1,-1, -1); ADD_WEIGHTED( 0,-1, -1); ADD_WEIGHTED( 1,-1, -1);
+ ADD_WEIGHTED(-1, 0, -1); ADD_WEIGHTED( 0, 0, -1); ADD_WEIGHTED( 1, 0, -1);
+ ADD_WEIGHTED(-1, 1, -1); ADD_WEIGHTED( 0, 1, -1); ADD_WEIGHTED( 1, 1, -1);
+
+ ADD_WEIGHTED(-1,-1, 0); ADD_WEIGHTED( 0,-1, 0); ADD_WEIGHTED( 1,-1, 0);
+ ADD_WEIGHTED(-1, 0, 0); ADD_WEIGHTED( 0, 0, 0); ADD_WEIGHTED( 1, 0, 0);
+ ADD_WEIGHTED(-1, 1, 0); ADD_WEIGHTED( 0, 1, 0); ADD_WEIGHTED( 1, 1, 0);
+
+ ADD_WEIGHTED(-1,-1, 1); ADD_WEIGHTED( 0,-1, 1); ADD_WEIGHTED( 1,-1, 1);
+ ADD_WEIGHTED(-1, 0, 1); ADD_WEIGHTED( 0, 0, 1); ADD_WEIGHTED( 1, 0, 1);
+ ADD_WEIGHTED(-1, 1, 1); ADD_WEIGHTED( 0, 1, 1); ADD_WEIGHTED( 1, 1, 1);
+
+ return result;
+}
+
+inline Real WaveletNoiseField::WNoise(const Vec3& p, Real *data) {
+ Real w[3][3], t, result = 0;
+
+ // Evaluate quadratic B-spline basis functions
+ int midX = (int)ceilf(p[0] - 0.5f);
+ t = midX - (p[0] - 0.5f);
+ w[0][0] = t * t * 0.5f;
+ w[0][2] = (1.f - t) * (1.f - t) *0.5f;
+ w[0][1] = 1.f - w[0][0] - w[0][2];
+
+ int midY = (int)ceilf(p[1] - 0.5f);
+ t = midY - (p[1] - 0.5f);
+ w[1][0] = t * t * 0.5f;
+ w[1][2] = (1.f - t) * (1.f - t) *0.5f;
+ w[1][1] = 1.f - w[1][0] - w[1][2];
+
+ int midZ = (int)ceilf(p[2] - 0.5f);
+ t = midZ - (p[2] - 0.5f);
+ w[2][0] = t * t * 0.5f;
+ w[2][2] = (1.f - t) * (1.f - t) *0.5f;
+ w[2][1] = 1.f - w[2][0] - w[2][2];
+
+ // Evaluate noise by weighting noise coefficients by basis function values
+ int xC, yC, zC;
+ Real weight = 1;
+
+ ADD_WEIGHTED(-1,-1, -1); ADD_WEIGHTED( 0,-1, -1); ADD_WEIGHTED( 1,-1, -1);
+ ADD_WEIGHTED(-1, 0, -1); ADD_WEIGHTED( 0, 0, -1); ADD_WEIGHTED( 1, 0, -1);
+ ADD_WEIGHTED(-1, 1, -1); ADD_WEIGHTED( 0, 1, -1); ADD_WEIGHTED( 1, 1, -1);
+
+ ADD_WEIGHTED(-1,-1, 0); ADD_WEIGHTED( 0,-1, 0); ADD_WEIGHTED( 1,-1, 0);
+ ADD_WEIGHTED(-1, 0, 0); ADD_WEIGHTED( 0, 0, 0); ADD_WEIGHTED( 1, 0, 0);
+ ADD_WEIGHTED(-1, 1, 0); ADD_WEIGHTED( 0, 1, 0); ADD_WEIGHTED( 1, 1, 0);
+
+ ADD_WEIGHTED(-1,-1, 1); ADD_WEIGHTED( 0,-1, 1); ADD_WEIGHTED( 1,-1, 1);
+ ADD_WEIGHTED(-1, 0, 1); ADD_WEIGHTED( 0, 0, 1); ADD_WEIGHTED( 1, 0, 1);
+ ADD_WEIGHTED(-1, 1, 1); ADD_WEIGHTED( 0, 1, 1); ADD_WEIGHTED( 1, 1, 1);
+
+ return result;
+}
+
+
+
+#define ADD_WEIGHTEDX(x,y,z)\
+ weight = dw[0][(x) + 1] * w[1][(y) + 1] * w[2][(z) + 1];\
+ result += weight * neighbors[x + 1][y + 1][z + 1];
+
+#define ADD_WEIGHTEDY(x,y,z)\
+ weight = w[0][(x) + 1] * dw[1][(y) + 1] * w[2][(z) + 1];\
+ result += weight * neighbors[x + 1][y + 1][z + 1];
+
+#define ADD_WEIGHTEDZ(x,y,z)\
+ weight = w[0][(x) + 1] * w[1][(y) + 1] * dw[2][(z) + 1];\
+ result += weight * neighbors[x + 1][y + 1][z + 1];
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// compute all derivatives in at once
+//////////////////////////////////////////////////////////////////////////////////////////
+inline Vec3 WaveletNoiseField::WNoiseVec(const Vec3& p, Real *data)
+{
+ Vec3 final(0.);
+ Real w[3][3];
+ Real dw[3][3];
+ Real result = 0;
+ int xC, yC, zC;
+ Real weight;
+
+ int midX = (int)ceil(p[0] - 0.5f);
+ int midY = (int)ceil(p[1] - 0.5f);
+ int midZ = (int)ceil(p[2] - 0.5f);
+
+ Real t0 = midX - (p[0] - 0.5f);
+ Real t1 = midY - (p[1] - 0.5f);
+ Real t2 = midZ - (p[2] - 0.5f);
+
+ // precache all the neighbors for fast access
+ Real neighbors[3][3][3];
+ for (int z = -1; z <=1; z++)
+ for (int y = -1; y <= 1; y++)
+ for (int x = -1; x <= 1; x++)
+ {
+ xC = modFast128(midX + (x));
+ yC = modFast128(midY + (y));
+ zC = modFast128(midZ + (z));
+ neighbors[x + 1][y + 1][z + 1] = data[zC * NOISE_TILE_SIZE * NOISE_TILE_SIZE + yC * NOISE_TILE_SIZE + xC];
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // evaluate splines
+ ///////////////////////////////////////////////////////////////////////////////////////
+ dw[0][0] = -t0;
+ dw[0][2] = (1.f - t0);
+ dw[0][1] = 2.0f * t0 - 1.0f;
+
+ dw[1][0] = -t1;
+ dw[1][2] = (1.0f - t1);
+ dw[1][1] = 2.0f * t1 - 1.0f;
+
+ dw[2][0] = -t2;
+ dw[2][2] = (1.0f - t2);
+ dw[2][1] = 2.0f * t2 - 1.0f;
+
+ w[0][0] = t0 * t0 * 0.5f;
+ w[0][2] = (1.f - t0) * (1.f - t0) *0.5f;
+ w[0][1] = 1.f - w[0][0] - w[0][2];
+
+ w[1][0] = t1 * t1 * 0.5f;
+ w[1][2] = (1.f - t1) * (1.f - t1) *0.5f;
+ w[1][1] = 1.f - w[1][0] - w[1][2];
+
+ w[2][0] = t2 * t2 * 0.5f;
+ w[2][2] = (1.f - t2) * (1.f - t2) *0.5f;
+ w[2][1] = 1.f - w[2][0] - w[2][2];
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // x derivative
+ ///////////////////////////////////////////////////////////////////////////////////////
+ result = 0.0f;
+ ADD_WEIGHTEDX(-1,-1, -1); ADD_WEIGHTEDX( 0,-1, -1); ADD_WEIGHTEDX( 1,-1, -1);
+ ADD_WEIGHTEDX(-1, 0, -1); ADD_WEIGHTEDX( 0, 0, -1); ADD_WEIGHTEDX( 1, 0, -1);
+ ADD_WEIGHTEDX(-1, 1, -1); ADD_WEIGHTEDX( 0, 1, -1); ADD_WEIGHTEDX( 1, 1, -1);
+
+ ADD_WEIGHTEDX(-1,-1, 0); ADD_WEIGHTEDX( 0,-1, 0); ADD_WEIGHTEDX( 1,-1, 0);
+ ADD_WEIGHTEDX(-1, 0, 0); ADD_WEIGHTEDX( 0, 0, 0); ADD_WEIGHTEDX( 1, 0, 0);
+ ADD_WEIGHTEDX(-1, 1, 0); ADD_WEIGHTEDX( 0, 1, 0); ADD_WEIGHTEDX( 1, 1, 0);
+
+ ADD_WEIGHTEDX(-1,-1, 1); ADD_WEIGHTEDX( 0,-1, 1); ADD_WEIGHTEDX( 1,-1, 1);
+ ADD_WEIGHTEDX(-1, 0, 1); ADD_WEIGHTEDX( 0, 0, 1); ADD_WEIGHTEDX( 1, 0, 1);
+ ADD_WEIGHTEDX(-1, 1, 1); ADD_WEIGHTEDX( 0, 1, 1); ADD_WEIGHTEDX( 1, 1, 1);
+ final[0] = result;
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // y derivative
+ ///////////////////////////////////////////////////////////////////////////////////////
+ result = 0.0f;
+ ADD_WEIGHTEDY(-1,-1, -1); ADD_WEIGHTEDY( 0,-1, -1); ADD_WEIGHTEDY( 1,-1, -1);
+ ADD_WEIGHTEDY(-1, 0, -1); ADD_WEIGHTEDY( 0, 0, -1); ADD_WEIGHTEDY( 1, 0, -1);
+ ADD_WEIGHTEDY(-1, 1, -1); ADD_WEIGHTEDY( 0, 1, -1); ADD_WEIGHTEDY( 1, 1, -1);
+
+ ADD_WEIGHTEDY(-1,-1, 0); ADD_WEIGHTEDY( 0,-1, 0); ADD_WEIGHTEDY( 1,-1, 0);
+ ADD_WEIGHTEDY(-1, 0, 0); ADD_WEIGHTEDY( 0, 0, 0); ADD_WEIGHTEDY( 1, 0, 0);
+ ADD_WEIGHTEDY(-1, 1, 0); ADD_WEIGHTEDY( 0, 1, 0); ADD_WEIGHTEDY( 1, 1, 0);
+
+ ADD_WEIGHTEDY(-1,-1, 1); ADD_WEIGHTEDY( 0,-1, 1); ADD_WEIGHTEDY( 1,-1, 1);
+ ADD_WEIGHTEDY(-1, 0, 1); ADD_WEIGHTEDY( 0, 0, 1); ADD_WEIGHTEDY( 1, 0, 1);
+ ADD_WEIGHTEDY(-1, 1, 1); ADD_WEIGHTEDY( 0, 1, 1); ADD_WEIGHTEDY( 1, 1, 1);
+ final[1] = result;
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // z derivative
+ ///////////////////////////////////////////////////////////////////////////////////////
+ result = 0.0f;
+ ADD_WEIGHTEDZ(-1,-1, -1); ADD_WEIGHTEDZ( 0,-1, -1); ADD_WEIGHTEDZ( 1,-1, -1);
+ ADD_WEIGHTEDZ(-1, 0, -1); ADD_WEIGHTEDZ( 0, 0, -1); ADD_WEIGHTEDZ( 1, 0, -1);
+ ADD_WEIGHTEDZ(-1, 1, -1); ADD_WEIGHTEDZ( 0, 1, -1); ADD_WEIGHTEDZ( 1, 1, -1);
+
+ ADD_WEIGHTEDZ(-1,-1, 0); ADD_WEIGHTEDZ( 0,-1, 0); ADD_WEIGHTEDZ( 1,-1, 0);
+ ADD_WEIGHTEDZ(-1, 0, 0); ADD_WEIGHTEDZ( 0, 0, 0); ADD_WEIGHTEDZ( 1, 0, 0);
+ ADD_WEIGHTEDZ(-1, 1, 0); ADD_WEIGHTEDZ( 0, 1, 0); ADD_WEIGHTEDZ( 1, 1, 0);
+
+ ADD_WEIGHTEDZ(-1,-1, 1); ADD_WEIGHTEDZ( 0,-1, 1); ADD_WEIGHTEDZ( 1,-1, 1);
+ ADD_WEIGHTEDZ(-1, 0, 1); ADD_WEIGHTEDZ( 0, 0, 1); ADD_WEIGHTEDZ( 1, 0, 1);
+ ADD_WEIGHTEDZ(-1, 1, 1); ADD_WEIGHTEDZ( 0, 1, 1); ADD_WEIGHTEDZ( 1, 1, 1);
+ final[2] = result;
+
+ //debMsg("FINAL","at "<<p<<" = "<<final); // DEBUG
+ return final;
+}
+#undef ADD_WEIGHTEDX
+#undef ADD_WEIGHTEDY
+#undef ADD_WEIGHTEDZ
+
+inline Real WaveletNoiseField::evaluate(Vec3 pos, int tile) const {
+ pos[0] *= mGsInvX;
+ pos[1] *= mGsInvY;
+ pos[2] *= mGsInvZ;
+ pos += mSeedOffset;
+
+ // time anim
+ pos += Vec3(getTime());
+
+ pos[0] *= mPosScale[0];
+ pos[1] *= mPosScale[1];
+ pos[2] *= mPosScale[2];
+ pos += mPosOffset;
+
+ const int n3 = square(NOISE_TILE_SIZE) * NOISE_TILE_SIZE;
+ Real v = WNoise(pos, &mNoiseTile[tile*n3]);
+
+ v += mValOffset;
+ v *= mValScale;
+ if (mClamp) {
+ if (v< mClampNeg) v = mClampNeg;
+ if (v> mClampPos) v = mClampPos;
+ }
+ return v;
+}
+
+inline Vec3 WaveletNoiseField::evaluateVec(Vec3 pos, int tile) const {
+ pos[0] *= mGsInvX;
+ pos[1] *= mGsInvY;
+ pos[2] *= mGsInvZ;
+ pos += mSeedOffset;
+
+ // time anim
+ pos += Vec3(getTime());
+
+ pos[0] *= mPosScale[0];
+ pos[1] *= mPosScale[1];
+ pos[2] *= mPosScale[2];
+ pos += mPosOffset;
+
+ const int n3 = square(NOISE_TILE_SIZE) * NOISE_TILE_SIZE;
+ Vec3 v = WNoiseVec(pos, &mNoiseTile[tile*n3]);
+
+ v += Vec3(mValOffset);
+ v *= mValScale;
+
+ if (mClamp) {
+ for(int i=0; i<3; i++) {
+ if (v[i]< mClampNeg) v[i] = mClampNeg;
+ if (v[i]> mClampPos) v[i] = mClampPos;
+ }
+ }
+ return v;
+}
+
+inline Vec3 WaveletNoiseField::evaluateCurl(Vec3 pos) const {
+ // gradients of w0-w2
+ Vec3 d0 = evaluateVec(pos,0),
+ d1 = evaluateVec(pos,1),
+ d2 = evaluateVec(pos,2);
+
+ return Vec3(d0.y-d1.z, d2.z-d0.x, d1.x-d2.y);
+}
+
+} // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h.reg
new file mode 100644
index 00000000000..74b1bd96478
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h.reg
@@ -0,0 +1,12 @@
+#include "noisefield.h"
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","NoiseField","PbClass"); template<> const char* Namify<WaveletNoiseField >::S = "WaveletNoiseField";
+>WaveletNoiseField^
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","WaveletNoiseField",WaveletNoiseField::_W_0);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","posOffset",WaveletNoiseField::_GET_mPosOffset,WaveletNoiseField::_SET_mPosOffset);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","posScale",WaveletNoiseField::_GET_mPosScale,WaveletNoiseField::_SET_mPosScale);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","valOffset",WaveletNoiseField::_GET_mValOffset,WaveletNoiseField::_SET_mValOffset);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","valScale",WaveletNoiseField::_GET_mValScale,WaveletNoiseField::_SET_mValScale);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","clamp",WaveletNoiseField::_GET_mClamp,WaveletNoiseField::_SET_mClamp);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","clampNeg",WaveletNoiseField::_GET_mClampNeg,WaveletNoiseField::_SET_mClampNeg);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","clampPos",WaveletNoiseField::_GET_mClampPos,WaveletNoiseField::_SET_mClampPos);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","timeAnim",WaveletNoiseField::_GET_mTimeAnim,WaveletNoiseField::_SET_mTimeAnim);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h.reg.cpp
new file mode 100644
index 00000000000..6eed65f816b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/noisefield.h.reg.cpp
@@ -0,0 +1,40 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "noisefield.h"
+namespace Manta {
+#ifdef _C_WaveletNoiseField
+ static const Pb::Register _R_13 ("WaveletNoiseField","NoiseField","PbClass"); template<> const char* Namify<WaveletNoiseField >::S = "WaveletNoiseField";
+ static const Pb::Register _R_14 ("WaveletNoiseField","WaveletNoiseField",WaveletNoiseField::_W_0);
+ static const Pb::Register _R_15 ("WaveletNoiseField","posOffset",WaveletNoiseField::_GET_mPosOffset,WaveletNoiseField::_SET_mPosOffset);
+ static const Pb::Register _R_16 ("WaveletNoiseField","posScale",WaveletNoiseField::_GET_mPosScale,WaveletNoiseField::_SET_mPosScale);
+ static const Pb::Register _R_17 ("WaveletNoiseField","valOffset",WaveletNoiseField::_GET_mValOffset,WaveletNoiseField::_SET_mValOffset);
+ static const Pb::Register _R_18 ("WaveletNoiseField","valScale",WaveletNoiseField::_GET_mValScale,WaveletNoiseField::_SET_mValScale);
+ static const Pb::Register _R_19 ("WaveletNoiseField","clamp",WaveletNoiseField::_GET_mClamp,WaveletNoiseField::_SET_mClamp);
+ static const Pb::Register _R_20 ("WaveletNoiseField","clampNeg",WaveletNoiseField::_GET_mClampNeg,WaveletNoiseField::_SET_mClampNeg);
+ static const Pb::Register _R_21 ("WaveletNoiseField","clampPos",WaveletNoiseField::_GET_mClampPos,WaveletNoiseField::_SET_mClampPos);
+ static const Pb::Register _R_22 ("WaveletNoiseField","timeAnim",WaveletNoiseField::_GET_mTimeAnim,WaveletNoiseField::_SET_mTimeAnim);
+#endif
+extern "C" {
+void PbRegister_file_13()
+{
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.cpp
new file mode 100644
index 00000000000..41accec6159
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.cpp
@@ -0,0 +1,986 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2013 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Particle data functionality
+ *
+ ******************************************************************************/
+
+#include <fstream>
+#include <cstring>
+#if NO_ZLIB!=1
+#include <zlib.h>
+#endif
+#include "particle.h"
+#include "levelset.h"
+#include "mantaio.h"
+
+using namespace std;
+namespace Manta {
+
+
+ParticleBase::ParticleBase(FluidSolver* parent)
+ : PbClass(parent), mAllowCompress(true), mFreePdata(false)
+{
+}
+
+ParticleBase::~ParticleBase()
+{
+ // make sure data fields now parent system is deleted
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i)
+ mPartData[i]->setParticleSys(NULL);
+
+ if(mFreePdata) {
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i)
+ delete mPartData[i];
+ }
+
+}
+
+std::string ParticleBase::infoString() const
+{
+ return "ParticleSystem " + mName + " <no info>";
+}
+
+void ParticleBase::cloneParticleData(ParticleBase* nm)
+{
+ // clone additional data , and make sure the copied particle system deletes it
+ nm->mFreePdata = true;
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i) {
+ ParticleDataBase* pdata = mPartData[i]->clone();
+ nm->registerPdata(pdata);
+ }
+}
+
+void ParticleBase::deregister(ParticleDataBase* pdata)
+{
+ bool done = false;
+ // remove pointer from particle data list
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i) {
+ if(mPartData[i] == pdata) {
+ if(i<(IndexInt)mPartData.size()-1)
+ mPartData[i] = mPartData[mPartData.size()-1];
+ mPartData.pop_back();
+ done = true;
+ }
+ }
+ if(!done)
+ errMsg("Invalid pointer given, not registered!");
+}
+
+// create and attach a new pdata field to this particle system
+PbClass* ParticleBase::create(PbType t, PbTypeVec T, const string& name)
+{
+# if NOPYTHON!=1
+ _args.add("nocheck",true);
+ if(t.str() == "") errMsg("Specify particle data type to create");
+ //debMsg( "Pdata creating '"<< t.str <<" with size "<< this->getSizeSlow(), 5 );
+
+ PbClass* pyObj = PbClass::createPyObject(t.str() + T.str(), name, _args, this->getParent());
+
+ ParticleDataBase* pdata = dynamic_cast<ParticleDataBase*>(pyObj);
+ if(!pdata) {
+ errMsg("Unable to get particle data pointer from newly created object. Only create ParticleData type with a ParticleSys.creat() call, eg, PdataReal, PdataVec3 etc.");
+ delete pyObj;
+ return NULL;
+ } else {
+ this->registerPdata(pdata);
+ }
+
+ // directly init size of new pdata field:
+ pdata->resize(this->getSizeSlow());
+# else
+ PbClass* pyObj = NULL;
+# endif
+ return pyObj;
+}
+
+void ParticleBase::registerPdata(ParticleDataBase* pdata)
+{
+ pdata->setParticleSys(this);
+ mPartData.push_back(pdata);
+
+ if(pdata->getType() == ParticleDataBase::TypeReal) {
+ ParticleDataImpl<Real>* pd = dynamic_cast< ParticleDataImpl<Real>* >(pdata);
+ if(!pd) errMsg("Invalid pdata object posing as real!");
+ this->registerPdataReal(pd);
+ } else if(pdata->getType() == ParticleDataBase::TypeInt) {
+ ParticleDataImpl<int>* pd = dynamic_cast< ParticleDataImpl<int>* >(pdata);
+ if(!pd) errMsg("Invalid pdata object posing as int!");
+ this->registerPdataInt(pd);
+ } else if(pdata->getType() == ParticleDataBase::TypeVec3) {
+ ParticleDataImpl<Vec3>* pd = dynamic_cast< ParticleDataImpl<Vec3>* >(pdata);
+ if(!pd) errMsg("Invalid pdata object posing as vec3!");
+ this->registerPdataVec3(pd);
+ }
+}
+void ParticleBase::registerPdataReal(ParticleDataImpl<Real>* pd) { mPdataReal.push_back(pd); }
+void ParticleBase::registerPdataVec3(ParticleDataImpl<Vec3>* pd) { mPdataVec3.push_back(pd); }
+void ParticleBase::registerPdataInt (ParticleDataImpl<int >* pd) { mPdataInt .push_back(pd); }
+
+void ParticleBase::addAllPdata()
+{
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i) {
+ mPartData[i]->addEntry();
+ }
+}
+
+
+BasicParticleSystem::BasicParticleSystem(FluidSolver* parent)
+ : ParticleSystem<BasicParticleData>(parent)
+{
+ this->mAllowCompress = false;
+}
+
+// file io
+
+void BasicParticleSystem::writeParticlesText(const string name) const
+{
+ ofstream ofs(name.c_str());
+ if(!ofs.good()) errMsg("can't open file!");
+ ofs << this->size()<<", pdata: "<< mPartData.size()<<" ("<<mPdataInt.size()<<","<<mPdataReal.size()<<","<<mPdataVec3.size()<<") \n";
+ for(IndexInt i=0; i<this->size(); ++i) {
+ ofs << i<<": "<< this->getPos(i) <<" , "<< this->getStatus(i) <<". ";
+ for(IndexInt pd=0; pd<(IndexInt)mPdataInt.size() ; ++pd) ofs << mPdataInt [pd]->get(i)<<" ";
+ for(IndexInt pd=0; pd<(IndexInt)mPdataReal.size(); ++pd) ofs << mPdataReal[pd]->get(i)<<" ";
+ for(IndexInt pd=0; pd<(IndexInt)mPdataVec3.size(); ++pd) ofs << mPdataVec3[pd]->get(i)<<" ";
+ ofs << "\n";
+ }
+ ofs.close();
+}
+
+void BasicParticleSystem::writeParticlesRawPositionsGz(const string name) const
+{
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "wb1");
+ if(!gzf) errMsg("can't open file "<<name);
+ for(IndexInt i=0; i<this->size(); ++i) {
+ Vector3D<float> p = toVec3f(this->getPos(i));
+ gzwrite(gzf, &p, sizeof(float)*3);
+ }
+ gzclose(gzf);
+# else
+ cout << "file format not supported without zlib" << endl;
+# endif
+}
+
+void BasicParticleSystem::writeParticlesRawVelocityGz(const string name) const
+{
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "wb1");
+ if (!gzf) errMsg("can't open file "<<name);
+ if( mPdataVec3.size() < 1 ) errMsg("no vec3 particle data channel found!");
+ // note , assuming particle data vec3 0 is velocity! make optional...
+ for(IndexInt i=0; i<this->size(); ++i) {
+ Vector3D<float> p = toVec3f(mPdataVec3[0]->get(i));
+ gzwrite(gzf, &p, sizeof(float)*3);
+ }
+ gzclose(gzf);
+# else
+ cout << "file format not supported without zlib" << endl;
+# endif
+}
+
+
+void BasicParticleSystem::load(const string name)
+{
+ if(name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if(ext == ".uni")
+ readParticlesUni(name, this );
+ else if(ext == ".raw") // raw = uni for now
+ readParticlesUni(name, this );
+ else
+ errMsg("particle '" + name +"' filetype not supported for loading");
+}
+
+void BasicParticleSystem::save(const string name) const
+{
+ if(name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if(ext == ".txt")
+ this->writeParticlesText(name);
+ else if(ext == ".uni")
+ writeParticlesUni(name, this);
+ else if(ext == ".raw") // raw = uni for now
+ writeParticlesUni(name, this);
+ // raw data formats, very basic for simple data transfer to other programs
+ else if(ext == ".posgz")
+ this->writeParticlesRawPositionsGz(name);
+ else if(ext == ".velgz")
+ this->writeParticlesRawVelocityGz(name);
+ else
+ errMsg("particle '" + name +"' filetype not supported for saving");
+}
+
+void BasicParticleSystem::printParts(IndexInt start, IndexInt stop, bool printIndex)
+{
+ std::ostringstream sstr;
+ IndexInt s = (start>0 ? start : 0 );
+ IndexInt e = (stop>0 ? stop : (IndexInt)mData.size() );
+ s = Manta::clamp(s, (IndexInt)0, (IndexInt)mData.size());
+ e = Manta::clamp(e, (IndexInt)0, (IndexInt)mData.size());
+
+ for(IndexInt i=s; i<e; ++i) {
+ if(printIndex) sstr << i<<": ";
+ sstr<<mData[i].pos<<" "<<mData[i].flag<<"\n";
+ }
+ debMsg( sstr.str() , 1 );
+}
+
+std::string BasicParticleSystem::getDataPointer() {
+ std::ostringstream out;
+ out << &mData;
+ return out.str();
+}
+
+void BasicParticleSystem::readParticles(BasicParticleSystem* from) {
+ // re-allocate all data
+ this->resizeAll(from->size());
+ assertMsg(from->size() == this->size() , "particle size doesn't match");
+
+ for(int i=0; i<this->size(); ++i) {
+ (*this)[i].pos = (*from)[i].pos;
+ (*this)[i].flag = (*from)[i].flag;
+ }
+ this->transformPositions(from->getParent()->getGridSize(), this->getParent()->getGridSize());
+}
+
+
+// particle data
+
+ParticleDataBase::ParticleDataBase(FluidSolver* parent)
+ : PbClass(parent), mpParticleSys(NULL)
+{
+}
+
+ParticleDataBase::~ParticleDataBase()
+{
+ // notify parent of deletion
+ if(mpParticleSys)
+ mpParticleSys->deregister(this);
+}
+
+
+// actual data implementation
+
+template<class T>
+ParticleDataImpl<T>::ParticleDataImpl(FluidSolver* parent)
+ : ParticleDataBase(parent), mpGridSource(NULL), mGridSourceMAC(false)
+{
+}
+
+template<class T>
+ParticleDataImpl<T>::ParticleDataImpl(FluidSolver* parent, ParticleDataImpl<T>* other)
+ : ParticleDataBase(parent), mpGridSource(NULL), mGridSourceMAC(false)
+{
+ this->mData = other->mData;
+ setName(other->getName());
+}
+
+template<class T>
+ParticleDataImpl<T>::~ParticleDataImpl()
+{
+}
+
+template<class T>
+IndexInt ParticleDataImpl<T>::getSizeSlow() const
+{
+ return mData.size();
+}
+template<class T>
+void ParticleDataImpl<T>::addEntry()
+{
+ // add zero'ed entry
+ T tmp = T(0.);
+ // for debugging, force init:
+ //tmp = T(0.02 * mData.size()); // increasing
+ //tmp = T(1.); // constant 1
+ return mData.push_back(tmp);
+}
+template<class T>
+void ParticleDataImpl<T>::resize(IndexInt s)
+{
+ mData.resize(s);
+}
+template<class T>
+void ParticleDataImpl<T>::copyValueSlow(IndexInt from, IndexInt to)
+{
+ this->copyValue(from,to);
+}
+template<class T>
+ParticleDataBase* ParticleDataImpl<T>::clone()
+{
+ ParticleDataImpl<T>* npd = new ParticleDataImpl<T>(getParent(), this);
+ return npd;
+}
+
+template<class T>
+void ParticleDataImpl<T>::setSource(Grid<T>* grid, bool isMAC)
+{
+ mpGridSource = grid;
+ mGridSourceMAC = isMAC;
+ if(isMAC) assertMsg(dynamic_cast<MACGrid*>(grid) != NULL , "Given grid is not a valid MAC grid");
+}
+
+template<class T>
+void ParticleDataImpl<T>::initNewValue(IndexInt idx, Vec3 pos)
+{
+ if(!mpGridSource)
+ mData[idx] = 0;
+ else {
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ }
+}
+// special handling needed for velocities
+template<>
+void ParticleDataImpl<Vec3>::initNewValue(IndexInt idx, Vec3 pos)
+{
+ if(!mpGridSource)
+ mData[idx] = 0;
+ else {
+ if(!mGridSourceMAC)
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ else
+ mData[idx] = ((MACGrid*)mpGridSource)->getInterpolated(pos);
+ }
+}
+
+template<typename T>
+void ParticleDataImpl<T>::load(string name)
+{
+ if(name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if(ext == ".uni")
+ readPdataUni<T>(name, this);
+ else if(ext == ".raw") // raw = uni for now
+ readPdataUni<T>(name, this);
+ else
+ errMsg("particle data '" + name +"' filetype not supported for loading");
+}
+
+template<typename T>
+void ParticleDataImpl<T>::save(string name)
+{
+ if(name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+ if(ext == ".uni")
+ writePdataUni<T>(name, this);
+ else if(ext == ".raw") // raw = uni for now
+ writePdataUni<T>(name, this);
+ else
+ errMsg("particle data '" + name +"' filetype not supported for saving");
+}
+
+// specializations
+
+template<>
+ParticleDataBase::PdataType ParticleDataImpl<Real>::getType() const
+{
+ return ParticleDataBase::TypeReal;
+}
+template<>
+ParticleDataBase::PdataType ParticleDataImpl<int>::getType() const
+{
+ return ParticleDataBase::TypeInt;
+}
+template<>
+ParticleDataBase::PdataType ParticleDataImpl<Vec3>::getType() const
+{
+ return ParticleDataBase::TypeVec3;
+}
+
+// note, we need a flag value for functions such as advection
+// ideally, this value should never be modified
+int ParticleIndexData::flag = 0;
+Vec3 ParticleIndexData::pos = Vec3(0.,0.,0.);
+
+template <class T, class S> struct knPdataAdd : public KernelBase {
+ knPdataAdd(ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) const { me[idx] += other[idx]; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<S>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knPdataAdd ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<S>& other; }
+;
+template <class T, class S> struct knPdataSub : public KernelBase {
+ knPdataSub(ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) const { me[idx] -= other[idx]; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<S>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knPdataSub ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<S>& other; }
+;
+template <class T, class S> struct knPdataMult : public KernelBase {
+ knPdataMult(ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) const { me[idx] *= other[idx]; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<S>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knPdataMult ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<S>& other; }
+;
+template <class T, class S> struct knPdataDiv : public KernelBase {
+ knPdataDiv(ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) const { me[idx] /= other[idx]; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<S>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<S> type1; void runMessage() { debMsg("Executing kernel knPdataDiv ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<S>& other; }
+;
+template <class T> struct knPdataSafeDiv : public KernelBase {
+ knPdataSafeDiv(ParticleDataImpl<T>& me, const ParticleDataImpl<T>& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<T>& other ) const { me[idx] = safeDivide(me[idx], other[idx]); } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<T>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<T> type1; void runMessage() { debMsg("Executing kernel knPdataSafeDiv ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<T>& other; }
+;
+
+template <class T, class S> struct knPdataSetScalar : public KernelBase {
+ knPdataSetScalar(ParticleDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const S& other ) const { me[idx] = other; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knPdataSetScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knPdataAddScalar : public KernelBase {
+ knPdataAddScalar(ParticleDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const S& other ) const { me[idx] += other; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knPdataAddScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knPdataMultScalar : public KernelBase {
+ knPdataMultScalar(ParticleDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const S& other ) const { me[idx] *= other; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1; void runMessage() { debMsg("Executing kernel knPdataMultScalar ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const S& other; }
+;
+template <class T, class S> struct knPdataScaledAdd : public KernelBase {
+ knPdataScaledAdd(ParticleDataImpl<T>& me, const ParticleDataImpl<T>& other, const S& factor) : KernelBase(me.size()) ,me(me),other(other),factor(factor) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const ParticleDataImpl<T>& other, const S& factor ) const { me[idx] += factor * other[idx]; } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<T>& getArg1() {
+ return other; }
+ typedef ParticleDataImpl<T> type1;inline const S& getArg2() {
+ return factor; }
+ typedef S type2; void runMessage() { debMsg("Executing kernel knPdataScaledAdd ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other,factor); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const ParticleDataImpl<T>& other; const S& factor; }
+;
+
+template <class T> struct knPdataClamp : public KernelBase {
+ knPdataClamp(ParticleDataImpl<T>& me, const T vmin, const T vmax) : KernelBase(me.size()) ,me(me),vmin(vmin),vmax(vmax) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const T vmin, const T vmax ) const { me[idx] = clamp(me[idx], vmin, vmax); } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const T& getArg1() {
+ return vmin; }
+ typedef T type1;inline const T& getArg2() {
+ return vmax; }
+ typedef T type2; void runMessage() { debMsg("Executing kernel knPdataClamp ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,vmin,vmax); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const T vmin; const T vmax; }
+;
+template <class T> struct knPdataClampMin : public KernelBase {
+ knPdataClampMin(ParticleDataImpl<T>& me, const T vmin) : KernelBase(me.size()) ,me(me),vmin(vmin) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const T vmin ) const { me[idx] = std::max(vmin, me[idx]); } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const T& getArg1() {
+ return vmin; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knPdataClampMin ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,vmin); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const T vmin; }
+;
+template <class T> struct knPdataClampMax : public KernelBase {
+ knPdataClampMax(ParticleDataImpl<T>& me, const T vmax) : KernelBase(me.size()) ,me(me),vmax(vmax) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T>& me, const T vmax ) const { me[idx] = std::min(vmax, me[idx]); } inline ParticleDataImpl<T>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const T& getArg1() {
+ return vmax; }
+ typedef T type1; void runMessage() { debMsg("Executing kernel knPdataClampMax ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,vmax); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T>& me; const T vmax; }
+;
+
+ struct knPdataClampMinVec3 : public KernelBase {
+ knPdataClampMinVec3(ParticleDataImpl<Vec3>& me, const Real vmin) : KernelBase(me.size()) ,me(me),vmin(vmin) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<Vec3>& me, const Real vmin ) const {
+ me[idx].x = std::max(vmin, me[idx].x);
+ me[idx].y = std::max(vmin, me[idx].y);
+ me[idx].z = std::max(vmin, me[idx].z);
+} inline ParticleDataImpl<Vec3>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<Vec3> type0;inline const Real& getArg1() {
+ return vmin; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knPdataClampMinVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,vmin); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<Vec3>& me; const Real vmin; }
+;
+
+ struct knPdataClampMaxVec3 : public KernelBase {
+ knPdataClampMaxVec3(ParticleDataImpl<Vec3>& me, const Real vmax) : KernelBase(me.size()) ,me(me),vmax(vmax) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<Vec3>& me, const Real vmax ) const {
+ me[idx].x = std::min(vmax, me[idx].x);
+ me[idx].y = std::min(vmax, me[idx].y);
+ me[idx].z = std::min(vmax, me[idx].z);
+} inline ParticleDataImpl<Vec3>& getArg0() {
+ return me; }
+ typedef ParticleDataImpl<Vec3> type0;inline const Real& getArg1() {
+ return vmax; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel knPdataClampMaxVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,vmax); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<Vec3>& me; const Real vmax; }
+;
+
+// python operators
+
+
+template<typename T>
+ParticleDataImpl<T>& ParticleDataImpl<T>::copyFrom(const ParticleDataImpl<T>& a)
+{
+ assertMsg(a.mData.size() == mData.size() , "different pdata size "<<a.mData.size()<<" vs "<<this->mData.size());
+ mData = a.mData;
+ return *this;
+}
+
+template<typename T>
+void ParticleDataImpl<T>::setConst(const T &s)
+{
+ knPdataSetScalar<T,T> op( *this, s );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::setConstRange(const T &s, const int begin, const int end)
+{
+ for(int i=begin; i<end; ++i) (*this)[i] = s;
+}
+
+// special set by flag
+
+template <class T, class S> struct knPdataSetScalarIntFlag : public KernelBase {
+ knPdataSetScalarIntFlag(ParticleDataImpl<T> &me, const S &other, const ParticleDataImpl<int> &t, const int itype) : KernelBase(me.size()) ,me(me),other(other),t(t),itype(itype) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<T> &me, const S &other, const ParticleDataImpl<int> &t, const int itype ) const {
+ if(t[idx]&itype) me[idx] = other;
+} inline ParticleDataImpl<T> & getArg0() {
+ return me; }
+ typedef ParticleDataImpl<T> type0;inline const S& getArg1() {
+ return other; }
+ typedef S type1;inline const ParticleDataImpl<int> & getArg2() {
+ return t; }
+ typedef ParticleDataImpl<int> type2;inline const int& getArg3() {
+ return itype; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel knPdataSetScalarIntFlag ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other,t,itype); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<T> & me; const S& other; const ParticleDataImpl<int> & t; const int itype; }
+;
+template<typename T>
+void ParticleDataImpl<T>::setConstIntFlag(const T &s, const ParticleDataImpl<int> &t, const int itype)
+{
+ knPdataSetScalarIntFlag<T,T> op(*this, s, t, itype);
+}
+
+template<typename T>
+void ParticleDataImpl<T>::add(const ParticleDataImpl<T>& a)
+{
+ knPdataAdd<T,T> op( *this, a );
+}
+template<typename T>
+void ParticleDataImpl<T>::sub(const ParticleDataImpl<T>& a)
+{
+ knPdataSub<T,T> op( *this, a );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::addConst(const T &s)
+{
+ knPdataAddScalar<T,T> op( *this, s );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::addScaled(const ParticleDataImpl<T>& a, const T& factor)
+{
+ knPdataScaledAdd<T,T> op( *this, a, factor );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::mult(const ParticleDataImpl<T>& a)
+{
+ knPdataMult<T,T> op( *this, a );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::safeDiv(const ParticleDataImpl<T>& a)
+{
+ knPdataSafeDiv<T> op( *this, a );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::multConst(const T &s)
+{
+ knPdataMultScalar<T,T> op( *this, s );
+}
+
+
+template<typename T>
+void ParticleDataImpl<T>::clamp(const Real vmin, const Real vmax)
+{
+ knPdataClamp<T> op( *this, vmin, vmax );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::clampMin(const Real vmin)
+{
+ knPdataClampMin<T> op( *this, vmin );
+}
+template<typename T>
+void ParticleDataImpl<T>::clampMax(const Real vmax)
+{
+ knPdataClampMax<T> op( *this, vmax );
+}
+
+template<>
+void ParticleDataImpl<Vec3>::clampMin(const Real vmin)
+{
+ knPdataClampMinVec3 op( *this, vmin );
+}
+template<>
+void ParticleDataImpl<Vec3>::clampMax(const Real vmax)
+{
+ knPdataClampMaxVec3 op( *this, vmax );
+}
+
+template<typename T> struct KnPtsSum : public KernelBase {
+ KnPtsSum(const ParticleDataImpl<T>& val, const ParticleDataImpl<int> *t, const int itype) : KernelBase(val.size()) ,val(val),t(t),itype(itype) ,result(T(0.)) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<T>& val, const ParticleDataImpl<int> *t, const int itype ,T& result) { if(t && !((*t)[idx]&itype)) return; result += val[idx]; } inline operator T () {
+ return result; }
+ inline T & getRet() {
+ return result; }
+ inline const ParticleDataImpl<T>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<T> type0;inline const ParticleDataImpl<int> * getArg1() {
+ return t; }
+ typedef ParticleDataImpl<int> type1;inline const int& getArg2() {
+ return itype; }
+ typedef int type2; void runMessage() { debMsg("Executing kernel KnPtsSum ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,t,itype,result); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ KnPtsSum (KnPtsSum& o, tbb::split) : KernelBase(o) ,val(o.val),t(o.t),itype(o.itype) ,result(T(0.)) {
+}
+ void join(const KnPtsSum & o) {
+ result += o.result; }
+ const ParticleDataImpl<T>& val; const ParticleDataImpl<int> * t; const int itype; T result; }
+;
+template<typename T> struct KnPtsSumSquare : public KernelBase {
+ KnPtsSumSquare(const ParticleDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,result(0.) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<T>& val ,Real& result) { result += normSquare(val[idx]); } inline operator Real () {
+ return result; }
+ inline Real & getRet() {
+ return result; }
+ inline const ParticleDataImpl<T>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<T> type0; void runMessage() { debMsg("Executing kernel KnPtsSumSquare ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,result); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ KnPtsSumSquare (KnPtsSumSquare& o, tbb::split) : KernelBase(o) ,val(o.val) ,result(0.) {
+}
+ void join(const KnPtsSumSquare & o) {
+ result += o.result; }
+ const ParticleDataImpl<T>& val; Real result; }
+;
+template<typename T> struct KnPtsSumMagnitude : public KernelBase {
+ KnPtsSumMagnitude(const ParticleDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,result(0.) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<T>& val ,Real& result) { result += norm(val[idx]); } inline operator Real () {
+ return result; }
+ inline Real & getRet() {
+ return result; }
+ inline const ParticleDataImpl<T>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<T> type0; void runMessage() { debMsg("Executing kernel KnPtsSumMagnitude ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,result); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ KnPtsSumMagnitude (KnPtsSumMagnitude& o, tbb::split) : KernelBase(o) ,val(o.val) ,result(0.) {
+}
+ void join(const KnPtsSumMagnitude & o) {
+ result += o.result; }
+ const ParticleDataImpl<T>& val; Real result; }
+;
+
+template<typename T>
+T ParticleDataImpl<T>::sum(const ParticleDataImpl<int> *t, const int itype) const
+{
+ return KnPtsSum<T>(*this, t, itype);
+}
+template<typename T>
+Real ParticleDataImpl<T>::sumSquare() const
+{
+ return KnPtsSumSquare<T>(*this);
+}
+template<typename T>
+Real ParticleDataImpl<T>::sumMagnitude() const
+{
+ return KnPtsSumMagnitude<T>(*this);
+}
+
+template<typename T>
+
+
+ struct CompPdata_Min : public KernelBase {
+ CompPdata_Min(const ParticleDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<T>& val ,Real& minVal) {
+ if(val[idx] < minVal) minVal = val[idx];
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const ParticleDataImpl<T>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<T> type0; void runMessage() { debMsg("Executing kernel CompPdata_Min ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,minVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompPdata_Min (CompPdata_Min& o, tbb::split) : KernelBase(o) ,val(o.val) ,minVal(std::numeric_limits<Real>::max()) {
+}
+ void join(const CompPdata_Min & o) {
+ minVal = min(minVal,o.minVal); }
+ const ParticleDataImpl<T>& val; Real minVal; }
+;
+
+template<typename T>
+
+
+ struct CompPdata_Max : public KernelBase {
+ CompPdata_Max(const ParticleDataImpl<T>& val) : KernelBase(val.size()) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<T>& val ,Real& maxVal) {
+ if(val[idx] > maxVal) maxVal = val[idx];
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const ParticleDataImpl<T>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<T> type0; void runMessage() { debMsg("Executing kernel CompPdata_Max ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,maxVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompPdata_Max (CompPdata_Max& o, tbb::split) : KernelBase(o) ,val(o.val) ,maxVal(-std::numeric_limits<Real>::max()) {
+}
+ void join(const CompPdata_Max & o) {
+ maxVal = max(maxVal,o.maxVal); }
+ const ParticleDataImpl<T>& val; Real maxVal; }
+;
+
+template<typename T>
+Real ParticleDataImpl<T>::getMin() const
+{
+ return CompPdata_Min<T>(*this);
+}
+
+template<typename T>
+Real ParticleDataImpl<T>::getMaxAbs() const
+{
+ Real amin = CompPdata_Min<T>(*this);
+ Real amax = CompPdata_Max<T>(*this);
+ return max(fabs(amin), fabs(amax));
+}
+
+template<typename T>
+Real ParticleDataImpl<T>::getMax() const
+{
+ return CompPdata_Max<T>(*this);
+}
+
+template<typename T>
+void ParticleDataImpl<T>::printPdata(IndexInt start, IndexInt stop, bool printIndex)
+{
+ std::ostringstream sstr;
+ IndexInt s = (start>0 ? start : 0 );
+ IndexInt e = (stop>0 ? stop : (IndexInt)mData.size() );
+ s = Manta::clamp(s, (IndexInt)0, (IndexInt)mData.size());
+ e = Manta::clamp(e, (IndexInt)0, (IndexInt)mData.size());
+
+ for(IndexInt i=s; i<e; ++i) {
+ if(printIndex) sstr << i<<": ";
+ sstr<<mData[i]<<" "<<"\n";
+ }
+ debMsg( sstr.str() , 1 );
+}
+template<class T> std::string ParticleDataImpl<T>::getDataPointer() {
+ std::ostringstream out;
+ out << &mData;
+ return out.str();
+}
+
+// specials for vec3
+// work on length values, ie, always positive (in contrast to scalar versions above)
+
+
+
+ struct CompPdata_MinVec3 : public KernelBase {
+ CompPdata_MinVec3(const ParticleDataImpl<Vec3>& val) : KernelBase(val.size()) ,val(val) ,minVal(std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<Vec3>& val ,Real& minVal) {
+ const Real s = normSquare(val[idx]);
+ if(s < minVal) minVal = s;
+} inline operator Real () {
+ return minVal; }
+ inline Real & getRet() {
+ return minVal; }
+ inline const ParticleDataImpl<Vec3>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<Vec3> type0; void runMessage() { debMsg("Executing kernel CompPdata_MinVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,minVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompPdata_MinVec3 (CompPdata_MinVec3& o, tbb::split) : KernelBase(o) ,val(o.val) ,minVal(std::numeric_limits<Real>::max()) {
+}
+ void join(const CompPdata_MinVec3 & o) {
+ minVal = min(minVal,o.minVal); }
+ const ParticleDataImpl<Vec3>& val; Real minVal; }
+;
+
+
+
+ struct CompPdata_MaxVec3 : public KernelBase {
+ CompPdata_MaxVec3(const ParticleDataImpl<Vec3>& val) : KernelBase(val.size()) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const ParticleDataImpl<Vec3>& val ,Real& maxVal) {
+ const Real s = normSquare(val[idx]);
+ if(s > maxVal) maxVal = s;
+} inline operator Real () {
+ return maxVal; }
+ inline Real & getRet() {
+ return maxVal; }
+ inline const ParticleDataImpl<Vec3>& getArg0() {
+ return val; }
+ typedef ParticleDataImpl<Vec3> type0; void runMessage() { debMsg("Executing kernel CompPdata_MaxVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, val,maxVal); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CompPdata_MaxVec3 (CompPdata_MaxVec3& o, tbb::split) : KernelBase(o) ,val(o.val) ,maxVal(-std::numeric_limits<Real>::max()) {
+}
+ void join(const CompPdata_MaxVec3 & o) {
+ maxVal = max(maxVal,o.maxVal); }
+ const ParticleDataImpl<Vec3>& val; Real maxVal; }
+;
+
+template<>
+Real ParticleDataImpl<Vec3>::getMin() const
+{
+ return sqrt(CompPdata_MinVec3(*this));
+}
+
+template<>
+Real ParticleDataImpl<Vec3>::getMaxAbs() const
+{
+ return sqrt(CompPdata_MaxVec3(*this)); // no minimum necessary here
+}
+
+template<>
+Real ParticleDataImpl<Vec3>::getMax() const
+{
+ return sqrt(CompPdata_MaxVec3(*this));
+}
+
+
+// explicit instantiation
+template class ParticleDataImpl<int>;
+template class ParticleDataImpl<Real>;
+template class ParticleDataImpl<Vec3>;
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h
new file mode 100644
index 00000000000..fcae886d050
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h
@@ -0,0 +1,1241 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Base class for particle systems
+ *
+ ******************************************************************************/
+
+#ifndef _PARTICLE_H
+#define _PARTICLE_H
+
+#include <vector>
+#include "grid.h"
+#include "vectorbase.h"
+#include "integrator.h"
+#include "randomstream.h"
+namespace Manta {
+
+// fwd decl
+template<class T> class Grid;
+class ParticleDataBase;
+template<class T> class ParticleDataImpl;
+
+//! Baseclass for particle systems. Does not implement any data
+class ParticleBase : public PbClass {public:
+ enum SystemType { BASE=0, PARTICLE, VORTEX, FILAMENT, FLIP, TURBULENCE, INDEX };
+
+ enum ParticleStatus {
+ PNONE = 0,
+ PNEW = (1<<0), // particles newly created in this step
+ PSPRAY = (1<<1), // secondary particle types
+ PBUBBLE = (1<<2),
+ PFOAM = (1<<3),
+ PTRACER = (1<<4),
+ PDELETE = (1<<10), // mark as deleted, will be deleted in next compress() step
+ PINVALID = (1<<30), // unused
+ };
+
+ ParticleBase(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ParticleBase::ParticleBase" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ParticleBase(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ParticleBase::ParticleBase" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ParticleBase::ParticleBase",e.what()); return -1; }
+ }
+
+ virtual ~ParticleBase();
+
+ //! copy all the particle data thats registered with the other particle system to this one
+ virtual void cloneParticleData(ParticleBase* nm);
+
+ virtual SystemType getType() const { return BASE; }
+ virtual std::string infoString() const;
+ virtual ParticleBase* clone() { assertMsg( false , "Dont use, override..."); return NULL; }
+
+ //! slow virtual function to query size, do not use in kernels! use size() instead
+ virtual IndexInt getSizeSlow() const { assertMsg( false , "Dont use, override..."); return 0; }
+
+ //! add a position as potential candidate for new particle (todo, make usable from parallel threads)
+ inline void addBuffered(const Vec3& pos, int flag=0);
+
+ //! particle data functions
+
+ //! create a particle data object
+ PbClass* create(PbType type, PbTypeVec T=PbTypeVec(), const std::string& name = ""); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleBase* pbo = dynamic_cast<ParticleBase*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleBase::create" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; PbType type = _args.get<PbType >("type",0,&_lock); PbTypeVec T = _args.getOpt<PbTypeVec >("T",1,PbTypeVec(),&_lock); const std::string& name = _args.getOpt<std::string >("name",2,"",&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->create(type,T,name)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleBase::create" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleBase::create",e.what()); return 0; }
+ }
+
+ //! add a particle data field, set its parent particle-system pointer
+ void registerPdata(ParticleDataBase* pdata);
+ void registerPdataReal(ParticleDataImpl<Real>* pdata);
+ void registerPdataVec3(ParticleDataImpl<Vec3>* pdata);
+ void registerPdataInt (ParticleDataImpl<int >* pdata);
+ //! remove a particle data entry
+ void deregister(ParticleDataBase* pdata);
+ //! add one zero entry to all data fields
+ void addAllPdata();
+ // note - deletion of pdata is handled in compress function
+
+ //! how many are there?
+ IndexInt getNumPdata() const { return mPartData.size(); }
+ //! access one of the fields
+ ParticleDataBase* getPdata(int i) { return mPartData[i]; }
+
+protected:
+ //! new particle candidates
+ std::vector<Vec3> mNewBufferPos;
+ std::vector<int> mNewBufferFlag;
+
+ //! allow automatic compression / resize? disallowed for, eg, flip particle systems
+ bool mAllowCompress;
+
+ //! store particle data , each pointer has its own storage vector of a certain type (int, real, vec3)
+ std::vector<ParticleDataBase*> mPartData;
+ //! lists of different types, for fast operations w/o virtual function calls (all calls necessary per particle)
+ std::vector< ParticleDataImpl<Real> *> mPdataReal;
+ std::vector< ParticleDataImpl<Vec3> *> mPdataVec3;
+ std::vector< ParticleDataImpl<int> *> mPdataInt; //! indicate that pdata of this particle system is copied, and needs to be freed
+ bool mFreePdata; public: PbArgs _args; }
+#define _C_ParticleBase
+;
+
+
+//! Main class for particle systems
+/*! Basetype S must at least contain flag, pos fields */
+template<class S> class ParticleSystem : public ParticleBase {public:
+ ParticleSystem(FluidSolver* parent) :ParticleBase(parent),mDeletes(0),mDeleteChunk(0){} static int _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ParticleSystem::ParticleSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ParticleSystem(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ParticleSystem::ParticleSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::ParticleSystem",e.what()); return -1; }
+ }
+
+ virtual ~ParticleSystem() {};
+
+ virtual SystemType getType() const { return S::getType(); };
+
+ //! accessors
+ inline S& operator[](IndexInt idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const S& operator[](IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ //! return size of container
+ //! note , python binding disabled for now! cannot yet deal with long-long types
+ inline IndexInt size() const { return mData.size(); }
+ //! slow virtual function of base class, also returns size
+ virtual IndexInt getSizeSlow() const { return size(); }
+ //! note , special call for python, note - doesnt support more than 2b parts!
+ int pySize() const { return (int)mData.size(); } static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::pySize" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->pySize()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::pySize" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::pySize",e.what()); return 0; }
+ }
+
+
+ //! query status
+ inline int getStatus(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx].flag; }
+ inline bool isActive(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PDELETE) == 0; }
+ inline bool isSpray(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PSPRAY); }
+ inline bool isBubble(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PBUBBLE); }
+ inline bool isFoam(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PFOAM); }
+ inline bool isTracer(IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PTRACER); }
+
+ //! update status
+ inline void setStatus(IndexInt idx, const int status) { DEBUG_ONLY(checkPartIndex(idx)); mData[idx].flag = status; }
+
+ //! safe accessor for python
+ void setPos(const IndexInt idx, const Vec3& pos) { DEBUG_ONLY(checkPartIndex(idx)); mData[idx].pos = pos; } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::setPos" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const IndexInt idx = _args.get<IndexInt >("idx",0,&_lock); const Vec3& pos = _args.get<Vec3 >("pos",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setPos(idx,pos); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::setPos" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::setPos",e.what()); return 0; }
+ }
+
+ const Vec3& getPos(const IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx].pos; } static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::getPos" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const IndexInt idx = _args.get<IndexInt >("idx",0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->getPos(idx)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::getPos" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::getPos",e.what()); return 0; }
+ }
+
+ //! copy all positions into pdata vec3 field
+ void getPosPdata(ParticleDataImpl<Vec3>& target) const ; static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::getPosPdata" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; ParticleDataImpl<Vec3>& target = *_args.getPtr<ParticleDataImpl<Vec3> >("target",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->getPosPdata(target); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::getPosPdata" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::getPosPdata",e.what()); return 0; }
+ }
+
+ void setPosPdata(const ParticleDataImpl<Vec3>& source); static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::setPosPdata" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<Vec3>& source = *_args.getPtr<ParticleDataImpl<Vec3> >("source",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setPosPdata(source); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::setPosPdata" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::setPosPdata",e.what()); return 0; }
+ }
+
+ //! transform coordinate system from one grid size to another (usually upon load)
+ void transformPositions( Vec3i dimOld, Vec3i dimNew );
+
+ //! explicitly trigger compression from outside
+ void doCompress() { if ( mDeletes > mDeleteChunk) compress(); }
+ //! insert buffered positions as new particles, update additional particle data
+ void insertBufferedParticles();
+ //! resize data vector, and all pdata fields
+ void resizeAll(IndexInt newsize);
+
+ //! adding and deleting
+ inline void kill(IndexInt idx);
+ IndexInt add(const S& data);
+ //! remove all particles, init 0 length arrays (also pdata)
+ void clear(); static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::clear",e.what()); return 0; }
+ }
+
+
+ //! Advect particle in grid velocity field
+ void advectInGrid(const FlagGrid &flags, const MACGrid &vel, const int integrationMode, const bool deleteInObstacle=true, const bool stopInObstacle=true, const ParticleDataImpl<int> *ptype=NULL, const int exclude=0); static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::advectInGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const int integrationMode = _args.get<int >("integrationMode",2,&_lock); const bool deleteInObstacle = _args.getOpt<bool >("deleteInObstacle",3,true,&_lock); const bool stopInObstacle = _args.getOpt<bool >("stopInObstacle",4,true,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",5,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",6,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->advectInGrid(flags,vel,integrationMode,deleteInObstacle,stopInObstacle,ptype,exclude); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::advectInGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::advectInGrid",e.what()); return 0; }
+ }
+
+
+ //! Project particles outside obstacles
+ void projectOutside(Grid<Vec3> &gradient); static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::projectOutside" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3> & gradient = *_args.getPtr<Grid<Vec3> >("gradient",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->projectOutside(gradient); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::projectOutside" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::projectOutside",e.what()); return 0; }
+ }
+
+ void projectOutOfBnd(const FlagGrid &flags, const Real bnd, const std::string &plane="xXyYzZ", const ParticleDataImpl<int> *ptype=NULL, const int exclude=0); static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleSystem::projectOutOfBnd" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const Real bnd = _args.get<Real >("bnd",1,&_lock); const std::string& plane = _args.getOpt<std::string >("plane",2,"xXyYzZ",&_lock); const ParticleDataImpl<int> * ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",3,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",4,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->projectOutOfBnd(flags,bnd,plane,ptype,exclude); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleSystem::projectOutOfBnd" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleSystem::projectOutOfBnd",e.what()); return 0; }
+ }
+
+
+ virtual ParticleBase* clone();
+ virtual std::string infoString() const;
+
+ //! debugging
+ inline void checkPartIndex(IndexInt idx) const;
+
+protected:
+ //! deletion count , and interval for re-compressing
+ IndexInt mDeletes, mDeleteChunk;
+ //! the particle data
+ std::vector<S> mData;
+ //! reduce storage , called by doCompress
+ virtual void compress(); public: PbArgs _args; }
+#define _C_ParticleSystem
+;
+
+//******************************************************************************
+
+//! Simplest data class for particle systems
+//! contains a position and an int flag; note that these are deprectated, and will at
+//! some point be replaced by the more flexible pdata fields. For now manually copy with
+//! getPosPdata / setPosPdata.
+struct BasicParticleData {
+public:
+ BasicParticleData() : pos(0.), flag(0) {}
+ BasicParticleData(const Vec3& p) : pos(p), flag(0) {}
+ static ParticleBase::SystemType getType() { return ParticleBase::PARTICLE; }
+
+ //! data (note, this size is currently hard coded for uni i/o)
+ Vec3 pos;
+ int flag;
+};
+
+class BasicParticleSystem : public ParticleSystem<BasicParticleData> {public:
+ BasicParticleSystem(FluidSolver* parent); static int _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "BasicParticleSystem::BasicParticleSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new BasicParticleSystem(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"BasicParticleSystem::BasicParticleSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::BasicParticleSystem",e.what()); return -1; }
+ }
+
+
+ //! file io
+ void save(const std::string name) const ; static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::save",e.what()); return 0; }
+ }
+
+ void load(const std::string name); static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::load",e.what()); return 0; }
+ }
+
+
+ //! save to text file
+ void writeParticlesText(const std::string name) const;
+ //! other output formats
+ void writeParticlesRawPositionsGz(const std::string name) const;
+ void writeParticlesRawVelocityGz(const std::string name) const;
+
+ //! read from other particle system (with resize)
+ void readParticles(BasicParticleSystem* from); static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::readParticles" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem* from = _args.getPtr<BasicParticleSystem >("from",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->readParticles(from); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::readParticles" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::readParticles",e.what()); return 0; }
+ }
+
+
+ //! add particles in python
+ void addParticle(Vec3 pos) { add(BasicParticleData(pos)); } static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::addParticle" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 pos = _args.get<Vec3 >("pos",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addParticle(pos); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::addParticle" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::addParticle",e.what()); return 0; }
+ }
+
+
+ //! dangerous, get low level access - avoid usage, only used in vortex filament advection for now
+ std::vector<BasicParticleData>& getData() { return mData; }
+
+ void printParts(IndexInt start=-1, IndexInt stop=-1, bool printIndex=false); static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::printParts" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; IndexInt start = _args.getOpt<IndexInt >("start",0,-1,&_lock); IndexInt stop = _args.getOpt<IndexInt >("stop",1,-1,&_lock); bool printIndex = _args.getOpt<bool >("printIndex",2,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->printParts(start,stop,printIndex); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::printParts" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::printParts",e.what()); return 0; }
+ }
+
+ //! get data pointer of particle data
+ std::string getDataPointer(); static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::getDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"BasicParticleSystem::getDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("BasicParticleSystem::getDataPointer",e.what()); return 0; }
+ }
+ public: PbArgs _args; }
+#define _C_BasicParticleSystem
+;
+
+
+//******************************************************************************
+
+//! Index into other particle system
+// used for grid based neighborhood searches on generic particle systems (stores
+// only active particles, and reduces copied data)
+// note - pos & flag are disabled here, do not use!
+struct ParticleIndexData {
+public:
+ ParticleIndexData() : sourceIndex(0) {}
+ static ParticleBase::SystemType getType() { return ParticleBase::INDEX; }
+
+ IndexInt sourceIndex; // index of this particle in the original particle system
+ //! note - the following two are needed for template instantiation, but not used
+ //! for the particle index system (use values from original one!)
+ static Vec3 pos; // do not use...
+ static int flag; // not needed usally
+ //Vec3 pos; // enable for debugging
+};
+
+class ParticleIndexSystem : public ParticleSystem<ParticleIndexData> {public:
+ ParticleIndexSystem(FluidSolver* parent) :ParticleSystem<ParticleIndexData>(parent){} static int _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ParticleIndexSystem::ParticleIndexSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ParticleIndexSystem(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ParticleIndexSystem::ParticleIndexSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ParticleIndexSystem::ParticleIndexSystem",e.what()); return -1; }
+ }
+;
+ //! we only need a resize function...
+ void resize(IndexInt size) { mData.resize(size); } public: PbArgs _args; }
+#define _C_ParticleIndexSystem
+;
+
+
+
+//******************************************************************************
+
+//! Particle set with connectivity
+
+template<class DATA, class CON> class ConnectedParticleSystem : public ParticleSystem<DATA> {public:
+ ConnectedParticleSystem(FluidSolver* parent) :ParticleSystem<DATA>(parent){} static int _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ConnectedParticleSystem::ConnectedParticleSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ConnectedParticleSystem(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ConnectedParticleSystem::ConnectedParticleSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ConnectedParticleSystem::ConnectedParticleSystem",e.what()); return -1; }
+ }
+
+
+ //! accessors
+ inline bool isSegActive(int i) { return (mSegments[i].flag & ParticleBase::PDELETE) == 0; }
+ inline int segSize() const { return mSegments.size(); }
+ inline CON& seg(int i) { return mSegments[i]; }
+ inline const CON& seg(int i) const { return mSegments[i]; }
+
+ virtual ParticleBase* clone();
+
+protected:
+ std::vector<CON> mSegments; virtual void compress(); public: PbArgs _args; }
+#define _C_ConnectedParticleSystem
+;
+
+//******************************************************************************
+
+//! abstract interface for particle data
+class ParticleDataBase : public PbClass {public:
+ ParticleDataBase(FluidSolver* parent); static int _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ParticleDataBase::ParticleDataBase" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ParticleDataBase(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ParticleDataBase::ParticleDataBase" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataBase::ParticleDataBase",e.what()); return -1; }
+ }
+
+ virtual ~ParticleDataBase();
+
+ //! data type IDs, in line with those for grids
+ enum PdataType { TypeNone = 0, TypeReal = 1, TypeInt = 2, TypeVec3 = 4 };
+
+ //! interface functions, using assert instead of pure virtual for python compatibility
+ virtual IndexInt getSizeSlow() const { assertMsg( false , "Dont use, override..."); return 0; }
+ virtual void addEntry() { assertMsg( false , "Dont use, override..."); return; }
+ virtual ParticleDataBase* clone() { assertMsg( false , "Dont use, override..."); return NULL; }
+ virtual PdataType getType() const { assertMsg( false , "Dont use, override..."); return TypeNone; }
+ virtual void resize(IndexInt size) { assertMsg( false , "Dont use, override..."); return; }
+ virtual void copyValueSlow(IndexInt from, IndexInt to) { assertMsg( false , "Dont use, override..."); return; }
+
+ //! set base pointer
+ void setParticleSys(ParticleBase* set) { mpParticleSys = set; }
+
+ //! debugging
+ inline void checkPartIndex(IndexInt idx) const;
+
+protected: ParticleBase* mpParticleSys; public: PbArgs _args; }
+#define _C_ParticleDataBase
+;
+
+
+//! abstract interface for particle data
+
+template<class T> class ParticleDataImpl : public ParticleDataBase {public:
+ ParticleDataImpl(FluidSolver* parent); static int _W_22 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "ParticleDataImpl::ParticleDataImpl" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new ParticleDataImpl(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"ParticleDataImpl::ParticleDataImpl" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::ParticleDataImpl",e.what()); return -1; }
+ }
+
+ ParticleDataImpl(FluidSolver* parent, ParticleDataImpl<T>* other);
+ virtual ~ParticleDataImpl();
+
+ //! access data
+ inline T& get(const IndexInt idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const T& get(const IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline T& operator[](const IndexInt idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const T& operator[](const IndexInt idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+
+ //! set all values to 0, note - different from particleSystem::clear! doesnt modify size of array (has to stay in sync with parent system)
+ void clear(); static PyObject* _W_23 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clear" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::clear" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::clear",e.what()); return 0; }
+ }
+
+
+ //! set grid from which to get data...
+ void setSource(Grid<T>* grid, bool isMAC=false ); static PyObject* _W_24 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setSource" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<T>* grid = _args.getPtr<Grid<T> >("grid",0,&_lock); bool isMAC = _args.getOpt<bool >("isMAC",1,false ,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setSource(grid,isMAC); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::setSource" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::setSource",e.what()); return 0; }
+ }
+
+
+ //! particle data base interface
+ virtual IndexInt getSizeSlow() const;
+ virtual void addEntry();
+ virtual ParticleDataBase* clone();
+ virtual PdataType getType() const;
+ virtual void resize(IndexInt s);
+ virtual void copyValueSlow(IndexInt from, IndexInt to);
+
+ IndexInt size() const { return mData.size(); }
+
+ //! fast inlined functions for per particle operations
+ inline void copyValue(IndexInt from, IndexInt to) { get(to) = get(from); }
+ void initNewValue(IndexInt idx, Vec3 pos);
+
+ //! python interface (similar to grid data)
+ ParticleDataImpl<T>& copyFrom(const ParticleDataImpl<T>& a); static PyObject* _W_25 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::copyFrom" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->copyFrom(a)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::copyFrom" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::copyFrom",e.what()); return 0; }
+ }
+
+ void setConst(const T &s); static PyObject* _W_26 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& s = *_args.getPtr<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::setConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::setConst",e.what()); return 0; }
+ }
+
+ void setConstRange(const T &s, const int begin, const int end); static PyObject* _W_27 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setConstRange" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& s = *_args.getPtr<T >("s",0,&_lock); const int begin = _args.get<int >("begin",1,&_lock); const int end = _args.get<int >("end",2,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConstRange(s,begin,end); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::setConstRange" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::setConstRange",e.what()); return 0; }
+ }
+
+ void add(const ParticleDataImpl<T>& a); static PyObject* _W_28 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::add" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->add(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::add" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::add",e.what()); return 0; }
+ }
+
+ void sub(const ParticleDataImpl<T>& a); static PyObject* _W_29 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sub" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->sub(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::sub" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::sub",e.what()); return 0; }
+ }
+
+ void addConst(const T &s); static PyObject* _W_30 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::addConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& s = *_args.getPtr<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::addConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::addConst",e.what()); return 0; }
+ }
+
+ void addScaled(const ParticleDataImpl<T>& a, const T& factor); static PyObject* _W_31 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::addScaled" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); const T& factor = *_args.getPtr<T >("factor",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->addScaled(a,factor); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::addScaled" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::addScaled",e.what()); return 0; }
+ }
+
+ void mult(const ParticleDataImpl<T>& a); static PyObject* _W_32 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::mult" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->mult(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::mult" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::mult",e.what()); return 0; }
+ }
+
+ void multConst(const T &s); static PyObject* _W_33 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::multConst" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& s = *_args.getPtr<T >("s",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->multConst(s); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::multConst" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::multConst",e.what()); return 0; }
+ }
+
+ void safeDiv(const ParticleDataImpl<T>& a); static PyObject* _W_34 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::safeDiv" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<T>& a = *_args.getPtr<ParticleDataImpl<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->safeDiv(a); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::safeDiv" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::safeDiv",e.what()); return 0; }
+ }
+
+ void clamp(const Real vmin, const Real vmax); static PyObject* _W_35 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clamp" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Real vmin = _args.get<Real >("vmin",0,&_lock); const Real vmax = _args.get<Real >("vmax",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clamp(vmin,vmax); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::clamp" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::clamp",e.what()); return 0; }
+ }
+
+ void clampMin(const Real vmin); static PyObject* _W_36 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clampMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Real vmin = _args.get<Real >("vmin",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clampMin(vmin); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::clampMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::clampMin",e.what()); return 0; }
+ }
+
+ void clampMax(const Real vmax); static PyObject* _W_37 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clampMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Real vmax = _args.get<Real >("vmax",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->clampMax(vmax); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::clampMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::clampMax",e.what()); return 0; }
+ }
+
+
+ Real getMaxAbs() const ; static PyObject* _W_38 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMaxAbs" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxAbs()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::getMaxAbs" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::getMaxAbs",e.what()); return 0; }
+ }
+
+ Real getMax() const ; static PyObject* _W_39 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMax" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMax()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::getMax" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::getMax",e.what()); return 0; }
+ }
+
+ Real getMin() const ; static PyObject* _W_40 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMin" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMin()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::getMin" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::getMin",e.what()); return 0; }
+ }
+
+
+ T sum(const ParticleDataImpl<int> *t=NULL, const int itype=0) const ; static PyObject* _W_41 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sum" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataImpl<int> * t = _args.getPtrOpt<ParticleDataImpl<int> >("t",0,NULL,&_lock); const int itype = _args.getOpt<int >("itype",1,0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->sum(t,itype)); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::sum" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::sum",e.what()); return 0; }
+ }
+
+ Real sumSquare() const ; static PyObject* _W_42 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sumSquare" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->sumSquare()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::sumSquare" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::sumSquare",e.what()); return 0; }
+ }
+
+ Real sumMagnitude() const ; static PyObject* _W_43 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sumMagnitude" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->sumMagnitude()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::sumMagnitude" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::sumMagnitude",e.what()); return 0; }
+ }
+
+
+ //! special, set if int flag in t has "flag"
+ void setConstIntFlag(const T &s, const ParticleDataImpl<int> &t, const int flag); static PyObject* _W_44 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setConstIntFlag" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const T& s = *_args.getPtr<T >("s",0,&_lock); const ParticleDataImpl<int> & t = *_args.getPtr<ParticleDataImpl<int> >("t",1,&_lock); const int flag = _args.get<int >("flag",2,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setConstIntFlag(s,t,flag); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::setConstIntFlag" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::setConstIntFlag",e.what()); return 0; }
+ }
+
+
+ void printPdata(IndexInt start=-1, IndexInt stop=-1, bool printIndex=false); static PyObject* _W_45 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::printPdata" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; IndexInt start = _args.getOpt<IndexInt >("start",0,-1,&_lock); IndexInt stop = _args.getOpt<IndexInt >("stop",1,-1,&_lock); bool printIndex = _args.getOpt<bool >("printIndex",2,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->printPdata(start,stop,printIndex); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::printPdata" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::printPdata",e.what()); return 0; }
+ }
+
+
+ //! file io
+ void save(const std::string name); static PyObject* _W_46 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::save" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->save(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::save" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::save",e.what()); return 0; }
+ }
+
+ void load(const std::string name); static PyObject* _W_47 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::load" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->load(name); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::load" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::load",e.what()); return 0; }
+ }
+
+
+ //! get data pointer of particle data
+ std::string getDataPointer(); static PyObject* _W_48 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getDataPointer" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getDataPointer()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::getDataPointer" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("ParticleDataImpl::getDataPointer",e.what()); return 0; }
+ }
+
+protected:
+ //! data storage
+ std::vector<T> mData;
+
+ //! optionally , we might have an associated grid from which to grab new data
+ Grid<T>* mpGridSource; //! unfortunately , we need to distinguish mac vs regular vec3
+ bool mGridSourceMAC; public: PbArgs _args; }
+#define _C_ParticleDataImpl
+;
+
+
+
+
+
+
+//******************************************************************************
+// Implementation
+//******************************************************************************
+
+const int DELETE_PART = 20; // chunk size for compression
+
+void ParticleBase::addBuffered(const Vec3& pos, int flag) {
+ mNewBufferPos.push_back(pos);
+ mNewBufferFlag.push_back(flag);
+}
+
+template<class S>
+void ParticleSystem<S>::clear() {
+ mDeleteChunk = mDeletes = 0;
+ this->resizeAll(0); // instead of mData.clear
+}
+
+template<class S>
+IndexInt ParticleSystem<S>::add(const S& data) {
+ mData.push_back(data);
+ mDeleteChunk = mData.size() / DELETE_PART;
+ this->addAllPdata();
+ return mData.size()-1;
+}
+
+template<class S>
+inline void ParticleSystem<S>::kill(IndexInt idx) {
+ assertMsg(idx>=0 && idx<size(), "Index out of bounds");
+ mData[idx].flag |= PDELETE;
+ if ( (++mDeletes > mDeleteChunk) && (mAllowCompress) ) compress();
+}
+
+template<class S>
+void ParticleSystem<S>::getPosPdata(ParticleDataImpl<Vec3>& target) const {
+ for(IndexInt i=0; i<(IndexInt)this->size(); ++i) {
+ target[i] = this->getPos(i);
+ }
+}
+template<class S>
+void ParticleSystem<S>::setPosPdata(const ParticleDataImpl<Vec3>& source) {
+ for(IndexInt i=0; i<(IndexInt)this->size(); ++i) {
+ this->setPos(i, source[i]);
+ }
+}
+
+template<class S>
+void ParticleSystem<S>::transformPositions( Vec3i dimOld, Vec3i dimNew )
+{
+ const Vec3 factor = calcGridSizeFactor( dimNew, dimOld );
+ for(IndexInt i=0; i<(IndexInt)this->size(); ++i) {
+ this->setPos(i, this->getPos(i) * factor );
+ }
+}
+
+// check for deletion/invalid position, otherwise return velocity
+
+
+
+
+
+template <class S> struct _GridAdvectKernel : public KernelBase {
+ _GridAdvectKernel(const KernelBase& base, std::vector<S>& p, const MACGrid& vel, const FlagGrid& flags, const Real dt, const bool deleteInObstacle, const bool stopInObstacle, const ParticleDataImpl<int> *ptype, const int exclude ,std::vector<Vec3> & u) : KernelBase(base) ,p(p),vel(vel),flags(flags),dt(dt),deleteInObstacle(deleteInObstacle),stopInObstacle(stopInObstacle),ptype(ptype),exclude(exclude) ,u(u){
+}
+ inline void op(IndexInt idx, std::vector<S>& p, const MACGrid& vel, const FlagGrid& flags, const Real dt, const bool deleteInObstacle, const bool stopInObstacle, const ParticleDataImpl<int> *ptype, const int exclude ,std::vector<Vec3> & u) const {
+ if ((p[idx].flag & ParticleBase::PDELETE) || (ptype && ((*ptype)[idx] & exclude))) {
+ u[idx] = 0.; return;
+ }
+ // special handling
+ if(deleteInObstacle || stopInObstacle) {
+ if (!flags.isInBounds(p[idx].pos, 1) || flags.isObstacle(p[idx].pos) ) {
+ if(stopInObstacle)
+ u[idx] = 0.;
+ // for simple tracer particles, its convenient to delete particles right away
+ // for other sim types, eg flip, we can try to fix positions later on
+ if(deleteInObstacle)
+ p[idx].flag |= ParticleBase::PDELETE;
+ return;
+ }
+ }
+ u[idx] = vel.getInterpolated(p[idx].pos) * dt;
+} void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, p,vel,flags,dt,deleteInObstacle,stopInObstacle,ptype,exclude,u); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<S>& p; const MACGrid& vel; const FlagGrid& flags; const Real dt; const bool deleteInObstacle; const bool stopInObstacle; const ParticleDataImpl<int> * ptype; const int exclude; std::vector<Vec3> & u; }
+; template <class S> struct GridAdvectKernel : public KernelBase {
+ GridAdvectKernel( std::vector<S>& p, const MACGrid& vel, const FlagGrid& flags, const Real dt, const bool deleteInObstacle, const bool stopInObstacle, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(p.size()) , _inner(KernelBase(p.size()),p,vel,flags,dt,deleteInObstacle,stopInObstacle,ptype,exclude,u) ,p(p),vel(vel),flags(flags),dt(dt),deleteInObstacle(deleteInObstacle),stopInObstacle(stopInObstacle),ptype(ptype),exclude(exclude) ,u((size)) {
+ runMessage(); run(); }
+ void run() {
+ _inner.run(); }
+ inline operator std::vector<Vec3> () {
+ return u; }
+ inline std::vector<Vec3> & getRet() {
+ return u; }
+ inline std::vector<S>& getArg0() {
+ return p; }
+ typedef std::vector<S> type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const FlagGrid& getArg2() {
+ return flags; }
+ typedef FlagGrid type2;inline const Real& getArg3() {
+ return dt; }
+ typedef Real type3;inline const bool& getArg4() {
+ return deleteInObstacle; }
+ typedef bool type4;inline const bool& getArg5() {
+ return stopInObstacle; }
+ typedef bool type5;inline const ParticleDataImpl<int> * getArg6() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type6;inline const int& getArg7() {
+ return exclude; }
+ typedef int type7; void runMessage() { debMsg("Executing kernel GridAdvectKernel ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; _GridAdvectKernel<S> _inner; std::vector<S>& p; const MACGrid& vel; const FlagGrid& flags; const Real dt; const bool deleteInObstacle; const bool stopInObstacle; const ParticleDataImpl<int> * ptype; const int exclude; std::vector<Vec3> u; }
+;;
+
+// final check after advection to make sure particles haven't escaped
+// (similar to particle advection kernel)
+
+template <class S> struct KnDeleteInObstacle : public KernelBase {
+ KnDeleteInObstacle(std::vector<S>& p, const FlagGrid& flags) : KernelBase(p.size()) ,p(p),flags(flags) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<S>& p, const FlagGrid& flags ) const {
+ if (p[idx].flag & ParticleBase::PDELETE) return;
+ if (!flags.isInBounds(p[idx].pos,1) || flags.isObstacle(p[idx].pos)) {
+ p[idx].flag |= ParticleBase::PDELETE;
+ }
+} inline std::vector<S>& getArg0() {
+ return p; }
+ typedef std::vector<S> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1; void runMessage() { debMsg("Executing kernel KnDeleteInObstacle ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, p,flags); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<S>& p; const FlagGrid& flags; }
+;
+
+// try to get closer to actual obstacle boundary
+static inline Vec3 bisectBacktracePos(const FlagGrid& flags, const Vec3& oldp, const Vec3& newp)
+{
+ Real s = 0.;
+ for(int i=1; i<5; ++i) {
+ Real ds = 1./(Real)(1<<i);
+ if (!flags.isObstacle( oldp*(1.-(s+ds)) + newp*(s+ds) )) {
+ s += ds;
+ }
+ }
+ return( oldp*(1.-(s)) + newp*(s) );
+}
+
+// at least make sure all particles are inside domain
+
+
+
+
+template <class S> struct KnClampPositions : public KernelBase {
+ KnClampPositions( std::vector<S>& p, const FlagGrid& flags, ParticleDataImpl<Vec3> *posOld=NULL, bool stopInObstacle=true, const ParticleDataImpl<int> *ptype=NULL, const int exclude=0) : KernelBase(p.size()) ,p(p),flags(flags),posOld(posOld),stopInObstacle(stopInObstacle),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, std::vector<S>& p, const FlagGrid& flags, ParticleDataImpl<Vec3> *posOld=NULL, bool stopInObstacle=true, const ParticleDataImpl<int> *ptype=NULL, const int exclude=0 ) const {
+ if (p[idx].flag & ParticleBase::PDELETE) return;
+ if (ptype && ((*ptype)[idx] & exclude)) {
+ if(posOld) p[idx].pos = (*posOld)[idx];
+ return;
+ }
+ if (!flags.isInBounds(p[idx].pos,0) ) {
+ p[idx].pos = clamp( p[idx].pos, Vec3(0.), toVec3(flags.getSize())-Vec3(1.) );
+ }
+ if (stopInObstacle && (flags.isObstacle(p[idx].pos)) ) {
+ p[idx].pos = bisectBacktracePos(flags, (*posOld)[idx], p[idx].pos);
+ }
+} inline std::vector<S>& getArg0() {
+ return p; }
+ typedef std::vector<S> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline ParticleDataImpl<Vec3> * getArg2() {
+ return posOld; }
+ typedef ParticleDataImpl<Vec3> type2;inline bool& getArg3() {
+ return stopInObstacle; }
+ typedef bool type3;inline const ParticleDataImpl<int> * getArg4() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type4;inline const int& getArg5() {
+ return exclude; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnClampPositions ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, p,flags,posOld,stopInObstacle,ptype,exclude); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ std::vector<S>& p; const FlagGrid& flags; ParticleDataImpl<Vec3> * posOld; bool stopInObstacle; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+
+// advection plugin
+template<class S>
+void ParticleSystem<S>::advectInGrid(
+ const FlagGrid &flags, const MACGrid &vel, const int integrationMode,
+ const bool deleteInObstacle, const bool stopInObstacle,
+ const ParticleDataImpl<int> *ptype, const int exclude)
+{
+ // position clamp requires old positions, backup
+ ParticleDataImpl<Vec3> *posOld = NULL;
+ if(!deleteInObstacle) {
+ posOld = new ParticleDataImpl<Vec3>(this->getParent());
+ posOld->resize(mData.size());
+ for(IndexInt i=0; i<(IndexInt)mData.size();++i) (*posOld)[i] = mData[i].pos;
+ }
+
+ // update positions
+ GridAdvectKernel<S> kernel(mData, vel, flags, getParent()->getDt(), deleteInObstacle, stopInObstacle, ptype, exclude);
+ integratePointSet(kernel, integrationMode);
+
+ if(!deleteInObstacle) {
+ KnClampPositions<S> (mData, flags, posOld, stopInObstacle, ptype, exclude);
+ delete posOld;
+ } else {
+ KnDeleteInObstacle<S>(mData, flags);
+ }
+}
+
+
+
+template <class S> struct KnProjectParticles : public KernelBase {
+ KnProjectParticles(ParticleSystem<S>& part, Grid<Vec3>& gradient) : KernelBase(part.size()) ,part(part),gradient(gradient) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleSystem<S>& part, Grid<Vec3>& gradient ) {
+ static RandomStream rand (3123984);
+ const double jlen = 0.1;
+
+ if (part.isActive(idx)) {
+ // project along levelset gradient
+ Vec3 p = part[idx].pos;
+ if (gradient.isInBounds(p)) {
+ Vec3 n = gradient.getInterpolated(p);
+ Real dist = normalize(n);
+ Vec3 dx = n * (-dist + jlen * (1 + rand.getReal()));
+ p += dx;
+ }
+ // clamp to outer boundaries (+jitter)
+ const double jlen = 0.1;
+ Vec3 jitter = jlen * rand.getVec3();
+ part[idx].pos = clamp(p, Vec3(1,1,1)+jitter, toVec3(gradient.getSize()-1)-jitter);
+ }
+} inline ParticleSystem<S>& getArg0() {
+ return part; }
+ typedef ParticleSystem<S> type0;inline Grid<Vec3>& getArg1() {
+ return gradient; }
+ typedef Grid<Vec3> type1; void runMessage() { debMsg("Executing kernel KnProjectParticles ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size; for (IndexInt i = 0; i < _sz; i++) op(i, part,gradient); }
+ ParticleSystem<S>& part; Grid<Vec3>& gradient; }
+;
+
+template<class S>
+void ParticleSystem<S>::projectOutside(Grid<Vec3> &gradient) {
+ KnProjectParticles<S>(*this, gradient);
+}
+
+
+template <class S> struct KnProjectOutOfBnd : public KernelBase {
+ KnProjectOutOfBnd(ParticleSystem<S> &part, const FlagGrid &flags, const Real bnd, const bool *axis, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(part.size()) ,part(part),flags(flags),bnd(bnd),axis(axis),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleSystem<S> &part, const FlagGrid &flags, const Real bnd, const bool *axis, const ParticleDataImpl<int> *ptype, const int exclude ) const {
+ if(!part.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ if(axis[0]) part[idx].pos.x = std::max(part[idx].pos.x, bnd);
+ if(axis[1]) part[idx].pos.x = std::min(part[idx].pos.x, static_cast<Real>(flags.getSizeX())-bnd);
+ if(axis[2]) part[idx].pos.y = std::max(part[idx].pos.y, bnd);
+ if(axis[3]) part[idx].pos.y = std::min(part[idx].pos.y, static_cast<Real>(flags.getSizeY())-bnd);
+ if(flags.is3D()) {
+ if(axis[4]) part[idx].pos.z = std::max(part[idx].pos.z, bnd);
+ if(axis[5]) part[idx].pos.z = std::min(part[idx].pos.z, static_cast<Real>(flags.getSizeZ())-bnd);
+ }
+} inline ParticleSystem<S> & getArg0() {
+ return part; }
+ typedef ParticleSystem<S> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Real& getArg2() {
+ return bnd; }
+ typedef Real type2;inline const bool* getArg3() {
+ return axis; }
+ typedef bool type3;inline const ParticleDataImpl<int> * getArg4() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type4;inline const int& getArg5() {
+ return exclude; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnProjectOutOfBnd ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, part,flags,bnd,axis,ptype,exclude); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleSystem<S> & part; const FlagGrid& flags; const Real bnd; const bool* axis; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+
+template<class S>
+void ParticleSystem<S>::projectOutOfBnd(const FlagGrid &flags, const Real bnd, const std::string &plane, const ParticleDataImpl<int> *ptype, const int exclude) {
+ bool axis[6] = { false };
+ for(std::string::const_iterator it=plane.begin(); it!=plane.end(); ++it) {
+ if(*it=='x') axis[0] = true;
+ if(*it=='X') axis[1] = true;
+ if(*it=='y') axis[2] = true;
+ if(*it=='Y') axis[3] = true;
+ if(*it=='z') axis[4] = true;
+ if(*it=='Z') axis[5] = true;
+ }
+ KnProjectOutOfBnd<S>(*this, flags, bnd, axis, ptype, exclude);
+}
+
+template<class S>
+void ParticleSystem<S>::resizeAll(IndexInt size) {
+ // resize all buffers to target size in 1 go
+ mData.resize(size);
+ for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i)
+ mPartData[i]->resize(size);
+}
+
+template<class S>
+void ParticleSystem<S>::compress() {
+ IndexInt nextRead = mData.size();
+ for (IndexInt i=0; i<(IndexInt)mData.size(); i++) {
+ while ((mData[i].flag & PDELETE) != 0) {
+ nextRead--;
+ mData[i] = mData[nextRead];
+ // ugly, but prevent virtual function calls here:
+ for(IndexInt pd=0; pd<(IndexInt)mPdataReal.size(); ++pd) mPdataReal[pd]->copyValue(nextRead, i);
+ for(IndexInt pd=0; pd<(IndexInt)mPdataVec3.size(); ++pd) mPdataVec3[pd]->copyValue(nextRead, i);
+ for(IndexInt pd=0; pd<(IndexInt)mPdataInt .size(); ++pd) mPdataInt [pd]->copyValue(nextRead, i);
+ mData[nextRead].flag = PINVALID;
+ }
+ }
+ if(nextRead<(IndexInt)mData.size()) debMsg("Deleted "<<((IndexInt)mData.size() - nextRead)<<" particles", 1); // debug info
+
+ resizeAll(nextRead);
+ mDeletes = 0;
+ mDeleteChunk = mData.size() / DELETE_PART;
+}
+
+//! insert buffered positions as new particles, update additional particle data
+template<class S>
+void ParticleSystem<S>::insertBufferedParticles() {
+ if(mNewBufferPos.size()==0) return;
+ IndexInt newCnt = mData.size();
+ resizeAll(newCnt + mNewBufferPos.size());
+
+ // clear new flag everywhere
+ for(IndexInt i=0; i<(IndexInt)mData.size(); ++i) mData[i].flag &= ~PNEW;
+
+ for(IndexInt i=0; i<(IndexInt)mNewBufferPos.size(); ++i) {
+ int flag = (mNewBufferFlag.size() > 0) ? mNewBufferFlag[i] : 0;
+ // note, other fields are not initialized here...
+ mData[newCnt].pos = mNewBufferPos[i];
+ mData[newCnt].flag = PNEW | flag;
+ // now init pdata fields from associated grids...
+ for(IndexInt pd=0; pd<(IndexInt)mPdataReal.size(); ++pd)
+ mPdataReal[pd]->initNewValue(newCnt, mNewBufferPos[i] );
+ for(IndexInt pd=0; pd<(IndexInt)mPdataVec3.size(); ++pd)
+ mPdataVec3[pd]->initNewValue(newCnt, mNewBufferPos[i] );
+ for(IndexInt pd=0; pd<(IndexInt)mPdataInt.size(); ++pd)
+ mPdataInt[pd]->initNewValue(newCnt, mNewBufferPos[i] );
+ newCnt++;
+ }
+ if(mNewBufferPos.size()>0) debMsg("Added & initialized "<<(IndexInt)mNewBufferPos.size()<<" particles", 2); // debug info
+ mNewBufferPos.clear();
+ mNewBufferFlag.clear();
+}
+
+
+template<class DATA, class CON>
+void ConnectedParticleSystem<DATA,CON>::compress() {
+ const IndexInt sz = ParticleSystem<DATA>::size();
+ IndexInt *renumber_back = new IndexInt[sz];
+ IndexInt *renumber = new IndexInt[sz];
+ for (IndexInt i=0; i<sz; i++)
+ renumber[i] = renumber_back[i] = -1;
+
+ // reorder elements
+ std::vector<DATA>& data = ParticleSystem<DATA>::mData;
+ IndexInt nextRead = sz;
+ for (IndexInt i=0; i<nextRead; i++) {
+ if ((data[i].flag & ParticleBase::PDELETE) != 0) {
+ nextRead--;
+ data[i] = data[nextRead];
+ data[nextRead].flag = 0;
+ renumber_back[i] = nextRead;
+ } else
+ renumber_back[i] = i;
+ }
+
+ // acceleration structure
+ for (IndexInt i=0; i<nextRead; i++)
+ renumber[renumber_back[i]] = i;
+
+ // rename indices in filaments
+ for (IndexInt i=0; i<(IndexInt)mSegments.size(); i++)
+ mSegments[i].renumber(renumber);
+
+ ParticleSystem<DATA>::mData.resize(nextRead);
+ ParticleSystem<DATA>::mDeletes = 0;
+ ParticleSystem<DATA>::mDeleteChunk = ParticleSystem<DATA>::size() / DELETE_PART;
+
+ delete[] renumber;
+ delete[] renumber_back;
+}
+
+template<class S>
+ParticleBase* ParticleSystem<S>::clone() {
+ ParticleSystem<S>* nm = new ParticleSystem<S>(getParent());
+ if(this->mAllowCompress) compress();
+
+ nm->mData = mData;
+ nm->setName(getName());
+ this->cloneParticleData(nm);
+ return nm;
+}
+
+template<class DATA,class CON>
+ParticleBase* ConnectedParticleSystem<DATA,CON>::clone() {
+ ConnectedParticleSystem<DATA,CON>* nm = new ConnectedParticleSystem<DATA,CON>(this->getParent());
+ if(this->mAllowCompress) compress();
+
+ nm->mData = this->mData;
+ nm->mSegments = mSegments;
+ nm->setName(this->getName());
+ this->cloneParticleData(nm);
+ return nm;
+}
+
+template<class S>
+std::string ParticleSystem<S>::infoString() const {
+ std::stringstream s;
+ s << "ParticleSys '" << getName() << "'\n-> ";
+ if(this->getNumPdata()>0) s<< "pdata: "<< this->getNumPdata();
+ s << "parts: " << size();
+ //for(IndexInt i=0; i<(IndexInt)mPartData.size(); ++i) { sstr << i<<":" << mPartData[i]->size() <<" "; }
+ return s.str();
+}
+
+template<class S>
+inline void ParticleSystem<S>::checkPartIndex(IndexInt idx) const {
+ IndexInt mySize = this->size();
+ if (idx<0 || idx > mySize ) {
+ errMsg( "ParticleBase " << " size " << mySize << " : index " << idx << " out of bound " );
+ }
+}
+
+inline void ParticleDataBase::checkPartIndex(IndexInt idx) const {
+ IndexInt mySize = this->getSizeSlow();
+ if (idx<0 || idx > mySize ) {
+ errMsg( "ParticleData " << " size " << mySize << " : index " << idx << " out of bound " );
+ }
+ if ( mpParticleSys && mpParticleSys->getSizeSlow()!=mySize ) {
+ errMsg( "ParticleData " << " size " << mySize << " does not match parent! (" << mpParticleSys->getSizeSlow() << ") " );
+ }
+}
+
+// set contents to zero, as for a grid
+template<class T>
+void ParticleDataImpl<T>::clear() {
+ for(IndexInt i=0; i<(IndexInt)mData.size(); ++i) mData[i] = 0.;
+}
+
+//! count by type flag
+int countParticles(const ParticleDataImpl<int> &t, const int flag);
+
+} // namespace
+
+#endif
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h.reg
new file mode 100644
index 00000000000..b681770c1d1
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h.reg
@@ -0,0 +1,70 @@
+#include "particle.h"
++ParticleBase^ static const Pb::Register _R_$IDX$ ("ParticleBase","ParticleBase","PbClass"); template<> const char* Namify<ParticleBase >::S = "ParticleBase";
+>ParticleBase^
++ParticleBase^ static const Pb::Register _R_$IDX$ ("ParticleBase","ParticleBase",ParticleBase::_W_0);
++ParticleBase^ static const Pb::Register _R_$IDX$ ("ParticleBase","create",ParticleBase::_W_1);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","ParticleSystem<$CT$>","ParticleBase"); template<> const char* Namify<ParticleSystem<$CT$> >::S = "ParticleSystem<$CT$>";
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","ParticleSystem",ParticleSystem<$CT$>::_W_2);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","pySize",ParticleSystem<$CT$>::_W_3);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","setPos",ParticleSystem<$CT$>::_W_4);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","getPos",ParticleSystem<$CT$>::_W_5);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","getPosPdata",ParticleSystem<$CT$>::_W_6);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","setPosPdata",ParticleSystem<$CT$>::_W_7);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","clear",ParticleSystem<$CT$>::_W_8);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","advectInGrid",ParticleSystem<$CT$>::_W_9);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","projectOutside",ParticleSystem<$CT$>::_W_10);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","projectOutOfBnd",ParticleSystem<$CT$>::_W_11);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","BasicParticleSystem","ParticleSystem<$BT$>"); template<> const char* Namify<BasicParticleSystem >::S = "BasicParticleSystem";
+>BasicParticleSystem^
+@BasicParticleSystem^^ParticleSystem^BasicParticleData
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","BasicParticleSystem",BasicParticleSystem::_W_12);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","save",BasicParticleSystem::_W_13);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","load",BasicParticleSystem::_W_14);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","readParticles",BasicParticleSystem::_W_15);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","addParticle",BasicParticleSystem::_W_16);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","printParts",BasicParticleSystem::_W_17);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","getDataPointer",BasicParticleSystem::_W_18);
++ParticleIndexSystem^ static const Pb::Register _R_$IDX$ ("ParticleIndexSystem","ParticleIndexSystem","ParticleSystem<$BT$>"); template<> const char* Namify<ParticleIndexSystem >::S = "ParticleIndexSystem";
+>ParticleIndexSystem^
+@ParticleIndexSystem^^ParticleSystem^ParticleIndexData
++ParticleIndexSystem^ static const Pb::Register _R_$IDX$ ("ParticleIndexSystem","ParticleIndexSystem",ParticleIndexSystem::_W_19);
++ConnectedParticleSystem^ static const Pb::Register _R_$IDX$ ("ConnectedParticleSystem<$CT$>","ConnectedParticleSystem<$CT$>","ParticleSystem<$BT$>"); template<> const char* Namify<ConnectedParticleSystem<$CT$> >::S = "ConnectedParticleSystem<$CT$>";
+@ConnectedParticleSystem^DATA,CON^ParticleSystem^DATA
++ConnectedParticleSystem^ static const Pb::Register _R_$IDX$ ("ConnectedParticleSystem<$CT$>","ConnectedParticleSystem",ConnectedParticleSystem<$CT$>::_W_20);
++ParticleDataBase^ static const Pb::Register _R_$IDX$ ("ParticleDataBase","ParticleDataBase","PbClass"); template<> const char* Namify<ParticleDataBase >::S = "ParticleDataBase";
+>ParticleDataBase^
++ParticleDataBase^ static const Pb::Register _R_$IDX$ ("ParticleDataBase","ParticleDataBase",ParticleDataBase::_W_21);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","ParticleDataImpl<$CT$>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<$CT$> >::S = "ParticleDataImpl<$CT$>";
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","ParticleDataImpl",ParticleDataImpl<$CT$>::_W_22);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","clear",ParticleDataImpl<$CT$>::_W_23);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","setSource",ParticleDataImpl<$CT$>::_W_24);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","copyFrom",ParticleDataImpl<$CT$>::_W_25);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","setConst",ParticleDataImpl<$CT$>::_W_26);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","setConstRange",ParticleDataImpl<$CT$>::_W_27);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","add",ParticleDataImpl<$CT$>::_W_28);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","sub",ParticleDataImpl<$CT$>::_W_29);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","addConst",ParticleDataImpl<$CT$>::_W_30);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","addScaled",ParticleDataImpl<$CT$>::_W_31);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","mult",ParticleDataImpl<$CT$>::_W_32);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","multConst",ParticleDataImpl<$CT$>::_W_33);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","safeDiv",ParticleDataImpl<$CT$>::_W_34);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","clamp",ParticleDataImpl<$CT$>::_W_35);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","clampMin",ParticleDataImpl<$CT$>::_W_36);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","clampMax",ParticleDataImpl<$CT$>::_W_37);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","getMaxAbs",ParticleDataImpl<$CT$>::_W_38);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","getMax",ParticleDataImpl<$CT$>::_W_39);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","getMin",ParticleDataImpl<$CT$>::_W_40);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","sum",ParticleDataImpl<$CT$>::_W_41);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","sumSquare",ParticleDataImpl<$CT$>::_W_42);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","sumMagnitude",ParticleDataImpl<$CT$>::_W_43);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","setConstIntFlag",ParticleDataImpl<$CT$>::_W_44);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","printPdata",ParticleDataImpl<$CT$>::_W_45);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","save",ParticleDataImpl<$CT$>::_W_46);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","load",ParticleDataImpl<$CT$>::_W_47);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","getDataPointer",ParticleDataImpl<$CT$>::_W_48);
+>ParticleDataImpl^int
+&static const Pb::Register _R_$IDX$ ("ParticleDataImpl<int>","PdataInt","");
+>ParticleDataImpl^Real
+&static const Pb::Register _R_$IDX$ ("ParticleDataImpl<Real>","PdataReal","");
+>ParticleDataImpl^Vec3
+&static const Pb::Register _R_$IDX$ ("ParticleDataImpl<Vec3>","PdataVec3","");
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h.reg.cpp
new file mode 100644
index 00000000000..cd4865f4f3d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/particle.h.reg.cpp
@@ -0,0 +1,275 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "particle.h"
+namespace Manta {
+#ifdef _C_BasicParticleSystem
+ static const Pb::Register _R_13 ("BasicParticleSystem","BasicParticleSystem","ParticleSystem<BasicParticleData>"); template<> const char* Namify<BasicParticleSystem >::S = "BasicParticleSystem";
+ static const Pb::Register _R_14 ("BasicParticleSystem","BasicParticleSystem",BasicParticleSystem::_W_12);
+ static const Pb::Register _R_15 ("BasicParticleSystem","save",BasicParticleSystem::_W_13);
+ static const Pb::Register _R_16 ("BasicParticleSystem","load",BasicParticleSystem::_W_14);
+ static const Pb::Register _R_17 ("BasicParticleSystem","readParticles",BasicParticleSystem::_W_15);
+ static const Pb::Register _R_18 ("BasicParticleSystem","addParticle",BasicParticleSystem::_W_16);
+ static const Pb::Register _R_19 ("BasicParticleSystem","printParts",BasicParticleSystem::_W_17);
+ static const Pb::Register _R_20 ("BasicParticleSystem","getDataPointer",BasicParticleSystem::_W_18);
+#endif
+#ifdef _C_ParticleBase
+ static const Pb::Register _R_21 ("ParticleBase","ParticleBase","PbClass"); template<> const char* Namify<ParticleBase >::S = "ParticleBase";
+ static const Pb::Register _R_22 ("ParticleBase","ParticleBase",ParticleBase::_W_0);
+ static const Pb::Register _R_23 ("ParticleBase","create",ParticleBase::_W_1);
+#endif
+#ifdef _C_ParticleDataBase
+ static const Pb::Register _R_24 ("ParticleDataBase","ParticleDataBase","PbClass"); template<> const char* Namify<ParticleDataBase >::S = "ParticleDataBase";
+ static const Pb::Register _R_25 ("ParticleDataBase","ParticleDataBase",ParticleDataBase::_W_21);
+#endif
+#ifdef _C_ParticleDataImpl
+ static const Pb::Register _R_26 ("ParticleDataImpl<int>","ParticleDataImpl<int>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<int> >::S = "ParticleDataImpl<int>";
+ static const Pb::Register _R_27 ("ParticleDataImpl<int>","ParticleDataImpl",ParticleDataImpl<int>::_W_22);
+ static const Pb::Register _R_28 ("ParticleDataImpl<int>","clear",ParticleDataImpl<int>::_W_23);
+ static const Pb::Register _R_29 ("ParticleDataImpl<int>","setSource",ParticleDataImpl<int>::_W_24);
+ static const Pb::Register _R_30 ("ParticleDataImpl<int>","copyFrom",ParticleDataImpl<int>::_W_25);
+ static const Pb::Register _R_31 ("ParticleDataImpl<int>","setConst",ParticleDataImpl<int>::_W_26);
+ static const Pb::Register _R_32 ("ParticleDataImpl<int>","setConstRange",ParticleDataImpl<int>::_W_27);
+ static const Pb::Register _R_33 ("ParticleDataImpl<int>","add",ParticleDataImpl<int>::_W_28);
+ static const Pb::Register _R_34 ("ParticleDataImpl<int>","sub",ParticleDataImpl<int>::_W_29);
+ static const Pb::Register _R_35 ("ParticleDataImpl<int>","addConst",ParticleDataImpl<int>::_W_30);
+ static const Pb::Register _R_36 ("ParticleDataImpl<int>","addScaled",ParticleDataImpl<int>::_W_31);
+ static const Pb::Register _R_37 ("ParticleDataImpl<int>","mult",ParticleDataImpl<int>::_W_32);
+ static const Pb::Register _R_38 ("ParticleDataImpl<int>","multConst",ParticleDataImpl<int>::_W_33);
+ static const Pb::Register _R_39 ("ParticleDataImpl<int>","safeDiv",ParticleDataImpl<int>::_W_34);
+ static const Pb::Register _R_40 ("ParticleDataImpl<int>","clamp",ParticleDataImpl<int>::_W_35);
+ static const Pb::Register _R_41 ("ParticleDataImpl<int>","clampMin",ParticleDataImpl<int>::_W_36);
+ static const Pb::Register _R_42 ("ParticleDataImpl<int>","clampMax",ParticleDataImpl<int>::_W_37);
+ static const Pb::Register _R_43 ("ParticleDataImpl<int>","getMaxAbs",ParticleDataImpl<int>::_W_38);
+ static const Pb::Register _R_44 ("ParticleDataImpl<int>","getMax",ParticleDataImpl<int>::_W_39);
+ static const Pb::Register _R_45 ("ParticleDataImpl<int>","getMin",ParticleDataImpl<int>::_W_40);
+ static const Pb::Register _R_46 ("ParticleDataImpl<int>","sum",ParticleDataImpl<int>::_W_41);
+ static const Pb::Register _R_47 ("ParticleDataImpl<int>","sumSquare",ParticleDataImpl<int>::_W_42);
+ static const Pb::Register _R_48 ("ParticleDataImpl<int>","sumMagnitude",ParticleDataImpl<int>::_W_43);
+ static const Pb::Register _R_49 ("ParticleDataImpl<int>","setConstIntFlag",ParticleDataImpl<int>::_W_44);
+ static const Pb::Register _R_50 ("ParticleDataImpl<int>","printPdata",ParticleDataImpl<int>::_W_45);
+ static const Pb::Register _R_51 ("ParticleDataImpl<int>","save",ParticleDataImpl<int>::_W_46);
+ static const Pb::Register _R_52 ("ParticleDataImpl<int>","load",ParticleDataImpl<int>::_W_47);
+ static const Pb::Register _R_53 ("ParticleDataImpl<int>","getDataPointer",ParticleDataImpl<int>::_W_48);
+ static const Pb::Register _R_54 ("ParticleDataImpl<Real>","ParticleDataImpl<Real>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<Real> >::S = "ParticleDataImpl<Real>";
+ static const Pb::Register _R_55 ("ParticleDataImpl<Real>","ParticleDataImpl",ParticleDataImpl<Real>::_W_22);
+ static const Pb::Register _R_56 ("ParticleDataImpl<Real>","clear",ParticleDataImpl<Real>::_W_23);
+ static const Pb::Register _R_57 ("ParticleDataImpl<Real>","setSource",ParticleDataImpl<Real>::_W_24);
+ static const Pb::Register _R_58 ("ParticleDataImpl<Real>","copyFrom",ParticleDataImpl<Real>::_W_25);
+ static const Pb::Register _R_59 ("ParticleDataImpl<Real>","setConst",ParticleDataImpl<Real>::_W_26);
+ static const Pb::Register _R_60 ("ParticleDataImpl<Real>","setConstRange",ParticleDataImpl<Real>::_W_27);
+ static const Pb::Register _R_61 ("ParticleDataImpl<Real>","add",ParticleDataImpl<Real>::_W_28);
+ static const Pb::Register _R_62 ("ParticleDataImpl<Real>","sub",ParticleDataImpl<Real>::_W_29);
+ static const Pb::Register _R_63 ("ParticleDataImpl<Real>","addConst",ParticleDataImpl<Real>::_W_30);
+ static const Pb::Register _R_64 ("ParticleDataImpl<Real>","addScaled",ParticleDataImpl<Real>::_W_31);
+ static const Pb::Register _R_65 ("ParticleDataImpl<Real>","mult",ParticleDataImpl<Real>::_W_32);
+ static const Pb::Register _R_66 ("ParticleDataImpl<Real>","multConst",ParticleDataImpl<Real>::_W_33);
+ static const Pb::Register _R_67 ("ParticleDataImpl<Real>","safeDiv",ParticleDataImpl<Real>::_W_34);
+ static const Pb::Register _R_68 ("ParticleDataImpl<Real>","clamp",ParticleDataImpl<Real>::_W_35);
+ static const Pb::Register _R_69 ("ParticleDataImpl<Real>","clampMin",ParticleDataImpl<Real>::_W_36);
+ static const Pb::Register _R_70 ("ParticleDataImpl<Real>","clampMax",ParticleDataImpl<Real>::_W_37);
+ static const Pb::Register _R_71 ("ParticleDataImpl<Real>","getMaxAbs",ParticleDataImpl<Real>::_W_38);
+ static const Pb::Register _R_72 ("ParticleDataImpl<Real>","getMax",ParticleDataImpl<Real>::_W_39);
+ static const Pb::Register _R_73 ("ParticleDataImpl<Real>","getMin",ParticleDataImpl<Real>::_W_40);
+ static const Pb::Register _R_74 ("ParticleDataImpl<Real>","sum",ParticleDataImpl<Real>::_W_41);
+ static const Pb::Register _R_75 ("ParticleDataImpl<Real>","sumSquare",ParticleDataImpl<Real>::_W_42);
+ static const Pb::Register _R_76 ("ParticleDataImpl<Real>","sumMagnitude",ParticleDataImpl<Real>::_W_43);
+ static const Pb::Register _R_77 ("ParticleDataImpl<Real>","setConstIntFlag",ParticleDataImpl<Real>::_W_44);
+ static const Pb::Register _R_78 ("ParticleDataImpl<Real>","printPdata",ParticleDataImpl<Real>::_W_45);
+ static const Pb::Register _R_79 ("ParticleDataImpl<Real>","save",ParticleDataImpl<Real>::_W_46);
+ static const Pb::Register _R_80 ("ParticleDataImpl<Real>","load",ParticleDataImpl<Real>::_W_47);
+ static const Pb::Register _R_81 ("ParticleDataImpl<Real>","getDataPointer",ParticleDataImpl<Real>::_W_48);
+ static const Pb::Register _R_82 ("ParticleDataImpl<Vec3>","ParticleDataImpl<Vec3>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<Vec3> >::S = "ParticleDataImpl<Vec3>";
+ static const Pb::Register _R_83 ("ParticleDataImpl<Vec3>","ParticleDataImpl",ParticleDataImpl<Vec3>::_W_22);
+ static const Pb::Register _R_84 ("ParticleDataImpl<Vec3>","clear",ParticleDataImpl<Vec3>::_W_23);
+ static const Pb::Register _R_85 ("ParticleDataImpl<Vec3>","setSource",ParticleDataImpl<Vec3>::_W_24);
+ static const Pb::Register _R_86 ("ParticleDataImpl<Vec3>","copyFrom",ParticleDataImpl<Vec3>::_W_25);
+ static const Pb::Register _R_87 ("ParticleDataImpl<Vec3>","setConst",ParticleDataImpl<Vec3>::_W_26);
+ static const Pb::Register _R_88 ("ParticleDataImpl<Vec3>","setConstRange",ParticleDataImpl<Vec3>::_W_27);
+ static const Pb::Register _R_89 ("ParticleDataImpl<Vec3>","add",ParticleDataImpl<Vec3>::_W_28);
+ static const Pb::Register _R_90 ("ParticleDataImpl<Vec3>","sub",ParticleDataImpl<Vec3>::_W_29);
+ static const Pb::Register _R_91 ("ParticleDataImpl<Vec3>","addConst",ParticleDataImpl<Vec3>::_W_30);
+ static const Pb::Register _R_92 ("ParticleDataImpl<Vec3>","addScaled",ParticleDataImpl<Vec3>::_W_31);
+ static const Pb::Register _R_93 ("ParticleDataImpl<Vec3>","mult",ParticleDataImpl<Vec3>::_W_32);
+ static const Pb::Register _R_94 ("ParticleDataImpl<Vec3>","multConst",ParticleDataImpl<Vec3>::_W_33);
+ static const Pb::Register _R_95 ("ParticleDataImpl<Vec3>","safeDiv",ParticleDataImpl<Vec3>::_W_34);
+ static const Pb::Register _R_96 ("ParticleDataImpl<Vec3>","clamp",ParticleDataImpl<Vec3>::_W_35);
+ static const Pb::Register _R_97 ("ParticleDataImpl<Vec3>","clampMin",ParticleDataImpl<Vec3>::_W_36);
+ static const Pb::Register _R_98 ("ParticleDataImpl<Vec3>","clampMax",ParticleDataImpl<Vec3>::_W_37);
+ static const Pb::Register _R_99 ("ParticleDataImpl<Vec3>","getMaxAbs",ParticleDataImpl<Vec3>::_W_38);
+ static const Pb::Register _R_100 ("ParticleDataImpl<Vec3>","getMax",ParticleDataImpl<Vec3>::_W_39);
+ static const Pb::Register _R_101 ("ParticleDataImpl<Vec3>","getMin",ParticleDataImpl<Vec3>::_W_40);
+ static const Pb::Register _R_102 ("ParticleDataImpl<Vec3>","sum",ParticleDataImpl<Vec3>::_W_41);
+ static const Pb::Register _R_103 ("ParticleDataImpl<Vec3>","sumSquare",ParticleDataImpl<Vec3>::_W_42);
+ static const Pb::Register _R_104 ("ParticleDataImpl<Vec3>","sumMagnitude",ParticleDataImpl<Vec3>::_W_43);
+ static const Pb::Register _R_105 ("ParticleDataImpl<Vec3>","setConstIntFlag",ParticleDataImpl<Vec3>::_W_44);
+ static const Pb::Register _R_106 ("ParticleDataImpl<Vec3>","printPdata",ParticleDataImpl<Vec3>::_W_45);
+ static const Pb::Register _R_107 ("ParticleDataImpl<Vec3>","save",ParticleDataImpl<Vec3>::_W_46);
+ static const Pb::Register _R_108 ("ParticleDataImpl<Vec3>","load",ParticleDataImpl<Vec3>::_W_47);
+ static const Pb::Register _R_109 ("ParticleDataImpl<Vec3>","getDataPointer",ParticleDataImpl<Vec3>::_W_48);
+#endif
+#ifdef _C_ParticleIndexSystem
+ static const Pb::Register _R_110 ("ParticleIndexSystem","ParticleIndexSystem","ParticleSystem<ParticleIndexData>"); template<> const char* Namify<ParticleIndexSystem >::S = "ParticleIndexSystem";
+ static const Pb::Register _R_111 ("ParticleIndexSystem","ParticleIndexSystem",ParticleIndexSystem::_W_19);
+#endif
+#ifdef _C_ParticleSystem
+ static const Pb::Register _R_112 ("ParticleSystem<BasicParticleData>","ParticleSystem<BasicParticleData>","ParticleBase"); template<> const char* Namify<ParticleSystem<BasicParticleData> >::S = "ParticleSystem<BasicParticleData>";
+ static const Pb::Register _R_113 ("ParticleSystem<BasicParticleData>","ParticleSystem",ParticleSystem<BasicParticleData>::_W_2);
+ static const Pb::Register _R_114 ("ParticleSystem<BasicParticleData>","pySize",ParticleSystem<BasicParticleData>::_W_3);
+ static const Pb::Register _R_115 ("ParticleSystem<BasicParticleData>","setPos",ParticleSystem<BasicParticleData>::_W_4);
+ static const Pb::Register _R_116 ("ParticleSystem<BasicParticleData>","getPos",ParticleSystem<BasicParticleData>::_W_5);
+ static const Pb::Register _R_117 ("ParticleSystem<BasicParticleData>","getPosPdata",ParticleSystem<BasicParticleData>::_W_6);
+ static const Pb::Register _R_118 ("ParticleSystem<BasicParticleData>","setPosPdata",ParticleSystem<BasicParticleData>::_W_7);
+ static const Pb::Register _R_119 ("ParticleSystem<BasicParticleData>","clear",ParticleSystem<BasicParticleData>::_W_8);
+ static const Pb::Register _R_120 ("ParticleSystem<BasicParticleData>","advectInGrid",ParticleSystem<BasicParticleData>::_W_9);
+ static const Pb::Register _R_121 ("ParticleSystem<BasicParticleData>","projectOutside",ParticleSystem<BasicParticleData>::_W_10);
+ static const Pb::Register _R_122 ("ParticleSystem<BasicParticleData>","projectOutOfBnd",ParticleSystem<BasicParticleData>::_W_11);
+ static const Pb::Register _R_123 ("ParticleSystem<ParticleIndexData>","ParticleSystem<ParticleIndexData>","ParticleBase"); template<> const char* Namify<ParticleSystem<ParticleIndexData> >::S = "ParticleSystem<ParticleIndexData>";
+ static const Pb::Register _R_124 ("ParticleSystem<ParticleIndexData>","ParticleSystem",ParticleSystem<ParticleIndexData>::_W_2);
+ static const Pb::Register _R_125 ("ParticleSystem<ParticleIndexData>","pySize",ParticleSystem<ParticleIndexData>::_W_3);
+ static const Pb::Register _R_126 ("ParticleSystem<ParticleIndexData>","setPos",ParticleSystem<ParticleIndexData>::_W_4);
+ static const Pb::Register _R_127 ("ParticleSystem<ParticleIndexData>","getPos",ParticleSystem<ParticleIndexData>::_W_5);
+ static const Pb::Register _R_128 ("ParticleSystem<ParticleIndexData>","getPosPdata",ParticleSystem<ParticleIndexData>::_W_6);
+ static const Pb::Register _R_129 ("ParticleSystem<ParticleIndexData>","setPosPdata",ParticleSystem<ParticleIndexData>::_W_7);
+ static const Pb::Register _R_130 ("ParticleSystem<ParticleIndexData>","clear",ParticleSystem<ParticleIndexData>::_W_8);
+ static const Pb::Register _R_131 ("ParticleSystem<ParticleIndexData>","advectInGrid",ParticleSystem<ParticleIndexData>::_W_9);
+ static const Pb::Register _R_132 ("ParticleSystem<ParticleIndexData>","projectOutside",ParticleSystem<ParticleIndexData>::_W_10);
+ static const Pb::Register _R_133 ("ParticleSystem<ParticleIndexData>","projectOutOfBnd",ParticleSystem<ParticleIndexData>::_W_11);
+#endif
+static const Pb::Register _R_10 ("ParticleDataImpl<int>","PdataInt","");
+static const Pb::Register _R_11 ("ParticleDataImpl<Real>","PdataReal","");
+static const Pb::Register _R_12 ("ParticleDataImpl<Vec3>","PdataVec3","");
+extern "C" {
+void PbRegister_file_10()
+{
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+ KEEP_UNUSED(_R_38);
+ KEEP_UNUSED(_R_39);
+ KEEP_UNUSED(_R_40);
+ KEEP_UNUSED(_R_41);
+ KEEP_UNUSED(_R_42);
+ KEEP_UNUSED(_R_43);
+ KEEP_UNUSED(_R_44);
+ KEEP_UNUSED(_R_45);
+ KEEP_UNUSED(_R_46);
+ KEEP_UNUSED(_R_47);
+ KEEP_UNUSED(_R_48);
+ KEEP_UNUSED(_R_49);
+ KEEP_UNUSED(_R_50);
+ KEEP_UNUSED(_R_51);
+ KEEP_UNUSED(_R_52);
+ KEEP_UNUSED(_R_53);
+ KEEP_UNUSED(_R_54);
+ KEEP_UNUSED(_R_55);
+ KEEP_UNUSED(_R_56);
+ KEEP_UNUSED(_R_57);
+ KEEP_UNUSED(_R_58);
+ KEEP_UNUSED(_R_59);
+ KEEP_UNUSED(_R_60);
+ KEEP_UNUSED(_R_61);
+ KEEP_UNUSED(_R_62);
+ KEEP_UNUSED(_R_63);
+ KEEP_UNUSED(_R_64);
+ KEEP_UNUSED(_R_65);
+ KEEP_UNUSED(_R_66);
+ KEEP_UNUSED(_R_67);
+ KEEP_UNUSED(_R_68);
+ KEEP_UNUSED(_R_69);
+ KEEP_UNUSED(_R_70);
+ KEEP_UNUSED(_R_71);
+ KEEP_UNUSED(_R_72);
+ KEEP_UNUSED(_R_73);
+ KEEP_UNUSED(_R_74);
+ KEEP_UNUSED(_R_75);
+ KEEP_UNUSED(_R_76);
+ KEEP_UNUSED(_R_77);
+ KEEP_UNUSED(_R_78);
+ KEEP_UNUSED(_R_79);
+ KEEP_UNUSED(_R_80);
+ KEEP_UNUSED(_R_81);
+ KEEP_UNUSED(_R_82);
+ KEEP_UNUSED(_R_83);
+ KEEP_UNUSED(_R_84);
+ KEEP_UNUSED(_R_85);
+ KEEP_UNUSED(_R_86);
+ KEEP_UNUSED(_R_87);
+ KEEP_UNUSED(_R_88);
+ KEEP_UNUSED(_R_89);
+ KEEP_UNUSED(_R_90);
+ KEEP_UNUSED(_R_91);
+ KEEP_UNUSED(_R_92);
+ KEEP_UNUSED(_R_93);
+ KEEP_UNUSED(_R_94);
+ KEEP_UNUSED(_R_95);
+ KEEP_UNUSED(_R_96);
+ KEEP_UNUSED(_R_97);
+ KEEP_UNUSED(_R_98);
+ KEEP_UNUSED(_R_99);
+ KEEP_UNUSED(_R_100);
+ KEEP_UNUSED(_R_101);
+ KEEP_UNUSED(_R_102);
+ KEEP_UNUSED(_R_103);
+ KEEP_UNUSED(_R_104);
+ KEEP_UNUSED(_R_105);
+ KEEP_UNUSED(_R_106);
+ KEEP_UNUSED(_R_107);
+ KEEP_UNUSED(_R_108);
+ KEEP_UNUSED(_R_109);
+ KEEP_UNUSED(_R_110);
+ KEEP_UNUSED(_R_111);
+ KEEP_UNUSED(_R_112);
+ KEEP_UNUSED(_R_113);
+ KEEP_UNUSED(_R_114);
+ KEEP_UNUSED(_R_115);
+ KEEP_UNUSED(_R_116);
+ KEEP_UNUSED(_R_117);
+ KEEP_UNUSED(_R_118);
+ KEEP_UNUSED(_R_119);
+ KEEP_UNUSED(_R_120);
+ KEEP_UNUSED(_R_121);
+ KEEP_UNUSED(_R_122);
+ KEEP_UNUSED(_R_123);
+ KEEP_UNUSED(_R_124);
+ KEEP_UNUSED(_R_125);
+ KEEP_UNUSED(_R_126);
+ KEEP_UNUSED(_R_127);
+ KEEP_UNUSED(_R_128);
+ KEEP_UNUSED(_R_129);
+ KEEP_UNUSED(_R_130);
+ KEEP_UNUSED(_R_131);
+ KEEP_UNUSED(_R_132);
+ KEEP_UNUSED(_R_133);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/advection.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/advection.cpp
new file mode 100644
index 00000000000..96794b3ba47
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/advection.cpp
@@ -0,0 +1,718 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2015 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for advection
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+#include <limits>
+
+using namespace std;
+
+namespace Manta {
+
+
+//! Semi-Lagrange interpolation kernel
+
+
+template <class T> struct SemiLagrange : public KernelBase {
+ SemiLagrange(const FlagGrid& flags, const MACGrid& vel, Grid<T>& dst, const Grid<T>& src, Real dt, bool isLevelset, int orderSpace, int orderTrace) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),src(src),dt(dt),isLevelset(isLevelset),orderSpace(orderSpace),orderTrace(orderTrace) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, Grid<T>& dst, const Grid<T>& src, Real dt, bool isLevelset, int orderSpace, int orderTrace ) const {
+ if (orderTrace == 1) {
+ // traceback position
+ Vec3 pos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getCentered(i,j,k) * dt;
+ dst(i,j,k) = src.getInterpolatedHi(pos, orderSpace);
+ } else if (orderTrace == 2) {
+ // backtracing using explicit midpoint
+ Vec3 p0 = Vec3(i+0.5f,j+0.5f,k+0.5f);
+ Vec3 p1 = p0 - vel.getCentered(i,j,k)*dt*0.5;
+ Vec3 p2 = p0 - vel.getInterpolated(p1)*dt;
+ dst(i,j,k) = src.getInterpolatedHi(p2, orderSpace);
+ } else {
+ assertMsg(false, "Unknown backtracing order "<<orderTrace);
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline Grid<T>& getArg2() {
+ return dst; }
+ typedef Grid<T> type2;inline const Grid<T>& getArg3() {
+ return src; }
+ typedef Grid<T> type3;inline Real& getArg4() {
+ return dt; }
+ typedef Real type4;inline bool& getArg5() {
+ return isLevelset; }
+ typedef bool type5;inline int& getArg6() {
+ return orderSpace; }
+ typedef int type6;inline int& getArg7() {
+ return orderTrace; }
+ typedef int type7; void runMessage() { debMsg("Executing kernel SemiLagrange ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,dst,src,dt,isLevelset,orderSpace,orderTrace); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,dst,src,dt,isLevelset,orderSpace,orderTrace); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; const MACGrid& vel; Grid<T>& dst; const Grid<T>& src; Real dt; bool isLevelset; int orderSpace; int orderTrace; }
+;
+
+//! Semi-Lagrange interpolation kernel for MAC grids
+
+
+ struct SemiLagrangeMAC : public KernelBase {
+ SemiLagrangeMAC(const FlagGrid& flags, const MACGrid& vel, MACGrid& dst, const MACGrid& src, Real dt, int orderSpace, int orderTrace) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),src(src),dt(dt),orderSpace(orderSpace),orderTrace(orderTrace) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, MACGrid& dst, const MACGrid& src, Real dt, int orderSpace, int orderTrace ) const {
+ if (orderTrace == 1) {
+ // get currect velocity at MAC position
+ // no need to shift xpos etc. as lookup field is also shifted
+ Vec3 xpos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACX(i,j,k) * dt;
+ Real vx = src.getInterpolatedComponentHi<0>(xpos, orderSpace);
+ Vec3 ypos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACY(i,j,k) * dt;
+ Real vy = src.getInterpolatedComponentHi<1>(ypos, orderSpace);
+ Vec3 zpos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACZ(i,j,k) * dt;
+ Real vz = src.getInterpolatedComponentHi<2>(zpos, orderSpace);
+
+ dst(i,j,k) = Vec3(vx,vy,vz);
+ } else if (orderTrace == 2) {
+ Vec3 p0 = Vec3(i+0.5,j+0.5,k+0.5);
+ Vec3 xp0 = Vec3(i,j+0.5f,k+0.5f);
+ Vec3 xp1 = xp0 - src.getAtMACX(i,j,k)*dt*0.5;
+ Vec3 xp2 = p0 - src.getInterpolated(xp1)*dt;
+ Real vx = src.getInterpolatedComponentHi<0>(xp2, orderSpace);
+ Vec3 yp0 = Vec3(i+0.5f,j,k+0.5f);
+ Vec3 yp1 = yp0 - src.getAtMACY(i,j,k)*dt*0.5;
+ Vec3 yp2 = p0 - src.getInterpolated(yp1)*dt;
+ Real vy = src.getInterpolatedComponentHi<1>(yp2, orderSpace);
+ Vec3 zp0 = Vec3(i+0.5f,j+0.5f,k);
+ Vec3 zp1 = zp0 - src.getAtMACZ(i,j,k)*dt*0.5;
+ Vec3 zp2 = p0 - src.getInterpolated(zp1)*dt;
+ Real vz = src.getInterpolatedComponentHi<2>(zp2, orderSpace);
+
+ dst(i,j,k) = Vec3(vx,vy,vz);
+ } else {
+ assertMsg(false, "Unknown backtracing order "<<orderTrace);
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return dst; }
+ typedef MACGrid type2;inline const MACGrid& getArg3() {
+ return src; }
+ typedef MACGrid type3;inline Real& getArg4() {
+ return dt; }
+ typedef Real type4;inline int& getArg5() {
+ return orderSpace; }
+ typedef int type5;inline int& getArg6() {
+ return orderTrace; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel SemiLagrangeMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,dst,src,dt,orderSpace,orderTrace); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,dst,src,dt,orderSpace,orderTrace); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; const MACGrid& vel; MACGrid& dst; const MACGrid& src; Real dt; int orderSpace; int orderTrace; }
+;
+
+
+//! Kernel: Correct based on forward and backward SL steps (for both centered & mac grids)
+
+
+
+template <class T> struct MacCormackCorrect : public KernelBase {
+ MacCormackCorrect(const FlagGrid& flags, Grid<T>& dst, const Grid<T>& old, const Grid<T>& fwd, const Grid<T>& bwd, Real strength, bool isLevelSet, bool isMAC=false ) : KernelBase(&flags,0) ,flags(flags),dst(dst),old(old),fwd(fwd),bwd(bwd),strength(strength),isLevelSet(isLevelSet),isMAC(isMAC) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags, Grid<T>& dst, const Grid<T>& old, const Grid<T>& fwd, const Grid<T>& bwd, Real strength, bool isLevelSet, bool isMAC=false ) const {
+ dst[idx] = fwd[idx];
+
+ if (flags.isFluid(idx)) {
+ // only correct inside fluid region; note, strenth of correction can be modified here
+ dst[idx] += strength * 0.5 * (old[idx] - bwd[idx]);
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<T>& getArg1() {
+ return dst; }
+ typedef Grid<T> type1;inline const Grid<T>& getArg2() {
+ return old; }
+ typedef Grid<T> type2;inline const Grid<T>& getArg3() {
+ return fwd; }
+ typedef Grid<T> type3;inline const Grid<T>& getArg4() {
+ return bwd; }
+ typedef Grid<T> type4;inline Real& getArg5() {
+ return strength; }
+ typedef Real type5;inline bool& getArg6() {
+ return isLevelSet; }
+ typedef bool type6;inline bool& getArg7() {
+ return isMAC; }
+ typedef bool type7; void runMessage() { debMsg("Executing kernel MacCormackCorrect ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, flags,dst,old,fwd,bwd,strength,isLevelSet,isMAC); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const FlagGrid& flags; Grid<T>& dst; const Grid<T>& old; const Grid<T>& fwd; const Grid<T>& bwd; Real strength; bool isLevelSet; bool isMAC; }
+;
+
+//! Kernel: Correct based on forward and backward SL steps (for both centered & mac grids)
+
+
+
+template <class T> struct MacCormackCorrectMAC : public KernelBase {
+ MacCormackCorrectMAC(const FlagGrid& flags, Grid<T>& dst, const Grid<T>& old, const Grid<T>& fwd, const Grid<T>& bwd, Real strength, bool isLevelSet, bool isMAC=false ) : KernelBase(&flags,0) ,flags(flags),dst(dst),old(old),fwd(fwd),bwd(bwd),strength(strength),isLevelSet(isLevelSet),isMAC(isMAC) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<T>& dst, const Grid<T>& old, const Grid<T>& fwd, const Grid<T>& bwd, Real strength, bool isLevelSet, bool isMAC=false ) const {
+ bool skip[3] = { false, false, false };
+
+ if (!flags.isFluid(i,j,k)) skip[0] = skip[1] = skip[2] = true;
+ if(isMAC) {
+ if( (i>0) && (!flags.isFluid(i-1,j,k) )) skip[0] = true;
+ if( (j>0) && (!flags.isFluid(i,j-1,k) )) skip[1] = true;
+ if( (k>0) && (!flags.isFluid(i,j,k-1) )) skip[2] = true;
+ }
+
+ for(int c=0; c<3; ++c ) {
+ if ( skip[c] ) {
+ dst(i,j,k)[c] = fwd(i,j,k)[c];
+ } else {
+ // perform actual correction with given strength
+ dst(i,j,k)[c] = fwd(i,j,k)[c] + strength * 0.5 * (old(i,j,k)[c] - bwd(i,j,k)[c]);
+ }
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<T>& getArg1() {
+ return dst; }
+ typedef Grid<T> type1;inline const Grid<T>& getArg2() {
+ return old; }
+ typedef Grid<T> type2;inline const Grid<T>& getArg3() {
+ return fwd; }
+ typedef Grid<T> type3;inline const Grid<T>& getArg4() {
+ return bwd; }
+ typedef Grid<T> type4;inline Real& getArg5() {
+ return strength; }
+ typedef Real type5;inline bool& getArg6() {
+ return isLevelSet; }
+ typedef bool type6;inline bool& getArg7() {
+ return isMAC; }
+ typedef bool type7; void runMessage() { debMsg("Executing kernel MacCormackCorrectMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,dst,old,fwd,bwd,strength,isLevelSet,isMAC); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,dst,old,fwd,bwd,strength,isLevelSet,isMAC); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; Grid<T>& dst; const Grid<T>& old; const Grid<T>& fwd; const Grid<T>& bwd; Real strength; bool isLevelSet; bool isMAC; }
+;
+
+// Helper to collect min/max in a template
+template<class T> inline void getMinMax(T& minv, T& maxv, const T& val) {
+ if (val < minv) minv = val;
+ if (val > maxv) maxv = val;
+}
+template<> inline void getMinMax<Vec3>(Vec3& minv, Vec3& maxv, const Vec3& val) {
+ getMinMax(minv.x, maxv.x, val.x);
+ getMinMax(minv.y, maxv.y, val.y);
+ getMinMax(minv.z, maxv.z, val.z);
+}
+
+//! detect out of bounds value
+template<class T> inline bool cmpMinMax(T& minv, T& maxv, const T& val) {
+ if (val < minv) return true;
+ if (val > maxv) return true;
+ return false;
+}
+template<> inline bool cmpMinMax<Vec3>(Vec3& minv, Vec3& maxv, const Vec3& val) {
+ return( cmpMinMax(minv.x, maxv.x, val.x) | cmpMinMax(minv.y, maxv.y, val.y) | cmpMinMax(minv.z, maxv.z, val.z));
+}
+
+
+#define checkFlag(x,y,z) (flags((x),(y),(z)) & (FlagGrid::TypeFluid|FlagGrid::TypeEmpty))
+
+//! Helper function for clamping non-mac grids (those have specialized per component version below)
+// Note - 2 clamp modes, a sharper one (default, clampMode 1, also uses backward step),
+// and a softer version (clampMode 2) that is recommended in Andy's paper
+template<class T>
+inline T doClampComponent(const Vec3i& gridSize, const FlagGrid& flags, T dst, const Grid<T>& orig, const T fwd, const Vec3& pos, const Vec3& vel, const int clampMode )
+{
+ T minv( std::numeric_limits<Real>::max()), maxv( -std::numeric_limits<Real>::max());
+ bool haveFl = false;
+
+ // forward (and optionally) backward
+ Vec3i positions[2];
+ int numPos = 1;
+ positions[0] = toVec3i(pos - vel);
+ if(clampMode==1) { numPos = 2;
+ positions[1] = toVec3i(pos + vel); }
+
+ for(int l=0; l<numPos; ++l) {
+ Vec3i& currPos = positions[l];
+
+ // clamp lookup to grid
+ const int i0 = clamp(currPos.x, 0, gridSize.x-1); // note! gridsize already has -1 from call
+ const int j0 = clamp(currPos.y, 0, gridSize.y-1);
+ const int k0 = clamp(currPos.z, 0, (orig.is3D() ? (gridSize.z-1) : 1) );
+ const int i1 = i0+1, j1 = j0+1, k1= (orig.is3D() ? (k0+1) : k0);
+
+ // find min/max around source pos
+ if(checkFlag(i0,j0,k0)) { getMinMax(minv, maxv, orig(i0,j0,k0)); haveFl=true; }
+ if(checkFlag(i1,j0,k0)) { getMinMax(minv, maxv, orig(i1,j0,k0)); haveFl=true; }
+ if(checkFlag(i0,j1,k0)) { getMinMax(minv, maxv, orig(i0,j1,k0)); haveFl=true; }
+ if(checkFlag(i1,j1,k0)) { getMinMax(minv, maxv, orig(i1,j1,k0)); haveFl=true; }
+
+ if(orig.is3D()) {
+ if(checkFlag(i0,j0,k1)) { getMinMax(minv, maxv, orig(i0,j0,k1)); haveFl=true; }
+ if(checkFlag(i1,j0,k1)) { getMinMax(minv, maxv, orig(i1,j0,k1)); haveFl=true; }
+ if(checkFlag(i0,j1,k1)) { getMinMax(minv, maxv, orig(i0,j1,k1)); haveFl=true; }
+ if(checkFlag(i1,j1,k1)) { getMinMax(minv, maxv, orig(i1,j1,k1)); haveFl=true; } }
+ }
+
+ if(!haveFl) return fwd;
+ if(clampMode==1) {
+ dst = clamp(dst, minv, maxv); // hard clamp
+ } else {
+ if(cmpMinMax(minv,maxv,dst)) dst = fwd; // recommended in paper, "softer"
+ }
+ return dst;
+}
+
+//! Helper function for clamping MAC grids, slight differences in flag checks
+// similar to scalar version, just uses single component c of vec3 values
+// for symmetry, reverts to first order near boundaries for clampMode 2
+template<int c>
+inline Real doClampComponentMAC(const FlagGrid& flags, const Vec3i& gridSize, Real dst, const MACGrid& orig, Real fwd, const Vec3& pos, const Vec3& vel, const int clampMode )
+{
+ Real minv = std::numeric_limits<Real>::max(), maxv = -std::numeric_limits<Real>::max();
+ //bool haveFl = false;
+
+ // forward (and optionally) backward
+ Vec3i positions[2];
+ int numPos = 1;
+ positions[0] = toVec3i(pos - vel);
+ if(clampMode==1) { numPos = 2;
+ positions[1] = toVec3i(pos + vel); }
+
+ Vec3i oPos = toVec3i(pos);
+ Vec3i nbPos = oPos; nbPos[c] -= 1;
+ if(clampMode==2 && (! (checkFlag(oPos.x,oPos.y,oPos.z) && checkFlag(nbPos.x,nbPos.y,nbPos.z)) )) return fwd; // replaces haveFl check
+
+ for(int l=0; l<numPos; ++l) {
+ Vec3i& currPos = positions[l];
+
+ const int i0 = clamp(currPos.x, 0, gridSize.x-1); // note! gridsize already has -1 from call
+ const int j0 = clamp(currPos.y, 0, gridSize.y-1); // but we need a clamp to -2 for the +1 offset below
+ const int k0 = clamp(currPos.z, 0, (orig.is3D() ? (gridSize.z-1) : 0) );
+ const int i1 = i0+1, j1 = j0+1, k1= (orig.is3D() ? (k0+1) : k0);
+
+ // find min/max around source pos
+ getMinMax(minv, maxv, orig(i0,j0,k0)[c]);
+ getMinMax(minv, maxv, orig(i1,j0,k0)[c]);
+ getMinMax(minv, maxv, orig(i0,j1,k0)[c]);
+ getMinMax(minv, maxv, orig(i1,j1,k0)[c]);
+
+ if(orig.is3D()) {
+ getMinMax(minv, maxv, orig(i0,j0,k1)[c]);
+ getMinMax(minv, maxv, orig(i1,j0,k1)[c]);
+ getMinMax(minv, maxv, orig(i0,j1,k1)[c]);
+ getMinMax(minv, maxv, orig(i1,j1,k1)[c]); }
+ }
+
+ if(clampMode==1) {
+ dst = clamp(dst, minv, maxv); // hard clamp
+ } else {
+ if(cmpMinMax(minv,maxv,dst)) dst = fwd; // recommended in paper, "softer"
+ }
+ return dst;
+}
+
+#undef checkFlag
+
+//! Kernel: Clamp obtained value to min/max in source area, and reset values that point out of grid or into boundaries
+// (note - MAC grids are handled below)
+
+
+template <class T> struct MacCormackClamp : public KernelBase {
+ MacCormackClamp(const FlagGrid& flags, const MACGrid& vel, Grid<T>& dst, const Grid<T>& orig, const Grid<T>& fwd, Real dt, const int clampMode) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),orig(orig),fwd(fwd),dt(dt),clampMode(clampMode) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, Grid<T>& dst, const Grid<T>& orig, const Grid<T>& fwd, Real dt, const int clampMode ) const {
+ T dval = dst(i,j,k);
+ Vec3i gridUpper = flags.getSize() - 1;
+
+ dval = doClampComponent<T>(gridUpper, flags, dval, orig, fwd(i,j,k), Vec3(i,j,k), vel.getCentered(i,j,k) * dt, clampMode );
+
+ if(1 && clampMode==1) {
+ // lookup forward/backward , round to closest NB
+ Vec3i posFwd = toVec3i( Vec3(i,j,k) + Vec3(0.5,0.5,0.5) - vel.getCentered(i,j,k) * dt );
+ Vec3i posBwd = toVec3i( Vec3(i,j,k) + Vec3(0.5,0.5,0.5) + vel.getCentered(i,j,k) * dt );
+
+ // test if lookups point out of grid or into obstacle (note doClampComponent already checks sides, below is needed for valid flags access)
+ if (posFwd.x < 0 || posFwd.y < 0 || posFwd.z < 0 ||
+ posBwd.x < 0 || posBwd.y < 0 || posBwd.z < 0 ||
+ posFwd.x > gridUpper.x || posFwd.y > gridUpper.y || ((posFwd.z > gridUpper.z)&&flags.is3D()) ||
+ posBwd.x > gridUpper.x || posBwd.y > gridUpper.y || ((posBwd.z > gridUpper.z)&&flags.is3D()) ||
+ flags.isObstacle(posFwd) || flags.isObstacle(posBwd) )
+ {
+ dval = fwd(i,j,k);
+ }
+ }
+ // clampMode 2 handles flags in doClampComponent call
+
+ dst(i,j,k) = dval;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline Grid<T>& getArg2() {
+ return dst; }
+ typedef Grid<T> type2;inline const Grid<T>& getArg3() {
+ return orig; }
+ typedef Grid<T> type3;inline const Grid<T>& getArg4() {
+ return fwd; }
+ typedef Grid<T> type4;inline Real& getArg5() {
+ return dt; }
+ typedef Real type5;inline const int& getArg6() {
+ return clampMode; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel MacCormackClamp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,dst,orig,fwd,dt,clampMode); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,dst,orig,fwd,dt,clampMode); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; const MACGrid& vel; Grid<T>& dst; const Grid<T>& orig; const Grid<T>& fwd; Real dt; const int clampMode; }
+;
+
+//! Kernel: same as MacCormackClamp above, but specialized version for MAC grids
+
+
+ struct MacCormackClampMAC : public KernelBase {
+ MacCormackClampMAC(const FlagGrid& flags, const MACGrid& vel, MACGrid& dst, const MACGrid& orig, const MACGrid& fwd, Real dt, const int clampMode) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),orig(orig),fwd(fwd),dt(dt),clampMode(clampMode) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, MACGrid& dst, const MACGrid& orig, const MACGrid& fwd, Real dt, const int clampMode ) const {
+ Vec3 pos(i,j,k);
+ Vec3 dval = dst(i,j,k);
+ Vec3 dfwd = fwd(i,j,k);
+ Vec3i gridUpper = flags.getSize() - 1;
+
+ dval.x = doClampComponentMAC<0>(flags, gridUpper, dval.x, orig, dfwd.x, pos, vel.getAtMACX(i,j,k) * dt, clampMode );
+ dval.y = doClampComponentMAC<1>(flags, gridUpper, dval.y, orig, dfwd.y, pos, vel.getAtMACY(i,j,k) * dt, clampMode );
+ if(flags.is3D())
+ dval.z = doClampComponentMAC<2>(flags, gridUpper, dval.z, orig, dfwd.z, pos, vel.getAtMACZ(i,j,k) * dt, clampMode );
+
+ // note - the MAC version currently does not check whether source points were inside an obstacle! (unlike centered version)
+ // this would need to be done for each face separately to stay symmetric...
+
+ dst(i,j,k) = dval;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return dst; }
+ typedef MACGrid type2;inline const MACGrid& getArg3() {
+ return orig; }
+ typedef MACGrid type3;inline const MACGrid& getArg4() {
+ return fwd; }
+ typedef MACGrid type4;inline Real& getArg5() {
+ return dt; }
+ typedef Real type5;inline const int& getArg6() {
+ return clampMode; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel MacCormackClampMAC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,dst,orig,fwd,dt,clampMode); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,dst,orig,fwd,dt,clampMode); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; const MACGrid& vel; MACGrid& dst; const MACGrid& orig; const MACGrid& fwd; Real dt; const int clampMode; }
+;
+
+
+//! template function for performing SL advection
+//! (Note boundary width only needed for specialization for MAC grids below)
+template<class GridType>
+void fnAdvectSemiLagrange(FluidSolver* parent, const FlagGrid& flags, const MACGrid& vel, GridType& orig, int order, Real strength, int orderSpace, int clampMode, int orderTrace) {
+ typedef typename GridType::BASETYPE T;
+
+ Real dt = parent->getDt();
+ bool levelset = orig.getType() & GridBase::TypeLevelset;
+
+ // forward step
+ GridType fwd(parent);
+ SemiLagrange<T> (flags, vel, fwd, orig, dt, levelset, orderSpace, orderTrace);
+
+ if (order == 1) {
+ orig.swap(fwd);
+ }
+ else if (order == 2) { // MacCormack
+ GridType bwd(parent);
+ GridType newGrid(parent);
+
+ // bwd <- backwards step
+ SemiLagrange<T> (flags, vel, bwd, fwd, -dt, levelset, orderSpace, orderTrace);
+
+ // newGrid <- compute correction
+ MacCormackCorrect<T> (flags, newGrid, orig, fwd, bwd, strength, levelset);
+
+ // clamp values
+ MacCormackClamp<T> (flags, vel, newGrid, orig, fwd, dt, clampMode);
+
+ orig.swap(newGrid);
+ }
+}
+
+// outflow functions
+
+//! calculate local propagation velocity for cell (i,j,k)
+Vec3 getBulkVel(const FlagGrid& flags, const MACGrid& vel, int i, int j, int k){
+ Vec3 avg = Vec3(0.);
+ int count = 0;
+ int size = 1; // stencil size
+ int nmax = (flags.is3D() ? size : 0);
+ // average the neighboring fluid / outflow cell's velocity
+ for (int n = -nmax; n <= nmax; n++){
+ for (int m = -size; m <= size; m++){
+ for (int l = -size; l <= size; l++){
+ if (flags.isInBounds(Vec3i(i+l,j+m,k+n)) && (flags.isFluid(i+l,j+m,k+n) || flags.isOutflow(i+l,j+m,k+n))){
+ avg += vel(i+l,j+m,k+n);
+ count++;
+ }
+ }
+ }
+ }
+ return count>0 ? avg/count : avg;
+}
+
+//! extrapolate normal velocity components into outflow cell
+ struct extrapolateVelConvectiveBC : public KernelBase {
+ extrapolateVelConvectiveBC(const FlagGrid& flags, const MACGrid& vel, MACGrid& velDst, const MACGrid& velPrev, Real timeStep) : KernelBase(&flags,0) ,flags(flags),vel(vel),velDst(velDst),velPrev(velPrev),timeStep(timeStep) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, MACGrid& velDst, const MACGrid& velPrev, Real timeStep ) const {
+ if (flags.isOutflow(i, j, k)) {
+ Vec3 bulkVel = getBulkVel(flags, vel, i, j, k);
+ int dim = flags.is3D() ? 3 : 2;
+ const Vec3i cur = Vec3i(i, j, k);
+ Vec3i low, up, flLow, flUp;
+ int cnt = 0;
+ // iterate over each velocity component x, y, z
+ for (int c = 0; c < dim; c++) {
+ low = up = flLow = flUp = cur;
+ Real factor = timeStep * max((Real)1.0, bulkVel[c]); // prevent the extrapolated velocity from exploding when bulk velocity below 1
+ low[c] = flLow[c] = cur[c] - 1;
+ up[c] = flUp[c] = cur[c] + 1;
+ // iterate over bWidth to allow for extrapolation into more distant outflow cells; hard-coded extrapolation distance of two cells
+ for (int d = 0; d<2; d++) {
+ bool extrapolateFromLower = flags.isInBounds(flLow) && flags.isFluid(flLow);
+ bool extrapolateFromUpper = flags.isInBounds(flUp) && flags.isFluid(flUp);
+ if (extrapolateFromLower || extrapolateFromUpper) {
+ if (extrapolateFromLower) {
+ velDst(i, j, k) += ((vel(i, j, k) - velPrev(i, j, k)) / factor) + vel(low);
+ cnt++;
+ }
+ if (extrapolateFromUpper) {
+ // check for cells equally far away from two fluid cells -> average value between both sides
+ velDst(i, j, k) += ((vel(i, j, k) - velPrev(i, j, k)) / factor) + vel(up);
+ cnt++;
+ }
+ break;
+ }
+ flLow[c]--;
+ flUp[c]++;
+ }
+ }
+ if (cnt > 0) velDst(i, j, k) /= cnt;
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return velDst; }
+ typedef MACGrid type2;inline const MACGrid& getArg3() {
+ return velPrev; }
+ typedef MACGrid type3;inline Real& getArg4() {
+ return timeStep; }
+ typedef Real type4; void runMessage() { debMsg("Executing kernel extrapolateVelConvectiveBC ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,vel,velDst,velPrev,timeStep); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,vel,velDst,velPrev,timeStep); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; const MACGrid& vel; MACGrid& velDst; const MACGrid& velPrev; Real timeStep; }
+;
+
+//! copy extrapolated velocity components
+ struct copyChangedVels : public KernelBase {
+ copyChangedVels(const FlagGrid& flags, const MACGrid& velDst, MACGrid& vel) : KernelBase(&flags,0) ,flags(flags),velDst(velDst),vel(vel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& velDst, MACGrid& vel ) const { if (flags.isOutflow(i,j,k)) vel(i, j, k) = velDst(i, j, k); } inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return velDst; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2; void runMessage() { debMsg("Executing kernel copyChangedVels ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,velDst,vel); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,velDst,vel); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; const MACGrid& velDst; MACGrid& vel; }
+;
+
+//! extrapolate normal velocity components into open boundary cells (marked as outflow cells)
+void applyOutflowBC(const FlagGrid& flags, MACGrid& vel, const MACGrid& velPrev, double timeStep) {
+ MACGrid velDst(vel.getParent()); // do not overwrite vel while it is read
+ extrapolateVelConvectiveBC(flags, vel, velDst, velPrev, max(1.0,timeStep*4));
+ copyChangedVels(flags,velDst,vel);
+}
+
+// advection helpers
+
+//! prevent parts of the surface getting "stuck" in obstacle regions
+ struct knResetPhiInObs : public KernelBase {
+ knResetPhiInObs(const FlagGrid& flags, Grid<Real>& sdf) : KernelBase(&flags,0) ,flags(flags),sdf(sdf) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& sdf ) const {
+ if( flags.isObstacle(i,j,k) && (sdf(i,j,k)<0.) ) {
+ sdf(i,j,k) = 0.1;
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return sdf; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel knResetPhiInObs ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,sdf); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,sdf); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; Grid<Real>& sdf; }
+;
+void resetPhiInObs(const FlagGrid& flags, Grid<Real>& sdf) { knResetPhiInObs(flags, sdf); } static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "resetPhiInObs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& sdf = *_args.getPtr<Grid<Real> >("sdf",1,&_lock); _retval = getPyNone(); resetPhiInObs(flags,sdf); _args.check(); }
+ pbFinalizePlugin(parent,"resetPhiInObs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("resetPhiInObs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_resetPhiInObs ("","resetPhiInObs",_W_0);
+extern "C" {
+ void PbRegister_resetPhiInObs() {
+ KEEP_UNUSED(_RP_resetPhiInObs); }
+ }
+
+
+
+// advection main calls
+
+//! template function for performing SL advection: specialized version for MAC grids
+template<>
+void fnAdvectSemiLagrange<MACGrid>(FluidSolver* parent, const FlagGrid& flags, const MACGrid& vel, MACGrid& orig, int order, Real strength, int orderSpace, int clampMode, int orderTrace) {
+ Real dt = parent->getDt();
+
+ // forward step
+ MACGrid fwd(parent);
+ SemiLagrangeMAC (flags, vel, fwd, orig, dt, orderSpace, orderTrace);
+
+ if (orderSpace != 1) { debMsg("Warning higher order for MAC grids not yet implemented...",1); }
+
+ if (order == 1) {
+ applyOutflowBC(flags, fwd, orig, dt);
+ orig.swap(fwd);
+ }
+ else if (order == 2) { // MacCormack
+ MACGrid bwd(parent);
+ MACGrid newGrid(parent);
+
+ // bwd <- backwards step
+ SemiLagrangeMAC (flags, vel, bwd, fwd, -dt, orderSpace, orderTrace);
+
+ // newGrid <- compute correction
+ MacCormackCorrectMAC<Vec3> (flags, newGrid, orig, fwd, bwd, strength, false, true);
+
+ // clamp values
+ MacCormackClampMAC (flags, vel, newGrid, orig, fwd, dt, clampMode);
+
+ applyOutflowBC(flags, newGrid, orig, dt);
+ orig.swap(newGrid);
+ }
+}
+
+
+//! Perform semi-lagrangian advection of target Real- or Vec3 grid
+//! Open boundary handling needs information about width of border
+//! Clamping modes: 1 regular clamp leading to more overshoot and sharper results, 2 revert to 1st order slightly smoother less overshoot (enable when 1 gives artifacts)
+
+
+void advectSemiLagrange(const FlagGrid* flags, const MACGrid* vel, GridBase* grid, int order = 1, Real strength = 1.0, int orderSpace = 1, bool openBounds = false, int boundaryWidth = -1, int clampMode = 2, int orderTrace = 1) {
+ assertMsg(order==1 || order==2, "AdvectSemiLagrange: Only order 1 (regular SL) and 2 (MacCormack) supported");
+ if((boundaryWidth!=-1)||(openBounds)) { debMsg("Warning: boundaryWidth and openBounds parameters in AdvectSemiLagrange plugin are deprecated (and have no more effect), please remove.", 0); }
+
+ // determine type of grid
+ if (grid->getType() & GridBase::TypeReal) {
+ fnAdvectSemiLagrange< Grid<Real> >(flags->getParent(), *flags, *vel, *((Grid<Real>*) grid), order, strength, orderSpace, clampMode, orderTrace);
+ }
+ else if (grid->getType() & GridBase::TypeMAC) {
+ fnAdvectSemiLagrange< MACGrid >(flags->getParent(), *flags, *vel, *((MACGrid*) grid), order, strength, orderSpace, clampMode, orderTrace);
+ }
+ else if (grid->getType() & GridBase::TypeVec3) {
+ fnAdvectSemiLagrange< Grid<Vec3> >(flags->getParent(), *flags, *vel, *((Grid<Vec3>*) grid), order, strength, orderSpace, clampMode, orderTrace);
+ }
+ else
+ errMsg("AdvectSemiLagrange: Grid Type is not supported (only Real, Vec3, MAC, Levelset)");
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "advectSemiLagrange" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid* flags = _args.getPtr<FlagGrid >("flags",0,&_lock); const MACGrid* vel = _args.getPtr<MACGrid >("vel",1,&_lock); GridBase* grid = _args.getPtr<GridBase >("grid",2,&_lock); int order = _args.getOpt<int >("order",3,1,&_lock); Real strength = _args.getOpt<Real >("strength",4,1.0,&_lock); int orderSpace = _args.getOpt<int >("orderSpace",5,1,&_lock); bool openBounds = _args.getOpt<bool >("openBounds",6,false,&_lock); int boundaryWidth = _args.getOpt<int >("boundaryWidth",7,-1,&_lock); int clampMode = _args.getOpt<int >("clampMode",8,2,&_lock); int orderTrace = _args.getOpt<int >("orderTrace",9,1,&_lock); _retval = getPyNone(); advectSemiLagrange(flags,vel,grid,order,strength,orderSpace,openBounds,boundaryWidth,clampMode,orderTrace); _args.check(); }
+ pbFinalizePlugin(parent,"advectSemiLagrange", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("advectSemiLagrange",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_advectSemiLagrange ("","advectSemiLagrange",_W_1);
+extern "C" {
+ void PbRegister_advectSemiLagrange() {
+ KEEP_UNUSED(_RP_advectSemiLagrange); }
+ }
+
+
+
+} // end namespace DDF
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/apic.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/apic.cpp
new file mode 100644
index 00000000000..bd728bf9348
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/apic.cpp
@@ -0,0 +1,274 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+// ----------------------------------------------------------------------------
+//
+// MantaFlow fluid solver framework
+// Copyright 2016-2017 Kiwon Um, Nils Thuerey
+//
+// This program is free software, distributed under the terms of the
+// Apache License, Version 2.0
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Affine Particle-In-Cell
+//
+// ----------------------------------------------------------------------------
+
+#include "particle.h"
+#include "grid.h"
+
+namespace Manta {
+
+
+
+
+
+
+ struct knApicMapLinearVec3ToMACGrid : public KernelBase {
+ knApicMapLinearVec3ToMACGrid( const BasicParticleSystem &p, MACGrid &mg, MACGrid &vg, const ParticleDataImpl<Vec3> &vp, const ParticleDataImpl<Vec3> &cpx, const ParticleDataImpl<Vec3> &cpy, const ParticleDataImpl<Vec3> &cpz, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(p.size()) ,p(p),mg(mg),vg(vg),vp(vp),cpx(cpx),cpy(cpy),cpz(cpz),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem &p, MACGrid &mg, MACGrid &vg, const ParticleDataImpl<Vec3> &vp, const ParticleDataImpl<Vec3> &cpx, const ParticleDataImpl<Vec3> &cpy, const ParticleDataImpl<Vec3> &cpz, const ParticleDataImpl<int> *ptype, const int exclude ) {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ const IndexInt dX[2] = { 0, vg.getStrideX() };
+ const IndexInt dY[2] = { 0, vg.getStrideY() };
+ const IndexInt dZ[2] = { 0, vg.getStrideZ() };
+
+ const Vec3 &pos = p[idx].pos, &vel = vp[idx];
+ const IndexInt fi = static_cast<IndexInt>(pos.x ), fj = static_cast<IndexInt>(pos.y ), fk = static_cast<IndexInt>(pos.z );
+ const IndexInt ci = static_cast<IndexInt>(pos.x-0.5), cj = static_cast<IndexInt>(pos.y-0.5), ck = static_cast<IndexInt>(pos.z-0.5);
+ const Real wfi = clamp(pos.x-fi, Real(0), Real(1)), wfj = clamp(pos.y-fj, Real(0), Real(1)), wfk = clamp(pos.z-fk, Real(0), Real(1));
+ const Real wci = clamp(Real(pos.x-ci-0.5), Real(0), Real(1)), wcj = clamp(Real(pos.y-cj-0.5), Real(0), Real(1)), wck = clamp(Real(pos.z-ck-0.5), Real(0), Real(1));
+ // TODO: check index for safety
+ { // u-face
+ const IndexInt gidx = fi*dX[1] + cj*dY[1] + ck*dZ[1];
+ const Vec3 gpos(fi, cj+0.5, ck+0.5);
+ const Real wi[2] = { Real(1)-wfi, wfi };
+ const Real wj[2] = { Real(1)-wcj, wcj };
+ const Real wk[2] = { Real(1)-wck, wck };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const Real w = wi[i]*wj[j]*wk[k];
+ mg[gidx+dX[i]+dY[j]+dZ[k]].x += w;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].x += w*vel.x;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].x += w*dot(cpx[idx], gpos + Vec3(i, j, k) - pos);
+ }
+ }
+ { // v-face
+ const IndexInt gidx = ci*dX[1] + fj*dY[1] + ck*dZ[1];
+ const Vec3 gpos(ci+0.5, fj, ck+0.5);
+ const Real wi[2] = { Real(1)-wci, wci };
+ const Real wj[2] = { Real(1)-wfj, wfj };
+ const Real wk[2] = { Real(1)-wck, wck };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const Real w = wi[i]*wj[j]*wk[k];
+ mg[gidx+dX[i]+dY[j]+dZ[k]].y += w;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].y += w*vel.y;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].y += w*dot(cpy[idx], gpos + Vec3(i, j, k) - pos);
+ }
+ }
+ if(!vg.is3D()) return;
+ { // w-face
+ const IndexInt gidx = ci*dX[1] + cj*dY[1] + fk*dZ[1];
+ const Vec3 gpos(ci+0.5, cj+0.5, fk);
+ const Real wi[2] = { Real(1)-wci, wci };
+ const Real wj[2] = { Real(1)-wcj, wcj };
+ const Real wk[2] = { Real(1)-wfk, wfk };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const Real w = wi[i]*wj[j]*wk[k];
+ mg[gidx+dX[i]+dY[j]+dZ[k]].z += w;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].z += w*vel.z;
+ vg[gidx+dX[i]+dY[j]+dZ[k]].z += w*dot(cpz[idx], gpos + Vec3(i, j, k) - pos);
+ }
+ }
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline MACGrid& getArg1() {
+ return mg; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return vg; }
+ typedef MACGrid type2;inline const ParticleDataImpl<Vec3> & getArg3() {
+ return vp; }
+ typedef ParticleDataImpl<Vec3> type3;inline const ParticleDataImpl<Vec3> & getArg4() {
+ return cpx; }
+ typedef ParticleDataImpl<Vec3> type4;inline const ParticleDataImpl<Vec3> & getArg5() {
+ return cpy; }
+ typedef ParticleDataImpl<Vec3> type5;inline const ParticleDataImpl<Vec3> & getArg6() {
+ return cpz; }
+ typedef ParticleDataImpl<Vec3> type6;inline const ParticleDataImpl<int> * getArg7() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type7;inline const int& getArg8() {
+ return exclude; }
+ typedef int type8; void runMessage() { debMsg("Executing kernel knApicMapLinearVec3ToMACGrid ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size; for (IndexInt i = 0; i < _sz; i++) op(i, p,mg,vg,vp,cpx,cpy,cpz,ptype,exclude); }
+ const BasicParticleSystem& p; MACGrid& mg; MACGrid& vg; const ParticleDataImpl<Vec3> & vp; const ParticleDataImpl<Vec3> & cpx; const ParticleDataImpl<Vec3> & cpy; const ParticleDataImpl<Vec3> & cpz; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+
+
+
+
+
+
+
+void apicMapPartsToMAC( const FlagGrid &flags, MACGrid &vel, const BasicParticleSystem &parts, const ParticleDataImpl<Vec3> &partVel, const ParticleDataImpl<Vec3> &cpx, const ParticleDataImpl<Vec3> &cpy, const ParticleDataImpl<Vec3> &cpz, MACGrid *mass=NULL, const ParticleDataImpl<int> *ptype=NULL, const int exclude=0) {
+ // affine map
+ // let's assume that the particle mass is constant, 1.0
+ const bool freeMass = !mass;
+ if(!mass) mass = new MACGrid(flags.getParent());
+ else mass->clear();
+
+ vel.clear();
+ knApicMapLinearVec3ToMACGrid(parts, *mass, vel, partVel, cpx, cpy, cpz, ptype, exclude);
+ mass->stomp(VECTOR_EPSILON);
+ vel.safeDivide(*mass);
+
+ if(freeMass) delete mass;
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "apicMapPartsToMAC" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); const ParticleDataImpl<Vec3> & partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",3,&_lock); const ParticleDataImpl<Vec3> & cpx = *_args.getPtr<ParticleDataImpl<Vec3> >("cpx",4,&_lock); const ParticleDataImpl<Vec3> & cpy = *_args.getPtr<ParticleDataImpl<Vec3> >("cpy",5,&_lock); const ParticleDataImpl<Vec3> & cpz = *_args.getPtr<ParticleDataImpl<Vec3> >("cpz",6,&_lock); MACGrid* mass = _args.getPtrOpt<MACGrid >("mass",7,NULL,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",8,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",9,0,&_lock); _retval = getPyNone(); apicMapPartsToMAC(flags,vel,parts,partVel,cpx,cpy,cpz,mass,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"apicMapPartsToMAC", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("apicMapPartsToMAC",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_apicMapPartsToMAC ("","apicMapPartsToMAC",_W_0);
+extern "C" {
+ void PbRegister_apicMapPartsToMAC() {
+ KEEP_UNUSED(_RP_apicMapPartsToMAC); }
+ }
+
+
+
+
+
+
+
+
+ struct knApicMapLinearMACGridToVec3 : public KernelBase {
+ knApicMapLinearMACGridToVec3( ParticleDataImpl<Vec3> &vp, ParticleDataImpl<Vec3> &cpx, ParticleDataImpl<Vec3> &cpy, ParticleDataImpl<Vec3> &cpz, const BasicParticleSystem &p, const MACGrid &vg, const FlagGrid &flags, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(vp.size()) ,vp(vp),cpx(cpx),cpy(cpy),cpz(cpz),p(p),vg(vg),flags(flags),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<Vec3> &vp, ParticleDataImpl<Vec3> &cpx, ParticleDataImpl<Vec3> &cpy, ParticleDataImpl<Vec3> &cpz, const BasicParticleSystem &p, const MACGrid &vg, const FlagGrid &flags, const ParticleDataImpl<int> *ptype, const int exclude ) const {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+
+ vp[idx] = cpx[idx] = cpy[idx] = cpz[idx] = Vec3(Real(0));
+ const IndexInt dX[2] = {0, vg.getStrideX()}, dY[2] = {0, vg.getStrideY()}, dZ[2] = {0, vg.getStrideZ()};
+ const Real gw[2] = {-Real(1), Real(1)};
+
+ const Vec3 &pos = p[idx].pos;
+ const IndexInt fi = static_cast<IndexInt>(pos.x ), fj = static_cast<IndexInt>(pos.y ), fk = static_cast<IndexInt>(pos.z );
+ const IndexInt ci = static_cast<IndexInt>(pos.x-0.5), cj = static_cast<IndexInt>(pos.y-0.5), ck = static_cast<IndexInt>(pos.z-0.5);
+ const Real wfi = clamp(pos.x-fi, Real(0), Real(1)), wfj = clamp(pos.y-fj, Real(0), Real(1)), wfk = clamp(pos.z-fk, Real(0), Real(1));
+ const Real wci = clamp(Real(pos.x-ci-0.5), Real(0), Real(1)), wcj = clamp(Real(pos.y-cj-0.5), Real(0), Real(1)), wck = clamp(Real(pos.z-ck-0.5), Real(0), Real(1));
+ // TODO: check index for safety
+ { // u
+ const IndexInt gidx = fi*dX[1] + cj*dY[1] + ck*dZ[1];
+ const Real wx[2] = { Real(1)-wfi, wfi };
+ const Real wy[2] = { Real(1)-wcj, wcj };
+ const Real wz[2] = { Real(1)-wck, wck };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const IndexInt vidx = gidx+dX[i]+dY[j]+dZ[k];
+ Real vgx = vg[vidx].x;
+ vp[idx].x += wx[i]*wy[j]*wz[k]*vgx;
+ cpx[idx].x += gw[i]*wy[j]*wz[k]*vgx;
+ cpx[idx].y += wx[i]*gw[j]*wz[k]*vgx;
+ cpx[idx].z += wx[i]*wy[j]*gw[k]*vgx;
+ }
+ }
+ { // v
+ const IndexInt gidx = ci*dX[1] + fj*dY[1] + ck*dZ[1];
+ const Real wx[2] = { Real(1)-wci, wci };
+ const Real wy[2] = { Real(1)-wfj, wfj };
+ const Real wz[2] = { Real(1)-wck, wck };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const IndexInt vidx = gidx+dX[i]+dY[j]+dZ[k];
+ Real vgy = vg[vidx].y;
+ vp[idx].y += wx[i]*wy[j]*wz[k]*vgy;
+ cpy[idx].x += gw[i]*wy[j]*wz[k]*vgy;
+ cpy[idx].y += wx[i]*gw[j]*wz[k]*vgy;
+ cpy[idx].z += wx[i]*wy[j]*gw[k]*vgy;
+ }
+ }
+ if(!vg.is3D()) return;
+ { // w
+ const IndexInt gidx = ci*dX[1] + cj*dY[1] + fk*dZ[1];
+ const Real wx[2] = { Real(1)-wci, wci };
+ const Real wy[2] = { Real(1)-wcj, wcj };
+ const Real wz[2] = { Real(1)-wfk, wfk };
+ for(int i=0; i<2; ++i)
+ for(int j=0; j<2; ++j)
+ for(int k=0; k<2; ++k) {
+ const IndexInt vidx = gidx+dX[i]+dY[j]+dZ[k];
+ Real vgz = vg[vidx].z;
+ vp[idx].z += wx[i]*wy[j]*wz[k]*vgz;
+ cpz[idx].x += gw[i]*wy[j]*wz[k]*vgz;
+ cpz[idx].y += wx[i]*gw[j]*wz[k]*vgz;
+ cpz[idx].z += wx[i]*wy[j]*gw[k]*vgz;
+ }
+ }
+} inline ParticleDataImpl<Vec3> & getArg0() {
+ return vp; }
+ typedef ParticleDataImpl<Vec3> type0;inline ParticleDataImpl<Vec3> & getArg1() {
+ return cpx; }
+ typedef ParticleDataImpl<Vec3> type1;inline ParticleDataImpl<Vec3> & getArg2() {
+ return cpy; }
+ typedef ParticleDataImpl<Vec3> type2;inline ParticleDataImpl<Vec3> & getArg3() {
+ return cpz; }
+ typedef ParticleDataImpl<Vec3> type3;inline const BasicParticleSystem& getArg4() {
+ return p; }
+ typedef BasicParticleSystem type4;inline const MACGrid& getArg5() {
+ return vg; }
+ typedef MACGrid type5;inline const FlagGrid& getArg6() {
+ return flags; }
+ typedef FlagGrid type6;inline const ParticleDataImpl<int> * getArg7() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type7;inline const int& getArg8() {
+ return exclude; }
+ typedef int type8; void runMessage() { debMsg("Executing kernel knApicMapLinearMACGridToVec3 ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, vp,cpx,cpy,cpz,p,vg,flags,ptype,exclude); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<Vec3> & vp; ParticleDataImpl<Vec3> & cpx; ParticleDataImpl<Vec3> & cpy; ParticleDataImpl<Vec3> & cpz; const BasicParticleSystem& p; const MACGrid& vg; const FlagGrid& flags; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+
+
+
+
+
+
+void apicMapMACGridToParts( ParticleDataImpl<Vec3> &partVel, ParticleDataImpl<Vec3> &cpx, ParticleDataImpl<Vec3> &cpy, ParticleDataImpl<Vec3> &cpz, const BasicParticleSystem &parts, const MACGrid &vel, const FlagGrid &flags, const ParticleDataImpl<int> *ptype=NULL, const int exclude=0) {
+ knApicMapLinearMACGridToVec3(partVel, cpx, cpy, cpz, parts, vel, flags, ptype, exclude);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "apicMapMACGridToParts" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; ParticleDataImpl<Vec3> & partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",0,&_lock); ParticleDataImpl<Vec3> & cpx = *_args.getPtr<ParticleDataImpl<Vec3> >("cpx",1,&_lock); ParticleDataImpl<Vec3> & cpy = *_args.getPtr<ParticleDataImpl<Vec3> >("cpy",2,&_lock); ParticleDataImpl<Vec3> & cpz = *_args.getPtr<ParticleDataImpl<Vec3> >("cpz",3,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",4,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",5,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",6,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",7,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",8,0,&_lock); _retval = getPyNone(); apicMapMACGridToParts(partVel,cpx,cpy,cpz,parts,vel,flags,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"apicMapMACGridToParts", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("apicMapMACGridToParts",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_apicMapMACGridToParts ("","apicMapMACGridToParts",_W_1);
+extern "C" {
+ void PbRegister_apicMapMACGridToParts() {
+ KEEP_UNUSED(_RP_apicMapMACGridToParts); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/extforces.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/extforces.cpp
new file mode 100644
index 00000000000..981be01601d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/extforces.cpp
@@ -0,0 +1,775 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * Set boundary conditions, gravity
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "commonkernels.h"
+#include "particle.h"
+
+using namespace std;
+
+namespace Manta {
+
+//! add constant force between fl/fl and fl/em cells
+ struct KnApplyForceField : public KernelBase {
+ KnApplyForceField(const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force, const Grid<Real>* include, bool additive, bool isMAC) : KernelBase(&flags,1) ,flags(flags),vel(vel),force(force),include(include),additive(additive),isMAC(isMAC) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force, const Grid<Real>* include, bool additive, bool isMAC ) const {
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curEmpty = flags.isEmpty(i,j,k);
+ if (!curFluid && !curEmpty) return;
+ if (include && ((*include)(i,j,k) > 0.)) return;
+
+ Real forceX = (isMAC) ? force(i,j,k).x : 0.5*(force(i-1,j,k).x + force(i,j,k).x);
+ Real forceY = (isMAC) ? force(i,j,k).y : 0.5*(force(i,j-1,k).y + force(i,j,k).y);
+
+ Real forceZ = 0.;
+ if(vel.is3D())
+ forceZ = (isMAC) ? force(i,j,k).z : 0.5*(force(i,j,k-1).z + force(i,j,k).z);
+
+ if (flags.isFluid(i-1,j,k) || (curFluid && flags.isEmpty(i-1,j,k)))
+ vel(i,j,k).x = (additive) ? vel(i,j,k).x+forceX : forceX;
+ if (flags.isFluid(i,j-1,k) || (curFluid && flags.isEmpty(i,j-1,k)))
+ vel(i,j,k).y = (additive) ? vel(i,j,k).y+forceY : forceY;
+ if (vel.is3D() && (flags.isFluid(i,j,k-1) || (curFluid && flags.isEmpty(i,j,k-1))))
+ vel(i,j,k).z = (additive) ? vel(i,j,k).z+forceZ : forceZ;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const Grid<Vec3>& getArg2() {
+ return force; }
+ typedef Grid<Vec3> type2;inline const Grid<Real>* getArg3() {
+ return include; }
+ typedef Grid<Real> type3;inline bool& getArg4() {
+ return additive; }
+ typedef bool type4;inline bool& getArg5() {
+ return isMAC; }
+ typedef bool type5; void runMessage() { debMsg("Executing kernel KnApplyForceField ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,force,include,additive,isMAC); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,force,include,additive,isMAC); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; MACGrid& vel; const Grid<Vec3>& force; const Grid<Real>* include; bool additive; bool isMAC; }
+;
+
+//! add constant force between fl/fl and fl/em cells
+ struct KnApplyForce : public KernelBase {
+ KnApplyForce(const FlagGrid& flags, MACGrid& vel, Vec3 force, const Grid<Real>* exclude, bool additive) : KernelBase(&flags,1) ,flags(flags),vel(vel),force(force),exclude(exclude),additive(additive) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, MACGrid& vel, Vec3 force, const Grid<Real>* exclude, bool additive ) const {
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curEmpty = flags.isEmpty(i,j,k);
+ if (!curFluid && !curEmpty) return;
+ if (exclude && ((*exclude)(i,j,k) < 0.)) return;
+
+ if (flags.isFluid(i-1,j,k) || (curFluid && flags.isEmpty(i-1,j,k)))
+ vel(i,j,k).x = (additive) ? vel(i,j,k).x+force.x : force.x;
+ if (flags.isFluid(i,j-1,k) || (curFluid && flags.isEmpty(i,j-1,k)))
+ vel(i,j,k).y = (additive) ? vel(i,j,k).y+force.y : force.y;
+ if (vel.is3D() && (flags.isFluid(i,j,k-1) || (curFluid && flags.isEmpty(i,j,k-1))))
+ vel(i,j,k).z = (additive) ? vel(i,j,k).z+force.z : force.z;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline Vec3& getArg2() {
+ return force; }
+ typedef Vec3 type2;inline const Grid<Real>* getArg3() {
+ return exclude; }
+ typedef Grid<Real> type3;inline bool& getArg4() {
+ return additive; }
+ typedef bool type4; void runMessage() { debMsg("Executing kernel KnApplyForce ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,force,exclude,additive); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,force,exclude,additive); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; MACGrid& vel; Vec3 force; const Grid<Real>* exclude; bool additive; }
+;
+
+//! add gravity forces to all fluid cells, automatically adapts to different grid sizes
+void addGravity(const FlagGrid& flags, MACGrid& vel, Vec3 gravity, const Grid<Real>* exclude=NULL) {
+ Vec3 f = gravity * flags.getParent()->getDt() / flags.getDx();
+ KnApplyForce(flags, vel, f, exclude, true);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addGravity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); Vec3 gravity = _args.get<Vec3 >("gravity",2,&_lock); const Grid<Real>* exclude = _args.getPtrOpt<Grid<Real> >("exclude",3,NULL,&_lock); _retval = getPyNone(); addGravity(flags,vel,gravity,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"addGravity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addGravity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addGravity ("","addGravity",_W_0);
+extern "C" {
+ void PbRegister_addGravity() {
+ KEEP_UNUSED(_RP_addGravity); }
+ }
+
+
+//! add gravity forces to all fluid cells , but dont account for changing cell size
+void addGravityNoScale(const FlagGrid& flags, MACGrid& vel, const Vec3& gravity, const Grid<Real>* exclude=NULL) {
+ const Vec3 f = gravity * flags.getParent()->getDt();
+ KnApplyForce(flags, vel, f, exclude, true);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addGravityNoScale" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Vec3& gravity = _args.get<Vec3 >("gravity",2,&_lock); const Grid<Real>* exclude = _args.getPtrOpt<Grid<Real> >("exclude",3,NULL,&_lock); _retval = getPyNone(); addGravityNoScale(flags,vel,gravity,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"addGravityNoScale", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addGravityNoScale",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addGravityNoScale ("","addGravityNoScale",_W_1);
+extern "C" {
+ void PbRegister_addGravityNoScale() {
+ KEEP_UNUSED(_RP_addGravityNoScale); }
+ }
+
+
+
+//! kernel to add Buoyancy force
+ struct KnAddBuoyancy : public KernelBase {
+ KnAddBuoyancy(const FlagGrid& flags, const Grid<Real>& factor, MACGrid& vel, Vec3 strength) : KernelBase(&flags,1) ,flags(flags),factor(factor),vel(vel),strength(strength) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const Grid<Real>& factor, MACGrid& vel, Vec3 strength ) const {
+ if (!flags.isFluid(i,j,k)) return;
+ if (flags.isFluid(i-1,j,k))
+ vel(i,j,k).x += (0.5 * strength.x) * (factor(i,j,k)+factor(i-1,j,k));
+ if (flags.isFluid(i,j-1,k))
+ vel(i,j,k).y += (0.5 * strength.y) * (factor(i,j,k)+factor(i,j-1,k));
+ if (vel.is3D() && flags.isFluid(i,j,k-1))
+ vel(i,j,k).z += (0.5 * strength.z) * (factor(i,j,k)+factor(i,j,k-1));
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const Grid<Real>& getArg1() {
+ return factor; }
+ typedef Grid<Real> type1;inline MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline Vec3& getArg3() {
+ return strength; }
+ typedef Vec3 type3; void runMessage() { debMsg("Executing kernel KnAddBuoyancy ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,factor,vel,strength); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,factor,vel,strength); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; const Grid<Real>& factor; MACGrid& vel; Vec3 strength; }
+;
+
+//! add Buoyancy force based on fctor (e.g. smoke density)
+void addBuoyancy(const FlagGrid& flags, const Grid<Real>& density, MACGrid& vel, Vec3 gravity, Real coefficient=1.) {
+ Vec3 f = -gravity * flags.getParent()->getDt() / flags.getParent()->getDx() * coefficient;
+ KnAddBuoyancy(flags,density, vel, f);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addBuoyancy" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",2,&_lock); Vec3 gravity = _args.get<Vec3 >("gravity",3,&_lock); Real coefficient = _args.getOpt<Real >("coefficient",4,1.,&_lock); _retval = getPyNone(); addBuoyancy(flags,density,vel,gravity,coefficient); _args.check(); }
+ pbFinalizePlugin(parent,"addBuoyancy", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addBuoyancy",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addBuoyancy ("","addBuoyancy",_W_2);
+extern "C" {
+ void PbRegister_addBuoyancy() {
+ KEEP_UNUSED(_RP_addBuoyancy); }
+ }
+
+
+
+// inflow / outflow boundaries
+
+//! helper to parse openbounds string [xXyYzZ] , convert to vec3
+inline void convertDescToVec(const string& desc, Vector3D<bool>& lo, Vector3D<bool>& up) {
+ for (size_t i = 0; i<desc.size(); i++) {
+ if (desc[i] == 'x') lo.x = true;
+ else if (desc[i] == 'y') lo.y = true;
+ else if (desc[i] == 'z') lo.z = true;
+ else if (desc[i] == 'X') up.x = true;
+ else if (desc[i] == 'Y') up.y = true;
+ else if (desc[i] == 'Z') up.z = true;
+ else errMsg("invalid character in boundary description string. Only [xyzXYZ] allowed.");
+ }
+}
+
+//! add empty and outflow flag to cells of open boundaries
+void setOpenBound(FlagGrid& flags, int bWidth, string openBound = "", int type = FlagGrid::TypeOutflow | FlagGrid::TypeEmpty){
+ if (openBound == "") return;
+ Vector3D<bool> lo, up;
+ convertDescToVec(openBound, lo, up);
+
+ FOR_IJK(flags){
+ bool loX = lo.x && i <= bWidth; // a cell which belongs to the lower x open bound
+ bool loY = lo.y && j <= bWidth;
+ bool upX = up.x && i >= flags.getSizeX() - bWidth - 1; // a cell which belongs to the upper x open bound
+ bool upY = up.y && j >= flags.getSizeY() - bWidth - 1;
+ bool innerI = i>bWidth && i<flags.getSizeX() - bWidth - 1; // a cell which does not belong to the lower or upper x bound
+ bool innerJ = j>bWidth && j<flags.getSizeY() - bWidth - 1;
+
+ // when setting boundaries to open: don't set shared part of wall to empty if neighboring wall is not open
+ if ( (!flags.is3D()) && (loX||upX||loY||upY)){
+ if ((loX || upX || innerI) && (loY || upY || innerJ) && flags.isObstacle(i, j, k)) flags(i, j, k) = type;
+ } else {
+ bool loZ = lo.z && k <= bWidth; // a cell which belongs to the lower z open bound
+ bool upZ = up.z && k >= flags.getSizeZ() - bWidth - 1; // a cell which belongs to the upper z open bound
+ bool innerK = k>bWidth && k<flags.getSizeZ() - bWidth - 1; // a cell which does not belong to the lower or upper z bound
+ if (loX || upX || loY || upY || loZ || upZ) {
+ if ((loX || upX || innerI) && (loY || upY || innerJ) && (loZ || upZ || innerK) && flags.isObstacle(i, j, k)) flags(i, j, k) = type;
+ }
+ }
+ }
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setOpenBound" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); int bWidth = _args.get<int >("bWidth",1,&_lock); string openBound = _args.getOpt<string >("openBound",2,"",&_lock); int type = _args.getOpt<int >("type",3,FlagGrid::TypeOutflow | FlagGrid::TypeEmpty,&_lock); _retval = getPyNone(); setOpenBound(flags,bWidth,openBound,type); _args.check(); }
+ pbFinalizePlugin(parent,"setOpenBound", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setOpenBound",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setOpenBound ("","setOpenBound",_W_3);
+extern "C" {
+ void PbRegister_setOpenBound() {
+ KEEP_UNUSED(_RP_setOpenBound); }
+ }
+
+
+
+//! delete fluid and ensure empty flag in outflow cells, delete particles and density and set phi to 0.5
+void resetOutflow(FlagGrid& flags, Grid<Real>* phi = 0, BasicParticleSystem* parts = 0, Grid<Real>* real = 0, Grid<int>* index = 0, ParticleIndexSystem* indexSys = 0){
+ // check if phi and parts -> pindex and gpi already created -> access particles from cell index, avoid extra looping over particles
+ if (parts && (!index || !indexSys)){
+ if (phi) debMsg("resetOpenBound for phi and particles, but missing index and indexSys for enhanced particle access!",1);
+ for (int idx = 0; idx < (int)parts->size(); idx++)
+ if (parts->isActive(idx) && flags.isInBounds(parts->getPos(idx)) && flags.isOutflow(parts->getPos(idx))) parts->kill(idx);
+ }
+ FOR_IJK(flags){
+ if (flags.isOutflow(i,j,k)){
+ flags(i, j, k) = (flags(i, j, k) | FlagGrid::TypeEmpty) & ~FlagGrid::TypeFluid; // make sure there is not fluid flag set and to reset the empty flag
+ // the particles in a cell i,j,k are particles[index(i,j,k)] to particles[index(i+1,j,k)-1]
+ if (parts && index && indexSys){
+ int isysIdxS = index->index(i, j, k);
+ int pStart = (*index)(isysIdxS), pEnd = 0;
+ if (flags.isInBounds(isysIdxS + 1)) pEnd = (*index)(isysIdxS + 1);
+ else pEnd = indexSys->size();
+ // now loop over particles in cell
+ for (int p = pStart; p<pEnd; ++p) {
+ int psrc = (*indexSys)[p].sourceIndex;
+ if (parts->isActive(psrc) && flags.isInBounds(parts->getPos(psrc))) parts->kill(psrc);
+ }
+ }
+ if (phi) (*phi)(i, j, k) = 0.5;
+ if (real) (*real)(i, j, k) = 0;
+ }
+ }
+ if (parts) parts->doCompress();
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "resetOutflow" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",1,0,&_lock); BasicParticleSystem* parts = _args.getPtrOpt<BasicParticleSystem >("parts",2,0,&_lock); Grid<Real>* real = _args.getPtrOpt<Grid<Real> >("real",3,0,&_lock); Grid<int>* index = _args.getPtrOpt<Grid<int> >("index",4,0,&_lock); ParticleIndexSystem* indexSys = _args.getPtrOpt<ParticleIndexSystem >("indexSys",5,0,&_lock); _retval = getPyNone(); resetOutflow(flags,phi,parts,real,index,indexSys); _args.check(); }
+ pbFinalizePlugin(parent,"resetOutflow", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("resetOutflow",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_resetOutflow ("","resetOutflow",_W_4);
+extern "C" {
+ void PbRegister_resetOutflow() {
+ KEEP_UNUSED(_RP_resetOutflow); }
+ }
+
+
+
+//! enforce a constant inflow/outflow at the grid boundaries
+ struct KnSetInflow : public KernelBase {
+ KnSetInflow(MACGrid& vel, int dim, int p0, const Vec3& val) : KernelBase(&vel,0) ,vel(vel),dim(dim),p0(p0),val(val) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& vel, int dim, int p0, const Vec3& val ) const {
+ Vec3i p(i,j,k);
+ if (p[dim] == p0 || p[dim] == p0+1)
+ vel(i,j,k) = val;
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline int& getArg1() {
+ return dim; }
+ typedef int type1;inline int& getArg2() {
+ return p0; }
+ typedef int type2;inline const Vec3& getArg3() {
+ return val; }
+ typedef Vec3 type3; void runMessage() { debMsg("Executing kernel KnSetInflow ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,vel,dim,p0,val); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,vel,dim,p0,val); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ MACGrid& vel; int dim; int p0; const Vec3& val; }
+;
+
+//! enforce a constant inflow/outflow at the grid boundaries
+void setInflowBcs(MACGrid& vel, string dir, Vec3 value) {
+ for(size_t i=0; i<dir.size(); i++) {
+ if (dir[i] >= 'x' && dir[i] <= 'z') {
+ int dim = dir[i]-'x';
+ KnSetInflow(vel,dim,0,value);
+ } else if (dir[i] >= 'X' && dir[i] <= 'Z') {
+ int dim = dir[i]-'X';
+ KnSetInflow(vel,dim,vel.getSize()[dim]-1,value);
+ } else
+ errMsg("invalid character in direction string. Only [xyzXYZ] allowed.");
+ }
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setInflowBcs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); string dir = _args.get<string >("dir",1,&_lock); Vec3 value = _args.get<Vec3 >("value",2,&_lock); _retval = getPyNone(); setInflowBcs(vel,dir,value); _args.check(); }
+ pbFinalizePlugin(parent,"setInflowBcs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setInflowBcs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setInflowBcs ("","setInflowBcs",_W_5);
+extern "C" {
+ void PbRegister_setInflowBcs() {
+ KEEP_UNUSED(_RP_setInflowBcs); }
+ }
+
+
+
+// set obstacle boundary conditions
+
+//! set no-stick wall boundary condition between ob/fl and ob/ob cells
+ struct KnSetWallBcs : public KernelBase {
+ KnSetWallBcs(const FlagGrid& flags, MACGrid& vel, const MACGrid* obvel) : KernelBase(&flags,0) ,flags(flags),vel(vel),obvel(obvel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, MACGrid& vel, const MACGrid* obvel ) const {
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curObs = flags.isObstacle(i,j,k);
+ Vec3 bcsVel(0.,0.,0.);
+ if (!curFluid && !curObs) return;
+
+ if (obvel) {
+ bcsVel.x = (*obvel)(i,j,k).x;
+ bcsVel.y = (*obvel)(i,j,k).y;
+ if((*obvel).is3D()) bcsVel.z = (*obvel)(i,j,k).z;
+ }
+
+ // we use i>0 instead of bnd=1 to check outer wall
+ if (i>0 && flags.isObstacle(i-1,j,k)) vel(i,j,k).x = bcsVel.x;
+ if (i>0 && curObs && flags.isFluid(i-1,j,k)) vel(i,j,k).x = bcsVel.x;
+ if (j>0 && flags.isObstacle(i,j-1,k)) vel(i,j,k).y = bcsVel.y;
+ if (j>0 && curObs && flags.isFluid(i,j-1,k)) vel(i,j,k).y = bcsVel.y;
+
+ if(!vel.is3D()) { vel(i,j,k).z = 0; } else {
+ if (k>0 && flags.isObstacle(i,j,k-1)) vel(i,j,k).z = bcsVel.z;
+ if (k>0 && curObs && flags.isFluid(i,j,k-1)) vel(i,j,k).z = bcsVel.z; }
+
+ if (curFluid) {
+ if ((i>0 && flags.isStick(i-1,j,k)) || (i<flags.getSizeX()-1 && flags.isStick(i+1,j,k)))
+ vel(i,j,k).y = vel(i,j,k).z = 0;
+ if ((j>0 && flags.isStick(i,j-1,k)) || (j<flags.getSizeY()-1 && flags.isStick(i,j+1,k)))
+ vel(i,j,k).x = vel(i,j,k).z = 0;
+ if (vel.is3D() && ((k>0 && flags.isStick(i,j,k-1)) || (k<flags.getSizeZ()-1 && flags.isStick(i,j,k+1))))
+ vel(i,j,k).x = vel(i,j,k).y = 0;
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const MACGrid* getArg2() {
+ return obvel; }
+ typedef MACGrid type2; void runMessage() { debMsg("Executing kernel KnSetWallBcs ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,vel,obvel); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,vel,obvel); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; MACGrid& vel; const MACGrid* obvel; }
+;
+
+//! set wall BCs for fill fraction mode, note - only needs obstacle SDF
+
+ struct KnSetWallBcsFrac : public KernelBase {
+ KnSetWallBcsFrac(const FlagGrid& flags, const MACGrid& vel, MACGrid& velTarget, const MACGrid* obvel, const Grid<Real>* phiObs, const int &boundaryWidth=0) : KernelBase(&flags,0) ,flags(flags),vel(vel),velTarget(velTarget),obvel(obvel),phiObs(phiObs),boundaryWidth(boundaryWidth) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, MACGrid& velTarget, const MACGrid* obvel, const Grid<Real>* phiObs, const int &boundaryWidth=0 ) const {
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curObs = flags.isObstacle(i,j,k);
+ velTarget(i,j,k) = vel(i,j,k);
+ if (!curFluid && !curObs) return;
+
+ // zero normal component in all obstacle regions
+ if(flags.isInBounds(Vec3i(i,j,k),1)) {
+
+ if( curObs | flags.isObstacle(i-1,j,k) ) {
+ Vec3 dphi(0.,0.,0.);
+ const Real tmp1 = (phiObs->get(i,j,k)+phiObs->get(i-1,j,k))*.5;
+ Real tmp2 = (phiObs->get(i,j+1,k)+phiObs->get(i-1,j+1,k))*.5;
+ Real phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i,j-1,k)+phiObs->get(i-1,j-1,k))*.5;
+ Real phi2 = (tmp1+tmp2)*.5;
+
+ dphi.x = phiObs->get(i,j,k)-phiObs->get(i-1,j,k);
+ dphi.y = phi1-phi2;
+
+ if(phiObs->is3D()) {
+ tmp2 = (phiObs->get(i,j,k+1)+phiObs->get(i-1,j,k+1))*.5;
+ phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i,j,k-1)+phiObs->get(i-1,j,k-1))*.5;
+ phi2 = (tmp1+tmp2)*.5;
+ dphi.z = phi1-phi2;
+ }
+
+ normalize(dphi);
+ Vec3 velMAC = vel.getAtMACX(i,j,k);
+ velTarget(i,j,k).x = velMAC.x - dot(dphi, velMAC) * dphi.x;
+ if (obvel) { // TODO (sebbas): TBC
+ Vec3 obvelMAC = (*obvel).getAtMACX(i,j,k);
+ velTarget(i,j,k).x += dot(dphi, obvelMAC) * dphi.x;
+ }
+ }
+
+ if( curObs | flags.isObstacle(i,j-1,k) ) {
+ Vec3 dphi(0.,0.,0.);
+ const Real tmp1 = (phiObs->get(i,j,k)+phiObs->get(i,j-1,k))*.5;
+ Real tmp2 = (phiObs->get(i+1,j,k)+phiObs->get(i+1,j-1,k))*.5;
+ Real phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i-1,j,k)+phiObs->get(i-1,j-1,k))*.5;
+ Real phi2 = (tmp1+tmp2)*.5;
+
+ dphi.x = phi1-phi2;
+ dphi.y = phiObs->get(i,j,k)-phiObs->get(i,j-1,k);
+ if(phiObs->is3D()) {
+ tmp2 = (phiObs->get(i,j,k+1)+phiObs->get(i,j-1,k+1))*.5;
+ phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i,j,k-1)+phiObs->get(i,j-1,k-1))*.5;
+ phi2 = (tmp1+tmp2)*.5;
+ dphi.z = phi1-phi2;
+ }
+
+ normalize(dphi);
+ Vec3 velMAC = vel.getAtMACY(i,j,k);
+ velTarget(i,j,k).y = velMAC.y - dot(dphi, velMAC) * dphi.y;
+ if (obvel) { // TODO (sebbas): TBC
+ Vec3 obvelMAC = (*obvel).getAtMACY(i,j,k);
+ velTarget(i,j,k).y += dot(dphi, obvelMAC) * dphi.y;
+ }
+ }
+
+ if( phiObs->is3D() && (curObs | flags.isObstacle(i,j,k-1)) ) {
+ Vec3 dphi(0.,0.,0.);
+ const Real tmp1 = (phiObs->get(i,j,k)+phiObs->get(i,j,k-1))*.5;
+
+ Real tmp2;
+ tmp2 = (phiObs->get(i+1,j,k)+phiObs->get(i+1,j,k-1))*.5;
+ Real phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i-1,j,k)+phiObs->get(i-1,j,k-1))*.5;
+ Real phi2 = (tmp1+tmp2)*.5;
+ dphi.x = phi1-phi2;
+
+ tmp2 = (phiObs->get(i,j+1,k)+phiObs->get(i,j+1,k-1))*.5;
+ phi1 = (tmp1+tmp2)*.5;
+ tmp2 = (phiObs->get(i,j-1,k)+phiObs->get(i,j-1,k-1))*.5;
+ phi2 = (tmp1+tmp2)*.5;
+ dphi.y = phi1-phi2;
+
+ dphi.z = phiObs->get(i,j,k) - phiObs->get(i,j,k-1);
+
+ normalize(dphi);
+ Vec3 velMAC = vel.getAtMACZ(i,j,k);
+ velTarget(i,j,k).z = velMAC.z - dot(dphi, velMAC) * dphi.z;
+ if (obvel) { // TODO (sebbas): TBC
+ Vec3 obvelMAC = (*obvel).getAtMACZ(i,j,k);
+ velTarget(i,j,k).z += dot(dphi, obvelMAC) * dphi.z;
+ }
+ }
+ } // not at boundary
+
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline MACGrid& getArg2() {
+ return velTarget; }
+ typedef MACGrid type2;inline const MACGrid* getArg3() {
+ return obvel; }
+ typedef MACGrid type3;inline const Grid<Real>* getArg4() {
+ return phiObs; }
+ typedef Grid<Real> type4;inline const int& getArg5() {
+ return boundaryWidth; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnSetWallBcsFrac ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,vel,velTarget,obvel,phiObs,boundaryWidth); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,vel,velTarget,obvel,phiObs,boundaryWidth); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; const MACGrid& vel; MACGrid& velTarget; const MACGrid* obvel; const Grid<Real>* phiObs; const int& boundaryWidth; }
+;
+
+//! set zero normal velocity boundary condition on walls
+// (optionally with second order accuracy using the obstacle SDF , fractions grid currentlyl not needed)
+void setWallBcs(const FlagGrid& flags, MACGrid& vel, const MACGrid* obvel = 0, const MACGrid* fractions = 0, const Grid<Real>* phiObs = 0, int boundaryWidth=0) {
+ if(!phiObs || !fractions) {
+ KnSetWallBcs(flags, vel, obvel);
+ } else {
+ MACGrid tmpvel(vel.getParent());
+ KnSetWallBcsFrac(flags, vel, tmpvel, obvel, phiObs, boundaryWidth);
+ vel.swap(tmpvel);
+ }
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setWallBcs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const MACGrid* obvel = _args.getPtrOpt<MACGrid >("obvel",2,0,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",3,0,&_lock); const Grid<Real>* phiObs = _args.getPtrOpt<Grid<Real> >("phiObs",4,0,&_lock); int boundaryWidth = _args.getOpt<int >("boundaryWidth",5,0,&_lock); _retval = getPyNone(); setWallBcs(flags,vel,obvel,fractions,phiObs,boundaryWidth); _args.check(); }
+ pbFinalizePlugin(parent,"setWallBcs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setWallBcs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setWallBcs ("","setWallBcs",_W_6);
+extern "C" {
+ void PbRegister_setWallBcs() {
+ KEEP_UNUSED(_RP_setWallBcs); }
+ }
+
+
+
+//! add Forces between fl/fl and fl/em cells (interpolate cell centered forces to MAC grid)
+ struct KnAddForceIfLower : public KernelBase {
+ KnAddForceIfLower(const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force) : KernelBase(&flags,1) ,flags(flags),vel(vel),force(force) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force ) const {
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curEmpty = flags.isEmpty(i,j,k);
+ if (!curFluid && !curEmpty) return;
+
+ if (flags.isFluid(i-1,j,k) || (curFluid && flags.isEmpty(i-1,j,k))) {
+ Real forceMACX = 0.5*(force(i-1,j,k).x + force(i,j,k).x);
+ Real min = std::min(vel(i,j,k).x, forceMACX);
+ Real max = std::max(vel(i,j,k).x, forceMACX);
+ Real sum = vel(i,j,k).x + forceMACX;
+ vel(i,j,k).x = (forceMACX > 0) ? std::min(sum, max) : std::max(sum, min);
+ }
+ if (flags.isFluid(i,j-1,k) || (curFluid && flags.isEmpty(i,j-1,k))) {
+ Real forceMACY = 0.5*(force(i,j-1,k).y + force(i,j,k).y);
+ Real min = std::min(vel(i,j,k).y, forceMACY);
+ Real max = std::max(vel(i,j,k).y, forceMACY);
+ Real sum = vel(i,j,k).y + forceMACY;
+ vel(i,j,k).y = (forceMACY > 0) ? std::min(sum, max) : std::max(sum, min);
+ }
+ if (vel.is3D() && (flags.isFluid(i,j,k-1) || (curFluid && flags.isEmpty(i,j,k-1)))) {
+ Real forceMACZ = 0.5*(force(i,j,k-1).z + force(i,j,k).z);
+ Real min = std::min(vel(i,j,k).z, forceMACZ);
+ Real max = std::max(vel(i,j,k).z, forceMACZ);
+ Real sum = vel(i,j,k).z + forceMACZ;
+ vel(i,j,k).z = (forceMACZ > 0) ? std::min(sum, max) : std::max(sum, min);
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const Grid<Vec3>& getArg2() {
+ return force; }
+ typedef Grid<Vec3> type2; void runMessage() { debMsg("Executing kernel KnAddForceIfLower ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,force); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,force); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; MACGrid& vel; const Grid<Vec3>& force; }
+;
+
+// Initial velocity for smoke
+void setInitialVelocity(const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& invel) {
+ KnAddForceIfLower(flags, vel, invel);
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setInitialVelocity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Grid<Vec3>& invel = *_args.getPtr<Grid<Vec3> >("invel",2,&_lock); _retval = getPyNone(); setInitialVelocity(flags,vel,invel); _args.check(); }
+ pbFinalizePlugin(parent,"setInitialVelocity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setInitialVelocity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setInitialVelocity ("","setInitialVelocity",_W_7);
+extern "C" {
+ void PbRegister_setInitialVelocity() {
+ KEEP_UNUSED(_RP_setInitialVelocity); }
+ }
+
+
+
+//! Kernel: gradient norm operator
+ struct KnConfForce : public KernelBase {
+ KnConfForce(Grid<Vec3>& force, const Grid<Real>& grid, const Grid<Vec3>& curl, Real str) : KernelBase(&force,1) ,force(force),grid(grid),curl(curl),str(str) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Vec3>& force, const Grid<Real>& grid, const Grid<Vec3>& curl, Real str ) const {
+ Vec3 grad = 0.5 * Vec3( grid(i+1,j,k)-grid(i-1,j,k),
+ grid(i,j+1,k)-grid(i,j-1,k), 0.);
+ if(grid.is3D()) grad[2]= 0.5*( grid(i,j,k+1)-grid(i,j,k-1) );
+ normalize(grad);
+ force(i,j,k) = str * cross(grad, curl(i,j,k));
+} inline Grid<Vec3>& getArg0() {
+ return force; }
+ typedef Grid<Vec3> type0;inline const Grid<Real>& getArg1() {
+ return grid; }
+ typedef Grid<Real> type1;inline const Grid<Vec3>& getArg2() {
+ return curl; }
+ typedef Grid<Vec3> type2;inline Real& getArg3() {
+ return str; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel KnConfForce ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,force,grid,curl,str); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,force,grid,curl,str); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<Vec3>& force; const Grid<Real>& grid; const Grid<Vec3>& curl; Real str; }
+;
+
+void vorticityConfinement(MACGrid& vel, const FlagGrid& flags, Real strength) {
+ Grid<Vec3> velCenter(flags.getParent()), curl(flags.getParent()), force(flags.getParent());
+ Grid<Real> norm(flags.getParent());
+
+ GetCentered(velCenter, vel);
+ CurlOp(velCenter, curl);
+ GridNorm(norm, curl);
+ KnConfForce(force, norm, curl, strength);
+ KnApplyForceField(flags, vel, force, NULL, true, false);
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "vorticityConfinement" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); Real strength = _args.get<Real >("strength",2,&_lock); _retval = getPyNone(); vorticityConfinement(vel,flags,strength); _args.check(); }
+ pbFinalizePlugin(parent,"vorticityConfinement", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("vorticityConfinement",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_vorticityConfinement ("","vorticityConfinement",_W_8);
+extern "C" {
+ void PbRegister_vorticityConfinement() {
+ KEEP_UNUSED(_RP_vorticityConfinement); }
+ }
+
+
+
+void addForceField(const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force, const Grid<Real>* region=NULL, bool isMAC=false) {
+ KnApplyForceField(flags, vel, force, region, true, isMAC);
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addForceField" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Grid<Vec3>& force = *_args.getPtr<Grid<Vec3> >("force",2,&_lock); const Grid<Real>* region = _args.getPtrOpt<Grid<Real> >("region",3,NULL,&_lock); bool isMAC = _args.getOpt<bool >("isMAC",4,false,&_lock); _retval = getPyNone(); addForceField(flags,vel,force,region,isMAC); _args.check(); }
+ pbFinalizePlugin(parent,"addForceField", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addForceField",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addForceField ("","addForceField",_W_9);
+extern "C" {
+ void PbRegister_addForceField() {
+ KEEP_UNUSED(_RP_addForceField); }
+ }
+
+
+
+void setForceField(const FlagGrid& flags, MACGrid& vel, const Grid<Vec3>& force, const Grid<Real>* region=NULL, bool isMAC=false) {
+ KnApplyForceField(flags, vel, force, region, false, isMAC);
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setForceField" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Grid<Vec3>& force = *_args.getPtr<Grid<Vec3> >("force",2,&_lock); const Grid<Real>* region = _args.getPtrOpt<Grid<Real> >("region",3,NULL,&_lock); bool isMAC = _args.getOpt<bool >("isMAC",4,false,&_lock); _retval = getPyNone(); setForceField(flags,vel,force,region,isMAC); _args.check(); }
+ pbFinalizePlugin(parent,"setForceField", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setForceField",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setForceField ("","setForceField",_W_10);
+extern "C" {
+ void PbRegister_setForceField() {
+ KEEP_UNUSED(_RP_setForceField); }
+ }
+
+
+
+
+
+void dissolveSmoke(const FlagGrid& flags, Grid<Real>& density, Grid<Real>* heat=NULL, Grid<Real>* red=NULL, Grid<Real>* green=NULL, Grid<Real>* blue=NULL, int speed=5, bool logFalloff=true) {
+ float dydx = 1.0f / (float)speed; // max density/speed = dydx
+ float fac = 1.0f - dydx;
+
+ FOR_IJK_BND(density, 0) {
+ bool curFluid = flags.isFluid(i,j,k);
+ if (!curFluid) continue;
+
+ if (logFalloff) {
+ density(i,j,k) *= fac;
+ if (heat) {
+ (*heat)(i,j,k) *= fac;
+ }
+ if (red) {
+ (*red)(i,j,k) *= fac;
+ (*green)(i,j,k) *= fac;
+ (*blue)(i,j,k) *= fac;
+ }
+ }
+ else { // linear falloff
+ float d = density(i,j,k);
+ density(i,j,k) -= dydx;
+ if (density(i,j,k) < 0.0f)
+ density(i,j,k) = 0.0f;
+ if (heat) {
+ if (fabs((*heat)(i,j,k)) < dydx) (*heat)(i,j,k) = 0.0f;
+ else if ((*heat)(i,j,k) > 0.0f) (*heat)(i,j,k) -= dydx;
+ else if ((*heat)(i,j,k) < 0.0f) (*heat)(i,j,k) += dydx;
+ }
+ if (red && notZero(d) ) {
+ (*red)(i,j,k) *= (density(i,j,k)/d);
+ (*green)(i,j,k) *= (density(i,j,k)/d);
+ (*blue)(i,j,k) *= (density(i,j,k)/d);
+ }
+ }
+ }
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "dissolveSmoke" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); Grid<Real>* heat = _args.getPtrOpt<Grid<Real> >("heat",2,NULL,&_lock); Grid<Real>* red = _args.getPtrOpt<Grid<Real> >("red",3,NULL,&_lock); Grid<Real>* green = _args.getPtrOpt<Grid<Real> >("green",4,NULL,&_lock); Grid<Real>* blue = _args.getPtrOpt<Grid<Real> >("blue",5,NULL,&_lock); int speed = _args.getOpt<int >("speed",6,5,&_lock); bool logFalloff = _args.getOpt<bool >("logFalloff",7,true,&_lock); _retval = getPyNone(); dissolveSmoke(flags,density,heat,red,green,blue,speed,logFalloff); _args.check(); }
+ pbFinalizePlugin(parent,"dissolveSmoke", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("dissolveSmoke",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_dissolveSmoke ("","dissolveSmoke",_W_11);
+extern "C" {
+ void PbRegister_dissolveSmoke() {
+ KEEP_UNUSED(_RP_dissolveSmoke); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/fire.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/fire.cpp
new file mode 100644
index 00000000000..c3c96523d9e
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/fire.cpp
@@ -0,0 +1,187 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2016 Sebastian Barschkis, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Fire modeling plugin
+ *
+ ******************************************************************************/
+
+#include "general.h"
+#include "grid.h"
+#include "vectorbase.h"
+
+using namespace std;
+
+namespace Manta {
+
+
+
+
+
+
+ struct KnProcessBurn : public KernelBase {
+ KnProcessBurn(Grid<Real>& fuel, Grid<Real>& density, Grid<Real>& react, Grid<Real>* red, Grid<Real>* green, Grid<Real>* blue, Grid<Real>* heat, Real burningRate, Real flameSmoke, Real ignitionTemp, Real maxTemp, Real dt, Vec3 flameSmokeColor) : KernelBase(&fuel,1) ,fuel(fuel),density(density),react(react),red(red),green(green),blue(blue),heat(heat),burningRate(burningRate),flameSmoke(flameSmoke),ignitionTemp(ignitionTemp),maxTemp(maxTemp),dt(dt),flameSmokeColor(flameSmokeColor) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& fuel, Grid<Real>& density, Grid<Real>& react, Grid<Real>* red, Grid<Real>* green, Grid<Real>* blue, Grid<Real>* heat, Real burningRate, Real flameSmoke, Real ignitionTemp, Real maxTemp, Real dt, Vec3 flameSmokeColor ) const {
+ // Save initial values
+ Real origFuel = fuel(i,j,k);
+ Real origSmoke = density(i,j,k);
+ Real smokeEmit = 0.0f;
+ Real flame = 0.0f;
+
+ // Process fuel
+ fuel(i,j,k) -= burningRate * dt;
+ if (fuel(i,j,k) < 0.0f)
+ fuel(i,j,k) = 0.0f;
+
+ // Process reaction coordinate
+ if (origFuel > VECTOR_EPSILON) {
+ react(i,j,k) *= fuel(i,j,k) / origFuel;
+ flame = pow(react(i,j,k), 0.5f);
+ } else {
+ react(i,j,k) = 0.0f;
+ }
+
+ // Set fluid temperature based on fuel burn rate and "flameSmoke" factor
+ smokeEmit = (origFuel < 1.0f) ? (1.0 - origFuel) * 0.5f : 0.0f;
+ smokeEmit = (smokeEmit + 0.5f) * (origFuel - fuel(i,j,k)) * 0.1f * flameSmoke;
+ density(i,j,k) += smokeEmit;
+ clamp( density(i,j,k), (Real)0.0f, (Real)1.0f);
+
+ // Set fluid temperature from the flame temperature profile
+ if (heat && flame)
+ (*heat)(i,j,k) = (1.0f - flame) * ignitionTemp + flame * maxTemp;
+
+ // Mix new color
+ if (smokeEmit > VECTOR_EPSILON) {
+ float smokeFactor = density(i,j,k) / (origSmoke + smokeEmit);
+ if(red) (*red)(i,j,k) = ((*red)(i,j,k) + flameSmokeColor.x * smokeEmit) * smokeFactor;
+ if(green) (*green)(i,j,k) = ((*green)(i,j,k) + flameSmokeColor.y * smokeEmit) * smokeFactor;
+ if(blue) (*blue)(i,j,k) = ((*blue)(i,j,k) + flameSmokeColor.z * smokeEmit) * smokeFactor;
+ }
+} inline Grid<Real>& getArg0() {
+ return fuel; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return density; }
+ typedef Grid<Real> type1;inline Grid<Real>& getArg2() {
+ return react; }
+ typedef Grid<Real> type2;inline Grid<Real>* getArg3() {
+ return red; }
+ typedef Grid<Real> type3;inline Grid<Real>* getArg4() {
+ return green; }
+ typedef Grid<Real> type4;inline Grid<Real>* getArg5() {
+ return blue; }
+ typedef Grid<Real> type5;inline Grid<Real>* getArg6() {
+ return heat; }
+ typedef Grid<Real> type6;inline Real& getArg7() {
+ return burningRate; }
+ typedef Real type7;inline Real& getArg8() {
+ return flameSmoke; }
+ typedef Real type8;inline Real& getArg9() {
+ return ignitionTemp; }
+ typedef Real type9;inline Real& getArg10() {
+ return maxTemp; }
+ typedef Real type10;inline Real& getArg11() {
+ return dt; }
+ typedef Real type11;inline Vec3& getArg12() {
+ return flameSmokeColor; }
+ typedef Vec3 type12; void runMessage() { debMsg("Executing kernel KnProcessBurn ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,fuel,density,react,red,green,blue,heat,burningRate,flameSmoke,ignitionTemp,maxTemp,dt,flameSmokeColor); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,fuel,density,react,red,green,blue,heat,burningRate,flameSmoke,ignitionTemp,maxTemp,dt,flameSmokeColor); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<Real>& fuel; Grid<Real>& density; Grid<Real>& react; Grid<Real>* red; Grid<Real>* green; Grid<Real>* blue; Grid<Real>* heat; Real burningRate; Real flameSmoke; Real ignitionTemp; Real maxTemp; Real dt; Vec3 flameSmokeColor; }
+;
+
+
+
+
+
+
+void processBurn(Grid<Real>& fuel, Grid<Real>& density, Grid<Real>& react, Grid<Real>* red = NULL, Grid<Real>* green = NULL, Grid<Real>* blue = NULL, Grid<Real>* heat = NULL, Real burningRate = 0.75f, Real flameSmoke = 1.0f, Real ignitionTemp = 1.25f, Real maxTemp = 1.75f, Vec3 flameSmokeColor = Vec3(0.7f, 0.7f, 0.7f)) {
+ Real dt = fuel.getParent()->getDt();
+ KnProcessBurn(fuel, density, react, red, green, blue, heat, burningRate,
+ flameSmoke, ignitionTemp, maxTemp, dt, flameSmokeColor);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "processBurn" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& fuel = *_args.getPtr<Grid<Real> >("fuel",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); Grid<Real>& react = *_args.getPtr<Grid<Real> >("react",2,&_lock); Grid<Real>* red = _args.getPtrOpt<Grid<Real> >("red",3,NULL,&_lock); Grid<Real>* green = _args.getPtrOpt<Grid<Real> >("green",4,NULL,&_lock); Grid<Real>* blue = _args.getPtrOpt<Grid<Real> >("blue",5,NULL,&_lock); Grid<Real>* heat = _args.getPtrOpt<Grid<Real> >("heat",6,NULL,&_lock); Real burningRate = _args.getOpt<Real >("burningRate",7,0.75f,&_lock); Real flameSmoke = _args.getOpt<Real >("flameSmoke",8,1.0f,&_lock); Real ignitionTemp = _args.getOpt<Real >("ignitionTemp",9,1.25f,&_lock); Real maxTemp = _args.getOpt<Real >("maxTemp",10,1.75f,&_lock); Vec3 flameSmokeColor = _args.getOpt<Vec3 >("flameSmokeColor",11,Vec3(0.7f, 0.7f, 0.7f),&_lock); _retval = getPyNone(); processBurn(fuel,density,react,red,green,blue,heat,burningRate,flameSmoke,ignitionTemp,maxTemp,flameSmokeColor); _args.check(); }
+ pbFinalizePlugin(parent,"processBurn", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("processBurn",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_processBurn ("","processBurn",_W_0);
+extern "C" {
+ void PbRegister_processBurn() {
+ KEEP_UNUSED(_RP_processBurn); }
+ }
+
+
+
+
+
+
+ struct KnUpdateFlame : public KernelBase {
+ KnUpdateFlame(const Grid<Real>& react, Grid<Real>& flame) : KernelBase(&react,1) ,react(react),flame(flame) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Real>& react, Grid<Real>& flame ) const {
+ if (react(i,j,k) > 0.0f)
+ flame(i,j,k) = pow(react(i,j,k), 0.5f);
+ else
+ flame(i,j,k) = 0.0f;
+} inline const Grid<Real>& getArg0() {
+ return react; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return flame; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel KnUpdateFlame ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,react,flame); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,react,flame); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const Grid<Real>& react; Grid<Real>& flame; }
+;
+
+
+void updateFlame(const Grid<Real>& react, Grid<Real>& flame) {
+ KnUpdateFlame(react, flame);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "updateFlame" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& react = *_args.getPtr<Grid<Real> >("react",0,&_lock); Grid<Real>& flame = *_args.getPtr<Grid<Real> >("flame",1,&_lock); _retval = getPyNone(); updateFlame(react,flame); _args.check(); }
+ pbFinalizePlugin(parent,"updateFlame", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("updateFlame",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_updateFlame ("","updateFlame",_W_1);
+extern "C" {
+ void PbRegister_updateFlame() {
+ KEEP_UNUSED(_RP_updateFlame); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/flip.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/flip.cpp
new file mode 100644
index 00000000000..ec004b3be1c
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/flip.cpp
@@ -0,0 +1,1344 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * FLIP (fluid implicit particles)
+ * for use with particle data fields
+ *
+ ******************************************************************************/
+
+#include "particle.h"
+#include "grid.h"
+#include "commonkernels.h"
+#include "randomstream.h"
+#include "levelset.h"
+#include "shapes.h"
+#include "matrixbase.h"
+
+using namespace std;
+namespace Manta {
+
+
+
+// init
+
+//! note - this is a simplified version , sampleLevelsetWithParticles has more functionality
+
+
+void sampleFlagsWithParticles(const FlagGrid& flags, BasicParticleSystem& parts, const int discretization, const Real randomness) {
+ const bool is3D = flags.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp (1.0 / discretization, 1.0 / discretization, 1.0/discretization);
+ RandomStream mRand(9832);
+
+ FOR_IJK_BND(flags, 0) {
+ if ( flags.isObstacle(i,j,k) ) continue;
+ if ( flags.isFluid(i,j,k) ) {
+ const Vec3 pos (i,j,k);
+ for (int dk=0; dk<(is3D ? discretization : 1); dk++)
+ for (int dj=0; dj<discretization; dj++)
+ for (int di=0; di<discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5+di, 0.5+dj, 0.5+dk);
+ subpos += jlen * (Vec3(1,1,1) - 2.0 * mRand.getVec3());
+ if(!is3D) subpos[2] = 0.5;
+ parts.addBuffered(subpos);
+ }
+ }
+ }
+ parts.insertBufferedParticles();
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "sampleFlagsWithParticles" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",1,&_lock); const int discretization = _args.get<int >("discretization",2,&_lock); const Real randomness = _args.get<Real >("randomness",3,&_lock); _retval = getPyNone(); sampleFlagsWithParticles(flags,parts,discretization,randomness); _args.check(); }
+ pbFinalizePlugin(parent,"sampleFlagsWithParticles", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("sampleFlagsWithParticles",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_sampleFlagsWithParticles ("","sampleFlagsWithParticles",_W_0);
+extern "C" {
+ void PbRegister_sampleFlagsWithParticles() {
+ KEEP_UNUSED(_RP_sampleFlagsWithParticles); }
+ }
+
+
+
+//! sample a level set with particles, use reset to clear the particle buffer,
+//! and skipEmpty for a continuous inflow (in the latter case, only empty cells will
+//! be re-filled once they empty when calling sampleLevelsetWithParticles during
+//! the main loop).
+
+
+void sampleLevelsetWithParticles(const LevelsetGrid& phi, const FlagGrid& flags, BasicParticleSystem& parts, const int discretization, const Real randomness, const bool reset=false, const bool refillEmpty=false, const int particleFlag=-1) {
+ const bool is3D = phi.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp (1.0 / discretization, 1.0 / discretization, 1.0/discretization);
+ RandomStream mRand(9832);
+
+ if(reset) {
+ parts.clear();
+ parts.doCompress();
+ }
+
+ FOR_IJK_BND(phi, 0) {
+ if ( flags.isObstacle(i,j,k) ) continue;
+ if ( refillEmpty && flags.isFluid(i,j,k) ) continue;
+ if ( phi(i,j,k) < 1.733 ) {
+ const Vec3 pos (i,j,k);
+ for (int dk=0; dk<(is3D ? discretization : 1); dk++)
+ for (int dj=0; dj<discretization; dj++)
+ for (int di=0; di<discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5+di, 0.5+dj, 0.5+dk);
+ subpos += jlen * (Vec3(1,1,1) - 2.0 * mRand.getVec3());
+ if(!is3D) subpos[2] = 0.5;
+ if( phi.getInterpolated(subpos) > 0. ) continue;
+ if(particleFlag < 0){
+ parts.addBuffered(subpos);
+ }
+ else{
+ parts.addBuffered(subpos, particleFlag);
+ }
+ }
+ }
+ }
+
+ parts.insertBufferedParticles();
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "sampleLevelsetWithParticles" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); const int discretization = _args.get<int >("discretization",3,&_lock); const Real randomness = _args.get<Real >("randomness",4,&_lock); const bool reset = _args.getOpt<bool >("reset",5,false,&_lock); const bool refillEmpty = _args.getOpt<bool >("refillEmpty",6,false,&_lock); const int particleFlag = _args.getOpt<int >("particleFlag",7,-1,&_lock); _retval = getPyNone(); sampleLevelsetWithParticles(phi,flags,parts,discretization,randomness,reset,refillEmpty,particleFlag); _args.check(); }
+ pbFinalizePlugin(parent,"sampleLevelsetWithParticles", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("sampleLevelsetWithParticles",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_sampleLevelsetWithParticles ("","sampleLevelsetWithParticles",_W_1);
+extern "C" {
+ void PbRegister_sampleLevelsetWithParticles() {
+ KEEP_UNUSED(_RP_sampleLevelsetWithParticles); }
+ }
+
+
+
+//! sample a shape with particles, use reset to clear the particle buffer,
+//! and skipEmpty for a continuous inflow (in the latter case, only empty cells will
+//! be re-filled once they empty when calling sampleShapeWithParticles during
+//! the main loop).
+
+
+
+void sampleShapeWithParticles(const Shape& shape, const FlagGrid& flags, BasicParticleSystem& parts, const int discretization, const Real randomness, const bool reset=false, const bool refillEmpty=false, const LevelsetGrid *exclude=NULL) {
+ const bool is3D = flags.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp (1.0 / discretization, 1.0 / discretization, 1.0/discretization);
+ RandomStream mRand(9832);
+
+ if(reset) {
+ parts.clear();
+ parts.doCompress();
+ }
+
+ FOR_IJK_BND(flags, 0) {
+ if ( flags.isObstacle(i,j,k) ) continue;
+ if ( refillEmpty && flags.isFluid(i,j,k) ) continue;
+ const Vec3 pos (i,j,k);
+ for (int dk=0; dk<(is3D ? discretization : 1); dk++)
+ for (int dj=0; dj<discretization; dj++)
+ for (int di=0; di<discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5+di, 0.5+dj, 0.5+dk);
+ subpos += jlen * (Vec3(1,1,1) - 2.0 * mRand.getVec3());
+ if(!is3D) subpos[2] = 0.5;
+ if(exclude && exclude->getInterpolated(subpos) <= 0.) continue;
+ if(!shape.isInside(subpos)) continue;
+ parts.addBuffered(subpos);
+ }
+ }
+
+ parts.insertBufferedParticles();
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "sampleShapeWithParticles" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Shape& shape = *_args.getPtr<Shape >("shape",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); const int discretization = _args.get<int >("discretization",3,&_lock); const Real randomness = _args.get<Real >("randomness",4,&_lock); const bool reset = _args.getOpt<bool >("reset",5,false,&_lock); const bool refillEmpty = _args.getOpt<bool >("refillEmpty",6,false,&_lock); const LevelsetGrid* exclude = _args.getPtrOpt<LevelsetGrid >("exclude",7,NULL,&_lock); _retval = getPyNone(); sampleShapeWithParticles(shape,flags,parts,discretization,randomness,reset,refillEmpty,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"sampleShapeWithParticles", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("sampleShapeWithParticles",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_sampleShapeWithParticles ("","sampleShapeWithParticles",_W_2);
+extern "C" {
+ void PbRegister_sampleShapeWithParticles() {
+ KEEP_UNUSED(_RP_sampleShapeWithParticles); }
+ }
+
+
+
+//! mark fluid cells and helpers
+ struct knClearFluidFlags : public KernelBase {
+ knClearFluidFlags(FlagGrid& flags, int dummy=0) : KernelBase(&flags,0) ,flags(flags),dummy(dummy) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, FlagGrid& flags, int dummy=0 ) const {
+ if (flags.isFluid(i,j,k)) {
+ flags(i,j,k) = (flags(i,j,k) | FlagGrid::TypeEmpty) & ~FlagGrid::TypeFluid;
+ }
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline int& getArg1() {
+ return dummy; }
+ typedef int type1; void runMessage() { debMsg("Executing kernel knClearFluidFlags ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,dummy); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,dummy); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ FlagGrid& flags; int dummy; }
+;
+
+ struct knSetNbObstacle : public KernelBase {
+ knSetNbObstacle(FlagGrid& nflags, const FlagGrid& flags, const Grid<Real>& phiObs) : KernelBase(&nflags,1) ,nflags(nflags),flags(flags),phiObs(phiObs) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, FlagGrid& nflags, const FlagGrid& flags, const Grid<Real>& phiObs ) const {
+ if ( phiObs(i,j,k)>0. ) return;
+ if (flags.isEmpty(i,j,k)) {
+ bool set=false;
+ if( (flags.isFluid(i-1,j,k)) && (phiObs(i+1,j,k)<=0.) ) set=true;
+ if( (flags.isFluid(i+1,j,k)) && (phiObs(i-1,j,k)<=0.) ) set=true;
+ if( (flags.isFluid(i,j-1,k)) && (phiObs(i,j+1,k)<=0.) ) set=true;
+ if( (flags.isFluid(i,j+1,k)) && (phiObs(i,j-1,k)<=0.) ) set=true;
+ if(flags.is3D()) {
+ if( (flags.isFluid(i,j,k-1)) && (phiObs(i,j,k+1)<=0.) ) set=true;
+ if( (flags.isFluid(i,j,k+1)) && (phiObs(i,j,k-1)<=0.) ) set=true;
+ }
+ if(set) nflags(i,j,k) = (flags(i,j,k) | FlagGrid::TypeFluid) & ~FlagGrid::TypeEmpty;
+ }
+} inline FlagGrid& getArg0() {
+ return nflags; }
+ typedef FlagGrid type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<Real>& getArg2() {
+ return phiObs; }
+ typedef Grid<Real> type2; void runMessage() { debMsg("Executing kernel knSetNbObstacle ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,nflags,flags,phiObs); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,nflags,flags,phiObs); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ FlagGrid& nflags; const FlagGrid& flags; const Grid<Real>& phiObs; }
+;
+void markFluidCells(const BasicParticleSystem& parts, FlagGrid& flags, const Grid<Real>* phiObs=NULL, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ // remove all fluid cells
+ knClearFluidFlags(flags, 0);
+
+ // mark all particles in flaggrid as fluid
+ for(IndexInt idx=0; idx<parts.size(); idx++) {
+ if (!parts.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) continue;
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if (flags.isInBounds(p) && flags.isEmpty(p))
+ flags(p) = (flags(p) | FlagGrid::TypeFluid) & ~FlagGrid::TypeEmpty;
+ }
+
+ // special for second order obstacle BCs, check empty cells in boundary region
+ if(phiObs) {
+ FlagGrid tmp(flags);
+ knSetNbObstacle(tmp, flags, *phiObs);
+ flags.swap(tmp);
+ }
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "markFluidCells" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const Grid<Real>* phiObs = _args.getPtrOpt<Grid<Real> >("phiObs",2,NULL,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",3,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",4,0,&_lock); _retval = getPyNone(); markFluidCells(parts,flags,phiObs,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"markFluidCells", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("markFluidCells",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_markFluidCells ("","markFluidCells",_W_3);
+extern "C" {
+ void PbRegister_markFluidCells() {
+ KEEP_UNUSED(_RP_markFluidCells); }
+ }
+
+
+
+// for testing purposes only...
+void testInitGridWithPos(Grid<Real>& grid) {
+ FOR_IJK(grid) { grid(i,j,k) = norm( Vec3(i,j,k) ); }
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "testInitGridWithPos" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& grid = *_args.getPtr<Grid<Real> >("grid",0,&_lock); _retval = getPyNone(); testInitGridWithPos(grid); _args.check(); }
+ pbFinalizePlugin(parent,"testInitGridWithPos", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("testInitGridWithPos",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_testInitGridWithPos ("","testInitGridWithPos",_W_4);
+extern "C" {
+ void PbRegister_testInitGridWithPos() {
+ KEEP_UNUSED(_RP_testInitGridWithPos); }
+ }
+
+
+
+
+
+//! helper to calculate particle radius factor to cover the diagonal of a cell in 2d/3d
+inline Real calculateRadiusFactor(const Grid<Real>& grid, Real factor) {
+ return (grid.is3D() ? sqrt(3.) : sqrt(2.) ) * (factor+.01); // note, a 1% safety factor is added here
+}
+
+//! re-sample particles based on an input levelset
+// optionally skip seeding new particles in "exclude" SDF
+
+
+
+void adjustNumber(BasicParticleSystem& parts, const MACGrid& vel, const FlagGrid& flags, int minParticles, int maxParticles, const LevelsetGrid& phi, Real radiusFactor=1. , Real narrowBand=-1. , const Grid<Real>* exclude=NULL ) {
+ // which levelset to use as threshold
+ const Real SURFACE_LS = -1.0 * calculateRadiusFactor(phi, radiusFactor);
+ Grid<int> tmp( vel.getParent() );
+ std::ostringstream out;
+
+ // count particles in cells, and delete excess particles
+ for (IndexInt idx=0; idx<(int)parts.size(); idx++) {
+ if (parts.isActive(idx)) {
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if (!tmp.isInBounds(p) ) {
+ parts.kill(idx); // out of domain, remove
+ continue;
+ }
+
+ Real phiv = phi.getInterpolated( parts.getPos(idx) );
+ if( phiv > 0 ) { parts.kill(idx); continue; }
+ if( narrowBand>0. && phiv < -narrowBand) { parts.kill(idx); continue; }
+
+ bool atSurface = false;
+ if (phiv > SURFACE_LS) atSurface = true;
+ int num = tmp(p);
+
+ // dont delete particles in non fluid cells here, the particles are "always right"
+ if ( num > maxParticles && (!atSurface) ) {
+ parts.kill(idx);
+ } else {
+ tmp(p) = num+1;
+ }
+ }
+ }
+
+ // seed new particles
+ RandomStream mRand(9832);
+ FOR_IJK(tmp) {
+ int cnt = tmp(i,j,k);
+
+ // skip cells near surface
+ if (phi(i,j,k) > SURFACE_LS) continue;
+ if( narrowBand>0. && phi(i,j,k) < -narrowBand ) { continue; }
+ if( exclude && ( (*exclude)(i,j,k) < 0.) ) { continue; }
+
+ if (flags.isFluid(i,j,k) && cnt < minParticles) {
+ for (int m=cnt; m < minParticles; m++) {
+ Vec3 pos = Vec3(i,j,k) + mRand.getVec3();
+ //Vec3 pos (i + 0.5, j + 0.5, k + 0.5); // cell center
+ parts.addBuffered( pos );
+ }
+ }
+ }
+
+ parts.doCompress();
+ parts.insertBufferedParticles();
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "adjustNumber" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); int minParticles = _args.get<int >("minParticles",3,&_lock); int maxParticles = _args.get<int >("maxParticles",4,&_lock); const LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",5,&_lock); Real radiusFactor = _args.getOpt<Real >("radiusFactor",6,1. ,&_lock); Real narrowBand = _args.getOpt<Real >("narrowBand",7,-1. ,&_lock); const Grid<Real>* exclude = _args.getPtrOpt<Grid<Real> >("exclude",8,NULL ,&_lock); _retval = getPyNone(); adjustNumber(parts,vel,flags,minParticles,maxParticles,phi,radiusFactor,narrowBand,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"adjustNumber", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("adjustNumber",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_adjustNumber ("","adjustNumber",_W_5);
+extern "C" {
+ void PbRegister_adjustNumber() {
+ KEEP_UNUSED(_RP_adjustNumber); }
+ }
+
+
+
+// simple and slow helper conversion to show contents of int grids like a real grid in the ui
+// (use eg to quickly display contents of the particle-index grid)
+
+void debugIntToReal(const Grid<int>& source, Grid<Real>& dest, Real factor=1. ) {
+ FOR_IJK( source ) { dest(i,j,k) = (Real)source(i,j,k) * factor; }
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "debugIntToReal" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<int>& source = *_args.getPtr<Grid<int> >("source",0,&_lock); Grid<Real>& dest = *_args.getPtr<Grid<Real> >("dest",1,&_lock); Real factor = _args.getOpt<Real >("factor",2,1. ,&_lock); _retval = getPyNone(); debugIntToReal(source,dest,factor); _args.check(); }
+ pbFinalizePlugin(parent,"debugIntToReal", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("debugIntToReal",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_debugIntToReal ("","debugIntToReal",_W_6);
+extern "C" {
+ void PbRegister_debugIntToReal() {
+ KEEP_UNUSED(_RP_debugIntToReal); }
+ }
+
+
+
+// build a grid that contains indices for a particle system
+// the particles in a cell i,j,k are particles[index(i,j,k)] to particles[index(i+1,j,k)-1]
+// (ie, particles[index(i+1,j,k)] already belongs to cell i+1,j,k)
+
+
+void gridParticleIndex(const BasicParticleSystem& parts, ParticleIndexSystem& indexSys, const FlagGrid& flags, Grid<int>& index, Grid<int>* counter=NULL ) {
+ bool delCounter = false;
+ if(!counter) { counter = new Grid<int>( flags.getParent() ); delCounter=true; }
+ else { counter->clear(); }
+
+ // count particles in cells, and delete excess particles
+ index.clear();
+ int inactive = 0;
+ for (IndexInt idx=0; idx<(IndexInt)parts.size(); idx++) {
+ if (parts.isActive(idx)) {
+ // check index for validity...
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if (! index.isInBounds(p)) { inactive++; continue; }
+
+ index(p)++;
+ } else {
+ inactive++;
+ }
+ }
+
+ // note - this one might be smaller...
+ indexSys.resize( parts.size()-inactive );
+
+ // convert per cell number to continuous index
+ IndexInt idx=0;
+ FOR_IJK( index ) {
+ int num = index(i,j,k);
+ index(i,j,k) = idx;
+ idx += num;
+ }
+
+ // add particles to indexed array, we still need a per cell particle counter
+ for (IndexInt idx=0; idx<(IndexInt)parts.size(); idx++) {
+ if (!parts.isActive(idx)) continue;
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if (! index.isInBounds(p)) { continue; }
+
+ // initialize position and index into original array
+ //indexSys[ index(p)+(*counter)(p) ].pos = parts[idx].pos;
+ indexSys[ index(p)+(*counter)(p) ].sourceIndex = idx;
+ (*counter)(p)++;
+ }
+
+ if(delCounter) delete counter;
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "gridParticleIndex" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleIndexSystem& indexSys = *_args.getPtr<ParticleIndexSystem >("indexSys",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); Grid<int>& index = *_args.getPtr<Grid<int> >("index",3,&_lock); Grid<int>* counter = _args.getPtrOpt<Grid<int> >("counter",4,NULL ,&_lock); _retval = getPyNone(); gridParticleIndex(parts,indexSys,flags,index,counter); _args.check(); }
+ pbFinalizePlugin(parent,"gridParticleIndex", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("gridParticleIndex",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_gridParticleIndex ("","gridParticleIndex",_W_7);
+extern "C" {
+ void PbRegister_gridParticleIndex() {
+ KEEP_UNUSED(_RP_gridParticleIndex); }
+ }
+
+
+
+
+
+
+
+ struct ComputeUnionLevelsetPindex : public KernelBase {
+ ComputeUnionLevelsetPindex(const Grid<int>& index, const BasicParticleSystem& parts, const ParticleIndexSystem& indexSys, LevelsetGrid& phi, const Real radius, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(&index,0) ,index(index),parts(parts),indexSys(indexSys),phi(phi),radius(radius),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<int>& index, const BasicParticleSystem& parts, const ParticleIndexSystem& indexSys, LevelsetGrid& phi, const Real radius, const ParticleDataImpl<int> *ptype, const int exclude ) const {
+ const Vec3 gridPos = Vec3(i,j,k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.0; // outside
+
+ int r = int(radius) + 1;
+ int rZ = phi.is3D() ? r : 0;
+ for(int zj=k-rZ; zj<=k+rZ; zj++)
+ for(int yj=j-r ; yj<=j+r ; yj++)
+ for(int xj=i-r ; xj<=i+r ; xj++) {
+ if (!phi.isInBounds(Vec3i(xj,yj,zj))) continue;
+
+ // note, for the particle indices in indexSys the access is periodic (ie, dont skip for eg inBounds(sx,10,10)
+ IndexInt isysIdxS = index.index(xj,yj,zj);
+ IndexInt pStart = index(isysIdxS), pEnd=0;
+ if(phi.isInBounds(isysIdxS+1)) pEnd = index(isysIdxS+1);
+ else pEnd = indexSys.size();
+
+ // now loop over particles in cell
+ for(IndexInt p=pStart; p<pEnd; ++p) {
+ const int psrc = indexSys[p].sourceIndex;
+ if(ptype && ((*ptype)[psrc] & exclude)) continue;
+ const Vec3 pos = parts[psrc].pos;
+ phiv = std::min( phiv , fabs( norm(gridPos-pos) )-radius );
+ }
+ }
+ phi(i,j,k) = phiv;
+} inline const Grid<int>& getArg0() {
+ return index; }
+ typedef Grid<int> type0;inline const BasicParticleSystem& getArg1() {
+ return parts; }
+ typedef BasicParticleSystem type1;inline const ParticleIndexSystem& getArg2() {
+ return indexSys; }
+ typedef ParticleIndexSystem type2;inline LevelsetGrid& getArg3() {
+ return phi; }
+ typedef LevelsetGrid type3;inline const Real& getArg4() {
+ return radius; }
+ typedef Real type4;inline const ParticleDataImpl<int> * getArg5() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type5;inline const int& getArg6() {
+ return exclude; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel ComputeUnionLevelsetPindex ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,index,parts,indexSys,phi,radius,ptype,exclude); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,index,parts,indexSys,phi,radius,ptype,exclude); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const Grid<int>& index; const BasicParticleSystem& parts; const ParticleIndexSystem& indexSys; LevelsetGrid& phi; const Real radius; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+
+
+
+
+void unionParticleLevelset(const BasicParticleSystem& parts, const ParticleIndexSystem& indexSys, const FlagGrid& flags, const Grid<int>& index, LevelsetGrid& phi, const Real radiusFactor=1., const ParticleDataImpl<int> *ptype=NULL, const int exclude=0) {
+ // use half a cell diagonal as base radius
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor);
+ // no reset of phi necessary here
+ ComputeUnionLevelsetPindex(index, parts, indexSys, phi, radius, ptype, exclude);
+
+ phi.setBound(0.5, 0);
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "unionParticleLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const ParticleIndexSystem& indexSys = *_args.getPtr<ParticleIndexSystem >("indexSys",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); const Grid<int>& index = *_args.getPtr<Grid<int> >("index",3,&_lock); LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",4,&_lock); const Real radiusFactor = _args.getOpt<Real >("radiusFactor",5,1.,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",6,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",7,0,&_lock); _retval = getPyNone(); unionParticleLevelset(parts,indexSys,flags,index,phi,radiusFactor,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"unionParticleLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("unionParticleLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_unionParticleLevelset ("","unionParticleLevelset",_W_8);
+extern "C" {
+ void PbRegister_unionParticleLevelset() {
+ KEEP_UNUSED(_RP_unionParticleLevelset); }
+ }
+
+
+
+//! kernel for computing averaged particle level set weights
+
+
+
+
+
+
+ struct ComputeAveragedLevelsetWeight : public KernelBase {
+ ComputeAveragedLevelsetWeight(const BasicParticleSystem& parts, const Grid<int>& index, const ParticleIndexSystem& indexSys, LevelsetGrid& phi, const Real radius, const ParticleDataImpl<int>* ptype, const int exclude, Grid<Vec3>* save_pAcc = NULL, Grid<Real>* save_rAcc = NULL) : KernelBase(&index,0) ,parts(parts),index(index),indexSys(indexSys),phi(phi),radius(radius),ptype(ptype),exclude(exclude),save_pAcc(save_pAcc),save_rAcc(save_rAcc) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const BasicParticleSystem& parts, const Grid<int>& index, const ParticleIndexSystem& indexSys, LevelsetGrid& phi, const Real radius, const ParticleDataImpl<int>* ptype, const int exclude, Grid<Vec3>* save_pAcc = NULL, Grid<Real>* save_rAcc = NULL ) const {
+ const Vec3 gridPos = Vec3(i,j,k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.0; // outside
+
+ // loop over neighborhood, similar to ComputeUnionLevelsetPindex
+ const Real sradiusInv = 1. / (4. * radius * radius) ;
+ int r = int(1. * radius) + 1;
+ int rZ = phi.is3D() ? r : 0;
+ // accumulators
+ Real wacc = 0.;
+ Vec3 pacc = Vec3(0.);
+ Real racc = 0.;
+
+ for(int zj=k-rZ; zj<=k+rZ; zj++)
+ for(int yj=j-r ; yj<=j+r ; yj++)
+ for(int xj=i-r ; xj<=i+r ; xj++) {
+ if (! phi.isInBounds(Vec3i(xj,yj,zj)) ) continue;
+
+ IndexInt isysIdxS = index.index(xj,yj,zj);
+ IndexInt pStart = index(isysIdxS), pEnd=0;
+ if(phi.isInBounds(isysIdxS+1)) pEnd = index(isysIdxS+1);
+ else pEnd = indexSys.size();
+ for(IndexInt p=pStart; p<pEnd; ++p) {
+ IndexInt psrc = indexSys[p].sourceIndex;
+ if(ptype && ((*ptype)[psrc] & exclude)) continue;
+
+ Vec3 pos = parts[psrc].pos;
+ Real s = normSquare(gridPos-pos) * sradiusInv;
+ //Real w = std::max(0., cubed(1.-s) );
+ Real w = std::max(0., (1.-s)); // a bit smoother
+ wacc += w;
+ racc += radius * w;
+ pacc += pos * w;
+ }
+ }
+
+ if(wacc > VECTOR_EPSILON) {
+ racc /= wacc;
+ pacc /= wacc;
+ phiv = fabs( norm(gridPos-pacc) )-racc;
+
+ if (save_pAcc) (*save_pAcc)(i, j, k) = pacc;
+ if (save_rAcc) (*save_rAcc)(i, j, k) = racc;
+ }
+ phi(i,j,k) = phiv;
+} inline const BasicParticleSystem& getArg0() {
+ return parts; }
+ typedef BasicParticleSystem type0;inline const Grid<int>& getArg1() {
+ return index; }
+ typedef Grid<int> type1;inline const ParticleIndexSystem& getArg2() {
+ return indexSys; }
+ typedef ParticleIndexSystem type2;inline LevelsetGrid& getArg3() {
+ return phi; }
+ typedef LevelsetGrid type3;inline const Real& getArg4() {
+ return radius; }
+ typedef Real type4;inline const ParticleDataImpl<int>* getArg5() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type5;inline const int& getArg6() {
+ return exclude; }
+ typedef int type6;inline Grid<Vec3>* getArg7() {
+ return save_pAcc; }
+ typedef Grid<Vec3> type7;inline Grid<Real>* getArg8() {
+ return save_rAcc; }
+ typedef Grid<Real> type8; void runMessage() { debMsg("Executing kernel ComputeAveragedLevelsetWeight ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,parts,index,indexSys,phi,radius,ptype,exclude,save_pAcc,save_rAcc); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,parts,index,indexSys,phi,radius,ptype,exclude,save_pAcc,save_rAcc); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const BasicParticleSystem& parts; const Grid<int>& index; const ParticleIndexSystem& indexSys; LevelsetGrid& phi; const Real radius; const ParticleDataImpl<int>* ptype; const int exclude; Grid<Vec3>* save_pAcc; Grid<Real>* save_rAcc; }
+;
+
+template<class T> T smoothingValue(const Grid<T> val, int i, int j, int k, T center) {
+ return val(i,j,k);
+}
+
+// smoothing, and
+
+template <class T> struct knSmoothGrid : public KernelBase {
+ knSmoothGrid(const Grid<T>& me, Grid<T>& tmp, Real factor) : KernelBase(&me,1) ,me(me),tmp(tmp),factor(factor) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<T>& me, Grid<T>& tmp, Real factor ) const {
+ T val = me(i,j,k) +
+ me(i+1,j,k) + me(i-1,j,k) +
+ me(i,j+1,k) + me(i,j-1,k) ;
+ if(me.is3D()) {
+ val += me(i,j,k+1) + me(i,j,k-1);
+ }
+ tmp(i,j,k) = val * factor;
+} inline const Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline Grid<T>& getArg1() {
+ return tmp; }
+ typedef Grid<T> type1;inline Real& getArg2() {
+ return factor; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel knSmoothGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,me,tmp,factor); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,me,tmp,factor); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const Grid<T>& me; Grid<T>& tmp; Real factor; }
+;
+
+
+template <class T> struct knSmoothGridNeg : public KernelBase {
+ knSmoothGridNeg(const Grid<T>& me, Grid<T>& tmp, Real factor) : KernelBase(&me,1) ,me(me),tmp(tmp),factor(factor) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<T>& me, Grid<T>& tmp, Real factor ) const {
+ T val = me(i,j,k) +
+ me(i+1,j,k) + me(i-1,j,k) +
+ me(i,j+1,k) + me(i,j-1,k) ;
+ if(me.is3D()) {
+ val += me(i,j,k+1) + me(i,j,k-1);
+ }
+ val *= factor;
+ if(val<tmp(i,j,k)) tmp(i,j,k) = val;
+ else tmp(i,j,k) = me(i,j,k);
+} inline const Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline Grid<T>& getArg1() {
+ return tmp; }
+ typedef Grid<T> type1;inline Real& getArg2() {
+ return factor; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel knSmoothGridNeg ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,me,tmp,factor); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,me,tmp,factor); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const Grid<T>& me; Grid<T>& tmp; Real factor; }
+;
+
+//! Zhu & Bridson particle level set creation
+
+
+
+
+void averagedParticleLevelset(const BasicParticleSystem& parts, const ParticleIndexSystem& indexSys, const FlagGrid& flags, const Grid<int>& index, LevelsetGrid& phi, const Real radiusFactor=1., const int smoothen=1, const int smoothenNeg=1, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ // use half a cell diagonal as base radius
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor);
+ ComputeAveragedLevelsetWeight(parts, index, indexSys, phi, radius, ptype, exclude);
+
+ // post-process level-set
+ for(int i=0; i<std::max(smoothen,smoothenNeg); ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ if(i<smoothen) {
+ knSmoothGrid <Real> (phi,tmp, 1./(phi.is3D() ? 7. : 5.) );
+ phi.swap(tmp);
+ }
+ if(i<smoothenNeg) {
+ knSmoothGridNeg <Real> (phi,tmp, 1./(phi.is3D() ? 7. : 5.) );
+ phi.swap(tmp);
+ }
+ }
+ phi.setBound(0.5, 0);
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "averagedParticleLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const ParticleIndexSystem& indexSys = *_args.getPtr<ParticleIndexSystem >("indexSys",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); const Grid<int>& index = *_args.getPtr<Grid<int> >("index",3,&_lock); LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",4,&_lock); const Real radiusFactor = _args.getOpt<Real >("radiusFactor",5,1.,&_lock); const int smoothen = _args.getOpt<int >("smoothen",6,1,&_lock); const int smoothenNeg = _args.getOpt<int >("smoothenNeg",7,1,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",8,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",9,0,&_lock); _retval = getPyNone(); averagedParticleLevelset(parts,indexSys,flags,index,phi,radiusFactor,smoothen,smoothenNeg,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"averagedParticleLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("averagedParticleLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_averagedParticleLevelset ("","averagedParticleLevelset",_W_9);
+extern "C" {
+ void PbRegister_averagedParticleLevelset() {
+ KEEP_UNUSED(_RP_averagedParticleLevelset); }
+ }
+
+
+
+//! kernel for improvedParticleLevelset
+
+
+
+ struct correctLevelset : public KernelBase {
+ correctLevelset(LevelsetGrid& phi, const Grid<Vec3>& pAcc, const Grid<Real>& rAcc, const Real radius, const Real t_low, const Real t_high) : KernelBase(&phi,1) ,phi(phi),pAcc(pAcc),rAcc(rAcc),radius(radius),t_low(t_low),t_high(t_high) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, LevelsetGrid& phi, const Grid<Vec3>& pAcc, const Grid<Real>& rAcc, const Real radius, const Real t_low, const Real t_high ) const {
+ if (rAcc(i, j, k) <= VECTOR_EPSILON) return; //outside nothing happens
+ Real x = pAcc(i, j, k).x;
+
+ // create jacobian of pAcc via central differences
+ Matrix3x3f jacobian = Matrix3x3f(
+ 0.5 * (pAcc(i+1, j, k ).x - pAcc(i-1, j, k ).x),
+ 0.5 * (pAcc(i, j+1, k ).x - pAcc(i, j-1, k ).x),
+ 0.5 * (pAcc(i, j , k+1).x - pAcc(i, j, k-1).x),
+ 0.5 * (pAcc(i+1, j, k ).y - pAcc(i-1, j, k ).y),
+ 0.5 * (pAcc(i, j+1, k ).y - pAcc(i, j-1, k ).y),
+ 0.5 * (pAcc(i, j, k+1).y - pAcc(i, j, k-1).y),
+ 0.5 * (pAcc(i+1, j, k ).z - pAcc(i-1, j, k ).z),
+ 0.5 * (pAcc(i, j+1, k ).z - pAcc(i, j-1, k ).z),
+ 0.5 * (pAcc(i, j, k+1).z - pAcc(i, j, k-1).z)
+ );
+
+ // compute largest eigenvalue of jacobian
+ Vec3 EV = jacobian.eigenvalues();
+ Real maxEV = std::max(std::max(EV.x, EV.y), EV.z);
+
+ // calculate correction factor
+ Real correction = 1;
+ if (maxEV >= t_low) {
+ Real t = (t_high - maxEV) / (t_high - t_low);
+ correction = t*t*t - 3 * t*t + 3 * t;
+ }
+ correction = (correction < 0) ? 0 : correction; // enforce correction factor to [0,1] (not explicitly in paper)
+
+ const Vec3 gridPos = Vec3(i, j, k) + Vec3(0.5); // shifted by half cell
+ const Real correctedPhi = fabs(norm(gridPos - pAcc(i, j, k))) - rAcc(i, j, k) * correction;
+ phi(i, j, k) = (correctedPhi > radius) ? radius : correctedPhi; // adjust too high outside values when too few particles are
+ // nearby to make smoothing possible (not in paper)
+} inline LevelsetGrid& getArg0() {
+ return phi; }
+ typedef LevelsetGrid type0;inline const Grid<Vec3>& getArg1() {
+ return pAcc; }
+ typedef Grid<Vec3> type1;inline const Grid<Real>& getArg2() {
+ return rAcc; }
+ typedef Grid<Real> type2;inline const Real& getArg3() {
+ return radius; }
+ typedef Real type3;inline const Real& getArg4() {
+ return t_low; }
+ typedef Real type4;inline const Real& getArg5() {
+ return t_high; }
+ typedef Real type5; void runMessage() { debMsg("Executing kernel correctLevelset ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,phi,pAcc,rAcc,radius,t_low,t_high); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,phi,pAcc,rAcc,radius,t_low,t_high); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ LevelsetGrid& phi; const Grid<Vec3>& pAcc; const Grid<Real>& rAcc; const Real radius; const Real t_low; const Real t_high; }
+;
+
+//! Approach from "A unified particle model for fluid-solid interactions" by Solenthaler et al. in 2007
+
+
+
+void improvedParticleLevelset(const BasicParticleSystem& parts, const ParticleIndexSystem& indexSys, const FlagGrid& flags, const Grid<int>& index, LevelsetGrid& phi, const Real radiusFactor = 1., const int smoothen = 1,const int smoothenNeg = 1, const Real t_low = 0.4, const Real t_high = 3.5, const ParticleDataImpl<int>* ptype = NULL, const int exclude = 0) {
+ // create temporary grids to store values from levelset weight computation
+ Grid<Vec3> save_pAcc(flags.getParent());
+ Grid<Real> save_rAcc(flags.getParent());
+
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor); // use half a cell diagonal as base radius
+ ComputeAveragedLevelsetWeight(parts, index, indexSys, phi, radius, ptype, exclude, &save_pAcc, &save_rAcc);
+ correctLevelset(phi, save_pAcc, save_rAcc, radius, t_low, t_high);
+
+ // post-process level-set
+ for (int i = 0; i<std::max(smoothen, smoothenNeg); ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ if (i<smoothen) {
+ knSmoothGrid <Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ if (i<smoothenNeg) {
+ knSmoothGridNeg <Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ }
+ phi.setBound(0.5, 0);
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "improvedParticleLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const ParticleIndexSystem& indexSys = *_args.getPtr<ParticleIndexSystem >("indexSys",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); const Grid<int>& index = *_args.getPtr<Grid<int> >("index",3,&_lock); LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",4,&_lock); const Real radiusFactor = _args.getOpt<Real >("radiusFactor",5,1.,&_lock); const int smoothen = _args.getOpt<int >("smoothen",6,1,&_lock); const int smoothenNeg = _args.getOpt<int >("smoothenNeg",7,1,&_lock); const Real t_low = _args.getOpt<Real >("t_low",8,0.4,&_lock); const Real t_high = _args.getOpt<Real >("t_high",9,3.5,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",10,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",11,0,&_lock); _retval = getPyNone(); improvedParticleLevelset(parts,indexSys,flags,index,phi,radiusFactor,smoothen,smoothenNeg,t_low,t_high,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"improvedParticleLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("improvedParticleLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_improvedParticleLevelset ("","improvedParticleLevelset",_W_10);
+extern "C" {
+ void PbRegister_improvedParticleLevelset() {
+ KEEP_UNUSED(_RP_improvedParticleLevelset); }
+ }
+
+
+
+
+
+
+ struct knPushOutofObs : public KernelBase {
+ knPushOutofObs(BasicParticleSystem& parts, const FlagGrid& flags, const Grid<Real>& phiObs, const Real shift, const Real thresh, const ParticleDataImpl<int>* ptype, const int exclude) : KernelBase(parts.size()) ,parts(parts),flags(flags),phiObs(phiObs),shift(shift),thresh(thresh),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystem& parts, const FlagGrid& flags, const Grid<Real>& phiObs, const Real shift, const Real thresh, const ParticleDataImpl<int>* ptype, const int exclude ) const {
+ if (!parts.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ Vec3i p = toVec3i( parts.getPos(idx) );
+
+ if (!flags.isInBounds(p)) return;
+ Real v = phiObs.getInterpolated(parts.getPos(idx));
+ if(v < thresh) {
+ Vec3 grad = getGradient( phiObs, p.x,p.y,p.z );
+ if( normalize(grad) < VECTOR_EPSILON ) return;
+ parts.setPos(idx, parts.getPos(idx) + grad*(thresh - v + shift));
+ }
+} inline BasicParticleSystem& getArg0() {
+ return parts; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<Real>& getArg2() {
+ return phiObs; }
+ typedef Grid<Real> type2;inline const Real& getArg3() {
+ return shift; }
+ typedef Real type3;inline const Real& getArg4() {
+ return thresh; }
+ typedef Real type4;inline const ParticleDataImpl<int>* getArg5() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type5;inline const int& getArg6() {
+ return exclude; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel knPushOutofObs ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, parts,flags,phiObs,shift,thresh,ptype,exclude); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ BasicParticleSystem& parts; const FlagGrid& flags; const Grid<Real>& phiObs; const Real shift; const Real thresh; const ParticleDataImpl<int>* ptype; const int exclude; }
+;
+//! push particles out of obstacle levelset
+
+void pushOutofObs(BasicParticleSystem& parts, const FlagGrid& flags, const Grid<Real>& phiObs, const Real shift=0, const Real thresh=0, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ knPushOutofObs(parts, flags, phiObs, shift, thresh, ptype, exclude);
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "pushOutofObs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const Grid<Real>& phiObs = *_args.getPtr<Grid<Real> >("phiObs",2,&_lock); const Real shift = _args.getOpt<Real >("shift",3,0,&_lock); const Real thresh = _args.getOpt<Real >("thresh",4,0,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",5,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",6,0,&_lock); _retval = getPyNone(); pushOutofObs(parts,flags,phiObs,shift,thresh,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"pushOutofObs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("pushOutofObs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_pushOutofObs ("","pushOutofObs",_W_11);
+extern "C" {
+ void PbRegister_pushOutofObs() {
+ KEEP_UNUSED(_RP_pushOutofObs); }
+ }
+
+
+
+//******************************************************************************
+// grid interpolation functions
+
+
+template <class T> struct knSafeDivReal : public KernelBase {
+ knSafeDivReal(Grid<T>& me, const Grid<Real>& other, Real cutoff=VECTOR_EPSILON) : KernelBase(&me,0) ,me(me),other(other),cutoff(cutoff) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<T>& me, const Grid<Real>& other, Real cutoff=VECTOR_EPSILON ) const {
+ if(other[idx]<cutoff) {
+ me[idx] = 0.;
+ } else {
+ T div( other[idx] );
+ me[idx] = safeDivide(me[idx], div );
+ }
+} inline Grid<T>& getArg0() {
+ return me; }
+ typedef Grid<T> type0;inline const Grid<Real>& getArg1() {
+ return other; }
+ typedef Grid<Real> type1;inline Real& getArg2() {
+ return cutoff; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel knSafeDivReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, me,other,cutoff); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<T>& me; const Grid<Real>& other; Real cutoff; }
+;
+
+// Set velocities on the grid from the particle system
+
+
+
+
+ struct knMapLinearVec3ToMACGrid : public KernelBase {
+ knMapLinearVec3ToMACGrid(const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, Grid<Vec3>& tmp, const ParticleDataImpl<Vec3>& pvel, const ParticleDataImpl<int>* ptype, const int exclude) : KernelBase(p.size()) ,p(p),flags(flags),vel(vel),tmp(tmp),pvel(pvel),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, Grid<Vec3>& tmp, const ParticleDataImpl<Vec3>& pvel, const ParticleDataImpl<int>* ptype, const int exclude ) {
+ unusedParameter(flags);
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ vel.setInterpolated( p[idx].pos, pvel[idx], &tmp[0] );
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline Grid<Vec3>& getArg3() {
+ return tmp; }
+ typedef Grid<Vec3> type3;inline const ParticleDataImpl<Vec3>& getArg4() {
+ return pvel; }
+ typedef ParticleDataImpl<Vec3> type4;inline const ParticleDataImpl<int>* getArg5() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type5;inline const int& getArg6() {
+ return exclude; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel knMapLinearVec3ToMACGrid ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size; for (IndexInt i = 0; i < _sz; i++) op(i, p,flags,vel,tmp,pvel,ptype,exclude); }
+ const BasicParticleSystem& p; const FlagGrid& flags; const MACGrid& vel; Grid<Vec3>& tmp; const ParticleDataImpl<Vec3>& pvel; const ParticleDataImpl<int>* ptype; const int exclude; }
+;
+
+// optionally , this function can use an existing vec3 grid to store the weights
+// this is useful in combination with the simple extrapolation function
+
+
+
+void mapPartsToMAC(const FlagGrid& flags, MACGrid& vel, MACGrid& velOld, const BasicParticleSystem& parts, const ParticleDataImpl<Vec3>& partVel, Grid<Vec3>* weight=NULL, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ // interpol -> grid. tmpgrid for particle contribution weights
+ bool freeTmp = false;
+ if(!weight) {
+ weight = new Grid<Vec3>(flags.getParent());
+ freeTmp = true;
+ } else {
+ weight->clear(); // make sure we start with a zero grid!
+ }
+ vel.clear();
+ knMapLinearVec3ToMACGrid( parts, flags, vel, *weight, partVel, ptype, exclude );
+
+ // stomp small values in weight to zero to prevent roundoff errors
+ weight->stomp(Vec3(VECTOR_EPSILON));
+ vel.safeDivide(*weight);
+
+ // store original state
+ velOld.copyFrom( vel );
+ if(freeTmp) delete weight;
+} static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapPartsToMAC" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); MACGrid& velOld = *_args.getPtr<MACGrid >("velOld",2,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",3,&_lock); const ParticleDataImpl<Vec3>& partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",4,&_lock); Grid<Vec3>* weight = _args.getPtrOpt<Grid<Vec3> >("weight",5,NULL,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",6,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",7,0,&_lock); _retval = getPyNone(); mapPartsToMAC(flags,vel,velOld,parts,partVel,weight,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"mapPartsToMAC", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapPartsToMAC",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapPartsToMAC ("","mapPartsToMAC",_W_12);
+extern "C" {
+ void PbRegister_mapPartsToMAC() {
+ KEEP_UNUSED(_RP_mapPartsToMAC); }
+ }
+
+
+
+
+
+
+template <class T> struct knMapLinear : public KernelBase {
+ knMapLinear(const BasicParticleSystem& p, const FlagGrid& flags, const Grid<T>& target, Grid<Real>& gtmp, const ParticleDataImpl<T>& psource ) : KernelBase(p.size()) ,p(p),flags(flags),target(target),gtmp(gtmp),psource(psource) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& p, const FlagGrid& flags, const Grid<T>& target, Grid<Real>& gtmp, const ParticleDataImpl<T>& psource ) {
+ unusedParameter(flags);
+ if (!p.isActive(idx)) return;
+ target.setInterpolated( p[idx].pos, psource[idx], gtmp );
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<T>& getArg2() {
+ return target; }
+ typedef Grid<T> type2;inline Grid<Real>& getArg3() {
+ return gtmp; }
+ typedef Grid<Real> type3;inline const ParticleDataImpl<T>& getArg4() {
+ return psource; }
+ typedef ParticleDataImpl<T> type4; void runMessage() { debMsg("Executing kernel knMapLinear ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void run() {
+ const IndexInt _sz = size; for (IndexInt i = 0; i < _sz; i++) op(i, p,flags,target,gtmp,psource); }
+ const BasicParticleSystem& p; const FlagGrid& flags; const Grid<T>& target; Grid<Real>& gtmp; const ParticleDataImpl<T>& psource; }
+;
+
+template<class T>
+void mapLinearRealHelper(const FlagGrid& flags, Grid<T>& target,
+ const BasicParticleSystem& parts, const ParticleDataImpl<T>& source )
+{
+ Grid<Real> tmp(flags.getParent());
+ target.clear();
+ knMapLinear<T>( parts, flags, target, tmp, source );
+ knSafeDivReal<T>( target, tmp );
+}
+
+void mapPartsToGrid(const FlagGrid& flags, Grid<Real>& target , const BasicParticleSystem& parts , const ParticleDataImpl<Real>& source ) {
+ mapLinearRealHelper<Real>(flags,target,parts,source);
+} static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapPartsToGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",1,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); const ParticleDataImpl<Real>& source = *_args.getPtr<ParticleDataImpl<Real> >("source",3,&_lock); _retval = getPyNone(); mapPartsToGrid(flags,target,parts,source); _args.check(); }
+ pbFinalizePlugin(parent,"mapPartsToGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapPartsToGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapPartsToGrid ("","mapPartsToGrid",_W_13);
+extern "C" {
+ void PbRegister_mapPartsToGrid() {
+ KEEP_UNUSED(_RP_mapPartsToGrid); }
+ }
+
+
+void mapPartsToGridVec3(const FlagGrid& flags, Grid<Vec3>& target , const BasicParticleSystem& parts , const ParticleDataImpl<Vec3>& source ) {
+ mapLinearRealHelper<Vec3>(flags,target,parts,source);
+} static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapPartsToGridVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); const ParticleDataImpl<Vec3>& source = *_args.getPtr<ParticleDataImpl<Vec3> >("source",3,&_lock); _retval = getPyNone(); mapPartsToGridVec3(flags,target,parts,source); _args.check(); }
+ pbFinalizePlugin(parent,"mapPartsToGridVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapPartsToGridVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapPartsToGridVec3 ("","mapPartsToGridVec3",_W_14);
+extern "C" {
+ void PbRegister_mapPartsToGridVec3() {
+ KEEP_UNUSED(_RP_mapPartsToGridVec3); }
+ }
+
+
+// integers need "max" mode, not yet implemented
+//PYTHON() void mapPartsToGridInt ( FlagGrid& flags, Grid<int >& target , BasicParticleSystem& parts , ParticleDataImpl<int >& source ) {
+// mapLinearRealHelper<int >(flags,target,parts,source);
+//}
+
+
+
+template <class T> struct knMapFromGrid : public KernelBase {
+ knMapFromGrid(const BasicParticleSystem& p, const Grid<T>& gsrc, ParticleDataImpl<T>& target ) : KernelBase(p.size()) ,p(p),gsrc(gsrc),target(target) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& p, const Grid<T>& gsrc, ParticleDataImpl<T>& target ) const {
+ if (!p.isActive(idx)) return;
+ target[idx] = gsrc.getInterpolated( p[idx].pos );
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const Grid<T>& getArg1() {
+ return gsrc; }
+ typedef Grid<T> type1;inline ParticleDataImpl<T>& getArg2() {
+ return target; }
+ typedef ParticleDataImpl<T> type2; void runMessage() { debMsg("Executing kernel knMapFromGrid ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, p,gsrc,target); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystem& p; const Grid<T>& gsrc; ParticleDataImpl<T>& target; }
+;
+void mapGridToParts(const Grid<Real>& source , const BasicParticleSystem& parts , ParticleDataImpl<Real>& target ) {
+ knMapFromGrid<Real>(parts, source, target);
+} static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapGridToParts" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",0,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",1,&_lock); ParticleDataImpl<Real>& target = *_args.getPtr<ParticleDataImpl<Real> >("target",2,&_lock); _retval = getPyNone(); mapGridToParts(source,parts,target); _args.check(); }
+ pbFinalizePlugin(parent,"mapGridToParts", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapGridToParts",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapGridToParts ("","mapGridToParts",_W_15);
+extern "C" {
+ void PbRegister_mapGridToParts() {
+ KEEP_UNUSED(_RP_mapGridToParts); }
+ }
+
+
+void mapGridToPartsVec3(const Grid<Vec3>& source , const BasicParticleSystem& parts , ParticleDataImpl<Vec3>& target ) {
+ knMapFromGrid<Vec3>(parts, source, target);
+} static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapGridToPartsVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Vec3>& source = *_args.getPtr<Grid<Vec3> >("source",0,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",1,&_lock); ParticleDataImpl<Vec3>& target = *_args.getPtr<ParticleDataImpl<Vec3> >("target",2,&_lock); _retval = getPyNone(); mapGridToPartsVec3(source,parts,target); _args.check(); }
+ pbFinalizePlugin(parent,"mapGridToPartsVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapGridToPartsVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapGridToPartsVec3 ("","mapGridToPartsVec3",_W_16);
+extern "C" {
+ void PbRegister_mapGridToPartsVec3() {
+ KEEP_UNUSED(_RP_mapGridToPartsVec3); }
+ }
+
+
+
+
+// Get velocities from grid
+
+
+
+
+ struct knMapLinearMACGridToVec3_PIC : public KernelBase {
+ knMapLinearMACGridToVec3_PIC(const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, ParticleDataImpl<Vec3>& pvel, const ParticleDataImpl<int>* ptype, const int exclude) : KernelBase(p.size()) ,p(p),flags(flags),vel(vel),pvel(pvel),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, ParticleDataImpl<Vec3>& pvel, const ParticleDataImpl<int>* ptype, const int exclude ) const {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ // pure PIC
+ pvel[idx] = vel.getInterpolated( p[idx].pos );
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline ParticleDataImpl<Vec3>& getArg3() {
+ return pvel; }
+ typedef ParticleDataImpl<Vec3> type3;inline const ParticleDataImpl<int>* getArg4() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type4;inline const int& getArg5() {
+ return exclude; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel knMapLinearMACGridToVec3_PIC ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, p,flags,vel,pvel,ptype,exclude); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystem& p; const FlagGrid& flags; const MACGrid& vel; ParticleDataImpl<Vec3>& pvel; const ParticleDataImpl<int>* ptype; const int exclude; }
+;
+
+
+void mapMACToParts(const FlagGrid& flags, const MACGrid& vel , const BasicParticleSystem& parts , ParticleDataImpl<Vec3>& partVel, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ knMapLinearMACGridToVec3_PIC( parts, flags, vel, partVel, ptype, exclude );
+} static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "mapMACToParts" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); ParticleDataImpl<Vec3>& partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",3,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",4,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",5,0,&_lock); _retval = getPyNone(); mapMACToParts(flags,vel,parts,partVel,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"mapMACToParts", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("mapMACToParts",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_mapMACToParts ("","mapMACToParts",_W_17);
+extern "C" {
+ void PbRegister_mapMACToParts() {
+ KEEP_UNUSED(_RP_mapMACToParts); }
+ }
+
+
+
+// with flip delta interpolation
+
+
+
+
+ struct knMapLinearMACGridToVec3_FLIP : public KernelBase {
+ knMapLinearMACGridToVec3_FLIP(const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, const MACGrid& oldVel, ParticleDataImpl<Vec3>& pvel, const Real flipRatio, const ParticleDataImpl<int>* ptype, const int exclude) : KernelBase(p.size()) ,p(p),flags(flags),vel(vel),oldVel(oldVel),pvel(pvel),flipRatio(flipRatio),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& p, const FlagGrid& flags, const MACGrid& vel, const MACGrid& oldVel, ParticleDataImpl<Vec3>& pvel, const Real flipRatio, const ParticleDataImpl<int>* ptype, const int exclude ) const {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude))) return;
+ Vec3 v = vel.getInterpolated(p[idx].pos);
+ Vec3 delta = v - oldVel.getInterpolated(p[idx].pos);
+ pvel[idx] = flipRatio * (pvel[idx] + delta) + (1.0 - flipRatio) * v;
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline const MACGrid& getArg3() {
+ return oldVel; }
+ typedef MACGrid type3;inline ParticleDataImpl<Vec3>& getArg4() {
+ return pvel; }
+ typedef ParticleDataImpl<Vec3> type4;inline const Real& getArg5() {
+ return flipRatio; }
+ typedef Real type5;inline const ParticleDataImpl<int>* getArg6() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type6;inline const int& getArg7() {
+ return exclude; }
+ typedef int type7; void runMessage() { debMsg("Executing kernel knMapLinearMACGridToVec3_FLIP ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, p,flags,vel,oldVel,pvel,flipRatio,ptype,exclude); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystem& p; const FlagGrid& flags; const MACGrid& vel; const MACGrid& oldVel; ParticleDataImpl<Vec3>& pvel; const Real flipRatio; const ParticleDataImpl<int>* ptype; const int exclude; }
+;
+
+
+
+void flipVelocityUpdate(const FlagGrid& flags, const MACGrid& vel, const MACGrid& velOld, const BasicParticleSystem& parts, ParticleDataImpl<Vec3>& partVel, const Real flipRatio, const ParticleDataImpl<int>* ptype=NULL, const int exclude=0) {
+ knMapLinearMACGridToVec3_FLIP( parts, flags, vel, velOld, partVel, flipRatio, ptype, exclude );
+} static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipVelocityUpdate" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const MACGrid& velOld = *_args.getPtr<MACGrid >("velOld",2,&_lock); const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",3,&_lock); ParticleDataImpl<Vec3>& partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",4,&_lock); const Real flipRatio = _args.get<Real >("flipRatio",5,&_lock); const ParticleDataImpl<int>* ptype = _args.getPtrOpt<ParticleDataImpl<int> >("ptype",6,NULL,&_lock); const int exclude = _args.getOpt<int >("exclude",7,0,&_lock); _retval = getPyNone(); flipVelocityUpdate(flags,vel,velOld,parts,partVel,flipRatio,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"flipVelocityUpdate", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipVelocityUpdate",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipVelocityUpdate ("","flipVelocityUpdate",_W_18);
+extern "C" {
+ void PbRegister_flipVelocityUpdate() {
+ KEEP_UNUSED(_RP_flipVelocityUpdate); }
+ }
+
+
+
+
+//******************************************************************************
+// narrow band
+
+
+ struct knCombineVels : public KernelBase {
+ knCombineVels(MACGrid& vel, const Grid<Vec3>& w, MACGrid& combineVel, const LevelsetGrid* phi, Real narrowBand, Real thresh ) : KernelBase(&vel,0) ,vel(vel),w(w),combineVel(combineVel),phi(phi),narrowBand(narrowBand),thresh(thresh) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& vel, const Grid<Vec3>& w, MACGrid& combineVel, const LevelsetGrid* phi, Real narrowBand, Real thresh ) const {
+ int idx = vel.index(i,j,k);
+
+ for(int c=0; c<3; ++c)
+ {
+ // Correct narrow-band FLIP
+ if(phi) {
+ Vec3 pos(i,j,k);
+ pos[(c+1)%3] += Real(0.5);
+ pos[(c+2)%3] += Real(0.5);
+ Real p = phi->getInterpolated(pos);
+ if (p < -narrowBand) { vel[idx][c] = 0; continue; }
+ }
+
+ if (w[idx][c] > thresh) {
+ combineVel[idx][c] = vel[idx][c];
+ vel[idx][c] = -1;
+ } else {
+ vel[idx][c] = 0;
+ }
+ }
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const Grid<Vec3>& getArg1() {
+ return w; }
+ typedef Grid<Vec3> type1;inline MACGrid& getArg2() {
+ return combineVel; }
+ typedef MACGrid type2;inline const LevelsetGrid* getArg3() {
+ return phi; }
+ typedef LevelsetGrid type3;inline Real& getArg4() {
+ return narrowBand; }
+ typedef Real type4;inline Real& getArg5() {
+ return thresh; }
+ typedef Real type5; void runMessage() { debMsg("Executing kernel knCombineVels ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,vel,w,combineVel,phi,narrowBand,thresh); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,vel,w,combineVel,phi,narrowBand,thresh); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ MACGrid& vel; const Grid<Vec3>& w; MACGrid& combineVel; const LevelsetGrid* phi; Real narrowBand; Real thresh; }
+;
+
+//! narrow band velocity combination
+
+void combineGridVel( MACGrid& vel, const Grid<Vec3>& weight, MACGrid& combineVel, const LevelsetGrid* phi=NULL, Real narrowBand=0.0, Real thresh=0.0) {
+ knCombineVels(vel, weight, combineVel, phi, narrowBand, thresh);
+} static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "combineGridVel" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); const Grid<Vec3>& weight = *_args.getPtr<Grid<Vec3> >("weight",1,&_lock); MACGrid& combineVel = *_args.getPtr<MACGrid >("combineVel",2,&_lock); const LevelsetGrid* phi = _args.getPtrOpt<LevelsetGrid >("phi",3,NULL,&_lock); Real narrowBand = _args.getOpt<Real >("narrowBand",4,0.0,&_lock); Real thresh = _args.getOpt<Real >("thresh",5,0.0,&_lock); _retval = getPyNone(); combineGridVel(vel,weight,combineVel,phi,narrowBand,thresh); _args.check(); }
+ pbFinalizePlugin(parent,"combineGridVel", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("combineGridVel",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_combineGridVel ("","combineGridVel",_W_19);
+extern "C" {
+ void PbRegister_combineGridVel() {
+ KEEP_UNUSED(_RP_combineGridVel); }
+ }
+
+
+
+//! surface tension helper
+void getLaplacian(Grid<Real> &laplacian, const Grid<Real> &grid) {
+ LaplaceOp(laplacian, grid);
+} static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getLaplacian" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & laplacian = *_args.getPtr<Grid<Real> >("laplacian",0,&_lock); const Grid<Real> & grid = *_args.getPtr<Grid<Real> >("grid",1,&_lock); _retval = getPyNone(); getLaplacian(laplacian,grid); _args.check(); }
+ pbFinalizePlugin(parent,"getLaplacian", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getLaplacian",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getLaplacian ("","getLaplacian",_W_20);
+extern "C" {
+ void PbRegister_getLaplacian() {
+ KEEP_UNUSED(_RP_getLaplacian); }
+ }
+
+
+
+void getCurvature(Grid<Real> &curv, const Grid<Real> &grid, const Real h=1.0) {
+ CurvatureOp(curv, grid, h);
+} static PyObject* _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getCurvature" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & curv = *_args.getPtr<Grid<Real> >("curv",0,&_lock); const Grid<Real> & grid = *_args.getPtr<Grid<Real> >("grid",1,&_lock); const Real h = _args.getOpt<Real >("h",2,1.0,&_lock); _retval = getPyNone(); getCurvature(curv,grid,h); _args.check(); }
+ pbFinalizePlugin(parent,"getCurvature", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getCurvature",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getCurvature ("","getCurvature",_W_21);
+extern "C" {
+ void PbRegister_getCurvature() {
+ KEEP_UNUSED(_RP_getCurvature); }
+ }
+
+
+
+} // namespace
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/fluidguiding.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/fluidguiding.cpp
new file mode 100644
index 00000000000..b71f3da8d89
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/fluidguiding.cpp
@@ -0,0 +1,486 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for pressure correction: solve_pressure, and ghost fluid helpers
+ *
+ ******************************************************************************/
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+#include "conjugategrad.h"
+#include "rcmatrix.h"
+
+using namespace std;
+namespace Manta {
+
+// only supports a single blur size for now, globals stored here
+bool gBlurPrecomputed = false;
+int gBlurKernelRadius = -1;
+Matrix gBlurKernel;
+
+// *****************************************************************************
+// Helper functions for fluid guiding
+
+//! creates a 1D (horizontal) Gaussian blur kernel of size n and standard deviation sigma
+Matrix get1DGaussianBlurKernel(const int n, const int sigma) {
+ Matrix x(n), y(n);
+ for (int j = 0; j < n; j++) {
+ x.add_to_element(0, j, - (n - 1)*0.5);
+ y.add_to_element(0, j, j - (n - 1)*0.5);
+ }
+ Matrix G(n);
+ Real sumG = 0;
+ for (int j = 0; j < n; j++) {
+ G.add_to_element(0, j, 1 / (2 * M_PI*sigma*sigma)*exp(-(x(0, j)*x(0, j) + y(0, j)*y(0, j)) / (2 * sigma*sigma)));
+ sumG += G(0, j);
+ }
+ G = G*(1.0 / sumG);
+ return G;
+}
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the x-direction
+//! (out must be a grid of zeros)
+ struct apply1DKernelDirX : public KernelBase {
+ apply1DKernelDirX(const MACGrid &in, MACGrid &out, const Matrix &kernel) : KernelBase(&in,0) ,in(in),out(out),kernel(kernel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel ) const {
+ int nx = in.getSizeX();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, ii = i - kCentre; m < kn; m++, ind--, ii++) {
+ if (ii < 0) continue;
+ else if (ii >= nx) break;
+ else out(i, j, k) += in(ii, j, k)*kernel(0,ind);
+ }
+} inline const MACGrid& getArg0() {
+ return in; }
+ typedef MACGrid type0;inline MACGrid& getArg1() {
+ return out; }
+ typedef MACGrid type1;inline const Matrix& getArg2() {
+ return kernel; }
+ typedef Matrix type2; void runMessage() { debMsg("Executing kernel apply1DKernelDirX ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,in,out,kernel); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,in,out,kernel); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const MACGrid& in; MACGrid& out; const Matrix& kernel; }
+;
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the y-direction
+//! (out must be a grid of zeros)
+ struct apply1DKernelDirY : public KernelBase {
+ apply1DKernelDirY(const MACGrid &in, MACGrid &out, const Matrix &kernel) : KernelBase(&in,0) ,in(in),out(out),kernel(kernel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel ) const {
+ int ny = in.getSizeY();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, jj = j - kCentre; m < kn; m++, ind--, jj++) {
+ if (jj < 0) continue;
+ else if (jj >= ny) break;
+ else out(i, j, k) += in(i, jj, k)*kernel(0, ind);
+ }
+} inline const MACGrid& getArg0() {
+ return in; }
+ typedef MACGrid type0;inline MACGrid& getArg1() {
+ return out; }
+ typedef MACGrid type1;inline const Matrix& getArg2() {
+ return kernel; }
+ typedef Matrix type2; void runMessage() { debMsg("Executing kernel apply1DKernelDirY ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,in,out,kernel); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,in,out,kernel); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const MACGrid& in; MACGrid& out; const Matrix& kernel; }
+;
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the z-direction
+//! (out must be a grid of zeros)
+ struct apply1DKernelDirZ : public KernelBase {
+ apply1DKernelDirZ(const MACGrid &in, MACGrid &out, const Matrix &kernel) : KernelBase(&in,0) ,in(in),out(out),kernel(kernel) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel ) const {
+ int nz = in.getSizeZ();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, kk = k - kCentre; m < kn; m++, ind--, kk++) {
+ if (kk < 0) continue;
+ else if (kk >= nz) break;
+ else out(i, j, k) += in(i, j, kk)*kernel(0, ind);
+ }
+} inline const MACGrid& getArg0() {
+ return in; }
+ typedef MACGrid type0;inline MACGrid& getArg1() {
+ return out; }
+ typedef MACGrid type1;inline const Matrix& getArg2() {
+ return kernel; }
+ typedef Matrix type2; void runMessage() { debMsg("Executing kernel apply1DKernelDirZ ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,in,out,kernel); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,in,out,kernel); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const MACGrid& in; MACGrid& out; const Matrix& kernel; }
+;
+
+//! Apply separable Gaussian blur in 2D
+void applySeparableKernel2D(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel) {
+ //int nx = grid.getSizeX(), ny = grid.getSizeY();
+ //int kn = kernel.n;
+ //int kCentre = kn / 2;
+ FluidSolver* parent = grid.getParent();
+ MACGrid orig = MACGrid(parent);
+ orig.copyFrom(grid);
+ MACGrid gridX = MACGrid(parent);
+ apply1DKernelDirX(grid, gridX, kernel);
+ MACGrid gridXY = MACGrid(parent);
+ apply1DKernelDirY(gridX, gridXY, kernel);
+ grid.copyFrom(gridXY);
+ FOR_IJK(grid) {
+ if ((i>0 && flags.isObstacle(i - 1, j, k)) || (j>0 && flags.isObstacle(i, j - 1, k)) || flags.isObstacle(i, j, k)) {
+ grid(i, j, k).x = orig(i, j, k).x;
+ grid(i, j, k).y = orig(i, j, k).y;
+ grid(i, j, k).z = orig(i, j, k).z;
+ }
+ }
+}
+
+//! Apply separable Gaussian blur in 3D
+void applySeparableKernel3D(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel) {
+ //int nx = grid.getSizeX(), ny = grid.getSizeY(), nz = grid.getSizeZ();
+ //int kn = kernel.n;
+ //int kCentre = kn / 2;
+ FluidSolver* parent = grid.getParent();
+ MACGrid orig = MACGrid(parent);
+ orig.copyFrom(grid);
+ MACGrid gridX = MACGrid(parent);
+ apply1DKernelDirX(grid, gridX, kernel);
+ MACGrid gridXY = MACGrid(parent);
+ apply1DKernelDirY(gridX, gridXY, kernel);
+ MACGrid gridXYZ = MACGrid(parent);
+ apply1DKernelDirZ(gridXY, gridXYZ, kernel);
+ grid.copyFrom(gridXYZ);
+ FOR_IJK(grid) {
+ if ((i>0 && flags.isObstacle(i - 1, j, k)) || (j>0 && flags.isObstacle(i, j - 1, k)) || (k>0 && flags.isObstacle(i, j, k - 1)) || flags.isObstacle(i, j, k)) {
+ grid(i, j, k).x = orig(i, j, k).x;
+ grid(i, j, k).y = orig(i, j, k).y;
+ grid(i, j, k).z = orig(i, j, k).z;
+ }
+ }
+}
+
+//! Apply separable Gaussian blur in 2D or 3D depending on input dimensions
+void applySeparableKernel(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel) {
+ if (!grid.is3D()) applySeparableKernel2D(grid, flags, kernel);
+ else applySeparableKernel3D(grid, flags, kernel);
+}
+
+
+//! Compute r-norm for the stopping criterion
+Real getRNorm(const MACGrid &x, const MACGrid &z) {
+ MACGrid r = MACGrid(x.getParent());
+ r.copyFrom(x);
+ r.sub(z);
+ return r.getMaxAbs();
+}
+
+//! Compute s-norm for the stopping criterion
+Real getSNorm(const Real rho, const MACGrid &z, const MACGrid &z_prev) {
+ MACGrid s = MACGrid(z_prev.getParent());
+ s.copyFrom(z_prev);
+ s.sub(z);
+ s.multConst(rho);
+ return s.getMaxAbs();
+}
+
+//! Compute primal eps for the stopping criterion
+Real getEpsPri(const Real eps_abs, const Real eps_rel,
+ const MACGrid &x, const MACGrid &z) {
+ Real max_norm = max(x.getMaxAbs(), z.getMaxAbs());
+ Real eps_pri = sqrt(x.is3D() ? 3.0 : 2.0)*eps_abs + eps_rel*max_norm;
+ return eps_pri;
+}
+
+//! Compute dual eps for the stopping criterion
+Real getEpsDual(const Real eps_abs, const Real eps_rel, const MACGrid &y) {
+ Real eps_dual = sqrt(y.is3D() ? 3.0 : 2.0)*eps_abs + eps_rel*y.getMaxAbs();
+ return eps_dual;
+}
+
+//! Create a spiral velocity field in 2D as a test scene (optionally in 3D)
+void getSpiralVelocity(const FlagGrid &flags, MACGrid &vel, Real strength = 1.0, bool with3D=false) {
+ int nx = flags.getSizeX(), ny = flags.getSizeY(), nz = 1;
+ if (with3D) nz = flags.getSizeZ();
+ Real midX = 0.5*(Real)(nx - 1);
+ Real midY = 0.5*(Real)(ny - 1);
+ Real midZ = 0.5*(Real)(nz - 1);
+ for (int i = 0; i < nx; i++) {
+ for (int j = 0; j < ny; j++) {
+ for (int k = 0; k < nz; k++) {
+ int idx = flags.index(i, j, k);
+ Real diffX = midX - i;
+ Real diffY = midY - j;
+ Real hypotenuse = sqrt(diffX*diffX + diffY*diffY);
+ if (hypotenuse > 0) {
+ vel[idx].x = diffY / hypotenuse;
+ vel[idx].y = -diffX / hypotenuse;
+ }
+ }
+ }
+ }
+ vel.multConst(strength);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getSpiralVelocity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); Real strength = _args.getOpt<Real >("strength",2,1.0,&_lock); bool with3D = _args.getOpt<bool >("with3D",3,false,&_lock); _retval = getPyNone(); getSpiralVelocity(flags,vel,strength,with3D); _args.check(); }
+ pbFinalizePlugin(parent,"getSpiralVelocity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getSpiralVelocity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getSpiralVelocity ("","getSpiralVelocity",_W_0);
+extern "C" {
+ void PbRegister_getSpiralVelocity() {
+ KEEP_UNUSED(_RP_getSpiralVelocity); }
+ }
+
+
+
+//! Set the guiding weight W as a gradient in the y-direction
+void setGradientYWeight(Grid<Real> &W, const int minY, const int maxY, const Real valAtMin, const Real valAtMax) {
+ FOR_IJK(W) {
+ if (minY <= j && j <= maxY) {
+ Real val = valAtMin;
+ if (valAtMax != valAtMin) {
+ Real ratio = (Real)(j - minY) / (Real)(maxY - minY);
+ val = ratio*valAtMax + (1.0 - ratio)*valAtMin;
+ }
+ W(i, j, k) = val;
+ }
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setGradientYWeight" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & W = *_args.getPtr<Grid<Real> >("W",0,&_lock); const int minY = _args.get<int >("minY",1,&_lock); const int maxY = _args.get<int >("maxY",2,&_lock); const Real valAtMin = _args.get<Real >("valAtMin",3,&_lock); const Real valAtMax = _args.get<Real >("valAtMax",4,&_lock); _retval = getPyNone(); setGradientYWeight(W,minY,maxY,valAtMin,valAtMax); _args.check(); }
+ pbFinalizePlugin(parent,"setGradientYWeight", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setGradientYWeight",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setGradientYWeight ("","setGradientYWeight",_W_1);
+extern "C" {
+ void PbRegister_setGradientYWeight() {
+ KEEP_UNUSED(_RP_setGradientYWeight); }
+ }
+
+
+
+// *****************************************************************************
+// More helper functions for fluid guiding
+
+//! Apply Gaussian blur (either 2D or 3D) in a separable way
+void applySeparableGaussianBlur(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel1D) {
+ assertMsg(gBlurPrecomputed, "Error - blue kernel not precomputed");
+ applySeparableKernel(grid, flags, kernel1D);
+}
+
+//! Precomputation performed before the first PD iteration
+void ADMM_precompute_Separable(int blurRadius) {
+ if (gBlurPrecomputed) {
+ assertMsg( gBlurKernelRadius == blurRadius, "More than a single blur radius not supported at the moment." );
+ return;
+ }
+ int kernelSize = 2 * blurRadius + 1;
+ gBlurKernel = get1DGaussianBlurKernel(kernelSize, kernelSize);
+ gBlurPrecomputed = true;
+ gBlurKernelRadius = blurRadius;
+}
+
+//! Apply approximate multiplication of inverse(M)
+void applyApproxInvM(MACGrid& v, const FlagGrid &flags, const MACGrid& invA) {
+ MACGrid v_new = MACGrid(v.getParent());
+ v_new.copyFrom(v);
+ v_new.mult(invA);
+ applySeparableGaussianBlur(v_new, flags, gBlurKernel);
+ applySeparableGaussianBlur(v_new, flags, gBlurKernel);
+ v_new.multConst(2.0);
+ v_new.mult(invA);
+ v.mult(invA);
+ v.sub(v_new);
+}
+
+//! Precompute Q, a reused quantity in the PD iterations
+//! Q = 2*G*G*(velT-velC)-sigma*velC
+void precomputeQ(MACGrid &Q, const FlagGrid &flags, const MACGrid &velT_region, const MACGrid &velC, const Matrix &gBlurKernel, const Real sigma) {
+ Q.copyFrom(velT_region);
+ Q.sub(velC);
+ applySeparableGaussianBlur(Q, flags, gBlurKernel);
+ applySeparableGaussianBlur(Q, flags, gBlurKernel);
+ Q.multConst(2.0);
+ Q.addScaled(velC, -sigma);
+}
+
+//! Precompute inverse(A), a reused quantity in the PD iterations
+//! A = 2*S^2 + p*I, invA = elementwise 1/A
+void precomputeInvA(MACGrid &invA, const Grid<Real> &weight, const Real sigma) {
+ FOR_IJK(invA) {
+ Real val = 2 * weight(i, j, k)*weight(i, j, k) + sigma;
+ if (val<0.01) val = 0.01;
+ Real invVal = 1.0 / val;
+ invA(i, j, k).x = invVal;
+ invA(i, j, k).y = invVal;
+ invA(i, j, k).z = invVal;
+ }
+}
+
+//! proximal operator of f , guiding
+void prox_f(MACGrid& v, const FlagGrid &flags, const MACGrid& Q, const MACGrid& velC, const Real sigma, const MACGrid& invA) {
+ v.multConst(sigma);
+ v.add(Q);
+ applyApproxInvM(v, flags, invA);
+ v.add(velC);
+}
+
+// *****************************************************************************
+
+// re-uses main pressure solve from pressure.cpp
+void solvePressure(
+ MACGrid& vel, Grid<Real>& pressure, const FlagGrid& flags, Real cgAccuracy = 1e-3,
+ const Grid<Real>* phi = 0,
+ const Grid<Real>* perCellCorr = 0,
+ const MACGrid* fractions = 0,
+ Real gfClamp = 1e-04,
+ Real cgMaxIterFac = 1.5,
+ bool precondition = true,
+ int preconditioner = 1,
+ bool enforceCompatibility = false,
+ bool useL2Norm = false,
+ bool zeroPressureFixing = false,
+ const Grid<Real> *curv = NULL,
+ const Real surfTens = 0.0,
+ Grid<Real>* retRhs = NULL );
+
+//! Main function for fluid guiding , includes "regular" pressure solve
+
+
+
+
+
+
+
+void PD_fluid_guiding(MACGrid& vel, MACGrid& velT, Grid<Real>& pressure, FlagGrid& flags, Grid<Real>& weight, int blurRadius = 5, Real theta = 1.0, Real tau = 1.0, Real sigma = 1.0, Real epsRel = 1e-3, Real epsAbs = 1e-3, int maxIters = 200, Grid<Real>* phi = 0, Grid<Real>* perCellCorr = 0, MACGrid* fractions = 0, Real gfClamp = 1e-04, Real cgMaxIterFac = 1.5, Real cgAccuracy = 1e-3, int preconditioner = 1, bool zeroPressureFixing = false, const Grid<Real> *curv = NULL, const Real surfTens = 0.) {
+ FluidSolver* parent = vel.getParent();
+
+ // initialize dual/slack variables
+ MACGrid velC = MACGrid(parent); velC.copyFrom(vel);
+ MACGrid x = MACGrid(parent);
+ MACGrid y = MACGrid(parent);
+ MACGrid z = MACGrid(parent);
+ MACGrid x0 = MACGrid(parent);
+ MACGrid z0 = MACGrid(parent);
+
+ // precomputation
+ ADMM_precompute_Separable(blurRadius);
+ MACGrid Q = MACGrid(parent);
+ precomputeQ(Q, flags, velT, velC, gBlurKernel, sigma);
+ MACGrid invA = MACGrid(parent);
+ precomputeInvA(invA, weight, sigma);
+
+ // loop
+ int iter = 0;
+ for (iter = 0; iter < maxIters; iter++) {
+ // x-update
+ x0.copyFrom(x);
+ x.multConst(1.0 / sigma);
+ x.add(y);
+ prox_f(x, flags, Q, velC, sigma, invA);
+ x.multConst(-sigma); x.addScaled(y, sigma); x.add(x0);
+
+ // z-update
+ z0.copyFrom(z);
+ z.addScaled(x, -tau);
+ Real cgAccuracyAdaptive = cgAccuracy;
+
+ solvePressure (z, pressure, flags, cgAccuracyAdaptive, phi, perCellCorr, fractions, gfClamp,
+ cgMaxIterFac, true, preconditioner, false, false, zeroPressureFixing, curv, surfTens );
+
+ // y-update
+ y.copyFrom(z);
+ y.sub(z0);
+ y.multConst(theta);
+ y.add(z);
+
+ // stopping criterion
+ bool stop = (iter > 0 && getRNorm(z, z0) < getEpsDual(epsAbs, epsRel, z));
+
+ if (stop || (iter == maxIters - 1)) break;
+ }
+
+ // vel_new = z
+ vel.copyFrom(z);
+
+ debMsg("PD_fluid_guiding iterations:" << iter, 1);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "PD_fluid_guiding" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); MACGrid& velT = *_args.getPtr<MACGrid >("velT",1,&_lock); Grid<Real>& pressure = *_args.getPtr<Grid<Real> >("pressure",2,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",3,&_lock); Grid<Real>& weight = *_args.getPtr<Grid<Real> >("weight",4,&_lock); int blurRadius = _args.getOpt<int >("blurRadius",5,5,&_lock); Real theta = _args.getOpt<Real >("theta",6,1.0,&_lock); Real tau = _args.getOpt<Real >("tau",7,1.0,&_lock); Real sigma = _args.getOpt<Real >("sigma",8,1.0,&_lock); Real epsRel = _args.getOpt<Real >("epsRel",9,1e-3,&_lock); Real epsAbs = _args.getOpt<Real >("epsAbs",10,1e-3,&_lock); int maxIters = _args.getOpt<int >("maxIters",11,200,&_lock); Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",12,0,&_lock); Grid<Real>* perCellCorr = _args.getPtrOpt<Grid<Real> >("perCellCorr",13,0,&_lock); MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",14,0,&_lock); Real gfClamp = _args.getOpt<Real >("gfClamp",15,1e-04,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",16,1.5,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",17,1e-3,&_lock); int preconditioner = _args.getOpt<int >("preconditioner",18,1,&_lock); bool zeroPressureFixing = _args.getOpt<bool >("zeroPressureFixing",19,false,&_lock); const Grid<Real> * curv = _args.getPtrOpt<Grid<Real> >("curv",20,NULL,&_lock); const Real surfTens = _args.getOpt<Real >("surfTens",21,0.,&_lock); _retval = getPyNone(); PD_fluid_guiding(vel,velT,pressure,flags,weight,blurRadius,theta,tau,sigma,epsRel,epsAbs,maxIters,phi,perCellCorr,fractions,gfClamp,cgMaxIterFac,cgAccuracy,preconditioner,zeroPressureFixing,curv,surfTens); _args.check(); }
+ pbFinalizePlugin(parent,"PD_fluid_guiding", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("PD_fluid_guiding",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_PD_fluid_guiding ("","PD_fluid_guiding",_W_2);
+extern "C" {
+ void PbRegister_PD_fluid_guiding() {
+ KEEP_UNUSED(_RP_PD_fluid_guiding); }
+ }
+
+
+
+//! reset precomputation
+void releaseBlurPrecomp() {
+ gBlurPrecomputed = false;
+ gBlurKernelRadius = -1;
+ gBlurKernel = 0.f;
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "releaseBlurPrecomp" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; _retval = getPyNone(); releaseBlurPrecomp(); _args.check(); }
+ pbFinalizePlugin(parent,"releaseBlurPrecomp", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("releaseBlurPrecomp",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_releaseBlurPrecomp ("","releaseBlurPrecomp",_W_3);
+extern "C" {
+ void PbRegister_releaseBlurPrecomp() {
+ KEEP_UNUSED(_RP_releaseBlurPrecomp); }
+ }
+
+
+
+
+} // end namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/initplugins.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/initplugins.cpp
new file mode 100644
index 00000000000..63f18a8e38b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/initplugins.cpp
@@ -0,0 +1,1167 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Tools to setup fields and inflows
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "shapes.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include "noisefield.h"
+#include "mesh.h"
+
+// disable saving projected images as ppms in blender
+#if BLENDER!=1
+#include "simpleimage.h"
+#endif
+
+using namespace std;
+
+namespace Manta {
+
+//! Apply noise to grid
+
+
+ struct KnApplyNoiseInfl : public KernelBase {
+ KnApplyNoiseInfl(const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, const Grid<Real>& sdf, Real scale, Real sigma) : KernelBase(&flags,0) ,flags(flags),density(density),noise(noise),sdf(sdf),scale(scale),sigma(sigma) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, const Grid<Real>& sdf, Real scale, Real sigma ) const {
+ if (!flags.isFluid(i,j,k) || sdf(i,j,k) > sigma) return;
+ Real factor = clamp(1.0-0.5/sigma * (sdf(i,j,k)+sigma), 0.0, 1.0);
+
+ Real target = noise.evaluate(Vec3(i,j,k)) * scale * factor;
+ if (density(i,j,k) < target)
+ density(i,j,k) = target;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return density; }
+ typedef Grid<Real> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline const Grid<Real>& getArg3() {
+ return sdf; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return scale; }
+ typedef Real type4;inline Real& getArg5() {
+ return sigma; }
+ typedef Real type5; void runMessage() { debMsg("Executing kernel KnApplyNoiseInfl ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,density,noise,sdf,scale,sigma); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,density,noise,sdf,scale,sigma); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; Grid<Real>& density; const WaveletNoiseField& noise; const Grid<Real>& sdf; Real scale; Real sigma; }
+;
+
+//! Init noise-modulated density inside shape
+
+void densityInflow(const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, Shape* shape, Real scale=1.0, Real sigma=0) {
+ Grid<Real> sdf = shape->computeLevelset();
+ KnApplyNoiseInfl(flags, density, noise, sdf, scale, sigma);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "densityInflow" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Shape* shape = _args.getPtr<Shape >("shape",3,&_lock); Real scale = _args.getOpt<Real >("scale",4,1.0,&_lock); Real sigma = _args.getOpt<Real >("sigma",5,0,&_lock); _retval = getPyNone(); densityInflow(flags,density,noise,shape,scale,sigma); _args.check(); }
+ pbFinalizePlugin(parent,"densityInflow", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("densityInflow",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_densityInflow ("","densityInflow",_W_0);
+extern "C" {
+ void PbRegister_densityInflow() {
+ KEEP_UNUSED(_RP_densityInflow); }
+ }
+
+
+//! Apply noise to real grid based on an SDF
+ struct KnAddNoise : public KernelBase {
+ KnAddNoise(const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, const Grid<Real>* sdf, Real scale) : KernelBase(&flags,0) ,flags(flags),density(density),noise(noise),sdf(sdf),scale(scale) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, const Grid<Real>* sdf, Real scale ) const {
+ if (!flags.isFluid(i,j,k) || (sdf && (*sdf)(i,j,k) > 0.) ) return;
+ density(i,j,k) += noise.evaluate(Vec3(i,j,k)) * scale;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return density; }
+ typedef Grid<Real> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline const Grid<Real>* getArg3() {
+ return sdf; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return scale; }
+ typedef Real type4; void runMessage() { debMsg("Executing kernel KnAddNoise ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,density,noise,sdf,scale); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,density,noise,sdf,scale); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; Grid<Real>& density; const WaveletNoiseField& noise; const Grid<Real>* sdf; Real scale; }
+;
+void addNoise(const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, const Grid<Real>* sdf=NULL, Real scale=1.0 ) {
+ KnAddNoise(flags, density, noise, sdf, scale );
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addNoise" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); const Grid<Real>* sdf = _args.getPtrOpt<Grid<Real> >("sdf",3,NULL,&_lock); Real scale = _args.getOpt<Real >("scale",4,1.0 ,&_lock); _retval = getPyNone(); addNoise(flags,density,noise,sdf,scale); _args.check(); }
+ pbFinalizePlugin(parent,"addNoise", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addNoise",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addNoise ("","addNoise",_W_1);
+extern "C" {
+ void PbRegister_addNoise() {
+ KEEP_UNUSED(_RP_addNoise); }
+ }
+
+
+
+//! sample noise field and set pdata with its values (for convenience, scale the noise values)
+
+template <class T> struct knSetPdataNoise : public KernelBase {
+ knSetPdataNoise(const BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, const WaveletNoiseField& noise, Real scale) : KernelBase(parts.size()) ,parts(parts),pdata(pdata),noise(noise),scale(scale) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, const WaveletNoiseField& noise, Real scale ) const {
+ pdata[idx] = noise.evaluate( parts.getPos(idx) ) * scale;
+} inline const BasicParticleSystem& getArg0() {
+ return parts; }
+ typedef BasicParticleSystem type0;inline ParticleDataImpl<T>& getArg1() {
+ return pdata; }
+ typedef ParticleDataImpl<T> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Real& getArg3() {
+ return scale; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel knSetPdataNoise ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, parts,pdata,noise,scale); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystem& parts; ParticleDataImpl<T>& pdata; const WaveletNoiseField& noise; Real scale; }
+;
+
+template <class T> struct knSetPdataNoiseVec : public KernelBase {
+ knSetPdataNoiseVec(const BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, const WaveletNoiseField& noise, Real scale) : KernelBase(parts.size()) ,parts(parts),pdata(pdata),noise(noise),scale(scale) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, const WaveletNoiseField& noise, Real scale ) const {
+ pdata[idx] = noise.evaluateVec( parts.getPos(idx) ) * scale;
+} inline const BasicParticleSystem& getArg0() {
+ return parts; }
+ typedef BasicParticleSystem type0;inline ParticleDataImpl<T>& getArg1() {
+ return pdata; }
+ typedef ParticleDataImpl<T> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Real& getArg3() {
+ return scale; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel knSetPdataNoiseVec ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, parts,pdata,noise,scale); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystem& parts; ParticleDataImpl<T>& pdata; const WaveletNoiseField& noise; Real scale; }
+;
+void setNoisePdata(const BasicParticleSystem& parts, ParticleDataImpl<Real>& pd, const WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoise<Real>(parts, pd,noise,scale); } static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setNoisePdata" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<Real>& pd = *_args.getPtr<ParticleDataImpl<Real> >("pd",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.,&_lock); _retval = getPyNone(); setNoisePdata(parts,pd,noise,scale); _args.check(); }
+ pbFinalizePlugin(parent,"setNoisePdata", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setNoisePdata",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setNoisePdata ("","setNoisePdata",_W_2);
+extern "C" {
+ void PbRegister_setNoisePdata() {
+ KEEP_UNUSED(_RP_setNoisePdata); }
+ }
+
+
+void setNoisePdataVec3(const BasicParticleSystem& parts, ParticleDataImpl<Vec3>& pd, const WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoiseVec<Vec3>(parts, pd,noise,scale); } static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setNoisePdataVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<Vec3>& pd = *_args.getPtr<ParticleDataImpl<Vec3> >("pd",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.,&_lock); _retval = getPyNone(); setNoisePdataVec3(parts,pd,noise,scale); _args.check(); }
+ pbFinalizePlugin(parent,"setNoisePdataVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setNoisePdataVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setNoisePdataVec3 ("","setNoisePdataVec3",_W_3);
+extern "C" {
+ void PbRegister_setNoisePdataVec3() {
+ KEEP_UNUSED(_RP_setNoisePdataVec3); }
+ }
+
+
+void setNoisePdataInt(const BasicParticleSystem& parts, ParticleDataImpl<int >& pd, const WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoise<int> (parts, pd,noise,scale); } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setNoisePdataInt" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<int >& pd = *_args.getPtr<ParticleDataImpl<int > >("pd",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.,&_lock); _retval = getPyNone(); setNoisePdataInt(parts,pd,noise,scale); _args.check(); }
+ pbFinalizePlugin(parent,"setNoisePdataInt", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setNoisePdataInt",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setNoisePdataInt ("","setNoisePdataInt",_W_4);
+extern "C" {
+ void PbRegister_setNoisePdataInt() {
+ KEEP_UNUSED(_RP_setNoisePdataInt); }
+ }
+
+
+
+//! SDF gradient from obstacle flags, for turbulence.py
+// FIXME, slow, without kernel...
+Grid<Vec3> obstacleGradient(const FlagGrid& flags) {
+ LevelsetGrid levelset(flags.getParent(),false);
+ Grid<Vec3> gradient(flags.getParent());
+
+ // rebuild obstacle levelset
+ FOR_IDX(levelset) {
+ levelset[idx] = flags.isObstacle(idx) ? -0.5 : 0.5;
+ }
+ levelset.reinitMarching(flags, 6.0, 0, true, false, FlagGrid::TypeReserved);
+
+ // build levelset gradient
+ GradientOp(gradient, levelset);
+
+ FOR_IDX(levelset) {
+ Vec3 grad = gradient[idx];
+ Real s = normalize(grad);
+ if (s <= 0.1 || levelset[idx] >= 0)
+ grad=Vec3(0.);
+ gradient[idx] = grad * levelset[idx];
+ }
+
+ return gradient;
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "obstacleGradient" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); _retval = toPy(obstacleGradient(flags)); _args.check(); }
+ pbFinalizePlugin(parent,"obstacleGradient", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("obstacleGradient",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_obstacleGradient ("","obstacleGradient",_W_5);
+extern "C" {
+ void PbRegister_obstacleGradient() {
+ KEEP_UNUSED(_RP_obstacleGradient); }
+ }
+
+
+
+//! SDF from obstacle flags, for turbulence.py
+LevelsetGrid obstacleLevelset(const FlagGrid& flags) {
+ LevelsetGrid levelset(flags.getParent(),false);
+
+ // rebuild obstacle levelset
+ FOR_IDX(levelset) {
+ levelset[idx] = flags.isObstacle(idx) ? -0.5 : 0.5;
+ }
+ levelset.reinitMarching(flags, 6.0, 0, true, false, FlagGrid::TypeReserved);
+
+ return levelset;
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "obstacleLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); _retval = toPy(obstacleLevelset(flags)); _args.check(); }
+ pbFinalizePlugin(parent,"obstacleLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("obstacleLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_obstacleLevelset ("","obstacleLevelset",_W_6);
+extern "C" {
+ void PbRegister_obstacleLevelset() {
+ KEEP_UNUSED(_RP_obstacleLevelset); }
+ }
+
+
+
+
+//*****************************************************************************
+// blender init functions
+
+
+
+ struct KnApplyEmission : public KernelBase {
+ KnApplyEmission(const FlagGrid& flags, Grid<Real>& target, const Grid<Real>& source, const Grid<Real>* emissionTexture, bool isAbsolute, int type) : KernelBase(&flags,0) ,flags(flags),target(target),source(source),emissionTexture(emissionTexture),isAbsolute(isAbsolute),type(type) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& target, const Grid<Real>& source, const Grid<Real>* emissionTexture, bool isAbsolute, int type ) const {
+ // if type is given, only apply emission when celltype matches type from flaggrid
+ // and if emission texture is given, only apply emission when some emission is present at cell (important for emit from particles)
+ bool isInflow = (type & FlagGrid::TypeInflow && flags.isInflow(i,j,k));
+ bool isOutflow = (type & FlagGrid::TypeOutflow && flags.isOutflow(i,j,k));
+ if ( (type && !isInflow && !isOutflow) && (emissionTexture && !(*emissionTexture)(i,j,k)) ) return;
+
+ if (isAbsolute)
+ target(i,j,k) = source(i,j,k);
+ else
+ target(i,j,k) += source(i,j,k);
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return target; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return source; }
+ typedef Grid<Real> type2;inline const Grid<Real>* getArg3() {
+ return emissionTexture; }
+ typedef Grid<Real> type3;inline bool& getArg4() {
+ return isAbsolute; }
+ typedef bool type4;inline int& getArg5() {
+ return type; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnApplyEmission ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,target,source,emissionTexture,isAbsolute,type); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,target,source,emissionTexture,isAbsolute,type); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; Grid<Real>& target; const Grid<Real>& source; const Grid<Real>* emissionTexture; bool isAbsolute; int type; }
+;
+
+//! Add emission values
+//isAbsolute: whether to add emission values to existing, or replace
+void applyEmission(FlagGrid& flags, Grid<Real>& target, Grid<Real>& source, Grid<Real>* emissionTexture=NULL, bool isAbsolute=true, int type=0) {
+ KnApplyEmission(flags, target, source, emissionTexture, isAbsolute, type);
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "applyEmission" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",1,&_lock); Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",2,&_lock); Grid<Real>* emissionTexture = _args.getPtrOpt<Grid<Real> >("emissionTexture",3,NULL,&_lock); bool isAbsolute = _args.getOpt<bool >("isAbsolute",4,true,&_lock); int type = _args.getOpt<int >("type",5,0,&_lock); _retval = getPyNone(); applyEmission(flags,target,source,emissionTexture,isAbsolute,type); _args.check(); }
+ pbFinalizePlugin(parent,"applyEmission", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("applyEmission",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_applyEmission ("","applyEmission",_W_7);
+extern "C" {
+ void PbRegister_applyEmission() {
+ KEEP_UNUSED(_RP_applyEmission); }
+ }
+
+
+
+// blender init functions for meshes
+
+
+
+ struct KnApplyDensity : public KernelBase {
+ KnApplyDensity(const FlagGrid& flags, Grid<Real>& density, const Grid<Real>& sdf, Real value, Real sigma) : KernelBase(&flags,0) ,flags(flags),density(density),sdf(sdf),value(value),sigma(sigma) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& density, const Grid<Real>& sdf, Real value, Real sigma ) const {
+ if (!flags.isFluid(i,j,k) || sdf(i,j,k) > sigma) return;
+ density(i,j,k) = value;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return density; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return sdf; }
+ typedef Grid<Real> type2;inline Real& getArg3() {
+ return value; }
+ typedef Real type3;inline Real& getArg4() {
+ return sigma; }
+ typedef Real type4; void runMessage() { debMsg("Executing kernel KnApplyDensity ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,density,sdf,value,sigma); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,density,sdf,value,sigma); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; Grid<Real>& density; const Grid<Real>& sdf; Real value; Real sigma; }
+;
+//! Init noise-modulated density inside mesh
+
+void densityInflowMeshNoise(const FlagGrid& flags, Grid<Real>& density, const WaveletNoiseField& noise, Mesh* mesh, Real scale=1.0, Real sigma=0) {
+ LevelsetGrid sdf(density.getParent(), false);
+ mesh->computeLevelset(sdf, 1.);
+ KnApplyNoiseInfl(flags, density, noise, sdf, scale, sigma);
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "densityInflowMeshNoise" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Mesh* mesh = _args.getPtr<Mesh >("mesh",3,&_lock); Real scale = _args.getOpt<Real >("scale",4,1.0,&_lock); Real sigma = _args.getOpt<Real >("sigma",5,0,&_lock); _retval = getPyNone(); densityInflowMeshNoise(flags,density,noise,mesh,scale,sigma); _args.check(); }
+ pbFinalizePlugin(parent,"densityInflowMeshNoise", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("densityInflowMeshNoise",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_densityInflowMeshNoise ("","densityInflowMeshNoise",_W_8);
+extern "C" {
+ void PbRegister_densityInflowMeshNoise() {
+ KEEP_UNUSED(_RP_densityInflowMeshNoise); }
+ }
+
+
+
+//! Init constant density inside mesh
+
+void densityInflowMesh(const FlagGrid& flags, Grid<Real>& density, Mesh* mesh, Real value=1., Real cutoff = 7, Real sigma=0) {
+ LevelsetGrid sdf(density.getParent(), false);
+ mesh->computeLevelset(sdf, 2., cutoff);
+ KnApplyDensity(flags, density, sdf, value, sigma);
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "densityInflowMesh" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); Mesh* mesh = _args.getPtr<Mesh >("mesh",2,&_lock); Real value = _args.getOpt<Real >("value",3,1.,&_lock); Real cutoff = _args.getOpt<Real >("cutoff",4,7,&_lock); Real sigma = _args.getOpt<Real >("sigma",5,0,&_lock); _retval = getPyNone(); densityInflowMesh(flags,density,mesh,value,cutoff,sigma); _args.check(); }
+ pbFinalizePlugin(parent,"densityInflowMesh", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("densityInflowMesh",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_densityInflowMesh ("","densityInflowMesh",_W_9);
+extern "C" {
+ void PbRegister_densityInflowMesh() {
+ KEEP_UNUSED(_RP_densityInflowMesh); }
+ }
+
+
+
+
+//*****************************************************************************
+
+//! check for symmetry , optionally enfore by copying
+
+void checkSymmetry( Grid<Real>& a, Grid<Real>* err=NULL, bool symmetrize=false, int axis=0, int bound=0) {
+ const int c = axis;
+ const int s = a.getSize()[c];
+ FOR_IJK(a) {
+ Vec3i idx(i,j,k), mdx(i,j,k);
+ mdx[c] = s-1-idx[c];
+ if( bound>0 && ((!a.isInBounds(idx,bound)) || (!a.isInBounds(mdx,bound))) ) continue;
+
+ if(err) (*err)(idx) = fabs( (double)(a(idx) - a(mdx) ) );
+ if(symmetrize && (idx[c]<s/2)) {
+ a(idx) = a(mdx);
+ }
+ }
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "checkSymmetry" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& a = *_args.getPtr<Grid<Real> >("a",0,&_lock); Grid<Real>* err = _args.getPtrOpt<Grid<Real> >("err",1,NULL,&_lock); bool symmetrize = _args.getOpt<bool >("symmetrize",2,false,&_lock); int axis = _args.getOpt<int >("axis",3,0,&_lock); int bound = _args.getOpt<int >("bound",4,0,&_lock); _retval = getPyNone(); checkSymmetry(a,err,symmetrize,axis,bound); _args.check(); }
+ pbFinalizePlugin(parent,"checkSymmetry", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("checkSymmetry",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_checkSymmetry ("","checkSymmetry",_W_10);
+extern "C" {
+ void PbRegister_checkSymmetry() {
+ KEEP_UNUSED(_RP_checkSymmetry); }
+ }
+
+
+//! check for symmetry , mac grid version
+
+
+void checkSymmetryVec3( Grid<Vec3>& a, Grid<Real>* err=NULL, bool symmetrize=false , int axis=0, int bound=0, int disable=0) {
+ if(err) err->setConst(0.);
+
+ // each dimension is measured separately for flexibility (could be combined)
+ const int c = axis;
+ const int o1 = (c+1)%3;
+ const int o2 = (c+2)%3;
+
+ // x
+ if(! (disable&1) ) {
+ const int s = a.getSize()[c]+1;
+ FOR_IJK(a) {
+ Vec3i idx(i,j,k), mdx(i,j,k);
+ mdx[c] = s-1-idx[c];
+ if(mdx[c] >= a.getSize()[c]) continue;
+ if( bound>0 && ((!a.isInBounds(idx,bound)) || (!a.isInBounds(mdx,bound))) ) continue;
+
+ // special case: center "line" of values , should be zero!
+ if(mdx[c] == idx[c] ) {
+ if(err) (*err)(idx) += fabs( (double)( a(idx)[c] ) );
+ if(symmetrize) a(idx)[c] = 0.;
+ continue;
+ }
+
+ // note - the a(mdx) component needs to be inverted here!
+ if(err) (*err)(idx) += fabs( (double)( a(idx)[c]- (a(mdx)[c]*-1.) ) );
+ if(symmetrize && (idx[c]<s/2)) {
+ a(idx)[c] = a(mdx)[c] * -1.;
+ }
+ }
+ }
+
+ // y
+ if(! (disable&2) ) {
+ const int s = a.getSize()[c];
+ FOR_IJK(a) {
+ Vec3i idx(i,j,k), mdx(i,j,k);
+ mdx[c] = s-1-idx[c];
+ if( bound>0 && ((!a.isInBounds(idx,bound)) || (!a.isInBounds(mdx,bound))) ) continue;
+
+ if(err) (*err)(idx) += fabs( (double)( a(idx)[o1]-a(mdx)[o1] ) );
+ if(symmetrize && (idx[c]<s/2)) {
+ a(idx)[o1] = a(mdx)[o1];
+ }
+ }
+ }
+
+ // z
+ if(! (disable&4) ) {
+ const int s = a.getSize()[c];
+ FOR_IJK(a) {
+ Vec3i idx(i,j,k), mdx(i,j,k);
+ mdx[c] = s-1-idx[c];
+ if( bound>0 && ((!a.isInBounds(idx,bound)) || (!a.isInBounds(mdx,bound))) ) continue;
+
+ if(err) (*err)(idx) += fabs( (double)( a(idx)[o2]-a(mdx)[o2] ) );
+ if(symmetrize && (idx[c]<s/2)) {
+ a(idx)[o2] = a(mdx)[o2];
+ }
+ }
+ }
+
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "checkSymmetryVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& a = *_args.getPtr<Grid<Vec3> >("a",0,&_lock); Grid<Real>* err = _args.getPtrOpt<Grid<Real> >("err",1,NULL,&_lock); bool symmetrize = _args.getOpt<bool >("symmetrize",2,false ,&_lock); int axis = _args.getOpt<int >("axis",3,0,&_lock); int bound = _args.getOpt<int >("bound",4,0,&_lock); int disable = _args.getOpt<int >("disable",5,0,&_lock); _retval = getPyNone(); checkSymmetryVec3(a,err,symmetrize,axis,bound,disable); _args.check(); }
+ pbFinalizePlugin(parent,"checkSymmetryVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("checkSymmetryVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_checkSymmetryVec3 ("","checkSymmetryVec3",_W_11);
+extern "C" {
+ void PbRegister_checkSymmetryVec3() {
+ KEEP_UNUSED(_RP_checkSymmetryVec3); }
+ }
+
+
+
+#if BLENDER!=1
+// from simpleimage.cpp
+void projectImg(SimpleImage& img, const Grid<Real>& val, int shadeMode = 0, Real scale = 1.);
+#endif
+
+//! output shaded (all 3 axes at once for 3D)
+//! shading modes: 0 smoke, 1 surfaces
+
+void projectPpmFull( const Grid<Real>& val, string name, int shadeMode=0, Real scale=1.) {
+ #if BLENDER!=1
+ SimpleImage img;
+ projectImg( img, val, shadeMode, scale );
+ img.writePpm( name );
+ #endif
+} static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "projectPpmFull" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& val = *_args.getPtr<Grid<Real> >("val",0,&_lock); string name = _args.get<string >("name",1,&_lock); int shadeMode = _args.getOpt<int >("shadeMode",2,0,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.,&_lock); _retval = getPyNone(); projectPpmFull(val,name,shadeMode,scale); _args.check(); }
+ pbFinalizePlugin(parent,"projectPpmFull", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("projectPpmFull",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_projectPpmFull ("","projectPpmFull",_W_12);
+extern "C" {
+ void PbRegister_projectPpmFull() {
+ KEEP_UNUSED(_RP_projectPpmFull); }
+ }
+
+
+
+// helper functions for pdata operator tests
+
+//! init some test particles at the origin
+
+void addTestParts( BasicParticleSystem& parts, int num) {
+ for(int i=0; i<num; ++i)
+ parts.addBuffered( Vec3(0,0,0) );
+
+ parts.doCompress();
+ parts.insertBufferedParticles();
+} static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addTestParts" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); int num = _args.get<int >("num",1,&_lock); _retval = getPyNone(); addTestParts(parts,num); _args.check(); }
+ pbFinalizePlugin(parent,"addTestParts", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addTestParts",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addTestParts ("","addTestParts",_W_13);
+extern "C" {
+ void PbRegister_addTestParts() {
+ KEEP_UNUSED(_RP_addTestParts); }
+ }
+
+
+
+//! calculate the difference between two pdata fields (note - slow!, not parallelized)
+
+Real pdataMaxDiff( const ParticleDataBase* a, const ParticleDataBase* b ) {
+ double maxVal = 0.;
+ //debMsg(" PD "<< a->getType()<<" as"<<a->getSizeSlow()<<" bs"<<b->getSizeSlow() , 1);
+ assertMsg(a->getType() == b->getType() , "pdataMaxDiff problem - different pdata types!");
+ assertMsg(a->getSizeSlow() == b->getSizeSlow(), "pdataMaxDiff problem - different pdata sizes!");
+
+ if (a->getType() & ParticleDataBase::TypeReal)
+ {
+ const ParticleDataImpl<Real>& av = *dynamic_cast<const ParticleDataImpl<Real>*>(a);
+ const ParticleDataImpl<Real>& bv = *dynamic_cast<const ParticleDataImpl<Real>*>(b);
+ FOR_PARTS(av) {
+ maxVal = std::max(maxVal, (double)fabs( av[idx]-bv[idx] ));
+ }
+ } else if (a->getType() & ParticleDataBase::TypeInt)
+ {
+ const ParticleDataImpl<int>& av = *dynamic_cast<const ParticleDataImpl<int>*>(a);
+ const ParticleDataImpl<int>& bv = *dynamic_cast<const ParticleDataImpl<int>*>(b);
+ FOR_PARTS(av) {
+ maxVal = std::max(maxVal, (double)fabs( (double)av[idx]-bv[idx] ));
+ }
+ } else if (a->getType() & ParticleDataBase::TypeVec3) {
+ const ParticleDataImpl<Vec3>& av = *dynamic_cast<const ParticleDataImpl<Vec3>*>(a);
+ const ParticleDataImpl<Vec3>& bv = *dynamic_cast<const ParticleDataImpl<Vec3>*>(b);
+ FOR_PARTS(av) {
+ double d = 0.;
+ for(int c=0; c<3; ++c) {
+ d += fabs( (double)av[idx][c] - (double)bv[idx][c] );
+ }
+ maxVal = std::max(maxVal, d );
+ }
+ } else {
+ errMsg("pdataMaxDiff: Grid Type is not supported (only Real, Vec3, int)");
+ }
+
+ return maxVal;
+} static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "pdataMaxDiff" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const ParticleDataBase* a = _args.getPtr<ParticleDataBase >("a",0,&_lock); const ParticleDataBase* b = _args.getPtr<ParticleDataBase >("b",1,&_lock); _retval = toPy(pdataMaxDiff(a,b)); _args.check(); }
+ pbFinalizePlugin(parent,"pdataMaxDiff", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("pdataMaxDiff",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_pdataMaxDiff ("","pdataMaxDiff",_W_14);
+extern "C" {
+ void PbRegister_pdataMaxDiff() {
+ KEEP_UNUSED(_RP_pdataMaxDiff); }
+ }
+
+
+
+
+//! calculate center of mass given density grid, for re-centering
+
+Vec3 calcCenterOfMass(const Grid<Real>& density) {
+ Vec3 p(0.0f);
+ Real w = 0.0f;
+ FOR_IJK(density){
+ p += density(i, j, k) * Vec3(i + 0.5f, j + 0.5f, k + 0.5f);
+ w += density(i, j, k);
+ }
+ if (w > 1e-6f)
+ p /= w;
+ return p;
+} static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "calcCenterOfMass" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",0,&_lock); _retval = toPy(calcCenterOfMass(density)); _args.check(); }
+ pbFinalizePlugin(parent,"calcCenterOfMass", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("calcCenterOfMass",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_calcCenterOfMass ("","calcCenterOfMass",_W_15);
+extern "C" {
+ void PbRegister_calcCenterOfMass() {
+ KEEP_UNUSED(_RP_calcCenterOfMass); }
+ }
+
+
+
+
+//*****************************************************************************
+// helper functions for volume fractions (which are needed for second order obstacle boundaries)
+
+
+
+inline static Real calcFraction(Real phi1, Real phi2)
+{
+ if(phi1>0. && phi2>0.) return 1.;
+ if(phi1<0. && phi2<0.) return 0.;
+
+ // make sure phi1 < phi2
+ if (phi2<phi1) { Real t = phi1; phi1= phi2; phi2 = t; }
+ Real denom = phi1-phi2;
+ if (denom > -1e-04) return 0.5;
+
+ Real frac = 1. - phi1/denom;
+ if(frac<0.01) frac = 0.; // stomp small values , dont mark as fluid
+ return std::min(Real(1), frac );
+}
+
+
+ struct KnUpdateFractions : public KernelBase {
+ KnUpdateFractions(const FlagGrid& flags, const Grid<Real>& phiObs, MACGrid& fractions, const int &boundaryWidth) : KernelBase(&flags,1) ,flags(flags),phiObs(phiObs),fractions(fractions),boundaryWidth(boundaryWidth) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const Grid<Real>& phiObs, MACGrid& fractions, const int &boundaryWidth ) const {
+
+ // walls at domain bounds and inner objects
+ fractions(i,j,k).x = calcFraction( phiObs(i,j,k) , phiObs(i-1,j,k));
+ fractions(i,j,k).y = calcFraction( phiObs(i,j,k) , phiObs(i,j-1,k));
+ if(phiObs.is3D()) {
+ fractions(i,j,k).z = calcFraction( phiObs(i,j,k) , phiObs(i,j,k-1));
+ }
+
+ // remaining BCs at the domain boundaries
+ const int w = boundaryWidth;
+ // only set if not in obstacle
+ if(phiObs(i,j,k)<0.) return;
+
+ // x-direction boundaries
+ if(i <= w+1) { //min x
+ if( (flags.isInflow(i-1,j,k)) ||
+ (flags.isOutflow(i-1,j,k)) ||
+ (flags.isOpen(i-1,j,k)) ) {
+ fractions(i,j,k).x = fractions(i,j,k).y = 1.; if(flags.is3D()) fractions(i,j,k).z = 1.;
+ }
+ }
+ if(i >= flags.getSizeX()-w-2) { //max x
+ if( (flags.isInflow(i+1,j,k)) ||
+ (flags.isOutflow(i+1,j,k)) ||
+ (flags.isOpen(i+1,j,k)) ) {
+ fractions(i+1,j,k).x = fractions(i+1,j,k).y = 1.; if(flags.is3D()) fractions(i+1,j,k).z = 1.;
+ }
+ }
+ // y-direction boundaries
+ if(j <= w+1) { //min y
+ if( (flags.isInflow(i,j-1,k)) ||
+ (flags.isOutflow(i,j-1,k)) ||
+ (flags.isOpen(i,j-1,k)) ) {
+ fractions(i,j,k).x = fractions(i,j,k).y = 1.; if(flags.is3D()) fractions(i,j,k).z = 1.;
+ }
+ }
+ if(j >= flags.getSizeY()-w-2) { //max y
+ if( (flags.isInflow(i,j+1,k)) ||
+ (flags.isOutflow(i,j+1,k)) ||
+ (flags.isOpen(i,j+1,k)) ) {
+ fractions(i,j+1,k).x = fractions(i,j+1,k).y = 1.; if(flags.is3D()) fractions(i,j+1,k).z = 1.;
+ }
+ }
+ // z-direction boundaries
+ if(flags.is3D()) {
+ if(k <= w+1) { //min z
+ if( (flags.isInflow(i,j,k-1)) ||
+ (flags.isOutflow(i,j,k-1)) ||
+ (flags.isOpen(i,j,k-1)) ) {
+ fractions(i,j,k).x = fractions(i,j,k).y = 1.; if(flags.is3D()) fractions(i,j,k).z = 1.;
+ }
+ }
+ if(j >= flags.getSizeZ()-w-2) { //max z
+ if( (flags.isInflow(i,j,k+1)) ||
+ (flags.isOutflow(i,j,k+1)) ||
+ (flags.isOpen(i,j,k+1)) ) {
+ fractions(i,j,k+1).x = fractions(i,j,k+1).y = 1.; if(flags.is3D()) fractions(i,j,k+1).z = 1.;
+ }
+ }
+ }
+
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const Grid<Real>& getArg1() {
+ return phiObs; }
+ typedef Grid<Real> type1;inline MACGrid& getArg2() {
+ return fractions; }
+ typedef MACGrid type2;inline const int& getArg3() {
+ return boundaryWidth; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel KnUpdateFractions ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,phiObs,fractions,boundaryWidth); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,phiObs,fractions,boundaryWidth); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; const Grid<Real>& phiObs; MACGrid& fractions; const int& boundaryWidth; }
+;
+
+//! update fill fraction values
+void updateFractions(const FlagGrid& flags, const Grid<Real>& phiObs, MACGrid& fractions, const int &boundaryWidth=0) {
+ fractions.setConst( Vec3(0.) );
+ KnUpdateFractions(flags, phiObs, fractions, boundaryWidth);
+} static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "updateFractions" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const Grid<Real>& phiObs = *_args.getPtr<Grid<Real> >("phiObs",1,&_lock); MACGrid& fractions = *_args.getPtr<MACGrid >("fractions",2,&_lock); const int& boundaryWidth = _args.getOpt<int >("boundaryWidth",3,0,&_lock); _retval = getPyNone(); updateFractions(flags,phiObs,fractions,boundaryWidth); _args.check(); }
+ pbFinalizePlugin(parent,"updateFractions", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("updateFractions",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_updateFractions ("","updateFractions",_W_16);
+extern "C" {
+ void PbRegister_updateFractions() {
+ KEEP_UNUSED(_RP_updateFractions); }
+ }
+
+
+
+
+ struct KnUpdateFlagsObs : public KernelBase {
+ KnUpdateFlagsObs(FlagGrid& flags, const MACGrid* fractions, const Grid<Real>& phiObs, const Grid<Real>* phiOut, const Grid<Real>* phiIn) : KernelBase(&flags,1) ,flags(flags),fractions(fractions),phiObs(phiObs),phiOut(phiOut),phiIn(phiIn) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, FlagGrid& flags, const MACGrid* fractions, const Grid<Real>& phiObs, const Grid<Real>* phiOut, const Grid<Real>* phiIn ) const {
+
+ bool isObs = false;
+ if(fractions) {
+ Real f = 0.;
+ f += fractions->get(i ,j,k).x;
+ f += fractions->get(i+1,j,k).x;
+ f += fractions->get(i,j ,k).y;
+ f += fractions->get(i,j+1,k).y;
+ if (flags.is3D()) {
+ f += fractions->get(i,j,k ).z;
+ f += fractions->get(i,j,k+1).z; }
+ if(f==0.) isObs = true;
+ } else {
+ if(phiObs(i,j,k) < 0.) isObs = true;
+ }
+
+ bool isOutflow = false;
+ bool isInflow = false;
+ if (phiOut && (*phiOut)(i,j,k) < 0.) isOutflow = true;
+ if (phiIn && (*phiIn)(i,j,k) < 0.) isInflow = true;
+
+ if (isObs) flags(i,j,k) = FlagGrid::TypeObstacle;
+ else if (isInflow) flags(i,j,k) = (FlagGrid::TypeFluid | FlagGrid::TypeInflow);
+ else if (isOutflow) flags(i,j,k) = (FlagGrid::TypeEmpty | FlagGrid::TypeOutflow);
+ else flags(i,j,k) = FlagGrid::TypeEmpty;
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid* getArg1() {
+ return fractions; }
+ typedef MACGrid type1;inline const Grid<Real>& getArg2() {
+ return phiObs; }
+ typedef Grid<Real> type2;inline const Grid<Real>* getArg3() {
+ return phiOut; }
+ typedef Grid<Real> type3;inline const Grid<Real>* getArg4() {
+ return phiIn; }
+ typedef Grid<Real> type4; void runMessage() { debMsg("Executing kernel KnUpdateFlagsObs ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,fractions,phiObs,phiOut,phiIn); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,fractions,phiObs,phiOut,phiIn); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ FlagGrid& flags; const MACGrid* fractions; const Grid<Real>& phiObs; const Grid<Real>* phiOut; const Grid<Real>* phiIn; }
+;
+
+//! update obstacle and outflow flags from levelsets
+//! optionally uses fill fractions for obstacle
+void setObstacleFlags(FlagGrid& flags, const Grid<Real>& phiObs, const MACGrid* fractions=NULL, const Grid<Real>* phiOut=NULL, const Grid<Real>* phiIn=NULL) {
+ KnUpdateFlagsObs(flags, fractions, phiObs, phiOut, phiIn);
+} static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setObstacleFlags" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const Grid<Real>& phiObs = *_args.getPtr<Grid<Real> >("phiObs",1,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",2,NULL,&_lock); const Grid<Real>* phiOut = _args.getPtrOpt<Grid<Real> >("phiOut",3,NULL,&_lock); const Grid<Real>* phiIn = _args.getPtrOpt<Grid<Real> >("phiIn",4,NULL,&_lock); _retval = getPyNone(); setObstacleFlags(flags,phiObs,fractions,phiOut,phiIn); _args.check(); }
+ pbFinalizePlugin(parent,"setObstacleFlags", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setObstacleFlags",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setObstacleFlags ("","setObstacleFlags",_W_17);
+extern "C" {
+ void PbRegister_setObstacleFlags() {
+ KEEP_UNUSED(_RP_setObstacleFlags); }
+ }
+
+
+
+
+//! small helper for test case test_1040_secOrderBnd.py
+ struct kninitVortexVelocity : public KernelBase {
+ kninitVortexVelocity(const Grid<Real> &phiObs, MACGrid& vel, const Vec3 &center, const Real &radius) : KernelBase(&phiObs,0) ,phiObs(phiObs),vel(vel),center(center),radius(radius) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Real> &phiObs, MACGrid& vel, const Vec3 &center, const Real &radius ) const {
+
+ if(phiObs(i,j,k) >= -1.) {
+
+ Real dx = i - center.x; if(dx>=0) dx -= .5; else dx += .5;
+ Real dy = j - center.y;
+ Real r = std::sqrt(dx*dx+dy*dy);
+ Real alpha = atan2(dy,dx);
+
+ vel(i,j,k).x = -std::sin(alpha)*(r/radius);
+
+ dx = i - center.x;
+ dy = j - center.y; if(dy>=0) dy -= .5; else dy += .5;
+ r = std::sqrt(dx*dx+dy*dy);
+ alpha = atan2(dy,dx);
+
+ vel(i,j,k).y = std::cos(alpha)*(r/radius);
+
+ }
+
+} inline const Grid<Real> & getArg0() {
+ return phiObs; }
+ typedef Grid<Real> type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const Vec3& getArg2() {
+ return center; }
+ typedef Vec3 type2;inline const Real& getArg3() {
+ return radius; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel kninitVortexVelocity ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,phiObs,vel,center,radius); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,phiObs,vel,center,radius); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const Grid<Real> & phiObs; MACGrid& vel; const Vec3& center; const Real& radius; }
+;
+
+void initVortexVelocity(const Grid<Real> &phiObs, MACGrid& vel, const Vec3 &center, const Real &radius) {
+ kninitVortexVelocity(phiObs, vel, center, radius);
+} static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "initVortexVelocity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real> & phiObs = *_args.getPtr<Grid<Real> >("phiObs",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Vec3& center = _args.get<Vec3 >("center",2,&_lock); const Real& radius = _args.get<Real >("radius",3,&_lock); _retval = getPyNone(); initVortexVelocity(phiObs,vel,center,radius); _args.check(); }
+ pbFinalizePlugin(parent,"initVortexVelocity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("initVortexVelocity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_initVortexVelocity ("","initVortexVelocity",_W_18);
+extern "C" {
+ void PbRegister_initVortexVelocity() {
+ KEEP_UNUSED(_RP_initVortexVelocity); }
+ }
+
+
+
+
+//*****************************************************************************
+// helper functions for blurring
+
+//! class for Gaussian Blur
+struct GaussianKernelCreator{
+public:
+
+ float mSigma;
+ int mDim;
+ float* mMat1D;
+
+ GaussianKernelCreator() : mSigma(0.0f), mDim(0), mMat1D(NULL) {}
+ GaussianKernelCreator(float sigma, int dim = 0)
+ : mSigma(0.0f), mDim(0), mMat1D(NULL) {
+ setGaussianSigma(sigma, dim);
+ }
+
+ Real getWeiAtDis(float disx, float disy){
+ float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma);
+ float v = m * exp(-(1.0*disx*disx + 1.0*disy*disy) / (2.0 * mSigma * mSigma));
+ return v;
+ }
+
+ Real getWeiAtDis(float disx, float disy, float disz){
+ float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma);
+ float v = m * exp(-(1.0*disx*disx + 1.0*disy*disy + 1.0*disz*disz) / (2.0 * mSigma * mSigma));
+ return v;
+ }
+
+ void setGaussianSigma(float sigma, int dim = 0){
+ mSigma = sigma;
+ if (dim < 3)
+ mDim = (int)(2.0 * 3.0 * sigma + 1.0f);
+ else
+ mDim = dim;
+ if (mDim < 3) mDim = 3;
+
+ if (mDim % 2 == 0) ++mDim;// make dim odd
+
+ float s2 = mSigma * mSigma;
+ int c = mDim / 2;
+ float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma);
+
+ // create 1D matrix
+ if (mMat1D) delete[] mMat1D;
+ mMat1D = new float[mDim];
+ for (int i = 0; i < (mDim + 1) / 2; i++){
+ float v = m * exp(-(1.0*i*i) / (2.0 * s2));
+ mMat1D[c + i] = v;
+ mMat1D[c - i] = v;
+ }
+ }
+
+ ~GaussianKernelCreator(){
+ if (mMat1D) delete[] mMat1D;
+ }
+
+ float get1DKernelValue(int off){
+ assertMsg(off >= 0 && off < mDim, "off exceeded boundary in Gaussian Kernel 1D!");
+ return mMat1D[off];
+ }
+
+};
+
+template<class T>
+T convolveGrid(Grid<T>& originGrid, GaussianKernelCreator& gkSigma, Vec3 pos, int cdir){
+ // pos should be the centre pos, e.g., 1.5, 4.5, 0.5 for grid pos 1,4,0
+ Vec3 step(1.0, 0.0, 0.0);
+ if (cdir == 1)// todo, z
+ step = Vec3(0.0, 1.0, 0.0);
+ else if (cdir == 2)
+ step = Vec3(0.0, 0.0, 1.0);
+ T pxResult(0);
+ for (int i = 0; i < gkSigma.mDim; ++i){
+ Vec3i curpos = toVec3i(pos - step*(i - gkSigma.mDim / 2));
+ if (originGrid.isInBounds(curpos))
+ pxResult += gkSigma.get1DKernelValue(i) * originGrid.get(curpos);
+ else{ // TODO , improve...
+ Vec3i curfitpos = curpos;
+ if (curfitpos.x < 0) curfitpos.x = 0;
+ else if (curfitpos.x >= originGrid.getSizeX()) curfitpos.x = originGrid.getSizeX() - 1;
+ if (curfitpos.y < 0) curfitpos.y = 0;
+ else if (curfitpos.y >= originGrid.getSizeY()) curfitpos.y = originGrid.getSizeY() - 1;
+ if (curfitpos.z < 0) curfitpos.z = 0;
+ else if (curfitpos.z >= originGrid.getSizeZ()) curfitpos.z = originGrid.getSizeZ() - 1;
+ pxResult += gkSigma.get1DKernelValue(i) * originGrid.get(curfitpos);
+ }
+ }
+ return pxResult;
+}
+
+
+template <class T> struct knBlurGrid : public KernelBase {
+ knBlurGrid(Grid<T>& originGrid, Grid<T>& targetGrid, GaussianKernelCreator& gkSigma, int cdir) : KernelBase(&originGrid,0) ,originGrid(originGrid),targetGrid(targetGrid),gkSigma(gkSigma),cdir(cdir) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>& originGrid, Grid<T>& targetGrid, GaussianKernelCreator& gkSigma, int cdir ) const {
+ targetGrid(i, j, k) = convolveGrid<T>(originGrid, gkSigma, Vec3(i, j, k), cdir);
+} inline Grid<T>& getArg0() {
+ return originGrid; }
+ typedef Grid<T> type0;inline Grid<T>& getArg1() {
+ return targetGrid; }
+ typedef Grid<T> type1;inline GaussianKernelCreator& getArg2() {
+ return gkSigma; }
+ typedef GaussianKernelCreator type2;inline int& getArg3() {
+ return cdir; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel knBlurGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,originGrid,targetGrid,gkSigma,cdir); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,originGrid,targetGrid,gkSigma,cdir); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<T>& originGrid; Grid<T>& targetGrid; GaussianKernelCreator& gkSigma; int cdir; }
+;
+
+template<class T>
+int blurGrid(Grid<T>& originGrid, Grid<T>& targetGrid, float sigma){
+ GaussianKernelCreator tmGK(sigma);
+ Grid<T> tmpGrid(originGrid);
+ knBlurGrid<T>(originGrid, tmpGrid, tmGK, 0); //blur x
+ knBlurGrid<T>(tmpGrid, targetGrid, tmGK, 1); //blur y
+ if (targetGrid.is3D()){
+ tmpGrid.copyFrom(targetGrid);
+ knBlurGrid<T>(tmpGrid, targetGrid, tmGK, 2);
+ }
+ return tmGK.mDim;
+}
+
+
+
+ struct KnBlurMACGridGauss : public KernelBase {
+ KnBlurMACGridGauss(MACGrid& originGrid, MACGrid& target, GaussianKernelCreator& gkSigma, int cdir) : KernelBase(&originGrid,0) ,originGrid(originGrid),target(target),gkSigma(gkSigma),cdir(cdir) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& originGrid, MACGrid& target, GaussianKernelCreator& gkSigma, int cdir ) const {
+ Vec3 pos(i, j, k);
+ Vec3 step(1.0, 0.0, 0.0);
+ if (cdir == 1)
+ step = Vec3(0.0, 1.0, 0.0);
+ else if (cdir == 2)
+ step = Vec3(0.0, 0.0, 1.0);
+
+ Vec3 pxResult(0.0f);
+ for (int di = 0; di < gkSigma.mDim; ++di){
+ Vec3i curpos = toVec3i(pos - step*(di - gkSigma.mDim / 2));
+ if (!originGrid.isInBounds(curpos)){
+ if (curpos.x < 0) curpos.x = 0;
+ else if (curpos.x >= originGrid.getSizeX()) curpos.x = originGrid.getSizeX() - 1;
+ if (curpos.y < 0) curpos.y = 0;
+ else if (curpos.y >= originGrid.getSizeY()) curpos.y = originGrid.getSizeY() - 1;
+ if (curpos.z < 0) curpos.z = 0;
+ else if (curpos.z >= originGrid.getSizeZ()) curpos.z = originGrid.getSizeZ() - 1;
+ }
+ pxResult += gkSigma.get1DKernelValue(di) * originGrid.get(curpos);
+ }
+ target(i,j,k) = pxResult;
+} inline MACGrid& getArg0() {
+ return originGrid; }
+ typedef MACGrid type0;inline MACGrid& getArg1() {
+ return target; }
+ typedef MACGrid type1;inline GaussianKernelCreator& getArg2() {
+ return gkSigma; }
+ typedef GaussianKernelCreator type2;inline int& getArg3() {
+ return cdir; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel KnBlurMACGridGauss ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,originGrid,target,gkSigma,cdir); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,originGrid,target,gkSigma,cdir); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ MACGrid& originGrid; MACGrid& target; GaussianKernelCreator& gkSigma; int cdir; }
+;
+
+int blurMacGrid(MACGrid& oG, MACGrid& tG, float si){
+ GaussianKernelCreator tmGK(si);
+ MACGrid tmpGrid(oG);
+ KnBlurMACGridGauss(oG, tmpGrid, tmGK, 0); //blur x
+ KnBlurMACGridGauss(tmpGrid, tG, tmGK, 1); //blur y
+ if (tG.is3D()){
+ tmpGrid.copyFrom(tG);
+ KnBlurMACGridGauss(tmpGrid, tG, tmGK, 2);
+ }
+ return tmGK.mDim;
+} static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "blurMacGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& oG = *_args.getPtr<MACGrid >("oG",0,&_lock); MACGrid& tG = *_args.getPtr<MACGrid >("tG",1,&_lock); float si = _args.get<float >("si",2,&_lock); _retval = toPy(blurMacGrid(oG,tG,si)); _args.check(); }
+ pbFinalizePlugin(parent,"blurMacGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("blurMacGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_blurMacGrid ("","blurMacGrid",_W_19);
+extern "C" {
+ void PbRegister_blurMacGrid() {
+ KEEP_UNUSED(_RP_blurMacGrid); }
+ }
+
+
+
+int blurRealGrid(Grid<Real>& oG, Grid<Real>& tG, float si){
+ return blurGrid<Real> (oG, tG, si);
+} static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "blurRealGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& oG = *_args.getPtr<Grid<Real> >("oG",0,&_lock); Grid<Real>& tG = *_args.getPtr<Grid<Real> >("tG",1,&_lock); float si = _args.get<float >("si",2,&_lock); _retval = toPy(blurRealGrid(oG,tG,si)); _args.check(); }
+ pbFinalizePlugin(parent,"blurRealGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("blurRealGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_blurRealGrid ("","blurRealGrid",_W_20);
+extern "C" {
+ void PbRegister_blurRealGrid() {
+ KEEP_UNUSED(_RP_blurRealGrid); }
+ }
+
+
+
+} // namespace
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/kepsilon.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/kepsilon.cpp
new file mode 100644
index 00000000000..2deaff7c172
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/kepsilon.cpp
@@ -0,0 +1,316 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Turbulence modeling plugins
+ *
+ ******************************************************************************/
+
+#include "grid.h"
+#include "commonkernels.h"
+#include "vortexsheet.h"
+#include "conjugategrad.h"
+
+using namespace std;
+
+namespace Manta {
+
+// k-epsilon model constants
+const Real keCmu = 0.09;
+const Real keC1 = 1.44;
+const Real keC2 = 1.92;
+const Real keS1 = 1.0;
+const Real keS2 = 1.3;
+
+// k-epsilon limiters
+const Real keU0 = 1.0;
+const Real keImin = 2e-3;
+const Real keImax = 1.0;
+const Real keNuMin = 1e-3;
+const Real keNuMax = 5.0;
+
+//! clamp k and epsilon to limits
+
+ struct KnTurbulenceClamp : public KernelBase {
+ KnTurbulenceClamp(Grid<Real>& kgrid, Grid<Real>& egrid, Real minK, Real maxK, Real minNu, Real maxNu) : KernelBase(&kgrid,0) ,kgrid(kgrid),egrid(egrid),minK(minK),maxK(maxK),minNu(minNu),maxNu(maxNu) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& kgrid, Grid<Real>& egrid, Real minK, Real maxK, Real minNu, Real maxNu ) const {
+ Real eps = egrid[idx];
+ Real ke = clamp(kgrid[idx],minK,maxK);
+ Real nu = keCmu*square(ke)/eps;
+ if (nu > maxNu)
+ eps = keCmu*square(ke)/maxNu;
+ if (nu < minNu)
+ eps = keCmu*square(ke)/minNu;
+
+ kgrid[idx] = ke;
+ egrid[idx] = eps;
+} inline Grid<Real>& getArg0() {
+ return kgrid; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return egrid; }
+ typedef Grid<Real> type1;inline Real& getArg2() {
+ return minK; }
+ typedef Real type2;inline Real& getArg3() {
+ return maxK; }
+ typedef Real type3;inline Real& getArg4() {
+ return minNu; }
+ typedef Real type4;inline Real& getArg5() {
+ return maxNu; }
+ typedef Real type5; void runMessage() { debMsg("Executing kernel KnTurbulenceClamp ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, kgrid,egrid,minK,maxK,minNu,maxNu); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<Real>& kgrid; Grid<Real>& egrid; Real minK; Real maxK; Real minNu; Real maxNu; }
+;
+
+//! Compute k-epsilon production term P = 2*nu_T*sum_ij(Sij^2) and the turbulent viscosity nu_T=C_mu*k^2/eps
+
+
+
+ struct KnComputeProduction : public KernelBase {
+ KnComputeProduction(const MACGrid& vel, const Grid<Vec3>& velCenter, const Grid<Real>& ke, const Grid<Real>& eps, Grid<Real>& prod, Grid<Real>& nuT, Grid<Real>* strain, Real pscale = 1.0f) : KernelBase(&vel,1) ,vel(vel),velCenter(velCenter),ke(ke),eps(eps),prod(prod),nuT(nuT),strain(strain),pscale(pscale) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid& vel, const Grid<Vec3>& velCenter, const Grid<Real>& ke, const Grid<Real>& eps, Grid<Real>& prod, Grid<Real>& nuT, Grid<Real>* strain, Real pscale = 1.0f ) const {
+ Real curEps = eps(i,j,k);
+ if (curEps > 0) {
+ // turbulent viscosity: nu_T = C_mu * k^2/eps
+ Real curNu = keCmu * square(ke(i,j,k)) / curEps;
+
+ // compute Sij = 1/2 * (dU_i/dx_j + dU_j/dx_i)
+ Vec3 diag = Vec3(vel(i+1,j,k).x, vel(i,j+1,k).y, vel(i,j,k+1).z) - vel(i,j,k);
+ Vec3 ux = 0.5*(velCenter(i+1,j,k)-velCenter(i-1,j,k));
+ Vec3 uy = 0.5*(velCenter(i,j+1,k)-velCenter(i,j-1,k));
+ Vec3 uz = 0.5*(velCenter(i,j,k+1)-velCenter(i,j,k-1));
+ Real S12 = 0.5*(ux.y+uy.x);
+ Real S13 = 0.5*(ux.z+uz.x);
+ Real S23 = 0.5*(uy.z+uz.y);
+ Real S2 = square(diag.x) + square(diag.y) + square(diag.z) +
+ 2.0*square(S12) + 2.0*square(S13) + 2.0*square(S23);
+
+ // P = 2*nu_T*sum_ij(Sij^2)
+ prod(i,j,k) = 2.0 * curNu * S2 * pscale;
+ nuT(i,j,k) = curNu;
+ if (strain) (*strain)(i,j,k) = sqrt(S2);
+ }
+ else {
+ prod(i,j,k) = 0;
+ nuT(i,j,k) = 0;
+ if (strain) (*strain)(i,j,k) = 0;
+ }
+} inline const MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const Grid<Vec3>& getArg1() {
+ return velCenter; }
+ typedef Grid<Vec3> type1;inline const Grid<Real>& getArg2() {
+ return ke; }
+ typedef Grid<Real> type2;inline const Grid<Real>& getArg3() {
+ return eps; }
+ typedef Grid<Real> type3;inline Grid<Real>& getArg4() {
+ return prod; }
+ typedef Grid<Real> type4;inline Grid<Real>& getArg5() {
+ return nuT; }
+ typedef Grid<Real> type5;inline Grid<Real>* getArg6() {
+ return strain; }
+ typedef Grid<Real> type6;inline Real& getArg7() {
+ return pscale; }
+ typedef Real type7; void runMessage() { debMsg("Executing kernel KnComputeProduction ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,velCenter,ke,eps,prod,nuT,strain,pscale); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,velCenter,ke,eps,prod,nuT,strain,pscale); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const MACGrid& vel; const Grid<Vec3>& velCenter; const Grid<Real>& ke; const Grid<Real>& eps; Grid<Real>& prod; Grid<Real>& nuT; Grid<Real>* strain; Real pscale; }
+;
+
+//! Compute k-epsilon production term P = 2*nu_T*sum_ij(Sij^2) and the turbulent viscosity nu_T=C_mu*k^2/eps
+
+void KEpsilonComputeProduction(const MACGrid& vel, Grid<Real>& k, Grid<Real>& eps, Grid<Real>& prod, Grid<Real>& nuT, Grid<Real>* strain=0, Real pscale = 1.0f) {
+ // get centered velocity grid
+ Grid<Vec3> vcenter(k.getParent());
+ GetCentered(vcenter, vel);
+ FillInBoundary(vcenter,1);
+
+ // compute limits
+ const Real minK = 1.5*square(keU0)*square(keImin);
+ const Real maxK = 1.5*square(keU0)*square(keImax);
+ KnTurbulenceClamp(k, eps, minK, maxK, keNuMin, keNuMax);
+
+ KnComputeProduction(vel, vcenter, k, eps, prod, nuT, strain, pscale);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "KEpsilonComputeProduction" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Real>& k = *_args.getPtr<Grid<Real> >("k",1,&_lock); Grid<Real>& eps = *_args.getPtr<Grid<Real> >("eps",2,&_lock); Grid<Real>& prod = *_args.getPtr<Grid<Real> >("prod",3,&_lock); Grid<Real>& nuT = *_args.getPtr<Grid<Real> >("nuT",4,&_lock); Grid<Real>* strain = _args.getPtrOpt<Grid<Real> >("strain",5,0,&_lock); Real pscale = _args.getOpt<Real >("pscale",6,1.0f,&_lock); _retval = getPyNone(); KEpsilonComputeProduction(vel,k,eps,prod,nuT,strain,pscale); _args.check(); }
+ pbFinalizePlugin(parent,"KEpsilonComputeProduction", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("KEpsilonComputeProduction",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_KEpsilonComputeProduction ("","KEpsilonComputeProduction",_W_0);
+extern "C" {
+ void PbRegister_KEpsilonComputeProduction() {
+ KEEP_UNUSED(_RP_KEpsilonComputeProduction); }
+ }
+
+
+
+//! Integrate source terms of k-epsilon equation
+
+ struct KnAddTurbulenceSource : public KernelBase {
+ KnAddTurbulenceSource(Grid<Real>& kgrid, Grid<Real>& egrid, const Grid<Real>& pgrid, Real dt) : KernelBase(&kgrid,0) ,kgrid(kgrid),egrid(egrid),pgrid(pgrid),dt(dt) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Real>& kgrid, Grid<Real>& egrid, const Grid<Real>& pgrid, Real dt ) const {
+ Real eps = egrid[idx], prod = pgrid[idx], ke = kgrid[idx];
+ if (ke <= 0) ke = 1e-3; // pre-clamp to avoid nan
+
+ Real newK = ke + dt*(prod - eps);
+ Real newEps = eps + dt*(prod * keC1 - eps * keC2) * (eps / ke);
+ if (newEps <= 0) newEps = 1e-4; // pre-clamp to avoid nan
+
+ kgrid[idx] = newK;
+ egrid[idx] = newEps;
+} inline Grid<Real>& getArg0() {
+ return kgrid; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return egrid; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return pgrid; }
+ typedef Grid<Real> type2;inline Real& getArg3() {
+ return dt; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel KnAddTurbulenceSource ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, kgrid,egrid,pgrid,dt); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<Real>& kgrid; Grid<Real>& egrid; const Grid<Real>& pgrid; Real dt; }
+;
+
+
+//! Integrate source terms of k-epsilon equation
+void KEpsilonSources(Grid<Real>& k, Grid<Real>& eps, Grid<Real>& prod) {
+ Real dt = k.getParent()->getDt();
+
+ KnAddTurbulenceSource(k, eps, prod, dt);
+
+ // compute limits
+ const Real minK = 1.5*square(keU0)*square(keImin);
+ const Real maxK = 1.5*square(keU0)*square(keImax);
+ KnTurbulenceClamp(k, eps, minK, maxK, keNuMin, keNuMax);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "KEpsilonSources" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& k = *_args.getPtr<Grid<Real> >("k",0,&_lock); Grid<Real>& eps = *_args.getPtr<Grid<Real> >("eps",1,&_lock); Grid<Real>& prod = *_args.getPtr<Grid<Real> >("prod",2,&_lock); _retval = getPyNone(); KEpsilonSources(k,eps,prod); _args.check(); }
+ pbFinalizePlugin(parent,"KEpsilonSources", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("KEpsilonSources",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_KEpsilonSources ("","KEpsilonSources",_W_1);
+extern "C" {
+ void PbRegister_KEpsilonSources() {
+ KEEP_UNUSED(_RP_KEpsilonSources); }
+ }
+
+
+
+//! Initialize the domain or boundary conditions
+void KEpsilonBcs(const FlagGrid& flags, Grid<Real>& k, Grid<Real>& eps, Real intensity, Real nu, bool fillArea) {
+ // compute limits
+ const Real vk = 1.5*square(keU0)*square(intensity);
+ const Real ve = keCmu*square(vk) / nu;
+
+ FOR_IDX(k) {
+ if (fillArea || flags.isObstacle(idx)) {
+ k[idx] = vk;
+ eps[idx] = ve;
+ }
+ }
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "KEpsilonBcs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& k = *_args.getPtr<Grid<Real> >("k",1,&_lock); Grid<Real>& eps = *_args.getPtr<Grid<Real> >("eps",2,&_lock); Real intensity = _args.get<Real >("intensity",3,&_lock); Real nu = _args.get<Real >("nu",4,&_lock); bool fillArea = _args.get<bool >("fillArea",5,&_lock); _retval = getPyNone(); KEpsilonBcs(flags,k,eps,intensity,nu,fillArea); _args.check(); }
+ pbFinalizePlugin(parent,"KEpsilonBcs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("KEpsilonBcs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_KEpsilonBcs ("","KEpsilonBcs",_W_2);
+extern "C" {
+ void PbRegister_KEpsilonBcs() {
+ KEEP_UNUSED(_RP_KEpsilonBcs); }
+ }
+
+
+
+//! Gradient diffusion smoothing. Not unconditionally stable -- should probably do substepping etc.
+void ApplyGradDiff(const Grid<Real>& grid, Grid<Real>& res, const Grid<Real>& nu, Real dt, Real sigma) {
+ // should do this (but requires better boundary handling)
+ /*MACGrid grad(grid.getParent());
+ GradientOpMAC(grad, grid);
+ grad *= nu;
+ DivergenceOpMAC(res, grad);
+ res *= dt/sigma; */
+
+ LaplaceOp(res, grid);
+ res *= nu;
+ res *= dt/sigma;
+}
+
+//! Compute k-epsilon turbulent viscosity
+void KEpsilonGradientDiffusion(Grid<Real>& k, Grid<Real>& eps, Grid<Real>& nuT, Real sigmaU=4.0, MACGrid* vel=0) {
+ Real dt = k.getParent()->getDt();
+ Grid<Real> res(k.getParent());
+
+ // gradient diffusion of k
+ ApplyGradDiff(k, res, nuT, dt, keS1);
+ k += res;
+
+ // gradient diffusion of epsilon
+ ApplyGradDiff(eps, res, nuT, dt, keS2);
+ eps += res;
+
+ // gradient diffusion of velocity
+ if (vel) {
+ Grid<Real> vc(k.getParent());
+ for (int c=0; c<3; c++) {
+ GetComponent(*vel, vc, c);
+ ApplyGradDiff(vc, res, nuT, dt, sigmaU);
+ vc += res;
+ SetComponent(*vel, vc, c);
+ }
+ }
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "KEpsilonGradientDiffusion" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& k = *_args.getPtr<Grid<Real> >("k",0,&_lock); Grid<Real>& eps = *_args.getPtr<Grid<Real> >("eps",1,&_lock); Grid<Real>& nuT = *_args.getPtr<Grid<Real> >("nuT",2,&_lock); Real sigmaU = _args.getOpt<Real >("sigmaU",3,4.0,&_lock); MACGrid* vel = _args.getPtrOpt<MACGrid >("vel",4,0,&_lock); _retval = getPyNone(); KEpsilonGradientDiffusion(k,eps,nuT,sigmaU,vel); _args.check(); }
+ pbFinalizePlugin(parent,"KEpsilonGradientDiffusion", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("KEpsilonGradientDiffusion",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_KEpsilonGradientDiffusion ("","KEpsilonGradientDiffusion",_W_3);
+extern "C" {
+ void PbRegister_KEpsilonGradientDiffusion() {
+ KEEP_UNUSED(_RP_KEpsilonGradientDiffusion); }
+ }
+
+
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/meshplugins.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/meshplugins.cpp
new file mode 100644
index 00000000000..f6109cefe90
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/meshplugins.cpp
@@ -0,0 +1,678 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Smoothing etc. for meshes
+ *
+ ******************************************************************************/
+
+/******************************************************************************/
+// Copyright note:
+//
+// These functions (C) Chris Wojtan
+// Long-term goal is to unify with his split&merge codebase
+//
+/******************************************************************************/
+
+#include <queue>
+#include <algorithm>
+#include "mesh.h"
+#include "kernel.h"
+#include "edgecollapse.h"
+#include <mesh.h>
+#include <stack>
+
+using namespace std;
+
+namespace Manta {
+
+//! Mesh smoothing
+/*! see Desbrun 99 "Implicit fairing of of irregular meshes using diffusion and curvature flow"*/
+void smoothMesh(Mesh& mesh, Real strength, int steps = 1, Real minLength=1e-5) {
+ const Real dt = mesh.getParent()->getDt();
+ const Real str = min(dt * strength, (Real)1);
+ mesh.rebuildQuickCheck();
+
+ // calculate original mesh volume
+ Vec3 origCM;
+ Real origVolume = mesh.computeCenterOfMass(origCM);
+
+ // temp vertices
+ const int numCorners = mesh.numTris() * 3;
+ const int numNodes= mesh.numNodes();
+ vector<Vec3> temp(numNodes);
+ vector<bool> visited(numNodes);
+
+ for (int s = 0; s<steps; s++) {
+ // reset markers
+ for(size_t i=0; i<visited.size(); i++) visited[i] = false;
+
+ for (int c = 0; c < numCorners; c++) {
+ const int node = mesh.corners(c).node;
+ if (visited[node]) continue;
+
+ const Vec3 pos = mesh.nodes(node).pos;
+ Vec3 dx(0.0);
+ Real totalLen = 0;
+
+ // rotate around vertex
+ set<int>& ring = mesh.get1Ring(node).nodes;
+ for(set<int>::iterator it=ring.begin(); it!=ring.end(); it++) {
+ Vec3 edge = mesh.nodes(*it).pos - pos;
+ Real len = norm(edge);
+
+ if (len > minLength) {
+ dx += edge * (1.0/len);
+ totalLen += len;
+ } else {
+ totalLen = 0.0;
+ break;
+ }
+ }
+ visited[node] = true;
+ temp[node] = pos;
+ if (totalLen != 0)
+ temp[node] += dx * (str / totalLen);
+ }
+
+ // copy back
+ for (int n=0; n<numNodes; n++)
+ if (!mesh.isNodeFixed(n))
+ mesh.nodes(n).pos = temp[n];
+ }
+
+ // calculate new mesh volume
+ Vec3 newCM;
+ Real newVolume = mesh.computeCenterOfMass(newCM);
+
+ // preserve volume : scale relative to CM
+ Real beta;
+#if defined(WIN32) || defined(_WIN32)
+ beta = pow( (Real)std::abs(origVolume/newVolume), (Real)(1./3.) );
+#else
+ beta = cbrt( origVolume/newVolume );
+# endif
+
+ for (int n=0; n<numNodes; n++)
+ if (!mesh.isNodeFixed(n))
+ mesh.nodes(n).pos = origCM + (mesh.nodes(n).pos - newCM) * beta;
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "smoothMesh" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); Real strength = _args.get<Real >("strength",1,&_lock); int steps = _args.getOpt<int >("steps",2,1,&_lock); Real minLength = _args.getOpt<Real >("minLength",3,1e-5,&_lock); _retval = getPyNone(); smoothMesh(mesh,strength,steps,minLength); _args.check(); }
+ pbFinalizePlugin(parent,"smoothMesh", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("smoothMesh",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_smoothMesh ("","smoothMesh",_W_0);
+extern "C" {
+ void PbRegister_smoothMesh() {
+ KEEP_UNUSED(_RP_smoothMesh); }
+ }
+
+
+
+//! Subdivide and edgecollapse to guarantee mesh with edgelengths between
+//! min/maxLength and an angle below minAngle
+void subdivideMesh(Mesh& mesh, Real minAngle, Real minLength, Real maxLength, bool cutTubes = false) {
+ // gather some statistics
+ int edgeSubdivs = 0, edgeCollsAngle = 0, edgeCollsLen = 0, edgeKill = 0;
+ mesh.rebuildQuickCheck();
+
+ vector<int> deletedNodes;
+ map<int,bool> taintedTris;
+ priority_queue<pair<Real,int> > pq;
+
+ //////////////////////////////////////////
+ // EDGE COLLAPSE //
+ // - particles marked for deletation //
+ //////////////////////////////////////////
+
+ for (int t=0; t<mesh.numTris(); t++) {
+ if(taintedTris.find(t)!=taintedTris.end())
+ continue;
+
+ // check if at least 2 nodes are marked for delete
+ bool k[3];
+ int numKill = 0;
+ for (int i=0; i<3; i++) {
+ k[i] = mesh.nodes(mesh.tris(t).c[i]).flags & Mesh::NfKillme;
+ if (k[i]) numKill++;
+ }
+ if (numKill<2) continue;
+
+ if (k[0] && k[1])
+ CollapseEdge(mesh, t, 2, mesh.getEdge(t,0), mesh.getNode(t,0), deletedNodes, taintedTris, edgeKill, cutTubes);
+ else if (k[1] && k[2])
+ CollapseEdge(mesh, t, 0, mesh.getEdge(t,1), mesh.getNode(t,1), deletedNodes, taintedTris, edgeKill, cutTubes);
+ else if (k[2] && k[0])
+ CollapseEdge(mesh, t, 1, mesh.getEdge(t,2), mesh.getNode(t,2), deletedNodes, taintedTris, edgeKill, cutTubes);
+ }
+
+ //////////////////////////////////////////
+ // EDGE COLLAPSING //
+ // - based on small triangle angle //
+ //////////////////////////////////////////
+
+ if (minAngle > 0) {
+ for(int t=0; t<mesh.numTris(); t++) {
+ // we only want to run through the edge list ONCE.
+ // we achieve this in a method very similar to the above subdivision method.
+
+ // if this triangle has already been deleted, ignore it
+ if(taintedTris.find(t)!=taintedTris.end())
+ continue;
+
+ // first we find the angles of this triangle
+ Vec3 e0 = mesh.getEdge(t,0), e1 = mesh.getEdge(t,1), e2 = mesh.getEdge(t,2);
+ Vec3 ne0 = e0;
+ Vec3 ne1 = e1;
+ Vec3 ne2 = e2;
+ normalize(ne0);
+ normalize(ne1);
+ normalize(ne2);
+
+ //Real thisArea = sqrMag(cross(-e2,e0));
+ // small angle approximation says sin(x) = arcsin(x) = x,
+ // arccos(x) = pi/2 - arcsin(x),
+ // cos(x) = dot(A,B),
+ // so angle is approximately 1 - dot(A,B).
+ Real angle[3];
+ angle[0] = 1.0-dot(ne0,-ne2);
+ angle[1] = 1.0-dot(ne1,-ne0);
+ angle[2] = 1.0-dot(ne2,-ne1);
+ Real worstAngle = angle[0];
+ int which = 0;
+ if(angle[1]<worstAngle) {
+ worstAngle = angle[1];
+ which = 1;
+ }
+ if(angle[2]<worstAngle) {
+ worstAngle = angle[2];
+ which = 2;
+ }
+
+ // then we see if the angle is too small
+ if(worstAngle<minAngle) {
+ Vec3 edgevect;
+ Vec3 endpoint;
+ switch(which) {
+ case 0:
+ endpoint = mesh.getNode(t,1);
+ edgevect = e1;
+ break;
+ case 1:
+ endpoint = mesh.getNode(t,2);
+ edgevect = e2;
+ break;
+ case 2:
+ endpoint = mesh.getNode(t,0);
+ edgevect = e0;
+ break;
+ default:
+ break;
+ }
+
+ CollapseEdge(mesh, t,which,edgevect,endpoint,deletedNodes,taintedTris, edgeCollsAngle, cutTubes);
+ }
+ }
+ }
+
+ //////////////////////
+ // EDGE SUBDIVISION //
+ //////////////////////
+
+ Real maxLength2 = maxLength*maxLength;
+ for (int t=0; t<mesh.numTris(); t++) {
+ // first we find the maximum length edge in this triangle
+ Vec3 e0 = mesh.getEdge(t,0), e1 = mesh.getEdge(t,1), e2 = mesh.getEdge(t,2);
+ Real d0 = normSquare(e0);
+ Real d1 = normSquare(e1);
+ Real d2 = normSquare(e2);
+
+ Real longest = max(d0,max(d1,d2));
+ if(longest > maxLength2) {
+ pq.push(pair<Real,int>(longest,t));
+ }
+ }
+ if (maxLength > 0) {
+
+ while(!pq.empty() && pq.top().first>maxLength2) {
+ // we only want to run through the edge list ONCE
+ // and we want to subdivide the original edges before we subdivide any newer, shorter edges,
+ // so whenever we subdivide, we add the 2 new triangles on the end of the SurfaceTri vector
+ // and mark the original subdivided triangles for deletion.
+ // when we are done subdividing, we delete the obsolete triangles
+
+ int triA = pq.top().second;
+ pq.pop();
+
+ if(taintedTris.find(triA)!=taintedTris.end())
+ continue;
+
+ // first we find the maximum length edge in this triangle
+ Vec3 e0 = mesh.getEdge(triA,0), e1 = mesh.getEdge(triA,1), e2 = mesh.getEdge(triA,2);
+ Real d0 = normSquare(e0);
+ Real d1 = normSquare(e1);
+ Real d2 = normSquare(e2);
+
+ Vec3 edgevect;
+ Vec3 endpoint;
+ int which;
+ if(d0>d1) {
+ if(d0>d2) {
+ edgevect = e0;
+ endpoint = mesh.getNode(triA, 0);;
+ which = 2; // 2 opposite of edge 0-1
+ } else {
+ edgevect = e2;
+ endpoint = mesh.getNode(triA, 2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ } else {
+ if(d1>d2) {
+ edgevect = e1;
+ endpoint = mesh.getNode(triA, 1);
+ which = 0; // 0 opposite of edge 1-2
+ } else {
+ edgevect = e2;
+ endpoint = mesh.getNode(triA, 2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ }
+ // This edge is too long, so we split it in the middle
+
+ // *
+ // / \.
+ // /C0 \.
+ // / \.
+ // / \.
+ // / B \.
+ // / \.
+ // /C1 C2 \.
+ // *---------------*
+ // \C2 C1 /
+ // \ /
+ // \ A /
+ // \ /
+ // \ /
+ // \C0 /
+ // \ /
+ // *
+ //
+ // BECOMES
+ //
+ // *
+ // /|\.
+ // / | \.
+ // /C0|C0\.
+ // / | \.
+ // / B1 | B2 \.
+ // / | \.
+ // /C1 C2|C1 C2 \.
+ // *-------*-------*
+ // \C2 C1|C2 C1/
+ // \ | /
+ // \ A2 | A1 /
+ // \ | /
+ // \C0|C0/
+ // \ | /
+ // \|/
+ // *
+
+ int triB = -1; bool haveB = false;
+ Corner ca_old[3],cb_old[3];
+ ca_old[0] = mesh.corners(triA, which);
+ ca_old[1] = mesh.corners(ca_old[0].next);
+ ca_old[2] = mesh.corners(ca_old[0].prev);
+ if (ca_old[0].opposite>=0) {
+ cb_old[0] = mesh.corners(ca_old[0].opposite);
+ cb_old[1] = mesh.corners(cb_old[0].next);
+ cb_old[2] = mesh.corners(cb_old[0].prev);
+ triB = cb_old[0].tri;
+ haveB = true;
+ }
+ //else throw Error("nonmanifold");
+
+ // subdivide in the middle of the edge and create new triangles
+ Node newNode;
+ newNode.flags = 0;
+
+ newNode.pos = endpoint + 0.5*edgevect; // fallback: linear average
+ // default: use butterfly
+ if (haveB)
+ newNode.pos = ModifiedButterflySubdivision(mesh, ca_old[0], cb_old[0], newNode.pos);
+
+ // find indices of two points of 'which'-edge
+ // merge flags
+ int P0 = ca_old[1].node;
+ int P1 = ca_old[2].node;
+ newNode.flags = mesh.nodes(P0).flags | mesh.nodes(P1).flags;
+
+ Real len0 = norm(mesh.nodes(P0).pos - newNode.pos);
+ Real len1 = norm(mesh.nodes(P1).pos - newNode.pos);
+
+ // remove P0/P1 1-ring connection
+ mesh.get1Ring(P0).nodes.erase(P1);
+ mesh.get1Ring(P1).nodes.erase(P0);
+ mesh.get1Ring(P0).tris.erase(triA);
+ mesh.get1Ring(P1).tris.erase(triA);
+ mesh.get1Ring(ca_old[0].node).tris.erase(triA);
+ if (haveB) {
+ mesh.get1Ring(P0).tris.erase(triB);
+ mesh.get1Ring(P1).tris.erase(triB);
+ mesh.get1Ring(cb_old[0].node).tris.erase(triB);
+ }
+
+ // init channel properties for new node
+ for(int i=0; i<mesh.numNodeChannels(); i++) {
+ mesh.nodeChannel(i)->addInterpol(P0, P1, len0/(len0+len1));
+ }
+
+ // write to array
+ mesh.addTri(Triangle(ca_old[0].node, ca_old[1].node, mesh.numNodes()));
+ mesh.addTri(Triangle(ca_old[0].node, mesh.numNodes(), ca_old[2].node));
+ if (haveB) {
+ mesh.addTri(Triangle(cb_old[0].node, cb_old[1].node, mesh.numNodes()));
+ mesh.addTri(Triangle(cb_old[0].node, mesh.numNodes(), cb_old[2].node));
+ }
+ mesh.addNode(newNode);
+
+ const int nt = haveB ? 4 : 2;
+ int triA1 = mesh.numTris()-nt;
+ int triA2 = mesh.numTris()-nt+1;
+ int triB1=0, triB2=0;
+ if (haveB) {
+ triB1 = mesh.numTris()-nt+2;
+ triB2 = mesh.numTris()-nt+3;
+ }
+ mesh.tris(triA1).flags = mesh.tris(triA).flags;
+ mesh.tris(triA2).flags = mesh.tris(triA).flags;
+ mesh.tris(triB1).flags = mesh.tris(triB).flags;
+ mesh.tris(triB2).flags = mesh.tris(triB).flags;
+
+ // connect new triangles to outside triangles,
+ // and connect outside triangles to these new ones
+ for (int c=0; c<3; c++) mesh.addCorner(Corner(triA1,mesh.tris(triA1).c[c]));
+ for (int c=0; c<3; c++) mesh.addCorner(Corner(triA2,mesh.tris(triA2).c[c]));
+ if (haveB) {
+ for (int c=0; c<3; c++) mesh.addCorner(Corner(triB1,mesh.tris(triB1).c[c]));
+ for (int c=0; c<3; c++) mesh.addCorner(Corner(triB2,mesh.tris(triB2).c[c]));
+ }
+
+ int baseIdx = 3*(mesh.numTris()-nt);
+ Corner* cBase = &mesh.corners(baseIdx);
+
+ // set next/prev
+ for (int t=0; t<nt; t++)
+ for (int c=0; c<3; c++) {
+ cBase[t*3+c].next = baseIdx+t*3+((c+1)%3);
+ cBase[t*3+c].prev = baseIdx+t*3+((c+2)%3);
+ }
+
+ // set opposites
+ // A1
+ cBase[0].opposite = haveB ? (baseIdx+9) : -1;
+ cBase[1].opposite = baseIdx+5;
+ cBase[2].opposite = -1;
+ if (ca_old[2].opposite>=0) {
+ cBase[2].opposite = ca_old[2].opposite;
+ mesh.corners(cBase[2].opposite).opposite = baseIdx+2;
+ }
+ // A2
+ cBase[3].opposite = haveB ? (baseIdx+6) : -1;
+ cBase[4].opposite = -1;
+ if (ca_old[1].opposite>=0) {
+ cBase[4].opposite = ca_old[1].opposite;
+ mesh.corners(cBase[4].opposite).opposite = baseIdx+4;
+ }
+ cBase[5].opposite = baseIdx+1;
+ if (haveB) {
+ // B1
+ cBase[6].opposite = baseIdx+3;
+ cBase[7].opposite = baseIdx+11;
+ cBase[8].opposite = -1;
+ if (cb_old[2].opposite>=0) {
+ cBase[8].opposite = cb_old[2].opposite;
+ mesh.corners(cBase[8].opposite).opposite = baseIdx+8;
+ }
+ // B2
+ cBase[9].opposite = baseIdx+0;
+ cBase[10].opposite = -1;
+ if (cb_old[1].opposite>=0) {
+ cBase[10].opposite = cb_old[1].opposite;
+ mesh.corners(cBase[10].opposite).opposite = baseIdx+10;
+ }
+ cBase[11].opposite = baseIdx+7;
+ }
+
+ ////////////////////
+ // mark the two original triangles for deletion
+ taintedTris[triA] = true;
+ mesh.removeTriFromLookup(triA);
+ if (haveB) {
+ taintedTris[triB] = true;
+ mesh.removeTriFromLookup(triB);
+ }
+
+ Real areaA1 = mesh.getFaceArea(triA1), areaA2 = mesh.getFaceArea(triA2);
+ Real areaB1=0, areaB2=0;
+ if (haveB) {
+ areaB1 = mesh.getFaceArea(triB1);
+ areaB2 = mesh.getFaceArea(triB2);
+ }
+
+ // add channel props for new triangles
+ for(int i=0; i<mesh.numTriChannels(); i++) {
+ mesh.triChannel(i)->addSplit(triA, areaA1/(areaA1+areaA2));
+ mesh.triChannel(i)->addSplit(triA, areaA2/(areaA1+areaA2));
+ if (haveB) {
+ mesh.triChannel(i)->addSplit(triB, areaB1/(areaB1+areaB2));
+ mesh.triChannel(i)->addSplit(triB, areaB2/(areaB1+areaB2));
+ }
+ }
+
+ // add the four new triangles to the prority queue
+ for(int i=mesh.numTris()-nt; i<mesh.numTris(); i++) {
+ // find the maximum length edge in this triangle
+ Vec3 ne0 = mesh.getEdge(i, 0), ne1 = mesh.getEdge(i, 1), ne2 = mesh.getEdge(i, 2);
+ Real nd0 = normSquare(ne0);
+ Real nd1 = normSquare(ne1);
+ Real nd2 = normSquare(ne2);
+ Real longest = max(nd0,max(nd1,nd2));
+ //longest = (int)(longest * 1e2) / 1e2; // HACK: truncate
+ pq.push(pair<Real,int>(longest,i));
+ }
+ edgeSubdivs++;
+ }
+ }
+
+ //////////////////////////////////////////
+ // EDGE COLLAPSING //
+ // - based on short edge length //
+ //////////////////////////////////////////
+ if (minLength > 0) {
+ const Real minLength2 = minLength*minLength;
+ for(int t=0; t<mesh.numTris(); t++) {
+ // we only want to run through the edge list ONCE.
+ // we achieve this in a method very similar to the above subdivision method.
+
+ // NOTE:
+ // priority queue does not work so great in the edge collapse case,
+ // because collapsing one triangle affects the edge lengths
+ // of many neighbor triangles,
+ // and we do not update their maximum edge length in the queue.
+
+ // if this triangle has already been deleted, ignore it
+ //if(taintedTris[t])
+ // continue;
+
+ if(taintedTris.find(t)!=taintedTris.end())
+ continue;
+
+ // first we find the minimum length edge in this triangle
+ Vec3 e0 = mesh.getEdge(t,0), e1 = mesh.getEdge(t,1), e2 = mesh.getEdge(t,2);
+ Real d0 = normSquare(e0);
+ Real d1 = normSquare(e1);
+ Real d2 = normSquare(e2);
+
+ Vec3 edgevect;
+ Vec3 endpoint;
+ Real dist2;
+ int which;
+ if(d0<d1) {
+ if(d0<d2) {
+ dist2 = d0;
+ edgevect = e0;
+ endpoint = mesh.getNode(t,0);
+ which = 2; // 2 opposite of edge 0-1
+ } else {
+ dist2 = d2;
+ edgevect = e2;
+ endpoint = mesh.getNode(t,2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ } else {
+ if(d1<d2) {
+ dist2 = d1;
+ edgevect = e1;
+ endpoint = mesh.getNode(t,1);
+ which = 0; // 0 opposite of edge 1-2
+ } else {
+ dist2 = d2;
+ edgevect = e2;
+ endpoint = mesh.getNode(t,2);
+ which = 1; // 1 opposite of edge 2-0
+ }
+ }
+ // then we see if the min length edge is too short
+ if(dist2<minLength2) {
+ CollapseEdge(mesh, t,which,edgevect,endpoint, deletedNodes,taintedTris, edgeCollsLen, cutTubes);
+ }
+ }
+ }
+ // cleanup nodes and triangles marked for deletion
+
+ // we run backwards through the deleted array,
+ // replacing triangles with ones from the back
+ // (this avoids the potential problem of overwriting a triangle
+ // with a to-be-deleted triangle)
+ std::map<int,bool>::reverse_iterator tti = taintedTris.rbegin();
+ for(;tti!=taintedTris.rend(); tti++)
+ mesh.removeTri(tti->first);
+
+ mesh.removeNodes(deletedNodes);
+ cout << "Surface subdivision finished with " << mesh.numNodes() << " surface nodes and " << mesh.numTris();
+ cout << " surface triangles, edgeSubdivs:" << edgeSubdivs << ", edgeCollapses: " << edgeCollsLen;
+ cout << " + " << edgeCollsAngle << " + " << edgeKill << endl;
+ //mesh.sanityCheck();
+
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "subdivideMesh" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); Real minAngle = _args.get<Real >("minAngle",1,&_lock); Real minLength = _args.get<Real >("minLength",2,&_lock); Real maxLength = _args.get<Real >("maxLength",3,&_lock); bool cutTubes = _args.getOpt<bool >("cutTubes",4,false,&_lock); _retval = getPyNone(); subdivideMesh(mesh,minAngle,minLength,maxLength,cutTubes); _args.check(); }
+ pbFinalizePlugin(parent,"subdivideMesh", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("subdivideMesh",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_subdivideMesh ("","subdivideMesh",_W_1);
+extern "C" {
+ void PbRegister_subdivideMesh() {
+ KEEP_UNUSED(_RP_subdivideMesh); }
+ }
+
+
+
+void killSmallComponents(Mesh& mesh, int elements = 10) {
+ const int num = mesh.numTris();
+ vector<int> comp(num);
+ vector<int> numEl;
+ vector<int> deletedNodes;
+ vector<bool> isNodeDel(mesh.numNodes());
+ map<int,bool> taintedTris;
+ // enumerate components
+ int cur=0;
+ for (int i=0; i<num; i++) {
+ if (comp[i]==0) {
+ cur++;
+ comp[i] = cur;
+
+ stack<int> stack;
+ stack.push(i);
+ int cnt = 1;
+ while(!stack.empty()) {
+ int tri = stack.top();
+ stack.pop();
+ for (int c=0; c<3; c++) {
+ int op = mesh.corners(tri,c).opposite;
+ if (op < 0) continue;
+ int ntri = mesh.corners(op).tri;
+ if (comp[ntri]==0) {
+ comp[ntri] = cur;
+ stack.push(ntri);
+ cnt++;
+ }
+ }
+ }
+ numEl.push_back(cnt);
+ }
+ }
+ // kill small components
+ for (int j=0; j<num; j++) {
+ if (numEl[comp[j]-1] < elements) {
+ taintedTris[j] = true;
+ for (int c=0; c<3; c++) {
+ int n=mesh.tris(j).c[c];
+ if (!isNodeDel[n]) {
+ isNodeDel[n] = true;
+ deletedNodes.push_back(n);
+ }
+ }
+ }
+ }
+
+ std::map<int,bool>::reverse_iterator tti = taintedTris.rbegin();
+ for(;tti!=taintedTris.rend(); tti++)
+ mesh.removeTri(tti->first);
+
+ mesh.removeNodes(deletedNodes);
+
+ if (!taintedTris.empty())
+ cout << "Killed small components : " << deletedNodes.size() << " nodes, " << taintedTris.size() << " tris deleted." << endl;
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "killSmallComponents" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); int elements = _args.getOpt<int >("elements",1,10,&_lock); _retval = getPyNone(); killSmallComponents(mesh,elements); _args.check(); }
+ pbFinalizePlugin(parent,"killSmallComponents", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("killSmallComponents",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_killSmallComponents ("","killSmallComponents",_W_2);
+extern "C" {
+ void PbRegister_killSmallComponents() {
+ KEEP_UNUSED(_RP_killSmallComponents); }
+ }
+
+
+
+
+} //namespace
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/pressure.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/pressure.cpp
new file mode 100644
index 00000000000..74ef0ad1a4a
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/pressure.cpp
@@ -0,0 +1,731 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for pressure correction: solve_pressure, and ghost fluid helpers
+ *
+ ******************************************************************************/
+#include "vectorbase.h"
+#include "kernel.h"
+#include "conjugategrad.h"
+#include "multigrid.h"
+
+using namespace std;
+namespace Manta {
+
+//! Preconditioner for CG solver
+// - None: Use standard CG
+// - MIC: Modified incomplete Cholesky preconditioner
+// - MGDynamic: Multigrid preconditioner, rebuilt for each solve
+// - MGStatic: Multigrid preconditioner, built only once (faster than
+// MGDynamic, but works only if Poisson equation does not change)
+enum Preconditioner { PcNone = 0, PcMIC = 1, PcMGDynamic = 2, PcMGStatic = 3 };
+
+inline static Real surfTensHelper(const IndexInt idx, const int offset, const Grid<Real> &phi, const Grid<Real> &curv, const Real surfTens, const Real gfClamp);
+
+//! Kernel: Construct the right-hand side of the poisson equation
+
+
+
+
+
+
+ struct MakeRhs : public KernelBase {
+ MakeRhs( const FlagGrid& flags, Grid<Real>& rhs, const MACGrid& vel, const Grid<Real>* perCellCorr, const MACGrid* fractions, const Grid<Real> *phi, const Grid<Real> *curv, const Real surfTens, const Real gfClamp) : KernelBase(&flags,1) ,flags(flags),rhs(rhs),vel(vel),perCellCorr(perCellCorr),fractions(fractions),phi(phi),curv(curv),surfTens(surfTens),gfClamp(gfClamp) ,cnt(0),sum(0) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& rhs, const MACGrid& vel, const Grid<Real>* perCellCorr, const MACGrid* fractions, const Grid<Real> *phi, const Grid<Real> *curv, const Real surfTens, const Real gfClamp ,int& cnt,double& sum) {
+ if(!flags.isFluid(i,j,k)) {
+ rhs(i,j,k) = 0;
+ return;
+ }
+
+ // compute negative divergence
+ // no flag checks: assumes vel at obstacle interfaces is set to zero
+ Real set(0);
+ if(!fractions) {
+ set = vel(i,j,k).x - vel(i+1,j,k).x + vel(i,j,k).y - vel(i,j+1,k).y;
+ if(vel.is3D()) set += vel(i,j,k).z - vel(i,j,k+1).z;
+ } else {
+ set = (*fractions)(i,j,k).x * vel(i,j,k).x - (*fractions)(i+1,j,k).x * vel(i+1,j,k).x + (*fractions)(i,j,k).y * vel(i,j,k).y - (*fractions)(i,j+1,k).y * vel(i,j+1,k).y;
+ if(vel.is3D()) set += (*fractions)(i,j,k).z * vel(i,j,k).z - (*fractions)(i,j,k+1).z * vel(i,j,k+1).z;
+ }
+
+ // compute surface tension effect (optional)
+ if(phi && curv) {
+ const IndexInt idx = flags.index(i,j,k);
+ const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ if(flags.isEmpty(i-1,j,k)) set += surfTensHelper(idx, -X, *phi, *curv, surfTens, gfClamp);
+ if(flags.isEmpty(i+1,j,k)) set += surfTensHelper(idx, +X, *phi, *curv, surfTens, gfClamp);
+ if(flags.isEmpty(i,j-1,k)) set += surfTensHelper(idx, -Y, *phi, *curv, surfTens, gfClamp);
+ if(flags.isEmpty(i,j+1,k)) set += surfTensHelper(idx, +Y, *phi, *curv, surfTens, gfClamp);
+ if(vel.is3D()) {
+ if(flags.isEmpty(i,j,k-1)) set += surfTensHelper(idx, -Z, *phi, *curv, surfTens, gfClamp);
+ if(flags.isEmpty(i,j,k+1)) set += surfTensHelper(idx, +Z, *phi, *curv, surfTens, gfClamp);
+ }
+ }
+
+ // per cell divergence correction (optional)
+ if(perCellCorr)
+ set += perCellCorr->get(i,j,k);
+
+ // obtain sum, cell count
+ sum += set;
+ cnt++;
+
+ rhs(i,j,k) = set;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return rhs; }
+ typedef Grid<Real> type1;inline const MACGrid& getArg2() {
+ return vel; }
+ typedef MACGrid type2;inline const Grid<Real>* getArg3() {
+ return perCellCorr; }
+ typedef Grid<Real> type3;inline const MACGrid* getArg4() {
+ return fractions; }
+ typedef MACGrid type4;inline const Grid<Real> * getArg5() {
+ return phi; }
+ typedef Grid<Real> type5;inline const Grid<Real> * getArg6() {
+ return curv; }
+ typedef Grid<Real> type6;inline const Real& getArg7() {
+ return surfTens; }
+ typedef Real type7;inline const Real& getArg8() {
+ return gfClamp; }
+ typedef Real type8; void runMessage() { debMsg("Executing kernel MakeRhs ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,rhs,vel,perCellCorr,fractions,phi,curv,surfTens,gfClamp,cnt,sum); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,rhs,vel,perCellCorr,fractions,phi,curv,surfTens,gfClamp,cnt,sum); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_reduce (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_reduce (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ MakeRhs (MakeRhs& o, tbb::split) : KernelBase(o) ,flags(o.flags),rhs(o.rhs),vel(o.vel),perCellCorr(o.perCellCorr),fractions(o.fractions),phi(o.phi),curv(o.curv),surfTens(o.surfTens),gfClamp(o.gfClamp) ,cnt(0),sum(0) {
+}
+ void join(const MakeRhs & o) {
+ cnt += o.cnt; sum += o.sum; }
+ const FlagGrid& flags; Grid<Real>& rhs; const MACGrid& vel; const Grid<Real>* perCellCorr; const MACGrid* fractions; const Grid<Real> * phi; const Grid<Real> * curv; const Real surfTens; const Real gfClamp; int cnt; double sum; }
+;
+
+//! Kernel: make velocity divergence free by subtracting pressure gradient
+
+
+ struct knCorrectVelocity : public KernelBase {
+ knCorrectVelocity(const FlagGrid& flags, MACGrid& vel, const Grid<Real>& pressure) : KernelBase(&flags,1) ,flags(flags),vel(vel),pressure(pressure) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, MACGrid& vel, const Grid<Real>& pressure ) const {
+ const IndexInt idx = flags.index(i,j,k);
+ if(flags.isFluid(idx)) {
+ if( flags.isFluid(i-1,j,k)) vel[idx].x -= (pressure[idx] - pressure(i-1,j,k));
+ if( flags.isFluid(i,j-1,k)) vel[idx].y -= (pressure[idx] - pressure(i,j-1,k));
+ if(flags.is3D() && flags.isFluid(i,j,k-1)) vel[idx].z -= (pressure[idx] - pressure(i,j,k-1));
+
+ if( flags.isEmpty(i-1,j,k)) vel[idx].x -= pressure[idx];
+ if( flags.isEmpty(i,j-1,k)) vel[idx].y -= pressure[idx];
+ if(flags.is3D() && flags.isEmpty(i,j,k-1)) vel[idx].z -= pressure[idx];
+ } else if(flags.isEmpty(idx)&&!flags.isOutflow(idx)) { // don't change velocities in outflow cells
+ if(flags.isFluid(i-1,j,k)) vel[idx].x += pressure(i-1,j,k);
+ else vel[idx].x = 0.f;
+ if(flags.isFluid(i,j-1,k)) vel[idx].y += pressure(i,j-1,k);
+ else vel[idx].y = 0.f;
+ if(flags.is3D()) {
+ if(flags.isFluid(i,j,k-1)) vel[idx].z += pressure(i,j,k-1);
+ else vel[idx].z = 0.f;
+ }
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline const Grid<Real>& getArg2() {
+ return pressure; }
+ typedef Grid<Real> type2; void runMessage() { debMsg("Executing kernel knCorrectVelocity ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,pressure); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,vel,pressure); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; MACGrid& vel; const Grid<Real>& pressure; }
+;
+
+// *****************************************************************************
+// Ghost fluid helpers
+
+// calculate fraction filled with liquid (note, assumes inside value is < outside!)
+inline static Real thetaHelper(const Real inside, const Real outside)
+{
+ const Real denom = inside-outside;
+ if(denom > -1e-04) return 0.5; // should always be neg, and large enough...
+ return std::max(Real(0), std::min(Real(1), inside/denom));
+}
+
+// calculate ghost fluid factor, cell at idx should be a fluid cell
+inline static Real ghostFluidHelper(const IndexInt idx, const int offset, const Grid<Real> &phi, const Real gfClamp)
+{
+ Real alpha = thetaHelper(phi[idx], phi[idx+offset]);
+ if(alpha < gfClamp) return alpha = gfClamp;
+ return (1.-(1./alpha));
+}
+
+inline static Real surfTensHelper(const IndexInt idx, const int offset, const Grid<Real> &phi, const Grid<Real> &curv, const Real surfTens, const Real gfClamp)
+{
+ return surfTens*(curv[idx+offset] - ghostFluidHelper(idx, offset, phi, gfClamp)*curv[idx]);
+}
+
+//! Kernel: Adapt A0 for ghost fluid
+
+
+ struct ApplyGhostFluidDiagonal : public KernelBase {
+ ApplyGhostFluidDiagonal(Grid<Real> &A0, const FlagGrid &flags, const Grid<Real> &phi, const Real gfClamp) : KernelBase(&A0,1) ,A0(A0),flags(flags),phi(phi),gfClamp(gfClamp) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real> &A0, const FlagGrid &flags, const Grid<Real> &phi, const Real gfClamp ) const {
+ const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ const IndexInt idx = flags.index(i,j,k);
+ if(!flags.isFluid(idx)) return;
+
+ if(flags.isEmpty(i-1,j,k)) A0[idx] -= ghostFluidHelper(idx, -X, phi, gfClamp);
+ if(flags.isEmpty(i+1,j,k)) A0[idx] -= ghostFluidHelper(idx, +X, phi, gfClamp);
+ if(flags.isEmpty(i,j-1,k)) A0[idx] -= ghostFluidHelper(idx, -Y, phi, gfClamp);
+ if(flags.isEmpty(i,j+1,k)) A0[idx] -= ghostFluidHelper(idx, +Y, phi, gfClamp);
+ if(flags.is3D()) {
+ if(flags.isEmpty(i,j,k-1)) A0[idx] -= ghostFluidHelper(idx, -Z, phi, gfClamp);
+ if(flags.isEmpty(i,j,k+1)) A0[idx] -= ghostFluidHelper(idx, +Z, phi, gfClamp);
+ }
+} inline Grid<Real> & getArg0() {
+ return A0; }
+ typedef Grid<Real> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<Real> & getArg2() {
+ return phi; }
+ typedef Grid<Real> type2;inline const Real& getArg3() {
+ return gfClamp; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel ApplyGhostFluidDiagonal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,A0,flags,phi,gfClamp); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,A0,flags,phi,gfClamp); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<Real> & A0; const FlagGrid& flags; const Grid<Real> & phi; const Real gfClamp; }
+;
+
+//! Kernel: Apply velocity update: ghost fluid contribution
+
+
+
+
+ struct knCorrectVelocityGhostFluid : public KernelBase {
+ knCorrectVelocityGhostFluid( MACGrid &vel, const FlagGrid &flags, const Grid<Real> &pressure, const Grid<Real> &phi, Real gfClamp, const Grid<Real> *curv, const Real surfTens) : KernelBase(&vel,1) ,vel(vel),flags(flags),pressure(pressure),phi(phi),gfClamp(gfClamp),curv(curv),surfTens(surfTens) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid &vel, const FlagGrid &flags, const Grid<Real> &pressure, const Grid<Real> &phi, Real gfClamp, const Grid<Real> *curv, const Real surfTens ) const {
+ const IndexInt X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ const IndexInt idx = flags.index(i,j,k);
+ if(flags.isFluid(idx)) {
+ if( flags.isEmpty(i-1,j,k)) vel[idx][0] += pressure[idx] * ghostFluidHelper(idx, -X, phi, gfClamp);
+ if( flags.isEmpty(i,j-1,k)) vel[idx][1] += pressure[idx] * ghostFluidHelper(idx, -Y, phi, gfClamp);
+ if(flags.is3D() && flags.isEmpty(i,j,k-1)) vel[idx][2] += pressure[idx] * ghostFluidHelper(idx, -Z, phi, gfClamp);
+ } else if(flags.isEmpty(idx) && !flags.isOutflow(idx)) { // do not change velocities in outflow cells
+ if(flags.isFluid(i-1,j,k)) vel[idx][0] -= pressure(i-1,j,k) * ghostFluidHelper(idx-X, +X, phi, gfClamp);
+ else vel[idx].x = 0.f;
+ if(flags.isFluid(i,j-1,k)) vel[idx][1] -= pressure(i,j-1,k) * ghostFluidHelper(idx-Y, +Y, phi, gfClamp);
+ else vel[idx].y = 0.f;
+ if(flags.is3D()) {
+ if(flags.isFluid(i,j,k-1)) vel[idx][2] -= pressure(i,j,k-1) * ghostFluidHelper(idx-Z, +Z, phi, gfClamp);
+ else vel[idx].z = 0.f;
+ }
+ }
+
+ if(curv) {
+ if(flags.isFluid(idx)) {
+ if( flags.isEmpty(i-1,j,k)) vel[idx].x += surfTensHelper(idx, -X, phi, *curv, surfTens, gfClamp);
+ if( flags.isEmpty(i,j-1,k)) vel[idx].y += surfTensHelper(idx, -Y, phi, *curv, surfTens, gfClamp);
+ if(flags.is3D() && flags.isEmpty(i,j,k-1)) vel[idx].z += surfTensHelper(idx, -Z, phi, *curv, surfTens, gfClamp);
+ } else if(flags.isEmpty(idx) && !flags.isOutflow(idx)) { // do not change velocities in outflow cells
+ vel[idx].x -= (flags.isFluid(i-1,j,k)) ? surfTensHelper(idx-X, +X, phi, *curv, surfTens, gfClamp) : 0.f;
+ vel[idx].y -= (flags.isFluid(i,j-1,k)) ? surfTensHelper(idx-Y, +Y, phi, *curv, surfTens, gfClamp) : 0.f;
+ if(flags.is3D()) vel[idx].z -= (flags.isFluid(i,j,k-1)) ? surfTensHelper(idx-Z, +Z, phi, *curv, surfTens, gfClamp) : 0.f;
+ }
+ }
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<Real> & getArg2() {
+ return pressure; }
+ typedef Grid<Real> type2;inline const Grid<Real> & getArg3() {
+ return phi; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return gfClamp; }
+ typedef Real type4;inline const Grid<Real> * getArg5() {
+ return curv; }
+ typedef Grid<Real> type5;inline const Real& getArg6() {
+ return surfTens; }
+ typedef Real type6; void runMessage() { debMsg("Executing kernel knCorrectVelocityGhostFluid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,flags,pressure,phi,gfClamp,curv,surfTens); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,flags,pressure,phi,gfClamp,curv,surfTens); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ MACGrid& vel; const FlagGrid& flags; const Grid<Real> & pressure; const Grid<Real> & phi; Real gfClamp; const Grid<Real> * curv; const Real surfTens; }
+;
+
+
+// improve behavior of clamping for large time steps:
+inline static Real ghostFluidWasClamped(const IndexInt idx, const int offset, const Grid<Real> &phi, const Real gfClamp)
+{
+ const Real alpha = thetaHelper(phi[idx], phi[idx+offset]);
+ if(alpha < gfClamp) return true;
+ return false;
+}
+
+
+
+
+
+ struct knReplaceClampedGhostFluidVels : public KernelBase {
+ knReplaceClampedGhostFluidVels( MACGrid &vel, const FlagGrid &flags, const Grid<Real> &pressure, const Grid<Real> &phi, Real gfClamp ) : KernelBase(&vel,1) ,vel(vel),flags(flags),pressure(pressure),phi(phi),gfClamp(gfClamp) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid &vel, const FlagGrid &flags, const Grid<Real> &pressure, const Grid<Real> &phi, Real gfClamp ) const {
+ const IndexInt idx = flags.index(i,j,k);
+ const IndexInt X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ if(!flags.isEmpty(idx)) return;
+
+ if( flags.isFluid(i-1,j,k) && ghostFluidWasClamped(idx-X, +X, phi, gfClamp)) vel[idx][0] = vel[idx-X][0];
+ if( flags.isFluid(i,j-1,k) && ghostFluidWasClamped(idx-Y, +Y, phi, gfClamp)) vel[idx][1] = vel[idx-Y][1];
+ if(flags.is3D() && flags.isFluid(i,j,k-1) && ghostFluidWasClamped(idx-Z, +Z, phi, gfClamp)) vel[idx][2] = vel[idx-Z][2];
+
+ if( flags.isFluid(i+1,j,k) && ghostFluidWasClamped(idx+X, -X, phi, gfClamp)) vel[idx][0] = vel[idx+X][0];
+ if( flags.isFluid(i,j+1,k) && ghostFluidWasClamped(idx+Y, -Y, phi, gfClamp)) vel[idx][1] = vel[idx+Y][1];
+ if(flags.is3D() && flags.isFluid(i,j,k+1) && ghostFluidWasClamped(idx+Z, -Z, phi, gfClamp)) vel[idx][2] = vel[idx+Z][2];
+} inline MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const Grid<Real> & getArg2() {
+ return pressure; }
+ typedef Grid<Real> type2;inline const Grid<Real> & getArg3() {
+ return phi; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return gfClamp; }
+ typedef Real type4; void runMessage() { debMsg("Executing kernel knReplaceClampedGhostFluidVels ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,flags,pressure,phi,gfClamp); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,flags,pressure,phi,gfClamp); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ MACGrid& vel; const FlagGrid& flags; const Grid<Real> & pressure; const Grid<Real> & phi; Real gfClamp; }
+;
+
+//! Kernel: Compute min value of Real grid
+
+ struct CountEmptyCells : public KernelBase {
+ CountEmptyCells(const FlagGrid& flags) : KernelBase(&flags,0) ,flags(flags) ,numEmpty(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const FlagGrid& flags ,int& numEmpty) {
+ if(flags.isEmpty(idx)) numEmpty++;
+} inline operator int () {
+ return numEmpty; }
+ inline int & getRet() {
+ return numEmpty; }
+ inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0; void runMessage() { debMsg("Executing kernel CountEmptyCells ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, flags,numEmpty); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ CountEmptyCells (CountEmptyCells& o, tbb::split) : KernelBase(o) ,flags(o.flags) ,numEmpty(0) {
+}
+ void join(const CountEmptyCells & o) {
+ numEmpty += o.numEmpty; }
+ const FlagGrid& flags; int numEmpty; }
+;
+
+// *****************************************************************************
+// Misc helpers
+
+//! Change 'A' and 'rhs' such that pressure at 'fixPidx' is fixed to 'value'
+void fixPressure(int fixPidx, Real value, Grid<Real>& rhs, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak)
+{
+ // Bring to rhs at neighbors
+ rhs[fixPidx + Ai.getStrideX()] -= Ai[fixPidx] * value;
+ rhs[fixPidx + Aj.getStrideY()] -= Aj[fixPidx] * value;
+ rhs[fixPidx - Ai.getStrideX()] -= Ai[fixPidx - Ai.getStrideX()] * value;
+ rhs[fixPidx - Aj.getStrideY()] -= Aj[fixPidx - Aj.getStrideY()] * value;
+ if(rhs.is3D()) {
+ rhs[fixPidx + Ak.getStrideZ()] -= Ak[fixPidx] * value;
+ rhs[fixPidx - Ak.getStrideZ()] -= Ak[fixPidx - Ak.getStrideZ()] * value;
+ }
+
+ // Trivialize equation at 'fixPidx' to: pressure[fixPidx] = value
+ rhs[fixPidx] = value;
+ A0[fixPidx] = Real(1);
+ Ai[fixPidx] = Aj[fixPidx] = Ak[fixPidx] = Real(0);
+ Ai[fixPidx - Ai.getStrideX()] = Real(0);
+ Aj[fixPidx - Aj.getStrideY()] = Real(0);
+ if(rhs.is3D()) { Ak[fixPidx - Ak.getStrideZ()] = Real(0); }
+}
+
+// for "static" MG mode, keep one MG data structure per fluid solver
+// leave cleanup to OS/user if nonzero at program termination (PcMGStatic mode)
+// alternatively, manually release in scene file with releaseMG
+static std::map<FluidSolver*, GridMg*> gMapMG;
+
+void releaseMG(FluidSolver* solver=nullptr) {
+ // release all?
+ if(!solver) {
+ for(std::map<FluidSolver*, GridMg*>::iterator it = gMapMG.begin(); it != gMapMG.end(); it++) {
+ if(it->first != nullptr) releaseMG(it->first);
+ }
+ return;
+ }
+
+ GridMg* mg = gMapMG[solver];
+ if(mg) {
+ delete mg;
+ gMapMG[solver] = nullptr;
+ }
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "releaseMG" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FluidSolver* solver = _args.getPtrOpt<FluidSolver >("solver",0,nullptr,&_lock); _retval = getPyNone(); releaseMG(solver); _args.check(); }
+ pbFinalizePlugin(parent,"releaseMG", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("releaseMG",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_releaseMG ("","releaseMG",_W_0);
+extern "C" {
+ void PbRegister_releaseMG() {
+ KEEP_UNUSED(_RP_releaseMG); }
+ }
+
+
+
+
+// *****************************************************************************
+// Main pressure solve
+
+// Note , all three pressure solve helper functions take
+// identical parameters, apart from the RHS grid (and different const values)
+
+
+//! Compute rhs for pressure solve
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void computePressureRhs( Grid<Real>& rhs, const MACGrid& vel, const Grid<Real>& pressure, const FlagGrid& flags, Real cgAccuracy = 1e-3, const Grid<Real>* phi = 0, const Grid<Real>* perCellCorr = 0, const MACGrid* fractions = 0, Real gfClamp = 1e-04, Real cgMaxIterFac = 1.5, bool precondition = true, int preconditioner = PcMIC, bool enforceCompatibility = false, bool useL2Norm = false, bool zeroPressureFixing = false, const Grid<Real> *curv = NULL, const Real surfTens = 0. ) {
+ // compute divergence and init right hand side
+ MakeRhs kernMakeRhs (flags, rhs, vel, perCellCorr, fractions, phi, curv, surfTens, gfClamp );
+
+ if(enforceCompatibility)
+ rhs += (Real)(-kernMakeRhs.sum / (Real)kernMakeRhs.cnt);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "computePressureRhs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& rhs = *_args.getPtr<Grid<Real> >("rhs",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); const Grid<Real>& pressure = *_args.getPtr<Grid<Real> >("pressure",2,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",3,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",4,1e-3,&_lock); const Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",5,0,&_lock); const Grid<Real>* perCellCorr = _args.getPtrOpt<Grid<Real> >("perCellCorr",6,0,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",7,0,&_lock); Real gfClamp = _args.getOpt<Real >("gfClamp",8,1e-04,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",9,1.5,&_lock); bool precondition = _args.getOpt<bool >("precondition",10,true,&_lock); int preconditioner = _args.getOpt<int >("preconditioner",11,PcMIC,&_lock); bool enforceCompatibility = _args.getOpt<bool >("enforceCompatibility",12,false,&_lock); bool useL2Norm = _args.getOpt<bool >("useL2Norm",13,false,&_lock); bool zeroPressureFixing = _args.getOpt<bool >("zeroPressureFixing",14,false,&_lock); const Grid<Real> * curv = _args.getPtrOpt<Grid<Real> >("curv",15,NULL,&_lock); const Real surfTens = _args.getOpt<Real >("surfTens",16,0. ,&_lock); _retval = getPyNone(); computePressureRhs(rhs,vel,pressure,flags,cgAccuracy,phi,perCellCorr,fractions,gfClamp,cgMaxIterFac,precondition,preconditioner,enforceCompatibility,useL2Norm,zeroPressureFixing,curv,surfTens); _args.check(); }
+ pbFinalizePlugin(parent,"computePressureRhs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("computePressureRhs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_computePressureRhs ("","computePressureRhs",_W_1);
+extern "C" {
+ void PbRegister_computePressureRhs() {
+ KEEP_UNUSED(_RP_computePressureRhs); }
+ }
+
+
+
+//! Build and solve pressure system of equations
+//! perCellCorr: a divergence correction for each cell, optional
+//! fractions: for 2nd order obstacle boundaries, optional
+//! gfClamp: clamping threshold for ghost fluid method
+//! cgMaxIterFac: heuristic to determine maximal number of CG iteations, increase for more accurate solutions
+//! preconditioner: MIC, or MG (see Preconditioner enum)
+//! useL2Norm: use max norm by default, can be turned to L2 here
+//! zeroPressureFixing: remove null space by fixing a single pressure value, needed for MG
+//! curv: curvature for surface tension effects
+//! surfTens: surface tension coefficient
+//! retRhs: return RHS divergence, e.g., for debugging; optional
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void solvePressureSystem( Grid<Real>& rhs, MACGrid& vel, Grid<Real>& pressure, const FlagGrid& flags, Real cgAccuracy = 1e-3, const Grid<Real>* phi = 0, const Grid<Real>* perCellCorr = 0, const MACGrid* fractions = 0, Real gfClamp = 1e-04, Real cgMaxIterFac = 1.5, bool precondition = true, int preconditioner = PcMIC, const bool enforceCompatibility = false, const bool useL2Norm = false, const bool zeroPressureFixing = false, const Grid<Real> *curv = NULL, const Real surfTens = 0.) {
+ if(precondition==false) preconditioner = PcNone; // for backwards compatibility
+
+ // reserve temp grids
+ FluidSolver* parent = flags.getParent();
+ Grid<Real> residual(parent);
+ Grid<Real> search(parent);
+ Grid<Real> A0(parent);
+ Grid<Real> Ai(parent);
+ Grid<Real> Aj(parent);
+ Grid<Real> Ak(parent);
+ Grid<Real> tmp(parent);
+
+ // setup matrix and boundaries
+ MakeLaplaceMatrix(flags, A0, Ai, Aj, Ak, fractions);
+
+ if(phi) {
+ ApplyGhostFluidDiagonal(A0, flags, *phi, gfClamp);
+ }
+
+ // check whether we need to fix some pressure value...
+ // (manually enable, or automatically for high accuracy, can cause asymmetries otherwise)
+ if(zeroPressureFixing || cgAccuracy<1e-07) {
+ if(FLOATINGPOINT_PRECISION==1) debMsg("Warning - high CG accuracy with single-precision floating point accuracy might not converge...", 2);
+
+ int numEmpty = CountEmptyCells(flags);
+ IndexInt fixPidx = -1;
+ if(numEmpty==0) {
+ // Determine appropriate fluid cell for pressure fixing
+ // 1) First check some preferred positions for approx. symmetric zeroPressureFixing
+ Vec3i topCenter(flags.getSizeX() / 2, flags.getSizeY() - 1, flags.is3D() ? flags.getSizeZ() / 2 : 0);
+ Vec3i preferredPos [] = { topCenter,
+ topCenter - Vec3i(0,1,0),
+ topCenter - Vec3i(0,2,0) };
+
+ for (Vec3i pos : preferredPos) {
+ if(flags.isFluid(pos)) {
+ fixPidx = flags.index(pos);
+ break;
+ }
+ }
+
+ // 2) Then search whole domain
+ if(fixPidx == -1) {
+ FOR_IJK_BND(flags,1) {
+ if(flags.isFluid(i,j,k)) {
+ fixPidx = flags.index(i,j,k);
+ // break FOR_IJK_BND loop
+ i = flags.getSizeX()-1;
+ j = flags.getSizeY()-1;
+ k = __kmax;
+ }
+ }
+ }
+ //debMsg("No empty cells! Fixing pressure of cell "<<fixPidx<<" to zero",1);
+ }
+ if(fixPidx>=0) {
+ fixPressure(fixPidx, Real(0), rhs, A0, Ai, Aj, Ak);
+ static bool msgOnce = false;
+ if(!msgOnce) { debMsg("Pinning pressure of cell "<<fixPidx<<" to zero", 2); msgOnce=true; }
+ }
+ }
+
+ // CG setup
+ // note: the last factor increases the max iterations for 2d, which right now can't use a preconditioner
+ GridCgInterface *gcg;
+ if(vel.is3D())
+ gcg = new GridCg<ApplyMatrix> (pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+ else
+ gcg = new GridCg<ApplyMatrix2D>(pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
+
+ gcg->setAccuracy( cgAccuracy );
+ gcg->setUseL2Norm( useL2Norm );
+
+ int maxIter = 0;
+
+ Grid<Real> *pca0 = nullptr, *pca1 = nullptr, *pca2 = nullptr, *pca3 = nullptr;
+ GridMg* pmg = nullptr;
+
+ // optional preconditioning
+ if(preconditioner == PcNone || preconditioner == PcMIC) {
+ maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
+
+ pca0 = new Grid<Real>(parent);
+ pca1 = new Grid<Real>(parent);
+ pca2 = new Grid<Real>(parent);
+ pca3 = new Grid<Real>(parent);
+
+ gcg->setICPreconditioner(
+ preconditioner == PcMIC ? GridCgInterface::PC_mICP : GridCgInterface::PC_None,
+ pca0, pca1, pca2, pca3);
+ } else if(preconditioner == PcMGDynamic || preconditioner == PcMGStatic) {
+ maxIter = 100;
+
+ pmg = gMapMG[parent];
+ if(!pmg) {
+ pmg = new GridMg(pressure.getSize());
+ gMapMG[parent] = pmg;
+ }
+
+ gcg->setMGPreconditioner( GridCgInterface::PC_MGP, pmg);
+ }
+
+ // CG solve
+ for (int iter=0; iter<maxIter; iter++) {
+ if(!gcg->iterate()) iter=maxIter;
+ if(iter<maxIter) debMsg("FluidSolver::solvePressure iteration "<<iter<<", residual: "<<gcg->getResNorm(), 9);
+ }
+ debMsg("FluidSolver::solvePressure done. Iterations:"<<gcg->getIterations()<<", residual:"<<gcg->getResNorm(), 2);
+
+ // Cleanup
+ if(gcg) delete gcg;
+ if(pca0) delete pca0;
+ if(pca1) delete pca1;
+ if(pca2) delete pca2;
+ if(pca3) delete pca3;
+
+ // PcMGDynamic: always delete multigrid solver after use
+ // PcMGStatic: keep multigrid solver for next solve
+ if(pmg && preconditioner==PcMGDynamic) releaseMG(parent);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "solvePressureSystem" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& rhs = *_args.getPtr<Grid<Real> >("rhs",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); Grid<Real>& pressure = *_args.getPtr<Grid<Real> >("pressure",2,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",3,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",4,1e-3,&_lock); const Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",5,0,&_lock); const Grid<Real>* perCellCorr = _args.getPtrOpt<Grid<Real> >("perCellCorr",6,0,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",7,0,&_lock); Real gfClamp = _args.getOpt<Real >("gfClamp",8,1e-04,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",9,1.5,&_lock); bool precondition = _args.getOpt<bool >("precondition",10,true,&_lock); int preconditioner = _args.getOpt<int >("preconditioner",11,PcMIC,&_lock); const bool enforceCompatibility = _args.getOpt<bool >("enforceCompatibility",12,false,&_lock); const bool useL2Norm = _args.getOpt<bool >("useL2Norm",13,false,&_lock); const bool zeroPressureFixing = _args.getOpt<bool >("zeroPressureFixing",14,false,&_lock); const Grid<Real> * curv = _args.getPtrOpt<Grid<Real> >("curv",15,NULL,&_lock); const Real surfTens = _args.getOpt<Real >("surfTens",16,0.,&_lock); _retval = getPyNone(); solvePressureSystem(rhs,vel,pressure,flags,cgAccuracy,phi,perCellCorr,fractions,gfClamp,cgMaxIterFac,precondition,preconditioner,enforceCompatibility,useL2Norm,zeroPressureFixing,curv,surfTens); _args.check(); }
+ pbFinalizePlugin(parent,"solvePressureSystem", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("solvePressureSystem",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_solvePressureSystem ("","solvePressureSystem",_W_2);
+extern "C" {
+ void PbRegister_solvePressureSystem() {
+ KEEP_UNUSED(_RP_solvePressureSystem); }
+ }
+
+
+
+//! Apply pressure gradient to make velocity field divergence free
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void correctVelocity( MACGrid& vel, Grid<Real>& pressure, const FlagGrid& flags, Real cgAccuracy = 1e-3, const Grid<Real>* phi = 0, const Grid<Real>* perCellCorr = 0, const MACGrid* fractions = 0, Real gfClamp = 1e-04, Real cgMaxIterFac = 1.5, bool precondition = true, int preconditioner = PcMIC, bool enforceCompatibility = false, bool useL2Norm = false, bool zeroPressureFixing = false, const Grid<Real> *curv = NULL, const Real surfTens = 0.) {
+ knCorrectVelocity(flags, vel, pressure);
+ if(phi) {
+ knCorrectVelocityGhostFluid(vel, flags, pressure, *phi, gfClamp, curv, surfTens);
+ // improve behavior of clamping for large time steps:
+ knReplaceClampedGhostFluidVels(vel, flags, pressure, *phi, gfClamp);
+ }
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "correctVelocity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Real>& pressure = *_args.getPtr<Grid<Real> >("pressure",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",3,1e-3,&_lock); const Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",4,0,&_lock); const Grid<Real>* perCellCorr = _args.getPtrOpt<Grid<Real> >("perCellCorr",5,0,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",6,0,&_lock); Real gfClamp = _args.getOpt<Real >("gfClamp",7,1e-04,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",8,1.5,&_lock); bool precondition = _args.getOpt<bool >("precondition",9,true,&_lock); int preconditioner = _args.getOpt<int >("preconditioner",10,PcMIC,&_lock); bool enforceCompatibility = _args.getOpt<bool >("enforceCompatibility",11,false,&_lock); bool useL2Norm = _args.getOpt<bool >("useL2Norm",12,false,&_lock); bool zeroPressureFixing = _args.getOpt<bool >("zeroPressureFixing",13,false,&_lock); const Grid<Real> * curv = _args.getPtrOpt<Grid<Real> >("curv",14,NULL,&_lock); const Real surfTens = _args.getOpt<Real >("surfTens",15,0.,&_lock); _retval = getPyNone(); correctVelocity(vel,pressure,flags,cgAccuracy,phi,perCellCorr,fractions,gfClamp,cgMaxIterFac,precondition,preconditioner,enforceCompatibility,useL2Norm,zeroPressureFixing,curv,surfTens); _args.check(); }
+ pbFinalizePlugin(parent,"correctVelocity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("correctVelocity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_correctVelocity ("","correctVelocity",_W_3);
+extern "C" {
+ void PbRegister_correctVelocity() {
+ KEEP_UNUSED(_RP_correctVelocity); }
+ }
+
+
+
+//! Perform pressure projection of the velocity grid, calls
+//! all three pressure helper functions in a row.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void solvePressure( MACGrid& vel, Grid<Real>& pressure, const FlagGrid& flags, Real cgAccuracy = 1e-3, const Grid<Real>* phi = 0, const Grid<Real>* perCellCorr = 0, const MACGrid* fractions = 0, Real gfClamp = 1e-04, Real cgMaxIterFac = 1.5, bool precondition = true, int preconditioner = PcMIC, bool enforceCompatibility = false, bool useL2Norm = false, bool zeroPressureFixing = false, const Grid<Real> *curv = NULL, const Real surfTens = 0., Grid<Real>* retRhs = NULL) {
+ Grid<Real> rhs(vel.getParent());
+
+ computePressureRhs(
+ rhs, vel, pressure, flags, cgAccuracy,
+ phi, perCellCorr, fractions, gfClamp,
+ cgMaxIterFac, precondition, preconditioner, enforceCompatibility,
+ useL2Norm, zeroPressureFixing, curv, surfTens);
+
+ solvePressureSystem(
+ rhs, vel, pressure, flags, cgAccuracy,
+ phi, perCellCorr, fractions, gfClamp,
+ cgMaxIterFac, precondition, preconditioner, enforceCompatibility,
+ useL2Norm, zeroPressureFixing, curv, surfTens);
+
+ correctVelocity(
+ vel, pressure, flags, cgAccuracy,
+ phi, perCellCorr, fractions, gfClamp,
+ cgMaxIterFac, precondition, preconditioner, enforceCompatibility,
+ useL2Norm, zeroPressureFixing, curv, surfTens);
+
+ // optionally , return RHS
+ if(retRhs) {
+ retRhs->copyFrom(rhs);
+ }
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "solvePressure" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Real>& pressure = *_args.getPtr<Grid<Real> >("pressure",1,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",3,1e-3,&_lock); const Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",4,0,&_lock); const Grid<Real>* perCellCorr = _args.getPtrOpt<Grid<Real> >("perCellCorr",5,0,&_lock); const MACGrid* fractions = _args.getPtrOpt<MACGrid >("fractions",6,0,&_lock); Real gfClamp = _args.getOpt<Real >("gfClamp",7,1e-04,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",8,1.5,&_lock); bool precondition = _args.getOpt<bool >("precondition",9,true,&_lock); int preconditioner = _args.getOpt<int >("preconditioner",10,PcMIC,&_lock); bool enforceCompatibility = _args.getOpt<bool >("enforceCompatibility",11,false,&_lock); bool useL2Norm = _args.getOpt<bool >("useL2Norm",12,false,&_lock); bool zeroPressureFixing = _args.getOpt<bool >("zeroPressureFixing",13,false,&_lock); const Grid<Real> * curv = _args.getPtrOpt<Grid<Real> >("curv",14,NULL,&_lock); const Real surfTens = _args.getOpt<Real >("surfTens",15,0.,&_lock); Grid<Real>* retRhs = _args.getPtrOpt<Grid<Real> >("retRhs",16,NULL,&_lock); _retval = getPyNone(); solvePressure(vel,pressure,flags,cgAccuracy,phi,perCellCorr,fractions,gfClamp,cgMaxIterFac,precondition,preconditioner,enforceCompatibility,useL2Norm,zeroPressureFixing,curv,surfTens,retRhs); _args.check(); }
+ pbFinalizePlugin(parent,"solvePressure", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("solvePressure",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_solvePressure ("","solvePressure",_W_4);
+extern "C" {
+ void PbRegister_solvePressure() {
+ KEEP_UNUSED(_RP_solvePressure); }
+ }
+
+
+
+} // end namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/ptsplugins.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/ptsplugins.cpp
new file mode 100644
index 00000000000..fee70e90995
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/ptsplugins.cpp
@@ -0,0 +1,210 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+// ----------------------------------------------------------------------------
+//
+// MantaFlow fluid solver framework
+// Copyright 2018 Kiwon Um, Nils Thuerey
+//
+// This program is free software, distributed under the terms of the
+// GNU General Public License (GPL)
+// http://www.gnu.org/licenses
+//
+// Particle system helper
+//
+// ----------------------------------------------------------------------------
+
+#include "particle.h"
+
+
+namespace Manta {
+
+
+
+ struct KnAddForcePvel : public KernelBase {
+ KnAddForcePvel(ParticleDataImpl<Vec3> &v, const Vec3 &da, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(v.size()) ,v(v),da(da),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<Vec3> &v, const Vec3 &da, const ParticleDataImpl<int> *ptype, const int exclude ) const {
+ if(ptype && ((*ptype)[idx] & exclude)) return;
+ v[idx] += da;
+} inline ParticleDataImpl<Vec3> & getArg0() {
+ return v; }
+ typedef ParticleDataImpl<Vec3> type0;inline const Vec3& getArg1() {
+ return da; }
+ typedef Vec3 type1;inline const ParticleDataImpl<int> * getArg2() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type2;inline const int& getArg3() {
+ return exclude; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel KnAddForcePvel ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, v,da,ptype,exclude); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<Vec3> & v; const Vec3& da; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+//! add force to vec3 particle data; a: acceleration
+
+void addForcePvel(ParticleDataImpl<Vec3> &vel, const Vec3 &a, const Real dt, const ParticleDataImpl<int> *ptype, const int exclude) {
+ KnAddForcePvel(vel, a*dt, ptype, exclude);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "addForcePvel" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; ParticleDataImpl<Vec3> & vel = *_args.getPtr<ParticleDataImpl<Vec3> >("vel",0,&_lock); const Vec3& a = _args.get<Vec3 >("a",1,&_lock); const Real dt = _args.get<Real >("dt",2,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtr<ParticleDataImpl<int> >("ptype",3,&_lock); const int exclude = _args.get<int >("exclude",4,&_lock); _retval = getPyNone(); addForcePvel(vel,a,dt,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"addForcePvel", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("addForcePvel",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_addForcePvel ("","addForcePvel",_W_0);
+extern "C" {
+ void PbRegister_addForcePvel() {
+ KEEP_UNUSED(_RP_addForcePvel); }
+ }
+
+
+
+
+
+ struct KnUpdateVelocityFromDeltaPos : public KernelBase {
+ KnUpdateVelocityFromDeltaPos(const BasicParticleSystem &p, ParticleDataImpl<Vec3> &v, const ParticleDataImpl<Vec3> &x_prev, const Real over_dt, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(p.size()) ,p(p),v(v),x_prev(x_prev),over_dt(over_dt),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystem &p, ParticleDataImpl<Vec3> &v, const ParticleDataImpl<Vec3> &x_prev, const Real over_dt, const ParticleDataImpl<int> *ptype, const int exclude ) const {
+ if(ptype && ((*ptype)[idx] & exclude)) return;
+ v[idx] = (p[idx].pos - x_prev[idx])*over_dt;
+} inline const BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline ParticleDataImpl<Vec3> & getArg1() {
+ return v; }
+ typedef ParticleDataImpl<Vec3> type1;inline const ParticleDataImpl<Vec3> & getArg2() {
+ return x_prev; }
+ typedef ParticleDataImpl<Vec3> type2;inline const Real& getArg3() {
+ return over_dt; }
+ typedef Real type3;inline const ParticleDataImpl<int> * getArg4() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type4;inline const int& getArg5() {
+ return exclude; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnUpdateVelocityFromDeltaPos ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, p,v,x_prev,over_dt,ptype,exclude); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystem& p; ParticleDataImpl<Vec3> & v; const ParticleDataImpl<Vec3> & x_prev; const Real over_dt; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+//! retrieve velocity from position change
+
+void updateVelocityFromDeltaPos(const BasicParticleSystem& parts, ParticleDataImpl<Vec3> &vel, const ParticleDataImpl<Vec3> &x_prev, const Real dt, const ParticleDataImpl<int> *ptype, const int exclude) {
+ KnUpdateVelocityFromDeltaPos(parts, vel, x_prev, 1.0/dt, ptype, exclude);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "updateVelocityFromDeltaPos" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<Vec3> & vel = *_args.getPtr<ParticleDataImpl<Vec3> >("vel",1,&_lock); const ParticleDataImpl<Vec3> & x_prev = *_args.getPtr<ParticleDataImpl<Vec3> >("x_prev",2,&_lock); const Real dt = _args.get<Real >("dt",3,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtr<ParticleDataImpl<int> >("ptype",4,&_lock); const int exclude = _args.get<int >("exclude",5,&_lock); _retval = getPyNone(); updateVelocityFromDeltaPos(parts,vel,x_prev,dt,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"updateVelocityFromDeltaPos", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("updateVelocityFromDeltaPos",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_updateVelocityFromDeltaPos ("","updateVelocityFromDeltaPos",_W_1);
+extern "C" {
+ void PbRegister_updateVelocityFromDeltaPos() {
+ KEEP_UNUSED(_RP_updateVelocityFromDeltaPos); }
+ }
+
+
+
+
+
+ struct KnStepEuler : public KernelBase {
+ KnStepEuler(BasicParticleSystem &p, const ParticleDataImpl<Vec3> &v, const Real dt, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(p.size()) ,p(p),v(v),dt(dt),ptype(ptype),exclude(exclude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystem &p, const ParticleDataImpl<Vec3> &v, const Real dt, const ParticleDataImpl<int> *ptype, const int exclude ) const {
+ if(ptype && ((*ptype)[idx] & exclude)) return;
+ p[idx].pos += v[idx]*dt;
+} inline BasicParticleSystem& getArg0() {
+ return p; }
+ typedef BasicParticleSystem type0;inline const ParticleDataImpl<Vec3> & getArg1() {
+ return v; }
+ typedef ParticleDataImpl<Vec3> type1;inline const Real& getArg2() {
+ return dt; }
+ typedef Real type2;inline const ParticleDataImpl<int> * getArg3() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type3;inline const int& getArg4() {
+ return exclude; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel KnStepEuler ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, p,v,dt,ptype,exclude); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ BasicParticleSystem& p; const ParticleDataImpl<Vec3> & v; const Real dt; const ParticleDataImpl<int> * ptype; const int exclude; }
+;
+//! simple foward Euler integration for particle system
+
+void eulerStep(BasicParticleSystem& parts, const ParticleDataImpl<Vec3> &vel, const ParticleDataImpl<int> *ptype, const int exclude) {
+ KnStepEuler(parts, vel, parts.getParent()->getDt(), ptype, exclude);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "eulerStep" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const ParticleDataImpl<Vec3> & vel = *_args.getPtr<ParticleDataImpl<Vec3> >("vel",1,&_lock); const ParticleDataImpl<int> * ptype = _args.getPtr<ParticleDataImpl<int> >("ptype",2,&_lock); const int exclude = _args.get<int >("exclude",3,&_lock); _retval = getPyNone(); eulerStep(parts,vel,ptype,exclude); _args.check(); }
+ pbFinalizePlugin(parent,"eulerStep", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("eulerStep",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_eulerStep ("","eulerStep",_W_2);
+extern "C" {
+ void PbRegister_eulerStep() {
+ KEEP_UNUSED(_RP_eulerStep); }
+ }
+
+
+
+
+
+
+ struct KnSetPartType : public KernelBase {
+ KnSetPartType(ParticleDataImpl<int> &ptype, const BasicParticleSystem &part, const int mark, const int stype, const FlagGrid &flags, const int cflag) : KernelBase(ptype.size()) ,ptype(ptype),part(part),mark(mark),stype(stype),flags(flags),cflag(cflag) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, ParticleDataImpl<int> &ptype, const BasicParticleSystem &part, const int mark, const int stype, const FlagGrid &flags, const int cflag ) const {
+ if(flags.isInBounds(part.getPos(idx), 0) && (flags.getAt(part.getPos(idx))&cflag) && (ptype[idx]&stype)) ptype[idx] = mark;
+} inline ParticleDataImpl<int> & getArg0() {
+ return ptype; }
+ typedef ParticleDataImpl<int> type0;inline const BasicParticleSystem& getArg1() {
+ return part; }
+ typedef BasicParticleSystem type1;inline const int& getArg2() {
+ return mark; }
+ typedef int type2;inline const int& getArg3() {
+ return stype; }
+ typedef int type3;inline const FlagGrid& getArg4() {
+ return flags; }
+ typedef FlagGrid type4;inline const int& getArg5() {
+ return cflag; }
+ typedef int type5; void runMessage() { debMsg("Executing kernel KnSetPartType ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, ptype,part,mark,stype,flags,cflag); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ ParticleDataImpl<int> & ptype; const BasicParticleSystem& part; const int mark; const int stype; const FlagGrid& flags; const int cflag; }
+;
+//! if particle is stype and in cflag cell, set ptype as mark
+
+void setPartType(const BasicParticleSystem &parts, ParticleDataImpl<int> &ptype, const int mark, const int stype, const FlagGrid &flags, const int cflag) {
+ KnSetPartType(ptype, parts, mark, stype, flags, cflag);
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setPartType" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<int> & ptype = *_args.getPtr<ParticleDataImpl<int> >("ptype",1,&_lock); const int mark = _args.get<int >("mark",2,&_lock); const int stype = _args.get<int >("stype",3,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",4,&_lock); const int cflag = _args.get<int >("cflag",5,&_lock); _retval = getPyNone(); setPartType(parts,ptype,mark,stype,flags,cflag); _args.check(); }
+ pbFinalizePlugin(parent,"setPartType", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setPartType",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setPartType ("","setPartType",_W_3);
+extern "C" {
+ void PbRegister_setPartType() {
+ KEEP_UNUSED(_RP_setPartType); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/secondaryparticles.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/secondaryparticles.cpp
new file mode 100644
index 00000000000..bb3431d0d03
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/secondaryparticles.cpp
@@ -0,0 +1,1263 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+*
+* MantaFlow fluid solver framework
+* Copyright 2017 Georg Kohl, Nils Thuerey
+*
+* This program is free software, distributed under the terms of the
+* GNU General Public License (GPL)
+* http://www.gnu.org/licenses
+*
+* Secondary particle plugin for FLIP simulations
+*
+******************************************************************************/
+
+#include "particle.h"
+#include "commonkernels.h"
+
+namespace Manta {
+
+#pragma region Secondary Particles for FLIP
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+// Secondary Particles for FLIP
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+
+// helper function that clamps the value in potential to the interval [tauMin, tauMax] and normalizes it to [0, 1] afterwards
+Real clampPotential(Real potential, Real tauMin, Real tauMax) {
+ return (std::min(potential, tauMax) - std::min(potential, tauMin)) / (tauMax - tauMin);
+}
+
+// computes all three potentials(trapped air, wave crest, kinetic energy) and the neighbor ratio for every fluid cell and stores it in the respective grid.
+// Is less readable but significantly faster than using seperate potential computation
+
+
+
+
+ struct knFlipComputeSecondaryParticlePotentials : public KernelBase {
+ knFlipComputeSecondaryParticlePotentials( Grid<Real> &potTA, Grid<Real> &potWC, Grid<Real> &potKE, Grid<Real> &neighborRatio, const FlagGrid &flags, const MACGrid &v, const Grid<Vec3> &normal, const int radius, const Real tauMinTA, const Real tauMaxTA, const Real tauMinWC, const Real tauMaxWC, const Real tauMinKE, const Real tauMaxKE, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle | FlagGrid::TypeOutflow | FlagGrid::TypeInflow) : KernelBase(&potTA,radius) ,potTA(potTA),potWC(potWC),potKE(potKE),neighborRatio(neighborRatio),flags(flags),v(v),normal(normal),radius(radius),tauMinTA(tauMinTA),tauMaxTA(tauMaxTA),tauMinWC(tauMinWC),tauMaxWC(tauMaxWC),tauMinKE(tauMinKE),tauMaxKE(tauMaxKE),scaleFromManta(scaleFromManta),itype(itype),jtype(jtype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real> &potTA, Grid<Real> &potWC, Grid<Real> &potKE, Grid<Real> &neighborRatio, const FlagGrid &flags, const MACGrid &v, const Grid<Vec3> &normal, const int radius, const Real tauMinTA, const Real tauMaxTA, const Real tauMinWC, const Real tauMaxWC, const Real tauMinKE, const Real tauMaxKE, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle | FlagGrid::TypeOutflow | FlagGrid::TypeInflow ) const {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ //compute trapped air potential + wave crest potential + neighbor ratio at once
+ const Vec3 &xi = scaleFromManta * Vec3(i, j, k); //scale to unit cube
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k);
+ const Vec3 &ni = getNormalized(normal(i, j, k));
+ Real vdiff = 0; //for trapped air
+ Real kappa = 0; //for wave crests
+ int countFluid = 0; //for neighbor ratio
+ int countMaxFluid = 0; //for neighbor ratio
+
+ //iterate over neighboring cells within radius
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || !flags.isInBounds(Vec3i(x, y, z)) || (flags(x, y, z) & jtype)) continue;
+
+ if (flags(x, y, z) & itype) {
+ countFluid++;
+ countMaxFluid++;
+ }
+ else {
+ countMaxFluid++;
+ }
+
+ const Vec3 &xj = scaleFromManta * Vec3(x, y, z); //scale to unit cube
+ const Vec3 &vj = scaleFromManta * v.getCentered(x, y, z);
+ const Vec3 &nj = getNormalized(normal(x, y, z));
+ const Vec3 xij = xi - xj;
+ const Vec3 vij = vi - vj;
+ Real h = !potTA.is3D() ? 1.414*radius : 1.732*radius; //estimate sqrt(2)*radius resp. sqrt(3)*radius for h, due to squared resp. cubic neighbor area
+ vdiff += norm(vij) * (1 - dot(getNormalized(vij), getNormalized(xij))) * (1 - norm(xij) / h);
+
+ if (dot(getNormalized(xij), ni) < 0) { //identifies wave crests
+ kappa += (1 - dot(ni, nj)) * (1 - norm(xij) / h);
+ }
+ }
+ }
+ }
+
+ neighborRatio(i, j, k) = float(countFluid) / float(countMaxFluid);
+
+ potTA(i, j, k) = clampPotential(vdiff, tauMinTA, tauMaxTA);
+ if (dot(getNormalized(vi), ni) >= 0.6) { //avoid to mark boarders of the scene as wave crest
+ potWC(i, j, k) = clampPotential(kappa, tauMinWC, tauMaxWC);
+ }
+ else {
+ potWC(i, j, k) = Real(0);
+ }
+
+ //compute kinetic energy potential
+ Real ek = Real(0.5) * 125 * normSquare(vi); //use arbitrary constant for mass, potential adjusts with thresholds anyways
+ potKE(i, j, k) = clampPotential(ek, tauMinKE, tauMaxKE);
+} inline Grid<Real> & getArg0() {
+ return potTA; }
+ typedef Grid<Real> type0;inline Grid<Real> & getArg1() {
+ return potWC; }
+ typedef Grid<Real> type1;inline Grid<Real> & getArg2() {
+ return potKE; }
+ typedef Grid<Real> type2;inline Grid<Real> & getArg3() {
+ return neighborRatio; }
+ typedef Grid<Real> type3;inline const FlagGrid& getArg4() {
+ return flags; }
+ typedef FlagGrid type4;inline const MACGrid& getArg5() {
+ return v; }
+ typedef MACGrid type5;inline const Grid<Vec3> & getArg6() {
+ return normal; }
+ typedef Grid<Vec3> type6;inline const int& getArg7() {
+ return radius; }
+ typedef int type7;inline const Real& getArg8() {
+ return tauMinTA; }
+ typedef Real type8;inline const Real& getArg9() {
+ return tauMaxTA; }
+ typedef Real type9;inline const Real& getArg10() {
+ return tauMinWC; }
+ typedef Real type10;inline const Real& getArg11() {
+ return tauMaxWC; }
+ typedef Real type11;inline const Real& getArg12() {
+ return tauMinKE; }
+ typedef Real type12;inline const Real& getArg13() {
+ return tauMaxKE; }
+ typedef Real type13;inline const Real& getArg14() {
+ return scaleFromManta; }
+ typedef Real type14;inline const int& getArg15() {
+ return itype; }
+ typedef int type15;inline const int& getArg16() {
+ return jtype; }
+ typedef int type16; void runMessage() { debMsg("Executing kernel knFlipComputeSecondaryParticlePotentials ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=radius; j<_maxY; j++) for (int i=radius; i<_maxX; i++) op(i,j,k,potTA,potWC,potKE,neighborRatio,flags,v,normal,radius,tauMinTA,tauMaxTA,tauMinWC,tauMaxWC,tauMinKE,tauMaxKE,scaleFromManta,itype,jtype); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=radius; i<_maxX; i++) op(i,j,k,potTA,potWC,potKE,neighborRatio,flags,v,normal,radius,tauMinTA,tauMaxTA,tauMinWC,tauMaxWC,tauMinKE,tauMaxKE,scaleFromManta,itype,jtype); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(radius, maxY), *this); }
+ Grid<Real> & potTA; Grid<Real> & potWC; Grid<Real> & potKE; Grid<Real> & neighborRatio; const FlagGrid& flags; const MACGrid& v; const Grid<Vec3> & normal; const int radius; const Real tauMinTA; const Real tauMaxTA; const Real tauMinWC; const Real tauMaxWC; const Real tauMinKE; const Real tauMaxKE; const Real scaleFromManta; const int itype; const int jtype; }
+;
+
+
+
+
+void flipComputeSecondaryParticlePotentials( Grid<Real> &potTA, Grid<Real> &potWC, Grid<Real> &potKE, Grid<Real> &neighborRatio, const FlagGrid &flags, const MACGrid &v, Grid<Vec3>& normal, const Grid<Real>& phi, const int radius, const Real tauMinTA, const Real tauMaxTA, const Real tauMinWC, const Real tauMaxWC, const Real tauMinKE, const Real tauMaxKE, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle | FlagGrid::TypeOutflow | FlagGrid::TypeInflow) {
+ potTA.clear();
+ potWC.clear();
+ potKE.clear();
+ neighborRatio.clear();
+ GradientOp(normal, phi);
+ knFlipComputeSecondaryParticlePotentials(potTA, potWC, potKE, neighborRatio, flags, v, normal, radius, tauMinTA, tauMaxTA, tauMinWC, tauMaxWC, tauMinKE, tauMaxKE, scaleFromManta, itype, jtype);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipComputeSecondaryParticlePotentials" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & potTA = *_args.getPtr<Grid<Real> >("potTA",0,&_lock); Grid<Real> & potWC = *_args.getPtr<Grid<Real> >("potWC",1,&_lock); Grid<Real> & potKE = *_args.getPtr<Grid<Real> >("potKE",2,&_lock); Grid<Real> & neighborRatio = *_args.getPtr<Grid<Real> >("neighborRatio",3,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",4,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",5,&_lock); Grid<Vec3>& normal = *_args.getPtr<Grid<Vec3> >("normal",6,&_lock); const Grid<Real>& phi = *_args.getPtr<Grid<Real> >("phi",7,&_lock); const int radius = _args.get<int >("radius",8,&_lock); const Real tauMinTA = _args.get<Real >("tauMinTA",9,&_lock); const Real tauMaxTA = _args.get<Real >("tauMaxTA",10,&_lock); const Real tauMinWC = _args.get<Real >("tauMinWC",11,&_lock); const Real tauMaxWC = _args.get<Real >("tauMaxWC",12,&_lock); const Real tauMinKE = _args.get<Real >("tauMinKE",13,&_lock); const Real tauMaxKE = _args.get<Real >("tauMaxKE",14,&_lock); const Real scaleFromManta = _args.get<Real >("scaleFromManta",15,&_lock); const int itype = _args.getOpt<int >("itype",16,FlagGrid::TypeFluid,&_lock); const int jtype = _args.getOpt<int >("jtype",17,FlagGrid::TypeObstacle | FlagGrid::TypeOutflow | FlagGrid::TypeInflow,&_lock); _retval = getPyNone(); flipComputeSecondaryParticlePotentials(potTA,potWC,potKE,neighborRatio,flags,v,normal,phi,radius,tauMinTA,tauMaxTA,tauMinWC,tauMaxWC,tauMinKE,tauMaxKE,scaleFromManta,itype,jtype); _args.check(); }
+ pbFinalizePlugin(parent,"flipComputeSecondaryParticlePotentials", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipComputeSecondaryParticlePotentials",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipComputeSecondaryParticlePotentials ("","flipComputeSecondaryParticlePotentials",_W_0);
+extern "C" {
+ void PbRegister_flipComputeSecondaryParticlePotentials() {
+ KEEP_UNUSED(_RP_flipComputeSecondaryParticlePotentials); }
+ }
+
+
+
+// adds secondary particles to &pts_sec for every fluid cell in &flags according to the potential grids &potTA, &potWC and &potKE
+// secondary particles are uniformly sampled in every fluid cell in a randomly offset cylinder in fluid movement direction
+// In contrast to flipSampleSecondaryParticles this uses more cylinders per cell and interpolates velocity and potentials.
+// To control number of cylinders in each dimension adjust radius(0.25=>2 cyl, 0.1666=>3 cyl, 0.125=>3cyl etc.).
+
+
+
+
+
+ struct knFlipSampleSecondaryParticlesMoreCylinders : public KernelBase {
+ knFlipSampleSecondaryParticlesMoreCylinders( const FlagGrid &flags, const MACGrid &v, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const Real lMin, const Real lMax, const Grid<Real> &potTA, const Grid<Real> &potWC, const Grid<Real> &potKE, const Grid<Real> &neighborRatio, const Real c_s, const Real c_b, const Real k_ta, const Real k_wc, const Real dt, const int itype = FlagGrid::TypeFluid) : KernelBase(&flags,0) ,flags(flags),v(v),pts_sec(pts_sec),v_sec(v_sec),l_sec(l_sec),lMin(lMin),lMax(lMax),potTA(potTA),potWC(potWC),potKE(potKE),neighborRatio(neighborRatio),c_s(c_s),c_b(c_b),k_ta(k_ta),k_wc(k_wc),dt(dt),itype(itype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid &flags, const MACGrid &v, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const Real lMin, const Real lMax, const Grid<Real> &potTA, const Grid<Real> &potWC, const Grid<Real> &potKE, const Grid<Real> &neighborRatio, const Real c_s, const Real c_b, const Real k_ta, const Real k_wc, const Real dt, const int itype = FlagGrid::TypeFluid ) {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ RandomStream mRand(9832);
+ Real radius = 0.25; //diameter=0.5 => sampling with two cylinders in each dimension since cell size=1
+ for (Real x = i - radius; x <= i + radius; x += 2 * radius) {
+ for (Real y = j - radius; y <= j + radius; y += 2 * radius) {
+ for (Real z = k - radius; z <= k + radius; z += 2 * radius) {
+
+ Vec3 xi = Vec3(x, y, z);
+ Real KE = potKE.getInterpolated(xi);
+ Real TA = potTA.getInterpolated(xi);
+ Real WC = potWC.getInterpolated(xi);
+
+ const int n = KE * (k_ta*TA + k_wc*WC) * dt; //number of secondary particles
+ if (n == 0) continue;
+ Vec3 vi = v.getInterpolated(xi);
+ Vec3 dir = dt*vi; //direction of movement of current particle
+ Vec3 e1 = getNormalized(Vec3(dir.z, 0, -dir.x)); //perpendicular to dir
+ Vec3 e2 = getNormalized(cross(e1, dir)); //perpendicular to dir and e1, so e1 and e1 create reference plane
+
+ for (int di = 0; di < n; di++) {
+ const Real r = radius * sqrt(mRand.getReal()); //distance to cylinder axis
+ const Real theta = mRand.getReal() * Real(2) * M_PI; //azimuth
+ const Real h = mRand.getReal() * norm(dt*vi); //distance to reference plane
+ Vec3 xd = xi + r*cos(theta)*e1 + r*sin(theta)*e2 + h*getNormalized(vi);
+ if (!flags.is3D()) xd.z = 0;
+ pts_sec.add(xd);
+
+ v_sec[v_sec.size() - 1] = r*cos(theta)*e1 + r*sin(theta)*e2 + vi; //init velocity of new particle
+ Real temp = (KE + TA + WC) / 3;
+ l_sec[l_sec.size() - 1] = ((lMax - lMin) * temp) + lMin + mRand.getReal()*0.1; //init lifetime of new particle
+
+ //init type of new particle
+ if (neighborRatio(i, j, k) < c_s) { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PSPRAY; }
+ else if (neighborRatio(i, j, k) > c_b) { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PBUBBLE; }
+ else { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PFOAM; }
+ }
+ }
+ }
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return v; }
+ typedef MACGrid type1;inline BasicParticleSystem& getArg2() {
+ return pts_sec; }
+ typedef BasicParticleSystem type2;inline ParticleDataImpl<Vec3> & getArg3() {
+ return v_sec; }
+ typedef ParticleDataImpl<Vec3> type3;inline ParticleDataImpl<Real> & getArg4() {
+ return l_sec; }
+ typedef ParticleDataImpl<Real> type4;inline const Real& getArg5() {
+ return lMin; }
+ typedef Real type5;inline const Real& getArg6() {
+ return lMax; }
+ typedef Real type6;inline const Grid<Real> & getArg7() {
+ return potTA; }
+ typedef Grid<Real> type7;inline const Grid<Real> & getArg8() {
+ return potWC; }
+ typedef Grid<Real> type8;inline const Grid<Real> & getArg9() {
+ return potKE; }
+ typedef Grid<Real> type9;inline const Grid<Real> & getArg10() {
+ return neighborRatio; }
+ typedef Grid<Real> type10;inline const Real& getArg11() {
+ return c_s; }
+ typedef Real type11;inline const Real& getArg12() {
+ return c_b; }
+ typedef Real type12;inline const Real& getArg13() {
+ return k_ta; }
+ typedef Real type13;inline const Real& getArg14() {
+ return k_wc; }
+ typedef Real type14;inline const Real& getArg15() {
+ return dt; }
+ typedef Real type15;inline const int& getArg16() {
+ return itype; }
+ typedef int type16; void runMessage() { debMsg("Executing kernel knFlipSampleSecondaryParticlesMoreCylinders ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=0; j< _maxY; j++) for (int i=0; i< _maxX; i++) op(i,j,k, flags,v,pts_sec,v_sec,l_sec,lMin,lMax,potTA,potWC,potKE,neighborRatio,c_s,c_b,k_ta,k_wc,dt,itype); }
+ const FlagGrid& flags; const MACGrid& v; BasicParticleSystem& pts_sec; ParticleDataImpl<Vec3> & v_sec; ParticleDataImpl<Real> & l_sec; const Real lMin; const Real lMax; const Grid<Real> & potTA; const Grid<Real> & potWC; const Grid<Real> & potKE; const Grid<Real> & neighborRatio; const Real c_s; const Real c_b; const Real k_ta; const Real k_wc; const Real dt; const int itype; }
+;
+
+// adds secondary particles to &pts_sec for every fluid cell in &flags according to the potential grids &potTA, &potWC and &potKE
+// secondary particles are uniformly sampled in every fluid cell in a randomly offset cylinder in fluid movement direction
+
+
+
+
+
+ struct knFlipSampleSecondaryParticles : public KernelBase {
+ knFlipSampleSecondaryParticles( const FlagGrid &flags, const MACGrid &v, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const Real lMin, const Real lMax, const Grid<Real> &potTA, const Grid<Real> &potWC, const Grid<Real> &potKE, const Grid<Real> &neighborRatio, const Real c_s, const Real c_b, const Real k_ta, const Real k_wc, const Real dt, const int itype = FlagGrid::TypeFluid) : KernelBase(&flags,0) ,flags(flags),v(v),pts_sec(pts_sec),v_sec(v_sec),l_sec(l_sec),lMin(lMin),lMax(lMax),potTA(potTA),potWC(potWC),potKE(potKE),neighborRatio(neighborRatio),c_s(c_s),c_b(c_b),k_ta(k_ta),k_wc(k_wc),dt(dt),itype(itype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid &flags, const MACGrid &v, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const Real lMin, const Real lMax, const Grid<Real> &potTA, const Grid<Real> &potWC, const Grid<Real> &potKE, const Grid<Real> &neighborRatio, const Real c_s, const Real c_b, const Real k_ta, const Real k_wc, const Real dt, const int itype = FlagGrid::TypeFluid ) {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ Real KE = potKE(i, j, k);
+ Real TA = potTA(i, j, k);
+ Real WC = potWC(i, j, k);
+
+ const int n = KE * (k_ta*TA + k_wc*WC) * dt; //number of secondary particles
+ if (n == 0) return;
+ RandomStream mRand(9832);
+
+ Vec3 xi = Vec3(i + mRand.getReal(), j + mRand.getReal(), k + mRand.getReal()); //randomized offset uniform in cell
+ Vec3 vi = v.getInterpolated(xi);
+ Vec3 dir = dt*vi; //direction of movement of current particle
+ Vec3 e1 = getNormalized(Vec3(dir.z, 0, -dir.x)); //perpendicular to dir
+ Vec3 e2 = getNormalized(cross(e1, dir)); //perpendicular to dir and e1, so e1 and e1 create reference plane
+
+ for (int di = 0; di < n; di++) {
+ const Real r = Real(0.5) * sqrt(mRand.getReal()); //distance to cylinder axis
+ const Real theta = mRand.getReal() * Real(2) * M_PI; //azimuth
+ const Real h = mRand.getReal() * norm(dt*vi); //distance to reference plane
+ Vec3 xd = xi + r*cos(theta)*e1 + r*sin(theta)*e2 + h*getNormalized(vi);
+ if (!flags.is3D()) xd.z = 0;
+ pts_sec.add(xd);
+
+ v_sec[v_sec.size() - 1] = r*cos(theta)*e1 + r*sin(theta)*e2 + vi; //init velocity of new particle
+ Real temp = (KE + TA + WC) / 3;
+ l_sec[l_sec.size() - 1] = ((lMax - lMin) * temp) + lMin + mRand.getReal()*0.1; //init lifetime of new particle
+
+ //init type of new particle
+ if (neighborRatio(i, j, k) < c_s) { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PSPRAY; }
+ else if (neighborRatio(i, j, k) > c_b) { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PBUBBLE; }
+ else { pts_sec[pts_sec.size() - 1].flag = ParticleBase::PFOAM; }
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return v; }
+ typedef MACGrid type1;inline BasicParticleSystem& getArg2() {
+ return pts_sec; }
+ typedef BasicParticleSystem type2;inline ParticleDataImpl<Vec3> & getArg3() {
+ return v_sec; }
+ typedef ParticleDataImpl<Vec3> type3;inline ParticleDataImpl<Real> & getArg4() {
+ return l_sec; }
+ typedef ParticleDataImpl<Real> type4;inline const Real& getArg5() {
+ return lMin; }
+ typedef Real type5;inline const Real& getArg6() {
+ return lMax; }
+ typedef Real type6;inline const Grid<Real> & getArg7() {
+ return potTA; }
+ typedef Grid<Real> type7;inline const Grid<Real> & getArg8() {
+ return potWC; }
+ typedef Grid<Real> type8;inline const Grid<Real> & getArg9() {
+ return potKE; }
+ typedef Grid<Real> type9;inline const Grid<Real> & getArg10() {
+ return neighborRatio; }
+ typedef Grid<Real> type10;inline const Real& getArg11() {
+ return c_s; }
+ typedef Real type11;inline const Real& getArg12() {
+ return c_b; }
+ typedef Real type12;inline const Real& getArg13() {
+ return k_ta; }
+ typedef Real type13;inline const Real& getArg14() {
+ return k_wc; }
+ typedef Real type14;inline const Real& getArg15() {
+ return dt; }
+ typedef Real type15;inline const int& getArg16() {
+ return itype; }
+ typedef int type16; void runMessage() { debMsg("Executing kernel knFlipSampleSecondaryParticles ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void run() {
+ const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=0; j< _maxY; j++) for (int i=0; i< _maxX; i++) op(i,j,k, flags,v,pts_sec,v_sec,l_sec,lMin,lMax,potTA,potWC,potKE,neighborRatio,c_s,c_b,k_ta,k_wc,dt,itype); }
+ const FlagGrid& flags; const MACGrid& v; BasicParticleSystem& pts_sec; ParticleDataImpl<Vec3> & v_sec; ParticleDataImpl<Real> & l_sec; const Real lMin; const Real lMax; const Grid<Real> & potTA; const Grid<Real> & potWC; const Grid<Real> & potKE; const Grid<Real> & neighborRatio; const Real c_s; const Real c_b; const Real k_ta; const Real k_wc; const Real dt; const int itype; }
+;
+
+
+
+
+
+void flipSampleSecondaryParticles( const std::string mode, const FlagGrid &flags, const MACGrid &v, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const Real lMin, const Real lMax, const Grid<Real> &potTA, const Grid<Real> &potWC, const Grid<Real> &potKE, const Grid<Real> &neighborRatio, const Real c_s, const Real c_b, const Real k_ta, const Real k_wc, const Real dt, const int itype = FlagGrid::TypeFluid) {
+ if (mode == "single") {
+ knFlipSampleSecondaryParticles(flags, v, pts_sec, v_sec, l_sec, lMin, lMax, potTA, potWC, potKE, neighborRatio, c_s, c_b, k_ta, k_wc, dt, itype);
+ }
+ else if (mode == "multiple") {
+ knFlipSampleSecondaryParticlesMoreCylinders(flags, v, pts_sec, v_sec, l_sec, lMin, lMax, potTA, potWC, potKE, neighborRatio, c_s, c_b, k_ta, k_wc, dt, itype);
+ }
+ else {
+ throw std::invalid_argument("Unknown mode: use \"single\" or \"multiple\" instead!");
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipSampleSecondaryParticles" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string mode = _args.get<std::string >("mode",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",2,&_lock); BasicParticleSystem& pts_sec = *_args.getPtr<BasicParticleSystem >("pts_sec",3,&_lock); ParticleDataImpl<Vec3> & v_sec = *_args.getPtr<ParticleDataImpl<Vec3> >("v_sec",4,&_lock); ParticleDataImpl<Real> & l_sec = *_args.getPtr<ParticleDataImpl<Real> >("l_sec",5,&_lock); const Real lMin = _args.get<Real >("lMin",6,&_lock); const Real lMax = _args.get<Real >("lMax",7,&_lock); const Grid<Real> & potTA = *_args.getPtr<Grid<Real> >("potTA",8,&_lock); const Grid<Real> & potWC = *_args.getPtr<Grid<Real> >("potWC",9,&_lock); const Grid<Real> & potKE = *_args.getPtr<Grid<Real> >("potKE",10,&_lock); const Grid<Real> & neighborRatio = *_args.getPtr<Grid<Real> >("neighborRatio",11,&_lock); const Real c_s = _args.get<Real >("c_s",12,&_lock); const Real c_b = _args.get<Real >("c_b",13,&_lock); const Real k_ta = _args.get<Real >("k_ta",14,&_lock); const Real k_wc = _args.get<Real >("k_wc",15,&_lock); const Real dt = _args.get<Real >("dt",16,&_lock); const int itype = _args.getOpt<int >("itype",17,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); flipSampleSecondaryParticles(mode,flags,v,pts_sec,v_sec,l_sec,lMin,lMax,potTA,potWC,potKE,neighborRatio,c_s,c_b,k_ta,k_wc,dt,itype); _args.check(); }
+ pbFinalizePlugin(parent,"flipSampleSecondaryParticles", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipSampleSecondaryParticles",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipSampleSecondaryParticles ("","flipSampleSecondaryParticles",_W_1);
+extern "C" {
+ void PbRegister_flipSampleSecondaryParticles() {
+ KEEP_UNUSED(_RP_flipSampleSecondaryParticles); }
+ }
+
+
+
+
+
+
+// evaluates cubic spline with radius h and distance l in dim dimensions
+Real cubicSpline(const Real h, const Real l, const int dim) {
+ const Real h2 = square(h), h3 = h2*h, h4 = h3*h, h5 = h4*h;
+ const Real c[] = { Real(2e0 / (3e0*h)), Real(10e0 / (7e0*M_PI*h2)), Real(1e0 / (M_PI*h3)) };
+ const Real q = l / h;
+ if (q<1e0) return c[dim - 1] * (1e0 - 1.5*square(q) + 0.75*cubed(q));
+ else if (q<2e0) return c[dim - 1] * (0.25*cubed(2e0 - q));
+ return 0;
+}
+
+
+// updates position &pts_sec.pos and velocity &v_sec of secondary particles according to the particle type determined by the neighbor ratio with linear interpolation
+
+
+
+
+ struct knFlipUpdateSecondaryParticlesLinear : public KernelBase {
+ knFlipUpdateSecondaryParticlesLinear( BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const ParticleDataImpl<Vec3> &f_sec, const FlagGrid &flags, const MACGrid &v, const Grid<Real> &neighborRatio, const Vec3 gravity, const Real k_b, const Real k_d, const Real c_s, const Real c_b, const Real dt, const int exclude, const int antitunneling) : KernelBase(pts_sec.size()) ,pts_sec(pts_sec),v_sec(v_sec),l_sec(l_sec),f_sec(f_sec),flags(flags),v(v),neighborRatio(neighborRatio),gravity(gravity),k_b(k_b),k_d(k_d),c_s(c_s),c_b(c_b),dt(dt),exclude(exclude),antitunneling(antitunneling) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const ParticleDataImpl<Vec3> &f_sec, const FlagGrid &flags, const MACGrid &v, const Grid<Real> &neighborRatio, const Vec3 gravity, const Real k_b, const Real k_d, const Real c_s, const Real c_b, const Real dt, const int exclude, const int antitunneling ) const {
+
+ if (!pts_sec.isActive(idx) || pts_sec[idx].flag & exclude) return;
+ if (!flags.isInBounds(pts_sec[idx].pos)) {
+ pts_sec.kill(idx);
+ return;
+ }
+
+ Vec3i gridpos = toVec3i(pts_sec[idx].pos);
+ int i = gridpos.x;
+ int j = gridpos.y;
+ int k = gridpos.z;
+
+ //spray particle
+ if (neighborRatio(gridpos) < c_s) {
+ pts_sec[idx].flag |= ParticleBase::PSPRAY;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PFOAM);
+ v_sec[idx] += dt * ((f_sec[idx] / 1) + gravity); //TODO: if forces are added (e.g. fluid guiding), add parameter for mass instead of 1
+
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ //air bubble particle
+ else if (neighborRatio(gridpos) > c_b) {
+ pts_sec[idx].flag |= ParticleBase::PBUBBLE;
+ pts_sec[idx].flag &= ~(ParticleBase::PSPRAY | ParticleBase::PFOAM);
+
+ const Vec3 vj = (v.getInterpolated(pts_sec[idx].pos) - v_sec[idx]) / dt;
+ v_sec[idx] += dt * (k_b * -gravity + k_d * vj);
+
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ //foam particle
+ else {
+ pts_sec[idx].flag |= ParticleBase::PFOAM;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PSPRAY);
+
+ const Vec3 vj = v.getInterpolated(pts_sec[idx].pos);
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * vj);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v.getInterpolated(pts_sec[idx].pos);
+ }
+
+ //lifetime
+ l_sec[idx] -= dt;
+ if (l_sec[idx] <= Real(0)) {
+ pts_sec.kill(idx);
+ }
+} inline BasicParticleSystem& getArg0() {
+ return pts_sec; }
+ typedef BasicParticleSystem type0;inline ParticleDataImpl<Vec3> & getArg1() {
+ return v_sec; }
+ typedef ParticleDataImpl<Vec3> type1;inline ParticleDataImpl<Real> & getArg2() {
+ return l_sec; }
+ typedef ParticleDataImpl<Real> type2;inline const ParticleDataImpl<Vec3> & getArg3() {
+ return f_sec; }
+ typedef ParticleDataImpl<Vec3> type3;inline const FlagGrid& getArg4() {
+ return flags; }
+ typedef FlagGrid type4;inline const MACGrid& getArg5() {
+ return v; }
+ typedef MACGrid type5;inline const Grid<Real> & getArg6() {
+ return neighborRatio; }
+ typedef Grid<Real> type6;inline const Vec3& getArg7() {
+ return gravity; }
+ typedef Vec3 type7;inline const Real& getArg8() {
+ return k_b; }
+ typedef Real type8;inline const Real& getArg9() {
+ return k_d; }
+ typedef Real type9;inline const Real& getArg10() {
+ return c_s; }
+ typedef Real type10;inline const Real& getArg11() {
+ return c_b; }
+ typedef Real type11;inline const Real& getArg12() {
+ return dt; }
+ typedef Real type12;inline const int& getArg13() {
+ return exclude; }
+ typedef int type13;inline const int& getArg14() {
+ return antitunneling; }
+ typedef int type14; void runMessage() { debMsg("Executing kernel knFlipUpdateSecondaryParticlesLinear ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, pts_sec,v_sec,l_sec,f_sec,flags,v,neighborRatio,gravity,k_b,k_d,c_s,c_b,dt,exclude,antitunneling); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ BasicParticleSystem& pts_sec; ParticleDataImpl<Vec3> & v_sec; ParticleDataImpl<Real> & l_sec; const ParticleDataImpl<Vec3> & f_sec; const FlagGrid& flags; const MACGrid& v; const Grid<Real> & neighborRatio; const Vec3 gravity; const Real k_b; const Real k_d; const Real c_s; const Real c_b; const Real dt; const int exclude; const int antitunneling; }
+;
+// updates position &pts_sec.pos and velocity &v_sec of secondary particles according to the particle type determined by the neighbor ratio with cubic spline interpolation
+
+
+
+
+
+ struct knFlipUpdateSecondaryParticlesCubic : public KernelBase {
+ knFlipUpdateSecondaryParticlesCubic( BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const ParticleDataImpl<Vec3> &f_sec, const FlagGrid &flags, const MACGrid &v, const Grid<Real> &neighborRatio, const int radius, const Vec3 gravity, const Real k_b, const Real k_d, const Real c_s, const Real c_b, const Real dt, const int exclude, const int antitunneling, const int itype) : KernelBase(pts_sec.size()) ,pts_sec(pts_sec),v_sec(v_sec),l_sec(l_sec),f_sec(f_sec),flags(flags),v(v),neighborRatio(neighborRatio),radius(radius),gravity(gravity),k_b(k_b),k_d(k_d),c_s(c_s),c_b(c_b),dt(dt),exclude(exclude),antitunneling(antitunneling),itype(itype) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const ParticleDataImpl<Vec3> &f_sec, const FlagGrid &flags, const MACGrid &v, const Grid<Real> &neighborRatio, const int radius, const Vec3 gravity, const Real k_b, const Real k_d, const Real c_s, const Real c_b, const Real dt, const int exclude, const int antitunneling, const int itype ) const {
+
+ if (!pts_sec.isActive(idx) || pts_sec[idx].flag & exclude) return;
+ if (!flags.isInBounds(pts_sec[idx].pos)) {
+ pts_sec.kill(idx);
+ return;
+ }
+
+ Vec3i gridpos = toVec3i(pts_sec[idx].pos);
+ int i = gridpos.x;
+ int j = gridpos.y;
+ int k = gridpos.z;
+
+ //spray particle
+ if (neighborRatio(gridpos) < c_s) {
+ pts_sec[idx].flag |= ParticleBase::PSPRAY;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PFOAM);
+ v_sec[idx] += dt * ((f_sec[idx] / 1) + gravity); //TODO: if forces are added (e.g. fluid guiding), add parameter for mass instead of 1
+
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ //air bubble particle
+ else if (neighborRatio(gridpos) > c_b) {
+ pts_sec[idx].flag |= ParticleBase::PBUBBLE;
+ pts_sec[idx].flag &= ~(ParticleBase::PSPRAY | ParticleBase::PFOAM);
+ const Vec3 &xi = pts_sec[idx].pos;
+ Vec3 sumNumerator = Vec3(0, 0, 0);
+ Real sumDenominator = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ Vec3i xj = Vec3i(x, y, z);
+ if ((x == i && y == j && z == k) || !flags.isInBounds(xj)) continue;
+ if (!(flags(xj) & itype)) continue;
+ const Real len_xij = norm(xi - Vec3(x, y, z));
+
+ int dim = flags.is3D() ? 3 : 2;
+ Real dist = flags.is3D() ? 1.732 : 1.414;
+ Real weight = cubicSpline(radius * dist, len_xij, dim);
+ sumNumerator += v.getCentered(xj) * weight; //estimate next position by current velocity
+ sumDenominator += weight;
+ }
+ }
+ }
+ const Vec3 temp = ((sumNumerator / sumDenominator) - v_sec[idx]) / dt;
+ v_sec[idx] += dt * (k_b * -gravity + k_d * temp);
+
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * v_sec[idx]);
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * v_sec[idx];
+ }
+
+ //foam particle
+ else {
+ pts_sec[idx].flag |= ParticleBase::PFOAM;
+ pts_sec[idx].flag &= ~(ParticleBase::PBUBBLE | ParticleBase::PSPRAY);
+ const Vec3 &xi = pts_sec[idx].pos;
+ Vec3 sumNumerator = Vec3(0, 0, 0);
+ Real sumDenominator = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ Vec3i xj = Vec3i(x, y, z);
+ if ((x == i && y == j && z == k) || !flags.isInBounds(xj)) continue;
+ if (!(flags(xj) & itype)) continue;
+ const Real len_xij = norm(xi - Vec3(x, y, z));
+
+ int dim = flags.is3D() ? 3 : 2;
+ Real dist = flags.is3D() ? 1.732 : 1.414;
+ Real weight = cubicSpline(radius * dist, len_xij, dim);
+ sumNumerator += v.getCentered(xj) * weight; //estimate next position by current velocity
+ sumDenominator += weight;
+ }
+ }
+ }
+
+ //anti tunneling for small obstacles
+ for (int ct = 1; ct < antitunneling; ct++) {
+ Vec3i tempPos = toVec3i(pts_sec[idx].pos + ct * (1 / Real(antitunneling)) * dt * (sumNumerator / sumDenominator));
+ if (!flags.isInBounds(tempPos) || flags(tempPos) & FlagGrid::TypeObstacle) {
+ pts_sec.kill(idx);
+ return;
+ }
+ }
+ pts_sec[idx].pos += dt * (sumNumerator / sumDenominator);
+ }
+
+ //lifetime
+ l_sec[idx] -= dt;
+ if (l_sec[idx] <= Real(0)) {
+ pts_sec.kill(idx);
+ }
+} inline BasicParticleSystem& getArg0() {
+ return pts_sec; }
+ typedef BasicParticleSystem type0;inline ParticleDataImpl<Vec3> & getArg1() {
+ return v_sec; }
+ typedef ParticleDataImpl<Vec3> type1;inline ParticleDataImpl<Real> & getArg2() {
+ return l_sec; }
+ typedef ParticleDataImpl<Real> type2;inline const ParticleDataImpl<Vec3> & getArg3() {
+ return f_sec; }
+ typedef ParticleDataImpl<Vec3> type3;inline const FlagGrid& getArg4() {
+ return flags; }
+ typedef FlagGrid type4;inline const MACGrid& getArg5() {
+ return v; }
+ typedef MACGrid type5;inline const Grid<Real> & getArg6() {
+ return neighborRatio; }
+ typedef Grid<Real> type6;inline const int& getArg7() {
+ return radius; }
+ typedef int type7;inline const Vec3& getArg8() {
+ return gravity; }
+ typedef Vec3 type8;inline const Real& getArg9() {
+ return k_b; }
+ typedef Real type9;inline const Real& getArg10() {
+ return k_d; }
+ typedef Real type10;inline const Real& getArg11() {
+ return c_s; }
+ typedef Real type11;inline const Real& getArg12() {
+ return c_b; }
+ typedef Real type12;inline const Real& getArg13() {
+ return dt; }
+ typedef Real type13;inline const int& getArg14() {
+ return exclude; }
+ typedef int type14;inline const int& getArg15() {
+ return antitunneling; }
+ typedef int type15;inline const int& getArg16() {
+ return itype; }
+ typedef int type16; void runMessage() { debMsg("Executing kernel knFlipUpdateSecondaryParticlesCubic ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, pts_sec,v_sec,l_sec,f_sec,flags,v,neighborRatio,radius,gravity,k_b,k_d,c_s,c_b,dt,exclude,antitunneling,itype); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ BasicParticleSystem& pts_sec; ParticleDataImpl<Vec3> & v_sec; ParticleDataImpl<Real> & l_sec; const ParticleDataImpl<Vec3> & f_sec; const FlagGrid& flags; const MACGrid& v; const Grid<Real> & neighborRatio; const int radius; const Vec3 gravity; const Real k_b; const Real k_d; const Real c_s; const Real c_b; const Real dt; const int exclude; const int antitunneling; const int itype; }
+;
+
+
+
+
+
+void flipUpdateSecondaryParticles( const std::string mode, BasicParticleSystem &pts_sec, ParticleDataImpl<Vec3> &v_sec, ParticleDataImpl<Real> &l_sec, const ParticleDataImpl<Vec3> &f_sec, FlagGrid &flags, const MACGrid &v, const Grid<Real> &neighborRatio, const int radius, const Vec3 gravity, const Real k_b, const Real k_d, const Real c_s, const Real c_b, const Real dt, const int exclude = ParticleBase::PTRACER, const int antitunneling=0, const int itype = FlagGrid::TypeFluid) {
+
+ Vec3 g = gravity / flags.getDx();
+ if (mode == "linear") {
+ knFlipUpdateSecondaryParticlesLinear(pts_sec, v_sec, l_sec, f_sec, flags, v, neighborRatio, g, k_b, k_d, c_s, c_b, dt, exclude, antitunneling);
+ }
+ else if (mode == "cubic") {
+ knFlipUpdateSecondaryParticlesCubic(pts_sec, v_sec, l_sec, f_sec, flags, v, neighborRatio, radius, g, k_b, k_d, c_s, c_b, dt, exclude, antitunneling, itype);
+ }
+ else {
+ throw std::invalid_argument("Unknown mode: use \"linear\" or \"cubic\" instead!");
+ }
+ pts_sec.doCompress();
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipUpdateSecondaryParticles" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const std::string mode = _args.get<std::string >("mode",0,&_lock); BasicParticleSystem& pts_sec = *_args.getPtr<BasicParticleSystem >("pts_sec",1,&_lock); ParticleDataImpl<Vec3> & v_sec = *_args.getPtr<ParticleDataImpl<Vec3> >("v_sec",2,&_lock); ParticleDataImpl<Real> & l_sec = *_args.getPtr<ParticleDataImpl<Real> >("l_sec",3,&_lock); const ParticleDataImpl<Vec3> & f_sec = *_args.getPtr<ParticleDataImpl<Vec3> >("f_sec",4,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",5,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",6,&_lock); const Grid<Real> & neighborRatio = *_args.getPtr<Grid<Real> >("neighborRatio",7,&_lock); const int radius = _args.get<int >("radius",8,&_lock); const Vec3 gravity = _args.get<Vec3 >("gravity",9,&_lock); const Real k_b = _args.get<Real >("k_b",10,&_lock); const Real k_d = _args.get<Real >("k_d",11,&_lock); const Real c_s = _args.get<Real >("c_s",12,&_lock); const Real c_b = _args.get<Real >("c_b",13,&_lock); const Real dt = _args.get<Real >("dt",14,&_lock); const int exclude = _args.getOpt<int >("exclude",15,ParticleBase::PTRACER,&_lock); const int antitunneling = _args.getOpt<int >("antitunneling",16,0,&_lock); const int itype = _args.getOpt<int >("itype",17,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); flipUpdateSecondaryParticles(mode,pts_sec,v_sec,l_sec,f_sec,flags,v,neighborRatio,radius,gravity,k_b,k_d,c_s,c_b,dt,exclude,antitunneling,itype); _args.check(); }
+ pbFinalizePlugin(parent,"flipUpdateSecondaryParticles", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipUpdateSecondaryParticles",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipUpdateSecondaryParticles ("","flipUpdateSecondaryParticles",_W_2);
+extern "C" {
+ void PbRegister_flipUpdateSecondaryParticles() {
+ KEEP_UNUSED(_RP_flipUpdateSecondaryParticles); }
+ }
+
+
+
+
+// removes secondary particles in &pts_sec that are inside boundaries (cells that are marked as obstacle/outflow in &flags)
+
+
+ struct knFlipDeleteParticlesInObstacle : public KernelBase {
+ knFlipDeleteParticlesInObstacle( BasicParticleSystem &pts, const FlagGrid &flags) : KernelBase(pts.size()) ,pts(pts),flags(flags) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystem &pts, const FlagGrid &flags ) const {
+
+ if (!pts.isActive(idx)) return;
+
+ const Vec3 &xi = pts[idx].pos;
+ const Vec3i xidx = toVec3i(xi);
+ //remove particles that completely left the bounds
+ if (!flags.isInBounds(xidx)) {
+ pts.kill(idx);
+ return;
+ }
+ int gridIndex = flags.index(xidx);
+ //remove particles that penetrate obstacles
+ if (flags[gridIndex] == FlagGrid::TypeObstacle || flags[gridIndex] == FlagGrid::TypeOutflow) {
+ pts.kill(idx);
+ }
+} inline BasicParticleSystem& getArg0() {
+ return pts; }
+ typedef BasicParticleSystem type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1; void runMessage() { debMsg("Executing kernel knFlipDeleteParticlesInObstacle ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, pts,flags); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ BasicParticleSystem& pts; const FlagGrid& flags; }
+;
+
+
+void flipDeleteParticlesInObstacle( BasicParticleSystem &pts, const FlagGrid &flags) {
+
+ knFlipDeleteParticlesInObstacle(pts, flags);
+ pts.doCompress();
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipDeleteParticlesInObstacle" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; BasicParticleSystem& pts = *_args.getPtr<BasicParticleSystem >("pts",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); _retval = getPyNone(); flipDeleteParticlesInObstacle(pts,flags); _args.check(); }
+ pbFinalizePlugin(parent,"flipDeleteParticlesInObstacle", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipDeleteParticlesInObstacle",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipDeleteParticlesInObstacle ("","flipDeleteParticlesInObstacle",_W_3);
+extern "C" {
+ void PbRegister_flipDeleteParticlesInObstacle() {
+ KEEP_UNUSED(_RP_flipDeleteParticlesInObstacle); }
+ }
+
+
+
+//helper method to debug statistical data from grid
+
+
+void debugGridInfo( const FlagGrid &flags, Grid<Real> &grid, std::string name, const int itype = FlagGrid::TypeFluid) {
+ FluidSolver* s = flags.getParent();
+ int countFluid = 0;
+ int countLargerZero = 0;
+ Real avg = 0;
+ Real max = 0;
+ Real sum = 0;
+ Real avgLargerZero = 0;
+ FOR_IJK_BND(grid, 1) {
+ if (!(flags(i, j, k) & itype)) continue;
+ countFluid++;
+ if (grid(i, j, k) > 0) countLargerZero++;
+ sum += grid(i, j, k);
+ if (grid(i, j, k) > max) max = grid(i, j, k);
+ }
+ avg = sum / std::max(Real(countFluid), Real(1));
+ avgLargerZero = sum / std::max(Real(countLargerZero), Real(1));
+
+ debMsg("Step: " << s->mFrame << " - Grid " << name <<
+ "\n\tcountFluid \t\t" << countFluid <<
+ "\n\tcountLargerZero \t" << countLargerZero <<
+ "\n\tsum \t\t\t" << sum <<
+ "\n\tavg \t\t\t" << avg <<
+ "\n\tavgLargerZero \t\t" << avgLargerZero <<
+ "\n\tmax \t\t\t" << max, 1);
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "debugGridInfo" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real> & grid = *_args.getPtr<Grid<Real> >("grid",1,&_lock); std::string name = _args.get<std::string >("name",2,&_lock); const int itype = _args.getOpt<int >("itype",3,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); debugGridInfo(flags,grid,name,itype); _args.check(); }
+ pbFinalizePlugin(parent,"debugGridInfo", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("debugGridInfo",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_debugGridInfo ("","debugGridInfo",_W_4);
+extern "C" {
+ void PbRegister_debugGridInfo() {
+ KEEP_UNUSED(_RP_debugGridInfo); }
+ }
+
+
+
+
+
+// The following methods are helper functions to recreate the velocity and flag grid from the underlying FLIP simulation.
+// They cannot simply be loaded because of the upres to a higher resolution, instead a levelset is used.
+
+
+ struct knSetFlagsFromLevelset : public KernelBase {
+ knSetFlagsFromLevelset( FlagGrid &flags, const Grid<Real> &phi, const int exclude = FlagGrid::TypeObstacle, const int itype = FlagGrid::TypeFluid) : KernelBase(&flags,0) ,flags(flags),phi(phi),exclude(exclude),itype(itype) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, FlagGrid &flags, const Grid<Real> &phi, const int exclude = FlagGrid::TypeObstacle, const int itype = FlagGrid::TypeFluid ) const {
+ if (phi(idx) < 0 && !(flags(idx) & exclude)) flags(idx) = itype;
+
+} inline FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const Grid<Real> & getArg1() {
+ return phi; }
+ typedef Grid<Real> type1;inline const int& getArg2() {
+ return exclude; }
+ typedef int type2;inline const int& getArg3() {
+ return itype; }
+ typedef int type3; void runMessage() { debMsg("Executing kernel knSetFlagsFromLevelset ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, flags,phi,exclude,itype); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ FlagGrid& flags; const Grid<Real> & phi; const int exclude; const int itype; }
+;
+
+
+void setFlagsFromLevelset( FlagGrid &flags, const Grid<Real> &phi, const int exclude = FlagGrid::TypeObstacle, const int itype = FlagGrid::TypeFluid) {
+ knSetFlagsFromLevelset(flags, phi, exclude, itype);
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setFlagsFromLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const Grid<Real> & phi = *_args.getPtr<Grid<Real> >("phi",1,&_lock); const int exclude = _args.getOpt<int >("exclude",2,FlagGrid::TypeObstacle,&_lock); const int itype = _args.getOpt<int >("itype",3,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); setFlagsFromLevelset(flags,phi,exclude,itype); _args.check(); }
+ pbFinalizePlugin(parent,"setFlagsFromLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setFlagsFromLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setFlagsFromLevelset ("","setFlagsFromLevelset",_W_5);
+extern "C" {
+ void PbRegister_setFlagsFromLevelset() {
+ KEEP_UNUSED(_RP_setFlagsFromLevelset); }
+ }
+
+
+
+
+
+ struct knSetMACFromLevelset : public KernelBase {
+ knSetMACFromLevelset( MACGrid &v, const Grid<Real> &phi, const Vec3 c) : KernelBase(&v,0) ,v(v),phi(phi),c(c) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid &v, const Grid<Real> &phi, const Vec3 c ) const {
+ if (phi.getInterpolated(Vec3(i, j, k)) > 0) v(i, j, k) = c;
+} inline MACGrid& getArg0() {
+ return v; }
+ typedef MACGrid type0;inline const Grid<Real> & getArg1() {
+ return phi; }
+ typedef Grid<Real> type1;inline const Vec3& getArg2() {
+ return c; }
+ typedef Vec3 type2; void runMessage() { debMsg("Executing kernel knSetMACFromLevelset ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,v,phi,c); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,v,phi,c); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ MACGrid& v; const Grid<Real> & phi; const Vec3 c; }
+;
+
+
+void setMACFromLevelset( MACGrid &v, const Grid<Real> &phi, const Vec3 c) {
+ knSetMACFromLevelset(v, phi, c);
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "setMACFromLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& v = *_args.getPtr<MACGrid >("v",0,&_lock); const Grid<Real> & phi = *_args.getPtr<Grid<Real> >("phi",1,&_lock); const Vec3 c = _args.get<Vec3 >("c",2,&_lock); _retval = getPyNone(); setMACFromLevelset(v,phi,c); _args.check(); }
+ pbFinalizePlugin(parent,"setMACFromLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("setMACFromLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_setMACFromLevelset ("","setMACFromLevelset",_W_6);
+extern "C" {
+ void PbRegister_setMACFromLevelset() {
+ KEEP_UNUSED(_RP_setMACFromLevelset); }
+ }
+
+
+
+
+
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+// END Secondary Particles for FLIP
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+#pragma endregion
+
+
+
+#pragma region Legacy Methods (still useful for debugging)
+//----------------------------------------------------------------------------------------------------------------------------------- -----------------
+// Legacy Methods (still useful for debugging)
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes trapped air potential for all fluid cells in &flags and saves it in &pot
+
+
+
+
+
+ struct knFlipComputePotentialTrappedAir : public KernelBase {
+ knFlipComputePotentialTrappedAir( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid) : KernelBase(&pot,1) ,pot(pot),flags(flags),v(v),radius(radius),tauMin(tauMin),tauMax(tauMax),scaleFromManta(scaleFromManta),itype(itype),jtype(jtype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid ) const {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ const Vec3 &xi = scaleFromManta * Vec3(i, j, k); //scale to unit cube
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k);
+ Real vdiff = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || !(flags(x, y, z) & jtype)) continue;
+
+ const Vec3 &xj = scaleFromManta * Vec3(x, y, z); //scale to unit cube
+ const Vec3 &vj = scaleFromManta * v.getCentered(x, y, z);
+ const Vec3 xij = xi - xj;
+ const Vec3 vij = vi - vj;
+ Real h = !pot.is3D() ? 1.414*radius : 1.732*radius; //estimate sqrt(2)*radius resp. sqrt(3)*radius for h, due to squared resp. cubic neighbor area
+ vdiff += norm(vij) * (1 - dot(getNormalized(vij), getNormalized(xij))) * (1 - norm(xij) / h);
+ }
+ }
+ }
+ pot(i, j, k) = (std::min(vdiff, tauMax) - std::min(vdiff, tauMin)) / (tauMax - tauMin);
+} inline Grid<Real> & getArg0() {
+ return pot; }
+ typedef Grid<Real> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return v; }
+ typedef MACGrid type2;inline const int& getArg3() {
+ return radius; }
+ typedef int type3;inline const Real& getArg4() {
+ return tauMin; }
+ typedef Real type4;inline const Real& getArg5() {
+ return tauMax; }
+ typedef Real type5;inline const Real& getArg6() {
+ return scaleFromManta; }
+ typedef Real type6;inline const int& getArg7() {
+ return itype; }
+ typedef int type7;inline const int& getArg8() {
+ return jtype; }
+ typedef int type8; void runMessage() { debMsg("Executing kernel knFlipComputePotentialTrappedAir ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,pot,flags,v,radius,tauMin,tauMax,scaleFromManta,itype,jtype); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,pot,flags,v,radius,tauMin,tauMax,scaleFromManta,itype,jtype); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<Real> & pot; const FlagGrid& flags; const MACGrid& v; const int radius; const Real tauMin; const Real tauMax; const Real scaleFromManta; const int itype; const int jtype; }
+;
+
+
+
+
+
+void flipComputePotentialTrappedAir( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid) {
+ pot.clear();
+ knFlipComputePotentialTrappedAir(pot, flags, v, radius, tauMin, tauMax, scaleFromManta, itype, jtype);
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipComputePotentialTrappedAir" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & pot = *_args.getPtr<Grid<Real> >("pot",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",2,&_lock); const int radius = _args.get<int >("radius",3,&_lock); const Real tauMin = _args.get<Real >("tauMin",4,&_lock); const Real tauMax = _args.get<Real >("tauMax",5,&_lock); const Real scaleFromManta = _args.get<Real >("scaleFromManta",6,&_lock); const int itype = _args.getOpt<int >("itype",7,FlagGrid::TypeFluid,&_lock); const int jtype = _args.getOpt<int >("jtype",8,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); flipComputePotentialTrappedAir(pot,flags,v,radius,tauMin,tauMax,scaleFromManta,itype,jtype); _args.check(); }
+ pbFinalizePlugin(parent,"flipComputePotentialTrappedAir", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipComputePotentialTrappedAir",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipComputePotentialTrappedAir ("","flipComputePotentialTrappedAir",_W_7);
+extern "C" {
+ void PbRegister_flipComputePotentialTrappedAir() {
+ KEEP_UNUSED(_RP_flipComputePotentialTrappedAir); }
+ }
+
+
+
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes kinetic energy potential for all fluid cells in &flags and saves it in &pot
+
+
+
+
+ struct knFlipComputePotentialKineticEnergy : public KernelBase {
+ knFlipComputePotentialKineticEnergy( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid) : KernelBase(&pot,0) ,pot(pot),flags(flags),v(v),tauMin(tauMin),tauMax(tauMax),scaleFromManta(scaleFromManta),itype(itype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid ) const {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k); //scale to unit cube
+ Real ek = Real(0.5) * 125 * normSquare(vi); //use arbitrary constant for mass, potential adjusts with thresholds anyways
+ pot(i, j, k) = (std::min(ek, tauMax) - std::min(ek, tauMin)) / (tauMax - tauMin);
+} inline Grid<Real> & getArg0() {
+ return pot; }
+ typedef Grid<Real> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return v; }
+ typedef MACGrid type2;inline const Real& getArg3() {
+ return tauMin; }
+ typedef Real type3;inline const Real& getArg4() {
+ return tauMax; }
+ typedef Real type4;inline const Real& getArg5() {
+ return scaleFromManta; }
+ typedef Real type5;inline const int& getArg6() {
+ return itype; }
+ typedef int type6; void runMessage() { debMsg("Executing kernel knFlipComputePotentialKineticEnergy ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,pot,flags,v,tauMin,tauMax,scaleFromManta,itype); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,pot,flags,v,tauMin,tauMax,scaleFromManta,itype); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<Real> & pot; const FlagGrid& flags; const MACGrid& v; const Real tauMin; const Real tauMax; const Real scaleFromManta; const int itype; }
+;
+
+
+
+
+void flipComputePotentialKineticEnergy( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid) {
+ pot.clear();
+ knFlipComputePotentialKineticEnergy(pot, flags, v, tauMin, tauMax, scaleFromManta, itype);
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipComputePotentialKineticEnergy" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & pot = *_args.getPtr<Grid<Real> >("pot",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",2,&_lock); const Real tauMin = _args.get<Real >("tauMin",3,&_lock); const Real tauMax = _args.get<Real >("tauMax",4,&_lock); const Real scaleFromManta = _args.get<Real >("scaleFromManta",5,&_lock); const int itype = _args.getOpt<int >("itype",6,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); flipComputePotentialKineticEnergy(pot,flags,v,tauMin,tauMax,scaleFromManta,itype); _args.check(); }
+ pbFinalizePlugin(parent,"flipComputePotentialKineticEnergy", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipComputePotentialKineticEnergy",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipComputePotentialKineticEnergy ("","flipComputePotentialKineticEnergy",_W_8);
+extern "C" {
+ void PbRegister_flipComputePotentialKineticEnergy() {
+ KEEP_UNUSED(_RP_flipComputePotentialKineticEnergy); }
+ }
+
+
+
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes wave crest potential for all fluid cells in &flags and saves it in &pot
+
+
+
+
+ struct knFlipComputePotentialWaveCrest : public KernelBase {
+ knFlipComputePotentialWaveCrest( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, Grid<Vec3> &normal, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid) : KernelBase(&pot,1) ,pot(pot),flags(flags),v(v),radius(radius),normal(normal),tauMin(tauMin),tauMax(tauMax),scaleFromManta(scaleFromManta),itype(itype),jtype(jtype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, Grid<Vec3> &normal, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid ) const {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ const Vec3 &xi = scaleFromManta * Vec3(i, j, k); //scale to unit cube
+ const Vec3 &vi = scaleFromManta * v.getCentered(i, j, k);
+ const Vec3 &ni = normal(i, j, k);
+ Real kappa = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || !(flags(x, y, z) & jtype)) continue;
+ const Vec3 &xj = scaleFromManta * Vec3(x, y, z); //scale to unit cube
+ const Vec3 &nj = normal(x, y, z);
+ const Vec3 xij = xi - xj;
+ if (dot(getNormalized(xij), ni) < 0) { //identifies wave crests
+ Real h = !pot.is3D() ? 1.414*radius : 1.732*radius; //estimate sqrt(2)*radius resp. sqrt(3)*radius for h, due to squared resp. cubic neighbor area
+ kappa += (1 - dot(ni, nj)) * (1 - norm(xij) / h);
+ }
+ }
+ }
+ }
+
+ if (dot(getNormalized(vi), ni) >= 0.6) { //avoid to mark boarders of the scene as wave crest
+ pot(i, j, k) = (std::min(kappa, tauMax) - std::min(kappa, tauMin)) / (tauMax - tauMin);
+ }
+ else {
+ pot(i, j, k) = Real(0);
+ }
+} inline Grid<Real> & getArg0() {
+ return pot; }
+ typedef Grid<Real> type0;inline const FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline const MACGrid& getArg2() {
+ return v; }
+ typedef MACGrid type2;inline const int& getArg3() {
+ return radius; }
+ typedef int type3;inline Grid<Vec3> & getArg4() {
+ return normal; }
+ typedef Grid<Vec3> type4;inline const Real& getArg5() {
+ return tauMin; }
+ typedef Real type5;inline const Real& getArg6() {
+ return tauMax; }
+ typedef Real type6;inline const Real& getArg7() {
+ return scaleFromManta; }
+ typedef Real type7;inline const int& getArg8() {
+ return itype; }
+ typedef int type8;inline const int& getArg9() {
+ return jtype; }
+ typedef int type9; void runMessage() { debMsg("Executing kernel knFlipComputePotentialWaveCrest ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,pot,flags,v,radius,normal,tauMin,tauMax,scaleFromManta,itype,jtype); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,pot,flags,v,radius,normal,tauMin,tauMax,scaleFromManta,itype,jtype); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ Grid<Real> & pot; const FlagGrid& flags; const MACGrid& v; const int radius; Grid<Vec3> & normal; const Real tauMin; const Real tauMax; const Real scaleFromManta; const int itype; const int jtype; }
+;
+
+
+
+
+void flipComputePotentialWaveCrest( Grid<Real> &pot, const FlagGrid &flags, const MACGrid &v, const int radius, Grid<Vec3> &normal, const Real tauMin, const Real tauMax, const Real scaleFromManta, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeFluid) {
+
+ pot.clear();
+ knFlipComputePotentialWaveCrest(pot, flags, v, radius, normal, tauMin, tauMax, scaleFromManta, itype, jtype);
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipComputePotentialWaveCrest" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real> & pot = *_args.getPtr<Grid<Real> >("pot",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); const MACGrid& v = *_args.getPtr<MACGrid >("v",2,&_lock); const int radius = _args.get<int >("radius",3,&_lock); Grid<Vec3> & normal = *_args.getPtr<Grid<Vec3> >("normal",4,&_lock); const Real tauMin = _args.get<Real >("tauMin",5,&_lock); const Real tauMax = _args.get<Real >("tauMax",6,&_lock); const Real scaleFromManta = _args.get<Real >("scaleFromManta",7,&_lock); const int itype = _args.getOpt<int >("itype",8,FlagGrid::TypeFluid,&_lock); const int jtype = _args.getOpt<int >("jtype",9,FlagGrid::TypeFluid,&_lock); _retval = getPyNone(); flipComputePotentialWaveCrest(pot,flags,v,radius,normal,tauMin,tauMax,scaleFromManta,itype,jtype); _args.check(); }
+ pbFinalizePlugin(parent,"flipComputePotentialWaveCrest", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipComputePotentialWaveCrest",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipComputePotentialWaveCrest ("","flipComputePotentialWaveCrest",_W_9);
+extern "C" {
+ void PbRegister_flipComputePotentialWaveCrest() {
+ KEEP_UNUSED(_RP_flipComputePotentialWaveCrest); }
+ }
+
+
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes normal grid &normal as gradient of levelset &phi and normalizes it
+
+ struct knFlipComputeSurfaceNormals : public KernelBase {
+ knFlipComputeSurfaceNormals(Grid<Vec3>& normal, const Grid<Real>& phi) : KernelBase(&normal,0) ,normal(normal),phi(phi) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, Grid<Vec3>& normal, const Grid<Real>& phi ) const {
+ normal[idx] = getNormalized(normal[idx]);
+} inline Grid<Vec3>& getArg0() {
+ return normal; }
+ typedef Grid<Vec3> type0;inline const Grid<Real>& getArg1() {
+ return phi; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel knFlipComputeSurfaceNormals ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, normal,phi); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ Grid<Vec3>& normal; const Grid<Real>& phi; }
+;
+
+void flipComputeSurfaceNormals(Grid<Vec3>& normal, const Grid<Real>& phi) {
+ GradientOp(normal, phi);
+ knFlipComputeSurfaceNormals(normal, phi);
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipComputeSurfaceNormals" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& normal = *_args.getPtr<Grid<Vec3> >("normal",0,&_lock); const Grid<Real>& phi = *_args.getPtr<Grid<Real> >("phi",1,&_lock); _retval = getPyNone(); flipComputeSurfaceNormals(normal,phi); _args.check(); }
+ pbFinalizePlugin(parent,"flipComputeSurfaceNormals", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipComputeSurfaceNormals",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipComputeSurfaceNormals ("","flipComputeSurfaceNormals",_W_10);
+extern "C" {
+ void PbRegister_flipComputeSurfaceNormals() {
+ KEEP_UNUSED(_RP_flipComputeSurfaceNormals); }
+ }
+
+
+
+// LEGACY METHOD! Use flipComputeSecondaryParticlePotentials instead!
+// computes the neighbor ratio for every fluid cell in &flags as the number of fluid neighbors over the maximum possible number of fluid neighbors
+
+
+
+ struct knFlipUpdateNeighborRatio : public KernelBase {
+ knFlipUpdateNeighborRatio( const FlagGrid &flags, Grid<Real> &neighborRatio, const int radius, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle) : KernelBase(&flags,1) ,flags(flags),neighborRatio(neighborRatio),radius(radius),itype(itype),jtype(jtype) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid &flags, Grid<Real> &neighborRatio, const int radius, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle ) const {
+
+ if (!(flags(i, j, k) & itype)) return;
+
+ int countFluid = 0;
+ int countMaxFluid = 0;
+ for (IndexInt x = i - radius; x <= i + radius; x++) {
+ for (IndexInt y = j - radius; y <= j + radius; y++) {
+ for (IndexInt z = k - radius; z <= k + radius; z++) {
+ if ((x == i && y == j && z == k) || (flags(x, y, z) & jtype)) continue;
+ if (flags(x, y, z) & itype) {
+ countFluid++;
+ countMaxFluid++;
+ }
+ else {
+ countMaxFluid++;
+ }
+ }
+ }
+ }
+ neighborRatio(i, j, k) = float(countFluid) / float(countMaxFluid);
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real> & getArg1() {
+ return neighborRatio; }
+ typedef Grid<Real> type1;inline const int& getArg2() {
+ return radius; }
+ typedef int type2;inline const int& getArg3() {
+ return itype; }
+ typedef int type3;inline const int& getArg4() {
+ return jtype; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel knFlipUpdateNeighborRatio ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,neighborRatio,radius,itype,jtype); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,neighborRatio,radius,itype,jtype); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; Grid<Real> & neighborRatio; const int radius; const int itype; const int jtype; }
+;
+
+
+
+void flipUpdateNeighborRatio( const FlagGrid &flags, Grid<Real> &neighborRatio, const int radius, const int itype = FlagGrid::TypeFluid, const int jtype = FlagGrid::TypeObstacle) {
+
+ neighborRatio.clear();
+ knFlipUpdateNeighborRatio(flags, neighborRatio, radius, itype, jtype);
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "flipUpdateNeighborRatio" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real> & neighborRatio = *_args.getPtr<Grid<Real> >("neighborRatio",1,&_lock); const int radius = _args.get<int >("radius",2,&_lock); const int itype = _args.getOpt<int >("itype",3,FlagGrid::TypeFluid,&_lock); const int jtype = _args.getOpt<int >("jtype",4,FlagGrid::TypeObstacle,&_lock); _retval = getPyNone(); flipUpdateNeighborRatio(flags,neighborRatio,radius,itype,jtype); _args.check(); }
+ pbFinalizePlugin(parent,"flipUpdateNeighborRatio", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("flipUpdateNeighborRatio",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_flipUpdateNeighborRatio ("","flipUpdateNeighborRatio",_W_11);
+extern "C" {
+ void PbRegister_flipUpdateNeighborRatio() {
+ KEEP_UNUSED(_RP_flipUpdateNeighborRatio); }
+ }
+
+
+
+
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+// Legacy Methods (still useful for debugging)
+//----------------------------------------------------------------------------------------------------------------------------------------------------
+#pragma endregion
+
+
+
+} //namespace
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/surfaceturbulence.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/surfaceturbulence.cpp
new file mode 100644
index 00000000000..2f8e79b9699
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/surfaceturbulence.cpp
@@ -0,0 +1,1436 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2016 Olivier Mercier, oli.mercier@gmail.com
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Surface Turbulence for Particle-Based Liquid Simulations
+ * Mercier et al., SIGGRAPH Asia 2015
+ *
+ * Possible speedups :
+ * - only initialize surface points around coarse particles near the surface. Use the flags in the fluid
+ * grid and only use cells with non-fluid neighbors.
+ *
+ ******************************************************************************/
+
+// use chrono stl for detailed timing only if available
+#ifdef __GNUC__
+#if __GNUC__<5
+#define USE_CHRONO 0
+#endif
+#endif
+
+#if MANTA_WITHCPP11==1
+#ifndef USE_CHRONO
+#define USE_CHRONO 1
+#endif
+#endif
+
+#include <iomanip>
+#if USE_CHRONO==1
+#include <chrono>
+#endif
+#include "particle.h"
+
+using namespace std;
+namespace Manta {
+
+// own namespace for globals
+namespace SurfaceTurbulence {
+
+
+//
+// **** surface turbulence parameters ****
+//
+struct SurfaceTurbulenceParameters {
+ int res;
+ Real outerRadius;
+ int surfaceDensity;
+ int nbSurfaceMaintenanceIterations;
+ Real dt;
+ Real waveSpeed;
+ Real waveDamping;
+ Real waveSeedFrequency;
+ Real waveMaxAmplitude;
+ Real waveMaxFrequency;
+ Real waveMaxSeedingAmplitude; // as ratio of max amp;
+ Real waveSeedingCurvatureThresholdRegionCenter;
+ Real waveSeedingCurvatureThresholdRegionRadius;
+ Real waveSeedStepSizeRatioOfMax;
+ Real innerRadius;
+ Real meanFineDistance;
+ Real constraintA;
+ Real normalRadius;
+ Real tangentRadius;
+ Real bndXm, bndXp, bndYm, bndYp, bndZm, bndZp;
+};
+SurfaceTurbulenceParameters params;
+
+
+//
+// **** acceleration grid for particle neighbor queries ****
+//
+struct ParticleAccelGrid{
+ int res;
+ vector<int>*** indices;
+
+ void init(int inRes) {
+ res = inRes;
+ indices = new vector<int>**[res];
+ for(int i=0; i<res; i++){
+ indices[i] = new vector<int>*[res];
+ for(int j=0; j<res; j++) {
+ indices[i][j] = new vector<int>[res];
+ }
+ }
+ }
+
+ void fillWith(const BasicParticleSystem& particles) {
+ // clear
+ for(int i=0; i<res; i++) {
+ for(int j=0; j<res; j++) {
+ for(int k=0; k<res; k++) {
+ indices[i][j][k].clear();
+ }}}
+
+ // fill
+ for(int id=0;id<particles.size();id++) {
+ Vec3 pos = particles.getPos(id);
+ int i = clamp<int>(floor(pos.x/params.res*res), 0, res-1);
+ int j = clamp<int>(floor(pos.y/params.res*res), 0, res-1);
+ int k = clamp<int>(floor(pos.z/params.res*res), 0, res-1);
+ indices[i][j][k].push_back(id);
+ }
+ }
+
+ void fillWith(const ParticleDataImpl<Vec3>& particles){
+ // clear
+ for(int i=0; i<res; i++) {
+ for(int j=0; j<res; j++) {
+ for(int k=0; k<res; k++) {
+ indices[i][j][k].clear();
+ }}}
+
+ // fill
+ for(int id=0;id<particles.size();id++) {
+ Vec3 pos = particles[id];
+ int i = clamp<int>(floor(pos.x/params.res*res), 0, res-1);
+ int j = clamp<int>(floor(pos.y/params.res*res), 0, res-1);
+ int k = clamp<int>(floor(pos.z/params.res*res), 0, res-1);
+ indices[i][j][k].push_back(id);
+ }
+ }
+};
+
+#define LOOP_NEIGHBORS_BEGIN(points, center, radius) \
+ int minI = clamp<int>(floor((center.x-radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ int maxI = clamp<int>(floor((center.x+radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ int minJ = clamp<int>(floor((center.y-radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ int maxJ = clamp<int>(floor((center.y+radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ int minK = clamp<int>(floor((center.z-radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ int maxK = clamp<int>(floor((center.z+radius)/params.res*points.accel->res), 0, points.accel->res-1); \
+ for(int i=minI; i<=maxI; i++) { \
+ for(int j=minJ; j<=maxJ; j++) { \
+ for(int k=minK; k<=maxK; k++) { \
+ for(int idLOOPNEIGHBORS=0;idLOOPNEIGHBORS<(int)points.accel->indices[i][j][k].size();idLOOPNEIGHBORS++) { \
+ int idn = points.accel->indices[i][j][k][idLOOPNEIGHBORS]; \
+ if(points.isActive(idn)) {
+#define LOOP_NEIGHBORS_END \
+ } \
+ } \
+ }}}
+
+#define LOOP_GHOSTS_POS_BEGIN(pos, radius) \
+ int flagLOOPGHOSTS = -1; \
+ Vec3 gPos; \
+ while(flagLOOPGHOSTS < 6) { \
+ if (flagLOOPGHOSTS < 0 && pos.x - params.bndXm <= radius) { flagLOOPGHOSTS = 0; gPos = Vec3(2.f*params.bndXm - pos.x, pos.y, pos.z); } \
+ else if(flagLOOPGHOSTS < 1 && params.bndXp - pos.x <= radius) { flagLOOPGHOSTS = 1; gPos = Vec3(2.f*params.bndXp - pos.x, pos.y, pos.z); } \
+ else if(flagLOOPGHOSTS < 2 && pos.y - params.bndYm <= radius) { flagLOOPGHOSTS = 2; gPos = Vec3(pos.x, 2.f*params.bndYm - pos.y, pos.z); } \
+ else if(flagLOOPGHOSTS < 3 && params.bndYp - pos.y <= radius) { flagLOOPGHOSTS = 3; gPos = Vec3(pos.x, 2.f*params.bndYp - pos.y, pos.z); } \
+ else if(flagLOOPGHOSTS < 4 && pos.z - params.bndZm <= radius) { flagLOOPGHOSTS = 4; gPos = Vec3(pos.x, pos.y, 2.f*params.bndZm - pos.z); } \
+ else if(flagLOOPGHOSTS < 5 && params.bndZp - pos.Z <= radius) { flagLOOPGHOSTS = 5; gPos = Vec3(pos.x, pos.y, 2.f*params.bndZp - pos.z); } \
+ else { flagLOOPGHOSTS = 6; gPos = Vec3(pos.x, pos.y, pos.z); }
+#define LOOP_GHOSTS_POS_NORMAL_BEGIN(pos, normal, radius) \
+ int flagLOOPGHOSTS = -1; \
+ Vec3 gPos, gNormal; \
+ while(flagLOOPGHOSTS < 6) { \
+ if (flagLOOPGHOSTS < 0 && pos.x - params.bndXm <= radius) { flagLOOPGHOSTS = 0; gPos = Vec3(2.f*params.bndXm - pos.x, pos.y, pos.z); gNormal = Vec3(-normal.x, normal.y, normal.z); } \
+ else if(flagLOOPGHOSTS < 1 && params.bndXp - pos.x <= radius) { flagLOOPGHOSTS = 1; gPos = Vec3(2.f*params.bndXp - pos.x, pos.y, pos.z); gNormal = Vec3(-normal.x, normal.y, normal.z); } \
+ else if(flagLOOPGHOSTS < 2 && pos.y - params.bndYm <= radius) { flagLOOPGHOSTS = 2; gPos = Vec3(pos.x, 2.f*params.bndYm - pos.y, pos.z); gNormal = Vec3( normal.x, -normal.y, normal.z); } \
+ else if(flagLOOPGHOSTS < 3 && params.bndYp - pos.y <= radius) { flagLOOPGHOSTS = 3; gPos = Vec3(pos.x, 2.f*params.bndYp - pos.y, pos.z); gNormal = Vec3( normal.x, -normal.y, normal.z); } \
+ else if(flagLOOPGHOSTS < 4 && pos.z - params.bndZm <= radius) { flagLOOPGHOSTS = 4; gPos = Vec3(pos.x, pos.y, 2.f*params.bndZm - pos.z); gNormal = Vec3( normal.x, normal.y, -normal.z); } \
+ else if(flagLOOPGHOSTS < 5 && params.bndZp - pos.Z <= radius) { flagLOOPGHOSTS = 5; gPos = Vec3(pos.x, pos.y, 2.f*params.bndZp - pos.z); gNormal = Vec3( normal.x, normal.y, -normal.z); } \
+ else { flagLOOPGHOSTS = 6; gPos = pos; gNormal = normal; }
+#define LOOP_GHOSTS_END \
+ }
+
+
+//
+// **** Wrappers around point sets to attach it an acceleration grid ****
+//
+struct PointSetWrapper {
+ ParticleAccelGrid* accel;
+
+ PointSetWrapper(ParticleAccelGrid* inAccel) {accel = inAccel;}
+ virtual void updateAccel() = 0;
+};
+
+struct BasicParticleSystemWrapper : PointSetWrapper {
+ BasicParticleSystem* points;
+
+ BasicParticleSystemWrapper(ParticleAccelGrid* inAccel) : PointSetWrapper(inAccel) {}
+
+ Vec3 getPos(int id) const {return points->getPos(id);}
+ void setPos(int id, Vec3 pos) {points->setPos(id, pos);}
+ void updateAccel() {accel->fillWith(*points);}
+ void clear() {points->clear();}
+ int size() const {return points->size();}
+ bool isActive(int id) const {return points->isActive(id);}
+ void addParticle(Vec3 pos) {points->addParticle(pos);}
+ int getStatus(int id) const {return points->getStatus(id);}
+ void addBuffered(Vec3 pos) {points->addBuffered(pos);}
+ void doCompress() {points->doCompress();}
+ void insertBufferedParticles() {points->insertBufferedParticles();}
+ void kill(int id) {points->kill(id);}
+
+ bool hasNeighbor(Vec3 pos, Real radius) const {
+ bool answer = false;
+ int minI = clamp<int>(floor((pos.x-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxI = clamp<int>(floor((pos.x+radius)/params.res*accel->res), 0, accel->res-1);
+ int minJ = clamp<int>(floor((pos.y-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxJ = clamp<int>(floor((pos.y+radius)/params.res*accel->res), 0, accel->res-1);
+ int minK = clamp<int>(floor((pos.z-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxK = clamp<int>(floor((pos.z+radius)/params.res*accel->res), 0, accel->res-1);
+ for(int i=minI; i<=maxI; i++) {
+ for(int j=minJ; j<=maxJ; j++) {
+ for(int k=minK; k<=maxK; k++) {
+ for(int id=0;id<(int)accel->indices[i][j][k].size();id++) {
+ if(points->isActive(accel->indices[i][j][k][id]) &&
+ norm(points->getPos(accel->indices[i][j][k][id]) - pos) <= radius
+ ) {answer = true; break;}
+ }
+ if(answer)break;}
+ if(answer)break;}
+ if(answer)break;}
+ return answer;
+ }
+
+ bool hasNeighborOtherThanItself(int idx, Real radius) const {
+ bool answer = false;
+ Vec3 pos = points->getPos(idx);
+ int minI = clamp<int>(floor((pos.x-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxI = clamp<int>(floor((pos.x+radius)/params.res*accel->res), 0, accel->res-1);
+ int minJ = clamp<int>(floor((pos.y-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxJ = clamp<int>(floor((pos.y+radius)/params.res*accel->res), 0, accel->res-1);
+ int minK = clamp<int>(floor((pos.z-radius)/params.res*accel->res), 0, accel->res-1);
+ int maxK = clamp<int>(floor((pos.z+radius)/params.res*accel->res), 0, accel->res-1);
+ for(int i=minI; i<=maxI; i++) {
+ for(int j=minJ; j<=maxJ; j++) {
+ for(int k=minK; k<=maxK; k++) {
+ for(int id=0;id<(int)accel->indices[i][j][k].size();id++) {
+ if(accel->indices[i][j][k][id] != idx &&
+ points->isActive(accel->indices[i][j][k][id]) &&
+ norm(points->getPos(accel->indices[i][j][k][id]) - pos) <= radius
+ ) {answer = true; break;}
+ }
+ if(answer)break;}
+ if(answer)break;}
+ if(answer)break;}
+ return answer;
+ }
+
+ void removeInvalidIndices(vector<int>& indices) {
+ vector<int> copy;
+ copy.resize(indices.size());
+ for(int i=0; i<(int)indices.size(); i++) {
+ copy[i] = indices[i];
+ }
+ indices.clear();
+ for(int i=0; i<(int)copy.size(); i++) {
+ if(points->isActive(copy[i])) {
+ indices.push_back(copy[i]);
+ }
+ }
+ }
+};
+
+struct ParticleDataImplVec3Wrapper : PointSetWrapper {
+ ParticleDataImpl<Vec3>* points;
+
+ ParticleDataImplVec3Wrapper(ParticleAccelGrid* inAccel) : PointSetWrapper(inAccel) {}
+
+ Vec3 getVec3(int id) const {return (*points)[id];}
+ void setVec3(int id, Vec3 vec) {(*points)[id] = vec;}
+ void updateAccel() {accel->fillWith(*points);}
+ bool isActive(int i) const {return true;}
+
+};
+
+
+//
+// **** globals ****
+//
+ParticleAccelGrid accelCoarse, accelSurface;
+BasicParticleSystemWrapper coarseParticles(&accelCoarse), surfacePoints(&accelSurface);
+ParticleDataImplVec3Wrapper coarseParticlesPrevPos(&accelCoarse); // WARNING: reusing the coarse accel grid to save space, don't query coarseParticlesPrevPos and coarseParticles at the same time.
+vector<Vec3> tempSurfaceVec3; // to store misc info on surface points
+vector<Real> tempSurfaceFloat; // to store misc info on surface points
+int frameCount = 0;
+
+
+
+
+//
+//**** weighting kernels *****
+//
+Real triangularWeight(Real distance, Real radius) {
+ return 1.0f - distance/radius;
+}
+Real exponentialWeight(Real distance, Real radius, Real falloff) {
+ if(distance > radius) return 0;
+ Real tmp = distance/radius;
+ return expf(-falloff*tmp*tmp);
+}
+
+Real weightKernelAdvection(Real distance) {
+ if(distance > 2.f*params.outerRadius) {
+ return 0;
+ } else {
+ return triangularWeight(distance, 2.f*params.outerRadius);
+ }
+}
+
+Real weightKernelCoarseDensity(Real distance) {
+ return exponentialWeight(distance, params.outerRadius, 2.0f);
+}
+
+Real weightSurfaceNormal(Real distance) {
+ if(distance > params.normalRadius) {
+ return 0;
+ } else {
+ return triangularWeight(distance, params.normalRadius);
+ }
+}
+
+Real weightSurfaceTangent(Real distance) {
+ if(distance > params.tangentRadius) {
+ return 0;
+ } else {
+ return triangularWeight(distance, params.tangentRadius);
+ }
+}
+
+
+//
+// **** utility ****
+//
+
+bool isInDomain(Vec3 pos)
+{
+ return params.bndXm <= pos.x && pos.x <= params.bndXp &&
+ params.bndYm <= pos.y && pos.y <= params.bndYp &&
+ params.bndZm <= pos.z && pos.z <= params.bndZp ;
+}
+
+Real smoothstep( Real edgeLeft, Real edgeRight, Real val ){
+ Real x = clamp((val - edgeLeft)/(edgeRight - edgeLeft), Real(0.), Real(1.) );
+ return x*x*(3 - 2*x);
+}
+
+
+//
+// **** surface initialization ****
+//
+
+void initFines(
+ const BasicParticleSystemWrapper& coarseParticles,
+ BasicParticleSystemWrapper& surfacePoints,
+ const FlagGrid& flags
+){
+ unsigned int discretization = (unsigned int) M_PI*(params.outerRadius+params.innerRadius)/params.meanFineDistance;
+ Real dtheta = 2*params.meanFineDistance/(params.outerRadius+params.innerRadius);
+ Real outerRadius2 = params.outerRadius*params.outerRadius;
+
+ surfacePoints.clear();
+ for (int idx=0; idx<(int)coarseParticles.size(); idx++) {
+
+ if(idx % 500 == 0) {cout << "Initializing surface points : " << setprecision(4) << 100.f*idx/coarseParticles.size() << "%" << endl;}
+
+ if (coarseParticles.isActive(idx)) {
+
+ // check flags if we are near surface
+ bool nearSurface = false;
+ Vec3 pos = coarseParticles.getPos(idx);
+ for(int i=-1; i<=1; i++) {
+ for(int j=-1; j<=1; j++) {
+ for(int k=-1; k<=1; k++) {
+ if( !flags.isFluid( ((int)pos.x)+i, ((int)pos.y)+j, ((int)pos.z)+k ) ) {
+ nearSurface = true;
+ break;
+ }
+ }}}
+
+ if(nearSurface) {
+ for(unsigned int i = 0; i <= discretization/2; ++i){
+ Real discretization2 = Real(floor(2*M_PI*sin(i*dtheta)/dtheta)+1);
+ for(Real phi = 0; phi < 2*M_PI; phi += Real(2*M_PI/discretization2)){
+ Real theta = i*dtheta;
+ Vec3 normal(sin(theta)*cos(phi), cos(theta), sin(theta)*sin(phi));
+ Vec3 position = coarseParticles.getPos(idx) + params.outerRadius*normal;
+
+ bool valid = true;
+ LOOP_NEIGHBORS_BEGIN(coarseParticles, position, 2.f*params.outerRadius)
+ if(idx!=idn && normSquare(position-coarseParticles.getPos(idn)) < outerRadius2) {
+ valid = false;
+ break;
+ }
+ LOOP_NEIGHBORS_END
+ if(valid) {
+ surfacePoints.addParticle(position);
+ }
+ }
+ }
+ }
+
+ }
+ }
+}
+
+//
+// **** surface advection ****
+//
+
+
+
+
+
+
+
+ struct advectSurfacePoints : public KernelBase {
+ advectSurfacePoints( BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles, const ParticleDataImplVec3Wrapper& coarseParticlesPrevPos ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),coarseParticles(coarseParticles),coarseParticlesPrevPos(coarseParticlesPrevPos) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles, const ParticleDataImplVec3Wrapper& coarseParticlesPrevPos ) const {
+ if(surfacePoints.isActive(idx)) {
+ Vec3 avgDisplacement(0,0,0);
+ Real totalWeight = 0;
+ Vec3 p = surfacePoints.getPos(idx);
+ LOOP_NEIGHBORS_BEGIN(coarseParticlesPrevPos, surfacePoints.getPos(idx), 2.0f*params.outerRadius)
+ if((coarseParticles.getStatus(idn) & ParticleBase::PNEW)==0 &&
+ (coarseParticles.getStatus(idn) & ParticleBase::PDELETE)==0)
+ {
+ Vec3 disp = coarseParticles.getPos(idn) - coarseParticlesPrevPos.getVec3(idn);
+ Real distance = norm(coarseParticlesPrevPos.getVec3(idn) - p);
+ Real w = weightKernelAdvection(distance);
+ avgDisplacement += w * disp;
+ totalWeight += w;
+ }
+ LOOP_NEIGHBORS_END
+ if(totalWeight != 0) avgDisplacement /= totalWeight;
+ surfacePoints.setPos(idx, p + avgDisplacement);
+ }
+} inline BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const BasicParticleSystemWrapper& getArg1() {
+ return coarseParticles; }
+ typedef BasicParticleSystemWrapper type1;inline const ParticleDataImplVec3Wrapper& getArg2() {
+ return coarseParticlesPrevPos; }
+ typedef ParticleDataImplVec3Wrapper type2; void runMessage() { debMsg("Executing kernel advectSurfacePoints ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,coarseParticles,coarseParticlesPrevPos); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ BasicParticleSystemWrapper& surfacePoints; const BasicParticleSystemWrapper& coarseParticles; const ParticleDataImplVec3Wrapper& coarseParticlesPrevPos; }
+;
+
+
+//
+// **** value and gradient of level-set band constraint ****
+//
+Real computeConstraintLevel(
+ const BasicParticleSystemWrapper& coarseParticles,
+ Vec3 pos
+){
+ Real lvl = 0.0f;
+ LOOP_NEIGHBORS_BEGIN(coarseParticles, pos, 1.5f*params.outerRadius)
+ lvl += expf(-params.constraintA*normSquare(coarseParticles.getPos(idn) - pos));
+ LOOP_NEIGHBORS_END
+ if(lvl > 1.0f) lvl = 1.0f;
+ lvl = (sqrtf(-logf(lvl)/params.constraintA)-params.innerRadius)/(params.outerRadius-params.innerRadius);
+ return lvl;
+}
+
+Vec3 computeConstraintGradient(
+ const BasicParticleSystemWrapper& coarseParticles,
+ Vec3 pos
+){
+ Vec3 gradient(0,0,0);
+ LOOP_NEIGHBORS_BEGIN(coarseParticles, pos, 1.5f*params.outerRadius)
+ gradient += 2.f*params.constraintA*(Real)(expf(-params.constraintA*normSquare(coarseParticles.getPos(idn) - pos)))*(pos - coarseParticles.getPos(idn));
+ LOOP_NEIGHBORS_END
+ return getNormalized(gradient);
+}
+
+
+//
+// **** compute surface normals ****
+//
+
+
+
+
+
+
+ struct computeSurfaceNormals : public KernelBase {
+ computeSurfaceNormals( const BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles, ParticleDataImpl<Vec3>& surfaceNormals ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),coarseParticles(coarseParticles),surfaceNormals(surfaceNormals) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles, ParticleDataImpl<Vec3>& surfaceNormals ) const {
+ Vec3 pos = surfacePoints.getPos(idx);
+
+ // approx normal with gradient
+ Vec3 gradient = computeConstraintGradient(coarseParticles, pos);
+
+ // get tangent frame
+ Vec3 n = getNormalized(gradient);
+ Vec3 vx(1,0,0);
+ Vec3 vy(0,1,0);
+ Real dotX = dot(n, vx);
+ Real dotY = dot(n, vy);
+ Vec3 t1 = getNormalized(fabs(dotX)<fabs(dotY) ? cross(n, vx) : cross(n, vy));
+ Vec3 t2 = getNormalized( cross(n,t1) ); // initial frame
+
+ // linear fit of neighboring surface points in approximated tangent frame
+ Real sw = 0, swx = 0, swy = 0, swxy = 0, swx2 = 0, swy2 = 0, swxz = 0, swyz = 0, swz = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.normalRadius)
+ Real x = dot(gPos - pos, t1);
+ Real y = dot(gPos - pos, t2);
+ Real z = dot(gPos - pos, n);
+ Real w = weightSurfaceNormal(norm(pos - gPos));
+ swx2 += w*x*x;
+ swy2 += w*y*y;
+ swxy += w*x*y;
+ swxz += w*x*z;
+ swyz += w*y*z;
+ swx += w*x;
+ swy += w*y;
+ swz += w*z;
+ sw += w;
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ Real det = -sw*swxy*swxy + 2.f*swx*swxy*swy - swx2*swy*swy - swx*swx*swy2 + sw*swx2*swy2;
+ if(det == 0) {surfaceNormals[idx]=Vec3(0,0,0);}
+ else {
+ Vec3 abc = 1.f/det*Vec3(
+ swxz*(-swy*swy+sw*swy2) + swyz*(-sw*swxy+swx*swy) + swz*(swxy*swy-swx*swy2),
+ swxz*(-sw*swxy+swx*swy) + swyz*(-swx*swx+sw*swx2) + swz*(swx*swxy-swx2*swy),
+ swxz*(swxy*swy-swx*swy2) + swyz*(swx*swxy-swx2*swy) + swz*(-swxy*swxy + swx2*swy2)
+ );
+ Vec3 normal = -getNormalized(t1*abc.x + t2*abc.y - n);
+ if(dot(gradient, normal) < 0) {normal = -normal;}
+ surfaceNormals[idx] = normal;
+ }
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const BasicParticleSystemWrapper& getArg1() {
+ return coarseParticles; }
+ typedef BasicParticleSystemWrapper type1;inline ParticleDataImpl<Vec3>& getArg2() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type2; void runMessage() { debMsg("Executing kernel computeSurfaceNormals ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,coarseParticles,surfaceNormals); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; const BasicParticleSystemWrapper& coarseParticles; ParticleDataImpl<Vec3>& surfaceNormals; }
+;
+
+
+//
+// **** smooth surface normals ****
+//
+
+
+
+
+
+ struct computeAveragedNormals : public KernelBase {
+ computeAveragedNormals( const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) const {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Vec3 newNormal = Vec3(0,0,0);
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+ Real w = weightSurfaceNormal(norm(pos - surfacePoints.getPos(idn)));
+ newNormal += w * surfaceNormals[idn];
+ LOOP_NEIGHBORS_END
+ tempSurfaceVec3[idx] = getNormalized(newNormal);
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1; void runMessage() { debMsg("Executing kernel computeAveragedNormals ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,surfaceNormals); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; const ParticleDataImpl<Vec3>& surfaceNormals; }
+;
+
+
+
+
+
+ struct assignNormals : public KernelBase {
+ assignNormals( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Vec3>& surfaceNormals ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Vec3>& surfaceNormals ) const {
+ surfaceNormals[idx] = tempSurfaceVec3[idx];
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1; void runMessage() { debMsg("Executing kernel assignNormals ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,surfaceNormals); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Vec3>& surfaceNormals; }
+;
+
+void smoothSurfaceNormals(
+ const BasicParticleSystemWrapper& surfacePoints,
+ ParticleDataImpl<Vec3>& surfaceNormals
+){
+ tempSurfaceVec3.resize(surfacePoints.size());
+
+ computeAveragedNormals(surfacePoints, surfaceNormals);
+ assignNormals(surfacePoints, surfaceNormals);
+}
+
+
+
+//
+// **** addition/deletion of particles. Not parallel to prevent write/delete conflicts ****
+//
+
+void addDeleteSurfacePoints(
+ BasicParticleSystemWrapper& surfacePoints
+){
+ int fixedSize = surfacePoints.size();
+ for (int idx=0; idx<fixedSize; idx++) {
+ // compute proxy tangent displacement
+ Vec3 pos = surfacePoints.getPos(idx);
+
+ Vec3 gradient = computeConstraintGradient(coarseParticles, pos);
+
+ Real wt = 0;
+ Vec3 tangentDisplacement(0,0,0);
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
+ if(idn != idx) {
+ Vec3 dir = pos - surfacePoints.getPos(idn);
+ Real length = norm(dir);
+ dir = getNormalized(dir);
+
+ // Decompose direction into normal and tangent directions.
+ Vec3 dn = dot(dir, gradient)*gradient;
+ Vec3 dt = dir - dn;
+
+ Real w = weightSurfaceTangent(length);
+ wt += w;
+ tangentDisplacement += w * dt;
+ }
+ LOOP_NEIGHBORS_END
+ if(norm(tangentDisplacement)!=0) {tangentDisplacement = getNormalized(tangentDisplacement);}
+
+ // check density criterion, add surface point if necessary
+ Vec3 creationPos = pos + params.meanFineDistance*tangentDisplacement;
+ if(
+ isInDomain(creationPos) &&
+ !surfacePoints.hasNeighbor(creationPos, params.meanFineDistance-(1e-6))
+ ) {
+ //create point
+ surfacePoints.addBuffered(creationPos);
+ }
+
+ }
+
+
+ surfacePoints.doCompress();
+ surfacePoints.insertBufferedParticles();
+
+
+ // check density criterion, delete surface points if necessary
+ fixedSize = surfacePoints.size();
+ for (int idx=0; idx<fixedSize; idx++) {
+ if(
+ !isInDomain(surfacePoints.getPos(idx)) ||
+ surfacePoints.hasNeighborOtherThanItself(idx, 0.67*params.meanFineDistance)
+ ) {
+ surfacePoints.kill(idx);
+ }
+ }
+
+ // delete surface points if no coarse neighbors in advection radius
+ fixedSize = surfacePoints.size();
+ for (int idx=0; idx<fixedSize; idx++) {
+ Vec3 pos = surfacePoints.getPos(idx);
+ if(!coarseParticles.hasNeighbor(pos, 2.f*params.outerRadius)) {
+ surfacePoints.kill(idx);
+ }
+ }
+
+ // delete surface point if too far from constraint
+ fixedSize = surfacePoints.size();
+ for (int idx=0; idx<fixedSize; idx++) {
+ Real level = computeConstraintLevel(coarseParticles, surfacePoints.getPos(idx));
+ if(level < -0.2 || level > 1.2) {
+ surfacePoints.kill(idx);
+ }
+ }
+
+
+ surfacePoints.doCompress();
+ surfacePoints.insertBufferedParticles();
+}
+
+
+//
+// **** surface maintenance ****
+//
+
+
+
+
+
+ struct computeSurfaceDensities : public KernelBase {
+ computeSurfaceDensities( const BasicParticleSystemWrapper& surfacePoints, void* dummy ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),dummy(dummy) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, void* dummy ) const {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Real density = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.normalRadius)
+ density += weightSurfaceNormal(norm(pos-gPos));
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ tempSurfaceFloat[idx] = density;
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline void* getArg1() {
+ return dummy; }
+ typedef void type1; void runMessage() { debMsg("Executing kernel computeSurfaceDensities ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,dummy); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; void* dummy; }
+;
+
+
+
+
+
+ struct computeSurfaceDisplacements : public KernelBase {
+ computeSurfaceDisplacements( const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) const {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Vec3 normal = surfaceNormals[idx];
+
+ Vec3 displacementNormal(0,0,0);
+ Vec3 displacementTangent(0,0,0);
+ Real wTotal = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
+
+ LOOP_GHOSTS_POS_NORMAL_BEGIN(surfacePoints.getPos(idn), surfaceNormals[idn], params.normalRadius)
+ Vec3 dir = pos - gPos;
+ Real length = norm(dir);
+ Vec3 dn = dot(dir,surfaceNormals[idx])*surfaceNormals[idx];
+ Vec3 dt = dir - dn;
+ if(tempSurfaceFloat[idn]==0) {continue;}
+ Real w = weightSurfaceNormal( length ) / tempSurfaceFloat[idn];
+
+ Vec3 crossVec = getNormalized(cross(normal, -dir));
+ Vec3 projectedNormal = getNormalized(gNormal - dot(crossVec,gNormal)*crossVec);
+ if(dot(projectedNormal, normal) < 0 || abs(dot(normal,normal+projectedNormal)) < 1e-6) {continue;}
+ dn = -dot(normal+projectedNormal,dir)/dot(normal,normal+projectedNormal)*normal;
+
+ displacementNormal += w * dn;
+ displacementTangent += w * getNormalized(dt);
+ wTotal += w;
+ LOOP_GHOSTS_END
+
+ LOOP_NEIGHBORS_END
+ if(wTotal != 0) {
+ displacementNormal /= wTotal;
+ displacementTangent /= wTotal;
+ }
+ displacementNormal *= .75f;
+ displacementTangent *= .25f * params.meanFineDistance;
+ tempSurfaceVec3[idx] = displacementNormal + displacementTangent;
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1; void runMessage() { debMsg("Executing kernel computeSurfaceDisplacements ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,surfaceNormals); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; const ParticleDataImpl<Vec3>& surfaceNormals; }
+;
+
+
+
+
+
+ struct applySurfaceDisplacements : public KernelBase {
+ applySurfaceDisplacements( BasicParticleSystemWrapper& surfacePoints, void* dummy ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),dummy(dummy) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystemWrapper& surfacePoints, void* dummy ) const {
+ surfacePoints.setPos(idx, surfacePoints.getPos(idx) + tempSurfaceVec3[idx]);
+} inline BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline void* getArg1() {
+ return dummy; }
+ typedef void type1; void runMessage() { debMsg("Executing kernel applySurfaceDisplacements ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,dummy); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ BasicParticleSystemWrapper& surfacePoints; void* dummy; }
+;
+
+
+void regularizeSurfacePoints(
+ BasicParticleSystemWrapper& surfacePoints,
+ const ParticleDataImpl<Vec3>& surfaceNormals
+){
+ tempSurfaceVec3.resize(surfacePoints.size());
+ tempSurfaceFloat.resize(surfacePoints.size());
+
+ computeSurfaceDensities(surfacePoints, 0);
+ computeSurfaceDisplacements(surfacePoints, surfaceNormals);
+ applySurfaceDisplacements(surfacePoints, 0);
+}
+
+
+
+
+
+
+ struct constrainSurface : public KernelBase {
+ constrainSurface( BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),coarseParticles(coarseParticles) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, BasicParticleSystemWrapper& surfacePoints, const BasicParticleSystemWrapper& coarseParticles ) const {
+ Vec3 pos = surfacePoints.getPos(idx);
+ Real level = computeConstraintLevel(coarseParticles, surfacePoints.getPos(idx));
+ if(level > 1) {
+ surfacePoints.setPos(idx, pos - (params.outerRadius-params.innerRadius)*(level-1)*computeConstraintGradient(coarseParticles, surfacePoints.getPos(idx)));
+ }else if(level < 0) {
+ surfacePoints.setPos(idx, pos - (params.outerRadius-params.innerRadius)* level *computeConstraintGradient(coarseParticles, surfacePoints.getPos(idx)));
+ }
+} inline BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const BasicParticleSystemWrapper& getArg1() {
+ return coarseParticles; }
+ typedef BasicParticleSystemWrapper type1; void runMessage() { debMsg("Executing kernel constrainSurface ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,coarseParticles); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ BasicParticleSystemWrapper& surfacePoints; const BasicParticleSystemWrapper& coarseParticles; }
+;
+
+
+
+
+
+
+
+
+
+ struct interpolateNewWaveData : public KernelBase {
+ interpolateNewWaveData( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, ParticleDataImpl<Real>& surfaceWaveDtH, ParticleDataImpl<Real>& surfaceWaveSeed, ParticleDataImpl<Real>& surfaceWaveSeedAmplitude ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceWaveH(surfaceWaveH),surfaceWaveDtH(surfaceWaveDtH),surfaceWaveSeed(surfaceWaveSeed),surfaceWaveSeedAmplitude(surfaceWaveSeedAmplitude) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, ParticleDataImpl<Real>& surfaceWaveDtH, ParticleDataImpl<Real>& surfaceWaveSeed, ParticleDataImpl<Real>& surfaceWaveSeedAmplitude ) const {
+ if(surfacePoints.getStatus(idx) & ParticleBase::PNEW) {
+ Vec3 pos = surfacePoints.getPos(idx);
+ surfaceWaveH[idx] = 0;
+ surfaceWaveDtH[idx] = 0;
+ Real wTotal = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
+ if(!(surfacePoints.getStatus(idn) & ParticleBase::PNEW)) {
+ Real w = weightSurfaceTangent(norm( pos - surfacePoints.getPos(idn) ));
+ surfaceWaveH[idx] += w * surfaceWaveH[idn];
+ surfaceWaveDtH[idx] += w * surfaceWaveDtH[idn];
+ surfaceWaveSeed[idx] += w * surfaceWaveSeed[idn];
+ surfaceWaveSeedAmplitude[idx] += w * surfaceWaveSeedAmplitude[idn];
+ wTotal += w;
+ }
+ LOOP_NEIGHBORS_END
+ if(wTotal != 0) {
+ surfaceWaveH[idx] /= wTotal;
+ surfaceWaveDtH[idx] /= wTotal;
+ surfaceWaveSeed[idx] /= wTotal;
+ surfaceWaveSeedAmplitude[idx] /= wTotal;
+ }
+ }
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Real>& getArg1() {
+ return surfaceWaveH; }
+ typedef ParticleDataImpl<Real> type1;inline ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveDtH; }
+ typedef ParticleDataImpl<Real> type2;inline ParticleDataImpl<Real>& getArg3() {
+ return surfaceWaveSeed; }
+ typedef ParticleDataImpl<Real> type3;inline ParticleDataImpl<Real>& getArg4() {
+ return surfaceWaveSeedAmplitude; }
+ typedef ParticleDataImpl<Real> type4; void runMessage() { debMsg("Executing kernel interpolateNewWaveData ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,surfaceWaveH,surfaceWaveDtH,surfaceWaveSeed,surfaceWaveSeedAmplitude); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Real>& surfaceWaveH; ParticleDataImpl<Real>& surfaceWaveDtH; ParticleDataImpl<Real>& surfaceWaveSeed; ParticleDataImpl<Real>& surfaceWaveSeedAmplitude; }
+;
+
+
+void surfaceMaintenance(
+ const BasicParticleSystemWrapper& coarseParticles,
+ BasicParticleSystemWrapper& surfacePoints,
+ ParticleDataImpl<Vec3>& surfaceNormals,
+ ParticleDataImpl<Real>& surfaceWaveH,
+ ParticleDataImpl<Real>& surfaceWaveDtH,
+ ParticleDataImpl<Real>& surfaceWaveSeed,
+ ParticleDataImpl<Real>& surfaceWaveSeedAmplitude,
+ int nbIterations
+){
+ int countIterations = nbIterations;
+ while(countIterations > 0) {
+ addDeleteSurfacePoints(surfacePoints);
+ surfacePoints.updateAccel();
+ computeSurfaceNormals(surfacePoints, coarseParticles, surfaceNormals);
+ smoothSurfaceNormals(surfacePoints, surfaceNormals);
+
+ regularizeSurfacePoints(surfacePoints, surfaceNormals);
+ surfacePoints.updateAccel();
+ constrainSurface(surfacePoints, coarseParticles);
+ surfacePoints.updateAccel();
+
+ interpolateNewWaveData(surfacePoints, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed, surfaceWaveSeedAmplitude);
+
+ countIterations--;
+ }
+}
+
+
+
+
+//
+// **** surface wave seeding and evolution ****
+//
+
+
+
+
+
+
+
+ struct addSeed : public KernelBase {
+ addSeed( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, const ParticleDataImpl<Real>& surfaceWaveSeed ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceWaveH(surfaceWaveH),surfaceWaveSeed(surfaceWaveSeed) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, const ParticleDataImpl<Real>& surfaceWaveSeed ) const {
+ surfaceWaveH[idx] += surfaceWaveSeed[idx];
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Real>& getArg1() {
+ return surfaceWaveH; }
+ typedef ParticleDataImpl<Real> type1;inline const ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveSeed; }
+ typedef ParticleDataImpl<Real> type2; void runMessage() { debMsg("Executing kernel addSeed ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,surfaceWaveH,surfaceWaveSeed); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Real>& surfaceWaveH; const ParticleDataImpl<Real>& surfaceWaveSeed; }
+;
+
+
+
+
+
+
+
+ struct computeSurfaceWaveNormal : public KernelBase {
+ computeSurfaceWaveNormal( const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals, const ParticleDataImpl<Real>& surfaceWaveH ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals),surfaceWaveH(surfaceWaveH) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals, const ParticleDataImpl<Real>& surfaceWaveH ) const {
+ Vec3 pos = surfacePoints.getPos(idx);
+
+ // get tangent frame
+ Vec3 n = getNormalized(surfaceNormals[idx]);
+ Vec3 vx(1,0,0);
+ Vec3 vy(0,1,0);
+ Real dotX = dot(n, vx);
+ Real dotY = dot(n, vy);
+ Vec3 t1 = getNormalized(fabs(dotX)<fabs(dotY) ? cross(n, vx) : cross(n, vy));
+ Vec3 t2 = getNormalized( cross(n,t1) );
+
+ // linear fit
+ Real sw = 0, swx = 0, swy = 0, swxy = 0, swx2 = 0, swy2 = 0, swxz = 0, swyz = 0, swz = 0;
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.tangentRadius)
+ Real x = dot(gPos - pos, t1);
+ Real y = dot(gPos - pos, t2);
+ Real z = surfaceWaveH[idn];
+ Real w = weightSurfaceTangent(norm(pos - gPos));
+ swx2 += w*x*x;
+ swy2 += w*y*y;
+ swxy += w*x*y;
+ swxz += w*x*z;
+ swyz += w*y*z;
+ swx += w*x;
+ swy += w*y;
+ swz += w*z;
+ sw += w;
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ Real det = -sw*swxy*swxy + 2.f*swx*swxy*swy - swx2*swy*swy - swx*swx*swy2 + sw*swx2*swy2;
+ if(det == 0) {tempSurfaceVec3[idx]=Vec3(0,0,0);}
+ else {
+ Vec3 abc = 1.f/det*Vec3(
+ swxz*(-swy*swy+sw*swy2) + swyz*(-sw*swxy+swx*swy) + swz*(swxy*swy-swx*swy2),
+ swxz*(-sw*swxy+swx*swy) + swyz*(-swx*swx+sw*swx2) + swz*(swx*swxy-swx2*swy),
+ swxz*(swxy*swy-swx*swy2) + swyz*(swx*swxy-swx2*swy) + swz*(-swxy*swxy + swx2*swy2)
+ );
+ Vec3 waveNormal = -getNormalized(vx*abc.x + vy*abc.y - Vec3(0,0,1));
+ tempSurfaceVec3[idx] = waveNormal;
+ }
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1;inline const ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveH; }
+ typedef ParticleDataImpl<Real> type2; void runMessage() { debMsg("Executing kernel computeSurfaceWaveNormal ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,surfaceNormals,surfaceWaveH); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; const ParticleDataImpl<Vec3>& surfaceNormals; const ParticleDataImpl<Real>& surfaceWaveH; }
+;
+
+
+
+
+
+
+ struct computeSurfaceWaveLaplacians : public KernelBase {
+ computeSurfaceWaveLaplacians( const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals, const ParticleDataImpl<Real>& surfaceWaveH ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals),surfaceWaveH(surfaceWaveH) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals, const ParticleDataImpl<Real>& surfaceWaveH ) const {
+ Real laplacian = 0;
+ Real wTotal = 0;
+ Vec3 pPos = surfacePoints.getPos(idx);
+ Vec3 pNormal = surfaceNormals[idx];
+
+ Vec3 vx(1,0,0);
+ Vec3 vy(0,1,0);
+ Real dotX = dot(pNormal, vx);
+ Real dotY = dot(pNormal, vy);
+ Vec3 t1 = getNormalized(fabs(dotX)<fabs(dotY) ? cross(pNormal, vx) : cross(pNormal, vy));
+ Vec3 t2 = getNormalized( cross(pNormal,t1) );
+
+ Vec3 pWaveNormal = tempSurfaceVec3[idx];
+ Real ph = surfaceWaveH[idx];
+ if(pWaveNormal.z == 0) {tempSurfaceFloat[idx]=0;}
+ else {
+
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.tangentRadius)
+ Real nh = surfaceWaveH[idn];
+ LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.tangentRadius)
+ Vec3 dir = gPos - pPos;
+ Real lengthDir = norm(dir);
+ if(lengthDir < 1e-5) continue;
+ Vec3 tangentDir = lengthDir*getNormalized(dir - dot(dir, pNormal)*pNormal);
+ Real dirX = dot(tangentDir, t1);
+ Real dirY = dot(tangentDir, t2);
+ Real dz = nh - ph - (-pWaveNormal.x/pWaveNormal.z)*dirX - (-pWaveNormal.y/pWaveNormal.z)*dirY;
+ Real w = weightSurfaceTangent(norm(pPos - gPos));
+ wTotal += w;
+ laplacian += clamp(w * 4*dz/(lengthDir*lengthDir), Real(-100.), Real(100.) );
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ if(wTotal != 0) {tempSurfaceFloat[idx] = laplacian/wTotal;}
+ else {tempSurfaceFloat[idx] = 0;}
+ }
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1;inline const ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveH; }
+ typedef ParticleDataImpl<Real> type2; void runMessage() { debMsg("Executing kernel computeSurfaceWaveLaplacians ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,surfaceNormals,surfaceWaveH); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; const ParticleDataImpl<Vec3>& surfaceNormals; const ParticleDataImpl<Real>& surfaceWaveH; }
+;
+
+
+
+
+
+
+
+
+ struct evolveWave : public KernelBase {
+ evolveWave( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, ParticleDataImpl<Real>& surfaceWaveDtH, const ParticleDataImpl<Real>& surfaceWaveSeed ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceWaveH(surfaceWaveH),surfaceWaveDtH(surfaceWaveDtH),surfaceWaveSeed(surfaceWaveSeed) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveH, ParticleDataImpl<Real>& surfaceWaveDtH, const ParticleDataImpl<Real>& surfaceWaveSeed ) const {
+ surfaceWaveDtH[idx] += params.waveSpeed*params.waveSpeed * params.dt * tempSurfaceFloat[idx];
+ surfaceWaveDtH[idx] /= (1 + params.dt * params.waveDamping);
+ surfaceWaveH[idx] += params.dt * surfaceWaveDtH[idx];
+ surfaceWaveH[idx] /= (1 + params.dt * params.waveDamping);
+ surfaceWaveH[idx] -= surfaceWaveSeed[idx];
+
+ // clamp H and DtH (to prevent rare extreme behaviors)
+ surfaceWaveDtH[idx] = clamp(surfaceWaveDtH[idx], -params.waveMaxFrequency*params.waveMaxAmplitude, params.waveMaxFrequency*params.waveMaxAmplitude);
+ surfaceWaveH[idx] = clamp(surfaceWaveH[idx], -params.waveMaxAmplitude, params.waveMaxAmplitude);
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Real>& getArg1() {
+ return surfaceWaveH; }
+ typedef ParticleDataImpl<Real> type1;inline ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveDtH; }
+ typedef ParticleDataImpl<Real> type2;inline const ParticleDataImpl<Real>& getArg3() {
+ return surfaceWaveSeed; }
+ typedef ParticleDataImpl<Real> type3; void runMessage() { debMsg("Executing kernel evolveWave ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,surfaceWaveH,surfaceWaveDtH,surfaceWaveSeed); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Real>& surfaceWaveH; ParticleDataImpl<Real>& surfaceWaveDtH; const ParticleDataImpl<Real>& surfaceWaveSeed; }
+;
+
+
+
+
+
+
+ struct computeSurfaceCurvature : public KernelBase {
+ computeSurfaceCurvature( const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceNormals(surfaceNormals) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, const ParticleDataImpl<Vec3>& surfaceNormals ) const {
+ Vec3 pPos = surfacePoints.getPos(idx);
+ Real wTotal = 0;
+ Real curv = 0;
+ Vec3 pNormal = surfaceNormals[idx];
+
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.normalRadius)
+ LOOP_GHOSTS_POS_NORMAL_BEGIN(surfacePoints.getPos(idn), surfaceNormals[idn], params.normalRadius)
+ Vec3 dir = pPos - gPos;
+ if(dot(pNormal, gNormal) < 0) {continue;} // backfacing
+ Real dist = norm(dir);
+ if(dist < params.normalRadius/100.f){ continue; }
+
+ Real distn = dot(dir, pNormal);
+
+ Real w = weightSurfaceNormal(dist);
+ curv += w * distn;
+ wTotal += w;
+ LOOP_GHOSTS_END
+ LOOP_NEIGHBORS_END
+ if(wTotal!=0) {curv /= wTotal;}
+ tempSurfaceFloat[idx] = fabs(curv);
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline const ParticleDataImpl<Vec3>& getArg1() {
+ return surfaceNormals; }
+ typedef ParticleDataImpl<Vec3> type1; void runMessage() { debMsg("Executing kernel computeSurfaceCurvature ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,surfaceNormals); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; const ParticleDataImpl<Vec3>& surfaceNormals; }
+;
+
+
+
+
+
+
+ struct smoothCurvature : public KernelBase {
+ smoothCurvature( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveSource ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceWaveSource(surfaceWaveSource) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveSource ) const {
+ Vec3 pPos = surfacePoints.getPos(idx);
+ Real curv = 0;
+ Real wTotal = 0;
+
+ LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.normalRadius)
+ Real w = weightSurfaceNormal(norm( pPos - surfacePoints.getPos(idn) ));
+ curv += w * tempSurfaceFloat[idn];
+ wTotal += w;
+ LOOP_NEIGHBORS_END
+ if(wTotal!=0) {curv /= wTotal;}
+ surfaceWaveSource[idx] = curv;
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Real>& getArg1() {
+ return surfaceWaveSource; }
+ typedef ParticleDataImpl<Real> type1; void runMessage() { debMsg("Executing kernel smoothCurvature ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,surfaceWaveSource); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Real>& surfaceWaveSource; }
+;
+
+
+
+
+
+
+
+
+ struct seedWaves : public KernelBase {
+ seedWaves( const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveSeed, ParticleDataImpl<Real>& surfaceWaveSeedAmplitude, ParticleDataImpl<Real>& surfaceWaveSource ) : KernelBase(surfacePoints.size()) ,surfacePoints(surfacePoints),surfaceWaveSeed(surfaceWaveSeed),surfaceWaveSeedAmplitude(surfaceWaveSeedAmplitude),surfaceWaveSource(surfaceWaveSource) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const BasicParticleSystemWrapper& surfacePoints, ParticleDataImpl<Real>& surfaceWaveSeed, ParticleDataImpl<Real>& surfaceWaveSeedAmplitude, ParticleDataImpl<Real>& surfaceWaveSource ) const {
+ Real source = smoothstep(params.waveSeedingCurvatureThresholdRegionCenter - params.waveSeedingCurvatureThresholdRegionRadius, params.waveSeedingCurvatureThresholdRegionCenter + params.waveSeedingCurvatureThresholdRegionRadius, (Real) surfaceWaveSource[idx]) * 2.f - 1.f;
+ Real freq = params.waveSeedFrequency;
+ Real theta = params.dt * frameCount * params.waveSpeed * freq;
+ Real costheta = cosf(theta);
+ Real maxSeedAmplitude = params.waveMaxSeedingAmplitude * params.waveMaxAmplitude;
+
+ surfaceWaveSeedAmplitude[idx] = clamp<Real>(surfaceWaveSeedAmplitude[idx]+source*params.waveSeedStepSizeRatioOfMax*maxSeedAmplitude, 0.f, maxSeedAmplitude);
+ surfaceWaveSeed[idx] = surfaceWaveSeedAmplitude[idx] * costheta;
+
+ // source values for display (not used after this point anyway)
+ surfaceWaveSource[idx] = (source>=0) ? 1 : 0;
+} inline const BasicParticleSystemWrapper& getArg0() {
+ return surfacePoints; }
+ typedef BasicParticleSystemWrapper type0;inline ParticleDataImpl<Real>& getArg1() {
+ return surfaceWaveSeed; }
+ typedef ParticleDataImpl<Real> type1;inline ParticleDataImpl<Real>& getArg2() {
+ return surfaceWaveSeedAmplitude; }
+ typedef ParticleDataImpl<Real> type2;inline ParticleDataImpl<Real>& getArg3() {
+ return surfaceWaveSource; }
+ typedef ParticleDataImpl<Real> type3; void runMessage() { debMsg("Executing kernel seedWaves ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, surfacePoints,surfaceWaveSeed,surfaceWaveSeedAmplitude,surfaceWaveSource); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ const BasicParticleSystemWrapper& surfacePoints; ParticleDataImpl<Real>& surfaceWaveSeed; ParticleDataImpl<Real>& surfaceWaveSeedAmplitude; ParticleDataImpl<Real>& surfaceWaveSource; }
+;
+
+
+
+void surfaceWaves(
+ const BasicParticleSystemWrapper& surfacePoints,
+ const ParticleDataImpl<Vec3>& surfaceNormals,
+ ParticleDataImpl<Real>& surfaceWaveH,
+ ParticleDataImpl<Real>& surfaceWaveDtH,
+ ParticleDataImpl<Real>& surfaceWaveSource,
+ ParticleDataImpl<Real>& surfaceWaveSeed,
+ ParticleDataImpl<Real>& surfaceWaveSeedAmplitude
+){
+ addSeed(surfacePoints, surfaceWaveH, surfaceWaveSeed);
+ computeSurfaceWaveNormal(surfacePoints, surfaceNormals, surfaceWaveH);
+ computeSurfaceWaveLaplacians(surfacePoints, surfaceNormals, surfaceWaveH);
+ evolveWave(surfacePoints, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed);
+ computeSurfaceCurvature(surfacePoints, surfaceNormals);
+ smoothCurvature(surfacePoints, surfaceWaveSource);
+ seedWaves(surfacePoints, surfaceWaveSeed, surfaceWaveSeedAmplitude, surfaceWaveSource);
+}
+
+
+
+//
+// **** main function ****
+//
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void particleSurfaceTurbulence( const FlagGrid& flags, BasicParticleSystem& coarseParts, ParticleDataImpl<Vec3>& coarsePartsPrevPos, BasicParticleSystem& surfPoints, ParticleDataImpl<Vec3>& surfaceNormals, ParticleDataImpl<Real>& surfaceWaveH, ParticleDataImpl<Real>& surfaceWaveDtH, BasicParticleSystem& surfacePointsDisplaced, ParticleDataImpl<Real>& surfaceWaveSource, ParticleDataImpl<Real>& surfaceWaveSeed, ParticleDataImpl<Real>& surfaceWaveSeedAmplitude, int res, Real outerRadius = 1.0f, int surfaceDensity = 20, int nbSurfaceMaintenanceIterations = 4, Real dt = 0.005f, Real waveSpeed = 16.0f, Real waveDamping = 0.0f, Real waveSeedFrequency = 4, Real waveMaxAmplitude = 0.25f, Real waveMaxFrequency = 800, Real waveMaxSeedingAmplitude = 0.5, Real waveSeedingCurvatureThresholdRegionCenter = 0.025f, Real waveSeedingCurvatureThresholdRegionRadius = 0.01f, Real waveSeedStepSizeRatioOfMax = 0.05f ) {
+# if USE_CHRONO==1
+ static std::chrono::high_resolution_clock::time_point begin, end;
+ end = std::chrono::high_resolution_clock::now();
+ cout << std::chrono::duration_cast<std::chrono::nanoseconds>(end-begin).count()/1000000000.f << " : time sim" << endl;
+ begin = std::chrono::high_resolution_clock::now();
+# endif
+
+ // wrap data
+ coarseParticles.points = &coarseParts;
+ coarseParticlesPrevPos.points = &coarsePartsPrevPos;
+ surfacePoints.points = &surfPoints;
+
+ // copy parameters
+ params.res = res;
+ params.outerRadius = outerRadius;
+ params.surfaceDensity = surfaceDensity;
+ params.nbSurfaceMaintenanceIterations = nbSurfaceMaintenanceIterations;
+ params.dt = dt;
+ params.waveSpeed = waveSpeed;
+ params.waveDamping = waveDamping;
+ params.waveSeedFrequency = waveSeedFrequency;
+ params.waveMaxAmplitude = waveMaxAmplitude;
+ params.waveMaxFrequency = waveMaxFrequency;
+ params.waveMaxSeedingAmplitude = waveMaxSeedingAmplitude;
+ params.waveSeedingCurvatureThresholdRegionCenter = waveSeedingCurvatureThresholdRegionCenter;
+ params.waveSeedingCurvatureThresholdRegionRadius = waveSeedingCurvatureThresholdRegionRadius;
+ params.waveSeedStepSizeRatioOfMax = waveSeedStepSizeRatioOfMax;
+
+ // compute other parameters
+ params.innerRadius = params.outerRadius/2.0;
+ params.meanFineDistance = M_PI*(params.outerRadius+params.innerRadius)/params.surfaceDensity;
+ params.constraintA = logf(2.0f/(1.0f + weightKernelCoarseDensity(params.outerRadius+params.innerRadius)))/(powf((params.outerRadius+params.innerRadius)/2,2) - params.innerRadius*params.innerRadius);
+ params.normalRadius = 0.5f*(params.outerRadius + params.innerRadius);
+ params.tangentRadius = 2.1f*params.meanFineDistance;
+ params.bndXm = params.bndYm = params.bndZm = 2;
+ params.bndXp = params.bndYp = params.bndZp = params.res-2;
+
+ if(frameCount==0) {
+
+ // initialize accel grids
+ accelCoarse.init(2.f*res/params.outerRadius);
+ accelSurface.init(1.f*res/(2.f*params.meanFineDistance));
+
+ // update coarse accel structure
+ coarseParticles.updateAccel();
+
+ // create surface points
+ initFines(coarseParticles, surfacePoints, flags);
+
+ // smooth surface
+ surfaceMaintenance(coarseParticles, surfacePoints, surfaceNormals, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed, surfaceWaveSeedAmplitude, 6*params.nbSurfaceMaintenanceIterations);
+
+ // set wave values to zero
+ for (int idx=0; idx<surfacePoints.size(); idx++) {
+ surfaceWaveH[idx] = 0;
+ surfaceWaveDtH[idx] = 0;
+ surfaceWaveSeed[idx] = 0;
+ surfaceWaveSeedAmplitude[idx] = 0;
+ }
+
+ } else {
+
+ // update coarse accel structure with previous coarse particles positions
+ coarseParticlesPrevPos.updateAccel();
+
+ //advect surface points following coarse particles
+ advectSurfacePoints(surfacePoints, coarseParticles, coarseParticlesPrevPos);
+ surfacePoints.updateAccel();
+
+ // update acceleration structure for surface points
+ coarseParticles.updateAccel();
+
+ //surface maintenance
+ surfaceMaintenance(coarseParticles, surfacePoints, surfaceNormals, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed, surfaceWaveSeedAmplitude, params.nbSurfaceMaintenanceIterations);
+
+ // surface waves
+ surfaceWaves(surfacePoints, surfaceNormals, surfaceWaveH, surfaceWaveDtH, surfaceWaveSource, surfaceWaveSeed, surfaceWaveSeedAmplitude);
+ }
+ frameCount++;
+
+ // save positions as previous positions for next step
+ for(int id=0;id<coarseParticles.size();id++) {
+ if((coarseParticles.getStatus(id) & ParticleBase::PNEW) == 0 &&
+ (coarseParticles.getStatus(id) & ParticleBase::PDELETE) == 0
+ ){
+ coarseParticlesPrevPos.setVec3(id, coarseParticles.getPos(id));
+ }
+ }
+
+ // create displaced points for display
+ surfacePointsDisplaced.clear();
+ for(int idx=0;idx<surfacePoints.size();idx++) {
+ if((surfacePoints.getStatus(idx) & ParticleBase::PDELETE) == 0) {
+ surfacePointsDisplaced.addParticle(surfacePoints.getPos(idx) + surfaceNormals[idx]*surfaceWaveH[idx]);
+ }
+ }
+
+# if USE_CHRONO==1
+ end = std::chrono::high_resolution_clock::now();
+ cout << std::chrono::duration_cast<std::chrono::nanoseconds>(end-begin).count()/1000000000.f << " : time upres" << endl;
+ begin = std::chrono::high_resolution_clock::now();
+# endif
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "particleSurfaceTurbulence" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); BasicParticleSystem& coarseParts = *_args.getPtr<BasicParticleSystem >("coarseParts",1,&_lock); ParticleDataImpl<Vec3>& coarsePartsPrevPos = *_args.getPtr<ParticleDataImpl<Vec3> >("coarsePartsPrevPos",2,&_lock); BasicParticleSystem& surfPoints = *_args.getPtr<BasicParticleSystem >("surfPoints",3,&_lock); ParticleDataImpl<Vec3>& surfaceNormals = *_args.getPtr<ParticleDataImpl<Vec3> >("surfaceNormals",4,&_lock); ParticleDataImpl<Real>& surfaceWaveH = *_args.getPtr<ParticleDataImpl<Real> >("surfaceWaveH",5,&_lock); ParticleDataImpl<Real>& surfaceWaveDtH = *_args.getPtr<ParticleDataImpl<Real> >("surfaceWaveDtH",6,&_lock); BasicParticleSystem& surfacePointsDisplaced = *_args.getPtr<BasicParticleSystem >("surfacePointsDisplaced",7,&_lock); ParticleDataImpl<Real>& surfaceWaveSource = *_args.getPtr<ParticleDataImpl<Real> >("surfaceWaveSource",8,&_lock); ParticleDataImpl<Real>& surfaceWaveSeed = *_args.getPtr<ParticleDataImpl<Real> >("surfaceWaveSeed",9,&_lock); ParticleDataImpl<Real>& surfaceWaveSeedAmplitude = *_args.getPtr<ParticleDataImpl<Real> >("surfaceWaveSeedAmplitude",10,&_lock); int res = _args.get<int >("res",11,&_lock); Real outerRadius = _args.getOpt<Real >("outerRadius",12,1.0f,&_lock); int surfaceDensity = _args.getOpt<int >("surfaceDensity",13,20,&_lock); int nbSurfaceMaintenanceIterations = _args.getOpt<int >("nbSurfaceMaintenanceIterations",14,4,&_lock); Real dt = _args.getOpt<Real >("dt",15,0.005f,&_lock); Real waveSpeed = _args.getOpt<Real >("waveSpeed",16,16.0f,&_lock); Real waveDamping = _args.getOpt<Real >("waveDamping",17,0.0f,&_lock); Real waveSeedFrequency = _args.getOpt<Real >("waveSeedFrequency",18,4,&_lock); Real waveMaxAmplitude = _args.getOpt<Real >("waveMaxAmplitude",19,0.25f,&_lock); Real waveMaxFrequency = _args.getOpt<Real >("waveMaxFrequency",20,800,&_lock); Real waveMaxSeedingAmplitude = _args.getOpt<Real >("waveMaxSeedingAmplitude",21,0.5,&_lock); Real waveSeedingCurvatureThresholdRegionCenter = _args.getOpt<Real >("waveSeedingCurvatureThresholdRegionCenter",22,0.025f,&_lock); Real waveSeedingCurvatureThresholdRegionRadius = _args.getOpt<Real >("waveSeedingCurvatureThresholdRegionRadius",23,0.01f,&_lock); Real waveSeedStepSizeRatioOfMax = _args.getOpt<Real >("waveSeedStepSizeRatioOfMax",24,0.05f ,&_lock); _retval = getPyNone(); particleSurfaceTurbulence(flags,coarseParts,coarsePartsPrevPos,surfPoints,surfaceNormals,surfaceWaveH,surfaceWaveDtH,surfacePointsDisplaced,surfaceWaveSource,surfaceWaveSeed,surfaceWaveSeedAmplitude,res,outerRadius,surfaceDensity,nbSurfaceMaintenanceIterations,dt,waveSpeed,waveDamping,waveSeedFrequency,waveMaxAmplitude,waveMaxFrequency,waveMaxSeedingAmplitude,waveSeedingCurvatureThresholdRegionCenter,waveSeedingCurvatureThresholdRegionRadius,waveSeedStepSizeRatioOfMax); _args.check(); }
+ pbFinalizePlugin(parent,"particleSurfaceTurbulence", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("particleSurfaceTurbulence",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_particleSurfaceTurbulence ("","particleSurfaceTurbulence",_W_0);
+extern "C" {
+ void PbRegister_particleSurfaceTurbulence() {
+ KEEP_UNUSED(_RP_particleSurfaceTurbulence); }
+ }
+
+
+
+
+
+
+void debugCheckParts(const BasicParticleSystem& parts, const FlagGrid& flags) {
+ for(int idx=0;idx<parts.size();idx++) {
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if(! flags.isInBounds(p) ) {
+ debMsg("bad position??? "<<idx<<" "<< parts.getPos(idx) ,1 ); exit(1);
+ }
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "debugCheckParts" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); _retval = getPyNone(); debugCheckParts(parts,flags); _args.check(); }
+ pbFinalizePlugin(parent,"debugCheckParts", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("debugCheckParts",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_debugCheckParts ("","debugCheckParts",_W_1);
+extern "C" {
+ void PbRegister_debugCheckParts() {
+ KEEP_UNUSED(_RP_debugCheckParts); }
+ }
+
+
+
+
+
+
+} // namespace SurfaceTurbulence
+
+} // namespace Manta
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/vortexplugins.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/vortexplugins.cpp
new file mode 100644
index 00000000000..3111223d050
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/vortexplugins.cpp
@@ -0,0 +1,453 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for using vortex sheet meshes
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include "vortexsheet.h"
+#include "vortexpart.h"
+#include "shapes.h"
+#include "commonkernels.h"
+#include "conjugategrad.h"
+#include "randomstream.h"
+#include "levelset.h"
+
+using namespace std;
+
+namespace Manta {
+
+//! Mark area of mesh inside shape as fixed nodes.
+//! Remove all other fixed nodes if 'exclusive' is set
+
+void markAsFixed(Mesh& mesh, const Shape* shape, bool exclusive=true) {
+ for (int i=0; i<mesh.numNodes(); i++) {
+ if (shape->isInside(mesh.nodes(i).pos))
+ mesh.nodes(i).flags |= Mesh::NfFixed;
+ else if (exclusive)
+ mesh.nodes(i).flags &= ~Mesh::NfFixed;
+ }
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "markAsFixed" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); const Shape* shape = _args.getPtr<Shape >("shape",1,&_lock); bool exclusive = _args.getOpt<bool >("exclusive",2,true,&_lock); _retval = getPyNone(); markAsFixed(mesh,shape,exclusive); _args.check(); }
+ pbFinalizePlugin(parent,"markAsFixed", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("markAsFixed",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_markAsFixed ("","markAsFixed",_W_0);
+extern "C" {
+ void PbRegister_markAsFixed() {
+ KEEP_UNUSED(_RP_markAsFixed); }
+ }
+
+
+
+//! Adapt texture coordinates of mesh inside shape
+//! to obtain an effective inflow effect
+
+void texcoordInflow(VortexSheetMesh& mesh, const Shape* shape, const MACGrid& vel) {
+ static Vec3 t0 = Vec3::Zero;
+
+ // get mean velocity
+ int cnt=0;
+ Vec3 meanV(0.0);
+ FOR_IJK(vel) {
+ if (shape->isInsideGrid(i,j,k)) {
+ cnt++;
+ meanV += vel.getCentered(i,j,k);
+ }
+ }
+ meanV /= (Real) cnt;
+ t0 -= mesh.getParent()->getDt() * meanV;
+ mesh.setReferenceTexOffset(t0);
+
+ // apply mean velocity
+ for (int i=0; i<mesh.numNodes(); i++) {
+ if (shape->isInside(mesh.nodes(i).pos)) {
+ Vec3 tc = mesh.nodes(i).pos + t0;
+ mesh.tex1(i) = tc;
+ mesh.tex2(i) = tc;
+ }
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "texcoordInflow" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); const Shape* shape = _args.getPtr<Shape >("shape",1,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",2,&_lock); _retval = getPyNone(); texcoordInflow(mesh,shape,vel); _args.check(); }
+ pbFinalizePlugin(parent,"texcoordInflow", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("texcoordInflow",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_texcoordInflow ("","texcoordInflow",_W_1);
+extern "C" {
+ void PbRegister_texcoordInflow() {
+ KEEP_UNUSED(_RP_texcoordInflow); }
+ }
+
+;
+
+//! Init smoke density values of the mesh surface inside source shape
+
+void meshSmokeInflow(VortexSheetMesh& mesh, const Shape* shape, Real amount) {
+ for (int t=0; t<mesh.numTris(); t++) {
+ if (shape->isInside(mesh.getFaceCenter(t)))
+ mesh.sheet(t).smokeAmount = amount;
+ }
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "meshSmokeInflow" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); const Shape* shape = _args.getPtr<Shape >("shape",1,&_lock); Real amount = _args.get<Real >("amount",2,&_lock); _retval = getPyNone(); meshSmokeInflow(mesh,shape,amount); _args.check(); }
+ pbFinalizePlugin(parent,"meshSmokeInflow", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("meshSmokeInflow",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_meshSmokeInflow ("","meshSmokeInflow",_W_2);
+extern "C" {
+ void PbRegister_meshSmokeInflow() {
+ KEEP_UNUSED(_RP_meshSmokeInflow); }
+ }
+
+
+
+
+ struct KnAcceleration : public KernelBase {
+ KnAcceleration(MACGrid& a, const MACGrid& v1, const MACGrid& v0, const Real idt) : KernelBase(&a,0) ,a(a),v1(v1),v0(v0),idt(idt) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, MACGrid& a, const MACGrid& v1, const MACGrid& v0, const Real idt ) const {
+ a[idx] = (v1[idx]-v0[idx])*idt;
+} inline MACGrid& getArg0() {
+ return a; }
+ typedef MACGrid type0;inline const MACGrid& getArg1() {
+ return v1; }
+ typedef MACGrid type1;inline const MACGrid& getArg2() {
+ return v0; }
+ typedef MACGrid type2;inline const Real& getArg3() {
+ return idt; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel KnAcceleration ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, a,v1,v0,idt); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ MACGrid& a; const MACGrid& v1; const MACGrid& v0; const Real idt; }
+;
+
+//! Add vorticity to vortex sheets based on buoyancy
+
+
+
+void vorticitySource(VortexSheetMesh& mesh, Vec3 gravity, const MACGrid* vel=NULL, const MACGrid* velOld=NULL, Real scale = 0.1, Real maxAmount = 0, Real mult = 1.0) {
+ Real dt = mesh.getParent()->getDt();
+ Real dx = mesh.getParent()->getDx();
+ MACGrid acceleration(mesh.getParent());
+ if (vel)
+ KnAcceleration(acceleration, *vel, *velOld, 1.0/dt);
+ const Real A= -1.0;
+ Real maxV = 0, meanV = 0;
+
+ for (int t=0; t<mesh.numTris(); t++) {
+ Vec3 fn = mesh.getFaceNormal(t);
+ Vec3 source;
+ if (vel) {
+ Vec3 a = acceleration.getInterpolated(mesh.getFaceCenter(t));
+ source = A*cross(fn, a-gravity) * scale;
+ } else {
+ source = A*cross(fn, -gravity) * scale;
+ }
+
+ if (mesh.isTriangleFixed(t)) source = 0;
+
+ mesh.sheet(t).vorticity *= mult;
+ mesh.sheet(t).vorticity += dt * source / dx;
+ // upper limit
+ Real v = norm(mesh.sheet(t).vorticity);
+ if (maxAmount>0 && v > maxAmount)
+ mesh.sheet(t).vorticity *= maxAmount/v;
+
+ //stats
+ if (v > maxV) maxV = v;
+ meanV += v;
+ }
+
+ cout << "vorticity: max " << maxV << " / mean " << meanV/mesh.numTris() << endl;
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "vorticitySource" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); Vec3 gravity = _args.get<Vec3 >("gravity",1,&_lock); const MACGrid* vel = _args.getPtrOpt<MACGrid >("vel",2,NULL,&_lock); const MACGrid* velOld = _args.getPtrOpt<MACGrid >("velOld",3,NULL,&_lock); Real scale = _args.getOpt<Real >("scale",4,0.1,&_lock); Real maxAmount = _args.getOpt<Real >("maxAmount",5,0,&_lock); Real mult = _args.getOpt<Real >("mult",6,1.0,&_lock); _retval = getPyNone(); vorticitySource(mesh,gravity,vel,velOld,scale,maxAmount,mult); _args.check(); }
+ pbFinalizePlugin(parent,"vorticitySource", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("vorticitySource",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_vorticitySource ("","vorticitySource",_W_3);
+extern "C" {
+ void PbRegister_vorticitySource() {
+ KEEP_UNUSED(_RP_vorticitySource); }
+ }
+
+
+
+
+void smoothVorticity(VortexSheetMesh& mesh, int iter=1, Real sigma=0.2, Real alpha=0.8) {
+ const Real mult = -0.5 / sigma / sigma;
+
+ // pre-calculate positions and weights
+ vector<Vec3> vort(mesh.numTris()), pos(mesh.numTris());
+ vector<Real> weights(3*mesh.numTris());
+ vector<int> index(3*mesh.numTris());
+ for(int i=0; i<mesh.numTris(); i++) {
+ pos[i] = mesh.getFaceCenter(i);
+ mesh.sheet(i).vorticitySmoothed = mesh.sheet(i).vorticity;
+ }
+ for(int i=0; i<mesh.numTris(); i++) {
+ for (int c=0; c<3; c++) {
+ int oc = mesh.corners(i,c).opposite;
+ if (oc>=0) {
+ int t = mesh.corners(oc).tri;
+ weights[3*i+c] = exp(normSquare(pos[t]-pos[i])*mult);
+ index[3*i+c] = t;
+ }
+ else {
+ weights[3*i+c] = 0;
+ index[3*i+c] = 0;
+ }
+ }
+ }
+
+ for (int it=0; it<iter; ++it) {
+ // first, preload
+ for(int i=0; i<mesh.numTris(); i++) vort[i] = mesh.sheet(i).vorticitySmoothed;
+
+ for(int i=0,idx=0; i<mesh.numTris(); i++) {
+ // loop over adjacent tris
+ Real sum=1.0f;
+ Vec3 v=vort[i];
+ for (int c=0;c<3;c++,idx++) {
+ Real w = weights[index[idx]];
+ v += w*vort[index[idx]];
+ sum += w;
+ }
+ mesh.sheet(i).vorticitySmoothed = v/sum;
+ }
+ }
+ for(int i=0; i<mesh.numTris(); i++) mesh.sheet(i).vorticitySmoothed *= alpha;
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "smoothVorticity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); int iter = _args.getOpt<int >("iter",1,1,&_lock); Real sigma = _args.getOpt<Real >("sigma",2,0.2,&_lock); Real alpha = _args.getOpt<Real >("alpha",3,0.8,&_lock); _retval = getPyNone(); smoothVorticity(mesh,iter,sigma,alpha); _args.check(); }
+ pbFinalizePlugin(parent,"smoothVorticity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("smoothVorticity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_smoothVorticity ("","smoothVorticity",_W_4);
+extern "C" {
+ void PbRegister_smoothVorticity() {
+ KEEP_UNUSED(_RP_smoothVorticity); }
+ }
+
+
+
+//! Seed Vortex Particles inside shape with K41 characteristics
+void VPseedK41(VortexParticleSystem& system, const Shape* shape, Real strength=0, Real sigma0=0.2, Real sigma1=1.0, Real probability=1.0, Real N=3.0) {
+ Grid<Real> temp(system.getParent());
+ const Real dt = system.getParent()->getDt();
+ static RandomStream rand(3489572);
+ Real s0 = pow( (Real)sigma0, (Real)(-N+1.0) );
+ Real s1 = pow( (Real)sigma1, (Real)(-N+1.0) );
+
+ FOR_IJK(temp) {
+ if (shape->isInsideGrid(i,j,k)) {
+ if (rand.getReal() < probability*dt) {
+ Real p = rand.getReal();
+ Real sigma = pow( (1.0-p)*s0 + p*s1, 1./(-N+1.0) );
+ Vec3 randDir (rand.getReal(), rand.getReal(), rand.getReal());
+ Vec3 posUpd (i+rand.getReal(), j+rand.getReal(), k+rand.getReal());
+ normalize(randDir);
+ Vec3 vorticity = randDir * strength * pow( (Real)sigma, (Real)(-10./6.+N/2.0) );
+ system.add(VortexParticleData(posUpd, vorticity, sigma));
+ }
+ }
+ }
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "VPseedK41" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexParticleSystem& system = *_args.getPtr<VortexParticleSystem >("system",0,&_lock); const Shape* shape = _args.getPtr<Shape >("shape",1,&_lock); Real strength = _args.getOpt<Real >("strength",2,0,&_lock); Real sigma0 = _args.getOpt<Real >("sigma0",3,0.2,&_lock); Real sigma1 = _args.getOpt<Real >("sigma1",4,1.0,&_lock); Real probability = _args.getOpt<Real >("probability",5,1.0,&_lock); Real N = _args.getOpt<Real >("N",6,3.0,&_lock); _retval = getPyNone(); VPseedK41(system,shape,strength,sigma0,sigma1,probability,N); _args.check(); }
+ pbFinalizePlugin(parent,"VPseedK41", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VPseedK41",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_VPseedK41 ("","VPseedK41",_W_5);
+extern "C" {
+ void PbRegister_VPseedK41() {
+ KEEP_UNUSED(_RP_VPseedK41); }
+ }
+
+
+
+//! Vortex-in-cell integration
+
+void VICintegration(VortexSheetMesh& mesh, Real sigma, Grid<Vec3>& vel, const FlagGrid& flags, Grid<Vec3>* vorticity=NULL, Real cgMaxIterFac=1.5, Real cgAccuracy=1e-3, Real scale = 0.01, int precondition=0) {
+
+ MuTime t0;
+ const Real fac = 16.0; // experimental factor to balance out regularization
+
+ // if no vort grid is given, use a temporary one
+ Grid<Vec3> vortTemp(mesh.getParent());
+ Grid<Vec3>& vort = (vorticity) ? (*vorticity) : (vortTemp);
+ vort.clear();
+
+ // map vorticity to grid using Peskin kernel
+ int sgi = ceil(sigma);
+ Real pkfac=M_PI/sigma;
+ const int numTris = mesh.numTris();
+ for (int t=0; t<numTris; t++) {
+ Vec3 pos = mesh.getFaceCenter(t);
+ Vec3 v = mesh.sheet(t).vorticity * mesh.getFaceArea(t) * fac;
+
+ // inner kernel
+ // first, summate
+ Real sum=0;
+ for (int i=-sgi; i<sgi; i++) {
+ if (pos.x+i < 0 || (int)pos.x+i >= vort.getSizeX()) continue;
+ for (int j=-sgi; j<sgi; j++) {
+ if (pos.y+j < 0 || (int)pos.y+j >= vort.getSizeY()) continue;
+ for (int k=-sgi; k<sgi; k++) {
+ if (pos.z+k < 0 || (int)pos.z+k >= vort.getSizeZ()) continue;
+ Vec3i cell(pos.x+i, pos.y+j, pos.z+k);
+ if (!flags.isFluid(cell)) continue;
+ Vec3 d = pos - Vec3(i+0.5+floor(pos.x), j+0.5+floor(pos.y), k+0.5+floor(pos.z));
+ Real dl = norm(d);
+ if (dl > sigma) continue;
+ // precalc Peskin kernel
+ sum += 1.0 + cos(dl * pkfac);
+ }
+ }
+ }
+ // then, apply normalized kernel
+ Real wnorm = 1.0/sum;
+ for (int i=-sgi; i<sgi; i++) {
+ if (pos.x+i < 0 || (int)pos.x+i >= vort.getSizeX()) continue;
+ for (int j=-sgi; j<sgi; j++) {
+ if (pos.y+j < 0 || (int)pos.y+j >= vort.getSizeY()) continue;
+ for (int k=-sgi; k<sgi; k++) {
+ if (pos.z+k < 0 || (int)pos.z+k >= vort.getSizeZ()) continue;
+ Vec3i cell(pos.x+i, pos.y+j, pos.z+k);
+ if (!flags.isFluid(cell)) continue;
+ Vec3 d = pos - Vec3(i+0.5+floor(pos.x), j+0.5+floor(pos.y), k+0.5+floor(pos.z));
+ Real dl = norm(d);
+ if (dl > sigma) continue;
+ Real w = (1.0 + cos(dl * pkfac))*wnorm;
+ vort(cell) += v * w;
+ }
+ }
+ }
+ }
+
+ // Prepare grids for poisson solve
+ Grid<Vec3> vortexCurl(mesh.getParent());
+ Grid<Real> rhs(mesh.getParent());
+ Grid<Real> solution(mesh.getParent());
+ Grid<Real> residual(mesh.getParent());
+ Grid<Real> search(mesh.getParent());
+ Grid<Real> temp1(mesh.getParent());
+ Grid<Real> A0(mesh.getParent());
+ Grid<Real> Ai(mesh.getParent());
+ Grid<Real> Aj(mesh.getParent());
+ Grid<Real> Ak(mesh.getParent());
+ Grid<Real> pca0(mesh.getParent());
+ Grid<Real> pca1(mesh.getParent());
+ Grid<Real> pca2(mesh.getParent());
+ Grid<Real> pca3(mesh.getParent());
+
+ MakeLaplaceMatrix (flags, A0, Ai, Aj, Ak);
+ CurlOp(vort, vortexCurl);
+
+ // Solve vector poisson equation
+ for (int c=0; c<3; c++) {
+ // construct rhs
+ if (vel.getType() & GridBase::TypeMAC)
+ GetShiftedComponent(vortexCurl, rhs, c);
+ else
+ GetComponent(vortexCurl, rhs, c);
+
+ // prepare CG solver
+ const int maxIter = (int)(cgMaxIterFac * vel.getSize().max());
+ GridCgInterface *gcg = new GridCg<ApplyMatrix>(solution, rhs, residual, search, flags, temp1, &A0, &Ai, &Aj, &Ak );
+ gcg->setAccuracy(cgAccuracy);
+ gcg->setUseL2Norm(true);
+ gcg->setICPreconditioner( (GridCgInterface::PreconditionType)precondition, &pca0, &pca1, &pca2, &pca3);
+
+ // iterations
+ for (int iter=0; iter<maxIter; iter++) {
+ if (!gcg->iterate()) iter=maxIter;
+ }
+ debMsg("VICintegration CG iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma(), 1);
+ delete gcg;
+
+ // copy back
+ solution *= scale;
+ SetComponent(vel, solution, c);
+ }
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "VICintegration" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); Real sigma = _args.get<Real >("sigma",1,&_lock); Grid<Vec3>& vel = *_args.getPtr<Grid<Vec3> >("vel",2,&_lock); const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",3,&_lock); Grid<Vec3>* vorticity = _args.getPtrOpt<Grid<Vec3> >("vorticity",4,NULL,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",5,1.5,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",6,1e-3,&_lock); Real scale = _args.getOpt<Real >("scale",7,0.01,&_lock); int precondition = _args.getOpt<int >("precondition",8,0,&_lock); _retval = getPyNone(); VICintegration(mesh,sigma,vel,flags,vorticity,cgMaxIterFac,cgAccuracy,scale,precondition); _args.check(); }
+ pbFinalizePlugin(parent,"VICintegration", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VICintegration",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_VICintegration ("","VICintegration",_W_6);
+extern "C" {
+ void PbRegister_VICintegration() {
+ KEEP_UNUSED(_RP_VICintegration); }
+ }
+
+
+
+//! Obtain density field from levelset with linear gradient of size sigma over the interface
+void densityFromLevelset(const LevelsetGrid& phi, Grid<Real>& density, Real value=1.0, Real sigma=1.0) {
+ FOR_IJK(phi) {
+ // remove boundary
+ if (i<2 || j<2 || k<2 || i>=phi.getSizeX()-2 || j>=phi.getSizeY()-2 || k>=phi.getSizeZ()-2)
+ density(i,j,k) = 0;
+ else if (phi(i,j,k) < -sigma)
+ density(i,j,k) = value;
+ else if (phi(i,j,k) > sigma)
+ density(i,j,k) = 0;
+ else
+ density(i,j,k) = clamp((Real)(0.5*value/sigma*(1.0-phi(i,j,k))), (Real)0.0, value);
+ }
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "densityFromLevelset" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); Real value = _args.getOpt<Real >("value",2,1.0,&_lock); Real sigma = _args.getOpt<Real >("sigma",3,1.0,&_lock); _retval = getPyNone(); densityFromLevelset(phi,density,value,sigma); _args.check(); }
+ pbFinalizePlugin(parent,"densityFromLevelset", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("densityFromLevelset",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_densityFromLevelset ("","densityFromLevelset",_W_7);
+extern "C" {
+ void PbRegister_densityFromLevelset() {
+ KEEP_UNUSED(_RP_densityFromLevelset); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/waveletturbulence.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/waveletturbulence.cpp
new file mode 100644
index 00000000000..81839c8cc23
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/waveletturbulence.cpp
@@ -0,0 +1,631 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Functions for calculating wavelet turbulence,
+ * plus helpers to compute vorticity, and strain rate magnitude
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "shapes.h"
+#include "commonkernels.h"
+#include "noisefield.h"
+
+using namespace std;
+
+namespace Manta {
+
+//*****************************************************************************
+
+// first some fairly generic interpolation functions for grids with multiple sizes
+
+//! same as in grid.h , but takes an additional optional "desired" size
+inline void calcGridSizeFactorMod(Vec3i s1, Vec3i s2, Vec3i optSize, Vec3 scale, Vec3& sourceFactor, Vec3& retOff ) {
+ for(int c=0; c<3; c++) {
+ if(optSize[c] > 0){ s2[c] = optSize[c]; }
+ }
+ sourceFactor = calcGridSizeFactor(s1,s2) / scale;
+ retOff = -retOff * sourceFactor + sourceFactor*0.5;
+}
+
+
+void interpolateGrid( Grid<Real>& target, const Grid<Real>& source , Vec3 scale=Vec3(1.), Vec3 offset=Vec3(0.), Vec3i size=Vec3i(-1,-1,-1) , int orderSpace=1 ) {
+ Vec3 sourceFactor(1.), off2 = offset;
+ calcGridSizeFactorMod(source.getSize(), target.getSize(), size, scale, sourceFactor, off2);
+
+ // a brief note on a mantaflow specialty: the target grid has to be the first argument here!
+ // the parent fluidsolver object is taken from the first grid, and it determines the size of the
+ // loop for the kernel call. as we're writing into target, it's important to loop exactly over
+ // all cells of the target grid... (note, when calling the plugin in python, it doesnt matter anymore).
+
+ // sourceFactor offset necessary to shift eval points by half a small cell width
+ knInterpolateGridTempl<Real>(target, source, sourceFactor, off2, orderSpace);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "interpolateGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",0,&_lock); const Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",1,&_lock); Vec3 scale = _args.getOpt<Vec3 >("scale",2,Vec3(1.),&_lock); Vec3 offset = _args.getOpt<Vec3 >("offset",3,Vec3(0.),&_lock); Vec3i size = _args.getOpt<Vec3i >("size",4,Vec3i(-1,-1,-1) ,&_lock); int orderSpace = _args.getOpt<int >("orderSpace",5,1 ,&_lock); _retval = getPyNone(); interpolateGrid(target,source,scale,offset,size,orderSpace); _args.check(); }
+ pbFinalizePlugin(parent,"interpolateGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("interpolateGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_interpolateGrid ("","interpolateGrid",_W_0);
+extern "C" {
+ void PbRegister_interpolateGrid() {
+ KEEP_UNUSED(_RP_interpolateGrid); }
+ }
+
+
+
+
+void interpolateGridVec3( Grid<Vec3>& target, const Grid<Vec3>& source , Vec3 scale=Vec3(1.), Vec3 offset=Vec3(0.), Vec3i size=Vec3i(-1,-1,-1) , int orderSpace=1 ) {
+ Vec3 sourceFactor(1.), off2 = offset;
+ calcGridSizeFactorMod(source.getSize(), target.getSize(), size, scale, sourceFactor, off2);
+ knInterpolateGridTempl<Vec3>(target, source, sourceFactor, off2, orderSpace);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "interpolateGridVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",0,&_lock); const Grid<Vec3>& source = *_args.getPtr<Grid<Vec3> >("source",1,&_lock); Vec3 scale = _args.getOpt<Vec3 >("scale",2,Vec3(1.),&_lock); Vec3 offset = _args.getOpt<Vec3 >("offset",3,Vec3(0.),&_lock); Vec3i size = _args.getOpt<Vec3i >("size",4,Vec3i(-1,-1,-1) ,&_lock); int orderSpace = _args.getOpt<int >("orderSpace",5,1 ,&_lock); _retval = getPyNone(); interpolateGridVec3(target,source,scale,offset,size,orderSpace); _args.check(); }
+ pbFinalizePlugin(parent,"interpolateGridVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("interpolateGridVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_interpolateGridVec3 ("","interpolateGridVec3",_W_1);
+extern "C" {
+ void PbRegister_interpolateGridVec3() {
+ KEEP_UNUSED(_RP_interpolateGridVec3); }
+ }
+
+
+
+
+//!interpolate a mac velocity grid from one size to another size
+
+
+ struct KnInterpolateMACGrid : public KernelBase {
+ KnInterpolateMACGrid(MACGrid& target, const MACGrid& source, const Vec3& sourceFactor, const Vec3& off, int orderSpace) : KernelBase(&target,0) ,target(target),source(source),sourceFactor(sourceFactor),off(off),orderSpace(orderSpace) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid& target, const MACGrid& source, const Vec3& sourceFactor, const Vec3& off, int orderSpace ) const {
+ Vec3 pos = Vec3(i,j,k) * sourceFactor + off;
+
+ Real vx = source.getInterpolatedHi(pos - Vec3(0.5,0,0), orderSpace)[0];
+ Real vy = source.getInterpolatedHi(pos - Vec3(0,0.5,0), orderSpace)[1];
+ Real vz = 0.f;
+ if(source.is3D()) vz = source.getInterpolatedHi(pos - Vec3(0,0,0.5), orderSpace)[2];
+
+ target(i,j,k) = Vec3(vx,vy,vz);
+} inline MACGrid& getArg0() {
+ return target; }
+ typedef MACGrid type0;inline const MACGrid& getArg1() {
+ return source; }
+ typedef MACGrid type1;inline const Vec3& getArg2() {
+ return sourceFactor; }
+ typedef Vec3 type2;inline const Vec3& getArg3() {
+ return off; }
+ typedef Vec3 type3;inline int& getArg4() {
+ return orderSpace; }
+ typedef int type4; void runMessage() { debMsg("Executing kernel KnInterpolateMACGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,target,source,sourceFactor,off,orderSpace); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,target,source,sourceFactor,off,orderSpace); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ MACGrid& target; const MACGrid& source; const Vec3& sourceFactor; const Vec3& off; int orderSpace; }
+;
+
+
+void interpolateMACGrid(MACGrid& target, const MACGrid& source, Vec3 scale=Vec3(1.), Vec3 offset=Vec3(0.), Vec3i size=Vec3i(-1,-1,-1) , int orderSpace=1) {
+ Vec3 sourceFactor(1.), off2 = offset;
+ calcGridSizeFactorMod(source.getSize(), target.getSize(), size, scale, sourceFactor, off2);
+ KnInterpolateMACGrid(target, source, sourceFactor, off2, orderSpace);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "interpolateMACGrid" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; MACGrid& target = *_args.getPtr<MACGrid >("target",0,&_lock); const MACGrid& source = *_args.getPtr<MACGrid >("source",1,&_lock); Vec3 scale = _args.getOpt<Vec3 >("scale",2,Vec3(1.),&_lock); Vec3 offset = _args.getOpt<Vec3 >("offset",3,Vec3(0.),&_lock); Vec3i size = _args.getOpt<Vec3i >("size",4,Vec3i(-1,-1,-1) ,&_lock); int orderSpace = _args.getOpt<int >("orderSpace",5,1,&_lock); _retval = getPyNone(); interpolateMACGrid(target,source,scale,offset,size,orderSpace); _args.check(); }
+ pbFinalizePlugin(parent,"interpolateMACGrid", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("interpolateMACGrid",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_interpolateMACGrid ("","interpolateMACGrid",_W_2);
+extern "C" {
+ void PbRegister_interpolateMACGrid() {
+ KEEP_UNUSED(_RP_interpolateMACGrid); }
+ }
+
+
+
+
+
+//*****************************************************************************
+
+//! Apply vector noise to grid, this is a simplified version - no position scaling or UVs
+
+
+
+ struct knApplySimpleNoiseVec3 : public KernelBase {
+ knApplySimpleNoiseVec3(const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale, const Grid<Real>* weight ) : KernelBase(&flags,0) ,flags(flags),target(target),noise(noise),scale(scale),weight(weight) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale, const Grid<Real>* weight ) const {
+ if ( !flags.isFluid(i,j,k) ) return;
+ Real factor = 1;
+ if(weight) factor = (*weight)(i,j,k);
+ target(i,j,k) += noise.evaluateCurl( Vec3(i,j,k)+Vec3(0.5) ) * scale * factor;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Vec3>& getArg1() {
+ return target; }
+ typedef Grid<Vec3> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Real& getArg3() {
+ return scale; }
+ typedef Real type3;inline const Grid<Real>* getArg4() {
+ return weight; }
+ typedef Grid<Real> type4; void runMessage() { debMsg("Executing kernel knApplySimpleNoiseVec3 ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,target,noise,scale,weight); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,target,noise,scale,weight); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; Grid<Vec3>& target; const WaveletNoiseField& noise; Real scale; const Grid<Real>* weight; }
+;
+
+
+void applySimpleNoiseVec3(const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale=1.0 , const Grid<Real>* weight=NULL ) {
+ // note - passing a MAC grid here is slightly inaccurate, we should evaluate each component separately
+ knApplySimpleNoiseVec3(flags, target, noise, scale , weight );
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "applySimpleNoiseVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.0 ,&_lock); const Grid<Real>* weight = _args.getPtrOpt<Grid<Real> >("weight",4,NULL ,&_lock); _retval = getPyNone(); applySimpleNoiseVec3(flags,target,noise,scale,weight); _args.check(); }
+ pbFinalizePlugin(parent,"applySimpleNoiseVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("applySimpleNoiseVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_applySimpleNoiseVec3 ("","applySimpleNoiseVec3",_W_3);
+extern "C" {
+ void PbRegister_applySimpleNoiseVec3() {
+ KEEP_UNUSED(_RP_applySimpleNoiseVec3); }
+ }
+
+
+
+
+//! Simple noise for a real grid , follows applySimpleNoiseVec3
+
+
+
+ struct knApplySimpleNoiseReal : public KernelBase {
+ knApplySimpleNoiseReal(const FlagGrid& flags, Grid<Real>& target, const WaveletNoiseField& noise, Real scale, const Grid<Real>* weight ) : KernelBase(&flags,0) ,flags(flags),target(target),noise(noise),scale(scale),weight(weight) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& target, const WaveletNoiseField& noise, Real scale, const Grid<Real>* weight ) const {
+ if ( !flags.isFluid(i,j,k) ) return;
+ Real factor = 1;
+ if(weight) factor = (*weight)(i,j,k);
+ target(i,j,k) += noise.evaluate( Vec3(i,j,k)+Vec3(0.5) ) * scale * factor;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return target; }
+ typedef Grid<Real> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Real& getArg3() {
+ return scale; }
+ typedef Real type3;inline const Grid<Real>* getArg4() {
+ return weight; }
+ typedef Grid<Real> type4; void runMessage() { debMsg("Executing kernel knApplySimpleNoiseReal ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,target,noise,scale,weight); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,target,noise,scale,weight); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; Grid<Real>& target; const WaveletNoiseField& noise; Real scale; const Grid<Real>* weight; }
+;
+
+
+void applySimpleNoiseReal(const FlagGrid& flags, Grid<Real>& target, const WaveletNoiseField& noise, Real scale=1.0 , const Grid<Real>* weight=NULL ) {
+ knApplySimpleNoiseReal(flags, target, noise, scale , weight );
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "applySimpleNoiseReal" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.0 ,&_lock); const Grid<Real>* weight = _args.getPtrOpt<Grid<Real> >("weight",4,NULL ,&_lock); _retval = getPyNone(); applySimpleNoiseReal(flags,target,noise,scale,weight); _args.check(); }
+ pbFinalizePlugin(parent,"applySimpleNoiseReal", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("applySimpleNoiseReal",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_applySimpleNoiseReal ("","applySimpleNoiseReal",_W_4);
+extern "C" {
+ void PbRegister_applySimpleNoiseReal() {
+ KEEP_UNUSED(_RP_applySimpleNoiseReal); }
+ }
+
+
+
+
+
+//! Apply vector-based wavelet noise to target grid
+//! This is the version with more functionality - supports uv grids, and on-the-fly interpolation
+//! of input grids.
+
+
+
+ struct knApplyNoiseVec3 : public KernelBase {
+ knApplyNoiseVec3(const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale, Real scaleSpatial, const Grid<Real>* weight, const Grid<Vec3>* uv, bool uvInterpol, const Vec3& sourceFactor ) : KernelBase(&flags,0) ,flags(flags),target(target),noise(noise),scale(scale),scaleSpatial(scaleSpatial),weight(weight),uv(uv),uvInterpol(uvInterpol),sourceFactor(sourceFactor) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale, Real scaleSpatial, const Grid<Real>* weight, const Grid<Vec3>* uv, bool uvInterpol, const Vec3& sourceFactor ) const {
+ if ( !flags.isFluid(i,j,k) ) return;
+
+ // get weighting, interpolate if necessary
+ Real w = 1;
+ if(weight) {
+ if(!uvInterpol) {
+ w = (*weight)(i,j,k);
+ } else {
+ w = weight->getInterpolated( Vec3(i,j,k) * sourceFactor );
+ }
+ }
+
+ // compute position where to evaluate the noise
+ Vec3 pos = Vec3(i,j,k)+Vec3(0.5);
+ if(uv) {
+ if(!uvInterpol) {
+ pos = (*uv)(i,j,k);
+ } else {
+ pos = uv->getInterpolated( Vec3(i,j,k) * sourceFactor );
+ // uv coordinates are in local space - so we need to adjust the values of the positions
+ pos /= sourceFactor;
+ }
+ }
+ pos *= scaleSpatial;
+
+ Vec3 noiseVec3 = noise.evaluateCurl( pos ) * scale * w;
+ //noiseVec3=pos; // debug , show interpolated positions
+ target(i,j,k) += noiseVec3;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Vec3>& getArg1() {
+ return target; }
+ typedef Grid<Vec3> type1;inline const WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Real& getArg3() {
+ return scale; }
+ typedef Real type3;inline Real& getArg4() {
+ return scaleSpatial; }
+ typedef Real type4;inline const Grid<Real>* getArg5() {
+ return weight; }
+ typedef Grid<Real> type5;inline const Grid<Vec3>* getArg6() {
+ return uv; }
+ typedef Grid<Vec3> type6;inline bool& getArg7() {
+ return uvInterpol; }
+ typedef bool type7;inline const Vec3& getArg8() {
+ return sourceFactor; }
+ typedef Vec3 type8; void runMessage() { debMsg("Executing kernel knApplyNoiseVec3 ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,target,noise,scale,scaleSpatial,weight,uv,uvInterpol,sourceFactor); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,target,noise,scale,scaleSpatial,weight,uv,uvInterpol,sourceFactor); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; Grid<Vec3>& target; const WaveletNoiseField& noise; Real scale; Real scaleSpatial; const Grid<Real>* weight; const Grid<Vec3>* uv; bool uvInterpol; const Vec3& sourceFactor; }
+;
+
+
+void applyNoiseVec3(const FlagGrid& flags, Grid<Vec3>& target, const WaveletNoiseField& noise, Real scale=1.0 , Real scaleSpatial=1.0 , const Grid<Real>* weight=NULL , const Grid<Vec3>* uv=NULL ) {
+ // check whether the uv grid has a different resolution
+ bool uvInterpol = false;
+ // and pre-compute conversion (only used if uvInterpol==true)
+ // used for both uv and weight grid...
+ Vec3 sourceFactor = Vec3(1.);
+ if(uv) {
+ uvInterpol = (target.getSize() != uv->getSize());
+ sourceFactor = calcGridSizeFactor( uv->getSize(), target.getSize() );
+ } else if(weight) {
+ uvInterpol = (target.getSize() != weight->getSize());
+ sourceFactor = calcGridSizeFactor( weight->getSize(), target.getSize() );
+ }
+ if(uv && weight) assertMsg( uv->getSize() == weight->getSize(), "UV and weight grid have to match!");
+
+ // note - passing a MAC grid here is slightly inaccurate, we should evaluate each component separately
+ knApplyNoiseVec3(flags, target, noise, scale, scaleSpatial, weight , uv,uvInterpol,sourceFactor );
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "applyNoiseVec3" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); const WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.0 ,&_lock); Real scaleSpatial = _args.getOpt<Real >("scaleSpatial",4,1.0 ,&_lock); const Grid<Real>* weight = _args.getPtrOpt<Grid<Real> >("weight",5,NULL ,&_lock); const Grid<Vec3>* uv = _args.getPtrOpt<Grid<Vec3> >("uv",6,NULL ,&_lock); _retval = getPyNone(); applyNoiseVec3(flags,target,noise,scale,scaleSpatial,weight,uv); _args.check(); }
+ pbFinalizePlugin(parent,"applyNoiseVec3", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("applyNoiseVec3",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_applyNoiseVec3 ("","applyNoiseVec3",_W_5);
+extern "C" {
+ void PbRegister_applyNoiseVec3() {
+ KEEP_UNUSED(_RP_applyNoiseVec3); }
+ }
+
+
+
+
+
+//! Compute energy of a staggered velocity field (at cell center)
+
+
+ struct KnApplyComputeEnergy : public KernelBase {
+ KnApplyComputeEnergy( const FlagGrid& flags, const MACGrid& vel, Grid<Real>& energy ) : KernelBase(&flags,0) ,flags(flags),vel(vel),energy(energy) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, const MACGrid& vel, Grid<Real>& energy ) const {
+ Real e = 0.f;
+ if ( flags.isFluid(i,j,k) ) {
+ Vec3 v = vel.getCentered(i,j,k);
+ e = 0.5 * (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+ }
+ energy(i,j,k) = e;
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline const MACGrid& getArg1() {
+ return vel; }
+ typedef MACGrid type1;inline Grid<Real>& getArg2() {
+ return energy; }
+ typedef Grid<Real> type2; void runMessage() { debMsg("Executing kernel KnApplyComputeEnergy ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,vel,energy); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,flags,vel,energy); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const FlagGrid& flags; const MACGrid& vel; Grid<Real>& energy; }
+;
+
+
+void computeEnergy( const FlagGrid& flags, const MACGrid& vel, Grid<Real>& energy ) {
+ KnApplyComputeEnergy( flags, vel, energy );
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "computeEnergy" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); const MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); Grid<Real>& energy = *_args.getPtr<Grid<Real> >("energy",2,&_lock); _retval = getPyNone(); computeEnergy(flags,vel,energy); _args.check(); }
+ pbFinalizePlugin(parent,"computeEnergy", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("computeEnergy",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_computeEnergy ("","computeEnergy",_W_6);
+extern "C" {
+ void PbRegister_computeEnergy() {
+ KEEP_UNUSED(_RP_computeEnergy); }
+ }
+
+
+
+
+
+void computeWaveletCoeffs(Grid<Real>& input) {
+ Grid<Real> temp1(input.getParent()), temp2(input.getParent());
+ WaveletNoiseField::computeCoefficients(input, temp1, temp2);
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "computeWaveletCoeffs" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& input = *_args.getPtr<Grid<Real> >("input",0,&_lock); _retval = getPyNone(); computeWaveletCoeffs(input); _args.check(); }
+ pbFinalizePlugin(parent,"computeWaveletCoeffs", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("computeWaveletCoeffs",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_computeWaveletCoeffs ("","computeWaveletCoeffs",_W_7);
+extern "C" {
+ void PbRegister_computeWaveletCoeffs() {
+ KEEP_UNUSED(_RP_computeWaveletCoeffs); }
+ }
+
+
+
+// note - alomst the same as for vorticity confinement
+void computeVorticity(const MACGrid& vel, Grid<Vec3>& vorticity, Grid<Real>* norm=NULL) {
+ Grid<Vec3> velCenter(vel.getParent());
+ GetCentered(velCenter, vel);
+ CurlOp(velCenter, vorticity);
+ if(norm) GridNorm( *norm, vorticity);
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "computeVorticity" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Vec3>& vorticity = *_args.getPtr<Grid<Vec3> >("vorticity",1,&_lock); Grid<Real>* norm = _args.getPtrOpt<Grid<Real> >("norm",2,NULL,&_lock); _retval = getPyNone(); computeVorticity(vel,vorticity,norm); _args.check(); }
+ pbFinalizePlugin(parent,"computeVorticity", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("computeVorticity",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_computeVorticity ("","computeVorticity",_W_8);
+extern "C" {
+ void PbRegister_computeVorticity() {
+ KEEP_UNUSED(_RP_computeVorticity); }
+ }
+
+
+
+// note - very similar to KnComputeProductionStrain, but for use as wavelet turb weighting
+
+
+ struct KnComputeStrainRateMag : public KernelBase {
+ KnComputeStrainRateMag(const MACGrid& vel, const Grid<Vec3>& velCenter, Grid<Real>& prod ) : KernelBase(&vel,1) ,vel(vel),velCenter(velCenter),prod(prod) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const MACGrid& vel, const Grid<Vec3>& velCenter, Grid<Real>& prod ) const {
+ // compute Sij = 1/2 * (dU_i/dx_j + dU_j/dx_i)
+ Vec3 diag = Vec3(vel(i+1,j,k).x, vel(i,j+1,k).y, 0. ) - vel(i,j,k);
+ if(vel.is3D()) diag[2] += vel(i,j,k+1).z;
+ else diag[2] = 0.;
+
+ Vec3 ux = 0.5*(velCenter(i+1,j,k)-velCenter(i-1,j,k));
+ Vec3 uy = 0.5*(velCenter(i,j+1,k)-velCenter(i,j-1,k));
+ Vec3 uz;
+ if(vel.is3D()) uz=0.5*(velCenter(i,j,k+1)-velCenter(i,j,k-1));
+
+ Real S12 = 0.5*(ux.y+uy.x);
+ Real S13 = 0.5*(ux.z+uz.x);
+ Real S23 = 0.5*(uy.z+uz.y);
+ Real S2 = square(diag.x) + square(diag.y) + square(diag.z) +
+ 2.0*square(S12) + 2.0*square(S13) + 2.0*square(S23);
+ prod(i,j,k) = S2;
+} inline const MACGrid& getArg0() {
+ return vel; }
+ typedef MACGrid type0;inline const Grid<Vec3>& getArg1() {
+ return velCenter; }
+ typedef Grid<Vec3> type1;inline Grid<Real>& getArg2() {
+ return prod; }
+ typedef Grid<Real> type2; void runMessage() { debMsg("Executing kernel KnComputeStrainRateMag ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,velCenter,prod); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,vel,velCenter,prod); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const MACGrid& vel; const Grid<Vec3>& velCenter; Grid<Real>& prod; }
+;
+void computeStrainRateMag(const MACGrid& vel, Grid<Real>& mag) {
+ Grid<Vec3> velCenter(vel.getParent());
+ GetCentered(velCenter, vel);
+ KnComputeStrainRateMag(vel, velCenter, mag);
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "computeStrainRateMag" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Real>& mag = *_args.getPtr<Grid<Real> >("mag",1,&_lock); _retval = getPyNone(); computeStrainRateMag(vel,mag); _args.check(); }
+ pbFinalizePlugin(parent,"computeStrainRateMag", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("computeStrainRateMag",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_computeStrainRateMag ("","computeStrainRateMag",_W_9);
+extern "C" {
+ void PbRegister_computeStrainRateMag() {
+ KEEP_UNUSED(_RP_computeStrainRateMag); }
+ }
+
+
+
+
+// extrapolate a real grid into a flagged region (based on initial flags)
+// by default extrapolates from fluid to obstacle cells
+template<class T>
+void extrapolSimpleFlagsHelper (const FlagGrid& flags, Grid<T>& val, int distance = 4,
+ int flagFrom=FlagGrid::TypeFluid, int flagTo=FlagGrid::TypeObstacle )
+{
+ Grid<int> tmp( flags.getParent() );
+ int dim = (flags.is3D() ? 3:2);
+ const Vec3i nb[6] = {
+ Vec3i(1 ,0,0), Vec3i(-1,0,0),
+ Vec3i(0,1 ,0), Vec3i(0,-1,0),
+ Vec3i(0,0,1 ), Vec3i(0,0,-1) };
+
+ // remove all fluid cells (set to 1)
+ tmp.clear();
+ bool foundTarget = false;
+ FOR_IJK_BND(flags,0) {
+ if (flags(i,j,k) & flagFrom)
+ tmp( Vec3i(i,j,k) ) = 1;
+ if (!foundTarget && (flags(i,j,k) & flagTo)) foundTarget=true;
+ }
+ // optimization, skip extrapolation if we dont have any cells to extrapolate to
+ if(!foundTarget) {
+ debMsg("No target cells found, skipping extrapolation", 1);
+ return;
+ }
+
+ // extrapolate for given distance
+ for(int d=1; d<1+distance; ++d) {
+
+ // TODO, parallelize
+ FOR_IJK_BND(flags,1) {
+ if (tmp(i,j,k) != 0) continue;
+ if (!(flags(i,j,k) & flagTo)) continue;
+
+ // copy from initialized neighbors
+ Vec3i p(i,j,k);
+ int nbs = 0;
+ T avgVal = 0.;
+ for (int n=0; n<2*dim; ++n) {
+ if (tmp(p+nb[n]) == d) {
+ avgVal += val(p+nb[n]);
+ nbs++;
+ }
+ }
+
+ if(nbs>0) {
+ tmp(p) = d+1;
+ val(p) = avgVal / nbs;
+ }
+ }
+
+ } // distance
+}
+
+
+void extrapolateSimpleFlags(const FlagGrid& flags, GridBase* val, int distance = 4, int flagFrom=FlagGrid::TypeFluid, int flagTo=FlagGrid::TypeObstacle ) {
+ if (val->getType() & GridBase::TypeReal) {
+ extrapolSimpleFlagsHelper<Real>(flags,*((Grid<Real>*) val),distance,flagFrom,flagTo);
+ }
+ else if (val->getType() & GridBase::TypeInt) {
+ extrapolSimpleFlagsHelper<int >(flags,*((Grid<int >*) val),distance,flagFrom,flagTo);
+ }
+ else if (val->getType() & GridBase::TypeVec3) {
+ extrapolSimpleFlagsHelper<Vec3>(flags,*((Grid<Vec3>*) val),distance,flagFrom,flagTo);
+ }
+ else
+ errMsg("extrapolateSimpleFlags: Grid Type is not supported (only int, Real, Vec3)");
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "extrapolateSimpleFlags" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); GridBase* val = _args.getPtr<GridBase >("val",1,&_lock); int distance = _args.getOpt<int >("distance",2,4,&_lock); int flagFrom = _args.getOpt<int >("flagFrom",3,FlagGrid::TypeFluid,&_lock); int flagTo = _args.getOpt<int >("flagTo",4,FlagGrid::TypeObstacle ,&_lock); _retval = getPyNone(); extrapolateSimpleFlags(flags,val,distance,flagFrom,flagTo); _args.check(); }
+ pbFinalizePlugin(parent,"extrapolateSimpleFlags", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("extrapolateSimpleFlags",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_extrapolateSimpleFlags ("","extrapolateSimpleFlags",_W_10);
+extern "C" {
+ void PbRegister_extrapolateSimpleFlags() {
+ KEEP_UNUSED(_RP_extrapolateSimpleFlags); }
+ }
+
+
+
+//! convert vel to a centered grid, then compute its curl
+void getCurl(const MACGrid& vel, Grid<Real>& vort, int comp) {
+ Grid<Vec3> velCenter(vel.getParent()), curl(vel.getParent());
+
+ GetCentered(velCenter, vel);
+ CurlOp(velCenter, curl);
+ GetComponent(curl, vort, comp);
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "getCurl" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Real>& vort = *_args.getPtr<Grid<Real> >("vort",1,&_lock); int comp = _args.get<int >("comp",2,&_lock); _retval = getPyNone(); getCurl(vel,vort,comp); _args.check(); }
+ pbFinalizePlugin(parent,"getCurl", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("getCurl",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_getCurl ("","getCurl",_W_11);
+extern "C" {
+ void PbRegister_getCurl() {
+ KEEP_UNUSED(_RP_getCurl); }
+ }
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/waves.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/waves.cpp
new file mode 100644
index 00000000000..9160e63cfcb
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/plugin/waves.cpp
@@ -0,0 +1,284 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Wave equation
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include "conjugategrad.h"
+#include <cmath>
+
+using namespace std;
+
+namespace Manta {
+
+
+/******************************************************************************
+ *
+ * explicit integration
+ *
+ ******************************************************************************/
+
+
+
+ struct knCalcSecDeriv2d : public KernelBase {
+ knCalcSecDeriv2d(const Grid<Real>& v, Grid<Real>& ret) : KernelBase(&v,1) ,v(v),ret(ret) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Grid<Real>& v, Grid<Real>& ret ) const {
+ ret(i,j,k) =
+ ( -4. * v(i,j,k) + v(i-1,j,k) + v(i+1,j,k) + v(i,j-1,k) + v(i,j+1,k) );
+} inline const Grid<Real>& getArg0() {
+ return v; }
+ typedef Grid<Real> type0;inline Grid<Real>& getArg1() {
+ return ret; }
+ typedef Grid<Real> type1; void runMessage() { debMsg("Executing kernel knCalcSecDeriv2d ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,v,ret); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,v,ret); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const Grid<Real>& v; Grid<Real>& ret; }
+;;
+
+//! calculate a second derivative for the wave equation
+void calcSecDeriv2d(const Grid<Real>& v, Grid<Real>& curv) {
+ knCalcSecDeriv2d(v,curv);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "calcSecDeriv2d" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const Grid<Real>& v = *_args.getPtr<Grid<Real> >("v",0,&_lock); Grid<Real>& curv = *_args.getPtr<Grid<Real> >("curv",1,&_lock); _retval = getPyNone(); calcSecDeriv2d(v,curv); _args.check(); }
+ pbFinalizePlugin(parent,"calcSecDeriv2d", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("calcSecDeriv2d",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_calcSecDeriv2d ("","calcSecDeriv2d",_W_0);
+extern "C" {
+ void PbRegister_calcSecDeriv2d() {
+ KEEP_UNUSED(_RP_calcSecDeriv2d); }
+ }
+
+
+
+
+// mass conservation
+
+
+ struct knTotalSum : public KernelBase {
+ knTotalSum(Grid<Real>& h) : KernelBase(&h,1) ,h(h) ,sum(0) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& h ,double& sum) { sum += h(i,j,k); } inline operator double () {
+ return sum; }
+ inline double & getRet() {
+ return sum; }
+ inline Grid<Real>& getArg0() {
+ return h; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel knTotalSum ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,h,sum); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,h,sum); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_reduce (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_reduce (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ knTotalSum (knTotalSum& o, tbb::split) : KernelBase(o) ,h(o.h) ,sum(0) {
+}
+ void join(const knTotalSum & o) {
+ sum += o.sum; }
+ Grid<Real>& h; double sum; }
+;
+
+//! calculate the sum of all values in a grid (for wave equation solves)
+Real totalSum(Grid<Real>& height) {
+ knTotalSum ts(height);
+ return ts.sum;
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "totalSum" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& height = *_args.getPtr<Grid<Real> >("height",0,&_lock); _retval = toPy(totalSum(height)); _args.check(); }
+ pbFinalizePlugin(parent,"totalSum", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("totalSum",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_totalSum ("","totalSum",_W_1);
+extern "C" {
+ void PbRegister_totalSum() {
+ KEEP_UNUSED(_RP_totalSum); }
+ }
+
+
+
+//! normalize all values in a grid (for wave equation solves)
+void normalizeSumTo(Grid<Real>& height, Real target) {
+ knTotalSum ts(height);
+ Real factor = target / ts.sum;
+ height.multConst(factor);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "normalizeSumTo" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; Grid<Real>& height = *_args.getPtr<Grid<Real> >("height",0,&_lock); Real target = _args.get<Real >("target",1,&_lock); _retval = getPyNone(); normalizeSumTo(height,target); _args.check(); }
+ pbFinalizePlugin(parent,"normalizeSumTo", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("normalizeSumTo",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_normalizeSumTo ("","normalizeSumTo",_W_2);
+extern "C" {
+ void PbRegister_normalizeSumTo() {
+ KEEP_UNUSED(_RP_normalizeSumTo); }
+ }
+
+
+
+
+/******************************************************************************
+ *
+ * implicit time integration
+ *
+ ******************************************************************************/
+
+
+
+//! Kernel: Construct the right-hand side of the poisson equation
+
+
+
+ struct MakeRhsWE : public KernelBase {
+ MakeRhsWE(const FlagGrid& flags, Grid<Real>& rhs, const Grid<Real>& ut, const Grid<Real>& utm1, Real s, bool crankNic=false) : KernelBase(&flags,1) ,flags(flags),rhs(rhs),ut(ut),utm1(utm1),s(s),crankNic(crankNic) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const FlagGrid& flags, Grid<Real>& rhs, const Grid<Real>& ut, const Grid<Real>& utm1, Real s, bool crankNic=false ) const {
+ rhs(i,j,k) = ( 2.*ut(i,j,k) - utm1(i,j,k) );
+ if(crankNic) {
+ rhs(i,j,k) += s * ( -4.*ut(i,j,k) + 1.*ut(i-1,j,k) + 1.*ut(i+1,j,k) + 1.*ut(i,j-1,k) + 1.*ut(i,j+1,k) );
+ }
+} inline const FlagGrid& getArg0() {
+ return flags; }
+ typedef FlagGrid type0;inline Grid<Real>& getArg1() {
+ return rhs; }
+ typedef Grid<Real> type1;inline const Grid<Real>& getArg2() {
+ return ut; }
+ typedef Grid<Real> type2;inline const Grid<Real>& getArg3() {
+ return utm1; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return s; }
+ typedef Real type4;inline bool& getArg5() {
+ return crankNic; }
+ typedef bool type5; void runMessage() { debMsg("Executing kernel MakeRhsWE ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=1; j<_maxY; j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,rhs,ut,utm1,s,crankNic); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=1; i<_maxX; i++) op(i,j,k,flags,rhs,ut,utm1,s,crankNic); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(1, maxY), *this); }
+ const FlagGrid& flags; Grid<Real>& rhs; const Grid<Real>& ut; const Grid<Real>& utm1; Real s; bool crankNic; }
+;
+
+
+
+
+
+//! do a CG solve for the wave equation (note, out grid only there for debugging... could be removed)
+
+
+
+
+
+void cgSolveWE(const FlagGrid& flags, Grid<Real>& ut, Grid<Real>& utm1, Grid<Real>& out, bool crankNic = false, Real cSqr = 0.25, Real cgMaxIterFac = 1.5, Real cgAccuracy = 1e-5 ) {
+ // reserve temp grids
+ FluidSolver* parent = flags.getParent();
+ Grid<Real> rhs(parent);
+ Grid<Real> residual(parent);
+ Grid<Real> search(parent);
+ Grid<Real> A0(parent);
+ Grid<Real> Ai(parent);
+ Grid<Real> Aj(parent);
+ Grid<Real> Ak(parent);
+ Grid<Real> tmp(parent);
+ // solution...
+ out.clear();
+
+ // setup matrix and boundaries
+ MakeLaplaceMatrix (flags, A0, Ai, Aj, Ak);
+ Real dt = parent->getDt();
+ Real s = dt*dt*cSqr * 0.5;
+ FOR_IJK(flags) {
+ Ai(i,j,k) *= s;
+ Aj(i,j,k) *= s;
+ Ak(i,j,k) *= s;
+ A0(i,j,k) *= s;
+ A0(i,j,k) += 1.;
+ }
+
+ // compute divergence and init right hand side
+ rhs.clear();
+ // h=dt
+ // rhs: = 2 ut - ut-1
+ // A: (h2 c2/ dx)=s , (1+4s)uij + s ui-1j + ...
+ // Cr.Nic.
+ // rhs: cr nic = 2 ut - ut-1 + h^2c^2/2 b
+ // A: (h2 c2/2 dx)=s , (1+4s)uij + s ui-1j + ...
+ MakeRhsWE kernMakeRhs(flags, rhs, ut,utm1, s, crankNic);
+
+ const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
+ GridCgInterface *gcg;
+ if (flags.is3D())
+ gcg = new GridCg<ApplyMatrix >(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+ else
+ gcg = new GridCg<ApplyMatrix2D>(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
+
+ gcg->setAccuracy( cgAccuracy );
+
+ // no preconditioning for now...
+ for (int iter=0; iter<maxIter; iter++) {
+ if (!gcg->iterate()) iter=maxIter;
+ }
+ debMsg("cgSolveWaveEq iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma(), 1);
+
+ utm1.swap( ut );
+ ut.copyFrom( out );
+
+ delete gcg;
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(parent, "cgSolveWE" , !noTiming ); PyObject *_retval = 0; {
+ ArgLocker _lock; const FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& ut = *_args.getPtr<Grid<Real> >("ut",1,&_lock); Grid<Real>& utm1 = *_args.getPtr<Grid<Real> >("utm1",2,&_lock); Grid<Real>& out = *_args.getPtr<Grid<Real> >("out",3,&_lock); bool crankNic = _args.getOpt<bool >("crankNic",4,false,&_lock); Real cSqr = _args.getOpt<Real >("cSqr",5,0.25,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",6,1.5,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",7,1e-5 ,&_lock); _retval = getPyNone(); cgSolveWE(flags,ut,utm1,out,crankNic,cSqr,cgMaxIterFac,cgAccuracy); _args.check(); }
+ pbFinalizePlugin(parent,"cgSolveWE", !noTiming ); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("cgSolveWE",e.what()); return 0; }
+ }
+ static const Pb::Register _RP_cgSolveWE ("","cgSolveWE",_W_3);
+extern "C" {
+ void PbRegister_cgSolveWE() {
+ KEEP_UNUSED(_RP_cgSolveWE); }
+ }
+
+
+
+
+
+
+} //namespace
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py
new file mode 100644
index 00000000000..1c7f01ab034
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py
@@ -0,0 +1,11 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py.reg
new file mode 100644
index 00000000000..bd36ccac6c2
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py.reg
@@ -0,0 +1,2 @@
+#include "registry.h"
+static const Pb::Register _reg("python/defines.py", "################################################################################\n#\n# MantaFlow fluid solver framework\n# Copyright 2011 Tobias Pfaff, Nils Thuerey \n#\n# This program is free software, distributed under the terms of the\n# Apache License, Version 2.0 \n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Defines some constants for use in python subprograms\n#\n#################################################################################\n\n# mantaflow conventions\nReal = float\n\n# some defines to make C code and scripts more alike...\nfalse = False\ntrue = True\nVec3 = vec3\nVec4 = vec4\nVec3Grid = VecGrid\n\n# grid flags\nFlagFluid = 1\nFlagObstacle = 2\nFlagEmpty = 4\nFlagInflow = 8\nFlagOutflow = 16\nFlagStick = 64\nFlagReserved = 256\n# and same for FlagGrid::CellType enum names:\nTypeFluid = 1\nTypeObstacle = 2\nTypeEmpty = 4\nTypeInflow = 8\nTypeOutflow = 16\nTypeStick = 64\nTypeReserved = 256\n\n# integration mode\nIntEuler = 0\nIntRK2 = 1\nIntRK4 = 2\n\n# CG preconditioner\nPcNone = 0\nPcMIC = 1\nPcMGDynamic = 2\nPcMGStatic = 3\n\n# particles\nPtypeSpray = 2\nPtypeBubble = 4\nPtypeFoam = 8\nPtypeTracer = 16\n\n\n\n\n");
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py.reg.cpp
new file mode 100644
index 00000000000..4453b91c673
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/python/defines.py.reg.cpp
@@ -0,0 +1,8 @@
+#include "registry.h"
+static const Pb::Register _reg("python/defines.py", "################################################################################\n#\n# MantaFlow fluid solver framework\n# Copyright 2011 Tobias Pfaff, Nils Thuerey \n#\n# This program is free software, distributed under the terms of the\n# Apache License, Version 2.0 \n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Defines some constants for use in python subprograms\n#\n#################################################################################\n\n# mantaflow conventions\nReal = float\n\n# some defines to make C code and scripts more alike...\nfalse = False\ntrue = True\nVec3 = vec3\nVec4 = vec4\nVec3Grid = VecGrid\n\n# grid flags\nFlagFluid = 1\nFlagObstacle = 2\nFlagEmpty = 4\nFlagInflow = 8\nFlagOutflow = 16\nFlagStick = 64\nFlagReserved = 256\n# and same for FlagGrid::CellType enum names:\nTypeFluid = 1\nTypeObstacle = 2\nTypeEmpty = 4\nTypeInflow = 8\nTypeOutflow = 16\nTypeStick = 64\nTypeReserved = 256\n\n# integration mode\nIntEuler = 0\nIntRK2 = 1\nIntRK4 = 2\n\n# CG preconditioner\nPcNone = 0\nPcMIC = 1\nPcMGDynamic = 2\nPcMGStatic = 3\n\n# particles\nPtypeSpray = 2\nPtypeBubble = 4\nPtypeFoam = 8\nPtypeTracer = 16\n\n\n\n\n");
+extern "C" {
+void PbRegister_file_0()
+{
+ KEEP_UNUSED(_reg);
+}
+} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/registration.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/registration.cpp
new file mode 100644
index 00000000000..211de7c79be
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/registration.cpp
@@ -0,0 +1,406 @@
+extern "C" {
+ extern void PbRegister_mantaMsg() ;
+ extern void PbRegister_printBuildInfo() ;
+ extern void PbRegister_setDebugLevel() ;
+ extern void PbRegister_assertNumpy() ;
+ extern void PbRegister_cgSolveDiffusion() ;
+ extern void PbRegister_gridMaxDiff() ;
+ extern void PbRegister_gridMaxDiffInt() ;
+ extern void PbRegister_gridMaxDiffVec3() ;
+ extern void PbRegister_copyMacToVec3() ;
+ extern void PbRegister_convertMacToVec3() ;
+ extern void PbRegister_resampleVec3ToMac() ;
+ extern void PbRegister_resampleMacToVec3() ;
+ extern void PbRegister_copyLevelsetToReal() ;
+ extern void PbRegister_copyVec3ToReal() ;
+ extern void PbRegister_copyRealToVec3() ;
+ extern void PbRegister_convertLevelsetToReal() ;
+ extern void PbRegister_swapComponents() ;
+ extern void PbRegister_getUvWeight() ;
+ extern void PbRegister_resetUvGrid() ;
+ extern void PbRegister_updateUvWeight() ;
+ extern void PbRegister_getGridAvg() ;
+ extern void PbRegister_getComponent() ;
+ extern void PbRegister_setComponent() ;
+ extern void PbRegister_markIsolatedFluidCell() ;
+ extern void PbRegister_copyMACData() ;
+ extern void PbRegister_getComp4d() ;
+ extern void PbRegister_setComp4d() ;
+ extern void PbRegister_grid4dMaxDiff() ;
+ extern void PbRegister_grid4dMaxDiffInt() ;
+ extern void PbRegister_grid4dMaxDiffVec3() ;
+ extern void PbRegister_grid4dMaxDiffVec4() ;
+ extern void PbRegister_setRegion4d() ;
+ extern void PbRegister_setRegion4dVec4() ;
+ extern void PbRegister_getSliceFrom4d() ;
+ extern void PbRegister_getSliceFrom4dVec() ;
+ extern void PbRegister_interpolateGrid4d() ;
+ extern void PbRegister_interpolateGrid4dVec() ;
+ extern void PbRegister_extrapolateMACSimple() ;
+ extern void PbRegister_extrapolateMACFromWeight() ;
+ extern void PbRegister_extrapolateLsSimple() ;
+ extern void PbRegister_extrapolateVec3Simple() ;
+ extern void PbRegister_getUniFileSize() ;
+ extern void PbRegister_printUniFileInfoString() ;
+ extern void PbRegister_getNpzFileSize() ;
+ extern void PbRegister_quantizeGrid() ;
+ extern void PbRegister_quantizeGridVec3() ;
+ extern void PbRegister_resetPhiInObs() ;
+ extern void PbRegister_advectSemiLagrange() ;
+ extern void PbRegister_addGravity() ;
+ extern void PbRegister_addGravityNoScale() ;
+ extern void PbRegister_addBuoyancy() ;
+ extern void PbRegister_setOpenBound() ;
+ extern void PbRegister_resetOutflow() ;
+ extern void PbRegister_setInflowBcs() ;
+ extern void PbRegister_setWallBcs() ;
+ extern void PbRegister_setInitialVelocity() ;
+ extern void PbRegister_vorticityConfinement() ;
+ extern void PbRegister_addForceField() ;
+ extern void PbRegister_setForceField() ;
+ extern void PbRegister_dissolveSmoke() ;
+ extern void PbRegister_apicMapPartsToMAC() ;
+ extern void PbRegister_apicMapMACGridToParts() ;
+ extern void PbRegister_sampleFlagsWithParticles() ;
+ extern void PbRegister_sampleLevelsetWithParticles() ;
+ extern void PbRegister_sampleShapeWithParticles() ;
+ extern void PbRegister_markFluidCells() ;
+ extern void PbRegister_testInitGridWithPos() ;
+ extern void PbRegister_adjustNumber() ;
+ extern void PbRegister_debugIntToReal() ;
+ extern void PbRegister_gridParticleIndex() ;
+ extern void PbRegister_unionParticleLevelset() ;
+ extern void PbRegister_averagedParticleLevelset() ;
+ extern void PbRegister_improvedParticleLevelset() ;
+ extern void PbRegister_pushOutofObs() ;
+ extern void PbRegister_mapPartsToMAC() ;
+ extern void PbRegister_mapPartsToGrid() ;
+ extern void PbRegister_mapPartsToGridVec3() ;
+ extern void PbRegister_mapGridToParts() ;
+ extern void PbRegister_mapGridToPartsVec3() ;
+ extern void PbRegister_mapMACToParts() ;
+ extern void PbRegister_flipVelocityUpdate() ;
+ extern void PbRegister_combineGridVel() ;
+ extern void PbRegister_getLaplacian() ;
+ extern void PbRegister_getCurvature() ;
+ extern void PbRegister_processBurn() ;
+ extern void PbRegister_updateFlame() ;
+ extern void PbRegister_getSpiralVelocity() ;
+ extern void PbRegister_setGradientYWeight() ;
+ extern void PbRegister_PD_fluid_guiding() ;
+ extern void PbRegister_releaseBlurPrecomp() ;
+ extern void PbRegister_KEpsilonComputeProduction() ;
+ extern void PbRegister_KEpsilonSources() ;
+ extern void PbRegister_KEpsilonBcs() ;
+ extern void PbRegister_KEpsilonGradientDiffusion() ;
+ extern void PbRegister_densityInflow() ;
+ extern void PbRegister_addNoise() ;
+ extern void PbRegister_setNoisePdata() ;
+ extern void PbRegister_setNoisePdataVec3() ;
+ extern void PbRegister_setNoisePdataInt() ;
+ extern void PbRegister_obstacleGradient() ;
+ extern void PbRegister_obstacleLevelset() ;
+ extern void PbRegister_applyEmission() ;
+ extern void PbRegister_densityInflowMeshNoise() ;
+ extern void PbRegister_densityInflowMesh() ;
+ extern void PbRegister_checkSymmetry() ;
+ extern void PbRegister_checkSymmetryVec3() ;
+ extern void PbRegister_projectPpmFull() ;
+ extern void PbRegister_addTestParts() ;
+ extern void PbRegister_pdataMaxDiff() ;
+ extern void PbRegister_calcCenterOfMass() ;
+ extern void PbRegister_updateFractions() ;
+ extern void PbRegister_setObstacleFlags() ;
+ extern void PbRegister_initVortexVelocity() ;
+ extern void PbRegister_blurMacGrid() ;
+ extern void PbRegister_blurRealGrid() ;
+ extern void PbRegister_smoothMesh() ;
+ extern void PbRegister_subdivideMesh() ;
+ extern void PbRegister_killSmallComponents() ;
+ extern void PbRegister_releaseMG() ;
+ extern void PbRegister_computePressureRhs() ;
+ extern void PbRegister_solvePressureSystem() ;
+ extern void PbRegister_correctVelocity() ;
+ extern void PbRegister_solvePressure() ;
+ extern void PbRegister_flipComputeSecondaryParticlePotentials() ;
+ extern void PbRegister_flipSampleSecondaryParticles() ;
+ extern void PbRegister_flipUpdateSecondaryParticles() ;
+ extern void PbRegister_flipDeleteParticlesInObstacle() ;
+ extern void PbRegister_debugGridInfo() ;
+ extern void PbRegister_setFlagsFromLevelset() ;
+ extern void PbRegister_setMACFromLevelset() ;
+ extern void PbRegister_flipComputePotentialTrappedAir() ;
+ extern void PbRegister_flipComputePotentialKineticEnergy() ;
+ extern void PbRegister_flipComputePotentialWaveCrest() ;
+ extern void PbRegister_flipComputeSurfaceNormals() ;
+ extern void PbRegister_flipUpdateNeighborRatio() ;
+ extern void PbRegister_addForcePvel() ;
+ extern void PbRegister_updateVelocityFromDeltaPos() ;
+ extern void PbRegister_eulerStep() ;
+ extern void PbRegister_setPartType() ;
+ extern void PbRegister_flipComputeSecondaryParticlePotentials() ;
+ extern void PbRegister_flipSampleSecondaryParticles() ;
+ extern void PbRegister_flipUpdateSecondaryParticles() ;
+ extern void PbRegister_flipDeleteParticlesInObstacle() ;
+ extern void PbRegister_debugGridInfo() ;
+ extern void PbRegister_setFlagsFromLevelset() ;
+ extern void PbRegister_setMACFromLevelset() ;
+ extern void PbRegister_flipComputePotentialTrappedAir() ;
+ extern void PbRegister_flipComputePotentialKineticEnergy() ;
+ extern void PbRegister_flipComputePotentialWaveCrest() ;
+ extern void PbRegister_flipComputeSurfaceNormals() ;
+ extern void PbRegister_flipUpdateNeighborRatio() ;
+ extern void PbRegister_particleSurfaceTurbulence() ;
+ extern void PbRegister_debugCheckParts() ;
+ extern void PbRegister_markAsFixed() ;
+ extern void PbRegister_texcoordInflow() ;
+ extern void PbRegister_meshSmokeInflow() ;
+ extern void PbRegister_vorticitySource() ;
+ extern void PbRegister_smoothVorticity() ;
+ extern void PbRegister_VPseedK41() ;
+ extern void PbRegister_VICintegration() ;
+ extern void PbRegister_densityFromLevelset() ;
+ extern void PbRegister_interpolateGrid() ;
+ extern void PbRegister_interpolateGridVec3() ;
+ extern void PbRegister_interpolateMACGrid() ;
+ extern void PbRegister_applySimpleNoiseVec3() ;
+ extern void PbRegister_applySimpleNoiseReal() ;
+ extern void PbRegister_applyNoiseVec3() ;
+ extern void PbRegister_computeEnergy() ;
+ extern void PbRegister_computeWaveletCoeffs() ;
+ extern void PbRegister_computeVorticity() ;
+ extern void PbRegister_computeStrainRateMag() ;
+ extern void PbRegister_extrapolateSimpleFlags() ;
+ extern void PbRegister_getCurl() ;
+ extern void PbRegister_calcSecDeriv2d() ;
+ extern void PbRegister_totalSum() ;
+ extern void PbRegister_normalizeSumTo() ;
+ extern void PbRegister_cgSolveWE() ;
+ extern void PbRegister_file_0();
+ extern void PbRegister_file_1();
+ extern void PbRegister_file_2();
+ extern void PbRegister_file_3();
+ extern void PbRegister_file_4();
+ extern void PbRegister_file_5();
+ extern void PbRegister_file_6();
+ extern void PbRegister_file_7();
+ extern void PbRegister_file_8();
+ extern void PbRegister_file_9();
+ extern void PbRegister_file_10();
+ extern void PbRegister_file_11();
+ extern void PbRegister_file_12();
+ extern void PbRegister_file_13();
+ extern void PbRegister_file_14();
+ extern void PbRegister_file_15();
+ extern void PbRegister_file_16();
+ extern void PbRegister_file_17();
+ extern void PbRegister_file_18();
+ extern void PbRegister_file_19();
+ extern void PbRegister_file_20();
+ extern void PbRegister_file_21();
+}
+
+namespace Pb {
+ void MantaEnsureRegistration()
+ {
+ PbRegister_mantaMsg() ;
+ PbRegister_printBuildInfo() ;
+ PbRegister_setDebugLevel() ;
+ PbRegister_assertNumpy() ;
+ PbRegister_cgSolveDiffusion() ;
+ PbRegister_gridMaxDiff() ;
+ PbRegister_gridMaxDiffInt() ;
+ PbRegister_gridMaxDiffVec3() ;
+ PbRegister_copyMacToVec3() ;
+ PbRegister_convertMacToVec3() ;
+ PbRegister_resampleVec3ToMac() ;
+ PbRegister_resampleMacToVec3() ;
+ PbRegister_copyLevelsetToReal() ;
+ PbRegister_copyVec3ToReal() ;
+ PbRegister_copyRealToVec3() ;
+ PbRegister_convertLevelsetToReal() ;
+ PbRegister_swapComponents() ;
+ PbRegister_getUvWeight() ;
+ PbRegister_resetUvGrid() ;
+ PbRegister_updateUvWeight() ;
+ PbRegister_getGridAvg() ;
+ PbRegister_getComponent() ;
+ PbRegister_setComponent() ;
+ PbRegister_markIsolatedFluidCell() ;
+ PbRegister_copyMACData() ;
+ PbRegister_getComp4d() ;
+ PbRegister_setComp4d() ;
+ PbRegister_grid4dMaxDiff() ;
+ PbRegister_grid4dMaxDiffInt() ;
+ PbRegister_grid4dMaxDiffVec3() ;
+ PbRegister_grid4dMaxDiffVec4() ;
+ PbRegister_setRegion4d() ;
+ PbRegister_setRegion4dVec4() ;
+ PbRegister_getSliceFrom4d() ;
+ PbRegister_getSliceFrom4dVec() ;
+ PbRegister_interpolateGrid4d() ;
+ PbRegister_interpolateGrid4dVec() ;
+ PbRegister_extrapolateMACSimple() ;
+ PbRegister_extrapolateMACFromWeight() ;
+ PbRegister_extrapolateLsSimple() ;
+ PbRegister_extrapolateVec3Simple() ;
+ PbRegister_getUniFileSize() ;
+ PbRegister_printUniFileInfoString() ;
+ PbRegister_getNpzFileSize() ;
+ PbRegister_quantizeGrid() ;
+ PbRegister_quantizeGridVec3() ;
+ PbRegister_resetPhiInObs() ;
+ PbRegister_advectSemiLagrange() ;
+ PbRegister_addGravity() ;
+ PbRegister_addGravityNoScale() ;
+ PbRegister_addBuoyancy() ;
+ PbRegister_setOpenBound() ;
+ PbRegister_resetOutflow() ;
+ PbRegister_setInflowBcs() ;
+ PbRegister_setWallBcs() ;
+ PbRegister_setInitialVelocity() ;
+ PbRegister_vorticityConfinement() ;
+ PbRegister_addForceField() ;
+ PbRegister_setForceField() ;
+ PbRegister_dissolveSmoke() ;
+ PbRegister_apicMapPartsToMAC() ;
+ PbRegister_apicMapMACGridToParts() ;
+ PbRegister_sampleFlagsWithParticles() ;
+ PbRegister_sampleLevelsetWithParticles() ;
+ PbRegister_sampleShapeWithParticles() ;
+ PbRegister_markFluidCells() ;
+ PbRegister_testInitGridWithPos() ;
+ PbRegister_adjustNumber() ;
+ PbRegister_debugIntToReal() ;
+ PbRegister_gridParticleIndex() ;
+ PbRegister_unionParticleLevelset() ;
+ PbRegister_averagedParticleLevelset() ;
+ PbRegister_improvedParticleLevelset() ;
+ PbRegister_pushOutofObs() ;
+ PbRegister_mapPartsToMAC() ;
+ PbRegister_mapPartsToGrid() ;
+ PbRegister_mapPartsToGridVec3() ;
+ PbRegister_mapGridToParts() ;
+ PbRegister_mapGridToPartsVec3() ;
+ PbRegister_mapMACToParts() ;
+ PbRegister_flipVelocityUpdate() ;
+ PbRegister_combineGridVel() ;
+ PbRegister_getLaplacian() ;
+ PbRegister_getCurvature() ;
+ PbRegister_processBurn() ;
+ PbRegister_updateFlame() ;
+ PbRegister_getSpiralVelocity() ;
+ PbRegister_setGradientYWeight() ;
+ PbRegister_PD_fluid_guiding() ;
+ PbRegister_releaseBlurPrecomp() ;
+ PbRegister_KEpsilonComputeProduction() ;
+ PbRegister_KEpsilonSources() ;
+ PbRegister_KEpsilonBcs() ;
+ PbRegister_KEpsilonGradientDiffusion() ;
+ PbRegister_densityInflow() ;
+ PbRegister_addNoise() ;
+ PbRegister_setNoisePdata() ;
+ PbRegister_setNoisePdataVec3() ;
+ PbRegister_setNoisePdataInt() ;
+ PbRegister_obstacleGradient() ;
+ PbRegister_obstacleLevelset() ;
+ PbRegister_applyEmission() ;
+ PbRegister_densityInflowMeshNoise() ;
+ PbRegister_densityInflowMesh() ;
+ PbRegister_checkSymmetry() ;
+ PbRegister_checkSymmetryVec3() ;
+ PbRegister_projectPpmFull() ;
+ PbRegister_addTestParts() ;
+ PbRegister_pdataMaxDiff() ;
+ PbRegister_calcCenterOfMass() ;
+ PbRegister_updateFractions() ;
+ PbRegister_setObstacleFlags() ;
+ PbRegister_initVortexVelocity() ;
+ PbRegister_blurMacGrid() ;
+ PbRegister_blurRealGrid() ;
+ PbRegister_smoothMesh() ;
+ PbRegister_subdivideMesh() ;
+ PbRegister_killSmallComponents() ;
+ PbRegister_releaseMG() ;
+ PbRegister_computePressureRhs() ;
+ PbRegister_solvePressureSystem() ;
+ PbRegister_correctVelocity() ;
+ PbRegister_solvePressure() ;
+ PbRegister_flipComputeSecondaryParticlePotentials() ;
+ PbRegister_flipSampleSecondaryParticles() ;
+ PbRegister_flipUpdateSecondaryParticles() ;
+ PbRegister_flipDeleteParticlesInObstacle() ;
+ PbRegister_debugGridInfo() ;
+ PbRegister_setFlagsFromLevelset() ;
+ PbRegister_setMACFromLevelset() ;
+ PbRegister_flipComputePotentialTrappedAir() ;
+ PbRegister_flipComputePotentialKineticEnergy() ;
+ PbRegister_flipComputePotentialWaveCrest() ;
+ PbRegister_flipComputeSurfaceNormals() ;
+ PbRegister_flipUpdateNeighborRatio() ;
+ PbRegister_addForcePvel() ;
+ PbRegister_updateVelocityFromDeltaPos() ;
+ PbRegister_eulerStep() ;
+ PbRegister_setPartType() ;
+ PbRegister_flipComputeSecondaryParticlePotentials() ;
+ PbRegister_flipSampleSecondaryParticles() ;
+ PbRegister_flipUpdateSecondaryParticles() ;
+ PbRegister_flipDeleteParticlesInObstacle() ;
+ PbRegister_debugGridInfo() ;
+ PbRegister_setFlagsFromLevelset() ;
+ PbRegister_setMACFromLevelset() ;
+ PbRegister_flipComputePotentialTrappedAir() ;
+ PbRegister_flipComputePotentialKineticEnergy() ;
+ PbRegister_flipComputePotentialWaveCrest() ;
+ PbRegister_flipComputeSurfaceNormals() ;
+ PbRegister_flipUpdateNeighborRatio() ;
+ PbRegister_particleSurfaceTurbulence() ;
+ PbRegister_debugCheckParts() ;
+ PbRegister_markAsFixed() ;
+ PbRegister_texcoordInflow() ;
+ PbRegister_meshSmokeInflow() ;
+ PbRegister_vorticitySource() ;
+ PbRegister_smoothVorticity() ;
+ PbRegister_VPseedK41() ;
+ PbRegister_VICintegration() ;
+ PbRegister_densityFromLevelset() ;
+ PbRegister_interpolateGrid() ;
+ PbRegister_interpolateGridVec3() ;
+ PbRegister_interpolateMACGrid() ;
+ PbRegister_applySimpleNoiseVec3() ;
+ PbRegister_applySimpleNoiseReal() ;
+ PbRegister_applyNoiseVec3() ;
+ PbRegister_computeEnergy() ;
+ PbRegister_computeWaveletCoeffs() ;
+ PbRegister_computeVorticity() ;
+ PbRegister_computeStrainRateMag() ;
+ PbRegister_extrapolateSimpleFlags() ;
+ PbRegister_getCurl() ;
+ PbRegister_calcSecDeriv2d() ;
+ PbRegister_totalSum() ;
+ PbRegister_normalizeSumTo() ;
+ PbRegister_cgSolveWE() ;
+ PbRegister_file_0();
+ PbRegister_file_1();
+ PbRegister_file_2();
+ PbRegister_file_3();
+ PbRegister_file_4();
+ PbRegister_file_5();
+ PbRegister_file_6();
+ PbRegister_file_7();
+ PbRegister_file_8();
+ PbRegister_file_9();
+ PbRegister_file_10();
+ PbRegister_file_11();
+ PbRegister_file_12();
+ PbRegister_file_13();
+ PbRegister_file_14();
+ PbRegister_file_15();
+ PbRegister_file_16();
+ PbRegister_file_17();
+ PbRegister_file_18();
+ PbRegister_file_19();
+ PbRegister_file_20();
+ PbRegister_file_21();
+ }
+}
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.cpp
new file mode 100644
index 00000000000..ba9a1849d6c
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.cpp
@@ -0,0 +1,624 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Shape classes
+ *
+ ******************************************************************************/
+
+#include "shapes.h"
+#include "commonkernels.h"
+#include "mesh.h"
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// Shape class members
+
+Shape::Shape (FluidSolver* parent)
+ : PbClass(parent), mType(TypeNone)
+{
+}
+
+LevelsetGrid Shape::computeLevelset() {
+ // note - 3d check deactivated! TODO double check...
+ LevelsetGrid phi(getParent());
+ generateLevelset(phi);
+ return phi;
+}
+
+bool Shape::isInside(const Vec3& pos) const {
+ return false;
+}
+
+//! Kernel: Apply a shape to a grid, setting value inside
+
+template <class T> struct ApplyShapeToGrid : public KernelBase {
+ ApplyShapeToGrid(Grid<T>* grid, Shape* shape, T value, FlagGrid* respectFlags) : KernelBase(grid,0) ,grid(grid),shape(shape),value(value),respectFlags(respectFlags) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>* grid, Shape* shape, T value, FlagGrid* respectFlags ) const {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ if (shape->isInsideGrid(i,j,k))
+ (*grid)(i,j,k) = value;
+} inline Grid<T>* getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline Shape* getArg1() {
+ return shape; }
+ typedef Shape type1;inline T& getArg2() {
+ return value; }
+ typedef T type2;inline FlagGrid* getArg3() {
+ return respectFlags; }
+ typedef FlagGrid type3; void runMessage() { debMsg("Executing kernel ApplyShapeToGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,shape,value,respectFlags); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,shape,value,respectFlags); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<T>* grid; Shape* shape; T value; FlagGrid* respectFlags; }
+;
+
+//! Kernel: Apply a shape to a grid, setting value inside (scaling by SDF value)
+
+template <class T> struct ApplyShapeToGridSmooth : public KernelBase {
+ ApplyShapeToGridSmooth(Grid<T>* grid, Grid<Real>& phi, Real sigma, Real shift, T value, FlagGrid* respectFlags) : KernelBase(grid,0) ,grid(grid),phi(phi),sigma(sigma),shift(shift),value(value),respectFlags(respectFlags) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<T>* grid, Grid<Real>& phi, Real sigma, Real shift, T value, FlagGrid* respectFlags ) const {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ const Real p = phi(i,j,k) - shift;
+ if (p < -sigma)
+ (*grid)(i,j,k) = value;
+ else if (p < sigma)
+ (*grid)(i,j,k) = value*(0.5f*(1.0f-p/sigma));
+} inline Grid<T>* getArg0() {
+ return grid; }
+ typedef Grid<T> type0;inline Grid<Real>& getArg1() {
+ return phi; }
+ typedef Grid<Real> type1;inline Real& getArg2() {
+ return sigma; }
+ typedef Real type2;inline Real& getArg3() {
+ return shift; }
+ typedef Real type3;inline T& getArg4() {
+ return value; }
+ typedef T type4;inline FlagGrid* getArg5() {
+ return respectFlags; }
+ typedef FlagGrid type5; void runMessage() { debMsg("Executing kernel ApplyShapeToGridSmooth ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,phi,sigma,shift,value,respectFlags); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,phi,sigma,shift,value,respectFlags); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<T>* grid; Grid<Real>& phi; Real sigma; Real shift; T value; FlagGrid* respectFlags; }
+;
+
+//! Kernel: Apply a shape to a MAC grid, setting value inside
+
+ struct ApplyShapeToMACGrid : public KernelBase {
+ ApplyShapeToMACGrid(MACGrid* grid, Shape* shape, Vec3 value, FlagGrid* respectFlags) : KernelBase(grid,0) ,grid(grid),shape(shape),value(value),respectFlags(respectFlags) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, MACGrid* grid, Shape* shape, Vec3 value, FlagGrid* respectFlags ) const {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ if (shape->isInside(Vec3(i,j+0.5,k+0.5))) (*grid)(i,j,k).x = value.x;
+ if (shape->isInside(Vec3(i+0.5,j,k+0.5))) (*grid)(i,j,k).y = value.y;
+ if (shape->isInside(Vec3(i+0.5,j+0.5,k))) (*grid)(i,j,k).z = value.z;
+} inline MACGrid* getArg0() {
+ return grid; }
+ typedef MACGrid type0;inline Shape* getArg1() {
+ return shape; }
+ typedef Shape type1;inline Vec3& getArg2() {
+ return value; }
+ typedef Vec3 type2;inline FlagGrid* getArg3() {
+ return respectFlags; }
+ typedef FlagGrid type3; void runMessage() { debMsg("Executing kernel ApplyShapeToMACGrid ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,shape,value,respectFlags); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,grid,shape,value,respectFlags); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ MACGrid* grid; Shape* shape; Vec3 value; FlagGrid* respectFlags; }
+;
+
+void Shape::applyToGrid(GridBase* grid, FlagGrid* respectFlags) {
+# if NOPYTHON!=1
+ if (grid->getType() & GridBase::TypeInt)
+ ApplyShapeToGrid<int> ((Grid<int>*)grid, this, _args.get<int>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeReal)
+ ApplyShapeToGrid<Real> ((Grid<Real>*)grid, this, _args.get<Real>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeMAC)
+ ApplyShapeToMACGrid ((MACGrid*)grid, this, _args.get<Vec3>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeVec3)
+ ApplyShapeToGrid<Vec3> ((Grid<Vec3>*)grid, this, _args.get<Vec3>("value"), respectFlags);
+ else
+ errMsg("Shape::applyToGrid(): unknown grid type");
+# else
+ errMsg("Not yet supported...");
+# endif
+}
+
+void Shape::applyToGridSmooth(GridBase* grid, Real sigma, Real shift, FlagGrid* respectFlags) {
+ Grid<Real> phi(grid->getParent());
+ generateLevelset(phi);
+
+# if NOPYTHON!=1
+ if (grid->getType() & GridBase::TypeInt)
+ ApplyShapeToGridSmooth<int> ((Grid<int>*)grid, phi, sigma, shift, _args.get<int>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeReal)
+ ApplyShapeToGridSmooth<Real> ((Grid<Real>*)grid, phi, sigma, shift, _args.get<Real>("value"), respectFlags);
+ else if (grid->getType() & GridBase::TypeVec3)
+ ApplyShapeToGridSmooth<Vec3> ((Grid<Vec3>*)grid, phi, sigma, shift, _args.get<Vec3>("value"), respectFlags);
+ else
+ errMsg("Shape::applyToGridSmooth(): unknown grid type");
+# else
+ errMsg("Not yet supported...");
+# endif
+}
+
+void Shape::collideMesh(Mesh& mesh) {
+ const Real margin = 0.2;
+
+ Grid<Real> phi(getParent());
+ Grid<Vec3> grad(getParent());
+ generateLevelset(phi);
+ GradientOp(grad, phi);
+
+ const int num=mesh.numNodes();
+ for(int i=0; i<num; i++) {
+ const Vec3& p = mesh.nodes(i).pos;
+ mesh.nodes(i).flags &= ~(Mesh::NfCollide | Mesh::NfMarked);
+ if (!phi.isInBounds(p,1)) continue;
+
+ for (int iter=0; iter<10; iter++) {
+ const Real dist= phi.getInterpolated(p);
+ if (dist<margin) {
+ Vec3 n = grad.getInterpolated(p);
+ normalize(n);
+ mesh.nodes(i).pos += (margin-dist) * n;
+ mesh.nodes(i).flags |= Mesh::NfCollide | Mesh::NfMarked;
+ }
+ else break;
+ }
+ }
+}
+
+//******************************************************************************
+// Derived shape class members
+
+Box::Box(FluidSolver* parent, Vec3 center, Vec3 p0, Vec3 p1, Vec3 size)
+ : Shape(parent)
+{
+ mType = TypeBox;
+ if (center.isValid() && size.isValid()) {
+ mP0 = center - size;
+ mP1 = center + size;
+ } else if (p0.isValid() && p1.isValid()) {
+ mP0 = p0;
+ mP1 = p1;
+ } else
+ errMsg("Box: specify either p0,p1 or size,center");
+
+}
+
+bool Box::isInside(const Vec3& pos) const {
+ return (pos.x >= mP0.x && pos.y >= mP0.y && pos.z >= mP0.z &&
+ pos.x <= mP1.x && pos.y <= mP1.y && pos.z <= mP1.z);
+}
+
+void Box::generateMesh(Mesh* mesh) {
+ const int quadidx[24] = { 0,4,6,2, 3,7,5,1, 0,1,5,4, 6,7,3,2, 0,2,3,1, 5,7,6,4 };
+ const int nodebase = mesh->numNodes();
+ int oldtri = mesh->numTris();
+ for (int i=0; i<8; i++) {
+ Node p;
+ p.flags = 0;
+ p.pos = mP0;
+ if (i&1) p.pos.x=mP1.x;
+ if (i&2) p.pos.y=mP1.y;
+ if (i&4) p.pos.z=mP1.z;
+ mesh->addNode(p);
+ }
+ for (int i=0; i<6; i++) {
+ mesh->addTri(Triangle(nodebase + quadidx[i*4+0], nodebase + quadidx[i*4+1], nodebase + quadidx[i*4+3]));
+ mesh->addTri(Triangle(nodebase + quadidx[i*4+1], nodebase + quadidx[i*4+2], nodebase + quadidx[i*4+3]));
+ }
+ mesh->rebuildCorners(oldtri,-1);
+ mesh->rebuildLookup(oldtri,-1);
+}
+
+//! Kernel: Analytic SDF for box shape
+ struct BoxSDF : public KernelBase {
+ BoxSDF(Grid<Real>& phi, const Vec3& p1, const Vec3& p2) : KernelBase(&phi,0) ,phi(phi),p1(p1),p2(p2) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& phi, const Vec3& p1, const Vec3& p2 ) const {
+ const Vec3 p(i+0.5, j+0.5, k+0.5);
+ if (p.x <= p2.x && p.x >= p1.x && p.y <= p2.y && p.y >= p1.y && p.z <= p2.z && p.z >= p1.z) {
+ // inside: minimal surface distance
+ Real mx = max(p.x-p2.x, p1.x-p.x);
+ Real my = max(p.y-p2.y, p1.y-p.y);
+ Real mz = max(p.z-p2.z, p1.z-p.z);
+ if(!phi.is3D()) mz = mx; // skip for 2d...
+ phi(i,j,k) = max(mx,max(my,mz));
+ } else if (p.y <= p2.y && p.y >= p1.y && p.z <= p2.z && p.z >= p1.z) {
+ // outside plane X
+ phi(i,j,k) = max(p.x-p2.x, p1.x-p.x);
+ } else if (p.x <= p2.x && p.x >= p1.x && p.z <= p2.z && p.z >= p1.z) {
+ // outside plane Y
+ phi(i,j,k) = max(p.y-p2.y, p1.y-p.y);
+ } else if (p.x <= p2.x && p.x >= p1.x && p.y <= p2.y && p.y >= p1.y) {
+ // outside plane Z
+ phi(i,j,k) = max(p.z-p2.z, p1.z-p.z);
+ } else if (p.x > p1.x && p.x < p2.x) {
+ // lines X
+ Real m1 = sqrt(square(p1.y-p.y)+square(p1.z-p.z));
+ Real m2 = sqrt(square(p2.y-p.y)+square(p1.z-p.z));
+ Real m3 = sqrt(square(p1.y-p.y)+square(p2.z-p.z));
+ Real m4 = sqrt(square(p2.y-p.y)+square(p2.z-p.z));
+ phi(i,j,k) = min(m1,min(m2,min(m3,m4)));
+ } else if (p.y > p1.y && p.y < p2.y) {
+ // lines Y
+ Real m1 = sqrt(square(p1.x-p.x)+square(p1.z-p.z));
+ Real m2 = sqrt(square(p2.x-p.x)+square(p1.z-p.z));
+ Real m3 = sqrt(square(p1.x-p.x)+square(p2.z-p.z));
+ Real m4 = sqrt(square(p2.x-p.x)+square(p2.z-p.z));
+ phi(i,j,k) = min(m1,min(m2,min(m3,m4)));
+ } else if (p.z > p1.x && p.z < p2.z) {
+ // lines Z
+ Real m1 = sqrt(square(p1.y-p.y)+square(p1.x-p.x));
+ Real m2 = sqrt(square(p2.y-p.y)+square(p1.x-p.x));
+ Real m3 = sqrt(square(p1.y-p.y)+square(p2.x-p.x));
+ Real m4 = sqrt(square(p2.y-p.y)+square(p2.x-p.x));
+ phi(i,j,k) = min(m1,min(m2,min(m3,m4)));
+ } else {
+ // points
+ Real m = norm(p-Vec3(p1.x,p1.y,p1.z));
+ m = min(m, norm(p-Vec3(p1.x,p1.y,p2.z)));
+ m = min(m, norm(p-Vec3(p1.x,p2.y,p1.z)));
+ m = min(m, norm(p-Vec3(p1.x,p2.y,p2.z)));
+ m = min(m, norm(p-Vec3(p2.x,p1.y,p1.z)));
+ m = min(m, norm(p-Vec3(p2.x,p1.y,p2.z)));
+ m = min(m, norm(p-Vec3(p2.x,p2.y,p1.z)));
+ m = min(m, norm(p-Vec3(p2.x,p2.y,p2.z)));
+ phi(i,j,k) = m;
+ }
+} inline Grid<Real>& getArg0() {
+ return phi; }
+ typedef Grid<Real> type0;inline const Vec3& getArg1() {
+ return p1; }
+ typedef Vec3 type1;inline const Vec3& getArg2() {
+ return p2; }
+ typedef Vec3 type2; void runMessage() { debMsg("Executing kernel BoxSDF ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,phi,p1,p2); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,phi,p1,p2); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<Real>& phi; const Vec3& p1; const Vec3& p2; }
+;
+void Box::generateLevelset(Grid<Real>& phi) {
+ BoxSDF(phi, mP0, mP1);
+}
+
+Sphere::Sphere (FluidSolver* parent, Vec3 center, Real radius, Vec3 scale)
+ : Shape(parent), mCenter(center), mScale(scale), mRadius(radius)
+{
+ mType = TypeSphere;
+}
+
+bool Sphere::isInside(const Vec3& pos) const {
+ return normSquare((pos - mCenter) / mScale) <= mRadius * mRadius;
+}
+
+struct Tri { Vec3 t[3]; int i[3]; Tri(Vec3 a,Vec3 b, Vec3 c) {t[0]=a;t[1]=b;t[2]=c;}};
+void Sphere::generateMesh(Mesh* mesh) {
+ vector<Tri> tris;
+ const int iterations = 3;
+ int oldtri = mesh->numTris();
+
+ // start with octahedron
+ const Real d = sqrt(0.5);
+ Vec3 p[6] = {Vec3(0,1,0), Vec3(0,-1,0), Vec3(-d,0,-d), Vec3(d,0,-d), Vec3(d,0,d), Vec3(-d,0,d)};
+ tris.push_back(Tri(p[0],p[4],p[3]));
+ tris.push_back(Tri(p[0],p[5],p[4]));
+ tris.push_back(Tri(p[0],p[2],p[5]));
+ tris.push_back(Tri(p[0],p[3],p[2]));
+ tris.push_back(Tri(p[1],p[3],p[4]));
+ tris.push_back(Tri(p[1],p[4],p[5]));
+ tris.push_back(Tri(p[1],p[5],p[2]));
+ tris.push_back(Tri(p[1],p[2],p[3]));
+
+ // Bisect each edge and move to the surface of a unit sphere
+ for (int it=0; it<iterations; it++) {
+ int ntold = tris.size();
+ for (int i=0; i<ntold; i++) {
+ Vec3 pa = 0.5 * (tris[i].t[0] + tris[i].t[1]);
+ Vec3 pb = 0.5 * (tris[i].t[1] + tris[i].t[2]);
+ Vec3 pc = 0.5 * (tris[i].t[2] + tris[i].t[0]);
+ normalize(pa); normalize(pb); normalize(pc);
+
+ tris.push_back(Tri(tris[i].t[0], pa, pc));
+ tris.push_back(Tri(pa, tris[i].t[1], pb));
+ tris.push_back(Tri(pb, tris[i].t[2], pc));
+ tris[i].t[0] = pa;
+ tris[i].t[1] = pb;
+ tris[i].t[2] = pc;
+ }
+ }
+
+ // index + scale
+ vector<Vec3> nodes;
+ for (size_t i=0; i<tris.size(); i++) {
+ for (int t=0; t<3; t++) {
+ Vec3 p = mCenter + tris[i].t[t] * mRadius * mScale;
+ // vector already there ?
+ int idx=nodes.size();
+ for (size_t j=0; j<nodes.size(); j++) {
+ if (p==nodes[j]) {
+ idx = j; break;
+ }
+ }
+ if (idx == (int)nodes.size())
+ nodes.push_back(p);
+ tris[i].i[t] = idx;
+ }
+ }
+
+ // add the to mesh
+ const int ni = mesh->numNodes();
+ for (size_t i=0; i<nodes.size(); i++) {
+ mesh->addNode(Node(nodes[i]));}
+ for (size_t t=0; t<tris.size(); t++)
+ mesh->addTri(Triangle(tris[t].i[0]+ni, tris[t].i[1]+ni, tris[t].i[2]+ni));
+
+ mesh->rebuildCorners(oldtri,-1);
+ mesh->rebuildLookup(oldtri,-1);
+}
+
+ struct SphereSDF : public KernelBase {
+ SphereSDF(Grid<Real>& phi, Vec3 center, Real radius, Vec3 scale) : KernelBase(&phi,0) ,phi(phi),center(center),radius(radius),scale(scale) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& phi, Vec3 center, Real radius, Vec3 scale ) const {
+ phi(i,j,k) = norm((Vec3(i+0.5,j+0.5,k+0.5)-center)/scale)-radius;
+} inline Grid<Real>& getArg0() {
+ return phi; }
+ typedef Grid<Real> type0;inline Vec3& getArg1() {
+ return center; }
+ typedef Vec3 type1;inline Real& getArg2() {
+ return radius; }
+ typedef Real type2;inline Vec3& getArg3() {
+ return scale; }
+ typedef Vec3 type3; void runMessage() { debMsg("Executing kernel SphereSDF ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,phi,center,radius,scale); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,phi,center,radius,scale); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<Real>& phi; Vec3 center; Real radius; Vec3 scale; }
+;
+void Sphere::generateLevelset(Grid<Real>& phi) {
+ SphereSDF(phi, mCenter, mRadius, mScale);
+}
+
+Cylinder::Cylinder(FluidSolver* parent, Vec3 center, Real radius, Vec3 z)
+ : Shape(parent), mCenter(center), mRadius(radius)
+{
+ mType = TypeCylinder;
+ mZDir = z;
+ mZ = normalize(mZDir);
+}
+
+bool Cylinder::isInside(const Vec3& pos) const {
+ Real z = dot(pos-mCenter, mZDir);
+ if (fabs(z) > mZ) return false;
+ Real r2 = normSquare(pos-mCenter)-square(z);
+ return r2 < square(mRadius);
+}
+
+void Cylinder::generateMesh(Mesh* mesh) {
+ // generate coordinate system
+ Vec3 x = getOrthogonalVector(mZDir)*mRadius;
+ Vec3 y = cross(x, mZDir);
+ Vec3 z = mZDir*mZ;
+ int oldtri = mesh->numTris();
+
+ // construct node ring
+ const int N = 20;
+ const int base = mesh->numNodes();
+ for (int i=0;i<N;i++) {
+ const Real phi = 2.0*M_PI*(Real)i/(Real)N;
+ Vec3 r = x*cos(phi) + y*sin(phi) + mCenter;
+ mesh->addNode(Node(r+z));
+ mesh->addNode(Node(r-z));
+ }
+ // top/bottom center
+ mesh->addNode(Node(mCenter+z));
+ mesh->addNode(Node(mCenter-z));
+
+ // connect with tris
+ for (int i=0;i<N;i++) {
+ int cur = base+2*i;
+ int next = base+2*((i+1)%N);
+ // outside
+ mesh->addTri(Triangle(cur, next, cur+1));
+ mesh->addTri(Triangle(next, next+1, cur+1));
+ // upper / lower
+ mesh->addTri(Triangle(cur,base+2*N,next));
+ mesh->addTri(Triangle(cur+1,next+1,base+2*N+1));
+ }
+
+ mesh->rebuildCorners(oldtri, -1);
+ mesh->rebuildLookup(oldtri,-1);
+}
+
+
+ struct CylinderSDF : public KernelBase {
+ CylinderSDF(Grid<Real>& phi, Vec3 center, Real radius, Vec3 zaxis, Real maxz) : KernelBase(&phi,0) ,phi(phi),center(center),radius(radius),zaxis(zaxis),maxz(maxz) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, Grid<Real>& phi, Vec3 center, Real radius, Vec3 zaxis, Real maxz ) const {
+ Vec3 p=Vec3(i+0.5,j+0.5,k+0.5)-center;
+ Real z = fabs(dot(p, zaxis));
+ Real r = sqrt(normSquare(p)-z*z);
+ if (z < maxz) {
+ // cylinder z area
+ if (r < radius)
+ phi(i,j,k) = max(r-radius,z-maxz);
+ else
+ phi(i,j,k) = r-radius;
+ } else if (r < radius) {
+ // cylinder top area
+ phi(i,j,k) = fabs(z-maxz);
+ } else {
+ // edge
+ phi(i,j,k) = sqrt(square(z-maxz)+square(r-radius));
+ }
+} inline Grid<Real>& getArg0() {
+ return phi; }
+ typedef Grid<Real> type0;inline Vec3& getArg1() {
+ return center; }
+ typedef Vec3 type1;inline Real& getArg2() {
+ return radius; }
+ typedef Real type2;inline Vec3& getArg3() {
+ return zaxis; }
+ typedef Vec3 type3;inline Real& getArg4() {
+ return maxz; }
+ typedef Real type4; void runMessage() { debMsg("Executing kernel CylinderSDF ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,phi,center,radius,zaxis,maxz); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,phi,center,radius,zaxis,maxz); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ Grid<Real>& phi; Vec3 center; Real radius; Vec3 zaxis; Real maxz; }
+;
+void Cylinder::generateLevelset(Grid<Real>& phi) {
+ CylinderSDF(phi, mCenter, mRadius, mZDir, mZ);
+}
+
+Slope::Slope(FluidSolver* parent, Real anglexy, Real angleyz, Real origin, Vec3 gs)
+ : Shape(parent), mAnglexy(anglexy), mAngleyz(angleyz), mOrigin(origin), mGs(gs)
+{
+ mType = TypeSlope;
+}
+
+void Slope::generateMesh(Mesh* mesh) {
+
+ const int oldtri = mesh->numTris();
+
+ Vec3 v1(0.,mOrigin,0.);
+ mesh->addNode(Node(v1));
+
+ Real dy1 = mGs.z * std::tan(mAngleyz);
+ Vec3 v2(0., mOrigin - dy1, mGs.z);
+ mesh->addNode(Node(v2));
+
+ Real dy2 = mGs.x * std::tan(mAnglexy);
+ Vec3 v3(mGs.x, v2.y - dy2, mGs.z);
+ mesh->addNode(Node(v3));
+
+ Vec3 v4(mGs.x, mOrigin - dy2, 0.);
+ mesh->addNode(Node(v4));
+
+ mesh->addTri(Triangle(0, 1, 2));
+ mesh->addTri(Triangle(2, 3, 0));
+
+ mesh->rebuildCorners(oldtri, -1);
+ mesh->rebuildLookup(oldtri,-1);
+
+}
+
+bool Slope::isInside(const Vec3& pos) const {
+
+ const Real alpha = -mAnglexy * M_PI / 180.;
+ const Real beta = -mAngleyz * M_PI / 180.;
+
+ Vec3 n(0,1,0);
+
+ n.x = std::sin(alpha)*std::cos(beta);
+ n.y = std::cos(alpha)*std::cos(beta);
+ n.z = std::sin(beta);
+
+ normalize(n);
+
+ const Real fac = std::sqrt(n.x*n.x + n.y*n.y + n.z*n.z);
+
+ return ((n.x*(double)pos.x + n.y*(double)pos.y + n.z*(double)pos.z - mOrigin) / fac) <= 0.;
+
+
+}
+
+ struct SlopeSDF : public KernelBase {
+ SlopeSDF(const Vec3 &n, Grid<Real> &phiObs, const Real &fac, const Real &origin) : KernelBase(&phiObs,0) ,n(n),phiObs(phiObs),fac(fac),origin(origin) {
+ runMessage(); run(); }
+ inline void op(int i, int j, int k, const Vec3 &n, Grid<Real> &phiObs, const Real &fac, const Real &origin ) const {
+
+ phiObs(i,j,k) = (n.x*(double)i + n.y*(double)j + n.z*(double)k - origin) * fac;
+
+} inline const Vec3& getArg0() {
+ return n; }
+ typedef Vec3 type0;inline Grid<Real> & getArg1() {
+ return phiObs; }
+ typedef Grid<Real> type1;inline const Real& getArg2() {
+ return fac; }
+ typedef Real type2;inline const Real& getArg3() {
+ return origin; }
+ typedef Real type3; void runMessage() { debMsg("Executing kernel SlopeSDF ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ const int _maxX = maxX; const int _maxY = maxY; if (maxZ>1) {
+ for (int k=__r.begin(); k!=(int)__r.end(); k++) for (int j=0; j<_maxY; j++) for (int i=0; i<_maxX; i++) op(i,j,k,n,phiObs,fac,origin); }
+ else {
+ const int k=0; for (int j=__r.begin(); j!=(int)__r.end(); j++) for (int i=0; i<_maxX; i++) op(i,j,k,n,phiObs,fac,origin); }
+ }
+ void run() {
+ if (maxZ>1) tbb::parallel_for (tbb::blocked_range<IndexInt>(minZ, maxZ), *this); else tbb::parallel_for (tbb::blocked_range<IndexInt>(0, maxY), *this); }
+ const Vec3& n; Grid<Real> & phiObs; const Real& fac; const Real& origin; }
+;
+
+void Slope::generateLevelset(Grid<Real>& phi) {
+
+ const Real alpha = -mAnglexy * M_PI / 180.;
+ const Real beta = -mAngleyz * M_PI / 180.;
+
+ Vec3 n(0,1,0);
+
+ n.x = std::sin(alpha)*std::cos(beta);
+ n.y = std::cos(alpha)*std::cos(beta);
+ n.z = std::sin(beta);
+
+ normalize(n);
+
+ const Real fac = 1. / std::sqrt(n.x*n.x + n.y*n.y + n.z*n.z);
+
+ SlopeSDF(n, phi, fac, mOrigin);
+
+}
+
+} //namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h
new file mode 100644
index 00000000000..f36c7ec232b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h
@@ -0,0 +1,285 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * shapes classes
+ *
+ ******************************************************************************/
+
+#ifndef _SHAPES_H
+#define _SHAPES_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include "levelset.h"
+
+namespace Manta {
+
+// forward declaration
+class Mesh;
+
+//! Base class for all shapes
+class Shape : public PbClass {public:
+ enum GridType { TypeNone = 0, TypeBox = 1, TypeSphere = 2, TypeCylinder = 3, TypeSlope = 4 };
+
+ Shape(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Shape::Shape" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new Shape(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Shape::Shape" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Shape::Shape",e.what()); return -1; }
+ }
+
+
+ //! Get the type of grid
+ inline GridType getType() const { return mType; }
+
+ //! Apply shape to flag grid, set inside cells to <value>
+ void applyToGrid(GridBase* grid, FlagGrid* respectFlags=0); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::applyToGrid" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; GridBase* grid = _args.getPtr<GridBase >("grid",0,&_lock); FlagGrid* respectFlags = _args.getPtrOpt<FlagGrid >("respectFlags",1,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->applyToGrid(grid,respectFlags); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::applyToGrid" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::applyToGrid",e.what()); return 0; }
+ }
+
+ void applyToGridSmooth(GridBase* grid, Real sigma=1.0, Real shift=0, FlagGrid* respectFlags=0); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::applyToGridSmooth" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; GridBase* grid = _args.getPtr<GridBase >("grid",0,&_lock); Real sigma = _args.getOpt<Real >("sigma",1,1.0,&_lock); Real shift = _args.getOpt<Real >("shift",2,0,&_lock); FlagGrid* respectFlags = _args.getPtrOpt<FlagGrid >("respectFlags",3,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->applyToGridSmooth(grid,sigma,shift,respectFlags); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::applyToGridSmooth" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::applyToGridSmooth",e.what()); return 0; }
+ }
+
+ LevelsetGrid computeLevelset(); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::computeLevelset" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->computeLevelset()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::computeLevelset" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::computeLevelset",e.what()); return 0; }
+ }
+
+ void collideMesh(Mesh& mesh); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::collideMesh" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->collideMesh(mesh); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::collideMesh" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::collideMesh",e.what()); return 0; }
+ }
+
+ virtual Vec3 getCenter() const { return Vec3::Zero; } static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::getCenter" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getCenter()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::getCenter" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::getCenter",e.what()); return 0; }
+ }
+
+ virtual void setCenter(const Vec3& center) {} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::setCenter" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; const Vec3& center = _args.get<Vec3 >("center",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setCenter(center); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::setCenter" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::setCenter",e.what()); return 0; }
+ }
+
+ virtual Vec3 getExtent() const { return Vec3::Zero; } static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Shape* pbo = dynamic_cast<Shape*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Shape::getExtent" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getExtent()); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Shape::getExtent" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Shape::getExtent",e.what()); return 0; }
+ }
+
+
+ //! Inside test of the shape
+ virtual bool isInside(const Vec3& pos) const;
+ inline bool isInsideGrid(int i, int j, int k) const { return isInside(Vec3(i+0.5,j+0.5,k+0.5)); };
+
+ virtual void generateMesh(Mesh* mesh) {} ;
+ virtual void generateLevelset(Grid<Real>& phi) {};
+
+protected: GridType mType; public: PbArgs _args; }
+#define _C_Shape
+;
+
+//! Dummy shape
+class NullShape : public Shape {
+public:
+ NullShape(FluidSolver* parent) :Shape(parent){} static int _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "NullShape::NullShape" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new NullShape(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"NullShape::NullShape" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("NullShape::NullShape",e.what()); return -1; }
+ }
+
+
+ virtual bool isInside(const Vec3& pos) const { return false; }
+ virtual void generateMesh(Mesh* mesh) {}
+
+protected: virtual void generateLevelset(Grid<Real>& phi) { gridSetConst<Real>( phi , 1000.0f ); } public: PbArgs _args; }
+#define _C_NullShape
+;
+
+//! Box shape
+class Box : public Shape {
+public:
+ Box(FluidSolver* parent, Vec3 center = Vec3::Invalid, Vec3 p0 = Vec3::Invalid, Vec3 p1 = Vec3::Invalid, Vec3 size = Vec3::Invalid); static int _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Box::Box" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); Vec3 center = _args.getOpt<Vec3 >("center",1,Vec3::Invalid,&_lock); Vec3 p0 = _args.getOpt<Vec3 >("p0",2,Vec3::Invalid,&_lock); Vec3 p1 = _args.getOpt<Vec3 >("p1",3,Vec3::Invalid,&_lock); Vec3 size = _args.getOpt<Vec3 >("size",4,Vec3::Invalid,&_lock); obj = new Box(parent,center,p0,p1,size); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Box::Box" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Box::Box",e.what()); return -1; }
+ }
+
+
+ inline Vec3 getSize() const { return mP1-mP0; }
+ inline Vec3 getP0() const { return mP0; }
+ inline Vec3 getP1() const { return mP1; }
+ virtual void setCenter(const Vec3& center) { Vec3 dh=0.5*(mP1-mP0); mP0 = center-dh; mP1 = center+dh;}
+ virtual Vec3 getCenter() const { return 0.5*(mP1+mP0); }
+ virtual Vec3 getExtent() const { return getSize(); }
+ virtual bool isInside(const Vec3& pos) const;
+ virtual void generateMesh(Mesh* mesh);
+ virtual void generateLevelset(Grid<Real>& phi);
+
+protected: Vec3 mP0, mP1; public: PbArgs _args; }
+#define _C_Box
+;
+
+//! Spherical shape
+class Sphere : public Shape {
+public:
+ Sphere(FluidSolver* parent, Vec3 center, Real radius, Vec3 scale=Vec3(1,1,1)); static int _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Sphere::Sphere" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); Vec3 center = _args.get<Vec3 >("center",1,&_lock); Real radius = _args.get<Real >("radius",2,&_lock); Vec3 scale = _args.getOpt<Vec3 >("scale",3,Vec3(1,1,1),&_lock); obj = new Sphere(parent,center,radius,scale); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Sphere::Sphere" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Sphere::Sphere",e.what()); return -1; }
+ }
+
+
+ virtual void setCenter(const Vec3& center) { mCenter = center; }
+ virtual Vec3 getCenter() const { return mCenter; }
+ inline Real getRadius() const { return mRadius; }
+ virtual Vec3 getExtent() const { return Vec3(2.0*mRadius); }
+ virtual bool isInside(const Vec3& pos) const;
+ virtual void generateMesh(Mesh* mesh);
+ virtual void generateLevelset(Grid<Real>& phi);
+
+protected:
+ Vec3 mCenter, mScale; Real mRadius; public: PbArgs _args; }
+#define _C_Sphere
+;
+
+//! Cylindrical shape
+class Cylinder : public Shape {
+public:
+ Cylinder(FluidSolver* parent, Vec3 center, Real radius, Vec3 z); static int _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Cylinder::Cylinder" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); Vec3 center = _args.get<Vec3 >("center",1,&_lock); Real radius = _args.get<Real >("radius",2,&_lock); Vec3 z = _args.get<Vec3 >("z",3,&_lock); obj = new Cylinder(parent,center,radius,z); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Cylinder::Cylinder" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Cylinder::Cylinder",e.what()); return -1; }
+ }
+
+
+ void setRadius(Real r) { mRadius = r; } static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Cylinder* pbo = dynamic_cast<Cylinder*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Cylinder::setRadius" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real r = _args.get<Real >("r",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setRadius(r); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Cylinder::setRadius" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Cylinder::setRadius",e.what()); return 0; }
+ }
+
+ void setZ(Vec3 z) { mZDir=z; mZ=normalize(mZDir); } static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Cylinder* pbo = dynamic_cast<Cylinder*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Cylinder::setZ" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Vec3 z = _args.get<Vec3 >("z",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setZ(z); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Cylinder::setZ" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Cylinder::setZ",e.what()); return 0; }
+ }
+
+
+ virtual void setCenter(const Vec3& center) { mCenter=center; }
+ virtual Vec3 getCenter() const { return mCenter; }
+ inline Real getRadius() const { return mRadius; }
+ inline Vec3 getZ() const { return mZ*mZDir; }
+ virtual Vec3 getExtent() const { return Vec3(2.0*sqrt(square(mZ)+square(mRadius))); }
+ virtual bool isInside(const Vec3& pos) const;
+ virtual void generateMesh(Mesh* mesh);
+ virtual void generateLevelset(Grid<Real>& phi);
+
+protected:
+ Vec3 mCenter, mZDir; Real mRadius, mZ; public: PbArgs _args; }
+#define _C_Cylinder
+;
+
+//! Slope shape
+// generates a levelset based on a plane
+// plane is specified by two angles and an offset on the y axis in (offset vector would be ( 0, offset, 0) )
+// the two angles are specified in degrees, between: y-axis and x-axis
+// y-axis and z-axis
+class Slope : public Shape {public:
+ Slope(FluidSolver* parent, Real anglexy, Real angleyz, Real origin, Vec3 gs); static int _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Slope::Slope" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); Real anglexy = _args.get<Real >("anglexy",1,&_lock); Real angleyz = _args.get<Real >("angleyz",2,&_lock); Real origin = _args.get<Real >("origin",3,&_lock); Vec3 gs = _args.get<Vec3 >("gs",4,&_lock); obj = new Slope(parent,anglexy,angleyz,origin,gs); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Slope::Slope" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Slope::Slope",e.what()); return -1; }
+ }
+
+
+ virtual void setOrigin (const Real& origin) { mOrigin=origin; }
+ virtual void setAnglexy(const Real& anglexy) { mAnglexy=anglexy; }
+ virtual void setAngleyz(const Real& angleyz) { mAnglexy=angleyz; }
+
+ inline Real getOrigin() const { return mOrigin; }
+ inline Real getmAnglexy() const { return mAnglexy; }
+ inline Real getmAngleyz() const { return mAngleyz; }
+ virtual bool isInside(const Vec3& pos) const;
+ virtual void generateMesh(Mesh* mesh);
+ virtual void generateLevelset(Grid<Real>& phi);
+
+protected:
+ Real mAnglexy, mAngleyz;
+ Real mOrigin; Vec3 mGs; public: PbArgs _args; }
+#define _C_Slope
+;
+
+} //namespace
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h.reg
new file mode 100644
index 00000000000..31a77644b43
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h.reg
@@ -0,0 +1,28 @@
+#include "shapes.h"
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","Shape","PbClass"); template<> const char* Namify<Shape >::S = "Shape";
+>Shape^
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","Shape",Shape::_W_0);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","applyToGrid",Shape::_W_1);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","applyToGridSmooth",Shape::_W_2);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","computeLevelset",Shape::_W_3);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","collideMesh",Shape::_W_4);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","getCenter",Shape::_W_5);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","setCenter",Shape::_W_6);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","getExtent",Shape::_W_7);
++NullShape^ static const Pb::Register _R_$IDX$ ("NullShape","NullShape","Shape"); template<> const char* Namify<NullShape >::S = "NullShape";
+>NullShape^
++NullShape^ static const Pb::Register _R_$IDX$ ("NullShape","NullShape",NullShape::_W_8);
++Box^ static const Pb::Register _R_$IDX$ ("Box","Box","Shape"); template<> const char* Namify<Box >::S = "Box";
+>Box^
++Box^ static const Pb::Register _R_$IDX$ ("Box","Box",Box::_W_9);
++Sphere^ static const Pb::Register _R_$IDX$ ("Sphere","Sphere","Shape"); template<> const char* Namify<Sphere >::S = "Sphere";
+>Sphere^
++Sphere^ static const Pb::Register _R_$IDX$ ("Sphere","Sphere",Sphere::_W_10);
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","Cylinder","Shape"); template<> const char* Namify<Cylinder >::S = "Cylinder";
+>Cylinder^
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","Cylinder",Cylinder::_W_11);
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","setRadius",Cylinder::_W_12);
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","setZ",Cylinder::_W_13);
++Slope^ static const Pb::Register _R_$IDX$ ("Slope","Slope","Shape"); template<> const char* Namify<Slope >::S = "Slope";
+>Slope^
++Slope^ static const Pb::Register _R_$IDX$ ("Slope","Slope",Slope::_W_14);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h.reg.cpp
new file mode 100644
index 00000000000..719de2e65e6
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/shapes.h.reg.cpp
@@ -0,0 +1,72 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "shapes.h"
+namespace Manta {
+#ifdef _C_Box
+ static const Pb::Register _R_12 ("Box","Box","Shape"); template<> const char* Namify<Box >::S = "Box";
+ static const Pb::Register _R_13 ("Box","Box",Box::_W_9);
+#endif
+#ifdef _C_Cylinder
+ static const Pb::Register _R_14 ("Cylinder","Cylinder","Shape"); template<> const char* Namify<Cylinder >::S = "Cylinder";
+ static const Pb::Register _R_15 ("Cylinder","Cylinder",Cylinder::_W_11);
+ static const Pb::Register _R_16 ("Cylinder","setRadius",Cylinder::_W_12);
+ static const Pb::Register _R_17 ("Cylinder","setZ",Cylinder::_W_13);
+#endif
+#ifdef _C_NullShape
+ static const Pb::Register _R_18 ("NullShape","NullShape","Shape"); template<> const char* Namify<NullShape >::S = "NullShape";
+ static const Pb::Register _R_19 ("NullShape","NullShape",NullShape::_W_8);
+#endif
+#ifdef _C_Shape
+ static const Pb::Register _R_20 ("Shape","Shape","PbClass"); template<> const char* Namify<Shape >::S = "Shape";
+ static const Pb::Register _R_21 ("Shape","Shape",Shape::_W_0);
+ static const Pb::Register _R_22 ("Shape","applyToGrid",Shape::_W_1);
+ static const Pb::Register _R_23 ("Shape","applyToGridSmooth",Shape::_W_2);
+ static const Pb::Register _R_24 ("Shape","computeLevelset",Shape::_W_3);
+ static const Pb::Register _R_25 ("Shape","collideMesh",Shape::_W_4);
+ static const Pb::Register _R_26 ("Shape","getCenter",Shape::_W_5);
+ static const Pb::Register _R_27 ("Shape","setCenter",Shape::_W_6);
+ static const Pb::Register _R_28 ("Shape","getExtent",Shape::_W_7);
+#endif
+#ifdef _C_Slope
+ static const Pb::Register _R_29 ("Slope","Slope","Shape"); template<> const char* Namify<Slope >::S = "Slope";
+ static const Pb::Register _R_30 ("Slope","Slope",Slope::_W_14);
+#endif
+#ifdef _C_Sphere
+ static const Pb::Register _R_31 ("Sphere","Sphere","Shape"); template<> const char* Namify<Sphere >::S = "Sphere";
+ static const Pb::Register _R_32 ("Sphere","Sphere",Sphere::_W_10);
+#endif
+extern "C" {
+void PbRegister_file_12()
+{
+ KEEP_UNUSED(_R_12);
+ KEEP_UNUSED(_R_13);
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/test.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/test.cpp
new file mode 100644
index 00000000000..accbd488afe
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/test.cpp
@@ -0,0 +1,93 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Use this file to test new functionality
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include <cmath>
+
+using namespace std;
+
+namespace Manta {
+
+// two simple example kernels
+
+
+
+ struct reductionTest : public KernelBase {
+ reductionTest(const Grid<Real>& v) : KernelBase(&v,0) ,v(v) ,sum(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& v ,double& sum) {
+ sum += v[idx];
+} inline operator double () {
+ return sum; }
+ inline double & getRet() {
+ return sum; }
+ inline const Grid<Real>& getArg0() {
+ return v; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel reductionTest ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, v,sum); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ reductionTest (reductionTest& o, tbb::split) : KernelBase(o) ,v(o.v) ,sum(0) {
+}
+ void join(const reductionTest & o) {
+ sum += o.sum; }
+ const Grid<Real>& v; double sum; }
+;
+
+
+
+ struct minReduction : public KernelBase {
+ minReduction(const Grid<Real>& v) : KernelBase(&v,0) ,v(v) ,sum(0) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, const Grid<Real>& v ,double& sum) {
+ if (sum < v[idx])
+ sum = v[idx];
+} inline operator double () {
+ return sum; }
+ inline double & getRet() {
+ return sum; }
+ inline const Grid<Real>& getArg0() {
+ return v; }
+ typedef Grid<Real> type0; void runMessage() { debMsg("Executing kernel minReduction ", 3); debMsg("Kernel range" << " x "<< maxX << " y "<< maxY << " z "<< minZ<<" - "<< maxZ << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, v,sum); }
+ void run() {
+ tbb::parallel_reduce (tbb::blocked_range<IndexInt>(0, size), *this); }
+ minReduction (minReduction& o, tbb::split) : KernelBase(o) ,v(o.v) ,sum(0) {
+}
+ void join(const minReduction & o) {
+ sum = min(sum,o.sum); }
+ const Grid<Real>& v; double sum; }
+;
+
+
+
+
+// ... add more test code here if necessary ...
+
+} //namespace
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.cpp
new file mode 100644
index 00000000000..b7fc69d4875
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.cpp
@@ -0,0 +1,128 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugin timing
+ *
+ ******************************************************************************/
+
+#include "timing.h"
+#include <fstream>
+
+using namespace std;
+namespace Manta {
+
+TimingData::TimingData() : updated(false), num(0) {
+}
+
+void TimingData::start(FluidSolver* parent, const string& name) {
+ mLastPlugin = name;
+ mPluginTimer.get();
+}
+
+void TimingData::stop(FluidSolver* parent, const string& name) {
+ if (mLastPlugin == name && name != "FluidSolver::step") {
+ updated = true;
+ const string parentName = parent ? parent->getName() : "";
+ MuTime diff = mPluginTimer.update();
+ vector<TimingSet>& cur = mData[name];
+ for (vector<TimingSet>::iterator it = cur.begin(); it != cur.end(); it++) {
+ if (it->solver == parentName) {
+ it->cur += diff;
+ it->updated = true;
+ return;
+ }
+ }
+ TimingSet s;
+ s.solver = parentName;
+ s.cur = diff;
+ s.updated = true;
+ cur.push_back(s);
+ }
+}
+
+void TimingData::step() {
+ if (updated)
+ num++;
+ std::map<std::string, std::vector<TimingSet> >::iterator it;
+ for (it = mData.begin(); it != mData.end(); it++) {
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) {
+ if (it2->updated) {
+ it2->total += it2->cur;
+ it2->num++;
+ }
+ it2->cur.clear();
+ it2->updated = false;
+ }
+ }
+ updated = false;
+}
+
+void TimingData::print() {
+ MuTime total;
+ total.clear();
+ std::map<std::string, std::vector<TimingSet> >::iterator it;
+ for (it = mData.begin(); it != mData.end(); it++)
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++)
+ total += it2->cur;
+
+ printf("\n-- STEP %3d ----------------------------\n", num);
+ for (it = mData.begin(); it != mData.end(); it++) {
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) {
+ if (!it2->updated) continue;
+ string name = it->first;
+ if (it->second.size() > 1 && !it2->solver.empty())
+ name += "[" + it2->solver + "]";
+ printf("[%4.1f%%] %s (%s)\n", 100.0*((Real)it2->cur.time / (Real)total.time),
+ name.c_str(), it2->cur.toString().c_str());
+ }
+ }
+ step();
+
+ printf("----------------------------------------\n");
+ printf("Total : %s\n\n", total.toString().c_str());
+}
+
+void TimingData::saveMean(const string& filename) {
+ ofstream ofs(filename.c_str());
+ step();
+ if (!ofs.good())
+ errMsg("can't open " + filename + " as timing log");
+ ofs << "Mean timings of " << num << " steps :" <<endl <<endl;
+ MuTime total;
+ total.clear();
+ std::map<std::string, std::vector<TimingSet> >::iterator it;
+ for (it = mData.begin(); it != mData.end(); it++)
+ for (vector<TimingSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) {
+ total += it2->cur;
+ string name = it->first;
+ if (it->second.size() > 1)
+ name += "[" + it2->solver + "]";
+
+ ofs << name << " " << (it2->total / it2->num) << endl;
+ }
+
+ ofs << endl << "Total : " << total << " (mean " << total/num << ")" << endl;
+ ofs.close();
+}
+
+}
+
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h
new file mode 100644
index 00000000000..092377cdcdc
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h
@@ -0,0 +1,96 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugin timing
+ *
+ ******************************************************************************/
+
+#ifndef _TIMING_H
+#define _TIMING_H
+
+#include "manta.h"
+#include <map>
+namespace Manta {
+
+
+class TimingData {
+private:
+ TimingData();
+public:
+ static TimingData& instance() { static TimingData a; return a; }
+
+ void print();
+ void saveMean(const std::string& filename);
+ void start(FluidSolver* parent, const std::string& name);
+ void stop(FluidSolver* parent, const std::string& name);
+protected:
+ void step();
+ struct TimingSet {
+ TimingSet() : num(0),updated(false) { cur.clear(); total.clear(); }
+ MuTime cur, total;
+ int num;
+ bool updated;
+ std::string solver;
+ };
+ bool updated;
+
+ int num;
+ MuTime mPluginTimer;
+ std::string mLastPlugin;
+ std::map<std::string, std::vector<TimingSet> > mData;
+};
+
+// Python interface
+class Timings : public PbClass {public:
+ Timings() :PbClass(0){} static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "Timings::Timings" , !noTiming ); {
+ ArgLocker _lock; obj = new Timings(); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"Timings::Timings" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("Timings::Timings",e.what()); return -1; }
+ }
+
+
+ void display() { TimingData::instance().print(); } static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Timings* pbo = dynamic_cast<Timings*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Timings::display" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->display(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Timings::display" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Timings::display",e.what()); return 0; }
+ }
+ void saveMean(std::string file) { TimingData::instance().saveMean(file); } static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); Timings* pbo = dynamic_cast<Timings*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "Timings::saveMean" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; std::string file = _args.get<std::string >("file",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->saveMean(file); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"Timings::saveMean" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("Timings::saveMean",e.what()); return 0; }
+ }
+ public: PbArgs _args; }
+#define _C_Timings
+;
+
+}
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h.reg
new file mode 100644
index 00000000000..4a653bf381d
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h.reg
@@ -0,0 +1,6 @@
+#include "timing.h"
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","Timings","PbClass"); template<> const char* Namify<Timings >::S = "Timings";
+>Timings^
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","Timings",Timings::_W_0);
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","display",Timings::_W_1);
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","saveMean",Timings::_W_2);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h.reg.cpp
new file mode 100644
index 00000000000..2217b5188f4
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/timing.h.reg.cpp
@@ -0,0 +1,28 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "timing.h"
+namespace Manta {
+#ifdef _C_Timings
+ static const Pb::Register _R_16 ("Timings","Timings","PbClass"); template<> const char* Namify<Timings >::S = "Timings";
+ static const Pb::Register _R_17 ("Timings","Timings",Timings::_W_0);
+ static const Pb::Register _R_18 ("Timings","display",Timings::_W_1);
+ static const Pb::Register _R_19 ("Timings","saveMean",Timings::_W_2);
+#endif
+extern "C" {
+void PbRegister_file_16()
+{
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+ KEEP_UNUSED(_R_19);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.cpp
new file mode 100644
index 00000000000..7a71ffa64d6
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.cpp
@@ -0,0 +1,182 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.ynu.org/licenses
+ *
+ * Turbulence particles
+ *
+ ******************************************************************************/
+
+#include "turbulencepart.h"
+#include "shapes.h"
+#include "randomstream.h"
+
+using namespace std;
+namespace Manta {
+
+TurbulenceParticleSystem::TurbulenceParticleSystem(FluidSolver* parent, WaveletNoiseField& noise) :
+ ParticleSystem<TurbulenceParticleData>(parent), noise(noise)
+{
+}
+
+ParticleBase* TurbulenceParticleSystem::clone() {
+ TurbulenceParticleSystem* nm = new TurbulenceParticleSystem(getParent(), noise);
+ compress();
+
+ nm->mData = mData;
+ nm->setName(getName());
+ return nm;
+}
+
+inline Vec3 hsv2rgb(Real h, Real s, Real v){
+ Real r=0, g=0, b=0;
+
+ int i = (int)(h * 6);
+ Real f = h * 6 - i;
+ Real p = v * (1 - s);
+ Real q = v * (1 - f * s);
+ Real t = v * (1 - (1 - f) * s);
+
+ switch(i % 6){
+ case 0: r = v, g = t, b = p; break;
+ case 1: r = q, g = v, b = p; break;
+ case 2: r = p, g = v, b = t; break;
+ case 3: r = p, g = q, b = v; break;
+ case 4: r = t, g = p, b = v; break;
+ case 5: r = v, g = p, b = q; break;
+ default: break;
+ }
+
+ return Vec3(r,g,b);
+}
+
+void TurbulenceParticleSystem::seed(Shape* shape, int num) {
+ static RandomStream rand(34894231);
+ Vec3 sz = shape->getExtent(), p0 = shape->getCenter() - sz*0.5;
+ for (int i=0; i<num; i++) {
+ Vec3 p;
+ do {
+ p = rand.getVec3() * sz + p0;
+ } while(!shape->isInside(p));
+ Real z = (p.z - p0.z)/sz.z;
+ add(TurbulenceParticleData(p,hsv2rgb(z,0.75,1.0)));
+ }
+}
+
+void TurbulenceParticleSystem::resetTexCoords(int num, const Vec3& inflow ) {
+ if (num==0) {
+ for (int i=0; i<size(); i++) mData[i].tex0 = mData[i].pos - inflow;
+ } else {
+ for (int i=0; i<size(); i++) mData[i].tex1 = mData[i].pos - inflow;
+ }
+}
+
+
+
+
+ struct KnSynthesizeTurbulence : public KernelBase {
+ KnSynthesizeTurbulence(TurbulenceParticleSystem& p, FlagGrid& flags, WaveletNoiseField& noise, Grid<Real>& kGrid, Real alpha, Real dt, int octaves, Real scale, Real invL0, Real kmin) : KernelBase(p.size()) ,p(p),flags(flags),noise(noise),kGrid(kGrid),alpha(alpha),dt(dt),octaves(octaves),scale(scale),invL0(invL0),kmin(kmin) {
+ runMessage(); run(); }
+ inline void op(IndexInt idx, TurbulenceParticleSystem& p, FlagGrid& flags, WaveletNoiseField& noise, Grid<Real>& kGrid, Real alpha, Real dt, int octaves, Real scale, Real invL0, Real kmin ) const {
+ const Real PERSISTENCE = 0.56123f;
+
+ const Vec3 pos(p[idx].pos);
+ if (flags.isInBounds(pos)) { // && !flags.isObstacle(pos)) {
+ Real k2 = kGrid.getInterpolated(pos)-kmin;
+ Real ks = k2<0 ? 0.0 : sqrt(k2);
+
+ // Wavelet noise lookup
+ Real amplitude = scale * ks;
+ Real multiplier = invL0;
+ Vec3 vel(0.);
+ for (int o=0; o<octaves; o++) {
+ //Vec3 ns = noise.evaluateCurl(p[i].pos * multiplier) * amplitude;
+ Vec3 n0 = noise.evaluateCurl(p[idx].tex0 * multiplier) * amplitude;
+ Vec3 n1 = noise.evaluateCurl(p[idx].tex1 * multiplier) * amplitude;
+ vel += alpha * n0 + (1.0f-alpha) * n1;
+
+ // next scale
+ amplitude *= PERSISTENCE;
+ multiplier *= 2.0f;
+ }
+
+ // advection
+ Vec3 dx = vel*dt;
+ p[idx].pos += dx;
+ p[idx].tex0 += dx;
+ p[idx].tex1 += dx;
+ }
+} inline TurbulenceParticleSystem& getArg0() {
+ return p; }
+ typedef TurbulenceParticleSystem type0;inline FlagGrid& getArg1() {
+ return flags; }
+ typedef FlagGrid type1;inline WaveletNoiseField& getArg2() {
+ return noise; }
+ typedef WaveletNoiseField type2;inline Grid<Real>& getArg3() {
+ return kGrid; }
+ typedef Grid<Real> type3;inline Real& getArg4() {
+ return alpha; }
+ typedef Real type4;inline Real& getArg5() {
+ return dt; }
+ typedef Real type5;inline int& getArg6() {
+ return octaves; }
+ typedef int type6;inline Real& getArg7() {
+ return scale; }
+ typedef Real type7;inline Real& getArg8() {
+ return invL0; }
+ typedef Real type8;inline Real& getArg9() {
+ return kmin; }
+ typedef Real type9; void runMessage() { debMsg("Executing kernel KnSynthesizeTurbulence ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, p,flags,noise,kGrid,alpha,dt,octaves,scale,invL0,kmin); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ TurbulenceParticleSystem& p; FlagGrid& flags; WaveletNoiseField& noise; Grid<Real>& kGrid; Real alpha; Real dt; int octaves; Real scale; Real invL0; Real kmin; }
+;
+
+void TurbulenceParticleSystem::synthesize(FlagGrid& flags, Grid<Real>& k, int octaves, Real switchLength, Real L0, Real scale, Vec3 inflowBias) {
+ static Real ctime = 0;
+ static Vec3 inflow(0.);
+ Real dt = getParent()->getDt();
+
+ // collect inflow bias
+ inflow += inflowBias * dt;
+
+ // alpha: hat function over time
+ Real oldAlpha = 2.0f*nmod(ctime/switchLength, Real(1.0) );
+ ctime += dt;
+ Real alpha = 2.0f*nmod(ctime/switchLength, Real(1.0) );
+
+ if (oldAlpha < 1.0f && alpha >= 1.0f) resetTexCoords(0, inflow);
+ if (oldAlpha > alpha) resetTexCoords(1, inflow);
+ if (alpha>1.0f) alpha=2.0f-alpha;
+ alpha = 1.0;
+
+ KnSynthesizeTurbulence(*this, flags, noise, k, alpha, dt, octaves, scale, 1.0f/L0, 1.5*square(0.1));
+}
+
+void TurbulenceParticleSystem::deleteInObstacle(FlagGrid& flags) {
+ for (int i=0; i<size(); i++)
+ if (flags.isObstacle(mData[i].pos))
+ mData[i].flag |= PDELETE;
+ compress();
+}
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h
new file mode 100644
index 00000000000..5ef50b44fcb
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h
@@ -0,0 +1,105 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Turbulence particles
+ *
+ ******************************************************************************/
+
+#ifndef _TURBULENCEPART_H_
+#define _TURBULENCEPART_H_
+
+#include "particle.h"
+#include "noisefield.h"
+
+namespace Manta {
+class Shape;
+
+
+
+struct TurbulenceParticleData {
+ TurbulenceParticleData() : pos(0.0),color(1.),tex0(0.0),tex1(0.0),flag(0) {}
+ TurbulenceParticleData(const Vec3& p, const Vec3& color = Vec3(1.)) : pos(p),color(color),tex0(p),tex1(p),flag(0) {}
+ Vec3 pos, color;
+ Vec3 tex0, tex1;
+ int flag;
+ static ParticleBase::SystemType getType() { return ParticleBase::TURBULENCE; }
+};
+
+//! Turbulence particles
+class TurbulenceParticleSystem : public ParticleSystem<TurbulenceParticleData> {public:
+ TurbulenceParticleSystem(FluidSolver* parent, WaveletNoiseField& noise); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "TurbulenceParticleSystem::TurbulenceParticleSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",1,&_lock); obj = new TurbulenceParticleSystem(parent,noise); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"TurbulenceParticleSystem::TurbulenceParticleSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("TurbulenceParticleSystem::TurbulenceParticleSystem",e.what()); return -1; }
+ }
+
+
+ void resetTexCoords(int num, const Vec3& inflow); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); TurbulenceParticleSystem* pbo = dynamic_cast<TurbulenceParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::resetTexCoords" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; int num = _args.get<int >("num",0,&_lock); const Vec3& inflow = _args.get<Vec3 >("inflow",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->resetTexCoords(num,inflow); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"TurbulenceParticleSystem::resetTexCoords" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("TurbulenceParticleSystem::resetTexCoords",e.what()); return 0; }
+ }
+
+ void seed(Shape* source, int num); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); TurbulenceParticleSystem* pbo = dynamic_cast<TurbulenceParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::seed" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Shape* source = _args.getPtr<Shape >("source",0,&_lock); int num = _args.get<int >("num",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->seed(source,num); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"TurbulenceParticleSystem::seed" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("TurbulenceParticleSystem::seed",e.what()); return 0; }
+ }
+
+ void synthesize(FlagGrid& flags, Grid<Real>& k, int octaves=2, Real switchLength=10.0, Real L0=0.1, Real scale=1.0, Vec3 inflowBias=0.0); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); TurbulenceParticleSystem* pbo = dynamic_cast<TurbulenceParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::synthesize" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& k = *_args.getPtr<Grid<Real> >("k",1,&_lock); int octaves = _args.getOpt<int >("octaves",2,2,&_lock); Real switchLength = _args.getOpt<Real >("switchLength",3,10.0,&_lock); Real L0 = _args.getOpt<Real >("L0",4,0.1,&_lock); Real scale = _args.getOpt<Real >("scale",5,1.0,&_lock); Vec3 inflowBias = _args.getOpt<Vec3 >("inflowBias",6,0.0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->synthesize(flags,k,octaves,switchLength,L0,scale,inflowBias); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"TurbulenceParticleSystem::synthesize" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("TurbulenceParticleSystem::synthesize",e.what()); return 0; }
+ }
+
+ void deleteInObstacle(FlagGrid& flags); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); TurbulenceParticleSystem* pbo = dynamic_cast<TurbulenceParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::deleteInObstacle" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->deleteInObstacle(flags); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"TurbulenceParticleSystem::deleteInObstacle" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("TurbulenceParticleSystem::deleteInObstacle",e.what()); return 0; }
+ }
+
+
+ virtual ParticleBase* clone();
+
+private: WaveletNoiseField& noise; public: PbArgs _args; }
+#define _C_TurbulenceParticleSystem
+;
+
+} // namespace
+
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h.reg
new file mode 100644
index 00000000000..f28cd70f4a3
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h.reg
@@ -0,0 +1,9 @@
+#include "turbulencepart.h"
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","TurbulenceParticleSystem","ParticleSystem<$BT$>"); template<> const char* Namify<TurbulenceParticleSystem >::S = "TurbulenceParticleSystem";
+>TurbulenceParticleSystem^
+@TurbulenceParticleSystem^^ParticleSystem^TurbulenceParticleData
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","TurbulenceParticleSystem",TurbulenceParticleSystem::_W_0);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","resetTexCoords",TurbulenceParticleSystem::_W_1);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","seed",TurbulenceParticleSystem::_W_2);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","synthesize",TurbulenceParticleSystem::_W_3);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","deleteInObstacle",TurbulenceParticleSystem::_W_4);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h.reg.cpp
new file mode 100644
index 00000000000..0cbdc53ed46
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/turbulencepart.h.reg.cpp
@@ -0,0 +1,56 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "turbulencepart.h"
+namespace Manta {
+#ifdef _C_ParticleSystem
+ static const Pb::Register _R_21 ("ParticleSystem<TurbulenceParticleData>","ParticleSystem<TurbulenceParticleData>","ParticleBase"); template<> const char* Namify<ParticleSystem<TurbulenceParticleData> >::S = "ParticleSystem<TurbulenceParticleData>";
+ static const Pb::Register _R_22 ("ParticleSystem<TurbulenceParticleData>","ParticleSystem",ParticleSystem<TurbulenceParticleData>::_W_2);
+ static const Pb::Register _R_23 ("ParticleSystem<TurbulenceParticleData>","pySize",ParticleSystem<TurbulenceParticleData>::_W_3);
+ static const Pb::Register _R_24 ("ParticleSystem<TurbulenceParticleData>","setPos",ParticleSystem<TurbulenceParticleData>::_W_4);
+ static const Pb::Register _R_25 ("ParticleSystem<TurbulenceParticleData>","getPos",ParticleSystem<TurbulenceParticleData>::_W_5);
+ static const Pb::Register _R_26 ("ParticleSystem<TurbulenceParticleData>","getPosPdata",ParticleSystem<TurbulenceParticleData>::_W_6);
+ static const Pb::Register _R_27 ("ParticleSystem<TurbulenceParticleData>","setPosPdata",ParticleSystem<TurbulenceParticleData>::_W_7);
+ static const Pb::Register _R_28 ("ParticleSystem<TurbulenceParticleData>","clear",ParticleSystem<TurbulenceParticleData>::_W_8);
+ static const Pb::Register _R_29 ("ParticleSystem<TurbulenceParticleData>","advectInGrid",ParticleSystem<TurbulenceParticleData>::_W_9);
+ static const Pb::Register _R_30 ("ParticleSystem<TurbulenceParticleData>","projectOutside",ParticleSystem<TurbulenceParticleData>::_W_10);
+ static const Pb::Register _R_31 ("ParticleSystem<TurbulenceParticleData>","projectOutOfBnd",ParticleSystem<TurbulenceParticleData>::_W_11);
+#endif
+#ifdef _C_TurbulenceParticleSystem
+ static const Pb::Register _R_32 ("TurbulenceParticleSystem","TurbulenceParticleSystem","ParticleSystem<TurbulenceParticleData>"); template<> const char* Namify<TurbulenceParticleSystem >::S = "TurbulenceParticleSystem";
+ static const Pb::Register _R_33 ("TurbulenceParticleSystem","TurbulenceParticleSystem",TurbulenceParticleSystem::_W_0);
+ static const Pb::Register _R_34 ("TurbulenceParticleSystem","resetTexCoords",TurbulenceParticleSystem::_W_1);
+ static const Pb::Register _R_35 ("TurbulenceParticleSystem","seed",TurbulenceParticleSystem::_W_2);
+ static const Pb::Register _R_36 ("TurbulenceParticleSystem","synthesize",TurbulenceParticleSystem::_W_3);
+ static const Pb::Register _R_37 ("TurbulenceParticleSystem","deleteInObstacle",TurbulenceParticleSystem::_W_4);
+#endif
+extern "C" {
+void PbRegister_file_21()
+{
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+ KEEP_UNUSED(_R_35);
+ KEEP_UNUSED(_R_36);
+ KEEP_UNUSED(_R_37);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.cpp
new file mode 100644
index 00000000000..683cc1b923b
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.cpp
@@ -0,0 +1,156 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex particles
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#include "vortexpart.h"
+#include "integrator.h"
+#include "mesh.h"
+
+using namespace std;
+namespace Manta {
+
+// vortex particle effect: (cyl coord around wp)
+// u = -|wp|*rho*exp( (-rho^2-z^2)/(2sigma^2) ) e_phi
+inline Vec3 VortexKernel(const Vec3& p, const vector<VortexParticleData>& vp, Real scale) {
+ Vec3 u(0.0);
+ for (size_t i=0; i<vp.size(); i++) {
+ if (vp[i].flag & ParticleBase::PDELETE) continue;
+
+ // cutoff radius
+ const Vec3 r = p - vp[i].pos;
+ const Real rlen2 = normSquare(r);
+ const Real sigma2 = square(vp[i].sigma);
+ if (rlen2 > 6.0 * sigma2 || rlen2 < 1e-8) continue;
+
+ // split vortex strength
+ Vec3 vortNorm = vp[i].vorticity;
+ Real strength = normalize(vortNorm) * scale;
+
+ // transform in cylinder coordinate system
+ const Real rlen = sqrt(rlen2);
+ const Real z = dot(r, vortNorm);
+ const Vec3 ePhi = cross(r, vortNorm) / rlen;
+ const Real rho2 = rlen2 - z*z;
+
+ Real vortex = 0;
+ if (rho2 > 1e-10) {
+ // evaluate Kernel
+ vortex = strength * sqrt(rho2) * exp (rlen2 * -0.5/sigma2);
+ }
+ u += vortex * ePhi;
+ }
+ return u;
+}
+
+
+ struct _KnVpAdvectMesh : public KernelBase {
+ _KnVpAdvectMesh(const KernelBase& base, vector<Node>& nodes, const vector<VortexParticleData>& vp, Real scale ,vector<Vec3> & u) : KernelBase(base) ,nodes(nodes),vp(vp),scale(scale) ,u(u){
+}
+ inline void op(IndexInt idx, vector<Node>& nodes, const vector<VortexParticleData>& vp, Real scale ,vector<Vec3> & u) const {
+ if (nodes[idx].flags & Mesh::NfFixed)
+ u[idx] = 0.0;
+ else
+ u[idx] = VortexKernel(nodes[idx].pos, vp, scale);
+} void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, nodes,vp,scale,u); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ vector<Node>& nodes; const vector<VortexParticleData>& vp; Real scale; vector<Vec3> & u; }
+; struct KnVpAdvectMesh : public KernelBase {
+ KnVpAdvectMesh(vector<Node>& nodes, const vector<VortexParticleData>& vp, Real scale) : KernelBase(nodes.size()) , _inner(KernelBase(nodes.size()),nodes,vp,scale,u) ,nodes(nodes),vp(vp),scale(scale) ,u((size)) {
+ runMessage(); run(); }
+ void run() {
+ _inner.run(); }
+ inline operator vector<Vec3> () {
+ return u; }
+ inline vector<Vec3> & getRet() {
+ return u; }
+ inline vector<Node>& getArg0() {
+ return nodes; }
+ typedef vector<Node> type0;inline const vector<VortexParticleData>& getArg1() {
+ return vp; }
+ typedef vector<VortexParticleData> type1;inline Real& getArg2() {
+ return scale; }
+ typedef Real type2; void runMessage() { debMsg("Executing kernel KnVpAdvectMesh ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; _KnVpAdvectMesh _inner; vector<Node>& nodes; const vector<VortexParticleData>& vp; Real scale; vector<Vec3> u; }
+;
+
+
+ struct _KnVpAdvectSelf : public KernelBase {
+ _KnVpAdvectSelf(const KernelBase& base, vector<VortexParticleData>& vp, Real scale ,vector<Vec3> & u) : KernelBase(base) ,vp(vp),scale(scale) ,u(u){
+}
+ inline void op(IndexInt idx, vector<VortexParticleData>& vp, Real scale ,vector<Vec3> & u) const {
+ if (vp[idx].flag & ParticleBase::PDELETE)
+ u[idx] = 0.0;
+ else
+ u[idx] = VortexKernel(vp[idx].pos, vp, scale);
+} void operator() (const tbb::blocked_range<IndexInt>& __r) const {
+ for (IndexInt idx=__r.begin(); idx!=(IndexInt)__r.end(); idx++) op(idx, vp,scale,u); }
+ void run() {
+ tbb::parallel_for (tbb::blocked_range<IndexInt>(0, size), *this); }
+ vector<VortexParticleData>& vp; Real scale; vector<Vec3> & u; }
+; struct KnVpAdvectSelf : public KernelBase {
+ KnVpAdvectSelf(vector<VortexParticleData>& vp, Real scale) : KernelBase(vp.size()) , _inner(KernelBase(vp.size()),vp,scale,u) ,vp(vp),scale(scale) ,u((size)) {
+ runMessage(); run(); }
+ void run() {
+ _inner.run(); }
+ inline operator vector<Vec3> () {
+ return u; }
+ inline vector<Vec3> & getRet() {
+ return u; }
+ inline vector<VortexParticleData>& getArg0() {
+ return vp; }
+ typedef vector<VortexParticleData> type0;inline Real& getArg1() {
+ return scale; }
+ typedef Real type1; void runMessage() { debMsg("Executing kernel KnVpAdvectSelf ", 3); debMsg("Kernel range" << " size "<< size << " " , 4); }; _KnVpAdvectSelf _inner; vector<VortexParticleData>& vp; Real scale; vector<Vec3> u; }
+;
+
+VortexParticleSystem::VortexParticleSystem(FluidSolver* parent) :
+ ParticleSystem<VortexParticleData>(parent)
+{
+}
+
+void VortexParticleSystem::advectSelf(Real scale, int integrationMode) {
+ KnVpAdvectSelf kernel(mData, scale* getParent()->getDt());
+ integratePointSet( kernel, integrationMode);
+}
+
+void VortexParticleSystem::applyToMesh(Mesh& mesh, Real scale, int integrationMode) {
+ KnVpAdvectMesh kernel(mesh.getNodeData(), mData, scale* getParent()->getDt());
+ integratePointSet( kernel, integrationMode);
+}
+
+ParticleBase* VortexParticleSystem::clone() {
+ VortexParticleSystem* nm = new VortexParticleSystem(getParent());
+ compress();
+
+ nm->mData = mData;
+ nm->setName(getName());
+ return nm;
+}
+
+
+
+} // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h
new file mode 100644
index 00000000000..84b2cb22da4
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h
@@ -0,0 +1,82 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex particles
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#ifndef _VORTEXPART_H
+#define _VORTEXPART_H
+
+#include "particle.h"
+
+namespace Manta {
+class Mesh;
+
+struct VortexParticleData {
+ VortexParticleData() : pos(0.0),vorticity(0.0),sigma(0),flag(0) {}
+ VortexParticleData(const Vec3& p, const Vec3& v, Real sig) : pos(p),vorticity(v),sigma(sig),flag(0) {}
+ Vec3 pos, vorticity;
+ Real sigma;
+ int flag;
+ static ParticleBase::SystemType getType() { return ParticleBase::VORTEX; }
+};
+
+//! Vortex particles
+class VortexParticleSystem : public ParticleSystem<VortexParticleData> {public:
+ VortexParticleSystem(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "VortexParticleSystem::VortexParticleSystem" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new VortexParticleSystem(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"VortexParticleSystem::VortexParticleSystem" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("VortexParticleSystem::VortexParticleSystem",e.what()); return -1; }
+ }
+
+
+ void advectSelf(Real scale=1.0, int integrationMode=IntRK4); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); VortexParticleSystem* pbo = dynamic_cast<VortexParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "VortexParticleSystem::advectSelf" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Real scale = _args.getOpt<Real >("scale",0,1.0,&_lock); int integrationMode = _args.getOpt<int >("integrationMode",1,IntRK4,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->advectSelf(scale,integrationMode); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"VortexParticleSystem::advectSelf" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VortexParticleSystem::advectSelf",e.what()); return 0; }
+ }
+
+ void applyToMesh(Mesh& mesh, Real scale=1.0, int integrationMode=IntRK4); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); VortexParticleSystem* pbo = dynamic_cast<VortexParticleSystem*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "VortexParticleSystem::applyToMesh" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); Real scale = _args.getOpt<Real >("scale",1,1.0,&_lock); int integrationMode = _args.getOpt<int >("integrationMode",2,IntRK4,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->applyToMesh(mesh,scale,integrationMode); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"VortexParticleSystem::applyToMesh" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VortexParticleSystem::applyToMesh",e.what()); return 0; }
+ }
+
+ virtual ParticleBase* clone(); public: PbArgs _args; }
+#define _C_VortexParticleSystem
+;
+
+} // namespace
+
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h.reg
new file mode 100644
index 00000000000..8d36d048fbd
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h.reg
@@ -0,0 +1,7 @@
+#include "vortexpart.h"
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","VortexParticleSystem","ParticleSystem<$BT$>"); template<> const char* Namify<VortexParticleSystem >::S = "VortexParticleSystem";
+>VortexParticleSystem^
+@VortexParticleSystem^^ParticleSystem^VortexParticleData
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","VortexParticleSystem",VortexParticleSystem::_W_0);
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","advectSelf",VortexParticleSystem::_W_1);
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","applyToMesh",VortexParticleSystem::_W_2);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h.reg.cpp
new file mode 100644
index 00000000000..f62b046c4c9
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexpart.h.reg.cpp
@@ -0,0 +1,52 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "vortexpart.h"
+namespace Manta {
+#ifdef _C_ParticleSystem
+ static const Pb::Register _R_20 ("ParticleSystem<VortexParticleData>","ParticleSystem<VortexParticleData>","ParticleBase"); template<> const char* Namify<ParticleSystem<VortexParticleData> >::S = "ParticleSystem<VortexParticleData>";
+ static const Pb::Register _R_21 ("ParticleSystem<VortexParticleData>","ParticleSystem",ParticleSystem<VortexParticleData>::_W_2);
+ static const Pb::Register _R_22 ("ParticleSystem<VortexParticleData>","pySize",ParticleSystem<VortexParticleData>::_W_3);
+ static const Pb::Register _R_23 ("ParticleSystem<VortexParticleData>","setPos",ParticleSystem<VortexParticleData>::_W_4);
+ static const Pb::Register _R_24 ("ParticleSystem<VortexParticleData>","getPos",ParticleSystem<VortexParticleData>::_W_5);
+ static const Pb::Register _R_25 ("ParticleSystem<VortexParticleData>","getPosPdata",ParticleSystem<VortexParticleData>::_W_6);
+ static const Pb::Register _R_26 ("ParticleSystem<VortexParticleData>","setPosPdata",ParticleSystem<VortexParticleData>::_W_7);
+ static const Pb::Register _R_27 ("ParticleSystem<VortexParticleData>","clear",ParticleSystem<VortexParticleData>::_W_8);
+ static const Pb::Register _R_28 ("ParticleSystem<VortexParticleData>","advectInGrid",ParticleSystem<VortexParticleData>::_W_9);
+ static const Pb::Register _R_29 ("ParticleSystem<VortexParticleData>","projectOutside",ParticleSystem<VortexParticleData>::_W_10);
+ static const Pb::Register _R_30 ("ParticleSystem<VortexParticleData>","projectOutOfBnd",ParticleSystem<VortexParticleData>::_W_11);
+#endif
+#ifdef _C_VortexParticleSystem
+ static const Pb::Register _R_31 ("VortexParticleSystem","VortexParticleSystem","ParticleSystem<VortexParticleData>"); template<> const char* Namify<VortexParticleSystem >::S = "VortexParticleSystem";
+ static const Pb::Register _R_32 ("VortexParticleSystem","VortexParticleSystem",VortexParticleSystem::_W_0);
+ static const Pb::Register _R_33 ("VortexParticleSystem","advectSelf",VortexParticleSystem::_W_1);
+ static const Pb::Register _R_34 ("VortexParticleSystem","applyToMesh",VortexParticleSystem::_W_2);
+#endif
+extern "C" {
+void PbRegister_file_20()
+{
+ KEEP_UNUSED(_R_20);
+ KEEP_UNUSED(_R_21);
+ KEEP_UNUSED(_R_22);
+ KEEP_UNUSED(_R_23);
+ KEEP_UNUSED(_R_24);
+ KEEP_UNUSED(_R_25);
+ KEEP_UNUSED(_R_26);
+ KEEP_UNUSED(_R_27);
+ KEEP_UNUSED(_R_28);
+ KEEP_UNUSED(_R_29);
+ KEEP_UNUSED(_R_30);
+ KEEP_UNUSED(_R_31);
+ KEEP_UNUSED(_R_32);
+ KEEP_UNUSED(_R_33);
+ KEEP_UNUSED(_R_34);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.cpp
new file mode 100644
index 00000000000..fa77901a9a6
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.cpp
@@ -0,0 +1,106 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex sheets
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#include "vortexsheet.h"
+#include "solvana.h"
+
+using namespace std;
+namespace Manta {
+
+// *****************************************************************************
+// VorticityChannel class members
+
+
+
+// *****************************************************************************
+// VortexSheet Mesh class members
+
+VortexSheetMesh::VortexSheetMesh(FluidSolver* parent) : Mesh(parent), mTexOffset(0.0f) {
+ addTriChannel(&mVorticity);
+ addNodeChannel(&mTex1);
+ addNodeChannel(&mTex2);
+ addNodeChannel(&mTurb);
+}
+
+
+Mesh* VortexSheetMesh::clone() {
+ VortexSheetMesh* nm = new VortexSheetMesh(mParent);
+ *nm = *this;
+ nm->setName(getName());
+ return nm;
+}
+
+
+void VortexSheetMesh::calcVorticity() {
+ for (size_t tri = 0; tri < mTris.size(); tri++) {
+ VortexSheetInfo& v = mVorticity.data[tri];
+ Vec3 e0 = getEdge(tri,0), e1 = getEdge(tri,1), e2 = getEdge(tri,2);
+ Real area = getFaceArea(tri);
+
+ if (area < 1e-10) {
+ v.smokeAmount = 0;
+ v.vorticity = 0;
+ } else {
+ v.smokeAmount = 0;
+ v.vorticity = (v.circulation[0]*e0 + v.circulation[1]*e1 + v.circulation[2]*e2) / area;
+ }
+ }
+}
+
+void VortexSheetMesh::calcCirculation() {
+ for (size_t tri = 0; tri < mTris.size(); tri++) {
+ VortexSheetInfo& v = mVorticity.data[tri];
+ Vec3 e0 = getEdge(tri,0), e1 = getEdge(tri,1), e2 = getEdge(tri,2);
+ Real area = getFaceArea(tri);
+
+ if (area < 1e-10 || normSquare(v.vorticity) < 1e-10) {
+ v.circulation = 0;
+ continue;
+ }
+
+ float cx, cy, cz;
+ SolveOverconstraint34(e0.x, e0.y, e0.z, e1.x, e1.y, e1.z, e2.x, e2.y, e2.z, v.vorticity.x, v.vorticity.y, v.vorticity.z, cx, cy, cz);
+ v.circulation = Vec3(cx, cy, cz) * area;
+ }
+}
+
+void VortexSheetMesh::resetTex1() {
+ for (size_t i=0; i<mNodes.size(); i++)
+ mTex1.data[i] = mNodes[i].pos + mTexOffset;
+}
+
+void VortexSheetMesh::resetTex2() {
+ for (size_t i=0; i<mNodes.size(); i++)
+ mTex2.data[i] = mNodes[i].pos + mTexOffset;
+}
+
+void VortexSheetMesh::reinitTexCoords() {
+ resetTex1();
+ resetTex2();
+}
+
+}; // namespace
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h
new file mode 100644
index 00000000000..3883f8e0149
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h
@@ -0,0 +1,132 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Vortex sheets
+ * (warning, the vortex methods are currently experimental, and not fully supported!)
+ *
+ ******************************************************************************/
+
+#ifndef _VORTEXSHEET_H
+#define _VORTEXSHEET_H
+
+#include "mesh.h"
+
+namespace Manta {
+
+//! Stores vortex sheet info
+struct VortexSheetInfo {
+ VortexSheetInfo() : vorticity(0.0), vorticitySmoothed(0.0), circulation(0.0), smokeAmount(1.0), smokeParticles(0.0) {}
+
+ Vec3 vorticity;
+ Vec3 vorticitySmoothed;
+ Vec3 circulation;
+ Real smokeAmount, smokeParticles;
+};
+
+//! Manages vortex sheet info
+struct VorticityChannel : public SimpleTriChannel<VortexSheetInfo> {
+ virtual TriChannel* clone() { VorticityChannel* vc = new VorticityChannel(); *vc = *this; return vc;}
+};
+
+//! Manages 3D texture coordinates
+struct TexCoord3Channel : public SimpleNodeChannel<Vec3> {
+ virtual NodeChannel* clone() { TexCoord3Channel* tc = new TexCoord3Channel(); *tc = *this; return tc; }
+
+ void addInterpol(int a, int b, Real alpha) { data.push_back((1.0-alpha)*data[a] + alpha*data[b]);}
+ void mergeWith(int node, int delnode, Real alpha) { data[node] = 0.5*(data[node]+data[delnode]); }
+};
+
+struct TurbulenceInfo {
+ TurbulenceInfo() : k(0.0), epsilon(0.0) {}
+ TurbulenceInfo(const TurbulenceInfo& a, const TurbulenceInfo& b, Real alpha) : k((1.0-alpha)*a.k+alpha*b.k), epsilon((1.0-alpha)*a.epsilon+alpha*b.epsilon) {}
+ Real k, epsilon;
+};
+
+//! Manages k-epsilon information
+struct TurbulenceChannel : public SimpleNodeChannel<TurbulenceInfo> {
+ virtual NodeChannel* clone() { TurbulenceChannel* tc = new TurbulenceChannel(); *tc = *this; return tc; }
+
+ void addInterpol(int a, int b, Real alpha) { data.push_back(TurbulenceInfo(data[a], data[b], alpha)); }
+ void mergeWith(int node, int delnode, Real alpha) { data[node] = TurbulenceInfo(data[node], data[delnode], 0.5); }
+};
+
+//! Typed Mesh with a vorticity and 2 texcoord3 channels
+class VortexSheetMesh : public Mesh {public:
+ VortexSheetMesh(FluidSolver* parent); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try {
+ PbArgs _args(_linargs, _kwds); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(0, "VortexSheetMesh::VortexSheetMesh" , !noTiming ); {
+ ArgLocker _lock; FluidSolver* parent = _args.getPtr<FluidSolver >("parent",0,&_lock); obj = new VortexSheetMesh(parent); obj->registerObject(_self, &_args); _args.check(); }
+ pbFinalizePlugin(obj->getParent(),"VortexSheetMesh::VortexSheetMesh" , !noTiming ); return 0; }
+ catch(std::exception& e) {
+ pbSetError("VortexSheetMesh::VortexSheetMesh",e.what()); return -1; }
+ }
+
+ virtual Mesh* clone();
+
+ virtual MeshType getType() { return TypeVortexSheet; }
+
+ inline VortexSheetInfo& sheet(int i) { return mVorticity.data[i]; };
+ inline Vec3& tex1(int i) { return mTex1.data[i]; }
+ inline Vec3& tex2(int i) { return mTex2.data[i]; }
+ inline TurbulenceInfo& turb(int i) { return mTurb.data[i]; }
+ void setReferenceTexOffset(const Vec3& ref) { mTexOffset = ref; }
+ void resetTex1();
+ void resetTex2();
+
+ void calcCirculation(); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); VortexSheetMesh* pbo = dynamic_cast<VortexSheetMesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::calcCirculation" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->calcCirculation(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"VortexSheetMesh::calcCirculation" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VortexSheetMesh::calcCirculation",e.what()); return 0; }
+ }
+
+ void calcVorticity(); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); VortexSheetMesh* pbo = dynamic_cast<VortexSheetMesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::calcVorticity" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->calcVorticity(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"VortexSheetMesh::calcVorticity" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VortexSheetMesh::calcVorticity",e.what()); return 0; }
+ }
+
+ void reinitTexCoords(); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds); VortexSheetMesh* pbo = dynamic_cast<VortexSheetMesh*>(Pb::objFromPy(_self)); bool noTiming = _args.getOpt<bool>("notiming", -1, 0); pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::reinitTexCoords" , !noTiming); PyObject *_retval = 0; {
+ ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->reinitTexCoords(); pbo->_args.check(); }
+ pbFinalizePlugin(pbo->getParent(),"VortexSheetMesh::reinitTexCoords" , !noTiming); return _retval; }
+ catch(std::exception& e) {
+ pbSetError("VortexSheetMesh::reinitTexCoords",e.what()); return 0; }
+ }
+
+
+protected:
+ Vec3 mTexOffset;
+ VorticityChannel mVorticity;
+ TexCoord3Channel mTex1, mTex2; TurbulenceChannel mTurb; public: PbArgs _args; }
+#define _C_VortexSheetMesh
+;
+
+}; // namespace
+
+#endif
+
+
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h.reg b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h.reg
new file mode 100644
index 00000000000..d5ad6b64113
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h.reg
@@ -0,0 +1,7 @@
+#include "vortexsheet.h"
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","VortexSheetMesh","Mesh"); template<> const char* Namify<VortexSheetMesh >::S = "VortexSheetMesh";
+>VortexSheetMesh^
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","VortexSheetMesh",VortexSheetMesh::_W_0);
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","calcCirculation",VortexSheetMesh::_W_1);
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","calcVorticity",VortexSheetMesh::_W_2);
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","reinitTexCoords",VortexSheetMesh::_W_3);
diff --git a/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h.reg.cpp b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h.reg.cpp
new file mode 100644
index 00000000000..57a61c01ecd
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/preprocessed/tbb/vortexsheet.h.reg.cpp
@@ -0,0 +1,30 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "vortexsheet.h"
+namespace Manta {
+#ifdef _C_VortexSheetMesh
+ static const Pb::Register _R_14 ("VortexSheetMesh","VortexSheetMesh","Mesh"); template<> const char* Namify<VortexSheetMesh >::S = "VortexSheetMesh";
+ static const Pb::Register _R_15 ("VortexSheetMesh","VortexSheetMesh",VortexSheetMesh::_W_0);
+ static const Pb::Register _R_16 ("VortexSheetMesh","calcCirculation",VortexSheetMesh::_W_1);
+ static const Pb::Register _R_17 ("VortexSheetMesh","calcVorticity",VortexSheetMesh::_W_2);
+ static const Pb::Register _R_18 ("VortexSheetMesh","reinitTexCoords",VortexSheetMesh::_W_3);
+#endif
+extern "C" {
+void PbRegister_file_14()
+{
+ KEEP_UNUSED(_R_14);
+ KEEP_UNUSED(_R_15);
+ KEEP_UNUSED(_R_16);
+ KEEP_UNUSED(_R_17);
+ KEEP_UNUSED(_R_18);
+}
+}} \ No newline at end of file
diff --git a/intern/mantaflow/intern/manta_develop/update_mantaflow.sh b/intern/mantaflow/intern/manta_develop/update_mantaflow.sh
new file mode 100644
index 00000000000..649ffaeed87
--- /dev/null
+++ b/intern/mantaflow/intern/manta_develop/update_mantaflow.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+#
+# ========================================================================================
+# UPDATING MANTAFLOW INSIDE BLENDER
+# ========================================================================================
+
+# ==================== 1) ENVIRONMENT SETUP =============================================
+
+# YOUR INSTALLATION PATHS GO HERE:
+MANTA_INSTALLATION=/Users/sebbas/Developer/Mantaflow/mantaflowDevelop
+BLENDER_INSTALLATION=/Users/sebbas/Developer/Blender/fluid-mantaflow
+
+# ==================== 2) BUILD MANTAFLOW (OPENMP AND TBB) ===============================
+
+# Need non-default (OpenMP enabled) compiler to build Mantaflow on OSX
+if [[ "$OSTYPE" == "darwin"* ]]; then
+ export CC=/usr/local/Cellar/gcc/9.1.0/bin/gcc-9
+ export CXX=/usr/local/Cellar/gcc/9.1.0/bin/g++-9
+fi
+
+cd $MANTA_INSTALLATION
+if cd mantaflowgit/; then git pull; else git clone git@bitbucket.org:thunil/mantaflowgit.git; cd mantaflowgit; fi
+git checkout develop
+MANTA_OMP_PATH=$MANTA_INSTALLATION/mantaflowgit/build_omp/
+MANTA_TBB_PATH=$MANTA_INSTALLATION/mantaflowgit/build_tbb/
+mkdir -p $MANTA_OMP_PATH $MANTA_TBB_PATH
+cd $MANTA_OMP_PATH
+cmake .. -DGUI=OFF -DOPENMP=ON -DBLENDER=ON -DPREPDEBUG=ON && make -j4
+cd $MANTA_TBB_PATH
+cmake .. -DGUI=OFF -DTBB=ON -DBLENDER=ON -DPREPDEBUG=ON && make -j4
+
+# ==================== 3) COPY MANTAFLOW FILES TO BLENDER DIRECTORIES ====================
+
+BLENDER_DEPENDENCIES_PATH=$BLENDER_INSTALLATION/blender/intern/mantaflow/intern/manta_develop/dependencies/
+mkdir -p $BLENDER_DEPENDENCIES_PATH && cp -Rf $MANTA_INSTALLATION/mantaflowgit/dependencies/cnpy "$_"
+echo "Copied Mantaflow dependencies to" $BLENDER_DEPENDENCIES_PATH
+
+BLENDER_HELPER_PATH=$BLENDER_INSTALLATION/blender/intern/mantaflow/intern/manta_develop/helper/
+mkdir -p $BLENDER_HELPER_PATH && cp -Rf $MANTA_INSTALLATION/mantaflowgit/source/util "$_"
+mkdir -p $BLENDER_HELPER_PATH && cp -Rf $MANTA_INSTALLATION/mantaflowgit/source/pwrapper "$_"
+echo "Copied Mantaflow helper files to" $BLENDER_HELPER_PATH
+
+BLENDER_OMP_PATH=$BLENDER_INSTALLATION/blender/intern/mantaflow/intern/manta_develop/preprocessed/omp/
+mkdir -p $BLENDER_OMP_PATH && cp -Rf $MANTA_INSTALLATION/mantaflowgit/build_omp/pp/source/. "$_"
+echo "Copied Mantaflow OpenMP preprocessed files to" $BLENDER_OMP_PATH
+
+BLENDER_TBB_PATH=$BLENDER_INSTALLATION/blender/intern/mantaflow/intern/manta_develop/preprocessed/tbb/
+mkdir -p $BLENDER_TBB_PATH && cp -Rf $MANTA_INSTALLATION/mantaflowgit/build_tbb/pp/source/. "$_"
+echo "Copied Mantaflow TBB preprocessed files to" $BLENDER_TBB_PATH
+
+# ==================== 4) CHECK CMAKE SETUP ==============================================
+
+# Make sure that all files copied from Mantaflow are listed in intern/mantaflow/CMakeLists.txt
+# Especially if new source files / plugins were added to Mantaflow.
diff --git a/intern/mantaflow/intern/manta_fluid_API.cpp b/intern/mantaflow/intern/manta_fluid_API.cpp
new file mode 100644
index 00000000000..26701148d7a
--- /dev/null
+++ b/intern/mantaflow/intern/manta_fluid_API.cpp
@@ -0,0 +1,880 @@
+/*
+ * ***** 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 <cmath>
+
+#include "MANTA_main.h"
+#include "manta_fluid_API.h"
+
+/* Fluid functions */
+extern "C" MANTA *manta_init(int *res, struct MantaModifierData *mmd)
+{
+ return new MANTA(res, mmd);
+}
+extern "C" void manta_free(MANTA *fluid)
+{
+ delete fluid;
+ fluid = NULL;
+}
+
+extern "C" void manta_ensure_obstacle(MANTA *fluid, struct MantaModifierData *mmd)
+{
+ if (fluid) {
+ fluid->initObstacle(mmd);
+ fluid->updatePointers();
+ }
+}
+extern "C" void manta_ensure_guiding(MANTA *fluid, struct MantaModifierData *mmd)
+{
+ if (fluid) {
+ fluid->initGuiding(mmd);
+ fluid->updatePointers();
+ }
+}
+extern "C" void manta_ensure_invelocity(MANTA *fluid, struct MantaModifierData *mmd)
+{
+ if (fluid) {
+ fluid->initInVelocity(mmd);
+ fluid->updatePointers();
+ }
+}
+extern "C" void manta_ensure_outflow(MANTA *fluid, struct MantaModifierData *mmd)
+{
+ if (fluid) {
+ fluid->initOutflow(mmd);
+ fluid->updatePointers();
+ }
+}
+
+extern "C" int manta_write_config(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->writeConfiguration(mmd, framenr);
+}
+
+extern "C" int manta_write_data(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->writeData(mmd, framenr);
+}
+
+extern "C" int manta_read_config(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readConfiguration(mmd, framenr);
+}
+
+extern "C" int manta_read_data(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readData(mmd, framenr);
+}
+
+extern "C" int manta_read_noise(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readNoise(mmd, framenr);
+}
+
+extern "C" int manta_read_mesh(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readMesh(mmd, framenr);
+}
+
+extern "C" int manta_read_particles(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readParticles(mmd, framenr);
+}
+
+extern "C" int manta_read_guiding(MANTA *fluid,
+ MantaModifierData *mmd,
+ int framenr,
+ bool sourceDomain)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readGuiding(mmd, framenr, sourceDomain);
+}
+
+extern "C" int manta_update_liquid_structures(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->updateFlipStructures(mmd, framenr);
+}
+
+extern "C" int manta_update_mesh_structures(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->updateMeshStructures(mmd, framenr);
+}
+
+extern "C" int manta_update_particle_structures(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->updateParticleStructures(mmd, framenr);
+}
+
+extern "C" int manta_bake_data(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeData(mmd, framenr);
+}
+
+extern "C" int manta_bake_noise(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeNoise(mmd, framenr);
+}
+
+extern "C" int manta_bake_mesh(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeMesh(mmd, framenr);
+}
+
+extern "C" int manta_bake_particles(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeParticles(mmd, framenr);
+}
+
+extern "C" int manta_bake_guiding(MANTA *fluid, MantaModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeGuiding(mmd, framenr);
+}
+
+extern "C" void manta_update_variables(MANTA *fluid, MantaModifierData *mmd)
+{
+ if (fluid)
+ fluid->updateVariables(mmd);
+}
+
+extern "C" int manta_get_frame(MANTA *fluid)
+{
+ if (!fluid)
+ return 0;
+ return fluid->getFrame();
+}
+
+extern "C" float manta_get_timestep(MANTA *fluid)
+{
+ if (!fluid)
+ return 0;
+ return fluid->getTimestep();
+}
+
+extern "C" void manta_adapt_timestep(MANTA *fluid)
+{
+ if (fluid)
+ fluid->adaptTimestep();
+}
+
+extern "C" bool manta_needs_realloc(MANTA *fluid, MantaModifierData *mmd)
+{
+ if (fluid)
+ return fluid->needsRealloc(mmd);
+ return false;
+}
+
+/* Fluid accessors */
+extern "C" 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;
+}
+extern "C" 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;
+}
+extern "C" float *manta_get_velocity_x(MANTA *fluid)
+{
+ return fluid->getVelocityX();
+}
+extern "C" float *manta_get_velocity_y(MANTA *fluid)
+{
+ return fluid->getVelocityY();
+}
+extern "C" float *manta_get_velocity_z(MANTA *fluid)
+{
+ return fluid->getVelocityZ();
+}
+
+extern "C" float *manta_get_ob_velocity_x(MANTA *fluid)
+{
+ return fluid->getObVelocityX();
+}
+extern "C" float *manta_get_ob_velocity_y(MANTA *fluid)
+{
+ return fluid->getObVelocityY();
+}
+extern "C" float *manta_get_ob_velocity_z(MANTA *fluid)
+{
+ return fluid->getObVelocityZ();
+}
+
+extern "C" float *manta_get_guide_velocity_x(MANTA *fluid)
+{
+ return fluid->getGuideVelocityX();
+}
+extern "C" float *manta_get_guide_velocity_y(MANTA *fluid)
+{
+ return fluid->getGuideVelocityY();
+}
+extern "C" float *manta_get_guide_velocity_z(MANTA *fluid)
+{
+ return fluid->getGuideVelocityZ();
+}
+
+extern "C" float *manta_get_in_velocity_x(MANTA *fluid)
+{
+ return fluid->getInVelocityX();
+}
+extern "C" float *manta_get_in_velocity_y(MANTA *fluid)
+{
+ return fluid->getInVelocityY();
+}
+extern "C" float *manta_get_in_velocity_z(MANTA *fluid)
+{
+ return fluid->getInVelocityZ();
+}
+
+extern "C" float *manta_get_force_x(MANTA *fluid)
+{
+ return fluid->getForceX();
+}
+extern "C" float *manta_get_force_y(MANTA *fluid)
+{
+ return fluid->getForceY();
+}
+extern "C" float *manta_get_force_z(MANTA *fluid)
+{
+ return fluid->getForceZ();
+}
+
+extern "C" float *manta_get_phiguide_in(MANTA *fluid)
+{
+ return fluid->getPhiGuideIn();
+}
+
+extern "C" int *manta_get_num_obstacle(MANTA *fluid)
+{
+ return fluid->getNumObstacle();
+}
+extern "C" int *manta_get_num_guide(MANTA *fluid)
+{
+ return fluid->getNumGuide();
+}
+
+extern "C" int manta_get_res_x(MANTA *fluid)
+{
+ return fluid->getResX();
+}
+extern "C" int manta_get_res_y(MANTA *fluid)
+{
+ return fluid->getResY();
+}
+extern "C" int manta_get_res_z(MANTA *fluid)
+{
+ return fluid->getResZ();
+}
+
+extern "C" float *manta_get_phi_in(MANTA *fluid)
+{
+ return fluid->getPhiIn();
+}
+extern "C" float *manta_get_phiobs_in(MANTA *fluid)
+{
+ return fluid->getPhiObsIn();
+}
+extern "C" float *manta_get_phiout_in(MANTA *fluid)
+{
+ return fluid->getPhiOutIn();
+}
+
+/* Smoke functions */
+extern "C" void manta_smoke_export_script(MANTA *smoke, MantaModifierData *mmd)
+{
+ if (!smoke || !mmd)
+ return;
+ smoke->exportSmokeScript(mmd);
+}
+
+extern "C" 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
+}
+
+extern "C" 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;
+ int m = 4, i_g = 1, i_b = 2, i_a = 3;
+ /* sequential data */
+ 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;
+ }
+}
+
+extern "C" 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);
+}
+
+extern "C" 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);
+}
+
+/* get a single color premultiplied voxel grid */
+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;
+ /* sequential data */
+ 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;
+ }
+}
+
+extern "C" 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);
+}
+
+extern "C" 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);
+}
+
+extern "C" void manta_smoke_ensure_heat(MANTA *smoke, struct MantaModifierData *mmd)
+{
+ if (smoke) {
+ smoke->initHeat(mmd);
+ smoke->updatePointers();
+ }
+}
+
+extern "C" void manta_smoke_ensure_fire(MANTA *smoke, struct MantaModifierData *mmd)
+{
+ if (smoke) {
+ smoke->initFire(mmd);
+ smoke->updatePointers();
+ }
+ if (smoke && smoke->usingNoise()) {
+ smoke->initFireHigh(mmd);
+ smoke->updatePointersNoise();
+ }
+}
+
+extern "C" void manta_smoke_ensure_colors(MANTA *smoke, struct MantaModifierData *mmd)
+{
+ if (smoke) {
+ smoke->initColors(mmd);
+ smoke->updatePointers();
+ }
+ if (smoke && smoke->usingNoise()) {
+ smoke->initColorsHigh(mmd);
+ smoke->updatePointersNoise();
+ }
+}
+
+/* Smoke accessors */
+extern "C" float *manta_smoke_get_density(MANTA *smoke)
+{
+ return smoke->getDensity();
+}
+extern "C" float *manta_smoke_get_fuel(MANTA *smoke)
+{
+ return smoke->getFuel();
+}
+extern "C" float *manta_smoke_get_react(MANTA *smoke)
+{
+ return smoke->getReact();
+}
+extern "C" float *manta_smoke_get_heat(MANTA *smoke)
+{
+ return smoke->getHeat();
+}
+extern "C" float *manta_smoke_get_flame(MANTA *smoke)
+{
+ return smoke->getFlame();
+}
+extern "C" float *manta_smoke_get_shadow(MANTA *fluid)
+{
+ return fluid->getShadow();
+}
+
+extern "C" float *manta_smoke_get_color_r(MANTA *smoke)
+{
+ return smoke->getColorR();
+}
+extern "C" float *manta_smoke_get_color_g(MANTA *smoke)
+{
+ return smoke->getColorG();
+}
+extern "C" float *manta_smoke_get_color_b(MANTA *smoke)
+{
+ return smoke->getColorB();
+}
+
+extern "C" int *manta_smoke_get_obstacle(MANTA *smoke)
+{
+ return smoke->getObstacle();
+}
+
+extern "C" float *manta_smoke_get_density_in(MANTA *smoke)
+{
+ return smoke->getDensityIn();
+}
+extern "C" float *manta_smoke_get_heat_in(MANTA *smoke)
+{
+ return smoke->getHeatIn();
+}
+extern "C" float *manta_smoke_get_color_r_in(MANTA *smoke)
+{
+ return smoke->getColorRIn();
+}
+extern "C" float *manta_smoke_get_color_g_in(MANTA *smoke)
+{
+ return smoke->getColorGIn();
+}
+extern "C" float *manta_smoke_get_color_b_in(MANTA *smoke)
+{
+ return smoke->getColorBIn();
+}
+extern "C" float *manta_smoke_get_fuel_in(MANTA *smoke)
+{
+ return smoke->getFuelIn();
+}
+extern "C" float *manta_smoke_get_react_in(MANTA *smoke)
+{
+ return smoke->getReactIn();
+}
+extern "C" float *manta_smoke_get_emission_in(MANTA *smoke)
+{
+ return smoke->getEmissionIn();
+}
+
+extern "C" int manta_smoke_has_heat(MANTA *smoke)
+{
+ return (smoke->getHeat()) ? 1 : 0;
+}
+extern "C" int manta_smoke_has_fuel(MANTA *smoke)
+{
+ return (smoke->getFuel()) ? 1 : 0;
+}
+extern "C" int manta_smoke_has_colors(MANTA *smoke)
+{
+ return (smoke->getColorR() && smoke->getColorG() && smoke->getColorB()) ? 1 : 0;
+}
+
+extern "C" float *manta_smoke_turbulence_get_density(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getDensityHigh() : NULL;
+}
+extern "C" float *manta_smoke_turbulence_get_fuel(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getFuelHigh() : NULL;
+}
+extern "C" float *manta_smoke_turbulence_get_react(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getReactHigh() : NULL;
+}
+extern "C" float *manta_smoke_turbulence_get_color_r(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getColorRHigh() : NULL;
+}
+extern "C" float *manta_smoke_turbulence_get_color_g(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getColorGHigh() : NULL;
+}
+extern "C" float *manta_smoke_turbulence_get_color_b(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getColorBHigh() : NULL;
+}
+extern "C" float *manta_smoke_turbulence_get_flame(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getFlameHigh() : NULL;
+}
+
+extern "C" int manta_smoke_turbulence_has_fuel(MANTA *smoke)
+{
+ return (smoke->getFuelHigh()) ? 1 : 0;
+}
+extern "C" int manta_smoke_turbulence_has_colors(MANTA *smoke)
+{
+ return (smoke->getColorRHigh() && smoke->getColorGHigh() && smoke->getColorBHigh()) ? 1 : 0;
+}
+
+extern "C" 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();
+ }
+}
+extern "C" 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 */
+extern "C" void manta_liquid_export_script(MANTA *liquid, MantaModifierData *mmd)
+{
+ if (!liquid || !mmd)
+ return;
+ liquid->exportLiquidScript(mmd);
+}
+
+extern "C" void manta_liquid_ensure_sndparts(MANTA *liquid, struct MantaModifierData *mmd)
+{
+ if (liquid) {
+ liquid->initLiquidSndParts(mmd);
+ liquid->updatePointers();
+ }
+}
+
+/* Liquid accessors */
+extern "C" int manta_liquid_get_particle_res_x(MANTA *liquid)
+{
+ return liquid->getParticleResX();
+}
+extern "C" int manta_liquid_get_particle_res_y(MANTA *liquid)
+{
+ return liquid->getParticleResY();
+}
+extern "C" int manta_liquid_get_particle_res_z(MANTA *liquid)
+{
+ return liquid->getParticleResZ();
+}
+
+extern "C" int manta_liquid_get_mesh_res_x(MANTA *liquid)
+{
+ return liquid->getMeshResX();
+}
+extern "C" int manta_liquid_get_mesh_res_y(MANTA *liquid)
+{
+ return liquid->getMeshResY();
+}
+extern "C" int manta_liquid_get_mesh_res_z(MANTA *liquid)
+{
+ return liquid->getMeshResZ();
+}
+
+extern "C" int manta_liquid_get_particle_upres(MANTA *liquid)
+{
+ return liquid->getParticleUpres();
+}
+extern "C" int manta_liquid_get_mesh_upres(MANTA *liquid)
+{
+ return liquid->getMeshUpres();
+}
+
+extern "C" int manta_liquid_get_num_verts(MANTA *liquid)
+{
+ return liquid->getNumVertices();
+}
+extern "C" int manta_liquid_get_num_normals(MANTA *liquid)
+{
+ return liquid->getNumNormals();
+}
+extern "C" int manta_liquid_get_num_triangles(MANTA *liquid)
+{
+ return liquid->getNumTriangles();
+}
+
+extern "C" float manta_liquid_get_vertex_x_at(MANTA *liquid, int i)
+{
+ return liquid->getVertexXAt(i);
+}
+extern "C" float manta_liquid_get_vertex_y_at(MANTA *liquid, int i)
+{
+ return liquid->getVertexYAt(i);
+}
+extern "C" float manta_liquid_get_vertex_z_at(MANTA *liquid, int i)
+{
+ return liquid->getVertexZAt(i);
+}
+
+extern "C" float manta_liquid_get_normal_x_at(MANTA *liquid, int i)
+{
+ return liquid->getNormalXAt(i);
+}
+extern "C" float manta_liquid_get_normal_y_at(MANTA *liquid, int i)
+{
+ return liquid->getNormalYAt(i);
+}
+extern "C" float manta_liquid_get_normal_z_at(MANTA *liquid, int i)
+{
+ return liquid->getNormalZAt(i);
+}
+
+extern "C" int manta_liquid_get_triangle_x_at(MANTA *liquid, int i)
+{
+ return liquid->getTriangleXAt(i);
+}
+extern "C" int manta_liquid_get_triangle_y_at(MANTA *liquid, int i)
+{
+ return liquid->getTriangleYAt(i);
+}
+extern "C" int manta_liquid_get_triangle_z_at(MANTA *liquid, int i)
+{
+ return liquid->getTriangleZAt(i);
+}
+
+extern "C" float manta_liquid_get_vertvel_x_at(MANTA *liquid, int i)
+{
+ return liquid->getVertVelXAt(i);
+}
+extern "C" float manta_liquid_get_vertvel_y_at(MANTA *liquid, int i)
+{
+ return liquid->getVertVelYAt(i);
+}
+extern "C" float manta_liquid_get_vertvel_z_at(MANTA *liquid, int i)
+{
+ return liquid->getVertVelZAt(i);
+}
+
+extern "C" int manta_liquid_get_num_flip_particles(MANTA *liquid)
+{
+ return liquid->getNumFlipParticles();
+}
+extern "C" int manta_liquid_get_num_snd_particles(MANTA *liquid)
+{
+ return liquid->getNumSndParticles();
+}
+
+extern "C" int manta_liquid_get_flip_particle_flag_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleFlagAt(i);
+}
+extern "C" int manta_liquid_get_snd_particle_flag_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleFlagAt(i);
+}
+
+extern "C" float manta_liquid_get_flip_particle_position_x_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticlePositionXAt(i);
+}
+extern "C" float manta_liquid_get_flip_particle_position_y_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticlePositionYAt(i);
+}
+extern "C" float manta_liquid_get_flip_particle_position_z_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticlePositionZAt(i);
+}
+
+extern "C" float manta_liquid_get_flip_particle_velocity_x_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleVelocityXAt(i);
+}
+extern "C" float manta_liquid_get_flip_particle_velocity_y_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleVelocityYAt(i);
+}
+extern "C" float manta_liquid_get_flip_particle_velocity_z_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleVelocityZAt(i);
+}
+
+extern "C" float manta_liquid_get_snd_particle_position_x_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticlePositionXAt(i);
+}
+extern "C" float manta_liquid_get_snd_particle_position_y_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticlePositionYAt(i);
+}
+extern "C" float manta_liquid_get_snd_particle_position_z_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticlePositionZAt(i);
+}
+
+extern "C" float manta_liquid_get_snd_particle_velocity_x_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleVelocityXAt(i);
+}
+extern "C" float manta_liquid_get_snd_particle_velocity_y_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleVelocityYAt(i);
+}
+extern "C" float manta_liquid_get_snd_particle_velocity_z_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleVelocityZAt(i);
+}
diff --git a/intern/elbeem/extern/LBM_fluidsim.h b/intern/mantaflow/intern/manta_python_API.cpp
index 256d8c59daa..4609aee2f08 100644
--- a/intern/elbeem/extern/LBM_fluidsim.h
+++ b/intern/mantaflow/intern/manta_python_API.cpp
@@ -1,8 +1,10 @@
/*
+ * ***** 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.
+ * 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
@@ -13,23 +15,23 @@
* 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) Blender Foundation.
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
*/
-/** \file
- * \ingroup elbeem
+/** \file mantaflow/intern/manta_python_API.cpp
+ * \ingroup mantaflow
*/
-#ifndef LBM_FLUIDSIM_H
-#define LBM_FLUIDSIM_H
-
-/* note; elbeem.h was exported all over, should only expose LBM_fluidsim.h */
-#include "elbeem.h"
-
-/* run simulation with given config file */
-// implemented in intern/elbeem/blendercall.cpp
-int performElbeemSimulation(char *cfgfilename);
-
+#include "Python.h"
+#include "manta_python_API.h"
+#include "manta.h"
-#endif
+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..cef129dd867
--- /dev/null
+++ b/intern/mantaflow/intern/strings/fluid_script.h
@@ -0,0 +1,788 @@
+/*
+ * ***** 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 <string>
+
+//////////////////////////////////////////////////////////////////////
+// LIBRARIES
+//////////////////////////////////////////////////////////////////////
+
+const std::string manta_import =
+ "\
+from manta import *\n\
+import os.path, shutil, math, sys, gc, multiprocessing, platform, time\n\
+\n\
+withMP = False\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_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\
+\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($NOISE_RESX$, $NOISE_RESY$, $NOISE_RESZ$)\n";
+
+const std::string fluid_variables_mesh =
+ "\n\
+mantaMsg('Fluid variables mesh')\n\
+upres_sm$ID$ = $MESH_SCALE$\n\
+gs_sm$ID$ = vec3($MESH_RESX$, $MESH_RESY$, $MESH_RESZ$)\n";
+
+const std::string fluid_variables_particles =
+ "\n\
+mantaMsg('Fluid variables particles')\n\
+upres_sp$ID$ = $PARTICLE_SCALE$\n\
+gs_sp$ID$ = vec3($PARTICLE_RESX$, $PARTICLE_RESY$, $PARTICLE_RESZ$)\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_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 / 10.\n\
+s$ID$.timestepMax = s$ID$.frameLength\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_time_stepping_noise =
+ "\n\
+mantaMsg('Fluid adaptive time stepping noise')\n\
+sn$ID$.frameLength = frameLength_s$ID$\n\
+sn$ID$.timestepMin = sn$ID$.frameLength / 10.\n\
+sn$ID$.timestepMax = sn$ID$.frameLength\n\
+sn$ID$.cfl = cflCond_s$ID$\n\
+sn$ID$.timestep = dt0_s$ID$\n\
+sn$ID$.timeTotal = timeTotal_s$ID$\n\
+#mantaMsg('noise timestep: ' + str(sn$ID$.timestep) + ' // timPerFrame: ' + str(sn$ID$.timePerFrame) + ' // frameLength: ' + str(sn$ID$.frameLength) + ' // timeTotal: ' + str(sn$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$ = 0\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_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\
+ # 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\
+ phiObs_s$ID$.setConst(9999)\n\
+ phiOut_s$ID$.setConst(9999)\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 '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\
+\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):\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\
+ p$ID$ = multiprocessing.Process(target=function, args=args)\n\
+ p$ID$.start()\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_guiding_s$ID$:\n\
+ fluid_load_guiding_$ID$(path_guiding, framenr, format_guiding)\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 withMP 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)\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\
+ mantaMsg('sn$ID$.timeTotal: ' + str(sn$ID$.timeTotal))\n\
+ \n\
+ fluid_load_data_$ID$(path_data, framenr, format_data)\n\
+ smoke_load_data_$ID$(path_data, framenr, format_data)\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 withMP 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\
+ \n\
+ fluid_load_data_$ID$(path_data, framenr, format_data)\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_load_data_$ID$(path_data, framenr, format_data)\n\
+ liquid_load_flip_$ID$(path_data, framenr, format_particles)\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 withMP 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\
+ \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\
+ if framenr>1:\n\
+ fluid_load_particles_$ID$(path_particles, framenr-1, format_particles)\n\
+ liquid_load_particles_$ID$(path_particles, framenr-1, format_particles)\n\
+ \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 withMP 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 withMP 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_data=format_guiding, path_data=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\
+ vel_dict = dict(vel=guidevel_sg$ID$)\n\
+ fluid_file_import_s$ID$(dict=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$(dict, path, framenr, file_format, mode_override=True):\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\
+ fluid_file_export_s$ID$(dict=fluid_particles_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\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\
+ fluid_file_export_s$ID$(dict=fluid_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\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\
+ fluid_file_export_s$ID$(dict=fluid_guiding_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\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..e339a60bc63
--- /dev/null
+++ b/intern/mantaflow/intern/strings/liquid_script.h
@@ -0,0 +1,439 @@
+/*
+ * ***** 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 <string>
+
+//////////////////////////////////////////////////////////////////////
+// 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\
+concaveUpper_s$ID$ = $MESH_CONCAVE_UPPER$\n\
+concaveLower_s$ID$ = $MESH_CONCAVE_LOWER$\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\
+fractions_s$ID$ = 0 # s$ID$.create(MACGrid) # TODO (sebbas): disabling fractions for now - not fracwallbcs not supporting obvels yet\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\
+\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=0, phiWalls=phiObs_s$ID$, outflow=boundConditions_s$ID$) # TODO (sebbas): bwidth=1 for fraction support\n\
+ \n\
+ if using_obstacle_s$ID$:\n\
+ mantaMsg('Initializing obstacle levelset')\n\
+ phiObsIn_s$ID$.fillHoles(maxsize=3)\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\
+ # additional sanity check: fill holes in phiObs which can result after joining with phiObsIn\n\
+ phiObs_s$ID$.fillHoles(maxsize=3)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=3, inside=True)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=3, 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\
+ #updateFractions(flags=flags_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$, boundaryWidth=boundaryWidth_s$ID$) # TODO (sebbas): uncomment for fraction support\n\
+ setObstacleFlags(flags=flags_s$ID$, phiObs=phiObs_s$ID$, phiOut=phiOut_s$ID$, fractions=fractions_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$, refillEmpty=True)\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(pp_s$ID$, pindex_s$ID$, flags_s$ID$, gpi_s$ID$, phiParts_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) # TODO (sebbas): uncomment for fraction support\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=obvel_s$ID$ if using_obstacle_s$ID$ else None, 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=obvel_s$ID$ if using_obstacle_s$ID$ else None, 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$)\n\
+ \n\
+ extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=4) #, intoObs=True) # TODO (sebbas): uncomment for fraction support\n\
+ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=obvel_s$ID$ if using_obstacle_s$ID$ else None, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
+ \n\
+ extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=(int(maxVel_s$ID$*1.25 )) ) # TODO (sebbas): extrapolation because of no fractions\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=1., 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=0.97)\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$) # mis-use phiParts as temp grid\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$, radiusFactor_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$, radiusFactor_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(boundaryWidth_s$ID$) # 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\
+ fluid_file_export_s$ID$(dict=liquid_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_save_flip =
+ "\n\
+def liquid_save_flip_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save flip')\n\
+ fluid_file_export_s$ID$(dict=liquid_flip_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_save_mesh =
+ "\n\
+def liquid_save_mesh_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save mesh')\n\
+ fluid_file_export_s$ID$(dict=liquid_mesh_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_save_meshvel =
+ "\n\
+def liquid_save_meshvel_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save mesh vel')\n\
+ fluid_file_export_s$ID$(dict=liquid_meshvel_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_save_particles =
+ "\n\
+def liquid_save_particles_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save particles')\n\
+ fluid_file_export_s$ID$(dict=liquid_particles_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\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..0b7fd4bddd9
--- /dev/null
+++ b/intern/mantaflow/intern/strings/smoke_script.h
@@ -0,0 +1,534 @@
+/*
+ * ***** 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 <string>
+
+//////////////////////////////////////////////////////////////////////
+// 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$ = $BUOYANCY_ALPHA$ / $FLUID_DOMAIN_SIZE$\n\
+buoyancy_heat_s$ID$ = $BUOYANCY_BETA$ / $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";
+
+const std::string smoke_variables_noise =
+ "\n\
+mantaMsg('Smoke variables noise')\n\
+wltStrength_s$ID$ = $WLT_STR$\n\
+octaves_s$ID$ = 0\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\
+mantaMsg('wltnoise_sn$ID$.posScale: (' + str(wltnoise_sn$ID$.posScale.x) + ', ' + str(wltnoise_sn$ID$.posScale.y) + ', ' + str(wltnoise_sn$ID$.posScale.z) + ')')\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$ = 0 # allocated dynamically\n\
+heatIn_s$ID$ = 0\n\
+flame_s$ID$ = 0\n\
+fuel_s$ID$ = 0\n\
+react_s$ID$ = 0\n\
+fuelIn_s$ID$ = 0\n\
+reactIn_s$ID$ = 0\n\
+color_r_s$ID$ = 0\n\
+color_g_s$ID$ = 0\n\
+color_b_s$ID$ = 0\n\
+color_r_in_s$ID$ = 0\n\
+color_g_in_s$ID$ = 0\n\
+color_b_in_s$ID$ = 0\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$ = 0\n\
+fuel_sn$ID$ = 0\n\
+react_sn$ID$ = 0\n\
+color_r_sn$ID$ = 0\n\
+color_g_sn$ID$ = 0\n\
+color_b_sn$ID$ = 0\n\
+wltnoise_sn$ID$ = sn$ID$.create(NoiseField, fixedSeed=265, loadFromFile=True)\n\
+\n\
+mantaMsg('Initializing UV Grids')\n\
+uv_s$ID$ = [] # list for UV grids\n\
+for i in range(uvs_s$ID$):\n\
+ uvGrid_s$ID$ = s$ID$.create(VecGrid)\n\
+ uv_s$ID$.append(uvGrid_s$ID$)\n\
+ resetUvGrid(target=uv_s$ID$[i], offset=uvs_offset_s$ID$)\n\
+\n\
+# Sync UV and texture grids\n\
+copyVec3ToReal(source=uv_s$ID$[0], targetX=texture_u_s$ID$, targetY=texture_v_s$ID$, targetZ=texture_w_s$ID$)\n\
+copyVec3ToReal(source=uv_s$ID$[1], 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$)\n\
+for i in range(uvs_s$ID$):\n\
+ k_s$ID$ = 'uvGrid' + str(i)\n\
+ v_s$ID$ = uv_s$ID$[i]\n\
+ smoke_noise_dict_s$ID$[k_s$ID$] = v_s$ID$\n";
+
+//////////////////////////////////////////////////////////////////////
+// ADDITIONAL GRIDS
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_alloc_colors =
+ "\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\
+tmpDict_s$ID$ = dict(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(tmpDict_s$ID$)\n\
+tmpDict_s$ID$ = dict(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\
+smoke_data_dict_s$ID$.update(tmpDict_s$ID$)\n";
+
+const std::string smoke_alloc_colors_noise =
+ "\
+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\
+tmpDict_s$ID$ = dict(color_r_noise=color_r_sn$ID$, color_g_noise=color_g_sn$ID$, color_b_noise=color_b_sn$ID$)\n\
+smoke_noise_dict_s$ID$.update(tmpDict_s$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\
+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\
+tmpDict_s$ID$ = dict(heat=heat_s$ID$, heatIn=heatIn_s$ID$,)\n\
+smoke_data_dict_s$ID$.update(tmpDict_s$ID$)\n";
+
+const std::string smoke_alloc_fire =
+ "\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\
+tmpDict_s$ID$ = dict(flame=flame_s$ID$, fuel=fuel_s$ID$, react=react_s$ID$,)\n\
+smoke_data_dict_s$ID$.update(tmpDict_s$ID$)\n\
+tmpDict_s$ID$ = dict(fuelIn=fuelIn_s$ID$, reactIn=reactIn_s$ID$,)\n\
+smoke_data_dict_s$ID$.update(tmpDict_s$ID$)\n";
+
+const std::string smoke_alloc_fire_noise =
+ "\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\
+tmpDict_s$ID$ = dict(flame_noise=flame_sn$ID$, fuel_noise=fuel_sn$ID$, react_noise=react_sn$ID$)\n\
+smoke_noise_dict_s$ID$.update(tmpDict_s$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(maxsize=3)\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\
+ # additional sanity check: fill holes in phiObs which can result after joining with phiObsIn\n\
+ phiObs_s$ID$.fillHoles(maxsize=3)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=3, inside=True)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=3, 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\
+ mantaMsg('Smoke inflow')\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\
+ vorticityConfinement(vel=vel_s$ID$, flags=flags_s$ID$, strength=vorticity_s$ID$)\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=$BURNING_RATE$, flameSmoke=$FLAME_SMOKE$, ignitionTemp=$IGNITION_TEMP$, maxTemp=$MAX_TEMP$, flameSmokeColor=vec3($FLAME_SMOKE_COLOR_X$,$FLAME_SMOKE_COLOR_Y$,$FLAME_SMOKE_COLOR_Z$))\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\
+ mantaMsg('Interpolating grids')\n\
+ interpolateGrid(target=phiIn_sn$ID$, source=phiIn_s$ID$)\n\
+ if using_outflow_s$ID$:\n\
+ interpolateGrid(target=phiOut_sn$ID$, source=phiOut_s$ID$)\n\
+ if using_obstacle_s$ID$:\n\
+ interpolateGrid(target=phiObs_sn$ID$, source=phiObs_s$ID$)\n\
+ interpolateMACGrid(target=vel_sn$ID$, source=vel_s$ID$)\n\
+ \n\
+ copyRealToVec3(sourceX=texture_u_s$ID$, sourceY=texture_v_s$ID$, sourceZ=texture_w_s$ID$, target=uv_s$ID$[0])\n\
+ copyRealToVec3(sourceX=texture_u2_s$ID$, sourceY=texture_v2_s$ID$, sourceZ=texture_w2_s$ID$, target=uv_s$ID$[1])\n\
+ \n\
+ flags_sn$ID$.initDomain(boundaryWidth=0, phiWalls=phiObs_sn$ID$, outflow=boundConditions_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\
+ 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=uv_s$ID$[0], targetX=texture_u_s$ID$, targetY=texture_v_s$ID$, targetZ=texture_w_s$ID$)\n\
+ copyVec3ToReal(source=uv_s$ID$[1], 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\
+ for i in range(uvs_s$ID$):\n\
+ mantaMsg('Advecting UV')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=uv_s$ID$[i], order=2)\n\
+ mantaMsg('Updating UVWeight')\n\
+ updateUvWeight(resetTime=sn$ID$.timestep*10.0 , index=i, numUvs=uvs_s$ID$, uv=uv_s$ID$[i], 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\
+ for i in range(uvs_s$ID$):\n\
+ uvWeight_s$ID$ = getUvWeight(uv_s$ID$[i])\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=uv_s$ID$[i])\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=$BURNING_RATE$, flameSmoke=$FLAME_SMOKE$, ignitionTemp=$IGNITION_TEMP$, maxTemp=$MAX_TEMP$, flameSmokeColor=vec3($FLAME_SMOKE_COLOR_X$,$FLAME_SMOKE_COLOR_Y$,$FLAME_SMOKE_COLOR_Z$))\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";
+
+//////////////////////////////////////////////////////////////////////
+// EXPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_save_data =
+ "\n\
+def smoke_save_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Smoke save data')\n\
+ fluid_file_export_s$ID$(dict=smoke_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string smoke_save_noise =
+ "\n\
+def smoke_save_noise_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Smoke save noise')\n\
+ fluid_file_export_s$ID$(dict=smoke_noise_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\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";
diff --git a/intern/smoke/CMakeLists.txt b/intern/smoke/CMakeLists.txt
deleted file mode 100644
index 5c8e495fa93..00000000000
--- a/intern/smoke/CMakeLists.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-# ***** 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) 2006, Blender Foundation
-# All rights reserved.
-# ***** END GPL LICENSE BLOCK *****
-
-set(INC
- intern
- ../memutil
-)
-
-set(INC_SYS
- ${BULLET_INCLUDE_DIRS}
- ${PNG_INCLUDE_DIRS}
- ${ZLIB_INCLUDE_DIRS}
-)
-
-set(SRC
- intern/EIGENVALUE_HELPER.cpp
- intern/FLUID_3D.cpp
- intern/FLUID_3D_SOLVERS.cpp
- intern/FLUID_3D_STATIC.cpp
- intern/LU_HELPER.cpp
- intern/SPHERE.cpp
- intern/WTURBULENCE.cpp
- intern/smoke_API.cpp
-
- extern/smoke_API.h
- intern/EIGENVALUE_HELPER.h
- intern/FFT_NOISE.h
- intern/FLUID_3D.h
- intern/IMAGE.h
- intern/INTERPOLATE.h
- intern/LU_HELPER.h
- intern/MERSENNETWISTER.h
- intern/OBSTACLE.h
- intern/SPHERE.h
- intern/VEC3.h
- intern/WAVELET_NOISE.h
- intern/WTURBULENCE.h
- intern/tnt/jama_eig.h
- intern/tnt/jama_lu.h
- intern/tnt/tnt.h
- intern/tnt/tnt_array1d.h
- intern/tnt/tnt_array1d_utils.h
- intern/tnt/tnt_array2d.h
- intern/tnt/tnt_array2d_utils.h
- intern/tnt/tnt_array3d.h
- intern/tnt/tnt_array3d_utils.h
- intern/tnt/tnt_cmat.h
- intern/tnt/tnt_fortran_array1d.h
- intern/tnt/tnt_fortran_array1d_utils.h
- intern/tnt/tnt_fortran_array2d.h
- intern/tnt/tnt_fortran_array2d_utils.h
- intern/tnt/tnt_fortran_array3d.h
- intern/tnt/tnt_fortran_array3d_utils.h
- intern/tnt/tnt_i_refvec.h
- intern/tnt/tnt_math_utils.h
- intern/tnt/tnt_sparse_matrix_csr.h
- intern/tnt/tnt_stopwatch.h
- intern/tnt/tnt_subscript.h
- intern/tnt/tnt_vec.h
- intern/tnt/tnt_version.h
-)
-
-set(LIB
-)
-
-# quiet -Wundef
-add_definitions(-DDDF_DEBUG=0)
-
-if(WITH_OPENMP)
- add_definitions(-DPARALLEL=1)
-else()
- add_definitions(-DPARALLEL=0)
-endif()
-
-if(WITH_FFTW3)
- add_definitions(-DWITH_FFTW3)
- list(APPEND INC_SYS
- ${FFTW3_INCLUDE_DIRS}
- )
-endif()
-
-blender_add_lib(bf_intern_smoke "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/intern/smoke/extern/smoke_API.h b/intern/smoke/extern/smoke_API.h
deleted file mode 100644
index 169f679526c..00000000000
--- a/intern/smoke/extern/smoke_API.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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) 2009 by Daniel Genrich
- * All rights reserved.
- */
-
-/** \file
- * \ingroup smoke
- */
-
-
-#ifndef SMOKE_API_H_
-#define SMOKE_API_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct FLUID_3D;
-
-// low res
-struct FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, int use_fire, int use_colors);
-void smoke_free(struct FLUID_3D *fluid);
-
-void smoke_initBlenderRNA(struct FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
- float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp);
-void smoke_step(struct FLUID_3D *fluid, float gravity[3], float dtSubdiv);
-
-float *smoke_get_density(struct FLUID_3D *fluid);
-float *smoke_get_flame(struct FLUID_3D *fluid);
-float *smoke_get_fuel(struct FLUID_3D *fluid);
-float *smoke_get_react(struct FLUID_3D *fluid);
-float *smoke_get_color_r(struct FLUID_3D *fluid);
-float *smoke_get_color_g(struct FLUID_3D *fluid);
-float *smoke_get_color_b(struct FLUID_3D *fluid);
-void smoke_get_rgba(struct FLUID_3D *fluid, float *data, int sequential);
-void smoke_get_rgba_from_density(struct FLUID_3D *fluid, float color[3], float *data, int sequential);
-float *smoke_get_heat(struct FLUID_3D *fluid);
-float *smoke_get_velocity_x(struct FLUID_3D *fluid);
-float *smoke_get_velocity_y(struct FLUID_3D *fluid);
-float *smoke_get_velocity_z(struct FLUID_3D *fluid);
-
-/* Moving obstacle velocity provided by blender */
-void smoke_get_ob_velocity(struct FLUID_3D *fluid, float **x, float **y, float **z);
-
-float *smoke_get_force_x(struct FLUID_3D *fluid);
-float *smoke_get_force_y(struct FLUID_3D *fluid);
-float *smoke_get_force_z(struct FLUID_3D *fluid);
-
-unsigned char *smoke_get_obstacle(struct FLUID_3D *fluid);
-
-size_t smoke_get_index(int x, int max_x, int y, int max_y, int z);
-size_t smoke_get_index2d(int x, int max_x, int y);
-
-void smoke_dissolve(struct FLUID_3D *fluid, int speed, int log);
-
-// wavelet turbulence functions
-struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors);
-void smoke_turbulence_free(struct WTURBULENCE *wt);
-void smoke_turbulence_step(struct WTURBULENCE *wt, struct FLUID_3D *fluid);
-
-float *smoke_turbulence_get_density(struct WTURBULENCE *wt);
-float *smoke_turbulence_get_color_r(struct WTURBULENCE *wt);
-float *smoke_turbulence_get_color_g(struct WTURBULENCE *wt);
-float *smoke_turbulence_get_color_b(struct WTURBULENCE *wt);
-void smoke_turbulence_get_rgba(struct WTURBULENCE *wt, float *data, int sequential);
-void smoke_turbulence_get_rgba_from_density(struct WTURBULENCE *wt, float color[3], float *data, int sequential);
-float *smoke_turbulence_get_flame(struct WTURBULENCE *wt);
-float *smoke_turbulence_get_fuel(struct WTURBULENCE *wt);
-float *smoke_turbulence_get_react(struct WTURBULENCE *wt);
-void smoke_turbulence_get_res(struct WTURBULENCE *wt, int *res);
-int smoke_turbulence_get_cells(struct WTURBULENCE *wt);
-void smoke_turbulence_set_noise(struct WTURBULENCE *wt, int type, const char *noisefile_path);
-void smoke_initWaveletBlenderRNA(struct WTURBULENCE *wt, float *strength);
-void smoke_dissolve_wavelet(struct WTURBULENCE *wt, int speed, int log);
-
-/* export */
-void smoke_export(struct FLUID_3D *fluid, float *dt, float *dx, float **dens, float **react, float **flame, float **fuel, float **heat, float **heatold,
- float **vx, float **vy, float **vz, float **r, float **g, float **b, unsigned char **obstacles);
-void smoke_turbulence_export(struct WTURBULENCE *wt, float **dens, float **react, float **flame, float **fuel,
- float **r, float **g, float **b, float **tcu, float **tcv, float **tcw);
-
-/* data fields */
-int smoke_has_heat(struct FLUID_3D *fluid);
-int smoke_has_fuel(struct FLUID_3D *fluid);
-int smoke_has_colors(struct FLUID_3D *fluid);
-int smoke_turbulence_has_fuel(struct WTURBULENCE *wt);
-int smoke_turbulence_has_colors(struct WTURBULENCE *wt);
-
-void smoke_ensure_heat(struct FLUID_3D *fluid);
-void smoke_ensure_fire(struct FLUID_3D *fluid, struct WTURBULENCE *wt);
-void smoke_ensure_colors(struct FLUID_3D *fluid, struct WTURBULENCE *wt, float init_r, float init_g, float init_b);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* SMOKE_API_H_ */
diff --git a/intern/smoke/intern/EIGENVALUE_HELPER.cpp b/intern/smoke/intern/EIGENVALUE_HELPER.cpp
deleted file mode 100644
index fbfd6d3bd22..00000000000
--- a/intern/smoke/intern/EIGENVALUE_HELPER.cpp
+++ /dev/null
@@ -1,888 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-
-#include "EIGENVALUE_HELPER.h"
-
-
-void Eigentred2(sEigenvalue& eval) {
-
- // This is derived from the Algol procedures tred2 by
- // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
- // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- int n=eval.n;
-
- for (int j = 0; j < n; j++) {
- eval.d[j] = eval.V[n-1][j];
- }
-
- // Householder reduction to tridiagonal form.
-
- for (int i = n-1; i > 0; i--) {
-
- // Scale to avoid under/overflow.
-
- float scale = 0.0;
- float h = 0.0;
- for (int k = 0; k < i; k++) {
- scale = scale + fabs(eval.d[k]);
- }
- if (scale == 0.0f) {
- eval.e[i] = eval.d[i-1];
- for (int j = 0; j < i; j++) {
- eval.d[j] = eval.V[i-1][j];
- eval.V[i][j] = 0.0;
- eval.V[j][i] = 0.0;
- }
- } else {
-
- // Generate Householder vector.
-
- for (int k = 0; k < i; k++) {
- eval.d[k] /= scale;
- h += eval.d[k] * eval.d[k];
- }
- float f = eval.d[i-1];
- float g = sqrt(h);
- if (f > 0) {
- g = -g;
- }
- eval.e[i] = scale * g;
- h = h - f * g;
- eval.d[i-1] = f - g;
- for (int j = 0; j < i; j++) {
- eval.e[j] = 0.0;
- }
-
- // Apply similarity transformation to remaining columns.
-
- for (int j = 0; j < i; j++) {
- f = eval.d[j];
- eval.V[j][i] = f;
- g = eval.e[j] + eval.V[j][j] * f;
- for (int k = j+1; k <= i-1; k++) {
- g += eval.V[k][j] * eval.d[k];
- eval.e[k] += eval.V[k][j] * f;
- }
- eval.e[j] = g;
- }
- f = 0.0;
- for (int j = 0; j < i; j++) {
- eval.e[j] /= h;
- f += eval.e[j] * eval.d[j];
- }
- float hh = f / (h + h);
- for (int j = 0; j < i; j++) {
- eval.e[j] -= hh * eval.d[j];
- }
- for (int j = 0; j < i; j++) {
- f = eval.d[j];
- g = eval.e[j];
- for (int k = j; k <= i-1; k++) {
- eval.V[k][j] -= (f * eval.e[k] + g * eval.d[k]);
- }
- eval.d[j] = eval.V[i-1][j];
- eval.V[i][j] = 0.0;
- }
- }
- eval.d[i] = h;
- }
-
- // Accumulate transformations.
-
- for (int i = 0; i < n-1; i++) {
- eval.V[n-1][i] = eval.V[i][i];
- eval.V[i][i] = 1.0;
- float h = eval.d[i+1];
- if (h != 0.0f) {
- for (int k = 0; k <= i; k++) {
- eval.d[k] = eval.V[k][i+1] / h;
- }
- for (int j = 0; j <= i; j++) {
- float g = 0.0;
- for (int k = 0; k <= i; k++) {
- g += eval.V[k][i+1] * eval.V[k][j];
- }
- for (int k = 0; k <= i; k++) {
- eval.V[k][j] -= g * eval.d[k];
- }
- }
- }
- for (int k = 0; k <= i; k++) {
- eval.V[k][i+1] = 0.0;
- }
- }
- for (int j = 0; j < n; j++) {
- eval.d[j] = eval.V[n-1][j];
- eval.V[n-1][j] = 0.0;
- }
- eval.V[n-1][n-1] = 1.0;
- eval.e[0] = 0.0;
-}
-
-void Eigencdiv(sEigenvalue& eval, float xr, float xi, float yr, float yi) {
- float r,d;
- if (fabs(yr) > fabs(yi)) {
- r = yi/yr;
- d = yr + r*yi;
- eval.cdivr = (xr + r*xi)/d;
- eval.cdivi = (xi - r*xr)/d;
- } else {
- r = yr/yi;
- d = yi + r*yr;
- eval.cdivr = (r*xr + xi)/d;
- eval.cdivi = (r*xi - xr)/d;
- }
- }
-
-void Eigentql2 (sEigenvalue& eval) {
-
- // This is derived from the Algol procedures tql2, by
- // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
- // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- int n=eval.n;
-
- for (int i = 1; i < n; i++) {
- eval.e[i-1] = eval.e[i];
- }
- eval.e[n-1] = 0.0;
-
- float f = 0.0;
- float tst1 = 0.0;
- float eps = pow(2.0,-52.0);
- for (int l = 0; l < n; l++) {
-
- // Find small subdiagonal element
-
- tst1 = max(tst1,fabs(eval.d[l]) + fabs(eval.e[l]));
- int m = l;
-
- // Original while-loop from Java code
- while (m < n) {
- if (fabs(eval.e[m]) <= eps*tst1) {
- break;
- }
- m++;
- }
-
-
- // If m == l, d[l] is an eigenvalue,
- // otherwise, iterate.
-
- if (m > l) {
- int iter = 0;
- do {
- iter = iter + 1; // (Could check iteration count here.)
-
- // Compute implicit shift
-
- float g = eval.d[l];
- float p = (eval.d[l+1] - g) / (2.0f * eval.e[l]);
- float r = hypot(p,1.0);
- if (p < 0) {
- r = -r;
- }
- eval.d[l] = eval.e[l] / (p + r);
- eval.d[l+1] = eval.e[l] * (p + r);
- float dl1 = eval.d[l+1];
- float h = g - eval.d[l];
- for (int i = l+2; i < n; i++) {
- eval.d[i] -= h;
- }
- f = f + h;
-
- // Implicit QL transformation.
-
- p = eval.d[m];
- float c = 1.0;
- float c2 = c;
- float c3 = c;
- float el1 = eval.e[l+1];
- float s = 0.0;
- float s2 = 0.0;
- for (int i = m-1; i >= l; i--) {
- c3 = c2;
- c2 = c;
- s2 = s;
- g = c * eval.e[i];
- h = c * p;
- r = hypot(p,eval.e[i]);
- eval.e[i+1] = s * r;
- s = eval.e[i] / r;
- c = p / r;
- p = c * eval.d[i] - s * g;
- eval.d[i+1] = h + s * (c * g + s * eval.d[i]);
-
- // Accumulate transformation.
-
- for (int k = 0; k < n; k++) {
- h = eval.V[k][i+1];
- eval.V[k][i+1] = s * eval.V[k][i] + c * h;
- eval.V[k][i] = c * eval.V[k][i] - s * h;
- }
- }
- p = -s * s2 * c3 * el1 * eval.e[l] / dl1;
- eval.e[l] = s * p;
- eval.d[l] = c * p;
-
- // Check for convergence.
-
- } while (fabs(eval.e[l]) > eps*tst1);
- }
- eval.d[l] = eval.d[l] + f;
- eval.e[l] = 0.0;
- }
-
- // Sort eigenvalues and corresponding vectors.
-
- for (int i = 0; i < n-1; i++) {
- int k = i;
- float p = eval.d[i];
- for (int j = i+1; j < n; j++) {
- if (eval.d[j] < p) {
- k = j;
- p = eval.d[j];
- }
- }
- if (k != i) {
- eval.d[k] = eval.d[i];
- eval.d[i] = p;
- for (int j = 0; j < n; j++) {
- p = eval.V[j][i];
- eval.V[j][i] = eval.V[j][k];
- eval.V[j][k] = p;
- }
- }
- }
-}
-
-void Eigenorthes (sEigenvalue& eval) {
-
- // This is derived from the Algol procedures orthes and ortran,
- // by Martin and Wilkinson, Handbook for Auto. Comp.,
- // Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutines in EISPACK.
-
- int n=eval.n;
-
- int low = 0;
- int high = n-1;
-
- for (int m = low+1; m <= high-1; m++) {
-
- // Scale column.
-
- float scale = 0.0;
- for (int i = m; i <= high; i++) {
- scale = scale + fabs(eval.H[i][m-1]);
- }
- if (scale != 0.0f) {
-
- // Compute Householder transformation.
-
- float h = 0.0;
- for (int i = high; i >= m; i--) {
- eval.ort[i] = eval.H[i][m-1]/scale;
- h += eval.ort[i] * eval.ort[i];
- }
- float g = sqrt(h);
- if (eval.ort[m] > 0) {
- g = -g;
- }
- h = h - eval.ort[m] * g;
- eval.ort[m] = eval.ort[m] - g;
-
- // Apply Householder similarity transformation
- // H = (I-u*u'/h)*H*(I-u*u')/h)
-
- for (int j = m; j < n; j++) {
- float f = 0.0;
- for (int i = high; i >= m; i--) {
- f += eval.ort[i]*eval.H[i][j];
- }
- f = f/h;
- for (int i = m; i <= high; i++) {
- eval.H[i][j] -= f*eval.ort[i];
- }
- }
-
- for (int i = 0; i <= high; i++) {
- float f = 0.0;
- for (int j = high; j >= m; j--) {
- f += eval.ort[j]*eval.H[i][j];
- }
- f = f/h;
- for (int j = m; j <= high; j++) {
- eval.H[i][j] -= f*eval.ort[j];
- }
- }
- eval.ort[m] = scale*eval.ort[m];
- eval.H[m][m-1] = scale*g;
- }
- }
-
- // Accumulate transformations (Algol's ortran).
-
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- eval.V[i][j] = (i == j ? 1.0 : 0.0);
- }
- }
-
- for (int m = high-1; m >= low+1; m--) {
- if (eval.H[m][m-1] != 0.0f) {
- for (int i = m+1; i <= high; i++) {
- eval.ort[i] = eval.H[i][m-1];
- }
- for (int j = m; j <= high; j++) {
- float g = 0.0;
- for (int i = m; i <= high; i++) {
- g += eval.ort[i] * eval.V[i][j];
- }
- // Double division avoids possible underflow
- g = (g / eval.ort[m]) / eval.H[m][m-1];
- for (int i = m; i <= high; i++) {
- eval.V[i][j] += g * eval.ort[i];
- }
- }
- }
- }
- }
-
-void Eigenhqr2 (sEigenvalue& eval) {
-
- // This is derived from the Algol procedure hqr2,
- // by Martin and Wilkinson, Handbook for Auto. Comp.,
- // Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- // Initialize
-
- int nn = eval.n;
- int n = nn-1;
- int low = 0;
- int high = nn-1;
- float eps = pow(2.0,-52.0);
- float exshift = 0.0;
- float p=0,q=0,r=0,s=0,z=0,t,w,x,y;
-
- // Store roots isolated by balanc and compute matrix norm
-
- float norm = 0.0;
- for (int i = 0; i < nn; i++) {
- if ((i < low) || (i > high)) {
- eval.d[i] = eval.H[i][i];
- eval.e[i] = 0.0;
- }
- for (int j = max(i-1,0); j < nn; j++) {
- norm = norm + fabs(eval.H[i][j]);
- }
- }
-
- // Outer loop over eigenvalue index
-
- int iter = 0;
- int totIter = 0;
- while (n >= low) {
-
- // NT limit no. of iterations
- totIter++;
- if(totIter>100) {
- //if(totIter>15) std::cout<<"!!!!iter ABORT !!!!!!! "<<totIter<<"\n";
- // NT hack/fix, return large eigenvalues
- for (int i = 0; i < nn; i++) {
- eval.d[i] = 10000.;
- eval.e[i] = 10000.;
- }
- return;
- }
-
- // Look for single small sub-diagonal element
-
- int l = n;
- while (l > low) {
- s = fabs(eval.H[l-1][l-1]) + fabs(eval.H[l][l]);
- if (s == 0.0f) {
- s = norm;
- }
- if (fabs(eval.H[l][l-1]) < eps * s) {
- break;
- }
- l--;
- }
-
- // Check for convergence
- // One root found
-
- if (l == n) {
- eval.H[n][n] = eval.H[n][n] + exshift;
- eval.d[n] = eval.H[n][n];
- eval.e[n] = 0.0;
- n--;
- iter = 0;
-
- // Two roots found
-
- } else if (l == n-1) {
- w = eval.H[n][n-1] * eval.H[n-1][n];
- p = (eval.H[n-1][n-1] - eval.H[n][n]) / 2.0f;
- q = p * p + w;
- z = sqrt(fabs(q));
- eval.H[n][n] = eval.H[n][n] + exshift;
- eval.H[n-1][n-1] = eval.H[n-1][n-1] + exshift;
- x = eval.H[n][n];
-
- // float pair
-
- if (q >= 0) {
- if (p >= 0) {
- z = p + z;
- } else {
- z = p - z;
- }
- eval.d[n-1] = x + z;
- eval.d[n] = eval.d[n-1];
- if (z != 0.0f) {
- eval.d[n] = x - w / z;
- }
- eval.e[n-1] = 0.0;
- eval.e[n] = 0.0;
- x = eval.H[n][n-1];
- s = fabs(x) + fabs(z);
- p = x / s;
- q = z / s;
- r = sqrt(p * p+q * q);
- p = p / r;
- q = q / r;
-
- // Row modification
-
- for (int j = n-1; j < nn; j++) {
- z = eval.H[n-1][j];
- eval.H[n-1][j] = q * z + p * eval.H[n][j];
- eval.H[n][j] = q * eval.H[n][j] - p * z;
- }
-
- // Column modification
-
- for (int i = 0; i <= n; i++) {
- z = eval.H[i][n-1];
- eval.H[i][n-1] = q * z + p * eval.H[i][n];
- eval.H[i][n] = q * eval.H[i][n] - p * z;
- }
-
- // Accumulate transformations
-
- for (int i = low; i <= high; i++) {
- z = eval.V[i][n-1];
- eval.V[i][n-1] = q * z + p * eval.V[i][n];
- eval.V[i][n] = q * eval.V[i][n] - p * z;
- }
-
- // Complex pair
-
- } else {
- eval.d[n-1] = x + p;
- eval.d[n] = x + p;
- eval.e[n-1] = z;
- eval.e[n] = -z;
- }
- n = n - 2;
- iter = 0;
-
- // No convergence yet
-
- } else {
-
- // Form shift
-
- x = eval.H[n][n];
- y = 0.0;
- w = 0.0;
- if (l < n) {
- y = eval.H[n-1][n-1];
- w = eval.H[n][n-1] * eval.H[n-1][n];
- }
-
- // Wilkinson's original ad hoc shift
-
- if (iter == 10) {
- exshift += x;
- for (int i = low; i <= n; i++) {
- eval.H[i][i] -= x;
- }
- s = fabs(eval.H[n][n-1]) + fabs(eval.H[n-1][n-2]);
- x = y = 0.75f * s;
- w = -0.4375f * s * s;
- }
-
- // MATLAB's new ad hoc shift
-
- if (iter == 30) {
- s = (y - x) / 2.0f;
- s = s * s + w;
- if (s > 0) {
- s = sqrt(s);
- if (y < x) {
- s = -s;
- }
- s = x - w / ((y - x) / 2.0f + s);
- for (int i = low; i <= n; i++) {
- eval.H[i][i] -= s;
- }
- exshift += s;
- x = y = w = 0.964;
- }
- }
-
- iter = iter + 1; // (Could check iteration count here.)
-
- // Look for two consecutive small sub-diagonal elements
-
- int m = n-2;
- while (m >= l) {
- z = eval.H[m][m];
- r = x - z;
- s = y - z;
- p = (r * s - w) / eval.H[m+1][m] + eval.H[m][m+1];
- q = eval.H[m+1][m+1] - z - r - s;
- r = eval.H[m+2][m+1];
- s = fabs(p) + fabs(q) + fabs(r);
- p = p / s;
- q = q / s;
- r = r / s;
- if (m == l) {
- break;
- }
- if (fabs(eval.H[m][m-1]) * (fabs(q) + fabs(r)) <
- eps * (fabs(p) * (fabs(eval.H[m-1][m-1]) + fabs(z) +
- fabs(eval.H[m+1][m+1])))) {
- break;
- }
- m--;
- }
-
- for (int i = m+2; i <= n; i++) {
- eval.H[i][i-2] = 0.0;
- if (i > m+2) {
- eval.H[i][i-3] = 0.0;
- }
- }
-
- // Double QR step involving rows l:n and columns m:n
-
- for (int k = m; k <= n-1; k++) {
- int notlast = (k != n-1);
- if (k != m) {
- p = eval.H[k][k-1];
- q = eval.H[k+1][k-1];
- r = (notlast ? eval.H[k+2][k-1] : 0.0f);
- x = fabs(p) + fabs(q) + fabs(r);
- if (x != 0.0f) {
- p = p / x;
- q = q / x;
- r = r / x;
- }
- }
- if (x == 0.0f) {
- break;
- }
- s = sqrt(p * p + q * q + r * r);
- if (p < 0) {
- s = -s;
- }
- if (s != 0) {
- if (k != m) {
- eval.H[k][k-1] = -s * x;
- } else if (l != m) {
- eval.H[k][k-1] = -eval.H[k][k-1];
- }
- p = p + s;
- x = p / s;
- y = q / s;
- z = r / s;
- q = q / p;
- r = r / p;
-
- // Row modification
-
- for (int j = k; j < nn; j++) {
- p = eval.H[k][j] + q * eval.H[k+1][j];
- if (notlast) {
- p = p + r * eval.H[k+2][j];
- eval.H[k+2][j] = eval.H[k+2][j] - p * z;
- }
- eval.H[k][j] = eval.H[k][j] - p * x;
- eval.H[k+1][j] = eval.H[k+1][j] - p * y;
- }
-
- // Column modification
-
- for (int i = 0; i <= min(n,k+3); i++) {
- p = x * eval.H[i][k] + y * eval.H[i][k+1];
- if (notlast) {
- p = p + z * eval.H[i][k+2];
- eval.H[i][k+2] = eval.H[i][k+2] - p * r;
- }
- eval.H[i][k] = eval.H[i][k] - p;
- eval.H[i][k+1] = eval.H[i][k+1] - p * q;
- }
-
- // Accumulate transformations
-
- for (int i = low; i <= high; i++) {
- p = x * eval.V[i][k] + y * eval.V[i][k+1];
- if (notlast) {
- p = p + z * eval.V[i][k+2];
- eval.V[i][k+2] = eval.V[i][k+2] - p * r;
- }
- eval.V[i][k] = eval.V[i][k] - p;
- eval.V[i][k+1] = eval.V[i][k+1] - p * q;
- }
- } // (s != 0)
- } // k loop
- } // check convergence
- } // while (n >= low)
- //if(totIter>15) std::cout<<"!!!!iter "<<totIter<<"\n";
-
- // Backsubstitute to find vectors of upper triangular form
-
- if (norm == 0.0f) {
- return;
- }
-
- for (n = nn-1; n >= 0; n--) {
- p = eval.d[n];
- q = eval.e[n];
-
- // float vector
-
- if (q == 0) {
- int l = n;
- eval.H[n][n] = 1.0;
- for (int i = n-1; i >= 0; i--) {
- w = eval.H[i][i] - p;
- r = 0.0;
- for (int j = l; j <= n; j++) {
- r = r + eval.H[i][j] * eval.H[j][n];
- }
- if (eval.e[i] < 0.0f) {
- z = w;
- s = r;
- } else {
- l = i;
- if (eval.e[i] == 0.0f) {
- if (w != 0.0f) {
- eval.H[i][n] = -r / w;
- } else {
- eval.H[i][n] = -r / (eps * norm);
- }
-
- // Solve real equations
-
- } else {
- x = eval.H[i][i+1];
- y = eval.H[i+1][i];
- q = (eval.d[i] - p) * (eval.d[i] - p) + eval.e[i] * eval.e[i];
- t = (x * s - z * r) / q;
- eval.H[i][n] = t;
- if (fabs(x) > fabs(z)) {
- eval.H[i+1][n] = (-r - w * t) / x;
- } else {
- eval.H[i+1][n] = (-s - y * t) / z;
- }
- }
-
- // Overflow control
-
- t = fabs(eval.H[i][n]);
- if ((eps * t) * t > 1) {
- for (int j = i; j <= n; j++) {
- eval.H[j][n] = eval.H[j][n] / t;
- }
- }
- }
- }
-
- // Complex vector
-
- } else if (q < 0) {
- int l = n-1;
-
- // Last vector component imaginary so matrix is triangular
-
- if (fabs(eval.H[n][n-1]) > fabs(eval.H[n-1][n])) {
- eval.H[n-1][n-1] = q / eval.H[n][n-1];
- eval.H[n-1][n] = -(eval.H[n][n] - p) / eval.H[n][n-1];
- } else {
- Eigencdiv(eval, 0.0,-eval.H[n-1][n],eval.H[n-1][n-1]-p,q);
- eval.H[n-1][n-1] = eval.cdivr;
- eval.H[n-1][n] = eval.cdivi;
- }
- eval.H[n][n-1] = 0.0;
- eval.H[n][n] = 1.0;
- for (int i = n-2; i >= 0; i--) {
- float ra,sa,vr,vi;
- ra = 0.0;
- sa = 0.0;
- for (int j = l; j <= n; j++) {
- ra = ra + eval.H[i][j] * eval.H[j][n-1];
- sa = sa + eval.H[i][j] * eval.H[j][n];
- }
- w = eval.H[i][i] - p;
-
- if (eval.e[i] < 0.0f) {
- z = w;
- r = ra;
- s = sa;
- } else {
- l = i;
- if (eval.e[i] == 0) {
- Eigencdiv(eval,-ra,-sa,w,q);
- eval.H[i][n-1] = eval.cdivr;
- eval.H[i][n] = eval.cdivi;
- } else {
-
- // Solve complex equations
-
- x = eval.H[i][i+1];
- y = eval.H[i+1][i];
- vr = (eval.d[i] - p) * (eval.d[i] - p) + eval.e[i] * eval.e[i] - q * q;
- vi = (eval.d[i] - p) * 2.0f * q;
- if ((vr == 0.0f) && (vi == 0.0f)) {
- vr = eps * norm * (fabs(w) + fabs(q) +
- fabs(x) + fabs(y) + fabs(z));
- }
- Eigencdiv(eval, x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
- eval.H[i][n-1] = eval.cdivr;
- eval.H[i][n] = eval.cdivi;
- if (fabs(x) > (fabs(z) + fabs(q))) {
- eval.H[i+1][n-1] = (-ra - w * eval.H[i][n-1] + q * eval.H[i][n]) / x;
- eval.H[i+1][n] = (-sa - w * eval.H[i][n] - q * eval.H[i][n-1]) / x;
- } else {
- Eigencdiv(eval, -r-y*eval.H[i][n-1],-s-y*eval.H[i][n],z,q);
- eval.H[i+1][n-1] = eval.cdivr;
- eval.H[i+1][n] = eval.cdivi;
- }
- }
-
- // Overflow control
-
- t = max(fabs(eval.H[i][n-1]),fabs(eval.H[i][n]));
- if ((eps * t) * t > 1) {
- for (int j = i; j <= n; j++) {
- eval.H[j][n-1] = eval.H[j][n-1] / t;
- eval.H[j][n] = eval.H[j][n] / t;
- }
- }
- }
- }
- }
- }
-
- // Vectors of isolated roots
-
- for (int i = 0; i < nn; i++) {
- if (i < low || i > high) {
- for (int j = i; j < nn; j++) {
- eval.V[i][j] = eval.H[i][j];
- }
- }
- }
-
- // Back transformation to get eigenvectors of original matrix
-
- for (int j = nn-1; j >= low; j--) {
- for (int i = low; i <= high; i++) {
- z = 0.0;
- for (int k = low; k <= min(j,high); k++) {
- z = z + eval.V[i][k] * eval.H[k][j];
- }
- eval.V[i][j] = z;
- }
- }
-}
-
-
-
-int computeEigenvalues3x3(
- float dout[3],
- float a[3][3])
-{
- /*TNT::Array2D<float> A = TNT::Array2D<float>(3,3, &a[0][0]);
- TNT::Array1D<float> eig = TNT::Array1D<float>(3);
- TNT::Array1D<float> eigImag = TNT::Array1D<float>(3);
- JAMA::Eigenvalue<float> jeig = JAMA::Eigenvalue<float>(A);*/
-
- sEigenvalue jeig;
-
- // Compute the values
- {
- jeig.n = 3;
- int n=3;
- //V = Array2D<float>(n,n);
- //d = Array1D<float>(n);
- //e = Array1D<float>(n);
- for (int y=0; y<3; y++)
- {
- jeig.d[y]=0.0f;
- jeig.e[y]=0.0f;
- for (int t=0; t<3; t++) jeig.V[y][t]=0.0f;
- }
-
- jeig.issymmetric = 1;
- for (int j = 0; (j < 3) && jeig.issymmetric; j++) {
- for (int i = 0; (i < 3) && jeig.issymmetric; i++) {
- jeig.issymmetric = (a[i][j] == a[j][i]);
- }
- }
-
- if (jeig.issymmetric) {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- jeig.V[i][j] = a[i][j];
- }
- }
-
- // Tridiagonalize.
- Eigentred2(jeig);
-
- // Diagonalize.
- Eigentql2(jeig);
-
- } else {
- //H = TNT::Array2D<float>(n,n);
- for (int y=0; y<3; y++)
- {
- jeig.ort[y]=0.0f;
- for (int t=0; t<3; t++) jeig.H[y][t]=0.0f;
- }
- //ort = TNT::Array1D<float>(n);
-
- for (int j = 0; j < n; j++) {
- for (int i = 0; i < n; i++) {
- jeig.H[i][j] = a[i][j];
- }
- }
-
- // Reduce to Hessenberg form.
- Eigenorthes(jeig);
-
- // Reduce Hessenberg to real Schur form.
- Eigenhqr2(jeig);
- }
- }
-
- //jeig.getfloatEigenvalues(eig);
-
- // complex ones
- //jeig.getImagEigenvalues(eigImag);
- dout[0] = sqrt(jeig.d[0]*jeig.d[0] + jeig.e[0]*jeig.e[0]);
- dout[1] = sqrt(jeig.d[1]*jeig.d[1] + jeig.e[1]*jeig.e[1]);
- dout[2] = sqrt(jeig.d[2]*jeig.d[2] + jeig.e[2]*jeig.e[2]);
- return 0;
-}
diff --git a/intern/smoke/intern/EIGENVALUE_HELPER.h b/intern/smoke/intern/EIGENVALUE_HELPER.h
deleted file mode 100644
index ef204b442d9..00000000000
--- a/intern/smoke/intern/EIGENVALUE_HELPER.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-//////////////////////////////////////////////////////////////////////
-// Modified to not require TNT matrix library anymore. It was very slow
-// when being run in parallel. Required TNT JAMA::Eigenvalue libraries were
-// converted into independent functions.
-// - MiikaH
-//
-//////////////////////////////////////////////////////////////////////
-// Helper function, compute eigenvalues of 3x3 matrix
-//////////////////////////////////////////////////////////////////////
-
-#ifndef EIGENVAL_HELPER_H
-#define EIGENVAL_HELPER_H
-
-//#include "tnt/jama_eig.h"
-
-#include <algorithm>
-#include <cmath>
-
-using namespace std;
-
-//////////////////////////////////////////////////////////////////////
-// eigenvalues of 3x3 non-symmetric matrix
-//////////////////////////////////////////////////////////////////////
-
-
-struct sEigenvalue
-{
- int n;
- int issymmetric;
- float d[3]; /* real part */
- float e[3]; /* img part */
- float V[3][3]; /* Eigenvectors */
-
- float H[3][3];
-
-
- float ort[3];
-
- float cdivr;
- float cdivi;
-};
-
-void Eigentred2(sEigenvalue& eval);
-
-void Eigencdiv(sEigenvalue& eval, float xr, float xi, float yr, float yi);
-
-void Eigentql2 (sEigenvalue& eval);
-
-void Eigenorthes (sEigenvalue& eval);
-
-void Eigenhqr2 (sEigenvalue& eval);
-
-int computeEigenvalues3x3(float dout[3], float a[3][3]);
-
-
-#endif
diff --git a/intern/smoke/intern/FFT_NOISE.h b/intern/smoke/intern/FFT_NOISE.h
deleted file mode 100644
index d44cbabd64e..00000000000
--- a/intern/smoke/intern/FFT_NOISE.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-/////////////////////////////////////////////////////////////////////////
-//
-
-#ifndef FFT_NOISE_H_
-#define FFT_NOISE_H_
-
-#ifdef WITH_FFTW3
-#include <iostream>
-#include <fftw3.h>
-#include <MERSENNETWISTER.h>
-
-#include "WAVELET_NOISE.h"
-
-#ifndef M_PI
-#define M_PI 3.14159265
-#endif
-
-/////////////////////////////////////////////////////////////////////////
-// shift spectrum to the format that FFTW expects
-/////////////////////////////////////////////////////////////////////////
-static void shift3D(float*& field, int xRes, int yRes, int zRes)
-{
- int xHalf = xRes / 2;
- int yHalf = yRes / 2;
- int zHalf = zRes / 2;
- // int slabSize = xRes * yRes;
- for (int z = 0; z < zHalf; z++)
- for (int y = 0; y < yHalf; y++)
- for (int x = 0; x < xHalf; x++)
- {
- int index = x + y * xRes + z * xRes * yRes;
- float temp;
- int xSwap = xHalf;
- int ySwap = yHalf * xRes;
- int zSwap = zHalf * xRes * yRes;
-
- // [0,0,0] to [1,1,1]
- temp = field[index];
- field[index] = field[index + xSwap + ySwap + zSwap];
- field[index + xSwap + ySwap + zSwap] = temp;
-
- // [1,0,0] to [0,1,1]
- temp = field[index + xSwap];
- field[index + xSwap] = field[index + ySwap + zSwap];
- field[index + ySwap + zSwap] = temp;
-
- // [0,1,0] to [1,0,1]
- temp = field[index + ySwap];
- field[index + ySwap] = field[index + xSwap + zSwap];
- field[index + xSwap + zSwap] = temp;
-
- // [0,0,1] to [1,1,0]
- temp = field[index + zSwap];
- field[index + zSwap] = field[index + xSwap + ySwap];
- field[index + xSwap + ySwap] = temp;
- }
-}
-
-static void generatTile_FFT(float* const noiseTileData, std::string filename)
-{
- if (loadTile(noiseTileData, filename)) return;
-
- int res = NOISE_TILE_SIZE;
- int xRes = res;
- int yRes = res;
- int zRes = res;
- int totalCells = xRes * yRes * zRes;
-
- // create and shift the filter
- float* filter = new float[totalCells];
- for (int z = 0; z < zRes; z++)
- for (int y = 0; y < yRes; y++)
- for (int x = 0; x < xRes; x++)
- {
- int index = x + y * xRes + z * xRes * yRes;
- float diff[] = {(float)abs(x - xRes / 2),
- (float)abs(y - yRes / 2),
- (float)abs(z - zRes / 2)};
- float radius = sqrtf(diff[0] * diff[0] +
- diff[1] * diff[1] +
- diff[2] * diff[2]) / (xRes / 2);
- radius *= M_PI;
- float H = cos((M_PI / 2.0f) * log(4.0f * radius / M_PI) / log(2.0f));
- H = H * H;
- float filtered = H;
-
- // clamp everything outside the wanted band
- if (radius >= M_PI / 2.0f)
- filtered = 0.0f;
-
- // make sure to capture all low frequencies
- if (radius <= M_PI / 4.0f)
- filtered = 1.0f;
-
- filter[index] = filtered;
- }
- shift3D(filter, xRes, yRes, zRes);
-
- // create the noise
- float* noise = new float[totalCells];
- int index = 0;
- MTRand twister;
- for (int z = 0; z < zRes; z++)
- for (int y = 0; y < yRes; y++)
- for (int x = 0; x < xRes; x++, index++)
- noise[index] = twister.randNorm();
-
- // create padded field
- fftw_complex* forward = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * totalCells);
-
- // init padded field
- index = 0;
- for (int z = 0; z < zRes; z++)
- for (int y = 0; y < yRes; y++)
- for (int x = 0; x < xRes; x++, index++)
- {
- forward[index][0] = noise[index];
- forward[index][1] = 0.0f;
- }
-
- // forward FFT
- fftw_complex* backward = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * totalCells);
- fftw_plan forwardPlan = fftw_plan_dft_3d(xRes, yRes, zRes, forward, backward, FFTW_FORWARD, FFTW_ESTIMATE);
- fftw_execute(forwardPlan);
- fftw_destroy_plan(forwardPlan);
-
- // apply filter
- index = 0;
- for (int z = 0; z < zRes; z++)
- for (int y = 0; y < yRes; y++)
- for (int x = 0; x < xRes; x++, index++)
- {
- backward[index][0] *= filter[index];
- backward[index][1] *= filter[index];
- }
-
- // backward FFT
- fftw_plan backwardPlan = fftw_plan_dft_3d(xRes, yRes, zRes, backward, forward, FFTW_BACKWARD, FFTW_ESTIMATE);
- fftw_execute(backwardPlan);
- fftw_destroy_plan(backwardPlan);
-
- // subtract out the low frequency components
- index = 0;
- for (int z = 0; z < zRes; z++)
- for (int y = 0; y < yRes; y++)
- for (int x = 0; x < xRes; x++, index++)
- noise[index] -= forward[index][0] / totalCells;
-
- // fill noiseTileData
- memcpy(noiseTileData, noise, sizeof(float) * totalCells);
- // save out the noise tile
- saveTile(noise, filename);
-
- fftw_free(forward);
- fftw_free(backward);
- delete[] filter;
- delete[] noise;
-}
-
-#endif
-
-#endif /* FFT_NOISE_H_ */
diff --git a/intern/smoke/intern/FLUID_3D.cpp b/intern/smoke/intern/FLUID_3D.cpp
deleted file mode 100644
index e76abea35d8..00000000000
--- a/intern/smoke/intern/FLUID_3D.cpp
+++ /dev/null
@@ -1,1792 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// FLUID_3D.cpp: implementation of the FLUID_3D class.
-//
-//////////////////////////////////////////////////////////////////////
-// Heavy parallel optimization done. Many of the old functions now
-// take begin and end parameters and process only specified part of the data.
-// Some functions were divided into multiple ones.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#include "FLUID_3D.h"
-#include "IMAGE.h"
-#include <INTERPOLATE.h>
-#include "SPHERE.h"
-#include <zlib.h>
-
-#include "float.h"
-
-#if PARALLEL==1
-#include <omp.h>
-#endif // PARALLEL
-
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
-FLUID_3D::FLUID_3D(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors) :
- _xRes(res[0]), _yRes(res[1]), _zRes(res[2]), _res(0.0f)
-{
- // set simulation consts
- _dt = dtdef; // just in case. set in step from a RNA factor
-
- _iterations = 100;
- _tempAmb = 0;
- _heatDiffusion = 1e-3;
- _totalTime = 0.0f;
- _totalSteps = 0;
- _res = Vec3Int(_xRes,_yRes,_zRes);
- _maxRes = MAX3(_xRes, _yRes, _zRes);
-
- // initialize wavelet turbulence
- /*
- if(amplify)
- _wTurbulence = new WTURBULENCE(_res[0],_res[1],_res[2], amplify, noisetype);
- else
- _wTurbulence = NULL;
- */
-
- // scale the constants according to the refinement of the grid
- if (!dx)
- _dx = 1.0f / (float)_maxRes;
- else
- _dx = dx;
- _constantScaling = 64.0f / _maxRes;
- _constantScaling = (_constantScaling < 1.0f) ? 1.0f : _constantScaling;
- _vorticityEps = 2.0f / _constantScaling; // Just in case set a default value
-
- // allocate arrays
- _totalCells = _xRes * _yRes * _zRes;
- _slabSize = _xRes * _yRes;
- _xVelocity = new float[_totalCells];
- _yVelocity = new float[_totalCells];
- _zVelocity = new float[_totalCells];
- _xVelocityOb = new float[_totalCells];
- _yVelocityOb = new float[_totalCells];
- _zVelocityOb = new float[_totalCells];
- _xVelocityOld = new float[_totalCells];
- _yVelocityOld = new float[_totalCells];
- _zVelocityOld = new float[_totalCells];
- _xForce = new float[_totalCells];
- _yForce = new float[_totalCells];
- _zForce = new float[_totalCells];
- _density = new float[_totalCells];
- _densityOld = new float[_totalCells];
- _obstacles = new unsigned char[_totalCells]; // set 0 at end of step
-
- // For threaded version:
- _xVelocityTemp = new float[_totalCells];
- _yVelocityTemp = new float[_totalCells];
- _zVelocityTemp = new float[_totalCells];
- _densityTemp = new float[_totalCells];
-
- // DG TODO: check if alloc went fine
-
- for (int x = 0; x < _totalCells; x++)
- {
- _density[x] = 0.0f;
- _densityOld[x] = 0.0f;
- _xVelocity[x] = 0.0f;
- _yVelocity[x] = 0.0f;
- _zVelocity[x] = 0.0f;
- _xVelocityOb[x] = 0.0f;
- _yVelocityOb[x] = 0.0f;
- _zVelocityOb[x] = 0.0f;
- _xVelocityOld[x] = 0.0f;
- _yVelocityOld[x] = 0.0f;
- _zVelocityOld[x] = 0.0f;
- _xForce[x] = 0.0f;
- _yForce[x] = 0.0f;
- _zForce[x] = 0.0f;
- _obstacles[x] = false;
- }
-
- /* heat */
- _heat = _heatOld = _heatTemp = NULL;
- if (init_heat) {
- initHeat();
- }
- // Fire simulation
- _flame = _fuel = _fuelTemp = _fuelOld = NULL;
- _react = _reactTemp = _reactOld = NULL;
- if (init_fire) {
- initFire();
- }
- // Smoke color
- _color_r = _color_rOld = _color_rTemp = NULL;
- _color_g = _color_gOld = _color_gTemp = NULL;
- _color_b = _color_bOld = _color_bTemp = NULL;
- if (init_colors) {
- initColors(0.0f, 0.0f, 0.0f);
- }
-
- // boundary conditions of the fluid domain
- // set default values -> vertically non-colliding
- _domainBcFront = true;
- _domainBcTop = false;
- _domainBcLeft = true;
- _domainBcBack = _domainBcFront;
- _domainBcBottom = _domainBcTop;
- _domainBcRight = _domainBcLeft;
-
- _colloPrev = 1; // default value
-}
-
-void FLUID_3D::initHeat()
-{
- if (!_heat) {
- _heat = new float[_totalCells];
- _heatOld = new float[_totalCells];
- _heatTemp = new float[_totalCells];
-
- for (int x = 0; x < _totalCells; x++)
- {
- _heat[x] = 0.0f;
- _heatOld[x] = 0.0f;
- }
- }
-}
-
-void FLUID_3D::initFire()
-{
- if (!_flame) {
- _flame = new float[_totalCells];
- _fuel = new float[_totalCells];
- _fuelTemp = new float[_totalCells];
- _fuelOld = new float[_totalCells];
- _react = new float[_totalCells];
- _reactTemp = new float[_totalCells];
- _reactOld = new float[_totalCells];
-
- for (int x = 0; x < _totalCells; x++)
- {
- _flame[x] = 0.0f;
- _fuel[x] = 0.0f;
- _fuelTemp[x] = 0.0f;
- _fuelOld[x] = 0.0f;
- _react[x] = 0.0f;
- _reactTemp[x] = 0.0f;
- _reactOld[x] = 0.0f;
- }
- }
-}
-
-void FLUID_3D::initColors(float init_r, float init_g, float init_b)
-{
- if (!_color_r) {
- _color_r = new float[_totalCells];
- _color_rOld = new float[_totalCells];
- _color_rTemp = new float[_totalCells];
- _color_g = new float[_totalCells];
- _color_gOld = new float[_totalCells];
- _color_gTemp = new float[_totalCells];
- _color_b = new float[_totalCells];
- _color_bOld = new float[_totalCells];
- _color_bTemp = new float[_totalCells];
-
- for (int x = 0; x < _totalCells; x++)
- {
- _color_r[x] = _density[x] * init_r;
- _color_rOld[x] = 0.0f;
- _color_g[x] = _density[x] * init_g;
- _color_gOld[x] = 0.0f;
- _color_b[x] = _density[x] * init_b;
- _color_bOld[x] = 0.0f;
- }
- }
-}
-
-void FLUID_3D::setBorderObstacles()
-{
-
- // set side obstacles
- unsigned int index;
- for (int y = 0; y < _yRes; y++)
- for (int x = 0; x < _xRes; x++)
- {
- // bottom slab
- index = x + y * _xRes;
- if(_domainBcBottom) _obstacles[index] = 1;
-
- // top slab
- index += _totalCells - _slabSize;
- if(_domainBcTop) _obstacles[index] = 1;
- }
-
- for (int z = 0; z < _zRes; z++)
- for (int x = 0; x < _xRes; x++)
- {
- // front slab
- index = x + z * _slabSize;
- if(_domainBcFront) _obstacles[index] = 1;
-
- // back slab
- index += _slabSize - _xRes;
- if(_domainBcBack) _obstacles[index] = 1;
- }
-
- for (int z = 0; z < _zRes; z++)
- for (int y = 0; y < _yRes; y++)
- {
- // left slab
- index = y * _xRes + z * _slabSize;
- if(_domainBcLeft) _obstacles[index] = 1;
-
- // right slab
- index += _xRes - 1;
- if(_domainBcRight) _obstacles[index] = 1;
- }
-}
-
-FLUID_3D::~FLUID_3D()
-{
- if (_xVelocity) delete[] _xVelocity;
- if (_yVelocity) delete[] _yVelocity;
- if (_zVelocity) delete[] _zVelocity;
- if (_xVelocityOb) delete[] _xVelocityOb;
- if (_yVelocityOb) delete[] _yVelocityOb;
- if (_zVelocityOb) delete[] _zVelocityOb;
- if (_xVelocityOld) delete[] _xVelocityOld;
- if (_yVelocityOld) delete[] _yVelocityOld;
- if (_zVelocityOld) delete[] _zVelocityOld;
- if (_xForce) delete[] _xForce;
- if (_yForce) delete[] _yForce;
- if (_zForce) delete[] _zForce;
- if (_density) delete[] _density;
- if (_densityOld) delete[] _densityOld;
- if (_heat) delete[] _heat;
- if (_heatOld) delete[] _heatOld;
- if (_obstacles) delete[] _obstacles;
-
- if (_xVelocityTemp) delete[] _xVelocityTemp;
- if (_yVelocityTemp) delete[] _yVelocityTemp;
- if (_zVelocityTemp) delete[] _zVelocityTemp;
- if (_densityTemp) delete[] _densityTemp;
- if (_heatTemp) delete[] _heatTemp;
-
- if (_flame) delete[] _flame;
- if (_fuel) delete[] _fuel;
- if (_fuelTemp) delete[] _fuelTemp;
- if (_fuelOld) delete[] _fuelOld;
- if (_react) delete[] _react;
- if (_reactTemp) delete[] _reactTemp;
- if (_reactOld) delete[] _reactOld;
-
- if (_color_r) delete[] _color_r;
- if (_color_rOld) delete[] _color_rOld;
- if (_color_rTemp) delete[] _color_rTemp;
- if (_color_g) delete[] _color_g;
- if (_color_gOld) delete[] _color_gOld;
- if (_color_gTemp) delete[] _color_gTemp;
- if (_color_b) delete[] _color_b;
- if (_color_bOld) delete[] _color_bOld;
- if (_color_bTemp) delete[] _color_bTemp;
-
- // printf("deleted fluid\n");
-}
-
-// init direct access functions from blender
-void FLUID_3D::initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *borderCollision, float *burning_rate,
- float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp)
-{
- _alpha = alpha;
- _beta = beta;
- _dtFactor = dt_factor;
- _vorticityRNA = vorticity;
- _borderColli = borderCollision;
- _burning_rate = burning_rate;
- _flame_smoke = flame_smoke;
- _flame_smoke_color = flame_smoke_color;
- _flame_vorticity = flame_vorticity;
- _ignition_temp = flame_ignition_temp;
- _max_temp = flame_max_temp;
-}
-
-//////////////////////////////////////////////////////////////////////
-// step simulation once
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::step(float dt, float gravity[3])
-{
-#if 0
- // If border rules have been changed
- if (_colloPrev != *_borderColli) {
- printf("Border collisions changed\n");
-
- // DG TODO: Need to check that no animated obstacle flags are overwritten
- setBorderCollisions();
- }
-#endif
-
- // DG: TODO for the moment redo border for every timestep since it's been deleted every time by moving obstacles
- setBorderCollisions();
-
-
- // set delta time by dt_factor
- _dt = (*_dtFactor) * dt;
- // set vorticity from RNA value
- _vorticityEps = (*_vorticityRNA)/_constantScaling;
-
-#if PARALLEL==1
- int threadval = 1;
- threadval = omp_get_max_threads();
-
- int stepParts = 1;
- float partSize = _zRes;
-
- stepParts = threadval*2; // Dividing parallelized sections into numOfThreads * 2 sections
- partSize = (float)_zRes/stepParts; // Size of one part;
-
- if (partSize < 4) {stepParts = threadval; // If the slice gets too low (might actually slow things down, change it to larger
- partSize = (float)_zRes/stepParts;}
- if (partSize < 4) {stepParts = (int)(ceil((float)_zRes/4.0f)); // If it's still too low (only possible on future systems with +24 cores), change it to 4
- partSize = (float)_zRes/stepParts;}
-#else
- int zBegin=0;
- int zEnd=_zRes;
-#endif
-
- wipeBoundariesSL(0, _zRes);
-
-#if PARALLEL==1
- #pragma omp parallel
- {
- #pragma omp for schedule(static,1)
- for (int i=0; i<stepParts; i++)
- {
- int zBegin = (int)((float)i*partSize + 0.5f);
- int zEnd = (int)((float)(i+1)*partSize + 0.5f);
-#endif
-
- addVorticity(zBegin, zEnd);
- addBuoyancy(_heat, _density, gravity, zBegin, zEnd);
- addForce(zBegin, zEnd);
-
-#if PARALLEL==1
- } // end of parallel
- #pragma omp barrier
-
- #pragma omp single
- {
-#endif
- /*
- * addForce() changed Temp values to preserve thread safety
- * (previous functions in per thread loop still needed
- * original velocity data)
- *
- * So swap temp values to velocity
- */
- SWAP_POINTERS(_xVelocity, _xVelocityTemp);
- SWAP_POINTERS(_yVelocity, _yVelocityTemp);
- SWAP_POINTERS(_zVelocity, _zVelocityTemp);
-#if PARALLEL==1
- } // end of single
-
- #pragma omp barrier
-
- #pragma omp for
- for (int i=0; i<2; i++)
- {
- if (i==0)
- {
-#endif
- project();
-#if PARALLEL==1
- }
- else if (i==1)
- {
-#endif
- if (_heat) {
- diffuseHeat();
- }
-#if PARALLEL==1
- }
- }
-
- #pragma omp barrier
-
- #pragma omp single
- {
-#endif
- /*
- * For thread safety use "Old" to read
- * "current" values but still allow changing values.
- */
- SWAP_POINTERS(_xVelocity, _xVelocityOld);
- SWAP_POINTERS(_yVelocity, _yVelocityOld);
- SWAP_POINTERS(_zVelocity, _zVelocityOld);
- SWAP_POINTERS(_density, _densityOld);
- SWAP_POINTERS(_heat, _heatOld);
-
- SWAP_POINTERS(_fuel, _fuelOld);
- SWAP_POINTERS(_react, _reactOld);
-
- SWAP_POINTERS(_color_r, _color_rOld);
- SWAP_POINTERS(_color_g, _color_gOld);
- SWAP_POINTERS(_color_b, _color_bOld);
-
- advectMacCormackBegin(0, _zRes);
-
-#if PARALLEL==1
- } // end of single
-
- #pragma omp barrier
-
-
- #pragma omp for schedule(static,1)
- for (int i=0; i<stepParts; i++)
- {
-
- int zBegin = (int)((float)i*partSize + 0.5f);
- int zEnd = (int)((float)(i+1)*partSize + 0.5f);
-#endif
-
- advectMacCormackEnd1(zBegin, zEnd);
-
-#if PARALLEL==1
- } // end of parallel
-
- #pragma omp barrier
-
- #pragma omp for schedule(static,1)
- for (int i=0; i<stepParts; i++)
- {
-
- int zBegin = (int)((float)i*partSize + 0.5f);
- int zEnd = (int)((float)(i+1)*partSize + 0.5f);
-#endif
-
- advectMacCormackEnd2(zBegin, zEnd);
-
- artificialDampingSL(zBegin, zEnd);
-
- // Using forces as temp arrays
-
-#if PARALLEL==1
- }
- }
-
-
-
- for (int i=1; i<stepParts; i++)
- {
- int zPos=(int)((float)i*partSize + 0.5f);
-
- artificialDampingExactSL(zPos);
-
- }
-#endif
-
- /*
- * swap final velocity back to Velocity array
- * from temp xForce storage
- */
- SWAP_POINTERS(_xVelocity, _xForce);
- SWAP_POINTERS(_yVelocity, _yForce);
- SWAP_POINTERS(_zVelocity, _zForce);
-
- _totalTime += _dt;
- _totalSteps++;
-
- for (int i = 0; i < _totalCells; i++)
- {
- _xForce[i] = _yForce[i] = _zForce[i] = 0.0f;
- }
-
-}
-
-
-// Set border collision model from RNA setting
-
-void FLUID_3D::setBorderCollisions() {
-
-
- _colloPrev = *_borderColli; // saving the current value
-
- // boundary conditions of the fluid domain
- if (_colloPrev == 0)
- {
- // No collisions
- _domainBcFront = false;
- _domainBcTop = false;
- _domainBcLeft = false;
- }
- else if (_colloPrev == 2)
- {
- // Collide with all sides
- _domainBcFront = true;
- _domainBcTop = true;
- _domainBcLeft = true;
- }
- else
- {
- // Default values: Collide with "walls", but not top and bottom
- _domainBcFront = true;
- _domainBcTop = false;
- _domainBcLeft = true;
- }
-
- _domainBcBack = _domainBcFront;
- _domainBcBottom = _domainBcTop;
- _domainBcRight = _domainBcLeft;
-
-
-
- // set side obstacles
- setBorderObstacles();
-}
-
-//////////////////////////////////////////////////////////////////////
-// helper function to dampen co-located grid artifacts of given arrays in intervals
-// (only needed for velocity, strength (w) depends on testcase...
-//////////////////////////////////////////////////////////////////////
-
-
-void FLUID_3D::artificialDampingSL(int zBegin, int zEnd) {
- const float w = 0.9;
-
- memmove(_xForce+(_slabSize*zBegin), _xVelocityTemp+(_slabSize*zBegin), sizeof(float)*_slabSize*(zEnd-zBegin));
- memmove(_yForce+(_slabSize*zBegin), _yVelocityTemp+(_slabSize*zBegin), sizeof(float)*_slabSize*(zEnd-zBegin));
- memmove(_zForce+(_slabSize*zBegin), _zVelocityTemp+(_slabSize*zBegin), sizeof(float)*_slabSize*(zEnd-zBegin));
-
-
- if(_totalSteps % 4 == 1) {
- for (int z = zBegin+1; z < zEnd-1; z++)
- for (int y = 1; y < _res[1]-1; y++)
- for (int x = 1+(y+z)%2; x < _res[0]-1; x+=2) {
- const int index = x + y*_res[0] + z * _slabSize;
- _xForce[index] = (1-w)*_xVelocityTemp[index] + 1.0f/6.0f * w*(
- _xVelocityTemp[index+1] + _xVelocityTemp[index-1] +
- _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] +
- _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] );
-
- _yForce[index] = (1-w)*_yVelocityTemp[index] + 1.0f/6.0f * w*(
- _yVelocityTemp[index+1] + _yVelocityTemp[index-1] +
- _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] +
- _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] );
-
- _zForce[index] = (1-w)*_zVelocityTemp[index] + 1.0f/6.0f * w*(
- _zVelocityTemp[index+1] + _zVelocityTemp[index-1] +
- _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] +
- _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] );
- }
- }
-
- if(_totalSteps % 4 == 3) {
- for (int z = zBegin+1; z < zEnd-1; z++)
- for (int y = 1; y < _res[1]-1; y++)
- for (int x = 1+(y+z+1)%2; x < _res[0]-1; x+=2) {
- const int index = x + y*_res[0] + z * _slabSize;
- _xForce[index] = (1-w)*_xVelocityTemp[index] + 1.0f/6.0f * w*(
- _xVelocityTemp[index+1] + _xVelocityTemp[index-1] +
- _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] +
- _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] );
-
- _yForce[index] = (1-w)*_yVelocityTemp[index] + 1.0f/6.0f * w*(
- _yVelocityTemp[index+1] + _yVelocityTemp[index-1] +
- _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] +
- _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] );
-
- _zForce[index] = (1-w)*_zVelocityTemp[index] + 1.0f/6.0f * w*(
- _zVelocityTemp[index+1] + _zVelocityTemp[index-1] +
- _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] +
- _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] );
- }
-
- }
-}
-
-
-
-void FLUID_3D::artificialDampingExactSL(int pos) {
- const float w = 0.9;
- int index, x,y,z;
-
-
- size_t posslab;
-
- for (z=pos-1; z<=pos; z++)
- {
- posslab=z * _slabSize;
-
- if(_totalSteps % 4 == 1) {
- for (y = 1; y < _res[1]-1; y++)
- for (x = 1+(y+z)%2; x < _res[0]-1; x+=2) {
- index = x + y*_res[0] + posslab;
- /*
- * Uses xForce as temporary storage to allow other threads to read
- * old values from xVelocityTemp
- */
- _xForce[index] = (1-w)*_xVelocityTemp[index] + 1.0f/6.0f * w*(
- _xVelocityTemp[index+1] + _xVelocityTemp[index-1] +
- _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] +
- _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] );
-
- _yForce[index] = (1-w)*_yVelocityTemp[index] + 1.0f/6.0f * w*(
- _yVelocityTemp[index+1] + _yVelocityTemp[index-1] +
- _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] +
- _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] );
-
- _zForce[index] = (1-w)*_zVelocityTemp[index] + 1.0f/6.0f * w*(
- _zVelocityTemp[index+1] + _zVelocityTemp[index-1] +
- _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] +
- _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] );
-
- }
- }
-
- if(_totalSteps % 4 == 3) {
- for (y = 1; y < _res[1]-1; y++)
- for (x = 1+(y+z+1)%2; x < _res[0]-1; x+=2) {
- index = x + y*_res[0] + posslab;
-
- /*
- * Uses xForce as temporary storage to allow other threads to read
- * old values from xVelocityTemp
- */
- _xForce[index] = (1-w)*_xVelocityTemp[index] + 1.0f/6.0f * w*(
- _xVelocityTemp[index+1] + _xVelocityTemp[index-1] +
- _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] +
- _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] );
-
- _yForce[index] = (1-w)*_yVelocityTemp[index] + 1.0f/6.0f * w*(
- _yVelocityTemp[index+1] + _yVelocityTemp[index-1] +
- _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] +
- _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] );
-
- _zForce[index] = (1-w)*_zVelocityTemp[index] + 1.0f/6.0f * w*(
- _zVelocityTemp[index+1] + _zVelocityTemp[index-1] +
- _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] +
- _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] );
-
- }
-
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// copy out the boundary in all directions
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::copyBorderAll(float* field, int zBegin, int zEnd)
-{
- int index, x, y, z;
- int zSize = zEnd-zBegin;
- int _blockTotalCells=_slabSize * zSize;
-
- if (zBegin==0)
- for (int y = 0; y < _yRes; y++)
- for (int x = 0; x < _xRes; x++)
- {
- // front slab
- index = x + y * _xRes;
- field[index] = field[index + _slabSize];
- }
-
- if (zEnd==_zRes)
- for (y = 0; y < _yRes; y++)
- for (x = 0; x < _xRes; x++)
- {
-
- // back slab
- index = x + y * _xRes + _blockTotalCells - _slabSize;
- field[index] = field[index - _slabSize];
- }
-
- for (z = 0; z < zSize; z++)
- for (x = 0; x < _xRes; x++)
- {
- // bottom slab
- index = x + z * _slabSize;
- field[index] = field[index + _xRes];
-
- // top slab
- index += _slabSize - _xRes;
- field[index] = field[index - _xRes];
- }
-
- for (z = 0; z < zSize; z++)
- for (y = 0; y < _yRes; y++)
- {
- // left slab
- index = y * _xRes + z * _slabSize;
- field[index] = field[index + 1];
-
- // right slab
- index += _xRes - 1;
- field[index] = field[index - 1];
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// wipe boundaries of velocity and density
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::wipeBoundaries(int zBegin, int zEnd)
-{
- setZeroBorder(_xVelocity, _res, zBegin, zEnd);
- setZeroBorder(_yVelocity, _res, zBegin, zEnd);
- setZeroBorder(_zVelocity, _res, zBegin, zEnd);
- setZeroBorder(_density, _res, zBegin, zEnd);
- if (_fuel) {
- setZeroBorder(_fuel, _res, zBegin, zEnd);
- setZeroBorder(_react, _res, zBegin, zEnd);
- }
- if (_color_r) {
- setZeroBorder(_color_r, _res, zBegin, zEnd);
- setZeroBorder(_color_g, _res, zBegin, zEnd);
- setZeroBorder(_color_b, _res, zBegin, zEnd);
- }
-}
-
-void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
-{
-
- /////////////////////////////////////
- // setZeroBorder to all:
- /////////////////////////////////////
-
- /////////////////////////////////////
- // setZeroX
- /////////////////////////////////////
-
- const int slabSize = _xRes * _yRes;
- int index, x,y,z;
-
- for (z = zBegin; z < zEnd; z++)
- for (y = 0; y < _yRes; y++)
- {
- // left slab
- index = y * _xRes + z * slabSize;
- _xVelocity[index] = 0.0f;
- _yVelocity[index] = 0.0f;
- _zVelocity[index] = 0.0f;
- _density[index] = 0.0f;
- if (_fuel) {
- _fuel[index] = 0.0f;
- _react[index] = 0.0f;
- }
- if (_color_r) {
- _color_r[index] = 0.0f;
- _color_g[index] = 0.0f;
- _color_b[index] = 0.0f;
- }
-
- // right slab
- index += _xRes - 1;
- _xVelocity[index] = 0.0f;
- _yVelocity[index] = 0.0f;
- _zVelocity[index] = 0.0f;
- _density[index] = 0.0f;
- if (_fuel) {
- _fuel[index] = 0.0f;
- _react[index] = 0.0f;
- }
- if (_color_r) {
- _color_r[index] = 0.0f;
- _color_g[index] = 0.0f;
- _color_b[index] = 0.0f;
- }
- }
-
- /////////////////////////////////////
- // setZeroY
- /////////////////////////////////////
-
- for (z = zBegin; z < zEnd; z++)
- for (x = 0; x < _xRes; x++)
- {
- // bottom slab
- index = x + z * slabSize;
- _xVelocity[index] = 0.0f;
- _yVelocity[index] = 0.0f;
- _zVelocity[index] = 0.0f;
- _density[index] = 0.0f;
- if (_fuel) {
- _fuel[index] = 0.0f;
- _react[index] = 0.0f;
- }
- if (_color_r) {
- _color_r[index] = 0.0f;
- _color_g[index] = 0.0f;
- _color_b[index] = 0.0f;
- }
-
- // top slab
- index += slabSize - _xRes;
- _xVelocity[index] = 0.0f;
- _yVelocity[index] = 0.0f;
- _zVelocity[index] = 0.0f;
- _density[index] = 0.0f;
- if (_fuel) {
- _fuel[index] = 0.0f;
- _react[index] = 0.0f;
- }
- if (_color_r) {
- _color_r[index] = 0.0f;
- _color_g[index] = 0.0f;
- _color_b[index] = 0.0f;
- }
-
- }
-
- /////////////////////////////////////
- // setZeroZ
- /////////////////////////////////////
-
-
- const int totalCells = _xRes * _yRes * _zRes;
-
- index = 0;
- if (zBegin == 0)
- for (y = 0; y < _yRes; y++)
- for (x = 0; x < _xRes; x++, index++)
- {
- // front slab
- _xVelocity[index] = 0.0f;
- _yVelocity[index] = 0.0f;
- _zVelocity[index] = 0.0f;
- _density[index] = 0.0f;
- if (_fuel) {
- _fuel[index] = 0.0f;
- _react[index] = 0.0f;
- }
- if (_color_r) {
- _color_r[index] = 0.0f;
- _color_g[index] = 0.0f;
- _color_b[index] = 0.0f;
- }
- }
-
- if (zEnd == _zRes)
- {
- index=0;
- int index_top=0;
- const int cellsslab = totalCells - slabSize;
-
- for (y = 0; y < _yRes; y++)
- for (x = 0; x < _xRes; x++, index++)
- {
-
- // back slab
- index_top = index + cellsslab;
- _xVelocity[index_top] = 0.0f;
- _yVelocity[index_top] = 0.0f;
- _zVelocity[index_top] = 0.0f;
- _density[index_top] = 0.0f;
- if (_fuel) {
- _fuel[index_top] = 0.0f;
- _react[index_top] = 0.0f;
- }
- if (_color_r) {
- _color_r[index_top] = 0.0f;
- _color_g[index_top] = 0.0f;
- _color_b[index_top] = 0.0f;
- }
- }
- }
-
-}
-//////////////////////////////////////////////////////////////////////
-// add forces to velocity field
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::addForce(int zBegin, int zEnd)
-{
- int begin=zBegin * _slabSize;
- int end=begin + (zEnd - zBegin) * _slabSize;
-
- for (int i = begin; i < end; i++)
- {
- _xVelocityTemp[i] = _xVelocity[i] + _dt * _xForce[i];
- _yVelocityTemp[i] = _yVelocity[i] + _dt * _yForce[i];
- _zVelocityTemp[i] = _zVelocity[i] + _dt * _zForce[i];
- }
-}
-//////////////////////////////////////////////////////////////////////
-// project into divergence free field
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::project()
-{
- int x, y, z;
- size_t index;
-
- float *_pressure = new float[_totalCells];
- float *_divergence = new float[_totalCells];
-
- memset(_pressure, 0, sizeof(float)*_totalCells);
- memset(_divergence, 0, sizeof(float)*_totalCells);
-
- // set velocity and pressure inside of obstacles to zero
- setObstacleBoundaries(_pressure, 0, _zRes);
-
- // copy out the boundaries
- if(!_domainBcLeft) setNeumannX(_xVelocity, _res, 0, _zRes);
- else setZeroX(_xVelocity, _res, 0, _zRes);
-
- if(!_domainBcFront) setNeumannY(_yVelocity, _res, 0, _zRes);
- else setZeroY(_yVelocity, _res, 0, _zRes);
-
- if(!_domainBcTop) setNeumannZ(_zVelocity, _res, 0, _zRes);
- else setZeroZ(_zVelocity, _res, 0, _zRes);
-
- // calculate divergence
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
-
- if(_obstacles[index])
- {
- _divergence[index] = 0.0f;
- continue;
- }
-
-
- float xright = _xVelocity[index + 1];
- float xleft = _xVelocity[index - 1];
- float yup = _yVelocity[index + _xRes];
- float ydown = _yVelocity[index - _xRes];
- float ztop = _zVelocity[index + _slabSize];
- float zbottom = _zVelocity[index - _slabSize];
-
- if(_obstacles[index+1]) xright = - _xVelocity[index]; // DG: +=
- if(_obstacles[index-1]) xleft = - _xVelocity[index];
- if(_obstacles[index+_xRes]) yup = - _yVelocity[index];
- if(_obstacles[index-_xRes]) ydown = - _yVelocity[index];
- if(_obstacles[index+_slabSize]) ztop = - _zVelocity[index];
- if(_obstacles[index-_slabSize]) zbottom = - _zVelocity[index];
-
- if(_obstacles[index+1] & 8) xright += _xVelocityOb[index + 1];
- if(_obstacles[index-1] & 8) xleft += _xVelocityOb[index - 1];
- if(_obstacles[index+_xRes] & 8) yup += _yVelocityOb[index + _xRes];
- if(_obstacles[index-_xRes] & 8) ydown += _yVelocityOb[index - _xRes];
- if(_obstacles[index+_slabSize] & 8) ztop += _zVelocityOb[index + _slabSize];
- if(_obstacles[index-_slabSize] & 8) zbottom += _zVelocityOb[index - _slabSize];
-
- _divergence[index] = -_dx * 0.5f * (
- xright - xleft +
- yup - ydown +
- ztop - zbottom );
-
- // Pressure is zero anyway since now a local array is used
- _pressure[index] = 0.0f;
- }
-
- copyBorderAll(_pressure, 0, _zRes);
-
- // fix fluid compression caused in isolated components by obstacle movement
- fixObstacleCompression(_divergence);
-
- // solve Poisson equation
- solvePressurePre(_pressure, _divergence, _obstacles);
-
- setObstaclePressure(_pressure, 0, _zRes);
-
- // project out solution
- // New idea for code from NVIDIA graphic gems 3 - DG
- float invDx = 1.0f / _dx;
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- float vMask[3] = {1.0f, 1.0f, 1.0f}, vObst[3] = {0, 0, 0};
- // float vR = 0.0f, vL = 0.0f, vT = 0.0f, vB = 0.0f, vD = 0.0f, vU = 0.0f; // UNUSED
-
- float pC = _pressure[index]; // center
- float pR = _pressure[index + 1]; // right
- float pL = _pressure[index - 1]; // left
- float pU = _pressure[index + _xRes]; // Up
- float pD = _pressure[index - _xRes]; // Down
- float pT = _pressure[index + _slabSize]; // top
- float pB = _pressure[index - _slabSize]; // bottom
-
- if(!_obstacles[index])
- {
- // DG TODO: What if obstacle is left + right and one of them is moving?
- if(_obstacles[index+1]) { pR = pC; vObst[0] = _xVelocityOb[index + 1]; vMask[0] = 0; }
- if(_obstacles[index-1]) { pL = pC; vObst[0] = _xVelocityOb[index - 1]; vMask[0] = 0; }
- if(_obstacles[index+_xRes]) { pU = pC; vObst[1] = _yVelocityOb[index + _xRes]; vMask[1] = 0; }
- if(_obstacles[index-_xRes]) { pD = pC; vObst[1] = _yVelocityOb[index - _xRes]; vMask[1] = 0; }
- if(_obstacles[index+_slabSize]) { pT = pC; vObst[2] = _zVelocityOb[index + _slabSize]; vMask[2] = 0; }
- if(_obstacles[index-_slabSize]) { pB = pC; vObst[2] = _zVelocityOb[index - _slabSize]; vMask[2] = 0; }
-
- _xVelocity[index] -= 0.5f * (pR - pL) * invDx;
- _yVelocity[index] -= 0.5f * (pU - pD) * invDx;
- _zVelocity[index] -= 0.5f * (pT - pB) * invDx;
-
- _xVelocity[index] = (vMask[0] * _xVelocity[index]) + vObst[0];
- _yVelocity[index] = (vMask[1] * _yVelocity[index]) + vObst[1];
- _zVelocity[index] = (vMask[2] * _zVelocity[index]) + vObst[2];
- }
- else
- {
- _xVelocity[index] = _xVelocityOb[index];
- _yVelocity[index] = _yVelocityOb[index];
- _zVelocity[index] = _zVelocityOb[index];
- }
- }
-
- // DG: was enabled in original code but now we do this later
- // setObstacleVelocity(0, _zRes);
-
- if (_pressure) delete[] _pressure;
- if (_divergence) delete[] _divergence;
-}
-
-//////////////////////////////////////////////////////////////////////
-// calculate the obstacle velocity at boundary
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setObstacleVelocity(int zBegin, int zEnd)
-{
-
- // completely TODO <-- who wrote this and what is here TODO? DG
-
- const size_t index_ = _slabSize + _xRes + 1;
-
- //int vIndex=_slabSize + _xRes + 1;
-
- int bb=0;
- int bt=0;
-
- if (zBegin == 0) {bb = 1;}
- if (zEnd == _zRes) {bt = 1;}
-
- // tag remaining obstacle blocks
- for (int z = zBegin + bb; z < zEnd - bt; z++)
- {
- size_t index = index_ +(z-1)*_slabSize;
-
- for (int y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (int x = 1; x < _xRes - 1; x++, index++)
- {
- if (!_obstacles[index])
- {
- // if(_obstacles[index+1]) xright = - _xVelocityOb[index];
- if((_obstacles[index - 1] & 8) && abs(_xVelocityOb[index - 1]) > FLT_EPSILON )
- {
- // printf("velocity x!\n");
- _xVelocity[index] = _xVelocityOb[index - 1];
- _xVelocity[index - 1] = _xVelocityOb[index - 1];
- }
- // if(_obstacles[index+_xRes]) yup = - _yVelocityOb[index];
- if((_obstacles[index - _xRes] & 8) && abs(_yVelocityOb[index - _xRes]) > FLT_EPSILON)
- {
- // printf("velocity y!\n");
- _yVelocity[index] = _yVelocityOb[index - _xRes];
- _yVelocity[index - _xRes] = _yVelocityOb[index - _xRes];
- }
- // if(_obstacles[index+_slabSize]) ztop = - _zVelocityOb[index];
- if((_obstacles[index - _slabSize] & 8) && abs(_zVelocityOb[index - _slabSize]) > FLT_EPSILON)
- {
- // printf("velocity z!\n");
- _zVelocity[index] = _zVelocityOb[index - _slabSize];
- _zVelocity[index - _slabSize] = _zVelocityOb[index - _slabSize];
- }
- }
- else
- {
- _density[index] = 0;
- }
- //vIndex++;
- } // x loop
- //vIndex += 2;
- } // y loop
- //vIndex += 2 * _xRes;
- } // z loop
-}
-
-//////////////////////////////////////////////////////////////////////
-// diffuse heat
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::diffuseHeat()
-{
- SWAP_POINTERS(_heat, _heatOld);
-
- copyBorderAll(_heatOld, 0, _zRes);
- solveHeat(_heat, _heatOld, _obstacles);
-
- // zero out inside obstacles
- for (int x = 0; x < _totalCells; x++)
- if (_obstacles[x])
- _heat[x] = 0.0f;
-}
-
-//////////////////////////////////////////////////////////////////////
-// stamp an obstacle in the _obstacles field
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::addObstacle(OBSTACLE* obstacle)
-{
- int index = 0;
- for (int z = 0; z < _zRes; z++)
- for (int y = 0; y < _yRes; y++)
- for (int x = 0; x < _xRes; x++, index++)
- if (obstacle->inside(x * _dx, y * _dx, z * _dx)) {
- _obstacles[index] = true;
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// calculate the obstacle directional types
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setObstaclePressure(float *_pressure, int zBegin, int zEnd)
-{
-
- // completely TODO <-- who wrote this and what is here TODO? DG
-
- const size_t index_ = _slabSize + _xRes + 1;
-
- //int vIndex=_slabSize + _xRes + 1;
-
- int bb=0;
- int bt=0;
-
- if (zBegin == 0) {bb = 1;}
- if (zEnd == _zRes) {bt = 1;}
-
- // tag remaining obstacle blocks
- for (int z = zBegin + bb; z < zEnd - bt; z++)
- {
- size_t index = index_ +(z-1)*_slabSize;
-
- for (int y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (int x = 1; x < _xRes - 1; x++, index++)
- {
- // could do cascade of ifs, but they are a pain
- if (_obstacles[index] /* && !(_obstacles[index] & 8) DG TODO TEST THIS CONDITION */)
- {
- const int top = _obstacles[index + _slabSize];
- const int bottom= _obstacles[index - _slabSize];
- const int up = _obstacles[index + _xRes];
- const int down = _obstacles[index - _xRes];
- const int left = _obstacles[index - 1];
- const int right = _obstacles[index + 1];
-
- // unused
- // const bool fullz = (top && bottom);
- // const bool fully = (up && down);
- //const bool fullx = (left && right);
-
- /*
- _xVelocity[index] =
- _yVelocity[index] =
- _zVelocity[index] = 0.0f;
- */
- _pressure[index] = 0.0f;
-
- // average pressure neighbors
- float pcnt = 0.;
- if (left && !right) {
- _pressure[index] += _pressure[index + 1];
- pcnt += 1.0f;
- }
- if (!left && right) {
- _pressure[index] += _pressure[index - 1];
- pcnt += 1.0f;
- }
- if (up && !down) {
- _pressure[index] += _pressure[index - _xRes];
- pcnt += 1.0f;
- }
- if (!up && down) {
- _pressure[index] += _pressure[index + _xRes];
- pcnt += 1.0f;
- }
- if (top && !bottom) {
- _pressure[index] += _pressure[index - _slabSize];
- pcnt += 1.0f;
- }
- if (!top && bottom) {
- _pressure[index] += _pressure[index + _slabSize];
- pcnt += 1.0f;
- }
-
- if(pcnt > 0.000001f)
- _pressure[index] /= pcnt;
-
- // TODO? set correct velocity bc's
- // velocities are only set to zero right now
- // this means it's not a full no-slip boundary condition
- // but a "half-slip" - still looks ok right now
- }
- //vIndex++;
- } // x loop
- //vIndex += 2;
- } // y loop
- //vIndex += 2 * _xRes;
- } // z loop
-}
-
-void FLUID_3D::setObstacleBoundaries(float *_pressure, int zBegin, int zEnd)
-{
- // cull degenerate obstacles , move to addObstacle?
-
- // r = b - Ax
- const size_t index_ = _slabSize + _xRes + 1;
-
- int bb=0;
- int bt=0;
-
- if (zBegin == 0) {bb = 1;}
- if (zEnd == _zRes) {bt = 1;}
-
- for (int z = zBegin + bb; z < zEnd - bt; z++)
- {
- size_t index = index_ +(z-1)*_slabSize;
-
- for (int y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (int x = 1; x < _xRes - 1; x++, index++)
- {
- if (_obstacles[index] != EMPTY)
- {
- const int top = _obstacles[index + _slabSize];
- const int bottom= _obstacles[index - _slabSize];
- const int up = _obstacles[index + _xRes];
- const int down = _obstacles[index - _xRes];
- const int left = _obstacles[index - 1];
- const int right = _obstacles[index + 1];
-
- int counter = 0;
- if (up) counter++;
- if (down) counter++;
- if (left) counter++;
- if (right) counter++;
- if (top) counter++;
- if (bottom) counter++;
-
- if (counter < 3)
- _obstacles[index] = EMPTY;
- }
- if (_obstacles[index])
- {
- _xVelocity[index] =
- _yVelocity[index] =
- _zVelocity[index] = 0.0f;
- _pressure[index] = 0.0f;
- }
- //vIndex++;
- } // x-loop
- //vIndex += 2;
- } // y-loop
- //vIndex += 2* _xRes;
- } // z-loop
-}
-
-void FLUID_3D::floodFillComponent(int *buffer, size_t *queue, size_t limit, size_t pos, int from, int to)
-{
- /* Flood 'from' cells with 'to' in the grid. Rely on (from != 0 && from != to && edges == 0) to stop. */
- int offsets[] = { -1, +1, -_xRes, +_xRes, -_slabSize, +_slabSize };
- size_t qend = 0;
-
- buffer[pos] = to;
- queue[qend++] = pos;
-
- for (size_t qidx = 0; qidx < qend; qidx++)
- {
- pos = queue[qidx];
-
- for (int i = 0; i < 6; i++)
- {
- size_t next = pos + offsets[i];
-
- if (next < limit && buffer[next] == from)
- {
- buffer[next] = to;
- queue[qend++] = next;
- }
- }
- }
-}
-
-void FLUID_3D::mergeComponents(int *buffer, size_t *queue, size_t cur, size_t other)
-{
- /* Replace higher value with lower. */
- if (buffer[other] < buffer[cur])
- {
- floodFillComponent(buffer, queue, cur, cur, buffer[cur], buffer[other]);
- }
- else if (buffer[cur] < buffer[other])
- {
- floodFillComponent(buffer, queue, cur, other, buffer[other], buffer[cur]);
- }
-}
-
-void FLUID_3D::fixObstacleCompression(float *divergence)
-{
- int x, y, z;
- size_t index;
-
- /* Find compartments completely separated by obstacles.
- * Edge of the domain is automatically component 0. */
- int *component = new int[_totalCells];
- size_t *queue = new size_t[_totalCells];
-
- memset(component, 0, sizeof(int) * _totalCells);
-
- int next_id = 1;
-
- for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
- {
- for (y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- if(!_obstacles[index])
- {
- /* Check for connection to the domain edge at iteration end. */
- if ((x == _xRes-2 && !_obstacles[index + 1]) ||
- (y == _yRes-2 && !_obstacles[index + _xRes]) ||
- (z == _zRes-2 && !_obstacles[index + _slabSize]))
- {
- component[index] = 0;
- }
- else {
- component[index] = next_id;
- }
-
- if (!_obstacles[index - 1])
- mergeComponents(component, queue, index, index - 1);
- if (!_obstacles[index - _xRes])
- mergeComponents(component, queue, index, index - _xRes);
- if (!_obstacles[index - _slabSize])
- mergeComponents(component, queue, index, index - _slabSize);
-
- if (component[index] == next_id)
- next_id++;
- }
- }
- }
- }
-
- delete[] queue;
-
- /* Compute average divergence within each component. */
- float *total_divergence = new float[next_id];
- int *component_size = new int[next_id];
-
- memset(total_divergence, 0, sizeof(float) * next_id);
- memset(component_size, 0, sizeof(int) * next_id);
-
- for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
- {
- for (y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- if(!_obstacles[index])
- {
- int ci = component[index];
-
- component_size[ci]++;
- total_divergence[ci] += divergence[index];
- }
- }
- }
- }
-
- /* Adjust divergence to make the average zero in each component except the edge. */
- total_divergence[0] = 0.0f;
-
- for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
- {
- for (y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- if(!_obstacles[index])
- {
- int ci = component[index];
-
- divergence[index] -= total_divergence[ci] / component_size[ci];
- }
- }
- }
- }
-
- delete[] component;
- delete[] component_size;
- delete[] total_divergence;
-}
-
-//////////////////////////////////////////////////////////////////////
-// add buoyancy forces
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::addBuoyancy(float *heat, float *density, float gravity[3], int zBegin, int zEnd)
-{
- int index = zBegin*_slabSize;
-
- for (int z = zBegin; z < zEnd; z++)
- for (int y = 0; y < _yRes; y++)
- for (int x = 0; x < _xRes; x++, index++)
- {
- float buoyancy = *_alpha * density[index] + (*_beta * (((heat) ? heat[index] : 0.0f) - _tempAmb));
- _xForce[index] -= gravity[0] * buoyancy;
- _yForce[index] -= gravity[1] * buoyancy;
- _zForce[index] -= gravity[2] * buoyancy;
- }
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// add vorticity to the force field
-//////////////////////////////////////////////////////////////////////
-#define VORT_VEL(i, j) \
- ((_obstacles[obpos[(i)]] & 8) ? ((abs(objvelocity[(j)][obpos[(i)]]) > FLT_EPSILON) ? objvelocity[(j)][obpos[(i)]] : velocity[(j)][index]) : velocity[(j)][obpos[(i)]])
-
-void FLUID_3D::addVorticity(int zBegin, int zEnd)
-{
- // set flame vorticity from RNA value
- float flame_vorticity = (*_flame_vorticity)/_constantScaling;
- //int x,y,z,index;
- if(_vorticityEps+flame_vorticity<=0.0f) return;
-
- int _blockSize=zEnd-zBegin;
- int _blockTotalCells = _slabSize * (_blockSize+2);
-
- float *_xVorticity, *_yVorticity, *_zVorticity, *_vorticity;
-
- int bb=0;
- int bt=0;
- int bb1=-1;
- int bt1=-1;
-
- if (zBegin == 0) {bb1 = 1; bb = 1; _blockTotalCells-=_blockSize;}
- if (zEnd == _zRes) {bt1 = 1;bt = 1; _blockTotalCells-=_blockSize;}
-
- _xVorticity = new float[_blockTotalCells];
- _yVorticity = new float[_blockTotalCells];
- _zVorticity = new float[_blockTotalCells];
- _vorticity = new float[_blockTotalCells];
-
- memset(_xVorticity, 0, sizeof(float)*_blockTotalCells);
- memset(_yVorticity, 0, sizeof(float)*_blockTotalCells);
- memset(_zVorticity, 0, sizeof(float)*_blockTotalCells);
- memset(_vorticity, 0, sizeof(float)*_blockTotalCells);
-
- //const size_t indexsetupV=_slabSize;
- const size_t index_ = _slabSize + _xRes + 1;
-
- // calculate vorticity
- float gridSize = 0.5f / _dx;
- //index = _slabSize + _xRes + 1;
-
- float *velocity[3];
- float *objvelocity[3];
-
- velocity[0] = _xVelocity;
- velocity[1] = _yVelocity;
- velocity[2] = _zVelocity;
-
- objvelocity[0] = _xVelocityOb;
- objvelocity[1] = _yVelocityOb;
- objvelocity[2] = _zVelocityOb;
-
- size_t vIndex=_xRes + 1;
- for (int z = zBegin + bb1; z < (zEnd - bt1); z++)
- {
- size_t index = index_ +(z-1)*_slabSize;
- vIndex = index-(zBegin-1+bb)*_slabSize;
-
- for (int y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (int x = 1; x < _xRes - 1; x++, index++)
- {
- if (!_obstacles[index])
- {
- int obpos[6];
-
- obpos[0] = (_obstacles[index + _xRes] == 1) ? index : index + _xRes; // up
- obpos[1] = (_obstacles[index - _xRes] == 1) ? index : index - _xRes; // down
- float dy = (obpos[0] == index || obpos[1] == index) ? 1.0f / _dx : gridSize;
-
- obpos[2] = (_obstacles[index + _slabSize] == 1) ? index : index + _slabSize; // out
- obpos[3] = (_obstacles[index - _slabSize] == 1) ? index : index - _slabSize; // in
- float dz = (obpos[2] == index || obpos[3] == index) ? 1.0f / _dx : gridSize;
-
- obpos[4] = (_obstacles[index + 1] == 1) ? index : index + 1; // right
- obpos[5] = (_obstacles[index - 1] == 1) ? index : index - 1; // left
- float dx = (obpos[4] == index || obpos[5] == index) ? 1.0f / _dx : gridSize;
-
- float xV[2], yV[2], zV[2];
-
- zV[1] = VORT_VEL(0, 2);
- zV[0] = VORT_VEL(1, 2);
- yV[1] = VORT_VEL(2, 1);
- yV[0] = VORT_VEL(3, 1);
- _xVorticity[vIndex] = (zV[1] - zV[0]) * dy + (-yV[1] + yV[0]) * dz;
-
- xV[1] = VORT_VEL(2, 0);
- xV[0] = VORT_VEL(3, 0);
- zV[1] = VORT_VEL(4, 2);
- zV[0] = VORT_VEL(5, 2);
- _yVorticity[vIndex] = (xV[1] - xV[0]) * dz + (-zV[1] + zV[0]) * dx;
-
- yV[1] = VORT_VEL(4, 1);
- yV[0] = VORT_VEL(5, 1);
- xV[1] = VORT_VEL(0, 0);
- xV[0] = VORT_VEL(1, 0);
- _zVorticity[vIndex] = (yV[1] - yV[0]) * dx + (-xV[1] + xV[0])* dy;
-
- _vorticity[vIndex] = sqrtf(_xVorticity[vIndex] * _xVorticity[vIndex] +
- _yVorticity[vIndex] * _yVorticity[vIndex] +
- _zVorticity[vIndex] * _zVorticity[vIndex]);
-
- }
- vIndex++;
- }
- vIndex+=2;
- }
- //vIndex+=2*_xRes;
- }
-
- // calculate normalized vorticity vectors
- float eps = _vorticityEps;
-
- //index = _slabSize + _xRes + 1;
- vIndex=_slabSize + _xRes + 1;
-
- for (int z = zBegin + bb; z < (zEnd - bt); z++)
- {
- size_t index = index_ +(z-1)*_slabSize;
- vIndex = index-(zBegin-1+bb)*_slabSize;
-
- for (int y = 1; y < _yRes - 1; y++, index += 2)
- {
- for (int x = 1; x < _xRes - 1; x++, index++)
- {
- //
-
- if (!_obstacles[index])
- {
- float N[3];
-
- int up = (_obstacles[index + _xRes] == 1) ? vIndex : vIndex + _xRes;
- int down = (_obstacles[index - _xRes] == 1) ? vIndex : vIndex - _xRes;
- float dy = (up == vIndex || down == vIndex) ? 1.0f / _dx : gridSize;
-
- int out = (_obstacles[index + _slabSize] == 1) ? vIndex : vIndex + _slabSize;
- int in = (_obstacles[index - _slabSize] == 1) ? vIndex : vIndex - _slabSize;
- float dz = (out == vIndex || in == vIndex) ? 1.0f / _dx : gridSize;
-
- int right = (_obstacles[index + 1] == 1) ? vIndex : vIndex + 1;
- int left = (_obstacles[index - 1] == 1) ? vIndex : vIndex - 1;
- float dx = (right == vIndex || left == vIndex) ? 1.0f / _dx : gridSize;
-
- N[0] = (_vorticity[right] - _vorticity[left]) * dx;
- N[1] = (_vorticity[up] - _vorticity[down]) * dy;
- N[2] = (_vorticity[out] - _vorticity[in]) * dz;
-
- float magnitude = sqrtf(N[0] * N[0] + N[1] * N[1] + N[2] * N[2]);
- if (magnitude > FLT_EPSILON)
- {
- float flame_vort = (_fuel) ? _fuel[index]*flame_vorticity : 0.0f;
- magnitude = 1.0f / magnitude;
- N[0] *= magnitude;
- N[1] *= magnitude;
- N[2] *= magnitude;
-
- _xForce[index] += (N[1] * _zVorticity[vIndex] - N[2] * _yVorticity[vIndex]) * _dx * (eps + flame_vort);
- _yForce[index] += (N[2] * _xVorticity[vIndex] - N[0] * _zVorticity[vIndex]) * _dx * (eps + flame_vort);
- _zForce[index] += (N[0] * _yVorticity[vIndex] - N[1] * _xVorticity[vIndex]) * _dx * (eps + flame_vort);
- }
- } // if
- vIndex++;
- } // x loop
- vIndex+=2;
- } // y loop
- //vIndex+=2*_xRes;
- } // z loop
-
- if (_xVorticity) delete[] _xVorticity;
- if (_yVorticity) delete[] _yVorticity;
- if (_zVorticity) delete[] _zVorticity;
- if (_vorticity) delete[] _vorticity;
-}
-
-
-void FLUID_3D::advectMacCormackBegin(int zBegin, int zEnd)
-{
- Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
-
- setZeroX(_xVelocityOld, res, zBegin, zEnd);
- setZeroY(_yVelocityOld, res, zBegin, zEnd);
- setZeroZ(_zVelocityOld, res, zBegin, zEnd);
-}
-
-//////////////////////////////////////////////////////////////////////
-// Advect using the MacCormack method from the Selle paper
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::advectMacCormackEnd1(int zBegin, int zEnd)
-{
- Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
-
- const float dt0 = _dt / _dx;
-
- int begin=zBegin * _slabSize;
- int end=begin + (zEnd - zBegin) * _slabSize;
- for (int x = begin; x < end; x++)
- _xForce[x] = 0.0;
-
- // advectFieldMacCormack1(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res)
-
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _densityTemp, res, zBegin, zEnd);
- if (_heat) {
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heatTemp, res, zBegin, zEnd);
- }
- if (_fuel) {
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _fuelOld, _fuelTemp, res, zBegin, zEnd);
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _reactOld, _reactTemp, res, zBegin, zEnd);
- }
- if (_color_r) {
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_rOld, _color_rTemp, res, zBegin, zEnd);
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_gOld, _color_gTemp, res, zBegin, zEnd);
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_bOld, _color_bTemp, res, zBegin, zEnd);
- }
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocity, res, zBegin, zEnd);
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocity, res, zBegin, zEnd);
- advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocity, res, zBegin, zEnd);
-
- // Have to wait untill all the threads are done -> so continuing in step 3
-}
-
-//////////////////////////////////////////////////////////////////////
-// Advect using the MacCormack method from the Selle paper
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::advectMacCormackEnd2(int zBegin, int zEnd)
-{
- const float dt0 = _dt / _dx;
- Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
-
- // use force array as temp array
- float* t1 = _xForce;
-
- // advectFieldMacCormack2(dt, xVelocity, yVelocity, zVelocity, oldField, newField, tempfield, temp, res, obstacles)
-
- /* finish advection */
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _density, _densityTemp, t1, res, _obstacles, zBegin, zEnd);
- if (_heat) {
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heat, _heatTemp, t1, res, _obstacles, zBegin, zEnd);
- }
- if (_fuel) {
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _fuelOld, _fuel, _fuelTemp, t1, res, _obstacles, zBegin, zEnd);
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _reactOld, _react, _reactTemp, t1, res, _obstacles, zBegin, zEnd);
- }
- if (_color_r) {
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_rOld, _color_r, _color_rTemp, t1, res, _obstacles, zBegin, zEnd);
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_gOld, _color_g, _color_gTemp, t1, res, _obstacles, zBegin, zEnd);
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_bOld, _color_b, _color_bTemp, t1, res, _obstacles, zBegin, zEnd);
- }
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocityTemp, _xVelocity, t1, res, _obstacles, zBegin, zEnd);
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocityTemp, _yVelocity, t1, res, _obstacles, zBegin, zEnd);
- advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocityTemp, _zVelocity, t1, res, _obstacles, zBegin, zEnd);
-
- /* set boundary conditions for velocity */
- if(!_domainBcLeft) copyBorderX(_xVelocityTemp, res, zBegin, zEnd);
- else setZeroX(_xVelocityTemp, res, zBegin, zEnd);
-
- if(!_domainBcFront) copyBorderY(_yVelocityTemp, res, zBegin, zEnd);
- else setZeroY(_yVelocityTemp, res, zBegin, zEnd);
-
- if(!_domainBcTop) copyBorderZ(_zVelocityTemp, res, zBegin, zEnd);
- else setZeroZ(_zVelocityTemp, res, zBegin, zEnd);
-
- /* clear data boundaries */
- setZeroBorder(_density, res, zBegin, zEnd);
- if (_fuel) {
- setZeroBorder(_fuel, res, zBegin, zEnd);
- setZeroBorder(_react, res, zBegin, zEnd);
- }
- if (_color_r) {
- setZeroBorder(_color_r, res, zBegin, zEnd);
- setZeroBorder(_color_g, res, zBegin, zEnd);
- setZeroBorder(_color_b, res, zBegin, zEnd);
- }
-}
-
-
-void FLUID_3D::processBurn(float *fuel, float *smoke, float *react, float *heat,
- float *r, float *g, float *b, int total_cells, float dt)
-{
- float burning_rate = *_burning_rate;
- float flame_smoke = *_flame_smoke;
- float ignition_point = *_ignition_temp;
- float temp_max = *_max_temp;
-
- for (int index = 0; index < total_cells; index++)
- {
- float orig_fuel = fuel[index];
- float orig_smoke = smoke[index];
- float smoke_emit = 0.0f;
- float flame = 0.0f;
-
- /* process fuel */
- fuel[index] -= burning_rate * dt;
- if (fuel[index] < 0.0f) fuel[index] = 0.0f;
- /* process reaction coordinate */
- if (orig_fuel > FLT_EPSILON) {
- react[index] *= fuel[index]/orig_fuel;
- flame = pow(react[index], 0.5f);
- }
- else {
- react[index] = 0.0f;
- }
-
- /* emit smoke based on fuel burn rate and "flame_smoke" factor */
- smoke_emit = (orig_fuel < 1.0f) ? (1.0f - orig_fuel)*0.5f : 0.0f;
- smoke_emit = (smoke_emit + 0.5f) * (orig_fuel-fuel[index]) * 0.1f * flame_smoke;
- smoke[index] += smoke_emit;
- CLAMP(smoke[index], 0.0f, 1.0f);
-
- /* set fluid temperature from the flame temperature profile */
- if (heat && flame)
- heat[index] = (1.0f - flame)*ignition_point + flame*temp_max;
-
- /* mix new color */
- if (r && smoke_emit > FLT_EPSILON) {
- float smoke_factor = smoke[index]/(orig_smoke+smoke_emit);
- r[index] = (r[index] + _flame_smoke_color[0] * smoke_emit) * smoke_factor;
- g[index] = (g[index] + _flame_smoke_color[1] * smoke_emit) * smoke_factor;
- b[index] = (b[index] + _flame_smoke_color[2] * smoke_emit) * smoke_factor;
- }
- }
-}
-
-void FLUID_3D::updateFlame(float *react, float *flame, int total_cells)
-{
- for (int index = 0; index < total_cells; index++)
- {
- /* model flame temperature curve from the reaction coordinate (fuel)
- * TODO: Would probably be best to get rid of whole "flame" data field.
- * Currently it's just sqrt mirror of reaction coordinate, and therefore
- * basically just waste of memory and disk space...
- */
- if (react[index]>0.0f) {
- /* do a smooth falloff for rest of the values */
- flame[index] = pow(react[index], 0.5f);
- }
- else
- flame[index] = 0.0f;
- }
-}
diff --git a/intern/smoke/intern/FLUID_3D.h b/intern/smoke/intern/FLUID_3D.h
deleted file mode 100644
index 097451836f2..00000000000
--- a/intern/smoke/intern/FLUID_3D.h
+++ /dev/null
@@ -1,269 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// FLUID_3D.h: interface for the FLUID_3D class.
-//
-//////////////////////////////////////////////////////////////////////
-// Heavy parallel optimization done. Many of the old functions now
-// take begin and end parameters and process only specified part of the data.
-// Some functions were divided into multiple ones.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#ifndef FLUID_3D_H
-#define FLUID_3D_H
-
-#include <cstdlib>
-#include <cmath>
-#include <cstring>
-#include <iostream>
-#include "OBSTACLE.h"
-// #include "WTURBULENCE.h"
-#include "VEC3.h"
-
-using namespace std;
-using namespace BasicVector;
-struct WTURBULENCE;
-
-struct FLUID_3D
-{
- public:
- FLUID_3D(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors);
- FLUID_3D() {};
- virtual ~FLUID_3D();
-
- void initHeat();
- void initFire();
- void initColors(float init_r, float init_g, float init_b);
-
- void initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
- float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *ignition_temp, float *max_temp);
-
- // create & allocate vector noise advection
- void initVectorNoise(int amplify);
-
- void addSmokeColumn();
- static void addSmokeTestCase(float* field, Vec3Int res);
-
- void step(float dt, float gravity[3]);
- void addObstacle(OBSTACLE* obstacle);
-
- const float* xVelocity() { return _xVelocity; };
- const float* yVelocity() { return _yVelocity; };
- const float* zVelocity() { return _zVelocity; };
-
- int xRes() const { return _xRes; };
- int yRes() const { return _yRes; };
- int zRes() const { return _zRes; };
-
- public:
- // dimensions
- int _xRes, _yRes, _zRes, _maxRes;
- Vec3Int _res;
- size_t _totalCells;
- int _slabSize;
- float _dx;
- float _p0[3];
- float _p1[3];
- float _totalTime;
- int _totalSteps;
- int _totalImgDumps;
- int _totalVelDumps;
-
- void artificialDampingSL(int zBegin, int zEnd);
- void artificialDampingExactSL(int pos);
-
- void setBorderObstacles();
-
- // fields
- float* _density;
- float* _densityOld;
- float* _heat;
- float* _heatOld;
- float* _xVelocity;
- float* _yVelocity;
- float* _zVelocity;
- float* _xVelocityOb;
- float* _yVelocityOb;
- float* _zVelocityOb;
- float* _xVelocityOld;
- float* _yVelocityOld;
- float* _zVelocityOld;
- float* _xForce;
- float* _yForce;
- float* _zForce;
- unsigned char* _obstacles; /* only used (useful) for static obstacles like domain boundaries */
- unsigned char* _obstaclesAnim;
-
- // Required for proper threading:
- float* _xVelocityTemp;
- float* _yVelocityTemp;
- float* _zVelocityTemp;
- float* _heatTemp;
- float* _densityTemp;
-
- // fire simulation
- float *_flame;
- float *_fuel;
- float *_fuelTemp;
- float *_fuelOld;
- float *_react;
- float *_reactTemp;
- float *_reactOld;
-
- // smoke color
- float *_color_r;
- float *_color_rOld;
- float *_color_rTemp;
- float *_color_g;
- float *_color_gOld;
- float *_color_gTemp;
- float *_color_b;
- float *_color_bOld;
- float *_color_bTemp;
-
-
- // CG fields
- int _iterations;
-
- // simulation constants
- float _dt;
- float *_dtFactor;
- float _vorticityEps;
- float _heatDiffusion;
- float *_vorticityRNA; // RNA-pointer.
- float *_alpha; // for the buoyancy density term <-- as pointer to get blender RNA in here
- float *_beta; // was _buoyancy <-- as pointer to get blender RNA in here
- float _tempAmb; /* ambient temperature */
- float _constantScaling;
-
- bool _domainBcFront; // z
- bool _domainBcTop; // y
- bool _domainBcLeft; // x
- bool _domainBcBack; // DOMAIN_BC_FRONT
- bool _domainBcBottom; // DOMAIN_BC_TOP
- bool _domainBcRight; // DOMAIN_BC_LEFT
- int *_borderColli; // border collision rules <-- as pointer to get blender RNA in here
- int _colloPrev; // To track whether value has been changed (to not
- // have to recalibrate borders if nothing has changed
- void setBorderCollisions();
-
- void setObstacleVelocity(int zBegin, int zEnd);
-
- // WTURBULENCE object, if active
- // WTURBULENCE* _wTurbulence;
-
- // boundary setting functions
- void copyBorderAll(float* field, int zBegin, int zEnd);
-
- // timestepping functions
- void wipeBoundaries(int zBegin, int zEnd);
- void wipeBoundariesSL(int zBegin, int zEnd);
- void addForce(int zBegin, int zEnd);
- void addVorticity(int zBegin, int zEnd);
- void addBuoyancy(float *heat, float *density, float gravity[3], int zBegin, int zEnd);
-
- // solver stuff
- void project();
- void diffuseHeat();
- void diffuseColor();
- void solvePressure(float* field, float* b, unsigned char* skip);
- void solvePressurePre(float* field, float* b, unsigned char* skip);
- void solveHeat(float* field, float* b, unsigned char* skip);
- void solveDiffusion(float* field, float* b, float* factor);
-
-
- // handle obstacle boundaries
- void setObstacleBoundaries(float *_pressure, int zBegin, int zEnd);
- void setObstaclePressure(float *_pressure, int zBegin, int zEnd);
-
- void fixObstacleCompression(float *divergence);
-
- public:
- // advection, accessed e.g. by WTURBULENCE class
- //void advectMacCormack();
- void advectMacCormackBegin(int zBegin, int zEnd);
- void advectMacCormackEnd1(int zBegin, int zEnd);
- void advectMacCormackEnd2(int zBegin, int zEnd);
-
- void floodFillComponent(int *components, size_t *queue, size_t limit, size_t start, int from, int to);
- void mergeComponents(int *components, size_t *queue, size_t cur, size_t other);
-
- /* burning */
- float *_burning_rate; // RNA pointer
- float *_flame_smoke; // RNA pointer
- float *_flame_smoke_color; // RNA pointer
- float *_flame_vorticity; // RNA pointer
- float *_ignition_temp; // RNA pointer
- float *_max_temp; // RNA pointer
- void processBurn(float *fuel, float *smoke, float *react, float *heat,
- float *r, float *g, float *b, int total_cells, float dt);
- void updateFlame(float *react, float *flame, int total_cells);
-
- // boundary setting functions
- static void copyBorderX(float* field, Vec3Int res, int zBegin, int zEnd);
- static void copyBorderY(float* field, Vec3Int res, int zBegin, int zEnd);
- static void copyBorderZ(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setNeumannX(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setNeumannY(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setNeumannZ(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setZeroX(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setZeroY(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setZeroZ(float* field, Vec3Int res, int zBegin, int zEnd);
- static void setZeroBorder(float* field, Vec3Int res, int zBegin, int zEnd) {
- setZeroX(field, res, zBegin, zEnd);
- setZeroY(field, res, zBegin, zEnd);
- setZeroZ(field, res, zBegin, zEnd);
- };
-
-
-
- // static advection functions, also used by WTURBULENCE
- static void advectFieldSemiLagrange(const float dt, const float* velx, const float* vely, const float* velz,
- float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd);
- static void advectFieldMacCormack1(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* tempResult, Vec3Int res, int zBegin, int zEnd);
- static void advectFieldMacCormack2(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* newField, float* tempResult, float* temp1,Vec3Int res, const unsigned char* obstacles, int zBegin, int zEnd);
-
-
- // temp ones for testing
- /*static void advectFieldMacCormack(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* newField, float* temp1, float* temp2, Vec3Int res, const unsigned char* obstacles);*/
- /*static void advectFieldSemiLagrange2(const float dt, const float* velx, const float* vely, const float* velz,
- float* oldField, float* newField, Vec3Int res);*/
-
- // maccormack helper functions
- static void clampExtrema(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd);
- static void clampOutsideRays(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* newField, Vec3Int res, const unsigned char* obstacles, const float *oldAdvection, int zBegin, int zEnd);
-
-
-
- // output helper functions
- // static void writeImageSliceXY(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.);
- // static void writeImageSliceYZ(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.);
- // static void writeImageSliceXZ(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.);
- // static void writeProjectedIntern(const float *field, Vec3Int res, int dir1, int dir2, string prefix, int picCnt, float scale=1.);
-};
-
-#endif
diff --git a/intern/smoke/intern/FLUID_3D_SOLVERS.cpp b/intern/smoke/intern/FLUID_3D_SOLVERS.cpp
deleted file mode 100644
index b05c45e1a02..00000000000
--- a/intern/smoke/intern/FLUID_3D_SOLVERS.cpp
+++ /dev/null
@@ -1,328 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// FLUID_3D.cpp: implementation of the FLUID_3D class.
-//
-//////////////////////////////////////////////////////////////////////
-// Both solvers optimized by merging loops and precalculating
-// stuff used in iteration loop.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#include "FLUID_3D.h"
-#include <cstring>
-#define SOLVER_ACCURACY 1e-06
-
-//////////////////////////////////////////////////////////////////////
-// solve the heat equation with CG
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::solveHeat(float* field, float* b, unsigned char* skip)
-{
- int x, y, z;
- const int twoxr = 2 * _xRes;
- size_t index;
- const float heatConst = _dt * _heatDiffusion / (_dx * _dx);
- float *_q, *_residual, *_direction, *_Acenter;
-
- // i = 0
- int i = 0;
-
- _residual = new float[_totalCells]; // set 0
- _direction = new float[_totalCells]; // set 0
- _q = new float[_totalCells]; // set 0
- _Acenter = new float[_totalCells]; // set 0
-
- memset(_residual, 0, sizeof(float)*_totalCells);
- memset(_q, 0, sizeof(float)*_totalCells);
- memset(_direction, 0, sizeof(float)*_totalCells);
- memset(_Acenter, 0, sizeof(float)*_totalCells);
-
- float deltaNew = 0.0f;
-
- // r = b - Ax
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += twoxr)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- // if the cell is a variable
- _Acenter[index] = 1.0f;
- if (!skip[index])
- {
- // set the matrix to the Poisson stencil in order
- if (!skip[index + 1]) _Acenter[index] += heatConst;
- if (!skip[index - 1]) _Acenter[index] += heatConst;
- if (!skip[index + _xRes]) _Acenter[index] += heatConst;
- if (!skip[index - _xRes]) _Acenter[index] += heatConst;
- if (!skip[index + _slabSize]) _Acenter[index] += heatConst;
- if (!skip[index - _slabSize]) _Acenter[index] += heatConst;
-
- _residual[index] = b[index] - (_Acenter[index] * field[index] +
- field[index - 1] * (skip[index - 1] ? 0.0f : -heatConst) +
- field[index + 1] * (skip[index + 1] ? 0.0f : -heatConst) +
- field[index - _xRes] * (skip[index - _xRes] ? 0.0f : -heatConst) +
- field[index + _xRes] * (skip[index + _xRes] ? 0.0f : -heatConst) +
- field[index - _slabSize] * (skip[index - _slabSize] ? 0.0f : -heatConst) +
- field[index + _slabSize] * (skip[index + _slabSize] ? 0.0f : -heatConst));
- }
- else
- {
- _residual[index] = 0.0f;
- }
-
- _direction[index] = _residual[index];
- deltaNew += _residual[index] * _residual[index];
- }
-
-
- // While deltaNew > (eps^2) * delta0
- const float eps = SOLVER_ACCURACY;
- float maxR = 2.0f * eps;
- while ((i < _iterations) && (maxR > eps))
- {
- // q = Ad
- float alpha = 0.0f;
-
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += twoxr)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- // if the cell is a variable
- if (!skip[index])
- {
-
- _q[index] = (_Acenter[index] * _direction[index] +
- _direction[index - 1] * (skip[index - 1] ? 0.0f : -heatConst) +
- _direction[index + 1] * (skip[index + 1] ? 0.0f : -heatConst) +
- _direction[index - _xRes] * (skip[index - _xRes] ? 0.0f : -heatConst) +
- _direction[index + _xRes] * (skip[index + _xRes] ? 0.0f : -heatConst) +
- _direction[index - _slabSize] * (skip[index - _slabSize] ? 0.0f : -heatConst) +
- _direction[index + _slabSize] * (skip[index + _slabSize] ? 0.0f : -heatConst));
- }
- else
- {
- _q[index] = 0.0f;
- }
- alpha += _direction[index] * _q[index];
- }
-
- if (fabs(alpha) > 0.0f)
- alpha = deltaNew / alpha;
-
- float deltaOld = deltaNew;
- deltaNew = 0.0f;
-
- maxR = 0.0f;
-
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += twoxr)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- field[index] += alpha * _direction[index];
-
- _residual[index] -= alpha * _q[index];
- maxR = (_residual[index] > maxR) ? _residual[index] : maxR;
-
- deltaNew += _residual[index] * _residual[index];
- }
-
- float beta = deltaNew / deltaOld;
-
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += twoxr)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- _direction[index] = _residual[index] + beta * _direction[index];
-
-
- i++;
- }
- // cout << i << " iterations converged to " << maxR << endl;
-
- if (_residual) delete[] _residual;
- if (_direction) delete[] _direction;
- if (_q) delete[] _q;
- if (_Acenter) delete[] _Acenter;
-}
-
-void FLUID_3D::solvePressurePre(float* field, float* b, unsigned char* skip)
-{
- int x, y, z;
- size_t index;
- float *_q, *_Precond, *_h, *_residual, *_direction;
-
- // i = 0
- int i = 0;
-
- _residual = new float[_totalCells]; // set 0
- _direction = new float[_totalCells]; // set 0
- _q = new float[_totalCells]; // set 0
- _h = new float[_totalCells]; // set 0
- _Precond = new float[_totalCells]; // set 0
-
- memset(_residual, 0, sizeof(float)*_xRes*_yRes*_zRes);
- memset(_q, 0, sizeof(float)*_xRes*_yRes*_zRes);
- memset(_direction, 0, sizeof(float)*_xRes*_yRes*_zRes);
- memset(_h, 0, sizeof(float)*_xRes*_yRes*_zRes);
- memset(_Precond, 0, sizeof(float)*_xRes*_yRes*_zRes);
-
- float deltaNew = 0.0f;
-
- // r = b - Ax
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- // if the cell is a variable
- float Acenter = 0.0f;
- if (!skip[index])
- {
- // set the matrix to the Poisson stencil in order
- if (!skip[index + 1]) Acenter += 1.0f;
- if (!skip[index - 1]) Acenter += 1.0f;
- if (!skip[index + _xRes]) Acenter += 1.0f;
- if (!skip[index - _xRes]) Acenter += 1.0f;
- if (!skip[index + _slabSize]) Acenter += 1.0f;
- if (!skip[index - _slabSize]) Acenter += 1.0f;
-
- _residual[index] = b[index] - (Acenter * field[index] +
- field[index - 1] * (skip[index - 1] ? 0.0f : -1.0f) +
- field[index + 1] * (skip[index + 1] ? 0.0f : -1.0f) +
- field[index - _xRes] * (skip[index - _xRes] ? 0.0f : -1.0f)+
- field[index + _xRes] * (skip[index + _xRes] ? 0.0f : -1.0f)+
- field[index - _slabSize] * (skip[index - _slabSize] ? 0.0f : -1.0f)+
- field[index + _slabSize] * (skip[index + _slabSize] ? 0.0f : -1.0f) );
- }
- else
- {
- _residual[index] = 0.0f;
- }
-
- // P^-1
- if(Acenter < 1.0f)
- _Precond[index] = 0.0;
- else
- _Precond[index] = 1.0f / Acenter;
-
- // p = P^-1 * r
- _direction[index] = _residual[index] * _Precond[index];
-
- deltaNew += _residual[index] * _direction[index];
- }
-
-
- // While deltaNew > (eps^2) * delta0
- const float eps = SOLVER_ACCURACY;
- //while ((i < _iterations) && (deltaNew > eps*delta0))
- float maxR = 2.0f * eps;
- // while (i < _iterations)
- while ((i < _iterations) && (maxR > 0.001f * eps))
- {
-
- float alpha = 0.0f;
-
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- // if the cell is a variable
- float Acenter = 0.0f;
- if (!skip[index])
- {
- // set the matrix to the Poisson stencil in order
- if (!skip[index + 1]) Acenter += 1.0f;
- if (!skip[index - 1]) Acenter += 1.0f;
- if (!skip[index + _xRes]) Acenter += 1.0f;
- if (!skip[index - _xRes]) Acenter += 1.0f;
- if (!skip[index + _slabSize]) Acenter += 1.0f;
- if (!skip[index - _slabSize]) Acenter += 1.0f;
-
- _q[index] = Acenter * _direction[index] +
- _direction[index - 1] * (skip[index - 1] ? 0.0f : -1.0f) +
- _direction[index + 1] * (skip[index + 1] ? 0.0f : -1.0f) +
- _direction[index - _xRes] * (skip[index - _xRes] ? 0.0f : -1.0f) +
- _direction[index + _xRes] * (skip[index + _xRes] ? 0.0f : -1.0f)+
- _direction[index - _slabSize] * (skip[index - _slabSize] ? 0.0f : -1.0f) +
- _direction[index + _slabSize] * (skip[index + _slabSize] ? 0.0f : -1.0f);
- }
- else
- {
- _q[index] = 0.0f;
- }
-
- alpha += _direction[index] * _q[index];
- }
-
-
- if (fabs(alpha) > 0.0f)
- alpha = deltaNew / alpha;
-
- float deltaOld = deltaNew;
- deltaNew = 0.0f;
-
- maxR = 0.0;
-
- float tmp;
-
- // x = x + alpha * d
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- {
- field[index] += alpha * _direction[index];
-
- _residual[index] -= alpha * _q[index];
-
- _h[index] = _Precond[index] * _residual[index];
-
- tmp = _residual[index] * _h[index];
- deltaNew += tmp;
- maxR = (tmp > maxR) ? tmp : maxR;
-
- }
-
-
- // beta = deltaNew / deltaOld
- float beta = deltaNew / deltaOld;
-
- // d = h + beta * d
- index = _slabSize + _xRes + 1;
- for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
- for (y = 1; y < _yRes - 1; y++, index += 2)
- for (x = 1; x < _xRes - 1; x++, index++)
- _direction[index] = _h[index] + beta * _direction[index];
-
- // i = i + 1
- i++;
- }
- // cout << i << " iterations converged to " << sqrt(maxR) << endl;
-
- if (_h) delete[] _h;
- if (_Precond) delete[] _Precond;
- if (_residual) delete[] _residual;
- if (_direction) delete[] _direction;
- if (_q) delete[] _q;
-}
diff --git a/intern/smoke/intern/FLUID_3D_STATIC.cpp b/intern/smoke/intern/FLUID_3D_STATIC.cpp
deleted file mode 100644
index 60c13ae9e60..00000000000
--- a/intern/smoke/intern/FLUID_3D_STATIC.cpp
+++ /dev/null
@@ -1,646 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// FLUID_3D.cpp: implementation of the static functions of the FLUID_3D class.
-//
-//////////////////////////////////////////////////////////////////////
-// Heavy parallel optimization done. Many of the old functions now
-// take begin and end parameters and process only specified part of the data.
-// Some functions were divided into multiple ones.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#include <zlib.h>
-#include "FLUID_3D.h"
-#include "IMAGE.h"
-#include "WTURBULENCE.h"
-#include "INTERPOLATE.h"
-
-//////////////////////////////////////////////////////////////////////
-// add a test cube of density to the center
-//////////////////////////////////////////////////////////////////////
-/*
-void FLUID_3D::addSmokeColumn() {
- addSmokeTestCase(_density, _res, 1.0);
- // addSmokeTestCase(_zVelocity, _res, 1.0);
- addSmokeTestCase(_heat, _res, 1.0);
- if (_wTurbulence) {
- addSmokeTestCase(_wTurbulence->getDensityBig(), _wTurbulence->getResBig(), 1.0);
- }
-}
-*/
-
-//////////////////////////////////////////////////////////////////////
-// generic static version, so that it can be applied to the
-// WTURBULENCE grid as well
-//////////////////////////////////////////////////////////////////////
-
-void FLUID_3D::addSmokeTestCase(float* field, Vec3Int res)
-{
- const int slabSize = res[0]*res[1]; int maxRes = (int)MAX3V(res);
- float dx = 1.0f / (float)maxRes;
-
- float xTotal = dx * res[0];
- float yTotal = dx * res[1];
-
- float heighMin = 0.05;
- float heighMax = 0.10;
-
- for (int y = 0; y < res[2]; y++)
- for (int z = (int)(heighMin*res[2]); z <= (int)(heighMax * res[2]); z++)
- for (int x = 0; x < res[0]; x++) {
- float xLength = x * dx - xTotal * 0.4f;
- float yLength = y * dx - yTotal * 0.5f;
- float radius = sqrtf(xLength * xLength + yLength * yLength);
-
- if (radius < 0.075f * xTotal) {
- int index = x + y * res[0] + z * slabSize;
- field[index] = 1.0f;
- }
- }
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// set x direction to Neumann boundary conditions
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setNeumannX(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int y = 0; y < res[1]; y++)
- {
- // left slab
- index = y * res[0] + z * slabSize;
- field[index] = field[index + 2];
-
- // right slab
- index = y * res[0] + z * slabSize + res[0] - 1;
- field[index] = field[index - 2];
- }
- }
-
-//////////////////////////////////////////////////////////////////////
-// set y direction to Neumann boundary conditions
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setNeumannY(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int x = 0; x < res[0]; x++)
- {
- // front slab
- index = x + z * slabSize;
- field[index] = field[index + 2 * res[0]];
-
- // back slab
- index = x + z * slabSize + slabSize - res[0];
- field[index] = field[index - 2 * res[0]];
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// set z direction to Neumann boundary conditions
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setNeumannZ(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- const int totalCells = res[0] * res[1] * res[2];
- const int cellsslab = totalCells - slabSize;
- int index;
-
- if (zBegin == 0) {
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++)
- {
- // front slab
- index = x + y * res[0];
- field[index] = field[index + 2 * slabSize];
- }
- }
-
- if (zEnd == res[2]) {
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++)
- {
- // back slab
- index = x + y * res[0] + cellsslab;
- field[index] = field[index - 2 * slabSize];
- }
- }
-
-}
-
-//////////////////////////////////////////////////////////////////////
-// set x direction to zero
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setZeroX(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int y = 0; y < res[1]; y++)
- {
- // left slab
- index = y * res[0] + z * slabSize;
- field[index] = 0.0f;
-
- // right slab
- index += res[0] - 1;
- field[index] = 0.0f;
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// set y direction to zero
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setZeroY(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int x = 0; x < res[0]; x++)
- {
- // bottom slab
- index = x + z * slabSize;
- field[index] = 0.0f;
-
- // top slab
- index += slabSize - res[0];
- field[index] = 0.0f;
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// set z direction to zero
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::setZeroZ(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- const int totalCells = res[0] * res[1] * res[2];
-
- int index = 0;
- if (zBegin == 0)
- {
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++, index++)
- {
- // front slab
- field[index] = 0.0f;
- }
- }
-
- if (zEnd == res[2])
- {
- index=0;
- int indexx=0;
- const int cellsslab = totalCells - slabSize;
-
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++, index++)
- {
-
- // back slab
- indexx = index + cellsslab;
- field[indexx] = 0.0f;
- }
- }
- }
-//////////////////////////////////////////////////////////////////////
-// copy grid boundary
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::copyBorderX(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int y = 0; y < res[1]; y++)
- {
- // left slab
- index = y * res[0] + z * slabSize;
- field[index] = field[index + 1];
-
- // right slab
- index += res[0] - 1;
- field[index] = field[index - 1];
- }
-}
-void FLUID_3D::copyBorderY(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- //const int totalCells = res[0] * res[1] * res[2];
- int index;
- for (int z = zBegin; z < zEnd; z++)
- for (int x = 0; x < res[0]; x++)
- {
- // bottom slab
- index = x + z * slabSize;
- field[index] = field[index + res[0]];
- // top slab
- index += slabSize - res[0];
- field[index] = field[index - res[0]];
- }
-}
-void FLUID_3D::copyBorderZ(float* field, Vec3Int res, int zBegin, int zEnd)
-{
- const int slabSize = res[0] * res[1];
- const int totalCells = res[0] * res[1] * res[2];
- int index=0;
-
- if (zBegin == 0)
- {
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++, index++)
- {
- field[index] = field[index + slabSize];
- }
- }
-
- if (zEnd == res[2])
- {
-
- index=0;
- int indexx=0;
- const int cellsslab = totalCells - slabSize;
-
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++, index++)
- {
- // back slab
- indexx = index + cellsslab;
- field[indexx] = field[indexx - slabSize];
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////
-// advect field with the semi lagrangian method
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::advectFieldSemiLagrange(const float dt, const float* velx, const float* vely, const float* velz,
- float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd)
-{
- const int xres = res[0];
- const int yres = res[1];
- const int zres = res[2];
- const int slabSize = res[0] * res[1];
-
-
- for (int z = zBegin; z < zEnd; z++)
- for (int y = 0; y < yres; y++)
- for (int x = 0; x < xres; x++)
- {
- const int index = x + y * xres + z * xres*yres;
-
- // backtrace
- float xTrace = x - dt * velx[index];
- float yTrace = y - dt * vely[index];
- float zTrace = z - dt * velz[index];
-
- // clamp backtrace to grid boundaries
- if (xTrace < 0.5f) xTrace = 0.5f;
- if (xTrace > xres - 1.5f) xTrace = xres - 1.5f;
- if (yTrace < 0.5f) yTrace = 0.5f;
- if (yTrace > yres - 1.5f) yTrace = yres - 1.5f;
- if (zTrace < 0.5f) zTrace = 0.5f;
- if (zTrace > zres - 1.5f) zTrace = zres - 1.5f;
-
- // locate neighbors to interpolate
- const int x0 = (int)xTrace;
- const int x1 = x0 + 1;
- const int y0 = (int)yTrace;
- const int y1 = y0 + 1;
- const int z0 = (int)zTrace;
- const int z1 = z0 + 1;
-
- // get interpolation weights
- const float s1 = xTrace - x0;
- const float s0 = 1.0f - s1;
- const float t1 = yTrace - y0;
- const float t0 = 1.0f - t1;
- const float u1 = zTrace - z0;
- const float u0 = 1.0f - u1;
-
- const int i000 = x0 + y0 * xres + z0 * slabSize;
- const int i010 = x0 + y1 * xres + z0 * slabSize;
- const int i100 = x1 + y0 * xres + z0 * slabSize;
- const int i110 = x1 + y1 * xres + z0 * slabSize;
- const int i001 = x0 + y0 * xres + z1 * slabSize;
- const int i011 = x0 + y1 * xres + z1 * slabSize;
- const int i101 = x1 + y0 * xres + z1 * slabSize;
- const int i111 = x1 + y1 * xres + z1 * slabSize;
-
- // interpolate
- // (indices could be computed once)
- newField[index] = u0 * (s0 * (t0 * oldField[i000] +
- t1 * oldField[i010]) +
- s1 * (t0 * oldField[i100] +
- t1 * oldField[i110])) +
- u1 * (s0 * (t0 * oldField[i001] +
- t1 * oldField[i011]) +
- s1 * (t0 * oldField[i101] +
- t1 * oldField[i111]));
- }
-}
-
-
-/////////////////////////////////////////////////////////////////////
-// advect field with the maccormack method
-//
-// comments are the pseudocode from selle's paper
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::advectFieldMacCormack1(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* tempResult, Vec3Int res, int zBegin, int zEnd)
-{
- /*const int sx= res[0];
- const int sy= res[1];
- const int sz= res[2];
-
- for (int x = 0; x < sx * sy * sz; x++)
- phiHatN[x] = phiHatN1[x] = oldField[x];*/ // not needed as all the values are written first
-
- float*& phiN = oldField;
- float*& phiN1 = tempResult;
-
-
-
- // phiHatN1 = A(phiN)
- advectFieldSemiLagrange( dt, xVelocity, yVelocity, zVelocity, phiN, phiN1, res, zBegin, zEnd); // uses wide data from old field and velocities (both are whole)
-}
-
-
-
-void FLUID_3D::advectFieldMacCormack2(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
- float* oldField, float* newField, float* tempResult, float* temp1, Vec3Int res, const unsigned char* obstacles, int zBegin, int zEnd)
-{
- float* phiHatN = tempResult;
- float* t1 = temp1;
- const int sx= res[0];
- const int sy= res[1];
-
- float*& phiN = oldField;
- float*& phiN1 = newField;
-
-
-
- // phiHatN = A^R(phiHatN1)
- advectFieldSemiLagrange( -1.0f*dt, xVelocity, yVelocity, zVelocity, phiHatN, t1, res, zBegin, zEnd); // uses wide data from old field and velocities (both are whole)
-
- // phiN1 = phiHatN1 + (phiN - phiHatN) / 2
- const int border = 0;
- for (int z = zBegin+border; z < zEnd-border; z++)
- for (int y = border; y < sy-border; y++)
- for (int x = border; x < sx-border; x++) {
- int index = x + y * sx + z * sx*sy;
- phiN1[index] = phiHatN[index] + (phiN[index] - t1[index]) * 0.50f;
- //phiN1[index] = phiHatN1[index]; // debug, correction off
- }
- copyBorderX(phiN1, res, zBegin, zEnd);
- copyBorderY(phiN1, res, zBegin, zEnd);
- copyBorderZ(phiN1, res, zBegin, zEnd);
-
- // clamp any newly created extrema
- clampExtrema(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res, zBegin, zEnd); // uses wide data from old field and velocities (both are whole)
-
- // if the error estimate was bad, revert to first order
- clampOutsideRays(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res, obstacles, phiHatN, zBegin, zEnd); // phiHatN is only used at cells within thread range, so its ok
-
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// Clamp the extrema generated by the BFECC error correction
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::clampExtrema(const float dt, const float* velx, const float* vely, const float* velz,
- float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd)
-{
- const int xres= res[0];
- const int yres= res[1];
- const int zres= res[2];
- const int slabSize = res[0] * res[1];
-
- int bb=0;
- int bt=0;
-
- if (zBegin == 0) {bb = 1;}
- if (zEnd == res[2]) {bt = 1;}
-
-
- for (int z = zBegin+bb; z < zEnd-bt; z++)
- for (int y = 1; y < yres-1; y++)
- for (int x = 1; x < xres-1; x++)
- {
- const int index = x + y * xres+ z * xres*yres;
- // backtrace
- float xTrace = x - dt * velx[index];
- float yTrace = y - dt * vely[index];
- float zTrace = z - dt * velz[index];
-
- // clamp backtrace to grid boundaries
- if (xTrace < 0.5f) xTrace = 0.5f;
- if (xTrace > xres - 1.5f) xTrace = xres - 1.5f;
- if (yTrace < 0.5f) yTrace = 0.5f;
- if (yTrace > yres - 1.5f) yTrace = yres - 1.5f;
- if (zTrace < 0.5f) zTrace = 0.5f;
- if (zTrace > zres - 1.5f) zTrace = zres - 1.5f;
-
- // locate neighbors to interpolate
- const int x0 = (int)xTrace;
- const int x1 = x0 + 1;
- const int y0 = (int)yTrace;
- const int y1 = y0 + 1;
- const int z0 = (int)zTrace;
- const int z1 = z0 + 1;
-
- const int i000 = x0 + y0 * xres + z0 * slabSize;
- const int i010 = x0 + y1 * xres + z0 * slabSize;
- const int i100 = x1 + y0 * xres + z0 * slabSize;
- const int i110 = x1 + y1 * xres + z0 * slabSize;
- const int i001 = x0 + y0 * xres + z1 * slabSize;
- const int i011 = x0 + y1 * xres + z1 * slabSize;
- const int i101 = x1 + y0 * xres + z1 * slabSize;
- const int i111 = x1 + y1 * xres + z1 * slabSize;
-
- float minField = oldField[i000];
- float maxField = oldField[i000];
-
- minField = (oldField[i010] < minField) ? oldField[i010] : minField;
- maxField = (oldField[i010] > maxField) ? oldField[i010] : maxField;
-
- minField = (oldField[i100] < minField) ? oldField[i100] : minField;
- maxField = (oldField[i100] > maxField) ? oldField[i100] : maxField;
-
- minField = (oldField[i110] < minField) ? oldField[i110] : minField;
- maxField = (oldField[i110] > maxField) ? oldField[i110] : maxField;
-
- minField = (oldField[i001] < minField) ? oldField[i001] : minField;
- maxField = (oldField[i001] > maxField) ? oldField[i001] : maxField;
-
- minField = (oldField[i011] < minField) ? oldField[i011] : minField;
- maxField = (oldField[i011] > maxField) ? oldField[i011] : maxField;
-
- minField = (oldField[i101] < minField) ? oldField[i101] : minField;
- maxField = (oldField[i101] > maxField) ? oldField[i101] : maxField;
-
- minField = (oldField[i111] < minField) ? oldField[i111] : minField;
- maxField = (oldField[i111] > maxField) ? oldField[i111] : maxField;
-
- newField[index] = (newField[index] > maxField) ? maxField : newField[index];
- newField[index] = (newField[index] < minField) ? minField : newField[index];
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// Reverts any backtraces that go into boundaries back to first
-// order -- in this case the error correction term was totally
-// incorrect
-//////////////////////////////////////////////////////////////////////
-void FLUID_3D::clampOutsideRays(const float dt, const float* velx, const float* vely, const float* velz,
- float* oldField, float* newField, Vec3Int res, const unsigned char* obstacles, const float *oldAdvection, int zBegin, int zEnd)
-{
- const int sx= res[0];
- const int sy= res[1];
- const int sz= res[2];
- const int slabSize = res[0] * res[1];
-
- int bb=0;
- int bt=0;
-
- if (zBegin == 0) {bb = 1;}
- if (zEnd == res[2]) {bt = 1;}
-
- for (int z = zBegin+bb; z < zEnd-bt; z++)
- for (int y = 1; y < sy-1; y++)
- for (int x = 1; x < sx-1; x++)
- {
- const int index = x + y * sx+ z * slabSize;
- // backtrace
- float xBackward = x + dt * velx[index];
- float yBackward = y + dt * vely[index];
- float zBackward = z + dt * velz[index];
- float xTrace = x - dt * velx[index];
- float yTrace = y - dt * vely[index];
- float zTrace = z - dt * velz[index];
-
- // see if it goes outside the boundaries
- bool hasObstacle =
- (zTrace < 1.0f) || (zTrace > sz - 2.0f) ||
- (yTrace < 1.0f) || (yTrace > sy - 2.0f) ||
- (xTrace < 1.0f) || (xTrace > sx - 2.0f) ||
- (zBackward < 1.0f) || (zBackward > sz - 2.0f) ||
- (yBackward < 1.0f) || (yBackward > sy - 2.0f) ||
- (xBackward < 1.0f) || (xBackward > sx - 2.0f);
- // reuse old advection instead of doing another one...
- if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
-
- // clamp to prevent an out of bounds access when looking into
- // the _obstacles array
- zTrace = (zTrace < 0.5f) ? 0.5f : zTrace;
- zTrace = (zTrace > sz - 1.5f) ? sz - 1.5f : zTrace;
- yTrace = (yTrace < 0.5f) ? 0.5f : yTrace;
- yTrace = (yTrace > sy - 1.5f) ? sy - 1.5f : yTrace;
- xTrace = (xTrace < 0.5f) ? 0.5f : xTrace;
- xTrace = (xTrace > sx - 1.5f) ? sx - 1.5f : xTrace;
-
- // locate neighbors to interpolate,
- // do backward first since we will use the forward indices if a
- // reversion is actually necessary
- zBackward = (zBackward < 0.5f) ? 0.5f : zBackward;
- zBackward = (zBackward > sz - 1.5f) ? sz - 1.5f : zBackward;
- yBackward = (yBackward < 0.5f) ? 0.5f : yBackward;
- yBackward = (yBackward > sy - 1.5f) ? sy - 1.5f : yBackward;
- xBackward = (xBackward < 0.5f) ? 0.5f : xBackward;
- xBackward = (xBackward > sx - 1.5f) ? sx - 1.5f : xBackward;
-
- int x0 = (int)xBackward;
- int x1 = x0 + 1;
- int y0 = (int)yBackward;
- int y1 = y0 + 1;
- int z0 = (int)zBackward;
- int z1 = z0 + 1;
- if(obstacles && !hasObstacle) {
- hasObstacle = hasObstacle ||
- obstacles[x0 + y0 * sx + z0*slabSize] ||
- obstacles[x0 + y1 * sx + z0*slabSize] ||
- obstacles[x1 + y0 * sx + z0*slabSize] ||
- obstacles[x1 + y1 * sx + z0*slabSize] ||
- obstacles[x0 + y0 * sx + z1*slabSize] ||
- obstacles[x0 + y1 * sx + z1*slabSize] ||
- obstacles[x1 + y0 * sx + z1*slabSize] ||
- obstacles[x1 + y1 * sx + z1*slabSize] ;
- }
- // reuse old advection instead of doing another one...
- if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
-
- x0 = (int)xTrace;
- x1 = x0 + 1;
- y0 = (int)yTrace;
- y1 = y0 + 1;
- z0 = (int)zTrace;
- z1 = z0 + 1;
- if(obstacles && !hasObstacle) {
- hasObstacle = hasObstacle ||
- obstacles[x0 + y0 * sx + z0*slabSize] ||
- obstacles[x0 + y1 * sx + z0*slabSize] ||
- obstacles[x1 + y0 * sx + z0*slabSize] ||
- obstacles[x1 + y1 * sx + z0*slabSize] ||
- obstacles[x0 + y0 * sx + z1*slabSize] ||
- obstacles[x0 + y1 * sx + z1*slabSize] ||
- obstacles[x1 + y0 * sx + z1*slabSize] ||
- obstacles[x1 + y1 * sx + z1*slabSize] ;
- } // obstacle array
- // reuse old advection instead of doing another one...
- if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
-
- // see if either the forward or backward ray went into
- // a boundary
- if (hasObstacle) {
- // get interpolation weights
- float s1 = xTrace - x0;
- float s0 = 1.0f - s1;
- float t1 = yTrace - y0;
- float t0 = 1.0f - t1;
- float u1 = zTrace - z0;
- float u0 = 1.0f - u1;
-
- const int i000 = x0 + y0 * sx + z0 * slabSize;
- const int i010 = x0 + y1 * sx + z0 * slabSize;
- const int i100 = x1 + y0 * sx + z0 * slabSize;
- const int i110 = x1 + y1 * sx + z0 * slabSize;
- const int i001 = x0 + y0 * sx + z1 * slabSize;
- const int i011 = x0 + y1 * sx + z1 * slabSize;
- const int i101 = x1 + y0 * sx + z1 * slabSize;
- const int i111 = x1 + y1 * sx + z1 * slabSize;
-
- // interpolate, (indices could be computed once)
- newField[index] = u0 * (s0 * (
- t0 * oldField[i000] +
- t1 * oldField[i010]) +
- s1 * (t0 * oldField[i100] +
- t1 * oldField[i110])) +
- u1 * (s0 * (t0 * oldField[i001] +
- t1 * oldField[i011]) +
- s1 * (t0 * oldField[i101] +
- t1 * oldField[i111]));
- }
- } // xyz
-}
diff --git a/intern/smoke/intern/IMAGE.h b/intern/smoke/intern/IMAGE.h
deleted file mode 100644
index 4680e4eace2..00000000000
--- a/intern/smoke/intern/IMAGE.h
+++ /dev/null
@@ -1,289 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-//////////////////////////////////////////////////////////////////////
-//
-#ifndef IMAGE_H
-#define IMAGE_H
-
-#include <stdlib.h>
-#include <string>
-#include <fstream>
-#include <sstream>
-#include <zlib.h>
-
-//////////////////////////////////////////////////////////////////////
-// NT helper functions
-//////////////////////////////////////////////////////////////////////
-template < class T > inline T ABS( T a ) {
- return (0 < a) ? a : -a ;
-}
-
-template < class T > inline void SWAP_POINTERS( T &a, T &b ) {
- T temp = a;
- a = b;
- b = temp;
-}
-
-template < class T > inline void CLAMP( T &a, T b=0., T c=1.) {
- if(a<b) { a=b; return; }
- if(a>c) { a=c; return; }
-}
-
-template < class T > inline T MIN( const T& a, const T& b) {
- return (a < b) ? a : b;
-}
-
-template < class T > inline T MAX( const T& a, const T& b) {
- return (a > b) ? a : b;
-}
-
-template < class T > inline T MAX3( const T& a, const T& b, const T& c) {
- T max = (a > b) ? a : b;
- max = (max > c) ? max : c;
- return max;
-}
-
-template < class T > inline float MAX3V( const T& vec) {
- float max = (vec[0] > vec[1]) ? vec[0] : vec[1];
- max = (max > vec[2]) ? max : vec[2];
- return max;
-}
-
-template < class T > inline float MIN3V( const T& vec) {
- float min = (vec[0] < vec[1]) ? vec[0] : vec[1];
- min = (min < vec[2]) ? min : vec[2];
- return min;
-}
-
-//////////////////////////////////////////////////////////////////////
-// PNG, POV-Ray, and PBRT output functions
-//////////////////////////////////////////////////////////////////////
-#ifndef NOPNG
-#ifdef WIN32
-#include "png.h"
-#else
-#include <png.h>
-#endif
-#endif // NOPNG
-
-/*
- NOTE when someone decided to uncomment the following code, please remember to put it between #ifndef NOPNG #endif
-*/
-namespace IMAGE {
- /*
- static int writePng(const char *fileName, unsigned char **rowsp, int w, int h)
- {
- // defaults
- const int colortype = PNG_COLOR_TYPE_RGBA;
- const int bitdepth = 8;
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- png_bytep *rows = rowsp;
-
- FILE *fp = NULL;
- std::string doing = "open for writing";
- if (!(fp = fopen(fileName, "wb"))) goto fail;
-
- if(!png_ptr) {
- doing = "create png write struct";
- if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail;
- }
- if(!info_ptr) {
- doing = "create png info struct";
- if (!(info_ptr = png_create_info_struct(png_ptr))) goto fail;
- }
-
- if (setjmp(png_jmpbuf(png_ptr))) goto fail;
- doing = "init IO";
- png_init_io(png_ptr, fp);
- doing = "write header";
- png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
- doing = "write info";
- png_write_info(png_ptr, info_ptr);
- doing = "write image";
- png_write_image(png_ptr, rows);
- doing = "write end";
- png_write_end(png_ptr, NULL);
- doing = "write destroy structs";
- png_destroy_write_struct(&png_ptr, &info_ptr);
-
- fclose( fp );
- return 0;
-
- fail:
- std::cerr << "writePng: could not "<<doing<<" !\n";
- if(fp) fclose( fp );
- if(png_ptr || info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
- return -1;
- }
- */
-
- /////////////////////////////////////////////////////////////////////////////////
- // write a numbered PNG file out, padded with zeros up to three zeros
- /////////////////////////////////////////////////////////////////////////////////
- /*
- static void dumpNumberedPNG(int counter, std::string prefix, float* field, int xRes, int yRes)
- {
- char buffer[256];
- sprintf(buffer,"%04i", counter);
- std::string number = std::string(buffer);
-
- unsigned char pngbuf[xRes*yRes*4];
- unsigned char *rows[yRes];
- float *pfield = field;
- for (int j=0; j<yRes; j++) {
- for (int i=0; i<xRes; i++) {
- float val = *pfield;
- if(val>1.) val=1.;
- if(val<0.) val=0.;
- pngbuf[(j*xRes+i)*4+0] = (unsigned char)(val*255.);
- pngbuf[(j*xRes+i)*4+1] = (unsigned char)(val*255.);
- pngbuf[(j*xRes+i)*4+2] = (unsigned char)(val*255.);
- pfield++;
- pngbuf[(j*xRes+i)*4+3] = 255;
- }
- rows[j] = &pngbuf[(yRes-j-1)*xRes*4];
- }
- std::string filenamePNG = prefix + number + std::string(".png");
- writePng(filenamePNG.c_str(), rows, xRes, yRes, false);
- printf("Writing %s\n", filenamePNG.c_str());
-
- }
-*/
- /////////////////////////////////////////////////////////////////////////////////
- // export pbrt volumegrid geometry object
- /////////////////////////////////////////////////////////////////////////////////
- /*
- static void dumpPBRT(int counter, std::string prefix, float* fieldOrg, int xRes, int yRes, int zRes)
- {
- char buffer[256];
- sprintf(buffer,"%04i", counter);
- std::string number = std::string(buffer);
-
- std::string filenamePbrt = prefix + number + std::string(".pbrt.gz");
- printf("Writing PBRT %s\n", filenamePbrt.c_str());
-
- float *field = new float[xRes*yRes*zRes];
- // normalize values
- float maxDensVal = ABS(fieldOrg[0]);
- float targetNorm = 0.5;
- for (int i = 0; i < xRes * yRes * zRes; i++) {
- if(ABS(fieldOrg[i])>maxDensVal) maxDensVal = ABS(fieldOrg[i]);
- field[i] = 0.;
- }
- if(maxDensVal>0.) {
- for (int i = 0; i < xRes * yRes * zRes; i++) {
- field[i] = ABS(fieldOrg[i]) / maxDensVal * targetNorm;
- }
- }
-
- std::fstream fout;
- fout.open(filenamePbrt.c_str(), std::ios::out);
-
- int maxRes = (xRes > yRes) ? xRes : yRes;
- maxRes = (maxRes > zRes) ? maxRes : zRes;
-
- const float xSize = 1.0 / (float)maxRes * (float)xRes;
- const float ySize = 1.0 / (float)maxRes * (float)yRes;
- const float zSize = 1.0 / (float)maxRes * (float)zRes;
-
- gzFile file;
- file = gzopen(filenamePbrt.c_str(), "wb1");
- if (file == NULL) {
- std::cerr << " Couldn't write file " << filenamePbrt << "!!!" << std::endl;
- return;
- }
-
- // dimensions
- gzprintf(file, "Volume \"volumegrid\" \n");
- gzprintf(file, " \"integer nx\" %i\n", xRes);
- gzprintf(file, " \"integer ny\" %i\n", yRes);
- gzprintf(file, " \"integer nz\" %i\n", zRes);
- gzprintf(file, " \"point p0\" [ 0.0 0.0 0.0 ] \"point p1\" [%f %f %f ] \n", xSize, ySize, zSize);
- gzprintf(file, " \"float density\" [ \n");
- for (int i = 0; i < xRes * yRes * zRes; i++)
- gzprintf(file, "%f ", field[i]);
- gzprintf(file, "] \n \n");
-
- gzclose(file);
- delete[] field;
- }
- */
-
- /////////////////////////////////////////////////////////////////////////////////
- // 3D df3 export
- /////////////////////////////////////////////////////////////////////////////////
-/*
- static void dumpDF3(int counter, std::string prefix, float* fieldOrg, int xRes, int yRes, int zRes)
- {
- char buffer[256];
-
- // do deferred copying to final directory, better for network directories
- sprintf(buffer,"%04i", counter);
- std::string number = std::string(buffer);
- std::string filenameDf3 = prefix + number + std::string(".df3.gz");
- printf("Writing DF3 %s\n", filenameDf3.c_str());
-
- gzFile file;
- file = gzopen(filenameDf3.c_str(), "wb1");
- if (file == NULL) {
- std::cerr << " Couldn't write file " << filenameDf3 << "!!!" << std::endl;
- return;
- }
-
- // dimensions
- const int byteSize = 2;
- const unsigned short int onx=xRes,ony=yRes,onz=zRes;
- unsigned short int nx,ny,nz;
- nx = onx >> 8;
- ny = ony >> 8;
- nz = onz >> 8;
- nx += (onx << 8);
- ny += (ony << 8);
- nz += (onz << 8);
- gzwrite(file, (void*)&nx, sizeof(short));
- gzwrite(file, (void*)&ny, sizeof(short));
- gzwrite(file, (void*)&nz, sizeof(short));
- const int nitems = onx*ony*onz;
- const float mul = (float)( (1<<(8*byteSize))-1);
-
- unsigned short int *buf = new unsigned short int[nitems];
- for (int k = 0; k < onz; k++)
- for (int j = 0; j < ony; j++)
- for (int i = 0; i < onx; i++) {
- float val = fieldOrg[k*(onx*ony)+j*onx+i] ;
- CLAMP(val);
- buf[k*(onx*ony)+j*onx+i] = (short int)(val*mul);
- }
- gzwrite(file, (void*)buf, sizeof(unsigned short int)* nitems);
-
- gzclose(file);
- delete[] buf;
- }
- */
-
-};
-
-
-#endif
-
diff --git a/intern/smoke/intern/INTERPOLATE.h b/intern/smoke/intern/INTERPOLATE.h
deleted file mode 100644
index e9821e4f93e..00000000000
--- a/intern/smoke/intern/INTERPOLATE.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-//////////////////////////////////////////////////////////////////////
-#ifndef INTERPOLATE_H
-#define INTERPOLATE_H
-
-#include <iostream>
-#include <VEC3.h>
-
-namespace INTERPOLATE {
-
-//////////////////////////////////////////////////////////////////////
-// linear interpolators
-//////////////////////////////////////////////////////////////////////
-static inline float lerp(float t, float a, float b) {
- return ( a + t * (b - a) );
-}
-
-static inline float lerp(float* field, float x, float y, int res) {
- // clamp backtrace to grid boundaries
- if (x < 0.5f) x = 0.5f;
- if (x > res - 1.5f) x = res - 1.5f;
- if (y < 0.5f) y = 0.5f;
- if (y > res - 1.5f) y = res - 1.5f;
-
- const int x0 = (int)x;
- const int y0 = (int)y;
- x -= x0;
- y -= y0;
- float d00, d10, d01, d11;
-
- // lerp the velocities
- d00 = field[x0 + y0 * res];
- d10 = field[(x0 + 1) + y0 * res];
- d01 = field[x0 + (y0 + 1) * res];
- d11 = field[(x0 + 1) + (y0 + 1) * res];
- return lerp(y, lerp(x, d00, d10),
- lerp(x, d01, d11));
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// 3d linear interpolation
-//////////////////////////////////////////////////////////////////////////////////////////
-static inline float lerp3d(float* field, float x, float y, float z, int xres, int yres, int zres) {
- // clamp pos to grid boundaries
- if (x < 0.5f) x = 0.5f;
- if (x > xres - 1.5f) x = xres - 1.5f;
- if (y < 0.5f) y = 0.5f;
- if (y > yres - 1.5f) y = yres - 1.5f;
- if (z < 0.5f) z = 0.5f;
- if (z > zres - 1.5f) z = zres - 1.5f;
-
- // locate neighbors to interpolate
- const int x0 = (int)x;
- const int x1 = x0 + 1;
- const int y0 = (int)y;
- const int y1 = y0 + 1;
- const int z0 = (int)z;
- const int z1 = z0 + 1;
-
- // get interpolation weights
- const float s1 = x - (float)x0;
- const float s0 = 1.0f - s1;
- const float t1 = y - (float)y0;
- const float t0 = 1.0f - t1;
- const float u1 = z - (float)z0;
- const float u0 = 1.0f - u1;
-
- const int slabSize = xres*yres;
- const int i000 = x0 + y0 * xres + z0 * slabSize;
- const int i010 = x0 + y1 * xres + z0 * slabSize;
- const int i100 = x1 + y0 * xres + z0 * slabSize;
- const int i110 = x1 + y1 * xres + z0 * slabSize;
- const int i001 = x0 + y0 * xres + z1 * slabSize;
- const int i011 = x0 + y1 * xres + z1 * slabSize;
- const int i101 = x1 + y0 * xres + z1 * slabSize;
- const int i111 = x1 + y1 * xres + z1 * slabSize;
-
- // interpolate (indices could be computed once)
- return ( u0 * (s0 * (t0 * field[i000] +
- t1 * field[i010]) +
- s1 * (t0 * field[i100] +
- t1 * field[i110])) +
- u1 * (s0 * (t0 * field[i001] +
- t1 * field[i011]) +
- s1 * (t0 * field[i101] +
- t1 * field[i111])) );
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// convert field entries of type T to floats, then interpolate
-//////////////////////////////////////////////////////////////////////////////////////////
-template <class T>
-static inline float lerp3dToFloat(T* field1,
- float x, float y, float z, int xres, int yres, int zres) {
- // clamp pos to grid boundaries
- if (x < 0.5f) x = 0.5f;
- if (x > xres - 1.5f) x = xres - 1.5f;
- if (y < 0.5f) y = 0.5f;
- if (y > yres - 1.5f) y = yres - 1.5f;
- if (z < 0.5f) z = 0.5f;
- if (z > zres - 1.5f) z = zres - 1.5f;
-
- // locate neighbors to interpolate
- const int x0 = (int)x;
- const int x1 = x0 + 1;
- const int y0 = (int)y;
- const int y1 = y0 + 1;
- const int z0 = (int)z;
- const int z1 = z0 + 1;
-
- // get interpolation weights
- const float s1 = x - (float)x0;
- const float s0 = 1.0f - s1;
- const float t1 = y - (float)y0;
- const float t0 = 1.0f - t1;
- const float u1 = z - (float)z0;
- const float u0 = 1.0f - u1;
-
- const int slabSize = xres*yres;
- const int i000 = x0 + y0 * xres + z0 * slabSize;
- const int i010 = x0 + y1 * xres + z0 * slabSize;
- const int i100 = x1 + y0 * xres + z0 * slabSize;
- const int i110 = x1 + y1 * xres + z0 * slabSize;
- const int i001 = x0 + y0 * xres + z1 * slabSize;
- const int i011 = x0 + y1 * xres + z1 * slabSize;
- const int i101 = x1 + y0 * xres + z1 * slabSize;
- const int i111 = x1 + y1 * xres + z1 * slabSize;
-
- // interpolate (indices could be computed once)
- return (float)(
- ( u0 * (s0 * (t0 * (float)field1[i000] +
- t1 * (float)field1[i010]) +
- s1 * (t0 * (float)field1[i100] +
- t1 * (float)field1[i110])) +
- u1 * (s0 * (t0 * (float)field1[i001] +
- t1 * (float)field1[i011]) +
- s1 * (t0 * (float)field1[i101] +
- t1 * (float)field1[i111])) ) );
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// interpolate a vector from 3 fields
-//////////////////////////////////////////////////////////////////////////////////////////
-static inline Vec3 lerp3dVec(float* field1, float* field2, float* field3,
- float x, float y, float z, int xres, int yres, int zres) {
- // clamp pos to grid boundaries
- if (x < 0.5f) x = 0.5f;
- if (x > xres - 1.5f) x = xres - 1.5f;
- if (y < 0.5f) y = 0.5f;
- if (y > yres - 1.5f) y = yres - 1.5f;
- if (z < 0.5f) z = 0.5f;
- if (z > zres - 1.5f) z = zres - 1.5f;
-
- // locate neighbors to interpolate
- const int x0 = (int)x;
- const int x1 = x0 + 1;
- const int y0 = (int)y;
- const int y1 = y0 + 1;
- const int z0 = (int)z;
- const int z1 = z0 + 1;
-
- // get interpolation weights
- const float s1 = x - (float)x0;
- const float s0 = 1.0f - s1;
- const float t1 = y - (float)y0;
- const float t0 = 1.0f - t1;
- const float u1 = z - (float)z0;
- const float u0 = 1.0f - u1;
-
- const int slabSize = xres*yres;
- const int i000 = x0 + y0 * xres + z0 * slabSize;
- const int i010 = x0 + y1 * xres + z0 * slabSize;
- const int i100 = x1 + y0 * xres + z0 * slabSize;
- const int i110 = x1 + y1 * xres + z0 * slabSize;
- const int i001 = x0 + y0 * xres + z1 * slabSize;
- const int i011 = x0 + y1 * xres + z1 * slabSize;
- const int i101 = x1 + y0 * xres + z1 * slabSize;
- const int i111 = x1 + y1 * xres + z1 * slabSize;
-
- // interpolate (indices could be computed once)
- return Vec3(
- ( u0 * (s0 * (t0 * field1[i000] +
- t1 * field1[i010]) +
- s1 * (t0 * field1[i100] +
- t1 * field1[i110])) +
- u1 * (s0 * (t0 * field1[i001] +
- t1 * field1[i011]) +
- s1 * (t0 * field1[i101] +
- t1 * field1[i111])) ) ,
- ( u0 * (s0 * (t0 * field2[i000] +
- t1 * field2[i010]) +
- s1 * (t0 * field2[i100] +
- t1 * field2[i110])) +
- u1 * (s0 * (t0 * field2[i001] +
- t1 * field2[i011]) +
- s1 * (t0 * field2[i101] +
- t1 * field2[i111])) ) ,
- ( u0 * (s0 * (t0 * field3[i000] +
- t1 * field3[i010]) +
- s1 * (t0 * field3[i100] +
- t1 * field3[i110])) +
- u1 * (s0 * (t0 * field3[i001] +
- t1 * field3[i011]) +
- s1 * (t0 * field3[i101] +
- t1 * field3[i111])) )
- );
-}
-
-};
-#endif
diff --git a/intern/smoke/intern/LICENSE.txt b/intern/smoke/intern/LICENSE.txt
deleted file mode 100644
index 94a9ed024d3..00000000000
--- a/intern/smoke/intern/LICENSE.txt
+++ /dev/null
@@ -1,674 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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 3 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, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- <program> Copyright (C) <year> <name of author>
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/intern/smoke/intern/LU_HELPER.cpp b/intern/smoke/intern/LU_HELPER.cpp
deleted file mode 100644
index 0a4260c2e64..00000000000
--- a/intern/smoke/intern/LU_HELPER.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-
-#include "LU_HELPER.h"
-
-int isNonsingular (sLU LU_) {
- for (int j = 0; j < 3; j++) {
- if (LU_.values[j][j] == 0)
- return 0;
- }
- return 1;
-}
-
-sLU computeLU( float a[3][3])
-{
- sLU result;
- int m=3;
- int n=3;
-
- //float LU_[3][3];
- for (int i = 0; i < m; i++) {
- result.piv[i] = i;
- for (int j = 0; j < n; j++) result.values[i][j]=a[i][j];
- }
-
- result.pivsign = 1;
- //Real *LUrowi = 0;;
- //Array1D<Real> LUcolj(m);
- //float *LUrowi = 0;
- float LUcolj[3];
-
- // Outer loop.
-
- for (int j = 0; j < n; j++) {
-
- // Make a copy of the j-th column to localize references.
-
- for (int i = 0; i < m; i++) {
- LUcolj[i] = result.values[i][j];
- }
-
- // Apply previous transformations.
-
- for (int i = 0; i < m; i++) {
- //float LUrowi[3];
- //LUrowi = result.values[i];
-
- // Most of the time is spent in the following dot product.
-
- int kmax = min(i,j);
- double s = 0.0;
- for (int k = 0; k < kmax; k++) {
- s += (double)(result.values[i][k]*LUcolj[k]);
- }
-
- result.values[i][j] = LUcolj[i] -= (float)s;
- }
-
- // Find pivot and exchange if necessary.
-
- int p = j;
- for (int i = j+1; i < m; i++) {
- if (abs(LUcolj[i]) > abs(LUcolj[p])) {
- p = i;
- }
- }
- if (p != j) {
- int k=0;
- for (k = 0; k < n; k++) {
- double t = result.values[p][k];
- result.values[p][k] = result.values[j][k];
- result.values[j][k] = t;
- }
- k = result.piv[p];
- result.piv[p] = result.piv[j];
- result.piv[j] = k;
- result.pivsign = -result.pivsign;
- }
-
- // Compute multipliers.
-
- if ((j < m) && (result.values[j][j] != 0.0f)) {
- for (int i = j+1; i < m; i++) {
- result.values[i][j] /= result.values[j][j];
- }
- }
- }
-
- return result;
-}
-
-void solveLU3x3(sLU& A, float x[3], float b[3])
-{
- //TNT::Array1D<float> jamaB = TNT::Array1D<float>(3, &b[0]);
- //TNT::Array1D<float> jamaX = A.solve(jamaB);
-
-
- // Solve A, B
-
- {
- if (!isNonsingular(A)) {
- x[0]=0.0f;
- x[1]=0.0f;
- x[2]=0.0f;
- return;
- }
-
-
- //Array1D<Real> Ax = permute_copy(b, piv);
- float Ax[3];
-
- // permute copy: b , A.piv
- {
- for (int i = 0; i < 3; i++)
- Ax[i] = b[A.piv[i]];
- }
-
- // Solve L*Y = B(piv)
- for (int k = 0; k < 3; k++) {
- for (int i = k+1; i < 3; i++) {
- Ax[i] -= Ax[k]*A.values[i][k];
- }
- }
-
- // Solve U*X = Y;
- for (int k = 2; k >= 0; k--) {
- Ax[k] /= A.values[k][k];
- for (int i = 0; i < k; i++)
- Ax[i] -= Ax[k]*A.values[i][k];
- }
-
-
- x[0] = Ax[0];
- x[1] = Ax[1];
- x[2] = Ax[2];
- return;
- }
-}
diff --git a/intern/smoke/intern/LU_HELPER.h b/intern/smoke/intern/LU_HELPER.h
deleted file mode 100644
index 3cc8e9e3ced..00000000000
--- a/intern/smoke/intern/LU_HELPER.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-//////////////////////////////////////////////////////////////////////
-// Modified to not require TNT matrix library anymore. It was very slow
-// when being run in parallel. Required TNT JAMA:LU libraries were
-// converted into independent functions.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#ifndef LU_HELPER_H
-#define LU_HELPER_H
-
-#include <cmath>
-#include <algorithm>
-
-using namespace std;
-
-//////////////////////////////////////////////////////////////////////
-// Helper function, compute eigenvalues of 3x3 matrix
-//////////////////////////////////////////////////////////////////////
-
-struct sLU
-{
- float values[3][3];
- int pivsign;
- int piv[3];
-};
-
-
-int isNonsingular (sLU LU_);
-sLU computeLU( float a[3][3]);
-void solveLU3x3(sLU& A, float x[3], float b[3]);
-
-
-#endif
diff --git a/intern/smoke/intern/MERSENNETWISTER.h b/intern/smoke/intern/MERSENNETWISTER.h
deleted file mode 100644
index b142ca4072b..00000000000
--- a/intern/smoke/intern/MERSENNETWISTER.h
+++ /dev/null
@@ -1,432 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-// MersenneTwister.h
-// Mersenne Twister random number generator -- a C++ class MTRand
-// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
-// Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com
-
-// The Mersenne Twister is an algorithm for generating random numbers. It
-// was designed with consideration of the flaws in various other generators.
-// The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
-// are far greater. The generator is also fast; it avoids multiplication and
-// division, and it benefits from caches and pipelines. For more information
-// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html
-
-// Reference
-// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
-// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
-// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
-
-// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
-// Copyright (C) 2000 - 2003, Richard J. Wagner
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-//
-// 1. Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in the
-// documentation and/or other materials provided with the distribution.
-//
-// 3. The names of its contributors may not be used to endorse or promote
-// products derived from this software without specific prior written
-// permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// The original code included the following notice:
-//
-// When you use this, send an email to: matumoto@math.keio.ac.jp
-// with an appropriate reference to your work.
-//
-// It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu
-// when you write.
-
-#ifndef MERSENNETWISTER_H
-#define MERSENNETWISTER_H
-
-// Not thread safe (unless auto-initialization is avoided and each thread has
-// its own MTRand object)
-
-#include <iostream>
-#include <limits.h>
-#include <stdio.h>
-#include <time.h>
-#include <math.h>
-
-class MTRand {
-// Data
-public:
- typedef unsigned long uint32; // unsigned integer type, at least 32 bits
-
- enum { N = 624 }; // length of state vector
- enum { SAVE = N + 1 }; // length of array for save()
-
-protected:
- enum { M = 397 }; // period parameter
-
- uint32 state[N]; // internal state
- uint32 *pNext; // next value to get from state
- int left; // number of values left before reload needed
-
-
-//Methods
-public:
- MTRand( const uint32& oneSeed ); // initialize with a simple uint32
- MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or an array
- MTRand(); // auto-initialize with /dev/urandom or time() and clock()
-
- // Do NOT use for CRYPTOGRAPHY without securely hashing several returned
- // values together, otherwise the generator state can be learned after
- // reading 624 consecutive values.
-
- // Access to 32-bit random numbers
- double rand(); // real number in [0,1]
- double rand( const double& n ); // real number in [0,n]
- double randExc(); // real number in [0,1)
- double randExc( const double& n ); // real number in [0,n)
- double randDblExc(); // real number in (0,1)
- double randDblExc( const double& n ); // real number in (0,n)
- uint32 randInt(); // integer in [0,2^32-1]
- uint32 randInt( const uint32& n ); // integer in [0,n] for n < 2^32
- double operator()() { return rand(); } // same as rand()
-
- // Access to 53-bit random numbers (capacity of IEEE double precision)
- double rand53(); // real number in [0,1)
-
- // Access to nonuniform random number distributions
- double randNorm( const double& mean = 0.0, const double& variance = 1.0 );
-
- // Re-seeding functions with same behavior as initializers
- void seed( const uint32 oneSeed );
- void seed( uint32 *const bigSeed, const uint32 seedLength = N );
- void seed();
-
- // Saving and loading generator state
- void save( uint32* saveArray ) const; // to array of size SAVE
- void load( uint32 *const loadArray ); // from such array
- friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand );
- friend std::istream& operator>>( std::istream& is, MTRand& mtrand );
-
-protected:
- void initialize( const uint32 oneSeed );
- void reload();
- uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; }
- uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; }
- uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; }
- uint32 mixBits( const uint32& u, const uint32& v ) const
- { return hiBit(u) | loBits(v); }
- uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const
- { return m ^ (mixBits(s0,s1)>>1) ^ ((~loBit(s1) + 1) & 0x9908b0dfUL); }
- static uint32 hash( time_t t, clock_t c );
-};
-
-
-inline MTRand::MTRand( const uint32& oneSeed )
- { seed(oneSeed); }
-
-inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength )
- { seed(bigSeed,seedLength); }
-
-inline MTRand::MTRand()
- { seed(); }
-
-inline double MTRand::rand()
- { return double(randInt()) * (1.0/4294967295.0); }
-
-inline double MTRand::rand( const double& n )
- { return rand() * n; }
-
-inline double MTRand::randExc()
- { return double(randInt()) * (1.0/4294967296.0); }
-
-inline double MTRand::randExc( const double& n )
- { return randExc() * n; }
-
-inline double MTRand::randDblExc()
- { return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); }
-
-inline double MTRand::randDblExc( const double& n )
- { return randDblExc() * n; }
-
-inline double MTRand::rand53()
-{
- uint32 a = randInt() >> 5, b = randInt() >> 6;
- return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0); // by Isaku Wada
-}
-
-inline double MTRand::randNorm( const double& mean, const double& variance )
-{
- // Return a real number from a normal (Gaussian) distribution with given
- // mean and variance by Box-Muller method
- double r = sqrt( -2.0 * log( 1.0-randDblExc()) ) * variance;
- double phi = 2.0 * 3.14159265358979323846264338328 * randExc();
- return mean + r * cos(phi);
-}
-
-inline MTRand::uint32 MTRand::randInt()
-{
- // Pull a 32-bit integer from the generator state
- // Every other access function simply transforms the numbers extracted here
-
- if( left == 0 ) reload();
- --left;
-
- uint32 s1;
- s1 = *pNext++;
- s1 ^= (s1 >> 11);
- s1 ^= (s1 << 7) & 0x9d2c5680UL;
- s1 ^= (s1 << 15) & 0xefc60000UL;
- return ( s1 ^ (s1 >> 18) );
-}
-
-inline MTRand::uint32 MTRand::randInt( const uint32& n )
-{
- // Find which bits are used in n
- // Optimized by Magnus Jonsson (magnus@smartelectronix.com)
- uint32 used = n;
- used |= used >> 1;
- used |= used >> 2;
- used |= used >> 4;
- used |= used >> 8;
- used |= used >> 16;
-
- // Draw numbers until one is found in [0,n]
- uint32 i;
- do
- i = randInt() & used; // toss unused bits to shorten search
- while( i > n );
- return i;
-}
-
-
-inline void MTRand::seed( const uint32 oneSeed )
-{
- // Seed the generator with a simple uint32
- initialize(oneSeed);
- reload();
-}
-
-
-inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
-{
- // Seed the generator with an array of uint32's
- // There are 2^19937-1 possible initial states. This function allows
- // all of those to be accessed by providing at least 19937 bits (with a
- // default seed length of N = 624 uint32's). Any bits above the lower 32
- // in each element are discarded.
- // Just call seed() if you want to get array from /dev/urandom
- initialize(19650218UL);
- int i = 1;
- uint32 j = 0;
- int k = ( (uint32)N > seedLength ? (uint32)N : seedLength );
- for( ; k; --k )
- {
- state[i] =
- state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL );
- state[i] += ( bigSeed[j] & 0xffffffffUL ) + j;
- state[i] &= 0xffffffffUL;
- ++i; ++j;
- if( i >= N ) { state[0] = state[N-1]; i = 1; }
- if( j >= seedLength ) j = 0;
- }
- for( k = N - 1; k; --k )
- {
- state[i] =
- state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL );
- state[i] -= i;
- state[i] &= 0xffffffffUL;
- ++i;
- if( i >= N ) { state[0] = state[N-1]; i = 1; }
- }
- state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array
- reload();
-}
-
-
-inline void MTRand::seed()
-{
- // seed deterministically to produce reproducible runs
- seed(123456);
-
- /*
- // Seed the generator with an array from /dev/urandom if available
- // Otherwise use a hash of time() and clock() values
-
- // First try getting an array from /dev/urandom
- FILE* urandom = fopen( "/dev/urandom", "rb" );
- if( urandom )
- {
- uint32 bigSeed[N];
- uint32 *s = bigSeed;
- int i = N;
- bool success = true;
- while( success && i-- )
- success = fread( s++, sizeof(uint32), 1, urandom );
- fclose(urandom);
- if( success ) { seed( bigSeed, N ); return; }
- }
-
- // Was not successful, so use time() and clock() instead
- seed( hash( time(NULL), clock() ) );
- */
-}
-
-
-inline void MTRand::initialize( const uint32 seed )
-{
- // Initialize generator state with seed
- // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
- // In previous versions, most significant bits (MSBs) of the seed affect
- // only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
- uint32 *s = state;
- uint32 *r = state;
- int i = 1;
- *s++ = seed & 0xffffffffUL;
- for( ; i < N; ++i )
- {
- *s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL;
- r++;
- }
-}
-
-
-inline void MTRand::reload()
-{
- // Generate N new values in state
- // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
- uint32 *p = state;
- int i;
- for( i = N - M; i--; ++p )
- *p = twist( p[M], p[0], p[1] );
- for( i = M; --i; ++p )
- *p = twist( p[M-N], p[0], p[1] );
- *p = twist( p[M-N], p[0], state[0] );
-
- left = N, pNext = state;
-}
-
-
-inline MTRand::uint32 MTRand::hash( time_t t, clock_t c )
-{
- // Get a uint32 from t and c
- // Better than uint32(x) in case x is floating point in [0,1]
- // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
-
- static uint32 differ = 0; // guarantee time-based seeds will change
-
- uint32 h1 = 0;
- unsigned char *p = (unsigned char *) &t;
- for( size_t i = 0; i < sizeof(t); ++i )
- {
- h1 *= UCHAR_MAX + 2U;
- h1 += p[i];
- }
- uint32 h2 = 0;
- p = (unsigned char *) &c;
- for( size_t j = 0; j < sizeof(c); ++j )
- {
- h2 *= UCHAR_MAX + 2U;
- h2 += p[j];
- }
- return ( h1 + differ++ ) ^ h2;
-}
-
-
-inline void MTRand::save( uint32* saveArray ) const
-{
- uint32 *sa = saveArray;
- const uint32 *s = state;
- int i = N;
- for( ; i--; *sa++ = *s++ ) {}
- *sa = left;
-}
-
-
-inline void MTRand::load( uint32 *const loadArray )
-{
- uint32 *s = state;
- uint32 *la = loadArray;
- int i = N;
- for( ; i--; *s++ = *la++ ) {}
- left = *la;
- pNext = &state[N-left];
-}
-
-
-inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
-{
- const MTRand::uint32 *s = mtrand.state;
- int i = mtrand.N;
- for( ; i--; os << *s++ << "\t" ) {}
- return os << mtrand.left;
-}
-
-
-inline std::istream& operator>>( std::istream& is, MTRand& mtrand )
-{
- MTRand::uint32 *s = mtrand.state;
- int i = mtrand.N;
- for( ; i--; is >> *s++ ) {}
- is >> mtrand.left;
- mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
- return is;
-}
-
-#endif // MERSENNETWISTER_H
-
-// Change log:
-//
-// v0.1 - First release on 15 May 2000
-// - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
-// - Translated from C to C++
-// - Made completely ANSI compliant
-// - Designed convenient interface for initialization, seeding, and
-// obtaining numbers in default or user-defined ranges
-// - Added automatic seeding from /dev/urandom or time() and clock()
-// - Provided functions for saving and loading generator state
-//
-// v0.2 - Fixed bug which reloaded generator one step too late
-//
-// v0.3 - Switched to clearer, faster reload() code from Matthew Bellew
-//
-// v0.4 - Removed trailing newline in saved generator format to be consistent
-// with output format of built-in types
-//
-// v0.5 - Improved portability by replacing static const int's with enum's and
-// clarifying return values in seed(); suggested by Eric Heimburg
-// - Removed MAXINT constant; use 0xffffffffUL instead
-//
-// v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits
-// - Changed integer [0,n] generator to give better uniformity
-//
-// v0.7 - Fixed operator precedence ambiguity in reload()
-// - Added access for real numbers in (0,1) and (0,n)
-//
-// v0.8 - Included time.h header to properly support time_t and clock_t
-//
-// v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto
-// - Allowed for seeding with arrays of any length
-// - Added access for real numbers in [0,1) with 53-bit resolution
-// - Added access for real numbers from normal (Gaussian) distributions
-// - Increased overall speed by optimizing twist()
-// - Doubled speed of integer [0,n] generation
-// - Fixed out-of-range number generation on 64-bit machines
-// - Improved portability by substituting literal constants for long enum's
-// - Changed license from GNU LGPL to BSD
-
diff --git a/intern/smoke/intern/Makefile.FFT b/intern/smoke/intern/Makefile.FFT
deleted file mode 100644
index 7e9d089cec2..00000000000
--- a/intern/smoke/intern/Makefile.FFT
+++ /dev/null
@@ -1,22 +0,0 @@
-# common stuff
-LDFLAGS_COMMON = -lfftw3 #-lglut -lglu32 -lopengl32 -lz -lpng
-CFLAGS_COMMON = -c -Wall -I./ #-I/cygdrive/c/lib/glvu/include -D_WIN32
-
-CC = g++
-CFLAGS = ${CFLAGS_COMMON} -O3 -Wno-unused
-LDFLAGS = ${LDFLAGS_COMMON}
-EXECUTABLE = noiseFFT
-
-SOURCES = noiseFFT.cpp
-OBJECTS = $(SOURCES:.cpp=.o)
-
-all: $(SOURCES) $(EXECUTABLE)
-
-$(EXECUTABLE): $(OBJECTS)
- $(CC) $(OBJECTS) $(LDFLAGS) -o $@
-
-.cpp.o:
- $(CC) $(CFLAGS) $< -o $@
-
-clean:
- rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
diff --git a/intern/smoke/intern/Makefile.cygwin b/intern/smoke/intern/Makefile.cygwin
deleted file mode 100644
index 2a747219554..00000000000
--- a/intern/smoke/intern/Makefile.cygwin
+++ /dev/null
@@ -1,23 +0,0 @@
-CC = g++
-LDFLAGS = -lz -lpng
-CFLAGS = -O3 -Wno-unused -c -Wall -I./ -D_WIN32
-EXECUTABLE = FLUID_3D
-
-SOURCES = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp
-OBJECTS = $(SOURCES:.cpp=.o)
-
-all: $(SOURCES) $(EXECUTABLE)
-
-$(EXECUTABLE): $(OBJECTS)
- $(CC) $(OBJECTS) $(LDFLAGS) -o $@
-
-.cpp.o:
- $(CC) $(CFLAGS) $< -o $@
-
-SPHERE.o: SPHERE.h
-FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp
-FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp
-main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp
-
-clean:
- rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
diff --git a/intern/smoke/intern/Makefile.linux b/intern/smoke/intern/Makefile.linux
deleted file mode 100644
index 5fbb6e6c3e3..00000000000
--- a/intern/smoke/intern/Makefile.linux
+++ /dev/null
@@ -1,23 +0,0 @@
-CC = g++
-LDFLAGS = -lz -lpng -fopenmp -lgomp
-CFLAGS = -c -Wall -I./ -fopenmp -DPARALLEL=1 -O3 -Wno-unused
-EXECUTABLE = FLUID_3D
-
-SOURCES = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp
-OBJECTS = $(SOURCES:.cpp=.o)
-
-all: $(SOURCES) $(EXECUTABLE)
-
-$(EXECUTABLE): $(OBJECTS)
- $(CC) $(OBJECTS) $(LDFLAGS) -o $@
-
-.cpp.o:
- $(CC) $(CFLAGS) $< -o $@
-
-SPHERE.o: SPHERE.h
-FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp
-FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp
-main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp
-
-clean:
- rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
diff --git a/intern/smoke/intern/Makefile.mac b/intern/smoke/intern/Makefile.mac
deleted file mode 100644
index d0b7bd38c85..00000000000
--- a/intern/smoke/intern/Makefile.mac
+++ /dev/null
@@ -1,35 +0,0 @@
-CC = g++
-
-# uncomment the other two OPENMP_... lines, if your gcc supports OpenMP
-#OPENMP_FLAGS = -fopenmp -DPARALLEL=1 -I/opt/gcc-4.3/usr/local/include
-#OPENMPLD_FLAGS = -fopenmp -lgomp -I/opt/gcc-4.3/usr/local/lib
-OPENMP_FLAGS =
-OPENMPLD_FLAGS =
-
-# assumes MacPorts libpng installation
-PNG_INCLUDE = -I/opt/local/include
-PNG_LIBS = -I/opt/local/lib
-
-LDFLAGS = $(PNG_LIBS)-lz -lpng $(OPENMPLD_FLAGS)
-CFLAGS = -c -Wall -I./ $(PNG_INCLUDE) $(OPENMP_FLAGS) -O3 -Wno-unused
-EXECUTABLE = FLUID_3D
-
-SOURCES = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp
-OBJECTS = $(SOURCES:.cpp=.o)
-
-all: $(SOURCES) $(EXECUTABLE)
-
-$(EXECUTABLE): $(OBJECTS)
- $(CC) $(OBJECTS) $(LDFLAGS) -o $@
-
-.cpp.o:
- $(CC) $(CFLAGS) $< -o $@
-
-SPHERE.o: SPHERE.h
-FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp
-FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp
-main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp
-
-clean:
- rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
-
diff --git a/intern/smoke/intern/OBSTACLE.h b/intern/smoke/intern/OBSTACLE.h
deleted file mode 100644
index a23b484e7c1..00000000000
--- a/intern/smoke/intern/OBSTACLE.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// OBSTACLE.h: interface for the OBSTACLE class.
-//
-//////////////////////////////////////////////////////////////////////
-
-#ifndef OBSTACLE_H
-#define OBSTACLE_H
-
-enum OBSTACLE_FLAGS {
- EMPTY = 0,
- /* 1 is used to flag an object cell */
- MARCHED = 2,
- RETIRED = 4,
- ANIMATED = 8,
-};
-
-class OBSTACLE
-{
-public:
- OBSTACLE() {};
- virtual ~OBSTACLE() {};
-
- virtual bool inside(float x, float y, float z) = 0;
-};
-
-#endif
diff --git a/intern/smoke/intern/SPHERE.cpp b/intern/smoke/intern/SPHERE.cpp
deleted file mode 100644
index 914ed5666c3..00000000000
--- a/intern/smoke/intern/SPHERE.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// SPHERE.cpp: implementation of the SPHERE class.
-//
-//////////////////////////////////////////////////////////////////////
-
-#include "SPHERE.h"
-
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
-SPHERE::SPHERE(float x, float y, float z, float radius) :
- _radius(radius)
-{
- _center[0] = x;
- _center[1] = y;
- _center[2] = z;
-}
-
-SPHERE::~SPHERE()
-{
-
-}
-
-bool SPHERE::inside(float x, float y, float z)
-{
- float translate[] = {x - _center[0], y - _center[1], z - _center[2]};
- float magnitude = translate[0] * translate[0] +
- translate[1] * translate[1] +
- translate[2] * translate[2];
-
- return (magnitude < _radius * _radius) ? true : false;
-}
diff --git a/intern/smoke/intern/SPHERE.h b/intern/smoke/intern/SPHERE.h
deleted file mode 100644
index 6fdc93a5ee9..00000000000
--- a/intern/smoke/intern/SPHERE.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// SPHERE.h: interface for the SPHERE class.
-//
-//////////////////////////////////////////////////////////////////////
-
-#ifndef SPHERE_H
-#define SPHERE_H
-
-#include "OBSTACLE.h"
-
-class SPHERE : public OBSTACLE
-{
-public:
- SPHERE(float x, float y, float z, float radius);
- virtual ~SPHERE();
-
- bool inside(float x, float y, float z);
-
-private:
- float _center[3];
- float _radius;
-};
-
-#endif
diff --git a/intern/smoke/intern/VEC3.h b/intern/smoke/intern/VEC3.h
deleted file mode 100644
index 3672da74196..00000000000
--- a/intern/smoke/intern/VEC3.h
+++ /dev/null
@@ -1,991 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/******************************************************************************
- * Copyright 2007 Nils Thuerey
- * Basic vector class
- *****************************************************************************/
-#ifndef BASICVECTOR_H
-#define BASICVECTOR_H
-
-#include <math.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <iostream>
-#include <sstream>
-
-// use which fp-precision? 1=float, 2=double
-#ifndef FLOATINGPOINT_PRECISION
-#if DDF_DEBUG==1
-#define FLOATINGPOINT_PRECISION 2
-#else // DDF_DEBUG==1
-#define FLOATINGPOINT_PRECISION 1
-#endif // DDF_DEBUG==1
-#endif
-
-// VECTOR_EPSILON is the minimal vector length
-// In order to be able to discriminate floating point values near zero, and
-// to be sure not to fail a comparison because of roundoff errors, use this
-// value as a threshold.
-
-#if FLOATINGPOINT_PRECISION==1
-typedef float Real;
-#define FP_REAL_MAX __FLT_MAX__
-#define VECTOR_EPSILON (1e-5f)
-#else
-typedef double Real;
-#define FP_REAL_MAX __DBL_MAX__
-#define VECTOR_EPSILON (1e-10)
-#endif
-
-
-// hardcoded limits for now...
-// for e.g. MSVC compiler...
-// some of these defines can be needed
-// for linux systems as well (e.g. FLT_MAX)
-#ifndef __FLT_MAX__
-# ifdef FLT_MAX // try to use it instead
-# define __FLT_MAX__ FLT_MAX
-# else // FLT_MAX
-# define __FLT_MAX__ 3.402823466e+38f
-# endif // FLT_MAX
-#endif // __FLT_MAX__
-#ifndef __DBL_MAX__
-# ifdef DBL_MAX // try to use it instead
-# define __DBL_MAX__ DBL_MAX
-# else // DBL_MAX
-# define __DBL_MAX__ 1.7976931348623158e+308
-# endif // DBL_MAX
-#endif // __DBL_MAX__
-
-#ifndef FLT_MAX
-#define FLT_MAX __FLT_MAX__
-#endif
-
-#ifndef DBL_MAX
-#define DBL_MAX __DBL_MAX__
-#endif
-
-#ifndef M_PI
-# define M_PI 3.1415926536
-# define M_E 2.7182818284
-#endif
-
-
-
-namespace BasicVector {
-
-
-// basic inlined vector class
-template<class Scalar>
-class Vector3Dim
-{
-public:
- // Constructor
- inline Vector3Dim();
- // Copy-Constructor
- inline Vector3Dim(const Vector3Dim<Scalar> &v );
- inline Vector3Dim(const float *);
- inline Vector3Dim(const double *);
- // construct a vector from one Scalar
- inline Vector3Dim(Scalar);
- // construct a vector from three Scalars
- inline Vector3Dim(Scalar, Scalar, Scalar);
-
- // get address of array for OpenGL
- Scalar *getAddress() { return value; }
-
- // Assignment operator
- inline const Vector3Dim<Scalar>& operator= (const Vector3Dim<Scalar>& v);
- // Assignment operator
- inline const Vector3Dim<Scalar>& operator= (Scalar s);
- // Assign and add operator
- inline const Vector3Dim<Scalar>& operator+= (const Vector3Dim<Scalar>& v);
- // Assign and add operator
- inline const Vector3Dim<Scalar>& operator+= (Scalar s);
- // Assign and sub operator
- inline const Vector3Dim<Scalar>& operator-= (const Vector3Dim<Scalar>& v);
- // Assign and sub operator
- inline const Vector3Dim<Scalar>& operator-= (Scalar s);
- // Assign and mult operator
- inline const Vector3Dim<Scalar>& operator*= (const Vector3Dim<Scalar>& v);
- // Assign and mult operator
- inline const Vector3Dim<Scalar>& operator*= (Scalar s);
- // Assign and div operator
- inline const Vector3Dim<Scalar>& operator/= (const Vector3Dim<Scalar>& v);
- // Assign and div operator
- inline const Vector3Dim<Scalar>& operator/= (Scalar s);
-
-
- // unary operator
- inline Vector3Dim<Scalar> operator- () const;
-
- // binary operator add
- inline Vector3Dim<Scalar> operator+ (const Vector3Dim<Scalar>&) const;
- // binary operator add
- inline Vector3Dim<Scalar> operator+ (Scalar) const;
- // binary operator sub
- inline Vector3Dim<Scalar> operator- (const Vector3Dim<Scalar>&) const;
- // binary operator sub
- inline Vector3Dim<Scalar> operator- (Scalar) const;
- // binary operator mult
- inline Vector3Dim<Scalar> operator* (const Vector3Dim<Scalar>&) const;
- // binary operator mult
- inline Vector3Dim<Scalar> operator* (Scalar) const;
- // binary operator div
- inline Vector3Dim<Scalar> operator/ (const Vector3Dim<Scalar>&) const;
- // binary operator div
- inline Vector3Dim<Scalar> operator/ (Scalar) const;
-
- // Projection normal to a vector
- inline Vector3Dim<Scalar> getOrthogonalntlVector3Dim() const;
- // Project into a plane
- inline const Vector3Dim<Scalar>& projectNormalTo(const Vector3Dim<Scalar> &v);
-
- // minimize
- inline const Vector3Dim<Scalar> &minimize(const Vector3Dim<Scalar> &);
- // maximize
- inline const Vector3Dim<Scalar> &maximize(const Vector3Dim<Scalar> &);
-
- // access operator
- inline Scalar& operator[](unsigned int i);
- // access operator
- inline const Scalar& operator[](unsigned int i) const;
-
- //! actual values
- union {
- struct {
- Scalar value[3];
- };
- struct {
- Scalar x;
- Scalar y;
- Scalar z;
- };
- struct {
- Scalar X;
- Scalar Y;
- Scalar Z;
- };
- };
-protected:
-
-};
-
-
-
-
-
-//------------------------------------------------------------------------------
-// VECTOR inline FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Constructor.
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim( void )
-{
- value[0] = value[1] = value[2] = 0;
-}
-
-
-
-/*************************************************************************
- Copy-Constructor.
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim( const Vector3Dim<Scalar> &v )
-{
- value[0] = v.value[0];
- value[1] = v.value[1];
- value[2] = v.value[2];
-}
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim( const float *fvalue)
-{
- value[0] = (Scalar)fvalue[0];
- value[1] = (Scalar)fvalue[1];
- value[2] = (Scalar)fvalue[2];
-}
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim( const double *fvalue)
-{
- value[0] = (Scalar)fvalue[0];
- value[1] = (Scalar)fvalue[1];
- value[2] = (Scalar)fvalue[2];
-}
-
-
-
-/*************************************************************************
- Constructor for a vector from a single Scalar. All components of
- the vector get the same value.
- \param s The value to set
- \return The new vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim(Scalar s )
-{
- value[0]= s;
- value[1]= s;
- value[2]= s;
-}
-
-
-/*************************************************************************
- Constructor for a vector from three Scalars.
- \param s1 The value for the first vector component
- \param s2 The value for the second vector component
- \param s3 The value for the third vector component
- \return The new vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>::Vector3Dim(Scalar s1, Scalar s2, Scalar s3)
-{
- value[0]= s1;
- value[1]= s2;
- value[2]= s3;
-}
-
-
-
-/*************************************************************************
- Copy a Vector3Dim componentwise.
- \param v vector with values to be copied
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator=( const Vector3Dim<Scalar> &v )
-{
- value[0] = v.value[0];
- value[1] = v.value[1];
- value[2] = v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Copy a Scalar to each component.
- \param s The value to copy
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator=(Scalar s)
-{
- value[0] = s;
- value[1] = s;
- value[2] = s;
- return *this;
-}
-
-
-/*************************************************************************
- Add another Vector3Dim componentwise.
- \param v vector with values to be added
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator+=( const Vector3Dim<Scalar> &v )
-{
- value[0] += v.value[0];
- value[1] += v.value[1];
- value[2] += v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Add a Scalar value to each component.
- \param s Value to add
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator+=(Scalar s)
-{
- value[0] += s;
- value[1] += s;
- value[2] += s;
- return *this;
-}
-
-
-/*************************************************************************
- Subtract another vector componentwise.
- \param v vector of values to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator-=( const Vector3Dim<Scalar> &v )
-{
- value[0] -= v.value[0];
- value[1] -= v.value[1];
- value[2] -= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Subtract a Scalar value from each component.
- \param s Value to subtract
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator-=(Scalar s)
-{
- value[0]-= s;
- value[1]-= s;
- value[2]-= s;
- return *this;
-}
-
-
-/*************************************************************************
- Multiply with another vector componentwise.
- \param v vector of values to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator*=( const Vector3Dim<Scalar> &v )
-{
- value[0] *= v.value[0];
- value[1] *= v.value[1];
- value[2] *= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Multiply each component with a Scalar value.
- \param s Value to multiply with
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator*=(Scalar s)
-{
- value[0] *= s;
- value[1] *= s;
- value[2] *= s;
- return *this;
-}
-
-
-/*************************************************************************
- Divide by another Vector3Dim componentwise.
- \param v vector of values to divide by
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator/=( const Vector3Dim<Scalar> &v )
-{
- value[0] /= v.value[0];
- value[1] /= v.value[1];
- value[2] /= v.value[2];
- return *this;
-}
-
-
-/*************************************************************************
- Divide each component by a Scalar value.
- \param s Value to divide by
- \return Reference to self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::operator/=(Scalar s)
-{
- value[0] /= s;
- value[1] /= s;
- value[2] /= s;
- return *this;
-}
-
-
-//------------------------------------------------------------------------------
-// unary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build componentwise the negative this vector.
- \return The new (negative) vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator-() const
-{
- return Vector3Dim<Scalar>(-value[0], -value[1], -value[2]);
-}
-
-
-
-//------------------------------------------------------------------------------
-// binary operators
-//------------------------------------------------------------------------------
-
-
-/*************************************************************************
- Build a vector with another vector added componentwise.
- \param v The second vector to add
- \return The sum vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator+( const Vector3Dim<Scalar> &v ) const
-{
- return Vector3Dim<Scalar>(value[0]+v.value[0],
- value[1]+v.value[1],
- value[2]+v.value[2]);
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value added to each component.
- \param s The Scalar value to add
- \return The sum vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator+(Scalar s) const
-{
- return Vector3Dim<Scalar>(value[0]+s,
- value[1]+s,
- value[2]+s);
-}
-
-
-/*************************************************************************
- Build a vector with another vector subtracted componentwise.
- \param v The second vector to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator-( const Vector3Dim<Scalar> &v ) const
-{
- return Vector3Dim<Scalar>(value[0]-v.value[0],
- value[1]-v.value[1],
- value[2]-v.value[2]);
-}
-
-
-/*************************************************************************
- Build a vector with a Scalar value subtracted componentwise.
- \param s The Scalar value to subtract
- \return The difference vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator-(Scalar s ) const
-{
- return Vector3Dim<Scalar>(value[0]-s,
- value[1]-s,
- value[2]-s);
-}
-
-
-
-/*************************************************************************
- Build a vector with another vector multiplied by componentwise.
- \param v The second vector to muliply with
- \return The product vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator*( const Vector3Dim<Scalar>& v) const
-{
- return Vector3Dim<Scalar>(value[0]*v.value[0],
- value[1]*v.value[1],
- value[2]*v.value[2]);
-}
-
-
-/*************************************************************************
- Build a Vector3Dim with a Scalar value multiplied to each component.
- \param s The Scalar value to multiply with
- \return The product vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator*(Scalar s) const
-{
- return Vector3Dim<Scalar>(value[0]*s, value[1]*s, value[2]*s);
-}
-
-
-/*************************************************************************
- Build a vector divided componentwise by another vector.
- \param v The second vector to divide by
- \return The ratio vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator/(const Vector3Dim<Scalar>& v) const
-{
- return Vector3Dim<Scalar>(value[0]/v.value[0],
- value[1]/v.value[1],
- value[2]/v.value[2]);
-}
-
-
-
-/*************************************************************************
- Build a vector divided componentwise by a Scalar value.
- \param s The Scalar value to divide by
- \return The ratio vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar>
-Vector3Dim<Scalar>::operator/(Scalar s) const
-{
- return Vector3Dim<Scalar>(value[0]/s,
- value[1]/s,
- value[2]/s);
-}
-
-
-
-
-
-/*************************************************************************
- Get a particular component of the vector.
- \param i Number of Scalar to get
- \return Reference to the component
- */
-template<class Scalar>
-inline Scalar&
-Vector3Dim<Scalar>::operator[]( unsigned int i )
-{
- return value[i];
-}
-
-
-/*************************************************************************
- Get a particular component of a constant vector.
- \param i Number of Scalar to get
- \return Reference to the component
- */
-template<class Scalar>
-inline const Scalar&
-Vector3Dim<Scalar>::operator[]( unsigned int i ) const
-{
- return value[i];
-}
-
-
-
-//------------------------------------------------------------------------------
-// BLITZ compatibility functions
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Compute the scalar product with another vector.
- \param v The second vector to work with
- \return The value of the scalar product
- */
-template<class Scalar>
-inline Scalar dot(const Vector3Dim<Scalar> &t, const Vector3Dim<Scalar> &v )
-{
- //return t.value[0]*v.value[0] + t.value[1]*v.value[1] + t.value[2]*v.value[2];
- return ((t[0]*v[0]) + (t[1]*v[1]) + (t[2]*v[2]));
-}
-
-
-/*************************************************************************
- Calculate the cross product of this and another vector
- */
-template<class Scalar>
-inline Vector3Dim<Scalar> cross(const Vector3Dim<Scalar> &t, const Vector3Dim<Scalar> &v)
-{
- Vector3Dim<Scalar> cp(
- ((t[1]*v[2]) - (t[2]*v[1])),
- ((t[2]*v[0]) - (t[0]*v[2])),
- ((t[0]*v[1]) - (t[1]*v[0])) );
- return cp;
-}
-
-
-
-
-/*************************************************************************
- Compute a vector that is orthonormal to self. Nothing else can be assumed
- for the direction of the new vector.
- \return The orthonormal vector
- */
-template<class Scalar>
-Vector3Dim<Scalar>
-Vector3Dim<Scalar>::getOrthogonalntlVector3Dim() const
-{
- // Determine the component with max. absolute value
- int max= (fabs(value[0]) > fabs(value[1])) ? 0 : 1;
- max= (fabs(value[max]) > fabs(value[2])) ? max : 2;
-
- /*************************************************************************
- Choose another axis than the one with max. component and project
- orthogonal to self
- */
- Vector3Dim<Scalar> vec(0.0);
- vec[(max+1)%3]= 1;
- vec.normalize();
- vec.projectNormalTo(this->getNormalized());
- return vec;
-}
-
-
-/*************************************************************************
- Projects the vector into a plane normal to the given vector, which must
- have unit length. Self is modified.
- \param v The plane normal
- \return The projected vector
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar>&
-Vector3Dim<Scalar>::projectNormalTo(const Vector3Dim<Scalar> &v)
-{
- Scalar sprod = dot(*this,v);
- value[0]= value[0] - v.value[0] * sprod;
- value[1]= value[1] - v.value[1] * sprod;
- value[2]= value[2] - v.value[2] * sprod;
- return *this;
-}
-
-
-
-//------------------------------------------------------------------------------
-// Other helper functions
-//------------------------------------------------------------------------------
-
-
-
-/*************************************************************************
- Minimize the vector, i.e. set each entry of the vector to the minimum
- of both values.
- \param pnt The second vector to compare with
- \return Reference to the modified self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar> &
-Vector3Dim<Scalar>::minimize(const Vector3Dim<Scalar> &pnt)
-{
- for (unsigned int i = 0; i < 3; i++)
- value[i] = MIN(value[i],pnt[i]);
- return *this;
-}
-
-
-
-/*************************************************************************
- Maximize the vector, i.e. set each entry of the vector to the maximum
- of both values.
- \param pnt The second vector to compare with
- \return Reference to the modified self
- */
-template<class Scalar>
-inline const Vector3Dim<Scalar> &
-Vector3Dim<Scalar>::maximize(const Vector3Dim<Scalar> &pnt)
-{
- for (unsigned int i = 0; i < 3; i++)
- value[i] = MAX(value[i],pnt[i]);
- return *this;
-}
-
-
-
-
-
-
-/************************************************************************/
-// HELPER FUNCTIONS, independent of implementation
-/************************************************************************/
-
-#define VECTOR_TYPE Vector3Dim<Scalar>
-
-
-/*************************************************************************
- Compute the length (norm) of the vector.
- \return The value of the norm
- */
-template<class Scalar>
-inline Scalar norm( const VECTOR_TYPE &v)
-{
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- return (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) ? 1. : sqrt(l);
-}
-
-// for e.g. min max operator
-inline Real normHelper(const Vector3Dim<Real> &v) {
- return norm(v);
-}
-inline Real normHelper(const Real &v) {
- return (0.0f < v) ? v : -v ;
-}
-inline Real normHelper(const int &v) {
- return (0 < v) ? (Real)(v) : (Real)(-v) ;
-}
-
-
-/*************************************************************************
- Same as getNorm but doesnt sqrt
- */
-template<class Scalar>
-inline Scalar normNoSqrt( const VECTOR_TYPE &v)
-{
- return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
-}
-
-
-/*************************************************************************
- Compute a normalized vector based on this vector.
- \return The new normalized vector
- */
-template<class Scalar>
-inline VECTOR_TYPE getNormalized( const VECTOR_TYPE &v)
-{
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON)
- return v; /* normalized "enough"... */
- else if (l > VECTOR_EPSILON*VECTOR_EPSILON)
- {
- Scalar fac = 1./sqrt(l);
- return VECTOR_TYPE(v[0]*fac, v[1]*fac, v[2]*fac);
- }
- else
- return VECTOR_TYPE((Scalar)0);
-}
-
-
-/*************************************************************************
- Compute the norm of the vector and normalize it.
- \return The value of the norm
- */
-template<class Scalar>
-inline Scalar normalize( VECTOR_TYPE &v)
-{
- Scalar norm;
- Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) {
- norm = 1.;
- } else if (l > VECTOR_EPSILON*VECTOR_EPSILON) {
- norm = sqrt(l);
- Scalar fac = 1./norm;
- v[0] *= fac;
- v[1] *= fac;
- v[2] *= fac;
- } else {
- v[0]= v[1]= v[2]= 0;
- norm = 0.;
- }
- return (Scalar)norm;
-}
-
-
-/*************************************************************************
- Compute a vector, that is self (as an incoming
- vector) reflected at a surface with a distinct normal vector. Note
- that the normal is reversed, if the scalar product with it is positive.
- \param n The surface normal
- \return The new reflected vector
- */
-template<class Scalar>
-inline VECTOR_TYPE reflectVector(const VECTOR_TYPE &t, const VECTOR_TYPE &n)
-{
- VECTOR_TYPE nn= (dot(t, n) > 0.0) ? (n*-1.0) : n;
- return ( t - nn * (2.0 * dot(nn, t)) );
-}
-
-
-
-/*************************************************************************
- * My own refraction calculation
- * Taken from Glassner's book, section 5.2 (Heckberts method)
- */
-template<class Scalar>
-inline VECTOR_TYPE refractVector(const VECTOR_TYPE &t, const VECTOR_TYPE &normal, Scalar nt, Scalar nair, int &refRefl)
-{
- Scalar eta = nair / nt;
- Scalar n = -dot(t, normal);
- Scalar tt = 1.0 + eta*eta* (n*n-1.0);
- if(tt<0.0) {
- // we have total reflection!
- refRefl = 1;
- } else {
- // normal reflection
- tt = eta*n - sqrt(tt);
- return( t*eta + normal*tt );
- }
- return t;
-}
-
-
-/*************************************************************************
- Test two ntlVector3Dims for equality based on the equality of their
- values within a small threshold.
- \param c The second vector to compare
- \return TRUE if both are equal
- \sa getEpsilon()
- */
-template<class Scalar>
-inline bool equal(const VECTOR_TYPE &v, const VECTOR_TYPE &c)
-{
- return (ABS(v[0]-c[0]) +
- ABS(v[1]-c[1]) +
- ABS(v[2]-c[2]) < VECTOR_EPSILON);
-}
-
-
-/*************************************************************************
- * Assume this vector is an RGB color, and convert it to HSV
- */
-template<class Scalar>
-inline void rgbToHsv( VECTOR_TYPE &V )
-{
- Scalar h=0,s=0,v=0;
- Scalar maxrgb, minrgb, delta;
- // convert to hsv...
- maxrgb = V[0];
- int maxindex = 1;
- if(V[2] > maxrgb){ maxrgb = V[2]; maxindex = 2; }
- if(V[1] > maxrgb){ maxrgb = V[1]; maxindex = 3; }
- minrgb = V[0];
- if(V[2] < minrgb) minrgb = V[2];
- if(V[1] < minrgb) minrgb = V[1];
-
- v = maxrgb;
- delta = maxrgb-minrgb;
-
- if(maxrgb > 0) s = delta/maxrgb;
- else s = 0;
-
- h = 0;
- if(s > 0) {
- if(maxindex == 1) {
- h = ((V[1]-V[2])/delta) + 0.0; }
- if(maxindex == 2) {
- h = ((V[2]-V[0])/delta) + 2.0; }
- if(maxindex == 3) {
- h = ((V[0]-V[1])/delta) + 4.0; }
- h *= 60.0;
- if(h < 0.0) h += 360.0;
- }
-
- V[0] = h;
- V[1] = s;
- V[2] = v;
-}
-
-/*************************************************************************
- * Assume this vector is HSV and convert to RGB
- */
-template<class Scalar>
-inline void hsvToRgb( VECTOR_TYPE &V )
-{
- Scalar h = V[0], s = V[1], v = V[2];
- Scalar r=0,g=0,b=0;
- Scalar p,q,t, fracth;
- int floorh;
- // ...and back to rgb
- if(s == 0) {
- r = g = b = v; }
- else {
- h /= 60.0;
- floorh = (int)h;
- fracth = h - floorh;
- p = v * (1.0 - s);
- q = v * (1.0 - (s * fracth));
- t = v * (1.0 - (s * (1.0 - fracth)));
- switch (floorh) {
- case 0: r = v; g = t; b = p; break;
- case 1: r = q; g = v; b = p; break;
- case 2: r = p; g = v; b = t; break;
- case 3: r = p; g = q; b = v; break;
- case 4: r = t; g = p; b = v; break;
- case 5: r = v; g = p; b = q; break;
- }
- }
-
- V[0] = r;
- V[1] = g;
- V[2] = b;
-}
-
-//------------------------------------------------------------------------------
-// STREAM FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-
-//! global string for formatting vector output in utilities.cpp
-//extern const char *globVecFormatStr;
-#if 0
-static const char *globVecFormatStr = "[%6.4f,%6.4f,%6.4f]";
-#endif
-
-/*************************************************************************
- Outputs the object in human readable form using the format
- [x,y,z]
- */
-template<class Scalar>
-std::ostream&
-operator<<( std::ostream& os, const BasicVector::Vector3Dim<Scalar>& i )
-{
-#if 0
- char buf[256];
-# if _WIN32
- sprintf(buf,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]);
-# else
- snprintf(buf,256,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]);
-# endif
- os << std::string(buf);
-#else
- (void)i; /* Ignored. */
-#endif
- return os;
-}
-
-
-/*************************************************************************
- Reads the contents of the object from a stream using the same format
- as the output operator.
- */
-template<class Scalar>
-std::istream&
-operator>>( std::istream& is, BasicVector::Vector3Dim<Scalar>& i )
-{
- char c;
- char dummy[3];
- is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c;
- return is;
-}
-
-
-/**************************************************************************/
-// typedefs!
-/**************************************************************************/
-
-/* get minimal vector length value that can be discriminated. */
-inline Real getVecEpsilon() { return (Real)VECTOR_EPSILON; }
-
-// a 3D integer vector
-typedef Vector3Dim<int> Vec3Int;
-
-// a 3D vector
-typedef Vector3Dim<Real> Vec3;
-
-
-}; // namespace
-
-
-#endif /* BASICVECTOR_H */
diff --git a/intern/smoke/intern/WAVELET_NOISE.h b/intern/smoke/intern/WAVELET_NOISE.h
deleted file mode 100644
index 13ffe1e9697..00000000000
--- a/intern/smoke/intern/WAVELET_NOISE.h
+++ /dev/null
@@ -1,519 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-//////////////////////////////////////////////////////////////////////////////////////////
-// Wavelet noise functions
-//
-// This code is based on the C code provided in the appendices of:
-//
-// @article{1073264,
-// author = {Robert L. Cook and Tony DeRose},
-// title = {Wavelet noise},
-// journal = {ACM Trans. Graph.},
-// volume = {24},
-// number = {3},
-// year = {2005},
-// issn = {0730-0301},
-// pages = {803--811},
-// doi = {http://doi.acm.org/10.1145/1073204.1073264},
-// publisher = {ACM},
-// address = {New York, NY, USA},
-// }
-//
-//////////////////////////////////////////////////////////////////////////////////////////
-
-#ifndef WAVELET_NOISE_H
-#define WAVELET_NOISE_H
-
-#include <MERSENNETWISTER.h>
-
-#include <string.h>
-
-#ifdef WIN32
-#include <float.h>
-#define isnan _isnan
-#endif
-
-// Tile file header, update revision upon any change done to the noise generator
-static const char tilefile_headerstring[] = "Noise Tile File rev. ";
-static const char tilefile_revision[] = "001";
-
-#define NOISE_TILE_SIZE 128
-static const int noiseTileSize = NOISE_TILE_SIZE;
-
-// warning - noiseTileSize has to be 128^3!
-#define modFast128(x) ((x) & 127)
-#define modFast64(x) ((x) & 63)
-#define DOWNCOEFFS 0.000334f,-0.001528f, 0.000410f, 0.003545f,-0.000938f,-0.008233f, 0.002172f, 0.019120f, \
- -0.005040f,-0.044412f, 0.011655f, 0.103311f,-0.025936f,-0.243780f, 0.033979f, 0.655340f, \
- 0.655340f, 0.033979f,-0.243780f,-0.025936f, 0.103311f, 0.011655f,-0.044412f,-0.005040f, \
- 0.019120f, 0.002172f,-0.008233f,-0.000938f, 0.003546f, 0.000410f,-0.001528f, 0.000334f
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Wavelet downsampling -- periodic boundary conditions
-//////////////////////////////////////////////////////////////////////////////////////////
-static void downsampleX(float *from, float *to, int n){
- // if these values are not local incorrect results are generated
- float downCoeffs[32] = { DOWNCOEFFS };
- const float *a = &downCoeffs[16];
- for (int i = 0; i < n / 2; i++) {
- to[i] = 0;
- for (int k = 2 * i - 16; k < 2 * i + 16; k++)
- to[i] += a[k - 2 * i] * from[modFast128(k)];
- }
-}
-static void downsampleY(float *from, float *to, int n){
- // if these values are not local incorrect results are generated
- float downCoeffs[32] = { DOWNCOEFFS };
- const float *a = &downCoeffs[16];
- for (int i = 0; i < n / 2; i++) {
- to[i * n] = 0;
- for (int k = 2 * i - 16; k < 2 * i + 16; k++)
- to[i * n] += a[k - 2 * i] * from[modFast128(k) * n];
- }
-}
-static void downsampleZ(float *from, float *to, int n){
- // if these values are not local incorrect results are generated
- float downCoeffs[32] = { DOWNCOEFFS };
- const float *a = &downCoeffs[16];
- for (int i = 0; i < n / 2; i++) {
- to[i * n * n] = 0;
- for (int k = 2 * i - 16; k < 2 * i + 16; k++)
- to[i * n * n] += a[k - 2 * i] * from[modFast128(k) * n * n];
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Wavelet downsampling -- Neumann boundary conditions
-//////////////////////////////////////////////////////////////////////////////////////////
-static void downsampleNeumann(const float *from, float *to, int n, int stride)
-{
- // if these values are not local incorrect results are generated
- float downCoeffs[32] = { DOWNCOEFFS };
- const float *const aCoCenter= &downCoeffs[16];
- for (int i = 0; i <= n / 2; i++) {
- to[i * stride] = 0;
- for (int k = 2 * i - 16; k < 2 * i + 16; k++) {
- // handle boundary
- float fromval;
- if (k < 0) {
- fromval = from[0];
- } else if(k > n - 1) {
- fromval = from[(n - 1) * stride];
- } else {
- fromval = from[k * stride];
- }
- to[i * stride] += aCoCenter[k - 2 * i] * fromval;
- }
- }
-}
-static void downsampleXNeumann(float* to, const float* from, int sx,int sy, int sz) {
- for (int iy = 0; iy < sy; iy++)
- for (int iz = 0; iz < sz; iz++) {
- const int i = iy * sx + iz*sx*sy;
- downsampleNeumann(&from[i], &to[i], sx, 1);
- }
-}
-static void downsampleYNeumann(float* to, const float* from, int sx,int sy, int sz) {
- for (int ix = 0; ix < sx; ix++)
- for (int iz = 0; iz < sz; iz++) {
- const int i = ix + iz*sx*sy;
- downsampleNeumann(&from[i], &to[i], sy, sx);
- }
-}
-static void downsampleZNeumann(float* to, const float* from, int sx,int sy, int sz) {
- for (int ix = 0; ix < sx; ix++)
- for (int iy = 0; iy < sy; iy++) {
- const int i = ix + iy*sx;
- downsampleNeumann(&from[i], &to[i], sz, sx*sy);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Wavelet upsampling - periodic boundary conditions
-//////////////////////////////////////////////////////////////////////////////////////////
-static float _upCoeffs[4] = {0.25f, 0.75f, 0.75f, 0.25f};
-static void upsampleX(float *from, float *to, int n) {
- const float *p = &_upCoeffs[2];
-
- for (int i = 0; i < n; i++) {
- to[i] = 0;
- for (int k = i / 2; k <= i / 2 + 1; k++)
- to[i] += p[i - 2 * k] * from[modFast64(k)];
- }
-}
-static void upsampleY(float *from, float *to, int n) {
- const float *p = &_upCoeffs[2];
-
- for (int i = 0; i < n; i++) {
- to[i * n] = 0;
- for (int k = i / 2; k <= i / 2 + 1; k++)
- to[i * n] += p[i - 2 * k] * from[modFast64(k) * n];
- }
-}
-static void upsampleZ(float *from, float *to, int n) {
- const float *p = &_upCoeffs[2];
-
- for (int i = 0; i < n; i++) {
- to[i * n * n] = 0;
- for (int k = i / 2; k <= i / 2 + 1; k++)
- to[i * n * n] += p[i - 2 * k] * from[modFast64(k) * n * n];
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Wavelet upsampling - Neumann boundary conditions
-//////////////////////////////////////////////////////////////////////////////////////////
-static void upsampleNeumann(const float *from, float *to, int n, int stride) {
- static const float *const pCoCenter = &_upCoeffs[2];
- for (int i = 0; i < n; i++) {
- to[i * stride] = 0;
- for (int k = i / 2; k <= i / 2 + 1; k++) {
- float fromval;
- if(k>n/2) {
- fromval = from[(n/2) * stride];
- } else {
- fromval = from[k * stride];
- }
- to[i * stride] += pCoCenter[i - 2 * k] * fromval;
- }
- }
-}
-static void upsampleXNeumann(float* to, const float* from, int sx, int sy, int sz) {
- for (int iy = 0; iy < sy; iy++)
- for (int iz = 0; iz < sz; iz++) {
- const int i = iy * sx + iz*sx*sy;
- upsampleNeumann(&from[i], &to[i], sx, 1);
- }
-}
-static void upsampleYNeumann(float* to, const float* from, int sx, int sy, int sz) {
- for (int ix = 0; ix < sx; ix++)
- for (int iz = 0; iz < sz; iz++) {
- const int i = ix + iz*sx*sy;
- upsampleNeumann(&from[i], &to[i], sy, sx);
- }
-}
-static void upsampleZNeumann(float* to, const float* from, int sx, int sy, int sz) {
- for (int ix = 0; ix < sx; ix++)
- for (int iy = 0; iy < sy; iy++) {
- const int i = ix + iy*sx;
- upsampleNeumann(&from[i], &to[i], sz, sx*sy);
- }
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// load in an existing noise tile
-//////////////////////////////////////////////////////////////////////////////////////////
-static bool loadTile(float* const noiseTileData, std::string filename)
-{
- FILE* file;
- char headerbuffer[64];
- size_t headerlen;
- size_t bread;
- int endiantest = 1;
- char endianness;
-
- file = fopen(filename.c_str(), "rb");
-
- if (file == NULL) {
- printf("loadTile: No noise tile '%s' found.\n", filename.c_str());
- return false;
- }
-
- //Check header
- headerlen = strlen(tilefile_headerstring) + strlen(tilefile_revision) + 2;
- bread = fread((void*)headerbuffer, 1, headerlen, file);
- if (*((unsigned char*)&endiantest) == 1)
- endianness = 'L';
- else
- endianness = 'B';
- if ((bread != headerlen)
- || (strncmp(headerbuffer, tilefile_headerstring, strlen(tilefile_headerstring)))
- || (strncmp(headerbuffer+ strlen(tilefile_headerstring), tilefile_revision, strlen(tilefile_revision)))
- || (headerbuffer[headerlen-2] != endianness)
- || (headerbuffer[headerlen-1] != (char)((char)sizeof(long)+'0')))
- {
- printf("loadTile : Noise tile '%s' was generated on an incompatible platform.\n",filename.c_str());
- fclose(file);
- return false;
- }
-
- // dimensions
- size_t gridSize = noiseTileSize * noiseTileSize * noiseTileSize;
-
- // noiseTileData memory is managed by caller
- bread = fread((void*)noiseTileData, sizeof(float), gridSize, file);
- fclose(file);
- printf("Noise tile file '%s' loaded.\n", filename.c_str());
-
- if (bread != gridSize) {
- printf("loadTile: Noise tile '%s' is wrong size %d.\n", filename.c_str(), (int)bread);
- return false;
- }
-
- // check for invalid nan tile data that could be generated. bug is now
- // fixed, but invalid files may still hang around
- if (isnan(noiseTileData[0])) {
- printf("loadTile: Noise tile '%s' contains nan values.\n", filename.c_str());
- return false;
- }
-
- return true;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// write out an existing noise tile
-//////////////////////////////////////////////////////////////////////////////////////////
-static void saveTile(float* const noiseTileData, std::string filename)
-{
- FILE* file;
- file = fopen(filename.c_str(), "wb");
- int endiantest=1;
- char longsize;
-
- if (file == NULL) {
- printf("saveTile: Noise tile '%s' could not be saved.\n", filename.c_str());
- return;
- }
-
- //Write file header
- fwrite(tilefile_headerstring, strlen(tilefile_headerstring), 1, file);
- fwrite(tilefile_revision, strlen(tilefile_revision), 1, file);
- //Endianness
- if (*((unsigned char*)&endiantest) == 1)
- fwrite("L", 1, 1, file); //Little endian
- else
- fwrite("B",1,1,file); //Big endian
- //32/64bit
- longsize = (char)sizeof(long)+'0';
- fwrite(&longsize, 1, 1, file);
-
-
- fwrite((void*)noiseTileData, sizeof(float), noiseTileSize * noiseTileSize * noiseTileSize, file);
- fclose(file);
-
- printf("saveTile: Noise tile file '%s' saved.\n", filename.c_str());
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// create a new noise tile if necessary
-//////////////////////////////////////////////////////////////////////////////////////////
-static void generateTile_WAVELET(float* const noiseTileData, std::string filename) {
- // if a tile already exists, just use that
- if (loadTile(noiseTileData, filename)) return;
-
- const int n = noiseTileSize;
- const int n3 = n*n*n;
- std::cout <<"Generating new 3d noise tile size="<<n<<"^3 \n";
- MTRand twister;
-
- float *temp13 = new float[n3];
- float *temp23 = new float[n3];
- float *noise3 = new float[n3];
-
- // initialize
- for (int i = 0; i < n3; i++) {
- temp13[i] = temp23[i] = noise3[i] = 0.;
- }
-
- // Step 1. Fill the tile with random numbers in the range -1 to 1.
- for (int i = 0; i < n3; i++)
- noise3[i] = twister.randNorm();
-
- // Steps 2 and 3. Downsample and upsample the tile
- for (int iy = 0; iy < n; iy++)
- for (int iz = 0; iz < n; iz++) {
- const int i = iy * n + iz*n*n;
- downsampleX(&noise3[i], &temp13[i], n);
- upsampleX (&temp13[i], &temp23[i], n);
- }
- for (int ix = 0; ix < n; ix++)
- for (int iz = 0; iz < n; iz++) {
- const int i = ix + iz*n*n;
- downsampleY(&temp23[i], &temp13[i], n);
- upsampleY (&temp13[i], &temp23[i], n);
- }
- for (int ix = 0; ix < n; ix++)
- for (int iy = 0; iy < n; iy++) {
- const int i = ix + iy*n;
- downsampleZ(&temp23[i], &temp13[i], n);
- upsampleZ (&temp13[i], &temp23[i], n);
- }
-
- // Step 4. Subtract out the coarse-scale contribution
- for (int i = 0; i < n3; i++)
- noise3[i] -= temp23[i];
-
- // Avoid even/odd variance difference by adding odd-offset version of noise to itself.
- int offset = n / 2;
- if (offset % 2 == 0) offset++;
-
- int icnt=0;
- for (int ix = 0; ix < n; ix++)
- for (int iy = 0; iy < n; iy++)
- for (int iz = 0; iz < n; iz++) {
- temp13[icnt] = noise3[modFast128(ix+offset) + modFast128(iy+offset)*n + modFast128(iz+offset)*n*n];
- icnt++;
- }
-
- for (int i = 0; i < n3; i++)
- noise3[i] += temp13[i];
-
- for (int i = 0; i < n3; i++)
- noiseTileData[i] = noise3[i];
-
- saveTile(noise3, filename);
- delete[] temp13;
- delete[] temp23;
- delete[] noise3;
- std::cout <<"Generating new 3d noise done\n";
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// x derivative of noise
-//////////////////////////////////////////////////////////////////////////////////////////
-static inline float WNoiseDx(Vec3 p, float* data) {
- int c[3], mid[3], n = noiseTileSize;
- float w[3][3], t, result = 0;
-
- mid[0] = (int)ceil(p[0] - 0.5f);
- t = mid[0] - (p[0] - 0.5f);
- w[0][0] = -t;
- w[0][2] = (1.f - t);
- w[0][1] = 2.0f * t - 1.0f;
-
- mid[1] = (int)ceil(p[1] - 0.5f);
- t = mid[1] - (p[1] - 0.5f);
- w[1][0] = t * t / 2;
- w[1][2] = (1 - t) * (1 - t) / 2;
- w[1][1] = 1 - w[1][0] - w[1][2];
-
- mid[2] = (int)ceil(p[2] - 0.5f);
- t = mid[2] - (p[2] - 0.5f);
- w[2][0] = t * t / 2;
- w[2][2] = (1 - t) * (1 - t)/2;
- w[2][1] = 1 - w[2][0] - w[2][2];
-
- // to optimize, explicitly unroll this loop
- for (int z = -1; z <=1; z++)
- for (int y = -1; y <=1; y++)
- for (int x = -1; x <=1; x++)
- {
- float weight = 1.0f;
- c[0] = modFast128(mid[0] + x);
- weight *= w[0][x+1];
- c[1] = modFast128(mid[1] + y);
- weight *= w[1][y+1];
- c[2] = modFast128(mid[2] + z);
- weight *= w[2][z+1];
- result += weight * data[c[2]*n*n+c[1]*n+c[0]];
- }
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// y derivative of noise
-//////////////////////////////////////////////////////////////////////////////////////////
-static inline float WNoiseDy(Vec3 p, float* data) {
- int c[3], mid[3], n=noiseTileSize;
- float w[3][3], t, result =0;
-
- mid[0] = (int)ceil(p[0] - 0.5f);
- t = mid[0]-(p[0] - 0.5f);
- w[0][0] = t * t / 2;
- w[0][2] = (1 - t) * (1 - t) / 2;
- w[0][1] = 1 - w[0][0] - w[0][2];
-
- mid[1] = (int)ceil(p[1] - 0.5f);
- t = mid[1]-(p[1] - 0.5f);
- w[1][0] = -t;
- w[1][2] = (1.f - t);
- w[1][1] = 2.0f * t - 1.0f;
-
- mid[2] = (int)ceil(p[2] - 0.5f);
- t = mid[2] - (p[2] - 0.5f);
- w[2][0] = t * t / 2;
- w[2][2] = (1 - t) * (1 - t)/2;
- w[2][1] = 1 - w[2][0] - w[2][2];
-
- // to optimize, explicitly unroll this loop
- for (int z = -1; z <=1; z++)
- for (int y = -1; y <=1; y++)
- for (int x = -1; x <=1; x++)
- {
- float weight = 1.0f;
- c[0] = modFast128(mid[0] + x);
- weight *= w[0][x+1];
- c[1] = modFast128(mid[1] + y);
- weight *= w[1][y+1];
- c[2] = modFast128(mid[2] + z);
- weight *= w[2][z+1];
- result += weight * data[c[2]*n*n+c[1]*n+c[0]];
- }
-
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// z derivative of noise
-//////////////////////////////////////////////////////////////////////////////////////////
-static inline float WNoiseDz(Vec3 p, float* data) {
- int c[3], mid[3], n=noiseTileSize;
- float w[3][3], t, result =0;
-
- mid[0] = (int)ceil(p[0] - 0.5f);
- t = mid[0]-(p[0] - 0.5f);
- w[0][0] = t * t / 2;
- w[0][2] = (1 - t) * (1 - t) / 2;
- w[0][1] = 1 - w[0][0] - w[0][2];
-
- mid[1] = (int)ceil(p[1] - 0.5f);
- t = mid[1]-(p[1] - 0.5f);
- w[1][0] = t * t / 2;
- w[1][2] = (1 - t) * (1 - t) / 2;
- w[1][1] = 1 - w[1][0] - w[1][2];
-
- mid[2] = (int)ceil(p[2] - 0.5f);
- t = mid[2] - (p[2] - 0.5f);
- w[2][0] = -t;
- w[2][2] = (1.f - t);
- w[2][1] = 2.0f * t - 1.0f;
-
- // to optimize, explicitly unroll this loop
- for (int z = -1; z <=1; z++)
- for (int y = -1; y <=1; y++)
- for (int x = -1; x <=1; x++)
- {
- float weight = 1.0f;
- c[0] = modFast128(mid[0] + x);
- weight *= w[0][x+1];
- c[1] = modFast128(mid[1] + y);
- weight *= w[1][y+1];
- c[2] = modFast128(mid[2] + z);
- weight *= w[2][z+1];
- result += weight * data[c[2]*n*n+c[1]*n+c[0]];
- }
- return result;
-}
-
-#endif
-
diff --git a/intern/smoke/intern/WTURBULENCE.cpp b/intern/smoke/intern/WTURBULENCE.cpp
deleted file mode 100644
index 0703412d013..00000000000
--- a/intern/smoke/intern/WTURBULENCE.cpp
+++ /dev/null
@@ -1,1198 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// WTURBULENCE handling
-///////////////////////////////////////////////////////////////////////////////////
-// Parallelized turbulence even further. TNT matrix library functions
-// rewritten to improve performance.
-// - MiikaH
-//////////////////////////////////////////////////////////////////////
-
-#include "WTURBULENCE.h"
-#include "INTERPOLATE.h"
-#include "IMAGE.h"
-#include <MERSENNETWISTER.h>
-#include "WAVELET_NOISE.h"
-#include "FFT_NOISE.h"
-#include "EIGENVALUE_HELPER.h"
-#include "LU_HELPER.h"
-#include "SPHERE.h"
-#include <zlib.h>
-#include <math.h>
-
-// needed to access static advection functions
-#include "FLUID_3D.h"
-
-#if PARALLEL==1
-#include <omp.h>
-#endif // PARALLEL
-
-// 2^ {-5/6}
-static const float persistence = 0.56123f;
-
-//////////////////////////////////////////////////////////////////////
-// constructor
-//////////////////////////////////////////////////////////////////////
-WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors)
-{
- // if noise magnitude is below this threshold, its contribution
- // is negilgible, so stop evaluating new octaves
- _cullingThreshold = 1e-3;
-
- // factor by which to increase the simulation resolution
- _amplify = amplify;
-
- // manually adjust the overall amount of turbulence
- // DG - RNA-fied _strength = 2.;
-
- // add the corresponding octaves of noise
- _octaves = (int)(log((float)_amplify) / log(2.0f) + 0.5f); // XXX DEBUG/ TODO: int casting correct? - dg
-
- // noise resolution
- _xResBig = _amplify * xResSm;
- _yResBig = _amplify * yResSm;
- _zResBig = _amplify * zResSm;
- _resBig = Vec3Int(_xResBig, _yResBig, _zResBig);
- _invResBig = Vec3(1.0f/(float)_resBig[0], 1.0f/(float)_resBig[1], 1.0f/(float)_resBig[2]);
- _slabSizeBig = _xResBig*_yResBig;
- _totalCellsBig = _slabSizeBig * _zResBig;
-
- // original / small resolution
- _xResSm = xResSm;
- _yResSm = yResSm;
- _zResSm = zResSm;
- _resSm = Vec3Int(xResSm, yResSm, zResSm);
- _invResSm = Vec3(1.0f/(float)_resSm[0], 1.0f/(float)_resSm[1], 1.0f/(float)_resSm[2] );
- _slabSizeSm = _xResSm*_yResSm;
- _totalCellsSm = _slabSizeSm * _zResSm;
-
- // allocate high resolution density field
- _totalStepsBig = 0;
- _densityBig = new float[_totalCellsBig];
- _densityBigOld = new float[_totalCellsBig];
-
- for(int i = 0; i < _totalCellsBig; i++) {
- _densityBig[i] =
- _densityBigOld[i] = 0.;
- }
-
- /* fire */
- _flameBig = _fuelBig = _fuelBigOld = NULL;
- _reactBig = _reactBigOld = NULL;
- if (init_fire) {
- initFire();
- }
- /* colors */
- _color_rBig = _color_rBigOld = NULL;
- _color_gBig = _color_gBigOld = NULL;
- _color_bBig = _color_bBigOld = NULL;
- if (init_colors) {
- initColors(0.0f, 0.0f, 0.0f);
- }
-
- // allocate & init texture coordinates
- _tcU = new float[_totalCellsSm];
- _tcV = new float[_totalCellsSm];
- _tcW = new float[_totalCellsSm];
- _tcTemp = new float[_totalCellsSm];
-
- // map all
- const float dx = 1.0f/(float)(_resSm[0]);
- const float dy = 1.0f/(float)(_resSm[1]);
- const float dz = 1.0f/(float)(_resSm[2]);
- int index = 0;
- for (int z = 0; z < _zResSm; z++)
- for (int y = 0; y < _yResSm; y++)
- for (int x = 0; x < _xResSm; x++, index++)
- {
- _tcU[index] = x*dx;
- _tcV[index] = y*dy;
- _tcW[index] = z*dz;
- _tcTemp[index] = 0.;
- }
-
- // noise tiles
- _noiseTile = new float[noiseTileSize * noiseTileSize * noiseTileSize];
- setNoise(noisetype, noisefile_path);
-}
-
-void WTURBULENCE::initFire()
-{
- if (!_fuelBig) {
- _flameBig = new float[_totalCellsBig];
- _fuelBig = new float[_totalCellsBig];
- _fuelBigOld = new float[_totalCellsBig];
- _reactBig = new float[_totalCellsBig];
- _reactBigOld = new float[_totalCellsBig];
-
- for(int i = 0; i < _totalCellsBig; i++) {
- _flameBig[i] =
- _fuelBig[i] =
- _fuelBigOld[i] = 0.;
- _reactBig[i] =
- _reactBigOld[i] = 0.;
- }
- }
-}
-
-void WTURBULENCE::initColors(float init_r, float init_g, float init_b)
-{
- if (!_color_rBig) {
- _color_rBig = new float[_totalCellsBig];
- _color_rBigOld = new float[_totalCellsBig];
- _color_gBig = new float[_totalCellsBig];
- _color_gBigOld = new float[_totalCellsBig];
- _color_bBig = new float[_totalCellsBig];
- _color_bBigOld = new float[_totalCellsBig];
-
- for(int i = 0; i < _totalCellsBig; i++) {
- _color_rBig[i] = _densityBig[i] * init_r;
- _color_rBigOld[i] = 0.0f;
- _color_gBig[i] = _densityBig[i] * init_g;
- _color_gBigOld[i] = 0.0f;
- _color_bBig[i] = _densityBig[i] * init_b;
- _color_bBigOld[i] = 0.0f;
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// destructor
-//////////////////////////////////////////////////////////////////////
-WTURBULENCE::~WTURBULENCE() {
- delete[] _densityBig;
- delete[] _densityBigOld;
- if (_flameBig) delete[] _flameBig;
- if (_fuelBig) delete[] _fuelBig;
- if (_fuelBigOld) delete[] _fuelBigOld;
- if (_reactBig) delete[] _reactBig;
- if (_reactBigOld) delete[] _reactBigOld;
-
- if (_color_rBig) delete[] _color_rBig;
- if (_color_rBigOld) delete[] _color_rBigOld;
- if (_color_gBig) delete[] _color_gBig;
- if (_color_gBigOld) delete[] _color_gBigOld;
- if (_color_bBig) delete[] _color_bBig;
- if (_color_bBigOld) delete[] _color_bBigOld;
-
- delete[] _tcU;
- delete[] _tcV;
- delete[] _tcW;
- delete[] _tcTemp;
-
- delete[] _noiseTile;
-}
-
-//////////////////////////////////////////////////////////////////////
-// Change noise type
-//
-// type (1<<0) = wavelet / 2
-// type (1<<1) = FFT / 4
-// type (1<<2) = curl / 8
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::setNoise(int type, const char *noisefile_path)
-{
- if(type == (1<<1)) // FFT
- {
-#ifdef WITH_FFTW3
- // needs fft
- std::string noiseTileFilename = std::string(noisefile_path) + std::string("noise.fft");
- generatTile_FFT(_noiseTile, noiseTileFilename);
- return;
-#else
- fprintf(stderr, "FFTW not enabled, falling back to wavelet noise.\n");
-#endif
- }
-#if 0
- if(type == (1<<2)) // curl
- {
- // TODO: not supported yet
- return;
- }
-#endif
-
- std::string noiseTileFilename = std::string(noisefile_path) + std::string("noise.wavelets");
- generateTile_WAVELET(_noiseTile, noiseTileFilename);
-}
-
-// init direct access functions from blender
-void WTURBULENCE::initBlenderRNA(float *strength)
-{
- _strength = strength;
-}
-
-//////////////////////////////////////////////////////////////////////
-// Get the smallest valid x derivative
-//
-// Takes the one-sided finite difference in both directions and
-// selects the smaller of the two
-//////////////////////////////////////////////////////////////////////
-static float minDx(int x, int y, int z, float* input, const Vec3Int& res)
-{
- const int index = x + y * res[0] + z * res[0] * res[1];
- const int maxx = res[0]-2;
-
- // get grid values
- float center = input[index];
- float left = (x <= 1) ? FLT_MAX : input[index - 1];
- float right = (x >= maxx) ? FLT_MAX : input[index + 1];
-
- const float dx = res[0];
-
- // get all the derivative estimates
- float dLeft = (x <= 1) ? FLT_MAX : (center - left) * dx;
- float dRight = (x >= maxx) ? FLT_MAX : (right - center) * dx;
- float dCenter = (x <= 1 || x >= maxx) ? FLT_MAX : (right - left) * dx * 0.5f;
-
- // if it's on a boundary, only one estimate is valid
- if (x <= 1) return dRight;
- if (x >= maxx) return dLeft;
-
- // if it's not on a boundary, get the smallest one
- float finalD;
- finalD = (fabs(dCenter) < fabs(dRight)) ? dCenter : dRight;
- finalD = (fabs(finalD) < fabs(dLeft)) ? finalD : dLeft;
-
- return finalD;
-}
-
-//////////////////////////////////////////////////////////////////////
-// get the smallest valid y derivative
-//
-// Takes the one-sided finite difference in both directions and
-// selects the smaller of the two
-//////////////////////////////////////////////////////////////////////
-static float minDy(int x, int y, int z, float* input, const Vec3Int& res)
-{
- const int index = x + y * res[0] + z * res[0] * res[1];
- const int maxy = res[1]-2;
-
- // get grid values
- float center = input[index];
- float down = (y <= 1) ? FLT_MAX : input[index - res[0]];
- float up = (y >= maxy) ? FLT_MAX : input[index + res[0]];
-
- const float dx = res[1]; // only for square domains
-
- // get all the derivative estimates
- float dDown = (y <= 1) ? FLT_MAX : (center - down) * dx;
- float dUp = (y >= maxy) ? FLT_MAX : (up - center) * dx;
- float dCenter = (y <= 1 || y >= maxy) ? FLT_MAX : (up - down) * dx * 0.5f;
-
- // if it's on a boundary, only one estimate is valid
- if (y <= 1) return dUp;
- if (y >= maxy) return dDown;
-
- // if it's not on a boundary, get the smallest one
- float finalD = (fabs(dCenter) < fabs(dUp)) ? dCenter : dUp;
- finalD = (fabs(finalD) < fabs(dDown)) ? finalD : dDown;
-
- return finalD;
-}
-
-//////////////////////////////////////////////////////////////////////
-// get the smallest valid z derivative
-//
-// Takes the one-sided finite difference in both directions and
-// selects the smaller of the two
-//////////////////////////////////////////////////////////////////////
-static float minDz(int x, int y, int z, float* input, const Vec3Int& res)
-{
- const int slab = res[0]*res[1];
- const int index = x + y * res[0] + z * slab;
- const int maxz = res[2]-2;
-
- // get grid values
- float center = input[index];
- float front = (z <= 1) ? FLT_MAX : input[index - slab];
- float back = (z >= maxz) ? FLT_MAX : input[index + slab];
-
- const float dx = res[2]; // only for square domains
-
- // get all the derivative estimates
- float dfront = (z <= 1) ? FLT_MAX : (center - front) * dx;
- float dback = (z >= maxz) ? FLT_MAX : (back - center) * dx;
- float dCenter = (z <= 1 || z >= maxz) ? FLT_MAX : (back - front) * dx * 0.5f;
-
- // if it's on a boundary, only one estimate is valid
- if (z <= 1) return dback;
- if (z >= maxz) return dfront;
-
- // if it's not on a boundary, get the smallest one
- float finalD = (fabs(dCenter) < fabs(dback)) ? dCenter : dback;
- finalD = (fabs(finalD) < fabs(dfront)) ? finalD : dfront;
-
- return finalD;
-}
-
-//////////////////////////////////////////////////////////////////////
-// handle texture coordinates (advection, reset, eigenvalues),
-// Beware -- uses big density maccormack as temporary arrays
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::advectTextureCoordinates (float dtOrg, float* xvel, float* yvel, float* zvel, float *tempBig1, float *tempBig2) {
-
- // advection
- SWAP_POINTERS(_tcTemp, _tcU);
- FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel,
- _tcTemp, tempBig1, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel,
- _tcTemp, _tcU, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]);
-
- SWAP_POINTERS(_tcTemp, _tcV);
- FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel,
- _tcTemp, tempBig1, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel,
- _tcTemp, _tcV, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]);
-
- SWAP_POINTERS(_tcTemp, _tcW);
- FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel,
- _tcTemp, tempBig1, _resSm, 0 , _resSm[2]);
- FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel,
- _tcTemp, _tcW, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]);
-}
-
-//////////////////////////////////////////////////////////////////////
-// Compute the eigenvalues of the advected texture
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::computeEigenvalues(float *_eigMin, float *_eigMax) {
- // stats
- float maxeig = -1.;
- float mineig = 10.;
-
- // texture coordinate eigenvalues
- for (int z = 1; z < _zResSm-1; z++) {
- for (int y = 1; y < _yResSm-1; y++)
- for (int x = 1; x < _xResSm-1; x++)
- {
- const int index = x+ y *_resSm[0] + z*_slabSizeSm;
-
- // compute jacobian
- float jacobian[3][3] = {
- { minDx(x, y, z, _tcU, _resSm), minDx(x, y, z, _tcV, _resSm), minDx(x, y, z, _tcW, _resSm) } ,
- { minDy(x, y, z, _tcU, _resSm), minDy(x, y, z, _tcV, _resSm), minDy(x, y, z, _tcW, _resSm) } ,
- { minDz(x, y, z, _tcU, _resSm), minDz(x, y, z, _tcV, _resSm), minDz(x, y, z, _tcW, _resSm) }
- };
-
- // ONLY compute the eigenvalues after checking that the matrix
- // is nonsingular
- sLU LU = computeLU(jacobian);
-
- if (isNonsingular(LU))
- {
- // get the analytic eigenvalues, quite slow right now...
- Vec3 eigenvalues = Vec3(1.);
- computeEigenvalues3x3( &eigenvalues[0], jacobian);
- _eigMax[index] = MAX3V(eigenvalues);
- _eigMin[index] = MIN3V(eigenvalues);
- maxeig = MAX(_eigMax[index],maxeig);
- mineig = MIN(_eigMin[index],mineig);
- }
- else
- {
- _eigMax[index] = 10.0f;
- _eigMin[index] = 0.1;
- }
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// advect & reset texture coordinates based on eigenvalues
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::resetTextureCoordinates(float *_eigMin, float *_eigMax)
-{
- // allowed deformation of the textures
- const float limit = 2.f;
- const float limitInv = 1.0f/limit;
-
- // standard reset
- int resets = 0;
- const float dx = 1.0f/(float)(_resSm[0]);
- const float dy = 1.0f/(float)(_resSm[1]);
- const float dz = 1.0f/(float)(_resSm[2]);
-
- for (int z = 1; z < _zResSm-1; z++)
- for (int y = 1; y < _yResSm-1; y++)
- for (int x = 1; x < _xResSm-1; x++)
- {
- const int index = x+ y *_resSm[0] + z*_slabSizeSm;
- if (_eigMax[index] > limit || _eigMin[index] < limitInv)
- {
- _tcU[index] = (float)x * dx;
- _tcV[index] = (float)y * dy;
- _tcW[index] = (float)z * dz;
- resets++;
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// Compute the highest frequency component of the wavelet
-// decomposition
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::decomposeEnergy(float *_energy, float *_highFreqEnergy)
-{
- // do the decomposition -- the goal here is to have
- // the energy with the high frequency component stomped out
- // stored in _tcTemp when it is done. _highFreqEnergy is only used
- // as an additional temp array
-
- // downsample input
- downsampleXNeumann(_highFreqEnergy, _energy, _xResSm, _yResSm, _zResSm);
- downsampleYNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm);
- downsampleZNeumann(_highFreqEnergy, _tcTemp, _xResSm, _yResSm, _zResSm);
-
- // upsample input
- upsampleZNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm);
- upsampleYNeumann(_highFreqEnergy, _tcTemp, _xResSm, _yResSm, _zResSm);
- upsampleXNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm);
-
- // subtract the down and upsampled field from the original field --
- // what should be left over is solely the high frequency component
- int index = 0;
- for (int z = 0; z < _zResSm; z++)
- for (int y = 0; y < _yResSm; y++) {
- for (int x = 0; x < _xResSm; x++, index++) {
- // brute force reset of boundaries
- if(z >= _zResSm - 1 || x >= _xResSm - 1 || y >= _yResSm - 1 || z <= 0 || y <= 0 || x <= 0)
- _highFreqEnergy[index] = 0.;
- else
- _highFreqEnergy[index] = _energy[index] - _tcTemp[index];
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////
-// compute velocity from energies and march into obstacles
-// for wavelet decomposition
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::computeEnergy(float *_energy, float* xvel, float* yvel, float* zvel, unsigned char *origObstacles)
-{
- unsigned char *obstacles = new unsigned char[_totalCellsSm];
- memcpy(obstacles, origObstacles, sizeof(unsigned char) * _totalCellsSm);
-
- // compute everywhere
- for (int x = 0; x < _totalCellsSm; x++)
- _energy[x] = 0.5f * (xvel[x] * xvel[x] + yvel[x] * yvel[x] + zvel[x] * zvel[x]);
-
- FLUID_3D::copyBorderX(_energy, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderY(_energy, _resSm, 0 , _resSm[2]);
- FLUID_3D::copyBorderZ(_energy, _resSm, 0 , _resSm[2]);
-
- // pseudo-march the values into the obstacles
- // the wavelet upsampler only uses a 3x3 support neighborhood, so
- // propagating the values in by 4 should be sufficient
- int index;
-
- // iterate
- for (int iter = 0; iter < 4; iter++)
- {
- index = _slabSizeSm + _xResSm + 1;
- for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm)
- for (int y = 1; y < _yResSm - 1; y++, index += 2)
- for (int x = 1; x < _xResSm - 1; x++, index++)
- if (obstacles[index] && obstacles[index] != RETIRED)
- {
- float sum = 0.0f;
- int valid = 0;
-
- if (!obstacles[index + 1] || obstacles[index + 1] == RETIRED)
- {
- sum += _energy[index + 1];
- valid++;
- }
- if (!obstacles[index - 1] || obstacles[index - 1] == RETIRED)
- {
- sum += _energy[index - 1];
- valid++;
- }
- if (!obstacles[index + _xResSm] || obstacles[index + _xResSm] == RETIRED)
- {
- sum += _energy[index + _xResSm];
- valid++;
- }
- if (!obstacles[index - _xResSm] || obstacles[index - _xResSm] == RETIRED)
- {
- sum += _energy[index - _xResSm];
- valid++;
- }
- if (!obstacles[index + _slabSizeSm] || obstacles[index + _slabSizeSm] == RETIRED)
- {
- sum += _energy[index + _slabSizeSm];
- valid++;
- }
- if (!obstacles[index - _slabSizeSm] || obstacles[index - _slabSizeSm] == RETIRED)
- {
- sum += _energy[index - _slabSizeSm];
- valid++;
- }
- if (valid > 0)
- {
- _energy[index] = sum / (float)valid;
- obstacles[index] = MARCHED;
- }
- }
- index = _slabSizeSm + _xResSm + 1;
- for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm)
- for (int y = 1; y < _yResSm - 1; y++, index += 2)
- for (int x = 1; x < _xResSm - 1; x++, index++)
- if (obstacles[index] == MARCHED)
- obstacles[index] = RETIRED;
- }
- index = _slabSizeSm + _xResSm + 1;
- for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm)
- for (int y = 1; y < _yResSm - 1; y++, index += 2)
- for (int x = 1; x < _xResSm - 1; x++, index++)
- if (obstacles[index])
- obstacles[index] = 1; // DG TODO ? animated obstacle flag?
-
- delete [] obstacles;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Evaluate derivatives
-//////////////////////////////////////////////////////////////////////////////////////////
-Vec3 WTURBULENCE::WVelocity(Vec3 orgPos)
-{
- // arbitrarily offset evaluation points
- const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2.0,0,0);
- const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2.0,0);
- const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2.0);
-
- const float f1y = WNoiseDy(p1, _noiseTile);
- const float f1z = WNoiseDz(p1, _noiseTile);
-
- const float f2x = WNoiseDx(p2, _noiseTile);
- const float f2z = WNoiseDz(p2, _noiseTile);
-
- const float f3x = WNoiseDx(p3, _noiseTile);
- const float f3y = WNoiseDy(p3, _noiseTile);
-
- Vec3 ret = Vec3(
- f3y - f2z,
- f1z - f3x,
- f2x - f1y );
- return ret;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Evaluate derivatives with Jacobian
-//////////////////////////////////////////////////////////////////////////////////////////
-Vec3 WTURBULENCE::WVelocityWithJacobian(const Vec3& orgPos, float* xUnwarped, float* yUnwarped, float* zUnwarped)
-{
- // arbitrarily offset evaluation points
- const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2.0,0,0);
- const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2.0,0);
- const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2.0);
-
- Vec3 final;
- final[0] = WNoiseDx(p1, _noiseTile);
- final[1] = WNoiseDy(p1, _noiseTile);
- final[2] = WNoiseDz(p1, _noiseTile);
- // UNUSED const float f1x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2];
- const float f1y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2];
- const float f1z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2];
-
- final[0] = WNoiseDx(p2, _noiseTile);
- final[1] = WNoiseDy(p2, _noiseTile);
- final[2] = WNoiseDz(p2, _noiseTile);
- const float f2x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2];
- // UNUSED const float f2y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2];
- const float f2z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2];
-
- final[0] = WNoiseDx(p3, _noiseTile);
- final[1] = WNoiseDy(p3, _noiseTile);
- final[2] = WNoiseDz(p3, _noiseTile);
- const float f3x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2];
- const float f3y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2];
- // UNUSED const float f3z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2];
-
- Vec3 ret = Vec3(
- f3y - f2z,
- f1z - f3x,
- f2x - f1y );
- return ret;
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// perform an actual noise advection step
-//////////////////////////////////////////////////////////////////////
-/*void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles)
-{
- // enlarge timestep to match grid
- const float dt = dtOrg * _amplify;
- const float invAmp = 1.0f / _amplify;
- float *tempBig1 = new float[_totalCellsBig];
- float *tempBig2 = new float[_totalCellsBig];
- float *bigUx = new float[_totalCellsBig];
- float *bigUy = new float[_totalCellsBig];
- float *bigUz = new float[_totalCellsBig];
- float *_energy = new float[_totalCellsSm];
- float *highFreqEnergy = new float[_totalCellsSm];
- float *eigMin = new float[_totalCellsSm];
- float *eigMax = new float[_totalCellsSm];
-
- memset(tempBig1, 0, sizeof(float)*_totalCellsBig);
- memset(tempBig2, 0, sizeof(float)*_totalCellsBig);
- memset(highFreqEnergy, 0, sizeof(float)*_totalCellsSm);
- memset(eigMin, 0, sizeof(float)*_totalCellsSm);
- memset(eigMax, 0, sizeof(float)*_totalCellsSm);
-
- // prepare textures
- advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempBig1, tempBig2);
-
- // compute eigenvalues of the texture coordinates
- computeEigenvalues(eigMin, eigMax);
-
- // do wavelet decomposition of energy
- computeEnergy(_energy, xvel, yvel, zvel, obstacles);
- decomposeEnergy(_energy, highFreqEnergy);
-
- // zero out coefficients inside of the obstacle
- for (int x = 0; x < _totalCellsSm; x++)
- if (obstacles[x]) _energy[x] = 0.f;
-
- float maxVelocity = 0.;
- for (int z = 1; z < _zResBig - 1; z++)
- for (int y = 1; y < _yResBig - 1; y++)
- for (int x = 1; x < _xResBig - 1; x++)
- {
- // get unit position for both fine and coarse grid
- const Vec3 pos = Vec3(x,y,z);
- const Vec3 posSm = pos * invAmp;
-
- // get grid index for both fine and coarse grid
- const int index = x + y *_xResBig + z *_slabSizeBig;
- const int indexSmall = (int)posSm[0] + (int)posSm[1] * _xResSm + (int)posSm[2] * _slabSizeSm;
-
- // get a linearly interpolated velocity and texcoords
- // from the coarse grid
- Vec3 vel = INTERPOLATE::lerp3dVec( xvel,yvel,zvel,
- posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
- Vec3 uvw = INTERPOLATE::lerp3dVec( _tcU,_tcV,_tcW,
- posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
-
- // multiply the texture coordinate by _resSm so that turbulence
- // synthesis begins at the first octave that the coarse grid
- // cannot capture
- Vec3 texCoord = Vec3(uvw[0] * _resSm[0],
- uvw[1] * _resSm[1],
- uvw[2] * _resSm[2]);
-
- // retrieve wavelet energy at highest frequency
- float energy = INTERPOLATE::lerp3d(
- highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm);
-
- // base amplitude for octave 0
- float coefficient = sqrtf(2.0f * fabs(energy));
- const float amplitude = *_strength * fabs(0.5 * coefficient) * persistence;
-
- // add noise to velocity, but only if the turbulence is
- // sufficiently undeformed, and the energy is large enough
- // to make a difference
- const bool addNoise = eigMax[indexSmall] < 2. &&
- eigMin[indexSmall] > 0.5;
- if (addNoise && amplitude > _cullingThreshold) {
- // base amplitude for octave 0
- float amplitudeScaled = amplitude;
-
- for (int octave = 0; octave < _octaves; octave++)
- {
- // multiply the vector noise times the maximum allowed
- // noise amplitude at this octave, and add it to the total
- vel += WVelocity(texCoord) * amplitudeScaled;
-
- // scale coefficient for next octave
- amplitudeScaled *= persistence;
- texCoord *= 2.0f;
- }
- }
-
- // Store velocity + turbulence in big grid for maccormack step
- //
- // If you wanted to save memory, you would instead perform a
- // semi-Lagrangian backtrace for the current grid cell here. Then
- // you could just throw the velocity away.
- bigUx[index] = vel[0];
- bigUy[index] = vel[1];
- bigUz[index] = vel[2];
-
- // compute the velocity magnitude for substepping later
- const float velMag = bigUx[index] * bigUx[index] +
- bigUy[index] * bigUy[index] +
- bigUz[index] * bigUz[index];
- if (velMag > maxVelocity) maxVelocity = velMag;
-
- // zero out velocity inside obstacles
- float obsCheck = INTERPOLATE::lerp3dToFloat(
- obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm);
- if (obsCheck > 0.95)
- bigUx[index] = bigUy[index] = bigUz[index] = 0.;
- }
-
- // prepare density for an advection
- SWAP_POINTERS(_densityBig, _densityBigOld);
-
- // based on the maximum velocity present, see if we need to substep,
- // but cap the maximum number of substeps to 5
- const int maxSubSteps = 5;
- maxVelocity = sqrt(maxVelocity) * dt;
- int totalSubsteps = (int)(maxVelocity / (float)maxSubSteps);
- totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
- totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
- const float dtSubdiv = dt / (float)totalSubsteps;
-
- // set boundaries of big velocity grid
- FLUID_3D::setZeroX(bigUx, _resBig, 0, _resBig[2]);
- FLUID_3D::setZeroY(bigUy, _resBig, 0, _resBig[2]);
- FLUID_3D::setZeroZ(bigUz, _resBig, 0, _resBig[2]);
-
- // do the MacCormack advection, with substepping if necessary
- for(int substep = 0; substep < totalSubsteps; substep++)
- {
- FLUID_3D::advectFieldMacCormack(dtSubdiv, bigUx, bigUy, bigUz,
- _densityBigOld, _densityBig, tempBig1, tempBig2, _resBig, NULL);
-
- if (substep < totalSubsteps - 1)
- SWAP_POINTERS(_densityBig, _densityBigOld);
- } // substep
-
- // wipe the density borders
- FLUID_3D::setZeroBorder(_densityBig, _resBig, 0, _resBig[2]);
-
- // reset texture coordinates now in preparation for next timestep
- // Shouldn't do this before generating the noise because then the
- // eigenvalues stored do not reflect the underlying texture coordinates
- resetTextureCoordinates(eigMin, eigMax);
-
- delete[] tempBig1;
- delete[] tempBig2;
- delete[] bigUx;
- delete[] bigUy;
- delete[] bigUz;
- delete[] _energy;
- delete[] highFreqEnergy;
-
- delete[] eigMin;
- delete[] eigMax;
-
-
- _totalStepsBig++;
-}*/
-
-//struct
-
-//////////////////////////////////////////////////////////////////////
-// perform the full turbulence algorithm, including OpenMP
-// if available
-//////////////////////////////////////////////////////////////////////
-void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles)
-{
- // enlarge timestep to match grid
- const float dt = dtOrg * _amplify;
- const float invAmp = 1.0f / _amplify;
- float *tempFuelBig = NULL, *tempReactBig = NULL;
- float *tempColor_rBig = NULL, *tempColor_gBig = NULL, *tempColor_bBig = NULL;
- float *tempDensityBig = (float *)calloc(_totalCellsBig, sizeof(float));
- float *tempBig = (float *)calloc(_totalCellsBig, sizeof(float));
- float *bigUx = (float *)calloc(_totalCellsBig, sizeof(float));
- float *bigUy = (float *)calloc(_totalCellsBig, sizeof(float));
- float *bigUz = (float *)calloc(_totalCellsBig, sizeof(float));
- float *_energy = (float *)calloc(_totalCellsSm, sizeof(float));
- float *highFreqEnergy = (float *)calloc(_totalCellsSm, sizeof(float));
- float *eigMin = (float *)calloc(_totalCellsSm, sizeof(float));
- float *eigMax = (float *)calloc(_totalCellsSm, sizeof(float));
-
- if (_fuelBig) {
- tempFuelBig = (float *)calloc(_totalCellsBig, sizeof(float));
- tempReactBig = (float *)calloc(_totalCellsBig, sizeof(float));
- }
- if (_color_rBig) {
- tempColor_rBig = (float *)calloc(_totalCellsBig, sizeof(float));
- tempColor_gBig = (float *)calloc(_totalCellsBig, sizeof(float));
- tempColor_bBig = (float *)calloc(_totalCellsBig, sizeof(float));
- }
-
- memset(_tcTemp, 0, sizeof(float)*_totalCellsSm);
-
-
- // prepare textures
- advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempDensityBig, tempBig);
-
- // do wavelet decomposition of energy
- computeEnergy(_energy, xvel, yvel, zvel, obstacles);
-
- for (int x = 0; x < _totalCellsSm; x++)
- if (obstacles[x]) _energy[x] = 0.f;
-
- decomposeEnergy(_energy, highFreqEnergy);
-
- // zero out coefficients inside of the obstacle
- for (int x = 0; x < _totalCellsSm; x++)
- if (obstacles[x]) highFreqEnergy[x] = 0.f;
-
- Vec3Int ressm(_xResSm, _yResSm, _zResSm);
- FLUID_3D::setNeumannX(highFreqEnergy, ressm, 0 , ressm[2]);
- FLUID_3D::setNeumannY(highFreqEnergy, ressm, 0 , ressm[2]);
- FLUID_3D::setNeumannZ(highFreqEnergy, ressm, 0 , ressm[2]);
-
-
- int threadval = 1;
-#if PARALLEL==1
- threadval = omp_get_max_threads();
-#endif
-
-
- // parallel region setup
- // Uses omp_get_max_trheads to get number of required cells.
- float* maxVelMagThreads = new float[threadval];
-
- for (int i=0; i<threadval; i++) maxVelMagThreads[i] = -1.0f;
-
-#if PARALLEL==1
-
-#pragma omp parallel
-#endif
- { float maxVelMag1 = 0.;
-#if PARALLEL==1
- const int id = omp_get_thread_num(); /*, num = omp_get_num_threads(); */
-#endif
-
- // vector noise main loop
-#if PARALLEL==1
-#pragma omp for schedule(static,1)
-#endif
- for (int zSmall = 0; zSmall < _zResSm; zSmall++)
- {
- for (int ySmall = 0; ySmall < _yResSm; ySmall++)
- for (int xSmall = 0; xSmall < _xResSm; xSmall++)
- {
- const int indexSmall = xSmall + ySmall * _xResSm + zSmall * _slabSizeSm;
-
- // compute jacobian
- float jacobian[3][3] = {
- { minDx(xSmall, ySmall, zSmall, _tcU, _resSm), minDx(xSmall, ySmall, zSmall, _tcV, _resSm), minDx(xSmall, ySmall, zSmall, _tcW, _resSm) } ,
- { minDy(xSmall, ySmall, zSmall, _tcU, _resSm), minDy(xSmall, ySmall, zSmall, _tcV, _resSm), minDy(xSmall, ySmall, zSmall, _tcW, _resSm) } ,
- { minDz(xSmall, ySmall, zSmall, _tcU, _resSm), minDz(xSmall, ySmall, zSmall, _tcV, _resSm), minDz(xSmall, ySmall, zSmall, _tcW, _resSm) }
- };
-
- // get LU factorization of texture jacobian and apply
- // it to unit vectors
- sLU LU = computeLU(jacobian);
- float xUnwarped[3], yUnwarped[3], zUnwarped[3];
- float xWarped[3], yWarped[3], zWarped[3];
- bool nonSingular = isNonsingular(LU);
-
- xUnwarped[0] = 1.0f; xUnwarped[1] = 0.0f; xUnwarped[2] = 0.0f;
- yUnwarped[0] = 0.0f; yUnwarped[1] = 1.0f; yUnwarped[2] = 0.0f;
- zUnwarped[0] = 0.0f; zUnwarped[1] = 0.0f; zUnwarped[2] = 1.0f;
-
- xWarped[0] = 1.0f; xWarped[1] = 0.0f; xWarped[2] = 0.0f;
- yWarped[0] = 0.0f; yWarped[1] = 1.0f; yWarped[2] = 0.0f;
- zWarped[0] = 0.0f; zWarped[1] = 0.0f; zWarped[2] = 1.0f;
-
-#if 0
- // UNUSED
- float eigMax = 10.0f;
- float eigMin = 0.1f;
-#endif
- if (nonSingular)
- {
- solveLU3x3(LU, xUnwarped, xWarped);
- solveLU3x3(LU, yUnwarped, yWarped);
- solveLU3x3(LU, zUnwarped, zWarped);
-
- // compute the eigenvalues while we have the Jacobian available
- Vec3 eigenvalues = Vec3(1.);
- computeEigenvalues3x3( &eigenvalues[0], jacobian);
- eigMax[indexSmall] = MAX3V(eigenvalues);
- eigMin[indexSmall] = MIN3V(eigenvalues);
- }
-
- // make sure to skip one on the beginning and end
- int xStart = (xSmall == 0) ? 1 : 0;
- int xEnd = (xSmall == _xResSm - 1) ? _amplify - 1 : _amplify;
- int yStart = (ySmall == 0) ? 1 : 0;
- int yEnd = (ySmall == _yResSm - 1) ? _amplify - 1 : _amplify;
- int zStart = (zSmall == 0) ? 1 : 0;
- int zEnd = (zSmall == _zResSm - 1) ? _amplify - 1 : _amplify;
-
- for (int zBig = zStart; zBig < zEnd; zBig++)
- for (int yBig = yStart; yBig < yEnd; yBig++)
- for (int xBig = xStart; xBig < xEnd; xBig++)
- {
- const int x = xSmall * _amplify + xBig;
- const int y = ySmall * _amplify + yBig;
- const int z = zSmall * _amplify + zBig;
-
- // get unit position for both fine and coarse grid
- const Vec3 pos = Vec3(x,y,z);
- const Vec3 posSm = pos * invAmp;
-
- // get grid index for both fine and coarse grid
- const int index = x + y *_xResBig + z *_slabSizeBig;
-
- // get a linearly interpolated velocity and texcoords
- // from the coarse grid
- Vec3 vel = INTERPOLATE::lerp3dVec( xvel,yvel,zvel,
- posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
- Vec3 uvw = INTERPOLATE::lerp3dVec( _tcU,_tcV,_tcW,
- posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm);
-
- // multiply the texture coordinate by _resSm so that turbulence
- // synthesis begins at the first octave that the coarse grid
- // cannot capture
- Vec3 texCoord = Vec3(uvw[0] * _resSm[0],
- uvw[1] * _resSm[1],
- uvw[2] * _resSm[2]);
-
- // retrieve wavelet energy at highest frequency
- float energy = INTERPOLATE::lerp3d(
- highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm);
-
- // base amplitude for octave 0
- float coefficient = sqrtf(2.0f * fabs(energy));
- const float amplitude = *_strength * fabs(0.5f * coefficient) * persistence;
-
- // add noise to velocity, but only if the turbulence is
- // sufficiently undeformed, and the energy is large enough
- // to make a difference
- const bool addNoise = eigMax[indexSmall] < 2.0f &&
- eigMin[indexSmall] > 0.5f;
- if (addNoise && amplitude > _cullingThreshold) {
- // base amplitude for octave 0
- float amplitudeScaled = amplitude;
-
- for (int octave = 0; octave < _octaves; octave++)
- {
- // multiply the vector noise times the maximum allowed
- // noise amplitude at this octave, and add it to the total
- vel += WVelocityWithJacobian(texCoord, &xUnwarped[0], &yUnwarped[0], &zUnwarped[0]) * amplitudeScaled;
-
- // scale coefficient for next octave
- amplitudeScaled *= persistence;
- texCoord *= 2.0f;
- }
- }
-
- // Store velocity + turbulence in big grid for maccormack step
- //
- // If you wanted to save memory, you would instead perform a
- // semi-Lagrangian backtrace for the current grid cell here. Then
- // you could just throw the velocity away.
- bigUx[index] = vel[0];
- bigUy[index] = vel[1];
- bigUz[index] = vel[2];
-
- // compute the velocity magnitude for substepping later
- const float velMag = bigUx[index] * bigUx[index] +
- bigUy[index] * bigUy[index] +
- bigUz[index] * bigUz[index];
- if (velMag > maxVelMag1) maxVelMag1 = velMag;
-
- // zero out velocity inside obstacles
- float obsCheck = INTERPOLATE::lerp3dToFloat(
- obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm);
- if (obsCheck > 0.95f)
- bigUx[index] = bigUy[index] = bigUz[index] = 0.;
- } // xyz*/
-
-#if PARALLEL==1
- maxVelMagThreads[id] = maxVelMag1;
-#else
- maxVelMagThreads[0] = maxVelMag1;
-#endif
- }
- }
- } // omp
-
- // compute maximum over threads
- float maxVelMag = maxVelMagThreads[0];
-#if PARALLEL==1
- for (int i = 1; i < threadval; i++)
- if (maxVelMag < maxVelMagThreads[i])
- maxVelMag = maxVelMagThreads[i];
-#endif
- delete [] maxVelMagThreads;
-
-
- // prepare density for an advection
- SWAP_POINTERS(_densityBig, _densityBigOld);
- SWAP_POINTERS(_fuelBig, _fuelBigOld);
- SWAP_POINTERS(_reactBig, _reactBigOld);
- SWAP_POINTERS(_color_rBig, _color_rBigOld);
- SWAP_POINTERS(_color_gBig, _color_gBigOld);
- SWAP_POINTERS(_color_bBig, _color_bBigOld);
-
- // based on the maximum velocity present, see if we need to substep,
- // but cap the maximum number of substeps to 5
- const int maxSubSteps = 25;
- const int maxVel = 5;
- maxVelMag = sqrt(maxVelMag) * dt;
- int totalSubsteps = (int)(maxVelMag / (float)maxVel);
- totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
- // printf("totalSubsteps: %d\n", totalSubsteps);
- totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
- const float dtSubdiv = dt / (float)totalSubsteps;
-
- // set boundaries of big velocity grid
- FLUID_3D::setZeroX(bigUx, _resBig, 0 , _resBig[2]);
- FLUID_3D::setZeroY(bigUy, _resBig, 0 , _resBig[2]);
- FLUID_3D::setZeroZ(bigUz, _resBig, 0 , _resBig[2]);
-
-#if PARALLEL==1
- int stepParts = threadval*2; // Dividing parallelized sections into numOfThreads * 2 sections
- float partSize = (float)_zResBig/stepParts; // Size of one part;
-
- if (partSize < 4) {stepParts = threadval; // If the slice gets too low (might actually slow things down, change it to larger
- partSize = (float)_zResBig/stepParts;}
- if (partSize < 4) {stepParts = (int)(ceil((float)_zResBig/4.0f)); // If it's still too low (only possible on future systems with +24 cores), change it to 4
- partSize = (float)_zResBig/stepParts;}
-#else
- int zBegin=0;
- int zEnd=_resBig[2];
-#endif
-
- // do the MacCormack advection, with substepping if necessary
- for(int substep = 0; substep < totalSubsteps; substep++)
- {
-
-#if PARALLEL==1
- #pragma omp parallel
- {
-
- #pragma omp for schedule(static,1)
- for (int i=0; i<stepParts; i++)
- {
- int zBegin = (int)((float)i*partSize + 0.5f);
- int zEnd = (int)((float)(i+1)*partSize + 0.5f);
-#endif
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _densityBigOld, tempDensityBig, _resBig, zBegin, zEnd);
- if (_fuelBig) {
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _fuelBigOld, tempFuelBig, _resBig, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _reactBigOld, tempReactBig, _resBig, zBegin, zEnd);
- }
- if (_color_rBig) {
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _color_rBigOld, tempColor_rBig, _resBig, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _color_gBigOld, tempColor_gBig, _resBig, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
- _color_bBigOld, tempColor_bBig, _resBig, zBegin, zEnd);
- }
-#if PARALLEL==1
- }
-
- #pragma omp barrier
-
- #pragma omp for schedule(static,1)
- for (int i=0; i<stepParts; i++)
- {
- int zBegin = (int)((float)i*partSize + 0.5f);
- int zEnd = (int)((float)(i+1)*partSize + 0.5f);
-#endif
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _densityBigOld, _densityBig, tempDensityBig, tempBig, _resBig, NULL, zBegin, zEnd);
- if (_fuelBig) {
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _fuelBigOld, _fuelBig, tempFuelBig, tempBig, _resBig, NULL, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _reactBigOld, _reactBig, tempReactBig, tempBig, _resBig, NULL, zBegin, zEnd);
- }
- if (_color_rBig) {
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _color_rBigOld, _color_rBig, tempColor_rBig, tempBig, _resBig, NULL, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _color_gBigOld, _color_gBig, tempColor_gBig, tempBig, _resBig, NULL, zBegin, zEnd);
- FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
- _color_bBigOld, _color_bBig, tempColor_bBig, tempBig, _resBig, NULL, zBegin, zEnd);
- }
-#if PARALLEL==1
- }
- }
-#endif
-
- if (substep < totalSubsteps - 1) {
- SWAP_POINTERS(_densityBig, _densityBigOld);
- SWAP_POINTERS(_fuelBig, _fuelBigOld);
- SWAP_POINTERS(_reactBig, _reactBigOld);
- SWAP_POINTERS(_color_rBig, _color_rBigOld);
- SWAP_POINTERS(_color_gBig, _color_gBigOld);
- SWAP_POINTERS(_color_bBig, _color_bBigOld);
- }
- } // substep
-
- free(tempDensityBig);
- if (tempFuelBig) free(tempFuelBig);
- if (tempReactBig) free(tempReactBig);
- if (tempColor_rBig) free(tempColor_rBig);
- if (tempColor_gBig) free(tempColor_gBig);
- if (tempColor_bBig) free(tempColor_bBig);
- free(tempBig);
- free(bigUx);
- free(bigUy);
- free(bigUz);
- free(_energy);
- free(highFreqEnergy);
-
- // wipe the density borders
- FLUID_3D::setZeroBorder(_densityBig, _resBig, 0 , _resBig[2]);
- if (_fuelBig) {
- FLUID_3D::setZeroBorder(_fuelBig, _resBig, 0 , _resBig[2]);
- FLUID_3D::setZeroBorder(_reactBig, _resBig, 0 , _resBig[2]);
- }
- if (_color_rBig) {
- FLUID_3D::setZeroBorder(_color_rBig, _resBig, 0 , _resBig[2]);
- FLUID_3D::setZeroBorder(_color_gBig, _resBig, 0 , _resBig[2]);
- FLUID_3D::setZeroBorder(_color_bBig, _resBig, 0 , _resBig[2]);
- }
-
- // reset texture coordinates now in preparation for next timestep
- // Shouldn't do this before generating the noise because then the
- // eigenvalues stored do not reflect the underlying texture coordinates
- resetTextureCoordinates(eigMin, eigMax);
-
- free(eigMin);
- free(eigMax);
-
- // output files
- // string prefix = string("./amplified.preview/density_bigxy_");
- // FLUID_3D::writeImageSliceXY(_densityBig, _resBig, _resBig[2]/2, prefix, _totalStepsBig, 1.0f);
- //string df3prefix = string("./df3/density_big_");
- //IMAGE::dumpDF3(_totalStepsBig, df3prefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]);
- // string pbrtPrefix = string("./pbrt/density_big_");
- // IMAGE::dumpPBRT(_totalStepsBig, pbrtPrefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]);
-
- _totalStepsBig++;
-}
diff --git a/intern/smoke/intern/WTURBULENCE.h b/intern/smoke/intern/WTURBULENCE.h
deleted file mode 100644
index 7ad04cfd36e..00000000000
--- a/intern/smoke/intern/WTURBULENCE.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-//////////////////////////////////////////////////////////////////////
-// This file is part of Wavelet Turbulence.
-//
-// Wavelet Turbulence 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 3 of the License, or
-// (at your option) any later version.
-//
-// Wavelet Turbulence 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 Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
-//
-// Copyright 2008 Theodore Kim and Nils Thuerey
-//
-// WTURBULENCE handling
-///////////////////////////////////////////////////////////////////////////////////
-
-#ifndef WTURBULENCE_H
-#define WTURBULENCE_H
-
-#include "VEC3.h"
-using namespace BasicVector;
-class SIMPLE_PARSER;
-
-///////////////////////////////////////////////////////////////////////////////
-/// Main WTURBULENCE class, stores large density array etc.
-///////////////////////////////////////////////////////////////////////////////
-struct WTURBULENCE
-{
- public:
- // both config files can be NULL, altCfg might override values from noiseCfg
- WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors);
-
- /// destructor
- virtual ~WTURBULENCE();
-
- void initFire();
- void initColors(float init_r, float init_g, float init_b);
-
- void setNoise(int type, const char *noisefile_path);
- void initBlenderRNA(float *strength);
-
- // step more readable version -- no rotation correction
- void stepTurbulenceReadable(float dt, float* xvel, float* yvel, float* zvel, unsigned char *obstacles);
-
- // step more complete version -- include rotation correction
- // and use OpenMP if available
- void stepTurbulenceFull(float dt, float* xvel, float* yvel, float* zvel, unsigned char *obstacles);
-
- // texcoord functions
- void advectTextureCoordinates(float dtOrg, float* xvel, float* yvel, float* zvel, float *tempBig1, float *tempBig2);
- void resetTextureCoordinates(float *_eigMin, float *_eigMax);
-
- void computeEnergy(float *energy, float* xvel, float* yvel, float* zvel, unsigned char *obstacles);
-
- // evaluate wavelet noise function
- Vec3 WVelocity(Vec3 p);
- Vec3 WVelocityWithJacobian(const Vec3& p, float* xUnwarped, float* yUnwarped, float* zUnwarped);
-
- // access functions
- inline float* getDensityBig() { return _densityBig; }
- inline float* getFlameBig() { return _flameBig; }
- inline float* getFuelBig() { return _fuelBig; }
- inline float* getArrayTcU() { return _tcU; }
- inline float* getArrayTcV() { return _tcV; }
- inline float* getArrayTcW() { return _tcW; }
-
- inline Vec3Int getResSm() { return _resSm; } // small resolution
- inline Vec3Int getResBig() { return _resBig; }
- inline int getOctaves() { return _octaves; }
-
- // is accessed on through rna gui
- float *_strength;
-
- // protected:
- // enlargement factor from original velocity field / simulation
- // _Big = _amplify * _Sm
- int _amplify;
- int _octaves;
-
- // noise settings
- float _cullingThreshold;
- // float _noiseStrength;
- // float _noiseSizeScale;
- // bool _uvwAdvection;
- // bool _uvwReset;
- // float _noiseTimeanimSpeed;
- // int _dumpInterval;
- // nt _noiseControlType;
- // debug, scale density for projections output images
- // float _outputScale;
-
- // noise resolution
- int _xResBig;
- int _yResBig;
- int _zResBig;
- Vec3Int _resBig;
- Vec3 _invResBig;
- int _totalCellsBig;
- int _slabSizeBig;
- // original / small resolution
- int _xResSm;
- int _yResSm;
- int _zResSm;
- Vec3Int _resSm;
- Vec3 _invResSm;
- int _totalCellsSm;
- int _slabSizeSm;
-
- float* _densityBig;
- float* _densityBigOld;
- float* _flameBig;
- float* _fuelBig;
- float* _fuelBigOld;
- float* _reactBig;
- float* _reactBigOld;
-
- float* _color_rBig;
- float* _color_rBigOld;
- float* _color_gBig;
- float* _color_gBigOld;
- float* _color_bBig;
- float* _color_bBigOld;
-
- // texture coordinates for noise
- float* _tcU;
- float* _tcV;
- float* _tcW;
- float* _tcTemp;
-
- // noise data
- float* _noiseTile;
- //float* _noiseTileExt;
-
- // step counter
- int _totalStepsBig;
-
- void computeEigenvalues(float *_eigMin, float *_eigMax);
- void decomposeEnergy(float *energy, float *_highFreqEnergy);
-};
-
-#endif // WTURBULENCE_H
-
diff --git a/intern/smoke/intern/smoke_API.cpp b/intern/smoke/intern/smoke_API.cpp
deleted file mode 100644
index a02fa3bd684..00000000000
--- a/intern/smoke/intern/smoke_API.cpp
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * 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) 2009 by Daniel Genrich
- * All rights reserved.
- */
-
-/** \file
- * \ingroup smoke
- */
-
-#include "FLUID_3D.h"
-#include "WTURBULENCE.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include "../extern/smoke_API.h" /* to ensure valid prototypes */
-
-extern "C" FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, int use_fire, int use_colors)
-{
- FLUID_3D *fluid = new FLUID_3D(res, dx, dtdef, use_heat, use_fire, use_colors);
- return fluid;
-}
-
-extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors)
-{
- if (amplify)
- return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype, noisefile_path, use_fire, use_colors);
- else
- return NULL;
-}
-
-extern "C" void smoke_free(FLUID_3D *fluid)
-{
- delete fluid;
- fluid = NULL;
-}
-
-extern "C" void smoke_turbulence_free(WTURBULENCE *wt)
-{
- delete wt;
- wt = NULL;
-}
-
-extern "C" size_t smoke_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;
-}
-
-extern "C" size_t smoke_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */)
-{
- return x + y * max_x;
-}
-
-extern "C" void smoke_step(FLUID_3D *fluid, float gravity[3], float dtSubdiv)
-{
- if (fluid->_fuel) {
- fluid->processBurn(fluid->_fuel, fluid->_density, fluid->_react, fluid->_heat,
- fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_totalCells, (*fluid->_dtFactor)*dtSubdiv);
- }
- fluid->step(dtSubdiv, gravity);
-
- if (fluid->_fuel) {
- fluid->updateFlame(fluid->_react, fluid->_flame, fluid->_totalCells);
- }
-}
-
-extern "C" void smoke_turbulence_step(WTURBULENCE *wt, FLUID_3D *fluid)
-{
- if (wt->_fuelBig) {
- fluid->processBurn(wt->_fuelBig, wt->_densityBig, wt->_reactBig, 0,
- wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_totalCellsBig, fluid->_dt);
- }
- wt->stepTurbulenceFull(fluid->_dt/fluid->_dx, fluid->_xVelocity, fluid->_yVelocity, fluid->_zVelocity, fluid->_obstacles);
-
- if (wt->_fuelBig) {
- fluid->updateFlame(wt->_reactBig, wt->_flameBig, wt->_totalCellsBig);
- }
-}
-
-extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
- float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp)
-{
- fluid->initBlenderRNA(alpha, beta, dt_factor, vorticity, border_colli, burning_rate, flame_smoke, flame_smoke_color, flame_vorticity, flame_ignition_temp, flame_max_temp);
-}
-
-extern "C" void smoke_initWaveletBlenderRNA(WTURBULENCE *wt, float *strength)
-{
- wt->initBlenderRNA(strength);
-}
-
-static void data_dissolve(float *density, float *heat, float *r, float *g, float *b, int total_cells, int speed, int log)
-{
- if (log) {
- /* max density/speed = dydx */
- float fac = 1.0f - (1.0f / (float)speed);
-
- for(size_t i = 0; i < total_cells; i++)
- {
- /* density */
- density[i] *= fac;
-
- /* heat */
- if (heat) {
- heat[i] *= fac;
- }
-
- /* color */
- if (r) {
- r[i] *= fac;
- g[i] *= fac;
- b[i] *= fac;
- }
- }
- }
- else // linear falloff
- {
- /* max density/speed = dydx */
- float dydx = 1.0f / (float)speed;
-
- for(size_t i = 0; i < total_cells; i++)
- {
- float d = density[i];
- /* density */
- density[i] -= dydx;
- if (density[i] < 0.0f)
- density[i] = 0.0f;
-
- /* heat */
- if (heat) {
- if (abs(heat[i]) < dydx) heat[i] = 0.0f;
- else if (heat[i] > 0.0f) heat[i] -= dydx;
- else if (heat[i] < 0.0f) heat[i] += dydx;
- }
-
- /* color */
- if (r && d) {
- r[i] *= (density[i]/d);
- g[i] *= (density[i]/d);
- b[i] *= (density[i]/d);
- }
-
- }
- }
-}
-
-extern "C" void smoke_dissolve(FLUID_3D *fluid, int speed, int log)
-{
- data_dissolve(fluid->_density, fluid->_heat, fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_totalCells, speed, log);
-}
-
-extern "C" void smoke_dissolve_wavelet(WTURBULENCE *wt, int speed, int log)
-{
- data_dissolve(wt->_densityBig, 0, wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_totalCellsBig, speed, log);
-}
-
-extern "C" void smoke_export(FLUID_3D *fluid, float *dt, float *dx, float **dens, float **react, float **flame, float **fuel, float **heat,
- float **heatold, float **vx, float **vy, float **vz, float **r, float **g, float **b, unsigned char **obstacles)
-{
- *dens = fluid->_density;
- if(fuel)
- *fuel = fluid->_fuel;
- if(react)
- *react = fluid->_react;
- if(flame)
- *flame = fluid->_flame;
- if(heat)
- *heat = fluid->_heat;
- if(heatold)
- *heatold = fluid->_heatOld;
- *vx = fluid->_xVelocity;
- *vy = fluid->_yVelocity;
- *vz = fluid->_zVelocity;
- if(r)
- *r = fluid->_color_r;
- if(g)
- *g = fluid->_color_g;
- if(b)
- *b = fluid->_color_b;
- *obstacles = fluid->_obstacles;
- *dt = fluid->_dt;
- *dx = fluid->_dx;
-}
-
-extern "C" void smoke_turbulence_export(WTURBULENCE *wt, float **dens, float **react, float **flame, float **fuel,
- float **r, float **g, float **b , float **tcu, float **tcv, float **tcw)
-{
- if (!wt)
- return;
-
- *dens = wt->_densityBig;
- if(fuel)
- *fuel = wt->_fuelBig;
- if(react)
- *react = wt->_reactBig;
- if(flame)
- *flame = wt->_flameBig;
- if(r)
- *r = wt->_color_rBig;
- if(g)
- *g = wt->_color_gBig;
- if(b)
- *b = wt->_color_bBig;
- *tcu = wt->_tcU;
- *tcv = wt->_tcV;
- *tcw = wt->_tcW;
-}
-
-extern "C" float *smoke_get_density(FLUID_3D *fluid)
-{
- return fluid->_density;
-}
-
-extern "C" float *smoke_get_fuel(FLUID_3D *fluid)
-{
- return fluid->_fuel;
-}
-
-extern "C" float *smoke_get_react(FLUID_3D *fluid)
-{
- return fluid->_react;
-}
-
-extern "C" float *smoke_get_heat(FLUID_3D *fluid)
-{
- return fluid->_heat;
-}
-
-extern "C" float *smoke_get_velocity_x(FLUID_3D *fluid)
-{
- return fluid->_xVelocity;
-}
-
-extern "C" float *smoke_get_velocity_y(FLUID_3D *fluid)
-{
- return fluid->_yVelocity;
-}
-
-extern "C" float *smoke_get_velocity_z(FLUID_3D *fluid)
-{
- return fluid->_zVelocity;
-}
-
-extern "C" float *smoke_get_force_x(FLUID_3D *fluid)
-{
- return fluid->_xForce;
-}
-
-extern "C" float *smoke_get_force_y(FLUID_3D *fluid)
-{
- return fluid->_yForce;
-}
-
-extern "C" float *smoke_get_force_z(FLUID_3D *fluid)
-{
- return fluid->_zForce;
-}
-
-extern "C" float *smoke_get_flame(FLUID_3D *fluid)
-{
- return fluid->_flame;
-}
-
-extern "C" float *smoke_get_color_r(FLUID_3D *fluid)
-{
- return fluid->_color_r;
-}
-
-extern "C" float *smoke_get_color_g(FLUID_3D *fluid)
-{
- return fluid->_color_g;
-}
-
-extern "C" float *smoke_get_color_b(FLUID_3D *fluid)
-{
- return fluid->_color_b;
-}
-
-static void get_rgba(float *r, float *g, float *b, float *a, int total_cells, float *data, int sequential)
-{
- int i;
- int m = 4, i_g = 1, i_b = 2, i_a = 3;
- /* sequential data */
- 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;
- }
-}
-
-extern "C" void smoke_get_rgba(FLUID_3D *fluid, float *data, int sequential)
-{
- get_rgba(fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_density, fluid->_totalCells, data, sequential);
-}
-
-extern "C" void smoke_turbulence_get_rgba(WTURBULENCE *wt, float *data, int sequential)
-{
- get_rgba(wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_densityBig, wt->_totalCellsBig, data, sequential);
-}
-
-/* get a single color premultiplied voxel grid */
-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;
- /* sequential data */
- 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;
- }
-}
-
-extern "C" void smoke_get_rgba_from_density(FLUID_3D *fluid, float color[3], float *data, int sequential)
-{
- get_rgba_from_density(color, fluid->_density, fluid->_totalCells, data, sequential);
-}
-
-extern "C" void smoke_turbulence_get_rgba_from_density(WTURBULENCE *wt, float color[3], float *data, int sequential)
-{
- get_rgba_from_density(color, wt->_densityBig, wt->_totalCellsBig, data, sequential);
-}
-
-extern "C" float *smoke_turbulence_get_density(WTURBULENCE *wt)
-{
- return wt ? wt->getDensityBig() : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_fuel(WTURBULENCE *wt)
-{
- return wt ? wt->getFuelBig() : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_react(WTURBULENCE *wt)
-{
- return wt ? wt->_reactBig : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_color_r(WTURBULENCE *wt)
-{
- return wt ? wt->_color_rBig : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_color_g(WTURBULENCE *wt)
-{
- return wt ? wt->_color_gBig : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_color_b(WTURBULENCE *wt)
-{
- return wt ? wt->_color_bBig : NULL;
-}
-
-extern "C" float *smoke_turbulence_get_flame(WTURBULENCE *wt)
-{
- return wt ? wt->getFlameBig() : NULL;
-}
-
-extern "C" void smoke_turbulence_get_res(WTURBULENCE *wt, int *res)
-{
- if (wt) {
- Vec3Int r = wt->getResBig();
- res[0] = r[0];
- res[1] = r[1];
- res[2] = r[2];
- }
-}
-
-extern "C" int smoke_turbulence_get_cells(WTURBULENCE *wt)
-{
- if (wt) {
- Vec3Int r = wt->getResBig();
- return r[0] * r[1] * r[2];
- }
- return 0;
-}
-
-extern "C" unsigned char *smoke_get_obstacle(FLUID_3D *fluid)
-{
- return fluid->_obstacles;
-}
-
-extern "C" void smoke_get_ob_velocity(FLUID_3D *fluid, float **x, float **y, float **z)
-{
- *x = fluid->_xVelocityOb;
- *y = fluid->_yVelocityOb;
- *z = fluid->_zVelocityOb;
-}
-
-#if 0
-extern "C" unsigned char *smoke_get_obstacle_anim(FLUID_3D *fluid)
-{
- return fluid->_obstaclesAnim;
-}
-#endif
-
-extern "C" void smoke_turbulence_set_noise(WTURBULENCE *wt, int type, const char *noisefile_path)
-{
- wt->setNoise(type, noisefile_path);
-}
-
-extern "C" int smoke_has_heat(FLUID_3D *fluid)
-{
- return (fluid->_heat) ? 1 : 0;
-}
-
-extern "C" int smoke_has_fuel(FLUID_3D *fluid)
-{
- return (fluid->_fuel) ? 1 : 0;
-}
-
-extern "C" int smoke_has_colors(FLUID_3D *fluid)
-{
- return (fluid->_color_r && fluid->_color_g && fluid->_color_b) ? 1 : 0;
-}
-
-extern "C" int smoke_turbulence_has_fuel(WTURBULENCE *wt)
-{
- return (wt->_fuelBig) ? 1 : 0;
-}
-
-extern "C" int smoke_turbulence_has_colors(WTURBULENCE *wt)
-{
- return (wt->_color_rBig && wt->_color_gBig && wt->_color_bBig) ? 1 : 0;
-}
-
-/* additional field initialization */
-extern "C" void smoke_ensure_heat(FLUID_3D *fluid)
-{
- if (fluid) {
- fluid->initHeat();
- }
-}
-
-extern "C" void smoke_ensure_fire(FLUID_3D *fluid, WTURBULENCE *wt)
-{
- if (fluid) {
- fluid->initFire();
- }
- if (wt) {
- wt->initFire();
- }
-}
-
-extern "C" void smoke_ensure_colors(FLUID_3D *fluid, WTURBULENCE *wt, float init_r, float init_g, float init_b)
-{
- if (fluid) {
- fluid->initColors(init_r, init_g, init_b);
- }
- if (wt) {
- wt->initColors(init_r, init_g, init_b);
- }
-}
diff --git a/intern/smoke/intern/tnt/jama_eig.h b/intern/smoke/intern/tnt/jama_eig.h
deleted file mode 100644
index 8b1ac999798..00000000000
--- a/intern/smoke/intern/tnt/jama_eig.h
+++ /dev/null
@@ -1,1053 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-#ifndef JAMA_EIG_H
-#define JAMA_EIG_H
-
-
-#include "tnt_array1d.h"
-#include "tnt_array2d.h"
-#include "tnt_math_utils.h"
-
-#include <algorithm>
-// for min(), max() below
-
-#include <cmath>
-// for fabs() below
-
-using namespace TNT;
-using namespace std;
-
-// NT debugging
-//static int gEigenDebug=0;
-//if(gEigenDebug) std::cerr<<"n="<<n<<" m="<<m<<" l="<<l<<"\n";
-// m has to be smaller l! in line 262
-// gcc can get confused with abs calls, replaced by fabs
-
-namespace JAMA
-{
-
-/**
-
- Computes eigenvalues and eigenvectors of a real (non-complex)
- matrix.
-<P>
- If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is
- diagonal and the eigenvector matrix V is orthogonal. That is,
- the diagonal values of D are the eigenvalues, and
- V*V' = I, where I is the identity matrix. The columns of V
- represent the eigenvectors in the sense that A*V = V*D.
-
-<P>
- If A is not symmetric, then the eigenvalue matrix D is block diagonal
- with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
- a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex
- eigenvalues look like
-<pre>
-
- u + iv . . . . .
- . u - iv . . . .
- . . a + ib . . .
- . . . a - ib . .
- . . . . x .
- . . . . . y
-</pre>
- then D looks like
-<pre>
-
- u v . . . .
- -v u . . . .
- . . a b . .
- . . -b a . .
- . . . . x .
- . . . . . y
-</pre>
- This keeps V a real matrix in both symmetric and non-symmetric
- cases, and A*V = V*D.
-
-
-
- <p>
- The matrix V may be badly
- conditioned, or even singular, so the validity of the equation
- A = V*D*inverse(V) depends upon the condition number of V.
-
- <p>
- (Adapted from JAMA, a Java Matrix Library, developed by jointly
- by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
-**/
-
-template <class Real>
-class Eigenvalue
-{
-
-
- /** Row and column dimension (square matrix). */
- int n;
-
- int issymmetric; /* boolean*/
-
- /** Arrays for internal storage of eigenvalues. */
-
- TNT::Array1D<Real> d; /* real part */
- TNT::Array1D<Real> e; /* img part */
-
- /** Array for internal storage of eigenvectors. */
- TNT::Array2D<Real> V;
-
- /** Array for internal storage of nonsymmetric Hessenberg form.
- @serial internal storage of nonsymmetric Hessenberg form.
- */
- TNT::Array2D<Real> H;
-
-
- /** Working storage for nonsymmetric algorithm.
- @serial working storage for nonsymmetric algorithm.
- */
- TNT::Array1D<Real> ort;
-
-
- // Symmetric Householder reduction to tridiagonal form.
-
- void tred2() {
-
- // This is derived from the Algol procedures tred2 by
- // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
- // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- for (int j = 0; j < n; j++) {
- d[j] = V[n-1][j];
- }
-
- // Householder reduction to tridiagonal form.
-
- for (int i = n-1; i > 0; i--) {
-
- // Scale to avoid under/overflow.
-
- Real scale = 0.0;
- Real h = 0.0;
- for (int k = 0; k < i; k++) {
- scale = scale + fabs(d[k]);
- }
- if (scale == 0.0) {
- e[i] = d[i-1];
- for (int j = 0; j < i; j++) {
- d[j] = V[i-1][j];
- V[i][j] = 0.0;
- V[j][i] = 0.0;
- }
- } else {
-
- // Generate Householder vector.
-
- for (int k = 0; k < i; k++) {
- d[k] /= scale;
- h += d[k] * d[k];
- }
- Real f = d[i-1];
- Real g = sqrt(h);
- if (f > 0) {
- g = -g;
- }
- e[i] = scale * g;
- h = h - f * g;
- d[i-1] = f - g;
- for (int j = 0; j < i; j++) {
- e[j] = 0.0;
- }
-
- // Apply similarity transformation to remaining columns.
-
- for (int j = 0; j < i; j++) {
- f = d[j];
- V[j][i] = f;
- g = e[j] + V[j][j] * f;
- for (int k = j+1; k <= i-1; k++) {
- g += V[k][j] * d[k];
- e[k] += V[k][j] * f;
- }
- e[j] = g;
- }
- f = 0.0;
- for (int j = 0; j < i; j++) {
- e[j] /= h;
- f += e[j] * d[j];
- }
- Real hh = f / (h + h);
- for (int j = 0; j < i; j++) {
- e[j] -= hh * d[j];
- }
- for (int j = 0; j < i; j++) {
- f = d[j];
- g = e[j];
- for (int k = j; k <= i-1; k++) {
- V[k][j] -= (f * e[k] + g * d[k]);
- }
- d[j] = V[i-1][j];
- V[i][j] = 0.0;
- }
- }
- d[i] = h;
- }
-
- // Accumulate transformations.
-
- for (int i = 0; i < n-1; i++) {
- V[n-1][i] = V[i][i];
- V[i][i] = 1.0;
- Real h = d[i+1];
- if (h != 0.0) {
- for (int k = 0; k <= i; k++) {
- d[k] = V[k][i+1] / h;
- }
- for (int j = 0; j <= i; j++) {
- Real g = 0.0;
- for (int k = 0; k <= i; k++) {
- g += V[k][i+1] * V[k][j];
- }
- for (int k = 0; k <= i; k++) {
- V[k][j] -= g * d[k];
- }
- }
- }
- for (int k = 0; k <= i; k++) {
- V[k][i+1] = 0.0;
- }
- }
- for (int j = 0; j < n; j++) {
- d[j] = V[n-1][j];
- V[n-1][j] = 0.0;
- }
- V[n-1][n-1] = 1.0;
- e[0] = 0.0;
- }
-
- // Symmetric tridiagonal QL algorithm.
-
- void tql2 () {
-
- // This is derived from the Algol procedures tql2, by
- // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
- // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- for (int i = 1; i < n; i++) {
- e[i-1] = e[i];
- }
- e[n-1] = 0.0;
-
- Real f = 0.0;
- Real tst1 = 0.0;
- Real eps = pow(2.0,-52.0);
- for (int l = 0; l < n; l++) {
-
- // Find small subdiagonal element
-
- tst1 = max(tst1,fabs(d[l]) + fabs(e[l]));
- int m = l;
-
- // Original while-loop from Java code
- while (m < n) {
- if (fabs(e[m]) <= eps*tst1) {
- break;
- }
- m++;
- }
-
-
- // If m == l, d[l] is an eigenvalue,
- // otherwise, iterate.
-
- if (m > l) {
- int iter = 0;
- do {
- iter = iter + 1; // (Could check iteration count here.)
-
- // Compute implicit shift
-
- Real g = d[l];
- Real p = (d[l+1] - g) / (2.0 * e[l]);
- Real r = hypot(p,1.0);
- if (p < 0) {
- r = -r;
- }
- d[l] = e[l] / (p + r);
- d[l+1] = e[l] * (p + r);
- Real dl1 = d[l+1];
- Real h = g - d[l];
- for (int i = l+2; i < n; i++) {
- d[i] -= h;
- }
- f = f + h;
-
- // Implicit QL transformation.
-
- p = d[m];
- Real c = 1.0;
- Real c2 = c;
- Real c3 = c;
- Real el1 = e[l+1];
- Real s = 0.0;
- Real s2 = 0.0;
- for (int i = m-1; i >= l; i--) {
- c3 = c2;
- c2 = c;
- s2 = s;
- g = c * e[i];
- h = c * p;
- r = hypot(p,e[i]);
- e[i+1] = s * r;
- s = e[i] / r;
- c = p / r;
- p = c * d[i] - s * g;
- d[i+1] = h + s * (c * g + s * d[i]);
-
- // Accumulate transformation.
-
- for (int k = 0; k < n; k++) {
- h = V[k][i+1];
- V[k][i+1] = s * V[k][i] + c * h;
- V[k][i] = c * V[k][i] - s * h;
- }
- }
- p = -s * s2 * c3 * el1 * e[l] / dl1;
- e[l] = s * p;
- d[l] = c * p;
-
- // Check for convergence.
-
- } while (fabs(e[l]) > eps*tst1);
- }
- d[l] = d[l] + f;
- e[l] = 0.0;
- }
-
- // Sort eigenvalues and corresponding vectors.
-
- for (int i = 0; i < n-1; i++) {
- int k = i;
- Real p = d[i];
- for (int j = i+1; j < n; j++) {
- if (d[j] < p) {
- k = j;
- p = d[j];
- }
- }
- if (k != i) {
- d[k] = d[i];
- d[i] = p;
- for (int j = 0; j < n; j++) {
- p = V[j][i];
- V[j][i] = V[j][k];
- V[j][k] = p;
- }
- }
- }
- }
-
- // Nonsymmetric reduction to Hessenberg form.
-
- void orthes () {
-
- // This is derived from the Algol procedures orthes and ortran,
- // by Martin and Wilkinson, Handbook for Auto. Comp.,
- // Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutines in EISPACK.
-
- int low = 0;
- int high = n-1;
-
- for (int m = low+1; m <= high-1; m++) {
-
- // Scale column.
-
- Real scale = 0.0;
- for (int i = m; i <= high; i++) {
- scale = scale + fabs(H[i][m-1]);
- }
- if (scale != 0.0) {
-
- // Compute Householder transformation.
-
- Real h = 0.0;
- for (int i = high; i >= m; i--) {
- ort[i] = H[i][m-1]/scale;
- h += ort[i] * ort[i];
- }
- Real g = sqrt(h);
- if (ort[m] > 0) {
- g = -g;
- }
- h = h - ort[m] * g;
- ort[m] = ort[m] - g;
-
- // Apply Householder similarity transformation
- // H = (I-u*u'/h)*H*(I-u*u')/h)
-
- for (int j = m; j < n; j++) {
- Real f = 0.0;
- for (int i = high; i >= m; i--) {
- f += ort[i]*H[i][j];
- }
- f = f/h;
- for (int i = m; i <= high; i++) {
- H[i][j] -= f*ort[i];
- }
- }
-
- for (int i = 0; i <= high; i++) {
- Real f = 0.0;
- for (int j = high; j >= m; j--) {
- f += ort[j]*H[i][j];
- }
- f = f/h;
- for (int j = m; j <= high; j++) {
- H[i][j] -= f*ort[j];
- }
- }
- ort[m] = scale*ort[m];
- H[m][m-1] = scale*g;
- }
- }
-
- // Accumulate transformations (Algol's ortran).
-
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- V[i][j] = (i == j ? 1.0 : 0.0);
- }
- }
-
- for (int m = high-1; m >= low+1; m--) {
- if (H[m][m-1] != 0.0) {
- for (int i = m+1; i <= high; i++) {
- ort[i] = H[i][m-1];
- }
- for (int j = m; j <= high; j++) {
- Real g = 0.0;
- for (int i = m; i <= high; i++) {
- g += ort[i] * V[i][j];
- }
- // Double division avoids possible underflow
- g = (g / ort[m]) / H[m][m-1];
- for (int i = m; i <= high; i++) {
- V[i][j] += g * ort[i];
- }
- }
- }
- }
- }
-
-
- // Complex scalar division.
-
- Real cdivr, cdivi;
- void cdiv(Real xr, Real xi, Real yr, Real yi) {
- Real r,d;
- if (fabs(yr) > fabs(yi)) {
- r = yi/yr;
- d = yr + r*yi;
- cdivr = (xr + r*xi)/d;
- cdivi = (xi - r*xr)/d;
- } else {
- r = yr/yi;
- d = yi + r*yr;
- cdivr = (r*xr + xi)/d;
- cdivi = (r*xi - xr)/d;
- }
- }
-
-
- // Nonsymmetric reduction from Hessenberg to real Schur form.
-
- void hqr2 () {
-
- // This is derived from the Algol procedure hqr2,
- // by Martin and Wilkinson, Handbook for Auto. Comp.,
- // Vol.ii-Linear Algebra, and the corresponding
- // Fortran subroutine in EISPACK.
-
- // Initialize
-
- int nn = this->n;
- int n = nn-1;
- int low = 0;
- int high = nn-1;
- Real eps = pow(2.0,-52.0);
- Real exshift = 0.0;
- Real p=0,q=0,r=0,s=0,z=0,t,w,x,y;
-
- // Store roots isolated by balanc and compute matrix norm
-
- Real norm = 0.0;
- for (int i = 0; i < nn; i++) {
- if ((i < low) || (i > high)) {
- d[i] = H[i][i];
- e[i] = 0.0;
- }
- for (int j = max(i-1,0); j < nn; j++) {
- norm = norm + fabs(H[i][j]);
- }
- }
-
- // Outer loop over eigenvalue index
-
- int iter = 0;
- int totIter = 0;
- while (n >= low) {
-
- // NT limit no. of iterations
- totIter++;
- if(totIter>100) {
- //if(totIter>15) std::cout<<"!!!!iter ABORT !!!!!!! "<<totIter<<"\n";
- // NT hack/fix, return large eigenvalues
- for (int i = 0; i < nn; i++) {
- d[i] = 10000.;
- e[i] = 10000.;
- }
- return;
- }
-
- // Look for single small sub-diagonal element
-
- int l = n;
- while (l > low) {
- s = fabs(H[l-1][l-1]) + fabs(H[l][l]);
- if (s == 0.0) {
- s = norm;
- }
- if (fabs(H[l][l-1]) < eps * s) {
- break;
- }
- l--;
- }
-
- // Check for convergence
- // One root found
-
- if (l == n) {
- H[n][n] = H[n][n] + exshift;
- d[n] = H[n][n];
- e[n] = 0.0;
- n--;
- iter = 0;
-
- // Two roots found
-
- } else if (l == n-1) {
- w = H[n][n-1] * H[n-1][n];
- p = (H[n-1][n-1] - H[n][n]) / 2.0;
- q = p * p + w;
- z = sqrt(fabs(q));
- H[n][n] = H[n][n] + exshift;
- H[n-1][n-1] = H[n-1][n-1] + exshift;
- x = H[n][n];
-
- // Real pair
-
- if (q >= 0) {
- if (p >= 0) {
- z = p + z;
- } else {
- z = p - z;
- }
- d[n-1] = x + z;
- d[n] = d[n-1];
- if (z != 0.0) {
- d[n] = x - w / z;
- }
- e[n-1] = 0.0;
- e[n] = 0.0;
- x = H[n][n-1];
- s = fabs(x) + fabs(z);
- p = x / s;
- q = z / s;
- r = sqrt(p * p+q * q);
- p = p / r;
- q = q / r;
-
- // Row modification
-
- for (int j = n-1; j < nn; j++) {
- z = H[n-1][j];
- H[n-1][j] = q * z + p * H[n][j];
- H[n][j] = q * H[n][j] - p * z;
- }
-
- // Column modification
-
- for (int i = 0; i <= n; i++) {
- z = H[i][n-1];
- H[i][n-1] = q * z + p * H[i][n];
- H[i][n] = q * H[i][n] - p * z;
- }
-
- // Accumulate transformations
-
- for (int i = low; i <= high; i++) {
- z = V[i][n-1];
- V[i][n-1] = q * z + p * V[i][n];
- V[i][n] = q * V[i][n] - p * z;
- }
-
- // Complex pair
-
- } else {
- d[n-1] = x + p;
- d[n] = x + p;
- e[n-1] = z;
- e[n] = -z;
- }
- n = n - 2;
- iter = 0;
-
- // No convergence yet
-
- } else {
-
- // Form shift
-
- x = H[n][n];
- y = 0.0;
- w = 0.0;
- if (l < n) {
- y = H[n-1][n-1];
- w = H[n][n-1] * H[n-1][n];
- }
-
- // Wilkinson's original ad hoc shift
-
- if (iter == 10) {
- exshift += x;
- for (int i = low; i <= n; i++) {
- H[i][i] -= x;
- }
- s = fabs(H[n][n-1]) + fabs(H[n-1][n-2]);
- x = y = 0.75 * s;
- w = -0.4375 * s * s;
- }
-
- // MATLAB's new ad hoc shift
-
- if (iter == 30) {
- s = (y - x) / 2.0;
- s = s * s + w;
- if (s > 0) {
- s = sqrt(s);
- if (y < x) {
- s = -s;
- }
- s = x - w / ((y - x) / 2.0 + s);
- for (int i = low; i <= n; i++) {
- H[i][i] -= s;
- }
- exshift += s;
- x = y = w = 0.964;
- }
- }
-
- iter = iter + 1; // (Could check iteration count here.)
-
- // Look for two consecutive small sub-diagonal elements
-
- int m = n-2;
- while (m >= l) {
- z = H[m][m];
- r = x - z;
- s = y - z;
- p = (r * s - w) / H[m+1][m] + H[m][m+1];
- q = H[m+1][m+1] - z - r - s;
- r = H[m+2][m+1];
- s = fabs(p) + fabs(q) + fabs(r);
- p = p / s;
- q = q / s;
- r = r / s;
- if (m == l) {
- break;
- }
- if (fabs(H[m][m-1]) * (fabs(q) + fabs(r)) <
- eps * (fabs(p) * (fabs(H[m-1][m-1]) + fabs(z) +
- fabs(H[m+1][m+1])))) {
- break;
- }
- m--;
- }
-
- for (int i = m+2; i <= n; i++) {
- H[i][i-2] = 0.0;
- if (i > m+2) {
- H[i][i-3] = 0.0;
- }
- }
-
- // Double QR step involving rows l:n and columns m:n
-
- for (int k = m; k <= n-1; k++) {
- int notlast = (k != n-1);
- if (k != m) {
- p = H[k][k-1];
- q = H[k+1][k-1];
- r = (notlast ? H[k+2][k-1] : 0.0);
- x = fabs(p) + fabs(q) + fabs(r);
- if (x != 0.0) {
- p = p / x;
- q = q / x;
- r = r / x;
- }
- }
- if (x == 0.0) {
- break;
- }
- s = sqrt(p * p + q * q + r * r);
- if (p < 0) {
- s = -s;
- }
- if (s != 0) {
- if (k != m) {
- H[k][k-1] = -s * x;
- } else if (l != m) {
- H[k][k-1] = -H[k][k-1];
- }
- p = p + s;
- x = p / s;
- y = q / s;
- z = r / s;
- q = q / p;
- r = r / p;
-
- // Row modification
-
- for (int j = k; j < nn; j++) {
- p = H[k][j] + q * H[k+1][j];
- if (notlast) {
- p = p + r * H[k+2][j];
- H[k+2][j] = H[k+2][j] - p * z;
- }
- H[k][j] = H[k][j] - p * x;
- H[k+1][j] = H[k+1][j] - p * y;
- }
-
- // Column modification
-
- for (int i = 0; i <= min(n,k+3); i++) {
- p = x * H[i][k] + y * H[i][k+1];
- if (notlast) {
- p = p + z * H[i][k+2];
- H[i][k+2] = H[i][k+2] - p * r;
- }
- H[i][k] = H[i][k] - p;
- H[i][k+1] = H[i][k+1] - p * q;
- }
-
- // Accumulate transformations
-
- for (int i = low; i <= high; i++) {
- p = x * V[i][k] + y * V[i][k+1];
- if (notlast) {
- p = p + z * V[i][k+2];
- V[i][k+2] = V[i][k+2] - p * r;
- }
- V[i][k] = V[i][k] - p;
- V[i][k+1] = V[i][k+1] - p * q;
- }
- } // (s != 0)
- } // k loop
- } // check convergence
- } // while (n >= low)
- //if(totIter>15) std::cout<<"!!!!iter "<<totIter<<"\n";
-
- // Backsubstitute to find vectors of upper triangular form
-
- if (norm == 0.0) {
- return;
- }
-
- for (n = nn-1; n >= 0; n--) {
- p = d[n];
- q = e[n];
-
- // Real vector
-
- if (q == 0) {
- int l = n;
- H[n][n] = 1.0;
- for (int i = n-1; i >= 0; i--) {
- w = H[i][i] - p;
- r = 0.0;
- for (int j = l; j <= n; j++) {
- r = r + H[i][j] * H[j][n];
- }
- if (e[i] < 0.0) {
- z = w;
- s = r;
- } else {
- l = i;
- if (e[i] == 0.0) {
- if (w != 0.0) {
- H[i][n] = -r / w;
- } else {
- H[i][n] = -r / (eps * norm);
- }
-
- // Solve real equations
-
- } else {
- x = H[i][i+1];
- y = H[i+1][i];
- q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
- t = (x * s - z * r) / q;
- H[i][n] = t;
- if (fabs(x) > fabs(z)) {
- H[i+1][n] = (-r - w * t) / x;
- } else {
- H[i+1][n] = (-s - y * t) / z;
- }
- }
-
- // Overflow control
-
- t = fabs(H[i][n]);
- if ((eps * t) * t > 1) {
- for (int j = i; j <= n; j++) {
- H[j][n] = H[j][n] / t;
- }
- }
- }
- }
-
- // Complex vector
-
- } else if (q < 0) {
- int l = n-1;
-
- // Last vector component imaginary so matrix is triangular
-
- if (fabs(H[n][n-1]) > fabs(H[n-1][n])) {
- H[n-1][n-1] = q / H[n][n-1];
- H[n-1][n] = -(H[n][n] - p) / H[n][n-1];
- } else {
- cdiv(0.0,-H[n-1][n],H[n-1][n-1]-p,q);
- H[n-1][n-1] = cdivr;
- H[n-1][n] = cdivi;
- }
- H[n][n-1] = 0.0;
- H[n][n] = 1.0;
- for (int i = n-2; i >= 0; i--) {
- Real ra,sa,vr,vi;
- ra = 0.0;
- sa = 0.0;
- for (int j = l; j <= n; j++) {
- ra = ra + H[i][j] * H[j][n-1];
- sa = sa + H[i][j] * H[j][n];
- }
- w = H[i][i] - p;
-
- if (e[i] < 0.0) {
- z = w;
- r = ra;
- s = sa;
- } else {
- l = i;
- if (e[i] == 0) {
- cdiv(-ra,-sa,w,q);
- H[i][n-1] = cdivr;
- H[i][n] = cdivi;
- } else {
-
- // Solve complex equations
-
- x = H[i][i+1];
- y = H[i+1][i];
- vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
- vi = (d[i] - p) * 2.0 * q;
- if ((vr == 0.0) && (vi == 0.0)) {
- vr = eps * norm * (fabs(w) + fabs(q) +
- fabs(x) + fabs(y) + fabs(z));
- }
- cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
- H[i][n-1] = cdivr;
- H[i][n] = cdivi;
- if (fabs(x) > (fabs(z) + fabs(q))) {
- H[i+1][n-1] = (-ra - w * H[i][n-1] + q * H[i][n]) / x;
- H[i+1][n] = (-sa - w * H[i][n] - q * H[i][n-1]) / x;
- } else {
- cdiv(-r-y*H[i][n-1],-s-y*H[i][n],z,q);
- H[i+1][n-1] = cdivr;
- H[i+1][n] = cdivi;
- }
- }
-
- // Overflow control
-
- t = max(fabs(H[i][n-1]),fabs(H[i][n]));
- if ((eps * t) * t > 1) {
- for (int j = i; j <= n; j++) {
- H[j][n-1] = H[j][n-1] / t;
- H[j][n] = H[j][n] / t;
- }
- }
- }
- }
- }
- }
-
- // Vectors of isolated roots
-
- for (int i = 0; i < nn; i++) {
- if (i < low || i > high) {
- for (int j = i; j < nn; j++) {
- V[i][j] = H[i][j];
- }
- }
- }
-
- // Back transformation to get eigenvectors of original matrix
-
- for (int j = nn-1; j >= low; j--) {
- for (int i = low; i <= high; i++) {
- z = 0.0;
- for (int k = low; k <= min(j,high); k++) {
- z = z + V[i][k] * H[k][j];
- }
- V[i][j] = z;
- }
- }
- }
-
-public:
-
-
- /** Check for symmetry, then construct the eigenvalue decomposition
- @param A Square real (non-complex) matrix
- */
-
- Eigenvalue(const TNT::Array2D<Real> &A) {
- n = A.dim2();
- V = Array2D<Real>(n,n);
- d = Array1D<Real>(n);
- e = Array1D<Real>(n);
-
- issymmetric = 1;
- for (int j = 0; (j < n) && issymmetric; j++) {
- for (int i = 0; (i < n) && issymmetric; i++) {
- issymmetric = (A[i][j] == A[j][i]);
- }
- }
-
- if (issymmetric) {
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- V[i][j] = A[i][j];
- }
- }
-
- // Tridiagonalize.
- tred2();
-
- // Diagonalize.
- tql2();
-
- } else {
- H = TNT::Array2D<Real>(n,n);
- ort = TNT::Array1D<Real>(n);
-
- for (int j = 0; j < n; j++) {
- for (int i = 0; i < n; i++) {
- H[i][j] = A[i][j];
- }
- }
-
- // Reduce to Hessenberg form.
- orthes();
-
- // Reduce Hessenberg to real Schur form.
- hqr2();
- }
- }
-
-
- /** Return the eigenvector matrix
- @return V
- */
-
- void getV (TNT::Array2D<Real> &V_) {
- V_ = V;
- return;
- }
-
- /** Return the real parts of the eigenvalues
- @return real(diag(D))
- */
-
- void getRealEigenvalues (TNT::Array1D<Real> &d_) {
- d_ = d;
- return ;
- }
-
- /** Return the imaginary parts of the eigenvalues
- in parameter e_.
-
- @pararm e_: new matrix with imaginary parts of the eigenvalues.
- */
- void getImagEigenvalues (TNT::Array1D<Real> &e_) {
- e_ = e;
- return;
- }
-
-
-/**
- Computes the block diagonal eigenvalue matrix.
- If the original matrix A is not symmetric, then the eigenvalue
- matrix D is block diagonal with the real eigenvalues in 1-by-1
- blocks and any complex eigenvalues,
- a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex
- eigenvalues look like
-<pre>
-
- u + iv . . . . .
- . u - iv . . . .
- . . a + ib . . .
- . . . a - ib . .
- . . . . x .
- . . . . . y
-</pre>
- then D looks like
-<pre>
-
- u v . . . .
- -v u . . . .
- . . a b . .
- . . -b a . .
- . . . . x .
- . . . . . y
-</pre>
- This keeps V a real matrix in both symmetric and non-symmetric
- cases, and A*V = V*D.
-
- @param D: upon return, the matrix is filled with the block diagonal
- eigenvalue matrix.
-
-*/
- void getD (TNT::Array2D<Real> &D) {
- D = Array2D<Real>(n,n);
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- D[i][j] = 0.0;
- }
- D[i][i] = d[i];
- if (e[i] > 0) {
- D[i][i+1] = e[i];
- } else if (e[i] < 0) {
- D[i][i-1] = e[i];
- }
- }
- }
-};
-
-} //namespace JAMA
-
-
-#endif
-// JAMA_EIG_H
diff --git a/intern/smoke/intern/tnt/jama_lu.h b/intern/smoke/intern/tnt/jama_lu.h
deleted file mode 100644
index 7855c060eca..00000000000
--- a/intern/smoke/intern/tnt/jama_lu.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-#ifndef JAMA_LU_H
-#define JAMA_LU_H
-
-#include "tnt.h"
-#include <algorithm>
-//for min(), max() below
-
-using namespace TNT;
-using namespace std;
-
-namespace JAMA
-{
-
- /** LU Decomposition.
- <P>
- For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
- unit lower triangular matrix L, an n-by-n upper triangular matrix U,
- and a permutation vector piv of length m so that A(piv,:) = L*U.
- If m < n, then L is m-by-m and U is m-by-n.
- <P>
- The LU decompostion with pivoting always exists, even if the matrix is
- singular, so the constructor will never fail. The primary use of the
- LU decomposition is in the solution of square systems of simultaneous
- linear equations. This will fail if isNonsingular() returns false.
- */
-template <class Real>
-class LU
-{
-
-
-
- /* Array for internal storage of decomposition. */
- Array2D<Real> LU_;
- int m, n, pivsign;
- Array1D<int> piv;
-
-
- Array2D<Real> permute_copy(const Array2D<Real> &A,
- const Array1D<int> &piv, int j0, int j1)
- {
- int piv_length = piv.dim();
-
- Array2D<Real> X(piv_length, j1-j0+1);
-
-
- for (int i = 0; i < piv_length; i++)
- for (int j = j0; j <= j1; j++)
- X[i][j-j0] = A[piv[i]][j];
-
- return X;
- }
-
- Array1D<Real> permute_copy(const Array1D<Real> &A,
- const Array1D<int> &piv)
- {
- int piv_length = piv.dim();
- if (piv_length != A.dim())
- return Array1D<Real>();
-
- Array1D<Real> x(piv_length);
-
-
- for (int i = 0; i < piv_length; i++)
- x[i] = A[piv[i]];
-
- return x;
- }
-
-
- public :
-
- /** LU Decomposition
- @param A Rectangular matrix
- @return LU Decomposition object to access L, U and piv.
- */
-
- LU (const Array2D<Real> &A) : LU_(A.copy()), m(A.dim1()), n(A.dim2()),
- piv(A.dim1())
-
- {
-
- // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
-
-
- for (int i = 0; i < m; i++) {
- piv[i] = i;
- }
- pivsign = 1;
- Real *LUrowi = 0;;
- Array1D<Real> LUcolj(m);
-
- // Outer loop.
-
- for (int j = 0; j < n; j++) {
-
- // Make a copy of the j-th column to localize references.
-
- for (int i = 0; i < m; i++) {
- LUcolj[i] = LU_[i][j];
- }
-
- // Apply previous transformations.
-
- for (int i = 0; i < m; i++) {
- LUrowi = LU_[i];
-
- // Most of the time is spent in the following dot product.
-
- int kmax = min(i,j);
- double s = 0.0;
- for (int k = 0; k < kmax; k++) {
- s += LUrowi[k]*LUcolj[k];
- }
-
- LUrowi[j] = LUcolj[i] -= s;
- }
-
- // Find pivot and exchange if necessary.
-
- int p = j;
- for (int i = j+1; i < m; i++) {
- if (abs(LUcolj[i]) > abs(LUcolj[p])) {
- p = i;
- }
- }
- if (p != j) {
- int k=0;
- for (k = 0; k < n; k++) {
- double t = LU_[p][k];
- LU_[p][k] = LU_[j][k];
- LU_[j][k] = t;
- }
- k = piv[p];
- piv[p] = piv[j];
- piv[j] = k;
- pivsign = -pivsign;
- }
-
- // Compute multipliers.
-
- if ((j < m) && (LU_[j][j] != 0.0)) {
- for (int i = j+1; i < m; i++) {
- LU_[i][j] /= LU_[j][j];
- }
- }
- }
- }
-
-
- /** Is the matrix nonsingular?
- @return 1 (true) if upper triangular factor U (and hence A)
- is nonsingular, 0 otherwise.
- */
-
- int isNonsingular () {
- for (int j = 0; j < n; j++) {
- if (LU_[j][j] == 0)
- return 0;
- }
- return 1;
- }
-
- /** Return lower triangular factor
- @return L
- */
-
- Array2D<Real> getL () {
- Array2D<Real> L_(m,n);
- for (int i = 0; i < m; i++) {
- for (int j = 0; j < n; j++) {
- if (i > j) {
- L_[i][j] = LU_[i][j];
- } else if (i == j) {
- L_[i][j] = 1.0;
- } else {
- L_[i][j] = 0.0;
- }
- }
- }
- return L_;
- }
-
- /** Return upper triangular factor
- @return U portion of LU factorization.
- */
-
- Array2D<Real> getU () {
- Array2D<Real> U_(n,n);
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- if (i <= j) {
- U_[i][j] = LU_[i][j];
- } else {
- U_[i][j] = 0.0;
- }
- }
- }
- return U_;
- }
-
- /** Return pivot permutation vector
- @return piv
- */
-
- Array1D<int> getPivot () {
- return piv;
- }
-
-
- /** Compute determinant using LU factors.
- @return determinant of A, or 0 if A is not square.
- */
-
- Real det () {
- if (m != n) {
- return Real(0);
- }
- Real d = Real(pivsign);
- for (int j = 0; j < n; j++) {
- d *= LU_[j][j];
- }
- return d;
- }
-
- /** Solve A*X = B
- @param B A Matrix with as many rows as A and any number of columns.
- @return X so that L*U*X = B(piv,:), if B is nonconformant, returns
- 0x0 (null) array.
- */
-
- Array2D<Real> solve (const Array2D<Real> &B)
- {
-
- /* Dimensions: A is mxn, X is nxk, B is mxk */
-
- if (B.dim1() != m) {
- return Array2D<Real>(0,0);
- }
- if (!isNonsingular()) {
- return Array2D<Real>(0,0);
- }
-
- // Copy right hand side with pivoting
- int nx = B.dim2();
-
-
- Array2D<Real> X = permute_copy(B, piv, 0, nx-1);
-
- // Solve L*Y = B(piv,:)
- for (int k = 0; k < n; k++) {
- for (int i = k+1; i < n; i++) {
- for (int j = 0; j < nx; j++) {
- X[i][j] -= X[k][j]*LU_[i][k];
- }
- }
- }
- // Solve U*X = Y;
- for (int k = n-1; k >= 0; k--) {
- for (int j = 0; j < nx; j++) {
- X[k][j] /= LU_[k][k];
- }
- for (int i = 0; i < k; i++) {
- for (int j = 0; j < nx; j++) {
- X[i][j] -= X[k][j]*LU_[i][k];
- }
- }
- }
- return X;
- }
-
-
- /** Solve A*x = b, where x and b are vectors of length equal
- to the number of rows in A.
-
- @param b a vector (Array1D> of length equal to the first dimension
- of A.
- @return x a vector (Array1D> so that L*U*x = b(piv), if B is nonconformant,
- returns 0x0 (null) array.
- */
-
- Array1D<Real> solve (const Array1D<Real> &b)
- {
-
- /* Dimensions: A is mxn, X is nxk, B is mxk */
-
- if (b.dim1() != m) {
- return Array1D<Real>();
- }
- if (!isNonsingular()) {
- return Array1D<Real>();
- }
-
-
- Array1D<Real> x = permute_copy(b, piv);
-
- // Solve L*Y = B(piv)
- for (int k = 0; k < n; k++) {
- for (int i = k+1; i < n; i++) {
- x[i] -= x[k]*LU_[i][k];
- }
- }
-
- // Solve U*X = Y;
- for (int k = n-1; k >= 0; k--) {
- x[k] /= LU_[k][k];
- for (int i = 0; i < k; i++)
- x[i] -= x[k]*LU_[i][k];
- }
-
-
- return x;
- }
-
-}; /* class LU */
-
-} /* namespace JAMA */
-
-#endif
-/* JAMA_LU_H */
diff --git a/intern/smoke/intern/tnt/tnt.h b/intern/smoke/intern/tnt/tnt.h
deleted file mode 100644
index ef9de784bb3..00000000000
--- a/intern/smoke/intern/tnt/tnt.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_H
-#define TNT_H
-
-
-
-//---------------------------------------------------------------------
-// Define this macro if you want TNT to track some of the out-of-bounds
-// indexing. This can encur a small run-time overhead, but is recommended
-// while developing code. It can be turned off for production runs.
-//
-// #define TNT_BOUNDS_CHECK
-//---------------------------------------------------------------------
-//
-
-//#define TNT_BOUNDS_CHECK
-
-
-
-#include "tnt_version.h"
-#include "tnt_math_utils.h"
-#include "tnt_array1d.h"
-#include "tnt_array2d.h"
-#include "tnt_array3d.h"
-#include "tnt_array1d_utils.h"
-#include "tnt_array2d_utils.h"
-#include "tnt_array3d_utils.h"
-
-#include "tnt_fortran_array1d.h"
-#include "tnt_fortran_array2d.h"
-#include "tnt_fortran_array3d.h"
-#include "tnt_fortran_array1d_utils.h"
-#include "tnt_fortran_array2d_utils.h"
-#include "tnt_fortran_array3d_utils.h"
-
-#include "tnt_sparse_matrix_csr.h"
-
-#include "tnt_stopwatch.h"
-#include "tnt_subscript.h"
-#include "tnt_vec.h"
-#include "tnt_cmat.h"
-
-
-#endif
-// TNT_H
diff --git a/intern/smoke/intern/tnt/tnt_array1d.h b/intern/smoke/intern/tnt/tnt_array1d.h
deleted file mode 100644
index 999cbd08d24..00000000000
--- a/intern/smoke/intern/tnt/tnt_array1d.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_ARRAY1D_H
-#define TNT_ARRAY1D_H
-
-//#include <cstdlib>
-#include <iostream>
-
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-
-#include "tnt_i_refvec.h"
-
-namespace TNT
-{
-
-template <class T>
-class Array1D
-{
-
- private:
-
- /* ... */
- i_refvec<T> v_;
- int n_;
- T* data_; /* this normally points to v_.begin(), but
- * could also point to a portion (subvector)
- * of v_.
- */
-
- void copy_(T* p, const T* q, int len) const;
- void set_(T* begin, T* end, const T& val);
-
-
- public:
-
- typedef T value_type;
-
-
- Array1D();
- explicit Array1D(int n);
- Array1D(int n, const T &a);
- Array1D(int n, T *a);
- inline Array1D(const Array1D &A);
- inline operator T*();
- inline operator const T*();
- inline Array1D & operator=(const T &a);
- inline Array1D & operator=(const Array1D &A);
- inline Array1D & ref(const Array1D &A);
- Array1D copy() const;
- Array1D & inject(const Array1D & A);
- inline T& operator[](int i);
- inline const T& operator[](int i) const;
- inline int dim1() const;
- inline int dim() const;
- ~Array1D();
-
-
- /* ... extended interface ... */
-
- inline int ref_count() const;
- inline Array1D<T> subarray(int i0, int i1);
-
-};
-
-
-
-
-template <class T>
-Array1D<T>::Array1D() : v_(), n_(0), data_(0) {}
-
-template <class T>
-Array1D<T>::Array1D(const Array1D<T> &A) : v_(A.v_), n_(A.n_),
- data_(A.data_)
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Array1D(const Array1D<T> &A) \n";
-#endif
-
-}
-
-
-template <class T>
-Array1D<T>::Array1D(int n) : v_(n), n_(n), data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Array1D(int n) \n";
-#endif
-}
-
-template <class T>
-Array1D<T>::Array1D(int n, const T &val) : v_(n), n_(n), data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Array1D(int n, const T& val) \n";
-#endif
- set_(data_, data_+ n, val);
-
-}
-
-template <class T>
-Array1D<T>::Array1D(int n, T *a) : v_(a), n_(n) , data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Array1D(int n, T* a) \n";
-#endif
-}
-
-template <class T>
-inline Array1D<T>::operator T*()
-{
- return &(v_[0]);
-}
-
-
-template <class T>
-inline Array1D<T>::operator const T*()
-{
- return &(v_[0]);
-}
-
-
-
-template <class T>
-inline T& Array1D<T>::operator[](int i)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i>= 0);
- assert(i < n_);
-#endif
- return data_[i];
-}
-
-template <class T>
-inline const T& Array1D<T>::operator[](int i) const
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i>= 0);
- assert(i < n_);
-#endif
- return data_[i];
-}
-
-
-
-
-template <class T>
-Array1D<T> & Array1D<T>::operator=(const T &a)
-{
- set_(data_, data_+n_, a);
- return *this;
-}
-
-template <class T>
-Array1D<T> Array1D<T>::copy() const
-{
- Array1D A( n_);
- copy_(A.data_, data_, n_);
-
- return A;
-}
-
-
-template <class T>
-Array1D<T> & Array1D<T>::inject(const Array1D &A)
-{
- if (A.n_ == n_)
- copy_(data_, A.data_, n_);
-
- return *this;
-}
-
-
-
-
-
-template <class T>
-Array1D<T> & Array1D<T>::ref(const Array1D<T> &A)
-{
- if (this != &A)
- {
- v_ = A.v_; /* operator= handles the reference counting. */
- n_ = A.n_;
- data_ = A.data_;
-
- }
- return *this;
-}
-
-template <class T>
-Array1D<T> & Array1D<T>::operator=(const Array1D<T> &A)
-{
- return ref(A);
-}
-
-template <class T>
-inline int Array1D<T>::dim1() const { return n_; }
-
-template <class T>
-inline int Array1D<T>::dim() const { return n_; }
-
-template <class T>
-Array1D<T>::~Array1D() {}
-
-
-/* ............................ exented interface ......................*/
-
-template <class T>
-inline int Array1D<T>::ref_count() const
-{
- return v_.ref_count();
-}
-
-template <class T>
-inline Array1D<T> Array1D<T>::subarray(int i0, int i1)
-{
- if ((i0 > 0) && (i1 < n_) || (i0 <= i1))
- {
- Array1D<T> X(*this); /* create a new instance of this array. */
- X.n_ = i1-i0+1;
- X.data_ += i0;
-
- return X;
- }
- else
- {
- return Array1D<T>();
- }
-}
-
-
-/* private internal functions */
-
-
-template <class T>
-void Array1D<T>::set_(T* begin, T* end, const T& a)
-{
- for (T* p=begin; p<end; p++)
- *p = a;
-
-}
-
-template <class T>
-void Array1D<T>::copy_(T* p, const T* q, int len) const
-{
- T *end = p + len;
- while (p<end )
- *p++ = *q++;
-
-}
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_ARRAY1D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_array1d_utils.h b/intern/smoke/intern/tnt/tnt_array1d_utils.h
deleted file mode 100644
index 4ff0c803325..00000000000
--- a/intern/smoke/intern/tnt/tnt_array1d_utils.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-#ifndef TNT_ARRAY1D_UTILS_H
-#define TNT_ARRAY1D_UTILS_H
-
-#include <cstdlib>
-#include <cassert>
-
-namespace TNT
-{
-
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Array1D<T> &A)
-{
- int N=A.dim1();
-
-#ifdef TNT_DEBUG
- s << "addr: " << (void *) &A[0] << "\n";
-#endif
- s << N << "\n";
- for (int j=0; j<N; j++)
- {
- s << A[j] << "\n";
- }
- s << "\n";
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Array1D<T> &A)
-{
- int N;
- s >> N;
-
- Array1D<T> B(N);
- for (int i=0; i<N; i++)
- s >> B[i];
- A = B;
- return s;
-}
-
-
-
-template <class T>
-Array1D<T> operator+(const Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Array1D<T>();
-
- else
- {
- Array1D<T> C(n);
-
- for (int i=0; i<n; i++)
- {
- C[i] = A[i] + B[i];
- }
- return C;
- }
-}
-
-
-
-template <class T>
-Array1D<T> operator-(const Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Array1D<T>();
-
- else
- {
- Array1D<T> C(n);
-
- for (int i=0; i<n; i++)
- {
- C[i] = A[i] - B[i];
- }
- return C;
- }
-}
-
-
-template <class T>
-Array1D<T> operator*(const Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Array1D<T>();
-
- else
- {
- Array1D<T> C(n);
-
- for (int i=0; i<n; i++)
- {
- C[i] = A[i] * B[i];
- }
- return C;
- }
-}
-
-
-template <class T>
-Array1D<T> operator/(const Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Array1D<T>();
-
- else
- {
- Array1D<T> C(n);
-
- for (int i=0; i<n; i++)
- {
- C[i] = A[i] / B[i];
- }
- return C;
- }
-}
-
-
-
-
-
-
-
-
-
-template <class T>
-Array1D<T>& operator+=(Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=0; i<n; i++)
- {
- A[i] += B[i];
- }
- }
- return A;
-}
-
-
-
-
-template <class T>
-Array1D<T>& operator-=(Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=0; i<n; i++)
- {
- A[i] -= B[i];
- }
- }
- return A;
-}
-
-
-
-template <class T>
-Array1D<T>& operator*=(Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=0; i<n; i++)
- {
- A[i] *= B[i];
- }
- }
- return A;
-}
-
-
-
-
-template <class T>
-Array1D<T>& operator/=(Array1D<T> &A, const Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=0; i<n; i++)
- {
- A[i] /= B[i];
- }
- }
- return A;
-}
-
-
-
-
-
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_array2d.h b/intern/smoke/intern/tnt/tnt_array2d.h
deleted file mode 100644
index e96beab9367..00000000000
--- a/intern/smoke/intern/tnt/tnt_array2d.h
+++ /dev/null
@@ -1,318 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_ARRAY2D_H
-#define TNT_ARRAY2D_H
-
-#include <cstdlib>
-#include <iostream>
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-#include "tnt_array1d.h"
-
-namespace TNT
-{
-
-template <class T>
-class Array2D
-{
-
-
- private:
-
-
-
- Array1D<T> data_;
- Array1D<T*> v_;
- int m_;
- int n_;
-
- public:
-
- typedef T value_type;
- Array2D();
- Array2D(int m, int n);
- Array2D(int m, int n, T *a);
- Array2D(int m, int n, const T &a);
- inline Array2D(const Array2D &A);
- inline operator T**();
- inline operator const T**();
- inline Array2D & operator=(const T &a);
- inline Array2D & operator=(const Array2D &A);
- inline Array2D & ref(const Array2D &A);
- Array2D copy() const;
- Array2D & inject(const Array2D & A);
- inline T* operator[](int i);
- inline const T* operator[](int i) const;
- inline int dim1() const;
- inline int dim2() const;
- ~Array2D();
-
- /* extended interface (not part of the standard) */
-
-
- inline int ref_count();
- inline int ref_count_data();
- inline int ref_count_dim1();
- Array2D subarray(int i0, int i1, int j0, int j1);
-
-};
-
-
-template <class T>
-Array2D<T>::Array2D() : data_(), v_(), m_(0), n_(0) {}
-
-template <class T>
-Array2D<T>::Array2D(const Array2D<T> &A) : data_(A.data_), v_(A.v_),
- m_(A.m_), n_(A.n_) {}
-
-
-
-
-template <class T>
-Array2D<T>::Array2D(int m, int n) : data_(m*n), v_(m), m_(m), n_(n)
-{
- if (m>0 && n>0)
- {
- T* p = &(data_[0]);
- for (int i=0; i<m; i++)
- {
- v_[i] = p;
- p += n;
- }
- }
-}
-
-
-
-template <class T>
-Array2D<T>::Array2D(int m, int n, const T &val) : data_(m*n), v_(m),
- m_(m), n_(n)
-{
- if (m>0 && n>0)
- {
- data_ = val;
- T* p = &(data_[0]);
- for (int i=0; i<m; i++)
- {
- v_[i] = p;
- p += n;
- }
- }
-}
-
-template <class T>
-Array2D<T>::Array2D(int m, int n, T *a) : data_(m*n, a), v_(m), m_(m), n_(n)
-{
- if (m>0 && n>0)
- {
- T* p = &(data_[0]);
-
- for (int i=0; i<m; i++)
- {
- v_[i] = p;
- p += n;
- }
- }
-}
-
-
-template <class T>
-inline T* Array2D<T>::operator[](int i)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 0);
- assert(i < m_);
-#endif
-
-return v_[i];
-
-}
-
-
-template <class T>
-inline const T* Array2D<T>::operator[](int i) const
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 0);
- assert(i < m_);
-#endif
-
-return v_[i];
-
-}
-
-template <class T>
-Array2D<T> & Array2D<T>::operator=(const T &a)
-{
- /* non-optimzied, but will work with subarrays in future verions */
-
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- v_[i][j] = a;
- return *this;
-}
-
-
-
-
-template <class T>
-Array2D<T> Array2D<T>::copy() const
-{
- Array2D A(m_, n_);
-
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- A[i][j] = v_[i][j];
-
-
- return A;
-}
-
-
-template <class T>
-Array2D<T> & Array2D<T>::inject(const Array2D &A)
-{
- if (A.m_ == m_ && A.n_ == n_)
- {
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- v_[i][j] = A[i][j];
- }
- return *this;
-}
-
-
-
-
-template <class T>
-Array2D<T> & Array2D<T>::ref(const Array2D<T> &A)
-{
- if (this != &A)
- {
- v_ = A.v_;
- data_ = A.data_;
- m_ = A.m_;
- n_ = A.n_;
-
- }
- return *this;
-}
-
-
-
-template <class T>
-Array2D<T> & Array2D<T>::operator=(const Array2D<T> &A)
-{
- return ref(A);
-}
-
-template <class T>
-inline int Array2D<T>::dim1() const { return m_; }
-
-template <class T>
-inline int Array2D<T>::dim2() const { return n_; }
-
-
-template <class T>
-Array2D<T>::~Array2D() {}
-
-
-
-
-template <class T>
-inline Array2D<T>::operator T**()
-{
- return &(v_[0]);
-}
-template <class T>
-inline Array2D<T>::operator const T**()
-{
- return &(v_[0]);
-}
-
-/* ............... extended interface ............... */
-/**
- Create a new view to a subarray defined by the boundaries
- [i0][i0] and [i1][j1]. The size of the subarray is
- (i1-i0) by (j1-j0). If either of these lengths are zero
- or negative, the subarray view is null.
-
-*/
-template <class T>
-Array2D<T> Array2D<T>::subarray(int i0, int i1, int j0, int j1)
-{
- Array2D<T> A;
- int m = i1-i0+1;
- int n = j1-j0+1;
-
- /* if either length is zero or negative, this is an invalide
- subarray. return a null view.
- */
- if (m<1 || n<1)
- return A;
-
- A.data_ = data_;
- A.m_ = m;
- A.n_ = n;
- A.v_ = Array1D<T*>(m);
- T* p = &(data_[0]) + i0 * n_ + j0;
- for (int i=0; i<m; i++)
- {
- A.v_[i] = p + i*n_;
-
- }
- return A;
-}
-
-template <class T>
-inline int Array2D<T>::ref_count()
-{
- return ref_count_data();
-}
-
-
-
-template <class T>
-inline int Array2D<T>::ref_count_data()
-{
- return data_.ref_count();
-}
-
-template <class T>
-inline int Array2D<T>::ref_count_dim1()
-{
- return v_.ref_count();
-}
-
-
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_ARRAY2D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_array2d_utils.h b/intern/smoke/intern/tnt/tnt_array2d_utils.h
deleted file mode 100644
index 63f98073506..00000000000
--- a/intern/smoke/intern/tnt/tnt_array2d_utils.h
+++ /dev/null
@@ -1,290 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_ARRAY2D_UTILS_H
-#define TNT_ARRAY2D_UTILS_H
-
-#include <cstdlib>
-#include <cassert>
-
-namespace TNT
-{
-
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Array2D<T> &A)
-{
- int M=A.dim1();
- int N=A.dim2();
-
- s << M << " " << N << "\n";
-
- for (int i=0; i<M; i++)
- {
- for (int j=0; j<N; j++)
- {
- s << A[i][j] << " ";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Array2D<T> &A)
-{
-
- int M, N;
-
- s >> M >> N;
-
- Array2D<T> B(M,N);
-
- for (int i=0; i<M; i++)
- for (int j=0; j<N; j++)
- {
- s >> B[i][j];
- }
-
- A = B;
- return s;
-}
-
-
-template <class T>
-Array2D<T> operator+(const Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Array2D<T>();
-
- else
- {
- Array2D<T> C(m,n);
-
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- C[i][j] = A[i][j] + B[i][j];
- }
- return C;
- }
-}
-
-template <class T>
-Array2D<T> operator-(const Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Array2D<T>();
-
- else
- {
- Array2D<T> C(m,n);
-
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- C[i][j] = A[i][j] - B[i][j];
- }
- return C;
- }
-}
-
-
-template <class T>
-Array2D<T> operator*(const Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Array2D<T>();
-
- else
- {
- Array2D<T> C(m,n);
-
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- C[i][j] = A[i][j] * B[i][j];
- }
- return C;
- }
-}
-
-
-
-
-template <class T>
-Array2D<T> operator/(const Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Array2D<T>();
-
- else
- {
- Array2D<T> C(m,n);
-
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- C[i][j] = A[i][j] / B[i][j];
- }
- return C;
- }
-}
-
-
-
-
-
-template <class T>
-Array2D<T>& operator+=(Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- A[i][j] += B[i][j];
- }
- }
- return A;
-}
-
-
-
-template <class T>
-Array2D<T>& operator-=(Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- A[i][j] -= B[i][j];
- }
- }
- return A;
-}
-
-
-
-template <class T>
-Array2D<T>& operator*=(Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- A[i][j] *= B[i][j];
- }
- }
- return A;
-}
-
-
-
-
-
-template <class T>
-Array2D<T>& operator/=(Array2D<T> &A, const Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=0; i<m; i++)
- {
- for (int j=0; j<n; j++)
- A[i][j] /= B[i][j];
- }
- }
- return A;
-}
-
-/**
- Matrix Multiply: compute C = A*B, where C[i][j]
- is the dot-product of row i of A and column j of B.
-
-
- @param A an (m x n) array
- @param B an (n x k) array
- @return the (m x k) array A*B, or a null array (0x0)
- if the matrices are non-conformant (i.e. the number
- of columns of A are different than the number of rows of B.)
-
-
-*/
-template <class T>
-Array2D<T> matmult(const Array2D<T> &A, const Array2D<T> &B)
-{
- if (A.dim2() != B.dim1())
- return Array2D<T>();
-
- int M = A.dim1();
- int N = A.dim2();
- int K = B.dim2();
-
- Array2D<T> C(M,K);
-
- for (int i=0; i<M; i++)
- for (int j=0; j<K; j++)
- {
- T sum = 0;
-
- for (int k=0; k<N; k++)
- sum += A[i][k] * B [k][j];
-
- C[i][j] = sum;
- }
-
- return C;
-
-}
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_array3d.h b/intern/smoke/intern/tnt/tnt_array3d.h
deleted file mode 100644
index e62358ea614..00000000000
--- a/intern/smoke/intern/tnt/tnt_array3d.h
+++ /dev/null
@@ -1,299 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_ARRAY3D_H
-#define TNT_ARRAY3D_H
-
-#include <cstdlib>
-#include <iostream>
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-#include "tnt_array1d.h"
-#include "tnt_array2d.h"
-
-namespace TNT
-{
-
-template <class T>
-class Array3D
-{
-
-
- private:
- Array1D<T> data_;
- Array2D<T*> v_;
- int m_;
- int n_;
- int g_;
-
-
- public:
-
- typedef T value_type;
-
- Array3D();
- Array3D(int m, int n, int g);
- Array3D(int m, int n, int g, T val);
- Array3D(int m, int n, int g, T *a);
-
- inline operator T***();
- inline operator const T***();
- inline Array3D(const Array3D &A);
- inline Array3D & operator=(const T &a);
- inline Array3D & operator=(const Array3D &A);
- inline Array3D & ref(const Array3D &A);
- Array3D copy() const;
- Array3D & inject(const Array3D & A);
-
- inline T** operator[](int i);
- inline const T* const * operator[](int i) const;
- inline int dim1() const;
- inline int dim2() const;
- inline int dim3() const;
- ~Array3D();
-
- /* extended interface */
-
- inline int ref_count(){ return data_.ref_count(); }
- Array3D subarray(int i0, int i1, int j0, int j1,
- int k0, int k1);
-};
-
-template <class T>
-Array3D<T>::Array3D() : data_(), v_(), m_(0), n_(0) {}
-
-template <class T>
-Array3D<T>::Array3D(const Array3D<T> &A) : data_(A.data_),
- v_(A.v_), m_(A.m_), n_(A.n_), g_(A.g_)
-{
-}
-
-
-
-template <class T>
-Array3D<T>::Array3D(int m, int n, int g) : data_(m*n*g), v_(m,n),
- m_(m), n_(n), g_(g)
-{
-
- if (m>0 && n>0 && g>0)
- {
- T* p = & (data_[0]);
- int ng = n_*g_;
-
- for (int i=0; i<m_; i++)
- {
- T* ping = p+ i*ng;
- for (int j=0; j<n; j++)
- v_[i][j] = ping + j*g_;
- }
- }
-}
-
-
-
-template <class T>
-Array3D<T>::Array3D(int m, int n, int g, T val) : data_(m*n*g, val),
- v_(m,n), m_(m), n_(n), g_(g)
-{
- if (m>0 && n>0 && g>0)
- {
-
- T* p = & (data_[0]);
- int ng = n_*g_;
-
- for (int i=0; i<m_; i++)
- {
- T* ping = p+ i*ng;
- for (int j=0; j<n; j++)
- v_[i][j] = ping + j*g_;
- }
- }
-}
-
-
-
-template <class T>
-Array3D<T>::Array3D(int m, int n, int g, T* a) :
- data_(m*n*g, a), v_(m,n), m_(m), n_(n), g_(g)
-{
-
- if (m>0 && n>0 && g>0)
- {
- T* p = & (data_[0]);
- int ng = n_*g_;
-
- for (int i=0; i<m_; i++)
- {
- T* ping = p+ i*ng;
- for (int j=0; j<n; j++)
- v_[i][j] = ping + j*g_;
- }
- }
-}
-
-
-
-template <class T>
-inline T** Array3D<T>::operator[](int i)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 0);
- assert(i < m_);
-#endif
-
-return v_[i];
-
-}
-
-template <class T>
-inline const T* const * Array3D<T>::operator[](int i) const
-{ return v_[i]; }
-
-template <class T>
-Array3D<T> & Array3D<T>::operator=(const T &a)
-{
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- for (int k=0; k<g_; k++)
- v_[i][j][k] = a;
-
- return *this;
-}
-
-template <class T>
-Array3D<T> Array3D<T>::copy() const
-{
- Array3D A(m_, n_, g_);
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- for (int k=0; k<g_; k++)
- A.v_[i][j][k] = v_[i][j][k];
-
- return A;
-}
-
-
-template <class T>
-Array3D<T> & Array3D<T>::inject(const Array3D &A)
-{
- if (A.m_ == m_ && A.n_ == n_ && A.g_ == g_)
-
- for (int i=0; i<m_; i++)
- for (int j=0; j<n_; j++)
- for (int k=0; k<g_; k++)
- v_[i][j][k] = A.v_[i][j][k];
-
- return *this;
-}
-
-
-
-template <class T>
-Array3D<T> & Array3D<T>::ref(const Array3D<T> &A)
-{
- if (this != &A)
- {
- m_ = A.m_;
- n_ = A.n_;
- g_ = A.g_;
- v_ = A.v_;
- data_ = A.data_;
- }
- return *this;
-}
-
-template <class T>
-Array3D<T> & Array3D<T>::operator=(const Array3D<T> &A)
-{
- return ref(A);
-}
-
-
-template <class T>
-inline int Array3D<T>::dim1() const { return m_; }
-
-template <class T>
-inline int Array3D<T>::dim2() const { return n_; }
-
-template <class T>
-inline int Array3D<T>::dim3() const { return g_; }
-
-
-
-template <class T>
-Array3D<T>::~Array3D() {}
-
-template <class T>
-inline Array3D<T>::operator T***()
-{
- return v_;
-}
-
-
-template <class T>
-inline Array3D<T>::operator const T***()
-{
- return v_;
-}
-
-/* extended interface */
-template <class T>
-Array3D<T> Array3D<T>::subarray(int i0, int i1, int j0,
- int j1, int k0, int k1)
-{
-
- /* check that ranges are valid. */
- if (!( 0 <= i0 && i0 <= i1 && i1 < m_ &&
- 0 <= j0 && j0 <= j1 && j1 < n_ &&
- 0 <= k0 && k0 <= k1 && k1 < g_))
- return Array3D<T>(); /* null array */
-
-
- Array3D<T> A;
- A.data_ = data_;
- A.m_ = i1-i0+1;
- A.n_ = j1-j0+1;
- A.g_ = k1-k0+1;
- A.v_ = Array2D<T*>(A.m_,A.n_);
- T* p = &(data_[0]) + i0*n_*g_ + j0*g_ + k0;
-
- for (int i=0; i<A.m_; i++)
- {
- T* ping = p + i*n_*g_;
- for (int j=0; j<A.n_; j++)
- A.v_[i][j] = ping + j*g_ ;
- }
-
- return A;
-}
-
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_ARRAY3D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_array3d_utils.h b/intern/smoke/intern/tnt/tnt_array3d_utils.h
deleted file mode 100644
index cbc02365f9a..00000000000
--- a/intern/smoke/intern/tnt/tnt_array3d_utils.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-
-
-#ifndef TNT_ARRAY3D_UTILS_H
-#define TNT_ARRAY3D_UTILS_H
-
-#include <cstdlib>
-#include <cassert>
-
-namespace TNT
-{
-
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Array3D<T> &A)
-{
- int M=A.dim1();
- int N=A.dim2();
- int K=A.dim3();
-
- s << M << " " << N << " " << K << "\n";
-
- for (int i=0; i<M; i++)
- {
- for (int j=0; j<N; j++)
- {
- for (int k=0; k<K; k++)
- s << A[i][j][k] << " ";
- s << "\n";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Array3D<T> &A)
-{
-
- int M, N, K;
-
- s >> M >> N >> K;
-
- Array3D<T> B(M,N,K);
-
- for (int i=0; i<M; i++)
- for (int j=0; j<N; j++)
- for (int k=0; k<K; k++)
- s >> B[i][j][k];
-
- A = B;
- return s;
-}
-
-
-
-template <class T>
-Array3D<T> operator+(const Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Array3D<T>();
-
- else
- {
- Array3D<T> C(m,n,p);
-
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- C[i][j][k] = A[i][j][k] + B[i][j][k];
-
- return C;
- }
-}
-
-
-template <class T>
-Array3D<T> operator-(const Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Array3D<T>();
-
- else
- {
- Array3D<T> C(m,n,p);
-
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- C[i][j][k] = A[i][j][k] - B[i][j][k];
-
- return C;
- }
-}
-
-
-
-
-template <class T>
-Array3D<T> operator*(const Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Array3D<T>();
-
- else
- {
- Array3D<T> C(m,n,p);
-
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- C[i][j][k] = A[i][j][k] * B[i][j][k];
-
- return C;
- }
-}
-
-
-template <class T>
-Array3D<T> operator/(const Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Array3D<T>();
-
- else
- {
- Array3D<T> C(m,n,p);
-
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- C[i][j][k] = A[i][j][k] / B[i][j][k];
-
- return C;
- }
-}
-
-
-
-template <class T>
-Array3D<T>& operator+=(Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- A[i][j][k] += B[i][j][k];
- }
-
- return A;
-}
-
-template <class T>
-Array3D<T>& operator-=(Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- A[i][j][k] -= B[i][j][k];
- }
-
- return A;
-}
-
-template <class T>
-Array3D<T>& operator*=(Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- A[i][j][k] *= B[i][j][k];
- }
-
- return A;
-}
-
-
-template <class T>
-Array3D<T>& operator/=(Array3D<T> &A, const Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=0; i<m; i++)
- for (int j=0; j<n; j++)
- for (int k=0; k<p; k++)
- A[i][j][k] /= B[i][j][k];
- }
-
- return A;
-}
-
-
-
-
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_cmat.h b/intern/smoke/intern/tnt/tnt_cmat.h
deleted file mode 100644
index 34d5412a9b8..00000000000
--- a/intern/smoke/intern/tnt/tnt_cmat.h
+++ /dev/null
@@ -1,583 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-// C compatible matrix: row-oriented, 0-based [i][j] and 1-based (i,j) indexing
-//
-
-#ifndef TNT_CMAT_H
-#define TNT_CMAT_H
-
-#include "tnt_subscript.h"
-#include "tnt_vec.h"
-#include <cstdlib>
-#include <cassert>
-#include <iostream>
-#include <sstream>
-
-namespace TNT
-{
-
-
-template <class T>
-class Matrix
-{
-
-
- public:
-
- typedef Subscript size_type;
- typedef T value_type;
- typedef T element_type;
- typedef T* pointer;
- typedef T* iterator;
- typedef T& reference;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
- Subscript lbound() const { return 1;}
-
- protected:
- Subscript m_;
- Subscript n_;
- Subscript mn_; // total size
- T* v_;
- T** row_;
- T* vm1_ ; // these point to the same data, but are 1-based
- T** rowm1_;
-
- // internal helper function to create the array
- // of row pointers
-
- void initialize(Subscript M, Subscript N)
- {
- mn_ = M*N;
- m_ = M;
- n_ = N;
-
- v_ = new T[mn_];
- row_ = new T*[M];
- rowm1_ = new T*[M];
-
- assert(v_ != NULL);
- assert(row_ != NULL);
- assert(rowm1_ != NULL);
-
- T* p = v_;
- vm1_ = v_ - 1;
- for (Subscript i=0; i<M; i++)
- {
- row_[i] = p;
- rowm1_[i] = p-1;
- p += N ;
-
- }
-
- rowm1_ -- ; // compensate for 1-based offset
- }
-
- void copy(const T* v)
- {
- Subscript N = m_ * n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = v[i];
- v_[i+1] = v[i+1];
- v_[i+2] = v[i+2];
- v_[i+3] = v[i+3];
- }
-
- for (i=N4; i< N; i++)
- v_[i] = v[i];
-#else
-
- for (i=0; i< N; i++)
- v_[i] = v[i];
-#endif
- }
-
- void set(const T& val)
- {
- Subscript N = m_ * n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = val;
- v_[i+1] = val;
- v_[i+2] = val;
- v_[i+3] = val;
- }
-
- for (i=N4; i< N; i++)
- v_[i] = val;
-#else
-
- for (i=0; i< N; i++)
- v_[i] = val;
-
-#endif
- }
-
-
-
- void destroy()
- {
- /* do nothing, if no memory has been previously allocated */
- if (v_ == NULL) return ;
-
- /* if we are here, then matrix was previously allocated */
- if (v_ != NULL) delete [] (v_);
- if (row_ != NULL) delete [] (row_);
-
- /* return rowm1_ back to original value */
- rowm1_ ++;
- if (rowm1_ != NULL ) delete [] (rowm1_);
- }
-
-
- public:
-
- operator T**(){ return row_; }
- operator T**() const { return row_; }
-
-
- Subscript size() const { return mn_; }
-
- // constructors
-
- Matrix() : m_(0), n_(0), mn_(0), v_(0), row_(0), vm1_(0), rowm1_(0) {};
-
- Matrix(const Matrix<T> &A)
- {
- initialize(A.m_, A.n_);
- copy(A.v_);
- }
-
- Matrix(Subscript M, Subscript N, const T& value = T())
- {
- initialize(M,N);
- set(value);
- }
-
- Matrix(Subscript M, Subscript N, const T* v)
- {
- initialize(M,N);
- copy(v);
- }
-
- Matrix(Subscript M, Subscript N, const char *s)
- {
- initialize(M,N);
- //std::istrstream ins(s);
- std::istringstream ins(s);
-
- Subscript i, j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- ins >> row_[i][j];
- }
-
- // destructor
- //
- ~Matrix()
- {
- destroy();
- }
-
-
- // reallocating
- //
- Matrix<T>& newsize(Subscript M, Subscript N)
- {
- if (num_rows() == M && num_cols() == N)
- return *this;
-
- destroy();
- initialize(M,N);
-
- return *this;
- }
-
-
-
-
- // assignments
- //
- Matrix<T>& operator=(const Matrix<T> &A)
- {
- if (v_ == A.v_)
- return *this;
-
- if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc
- copy(A.v_);
-
- else
- {
- destroy();
- initialize(A.m_, A.n_);
- copy(A.v_);
- }
-
- return *this;
- }
-
- Matrix<T>& operator=(const T& scalar)
- {
- set(scalar);
- return *this;
- }
-
-
- Subscript dim(Subscript d) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( d >= 1);
- assert( d <= 2);
-#endif
- return (d==1) ? m_ : ((d==2) ? n_ : 0);
- }
-
- Subscript num_rows() const { return m_; }
- Subscript num_cols() const { return n_; }
-
-
-
-
- inline T* operator[](Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
- assert(i < m_) ;
-#endif
- return row_[i];
- }
-
- inline const T* operator[](Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
- assert(i < m_) ;
-#endif
- return row_[i];
- }
-
- inline reference operator()(Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= mn_) ;
-#endif
- return vm1_[i];
- }
-
- inline const_reference operator()(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= mn_) ;
-#endif
- return vm1_[i];
- }
-
-
-
- inline reference operator()(Subscript i, Subscript j)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= m_) ;
- assert(1<=j);
- assert(j <= n_);
-#endif
- return rowm1_[i][j];
- }
-
-
-
- inline const_reference operator() (Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= m_) ;
- assert(1<=j);
- assert(j <= n_);
-#endif
- return rowm1_[i][j];
- }
-
-
-
-
-};
-
-
-/* *************************** I/O ********************************/
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Matrix<T> &A)
-{
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- s << M << " " << N << "\n";
-
- for (Subscript i=0; i<M; i++)
- {
- for (Subscript j=0; j<N; j++)
- {
- s << A[i][j] << " ";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Matrix<T> &A)
-{
-
- Subscript M, N;
-
- s >> M >> N;
-
- if ( !(M == A.num_rows() && N == A.num_cols() ))
- {
- A.newsize(M,N);
- }
-
-
- for (Subscript i=0; i<M; i++)
- for (Subscript j=0; j<N; j++)
- {
- s >> A[i][j];
- }
-
-
- return s;
-}
-
-// *******************[ basic matrix algorithms ]***************************
-
-
-template <class T>
-Matrix<T> operator+(const Matrix<T> &A,
- const Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- tmp[i][j] = A[i][j] + B[i][j];
-
- return tmp;
-}
-
-template <class T>
-Matrix<T> operator-(const Matrix<T> &A,
- const Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- tmp[i][j] = A[i][j] - B[i][j];
-
- return tmp;
-}
-
-template <class T>
-Matrix<T> mult_element(const Matrix<T> &A,
- const Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- tmp[i][j] = A[i][j] * B[i][j];
-
- return tmp;
-}
-
-
-template <class T>
-Matrix<T> transpose(const Matrix<T> &A)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- Matrix<T> S(N,M);
- Subscript i, j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- S[j][i] = A[i][j];
-
- return S;
-}
-
-
-
-template <class T>
-inline Matrix<T> matmult(const Matrix<T> &A,
- const Matrix<T> &B)
-{
-
-#ifdef TNT_BOUNDS_CHECK
- assert(A.num_cols() == B.num_rows());
-#endif
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
- Subscript K = B.num_cols();
-
- Matrix<T> tmp(M,K);
- T sum;
-
- for (Subscript i=0; i<M; i++)
- for (Subscript k=0; k<K; k++)
- {
- sum = 0;
- for (Subscript j=0; j<N; j++)
- sum = sum + A[i][j] * B[j][k];
-
- tmp[i][k] = sum;
- }
-
- return tmp;
-}
-
-template <class T>
-inline Matrix<T> operator*(const Matrix<T> &A,
- const Matrix<T> &B)
-{
- return matmult(A,B);
-}
-
-template <class T>
-inline int matmult(Matrix<T>& C, const Matrix<T> &A,
- const Matrix<T> &B)
-{
-
- assert(A.num_cols() == B.num_rows());
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
- Subscript K = B.num_cols();
-
- C.newsize(M,K);
-
- T sum;
-
- const T* row_i;
- const T* col_k;
-
- for (Subscript i=0; i<M; i++)
- for (Subscript k=0; k<K; k++)
- {
- row_i = &(A[i][0]);
- col_k = &(B[0][k]);
- sum = 0;
- for (Subscript j=0; j<N; j++)
- {
- sum += *row_i * *col_k;
- row_i++;
- col_k += K;
- }
- C[i][k] = sum;
- }
-
- return 0;
-}
-
-
-template <class T>
-Vector<T> matmult(const Matrix<T> &A, const Vector<T> &x)
-{
-
-#ifdef TNT_BOUNDS_CHECK
- assert(A.num_cols() == x.dim());
-#endif
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- Vector<T> tmp(M);
- T sum;
-
- for (Subscript i=0; i<M; i++)
- {
- sum = 0;
- const T* rowi = A[i];
- for (Subscript j=0; j<N; j++)
- sum = sum + rowi[j] * x[j];
-
- tmp[i] = sum;
- }
-
- return tmp;
-}
-
-template <class T>
-inline Vector<T> operator*(const Matrix<T> &A, const Vector<T> &x)
-{
- return matmult(A,x);
-}
-
-} // namespace TNT
-
-#endif
-// CMAT_H
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array1d.h b/intern/smoke/intern/tnt/tnt_fortran_array1d.h
deleted file mode 100644
index 45a764cf3e0..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array1d.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_FORTRAN_ARRAY1D_H
-#define TNT_FORTRAN_ARRAY1D_H
-
-#include <cstdlib>
-#include <iostream>
-
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-
-#include "tnt_i_refvec.h"
-
-namespace TNT
-{
-
-template <class T>
-class Fortran_Array1D
-{
-
- private:
-
- i_refvec<T> v_;
- int n_;
- T* data_; /* this normally points to v_.begin(), but
- * could also point to a portion (subvector)
- * of v_.
- */
-
- void initialize_(int n);
- void copy_(T* p, const T* q, int len) const;
- void set_(T* begin, T* end, const T& val);
-
-
- public:
-
- typedef T value_type;
-
-
- Fortran_Array1D();
- explicit Fortran_Array1D(int n);
- Fortran_Array1D(int n, const T &a);
- Fortran_Array1D(int n, T *a);
- inline Fortran_Array1D(const Fortran_Array1D &A);
- inline Fortran_Array1D & operator=(const T &a);
- inline Fortran_Array1D & operator=(const Fortran_Array1D &A);
- inline Fortran_Array1D & ref(const Fortran_Array1D &A);
- Fortran_Array1D copy() const;
- Fortran_Array1D & inject(const Fortran_Array1D & A);
- inline T& operator()(int i);
- inline const T& operator()(int i) const;
- inline int dim1() const;
- inline int dim() const;
- ~Fortran_Array1D();
-
-
- /* ... extended interface ... */
-
- inline int ref_count() const;
- inline Fortran_Array1D<T> subarray(int i0, int i1);
-
-};
-
-
-
-
-template <class T>
-Fortran_Array1D<T>::Fortran_Array1D() : v_(), n_(0), data_(0) {}
-
-template <class T>
-Fortran_Array1D<T>::Fortran_Array1D(const Fortran_Array1D<T> &A) : v_(A.v_), n_(A.n_),
- data_(A.data_)
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Fortran_Array1D(const Fortran_Array1D<T> &A) \n";
-#endif
-
-}
-
-
-template <class T>
-Fortran_Array1D<T>::Fortran_Array1D(int n) : v_(n), n_(n), data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Fortran_Array1D(int n) \n";
-#endif
-}
-
-template <class T>
-Fortran_Array1D<T>::Fortran_Array1D(int n, const T &val) : v_(n), n_(n), data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Fortran_Array1D(int n, const T& val) \n";
-#endif
- set_(data_, data_+ n, val);
-
-}
-
-template <class T>
-Fortran_Array1D<T>::Fortran_Array1D(int n, T *a) : v_(a), n_(n) , data_(v_.begin())
-{
-#ifdef TNT_DEBUG
- std::cout << "Created Fortran_Array1D(int n, T* a) \n";
-#endif
-}
-
-template <class T>
-inline T& Fortran_Array1D<T>::operator()(int i)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i>= 1);
- assert(i <= n_);
-#endif
- return data_[i-1];
-}
-
-template <class T>
-inline const T& Fortran_Array1D<T>::operator()(int i) const
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i>= 1);
- assert(i <= n_);
-#endif
- return data_[i-1];
-}
-
-
-
-
-template <class T>
-Fortran_Array1D<T> & Fortran_Array1D<T>::operator=(const T &a)
-{
- set_(data_, data_+n_, a);
- return *this;
-}
-
-template <class T>
-Fortran_Array1D<T> Fortran_Array1D<T>::copy() const
-{
- Fortran_Array1D A( n_);
- copy_(A.data_, data_, n_);
-
- return A;
-}
-
-
-template <class T>
-Fortran_Array1D<T> & Fortran_Array1D<T>::inject(const Fortran_Array1D &A)
-{
- if (A.n_ == n_)
- copy_(data_, A.data_, n_);
-
- return *this;
-}
-
-
-
-
-
-template <class T>
-Fortran_Array1D<T> & Fortran_Array1D<T>::ref(const Fortran_Array1D<T> &A)
-{
- if (this != &A)
- {
- v_ = A.v_; /* operator= handles the reference counting. */
- n_ = A.n_;
- data_ = A.data_;
-
- }
- return *this;
-}
-
-template <class T>
-Fortran_Array1D<T> & Fortran_Array1D<T>::operator=(const Fortran_Array1D<T> &A)
-{
- return ref(A);
-}
-
-template <class T>
-inline int Fortran_Array1D<T>::dim1() const { return n_; }
-
-template <class T>
-inline int Fortran_Array1D<T>::dim() const { return n_; }
-
-template <class T>
-Fortran_Array1D<T>::~Fortran_Array1D() {}
-
-
-/* ............................ exented interface ......................*/
-
-template <class T>
-inline int Fortran_Array1D<T>::ref_count() const
-{
- return v_.ref_count();
-}
-
-template <class T>
-inline Fortran_Array1D<T> Fortran_Array1D<T>::subarray(int i0, int i1)
-{
-#ifdef TNT_DEBUG
- std::cout << "entered subarray. \n";
-#endif
- if ((i0 > 0) && (i1 < n_) || (i0 <= i1))
- {
- Fortran_Array1D<T> X(*this); /* create a new instance of this array. */
- X.n_ = i1-i0+1;
- X.data_ += i0;
-
- return X;
- }
- else
- {
-#ifdef TNT_DEBUG
- std::cout << "subarray: null return.\n";
-#endif
- return Fortran_Array1D<T>();
- }
-}
-
-
-/* private internal functions */
-
-
-template <class T>
-void Fortran_Array1D<T>::set_(T* begin, T* end, const T& a)
-{
- for (T* p=begin; p<end; p++)
- *p = a;
-
-}
-
-template <class T>
-void Fortran_Array1D<T>::copy_(T* p, const T* q, int len) const
-{
- T *end = p + len;
- while (p<end )
- *p++ = *q++;
-
-}
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_FORTRAN_ARRAY1D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array1d_utils.h b/intern/smoke/intern/tnt/tnt_fortran_array1d_utils.h
deleted file mode 100644
index f06b33f1910..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array1d_utils.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-#ifndef TNT_FORTRAN_ARRAY1D_UTILS_H
-#define TNT_FORTRAN_ARRAY1D_UTILS_H
-
-#include <iostream>
-
-namespace TNT
-{
-
-
-/**
- Write an array to a character outstream. Output format is one that can
- be read back in via the in-stream operator: one integer
- denoting the array dimension (n), followed by n elements,
- one per line.
-
-*/
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Fortran_Array1D<T> &A)
-{
- int N=A.dim1();
-
- s << N << "\n";
- for (int j=1; j<=N; j++)
- {
- s << A(j) << "\n";
- }
- s << "\n";
-
- return s;
-}
-
-/**
- Read an array from a character stream. Input format
- is one integer, denoting the dimension (n), followed
- by n whitespace-separated elments. Newlines are ignored
-
- <p>
- Note: the array being read into references new memory
- storage. If the intent is to fill an existing conformant
- array, use <code> cin >> B; A.inject(B) ); </code>
- instead or read the elements in one-a-time by hand.
-
- @param s the charater to read from (typically <code>std::in</code>)
- @param A the array to read into.
-*/
-template <class T>
-std::istream& operator>>(std::istream &s, Fortran_Array1D<T> &A)
-{
- int N;
- s >> N;
-
- Fortran_Array1D<T> B(N);
- for (int i=1; i<=N; i++)
- s >> B(i);
- A = B;
- return s;
-}
-
-
-template <class T>
-Fortran_Array1D<T> operator+(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Fortran_Array1D<T>();
-
- else
- {
- Fortran_Array1D<T> C(n);
-
- for (int i=1; i<=n; i++)
- {
- C(i) = A(i) + B(i);
- }
- return C;
- }
-}
-
-
-
-template <class T>
-Fortran_Array1D<T> operator-(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Fortran_Array1D<T>();
-
- else
- {
- Fortran_Array1D<T> C(n);
-
- for (int i=1; i<=n; i++)
- {
- C(i) = A(i) - B(i);
- }
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array1D<T> operator*(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Fortran_Array1D<T>();
-
- else
- {
- Fortran_Array1D<T> C(n);
-
- for (int i=1; i<=n; i++)
- {
- C(i) = A(i) * B(i);
- }
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array1D<T> operator/(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() != n )
- return Fortran_Array1D<T>();
-
- else
- {
- Fortran_Array1D<T> C(n);
-
- for (int i=1; i<=n; i++)
- {
- C(i) = A(i) / B(i);
- }
- return C;
- }
-}
-
-
-
-
-
-
-
-
-
-template <class T>
-Fortran_Array1D<T>& operator+=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=1; i<=n; i++)
- {
- A(i) += B(i);
- }
- }
- return A;
-}
-
-
-
-
-template <class T>
-Fortran_Array1D<T>& operator-=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=1; i<=n; i++)
- {
- A(i) -= B(i);
- }
- }
- return A;
-}
-
-
-
-template <class T>
-Fortran_Array1D<T>& operator*=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=1; i<=n; i++)
- {
- A(i) *= B(i);
- }
- }
- return A;
-}
-
-
-
-
-template <class T>
-Fortran_Array1D<T>& operator/=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
-{
- int n = A.dim1();
-
- if (B.dim1() == n)
- {
- for (int i=1; i<=n; i++)
- {
- A(i) /= B(i);
- }
- }
- return A;
-}
-
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array2d.h b/intern/smoke/intern/tnt/tnt_fortran_array2d.h
deleted file mode 100644
index 7f14d5436e9..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array2d.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT): Two-dimensional Fortran numerical array
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_FORTRAN_ARRAY2D_H
-#define TNT_FORTRAN_ARRAY2D_H
-
-#include <cstdlib>
-#include <iostream>
-
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-#include "tnt_i_refvec.h"
-
-namespace TNT
-{
-
-template <class T>
-class Fortran_Array2D
-{
-
-
- private:
- i_refvec<T> v_;
- int m_;
- int n_;
- T* data_;
-
-
- void initialize_(int n);
- void copy_(T* p, const T* q, int len);
- void set_(T* begin, T* end, const T& val);
-
- public:
-
- typedef T value_type;
-
- Fortran_Array2D();
- Fortran_Array2D(int m, int n);
- Fortran_Array2D(int m, int n, T *a);
- Fortran_Array2D(int m, int n, const T &a);
- inline Fortran_Array2D(const Fortran_Array2D &A);
- inline Fortran_Array2D & operator=(const T &a);
- inline Fortran_Array2D & operator=(const Fortran_Array2D &A);
- inline Fortran_Array2D & ref(const Fortran_Array2D &A);
- Fortran_Array2D copy() const;
- Fortran_Array2D & inject(const Fortran_Array2D & A);
- inline T& operator()(int i, int j);
- inline const T& operator()(int i, int j) const ;
- inline int dim1() const;
- inline int dim2() const;
- ~Fortran_Array2D();
-
- /* extended interface */
-
- inline int ref_count() const;
-
-};
-
-template <class T>
-Fortran_Array2D<T>::Fortran_Array2D() : v_(), m_(0), n_(0), data_(0) {}
-
-
-template <class T>
-Fortran_Array2D<T>::Fortran_Array2D(const Fortran_Array2D<T> &A) : v_(A.v_),
- m_(A.m_), n_(A.n_), data_(A.data_) {}
-
-
-
-template <class T>
-Fortran_Array2D<T>::Fortran_Array2D(int m, int n) : v_(m*n), m_(m), n_(n),
- data_(v_.begin()) {}
-
-template <class T>
-Fortran_Array2D<T>::Fortran_Array2D(int m, int n, const T &val) :
- v_(m*n), m_(m), n_(n), data_(v_.begin())
-{
- set_(data_, data_+m*n, val);
-}
-
-
-template <class T>
-Fortran_Array2D<T>::Fortran_Array2D(int m, int n, T *a) : v_(a),
- m_(m), n_(n), data_(v_.begin()) {}
-
-
-
-
-template <class T>
-inline T& Fortran_Array2D<T>::operator()(int i, int j)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 1);
- assert(i <= m_);
- assert(j >= 1);
- assert(j <= n_);
-#endif
-
- return v_[ (j-1)*m_ + (i-1) ];
-
-}
-
-template <class T>
-inline const T& Fortran_Array2D<T>::operator()(int i, int j) const
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 1);
- assert(i <= m_);
- assert(j >= 1);
- assert(j <= n_);
-#endif
-
- return v_[ (j-1)*m_ + (i-1) ];
-
-}
-
-
-template <class T>
-Fortran_Array2D<T> & Fortran_Array2D<T>::operator=(const T &a)
-{
- set_(data_, data_+m_*n_, a);
- return *this;
-}
-
-template <class T>
-Fortran_Array2D<T> Fortran_Array2D<T>::copy() const
-{
-
- Fortran_Array2D B(m_,n_);
-
- B.inject(*this);
- return B;
-}
-
-
-template <class T>
-Fortran_Array2D<T> & Fortran_Array2D<T>::inject(const Fortran_Array2D &A)
-{
- if (m_ == A.m_ && n_ == A.n_)
- copy_(data_, A.data_, m_*n_);
-
- return *this;
-}
-
-
-
-template <class T>
-Fortran_Array2D<T> & Fortran_Array2D<T>::ref(const Fortran_Array2D<T> &A)
-{
- if (this != &A)
- {
- v_ = A.v_;
- m_ = A.m_;
- n_ = A.n_;
- data_ = A.data_;
- }
- return *this;
-}
-
-template <class T>
-Fortran_Array2D<T> & Fortran_Array2D<T>::operator=(const Fortran_Array2D<T> &A)
-{
- return ref(A);
-}
-
-template <class T>
-inline int Fortran_Array2D<T>::dim1() const { return m_; }
-
-template <class T>
-inline int Fortran_Array2D<T>::dim2() const { return n_; }
-
-
-template <class T>
-Fortran_Array2D<T>::~Fortran_Array2D()
-{
-}
-
-template <class T>
-inline int Fortran_Array2D<T>::ref_count() const { return v_.ref_count(); }
-
-
-
-
-template <class T>
-void Fortran_Array2D<T>::set_(T* begin, T* end, const T& a)
-{
- for (T* p=begin; p<end; p++)
- *p = a;
-
-}
-
-template <class T>
-void Fortran_Array2D<T>::copy_(T* p, const T* q, int len)
-{
- T *end = p + len;
- while (p<end )
- *p++ = *q++;
-
-}
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_FORTRAN_ARRAY2D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array2d_utils.h b/intern/smoke/intern/tnt/tnt_fortran_array2d_utils.h
deleted file mode 100644
index 078d34c087e..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array2d_utils.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_FORTRAN_ARRAY2D_UTILS_H
-#define TNT_FORTRAN_ARRAY2D_UTILS_H
-
-#include <iostream>
-
-namespace TNT
-{
-
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Fortran_Array2D<T> &A)
-{
- int M=A.dim1();
- int N=A.dim2();
-
- s << M << " " << N << "\n";
-
- for (int i=1; i<=M; i++)
- {
- for (int j=1; j<=N; j++)
- {
- s << A(i,j) << " ";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Fortran_Array2D<T> &A)
-{
-
- int M, N;
-
- s >> M >> N;
-
- Fortran_Array2D<T> B(M,N);
-
- for (int i=1; i<=M; i++)
- for (int j=1; j<=N; j++)
- {
- s >> B(i,j);
- }
-
- A = B;
- return s;
-}
-
-
-
-
-template <class T>
-Fortran_Array2D<T> operator+(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Fortran_Array2D<T>();
-
- else
- {
- Fortran_Array2D<T> C(m,n);
-
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- C(i,j) = A(i,j) + B(i,j);
- }
- return C;
- }
-}
-
-template <class T>
-Fortran_Array2D<T> operator-(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Fortran_Array2D<T>();
-
- else
- {
- Fortran_Array2D<T> C(m,n);
-
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- C(i,j) = A(i,j) - B(i,j);
- }
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array2D<T> operator*(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Fortran_Array2D<T>();
-
- else
- {
- Fortran_Array2D<T> C(m,n);
-
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- C(i,j) = A(i,j) * B(i,j);
- }
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array2D<T> operator/(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() != m || B.dim2() != n )
- return Fortran_Array2D<T>();
-
- else
- {
- Fortran_Array2D<T> C(m,n);
-
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- C(i,j) = A(i,j) / B(i,j);
- }
- return C;
- }
-}
-
-
-
-template <class T>
-Fortran_Array2D<T>& operator+=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- A(i,j) += B(i,j);
- }
- }
- return A;
-}
-
-template <class T>
-Fortran_Array2D<T>& operator-=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- A(i,j) -= B(i,j);
- }
- }
- return A;
-}
-
-template <class T>
-Fortran_Array2D<T>& operator*=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- A(i,j) *= B(i,j);
- }
- }
- return A;
-}
-
-template <class T>
-Fortran_Array2D<T>& operator/=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
-
- if (B.dim1() == m || B.dim2() == n )
- {
- for (int i=1; i<=m; i++)
- {
- for (int j=1; j<=n; j++)
- A(i,j) /= B(i,j);
- }
- }
- return A;
-}
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array3d.h b/intern/smoke/intern/tnt/tnt_fortran_array3d.h
deleted file mode 100644
index ee3de255a15..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array3d.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT): Three-dimensional Fortran numerical array
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_FORTRAN_ARRAY3D_H
-#define TNT_FORTRAN_ARRAY3D_H
-
-#include <cstdlib>
-#include <iostream>
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-#include "tnt_i_refvec.h"
-
-namespace TNT
-{
-
-template <class T>
-class Fortran_Array3D
-{
-
-
- private:
-
-
- i_refvec<T> v_;
- int m_;
- int n_;
- int k_;
- T* data_;
-
- public:
-
- typedef T value_type;
-
- Fortran_Array3D();
- Fortran_Array3D(int m, int n, int k);
- Fortran_Array3D(int m, int n, int k, T *a);
- Fortran_Array3D(int m, int n, int k, const T &a);
- inline Fortran_Array3D(const Fortran_Array3D &A);
- inline Fortran_Array3D & operator=(const T &a);
- inline Fortran_Array3D & operator=(const Fortran_Array3D &A);
- inline Fortran_Array3D & ref(const Fortran_Array3D &A);
- Fortran_Array3D copy() const;
- Fortran_Array3D & inject(const Fortran_Array3D & A);
- inline T& operator()(int i, int j, int k);
- inline const T& operator()(int i, int j, int k) const ;
- inline int dim1() const;
- inline int dim2() const;
- inline int dim3() const;
- inline int ref_count() const;
- ~Fortran_Array3D();
-
-
-};
-
-template <class T>
-Fortran_Array3D<T>::Fortran_Array3D() : v_(), m_(0), n_(0), k_(0), data_(0) {}
-
-
-template <class T>
-Fortran_Array3D<T>::Fortran_Array3D(const Fortran_Array3D<T> &A) :
- v_(A.v_), m_(A.m_), n_(A.n_), k_(A.k_), data_(A.data_) {}
-
-
-
-template <class T>
-Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k) :
- v_(m*n*k), m_(m), n_(n), k_(k), data_(v_.begin()) {}
-
-
-
-template <class T>
-Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k, const T &val) :
- v_(m*n*k), m_(m), n_(n), k_(k), data_(v_.begin())
-{
- for (T* p = data_; p < data_ + m*n*k; p++)
- *p = val;
-}
-
-template <class T>
-Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k, T *a) :
- v_(a), m_(m), n_(n), k_(k), data_(v_.begin()) {}
-
-
-
-
-template <class T>
-inline T& Fortran_Array3D<T>::operator()(int i, int j, int k)
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 1);
- assert(i <= m_);
- assert(j >= 1);
- assert(j <= n_);
- assert(k >= 1);
- assert(k <= k_);
-#endif
-
- return data_[(k-1)*m_*n_ + (j-1) * m_ + i-1];
-
-}
-
-template <class T>
-inline const T& Fortran_Array3D<T>::operator()(int i, int j, int k) const
-{
-#ifdef TNT_BOUNDS_CHECK
- assert(i >= 1);
- assert(i <= m_);
- assert(j >= 1);
- assert(j <= n_);
- assert(k >= 1);
- assert(k <= k_);
-#endif
-
- return data_[(k-1)*m_*n_ + (j-1) * m_ + i-1];
-}
-
-
-template <class T>
-Fortran_Array3D<T> & Fortran_Array3D<T>::operator=(const T &a)
-{
-
- T *end = data_ + m_*n_*k_;
-
- for (T *p=data_; p != end; *p++ = a);
-
- return *this;
-}
-
-template <class T>
-Fortran_Array3D<T> Fortran_Array3D<T>::copy() const
-{
-
- Fortran_Array3D B(m_, n_, k_);
- B.inject(*this);
- return B;
-
-}
-
-
-template <class T>
-Fortran_Array3D<T> & Fortran_Array3D<T>::inject(const Fortran_Array3D &A)
-{
-
- if (m_ == A.m_ && n_ == A.n_ && k_ == A.k_)
- {
- T *p = data_;
- T *end = data_ + m_*n_*k_;
- const T* q = A.data_;
- for (; p < end; *p++ = *q++);
- }
- return *this;
-}
-
-
-
-
-template <class T>
-Fortran_Array3D<T> & Fortran_Array3D<T>::ref(const Fortran_Array3D<T> &A)
-{
-
- if (this != &A)
- {
- v_ = A.v_;
- m_ = A.m_;
- n_ = A.n_;
- k_ = A.k_;
- data_ = A.data_;
- }
- return *this;
-}
-
-template <class T>
-Fortran_Array3D<T> & Fortran_Array3D<T>::operator=(const Fortran_Array3D<T> &A)
-{
- return ref(A);
-}
-
-template <class T>
-inline int Fortran_Array3D<T>::dim1() const { return m_; }
-
-template <class T>
-inline int Fortran_Array3D<T>::dim2() const { return n_; }
-
-template <class T>
-inline int Fortran_Array3D<T>::dim3() const { return k_; }
-
-
-template <class T>
-inline int Fortran_Array3D<T>::ref_count() const
-{
- return v_.ref_count();
-}
-
-template <class T>
-Fortran_Array3D<T>::~Fortran_Array3D()
-{
-}
-
-
-} /* namespace TNT */
-
-#endif
-/* TNT_FORTRAN_ARRAY3D_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_fortran_array3d_utils.h b/intern/smoke/intern/tnt/tnt_fortran_array3d_utils.h
deleted file mode 100644
index d337932380b..00000000000
--- a/intern/smoke/intern/tnt/tnt_fortran_array3d_utils.h
+++ /dev/null
@@ -1,252 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_FORTRAN_ARRAY3D_UTILS_H
-#define TNT_FORTRAN_ARRAY3D_UTILS_H
-
-#include <cstdlib>
-#include <cassert>
-
-namespace TNT
-{
-
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Fortran_Array3D<T> &A)
-{
- int M=A.dim1();
- int N=A.dim2();
- int K=A.dim3();
-
- s << M << " " << N << " " << K << "\n";
-
- for (int i=1; i<=M; i++)
- {
- for (int j=1; j<=N; j++)
- {
- for (int k=1; k<=K; k++)
- s << A(i,j,k) << " ";
- s << "\n";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Fortran_Array3D<T> &A)
-{
-
- int M, N, K;
-
- s >> M >> N >> K;
-
- Fortran_Array3D<T> B(M,N,K);
-
- for (int i=1; i<=M; i++)
- for (int j=1; j<=N; j++)
- for (int k=1; k<=K; k++)
- s >> B(i,j,k);
-
- A = B;
- return s;
-}
-
-
-template <class T>
-Fortran_Array3D<T> operator+(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Fortran_Array3D<T>();
-
- else
- {
- Fortran_Array3D<T> C(m,n,p);
-
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- C(i,j,k) = A(i,j,k)+ B(i,j,k);
-
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array3D<T> operator-(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Fortran_Array3D<T>();
-
- else
- {
- Fortran_Array3D<T> C(m,n,p);
-
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- C(i,j,k) = A(i,j,k)- B(i,j,k);
-
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array3D<T> operator*(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Fortran_Array3D<T>();
-
- else
- {
- Fortran_Array3D<T> C(m,n,p);
-
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- C(i,j,k) = A(i,j,k)* B(i,j,k);
-
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array3D<T> operator/(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
- return Fortran_Array3D<T>();
-
- else
- {
- Fortran_Array3D<T> C(m,n,p);
-
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- C(i,j,k) = A(i,j,k)/ B(i,j,k);
-
- return C;
- }
-}
-
-
-template <class T>
-Fortran_Array3D<T>& operator+=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- A(i,j,k) += B(i,j,k);
- }
-
- return A;
-}
-
-
-template <class T>
-Fortran_Array3D<T>& operator-=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- A(i,j,k) -= B(i,j,k);
- }
-
- return A;
-}
-
-
-template <class T>
-Fortran_Array3D<T>& operator*=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- A(i,j,k) *= B(i,j,k);
- }
-
- return A;
-}
-
-
-template <class T>
-Fortran_Array3D<T>& operator/=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
-{
- int m = A.dim1();
- int n = A.dim2();
- int p = A.dim3();
-
- if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
- {
- for (int i=1; i<=m; i++)
- for (int j=1; j<=n; j++)
- for (int k=1; k<=p; k++)
- A(i,j,k) /= B(i,j,k);
- }
-
- return A;
-}
-
-
-} // namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_i_refvec.h b/intern/smoke/intern/tnt/tnt_i_refvec.h
deleted file mode 100644
index eaf8a4d0e68..00000000000
--- a/intern/smoke/intern/tnt/tnt_i_refvec.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_I_REFVEC_H
-#define TNT_I_REFVEC_H
-
-#include <cstdlib>
-#include <iostream>
-
-#ifdef TNT_BOUNDS_CHECK
-#include <assert.h>
-#endif
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-namespace TNT
-{
-/*
- Internal representation of ref-counted array. The TNT
- arrays all use this building block.
-
- <p>
- If an array block is created by TNT, then every time
- an assignment is made, the left-hand-side reference
- is decreased by one, and the right-hand-side refernce
- count is increased by one. If the array block was
- external to TNT, the refernce count is a NULL pointer
- regardless of how many references are made, since the
- memory is not freed by TNT.
-
-
-
-*/
-template <class T>
-class i_refvec
-{
-
-
- private:
- T* data_;
- int *ref_count_;
-
-
- public:
-
- i_refvec();
- explicit i_refvec(int n);
- inline i_refvec(T* data);
- inline i_refvec(const i_refvec &v);
- inline T* begin();
- inline const T* begin() const;
- inline T& operator[](int i);
- inline const T& operator[](int i) const;
- inline i_refvec<T> & operator=(const i_refvec<T> &V);
- void copy_(T* p, const T* q, const T* e);
- void set_(T* p, const T* b, const T* e);
- inline int ref_count() const;
- inline int is_null() const;
- inline void destroy();
- ~i_refvec();
-
-};
-
-template <class T>
-void i_refvec<T>::copy_(T* p, const T* q, const T* e)
-{
- for (T* t=p; q<e; t++, q++)
- *t= *q;
-}
-
-template <class T>
-i_refvec<T>::i_refvec() : data_(NULL), ref_count_(NULL) {}
-
-/**
- In case n is 0 or negative, it does NOT call new.
-*/
-template <class T>
-i_refvec<T>::i_refvec(int n) : data_(NULL), ref_count_(NULL)
-{
- if (n >= 1)
- {
-#ifdef TNT_DEBUG
- std::cout << "new data storage.\n";
-#endif
- data_ = new T[n];
- ref_count_ = new int;
- *ref_count_ = 1;
- }
-}
-
-template <class T>
-inline i_refvec<T>::i_refvec(const i_refvec<T> &V): data_(V.data_),
- ref_count_(V.ref_count_)
-{
- if (V.ref_count_ != NULL)
- (*(V.ref_count_))++;
-}
-
-
-template <class T>
-i_refvec<T>::i_refvec(T* data) : data_(data), ref_count_(NULL) {}
-
-template <class T>
-inline T* i_refvec<T>::begin()
-{
- return data_;
-}
-
-template <class T>
-inline const T& i_refvec<T>::operator[](int i) const
-{
- return data_[i];
-}
-
-template <class T>
-inline T& i_refvec<T>::operator[](int i)
-{
- return data_[i];
-}
-
-
-template <class T>
-inline const T* i_refvec<T>::begin() const
-{
- return data_;
-}
-
-
-
-template <class T>
-i_refvec<T> & i_refvec<T>::operator=(const i_refvec<T> &V)
-{
- if (this == &V)
- return *this;
-
-
- if (ref_count_ != NULL)
- {
- (*ref_count_) --;
- if ((*ref_count_) == 0)
- destroy();
- }
-
- data_ = V.data_;
- ref_count_ = V.ref_count_;
-
- if (V.ref_count_ != NULL)
- (*(V.ref_count_))++;
-
- return *this;
-}
-
-template <class T>
-void i_refvec<T>::destroy()
-{
- if (ref_count_ != NULL)
- {
-#ifdef TNT_DEBUG
- std::cout << "destorying data... \n";
-#endif
- delete ref_count_;
-
-#ifdef TNT_DEBUG
- std::cout << "deleted ref_count_ ...\n";
-#endif
- if (data_ != NULL)
- delete []data_;
-#ifdef TNT_DEBUG
- std::cout << "deleted data_[] ...\n";
-#endif
- data_ = NULL;
- }
-}
-
-/*
-* return 1 is vector is empty, 0 otherwise
-*
-* if is_null() is false and ref_count() is 0, then
-*
-*/
-template<class T>
-int i_refvec<T>::is_null() const
-{
- return (data_ == NULL ? 1 : 0);
-}
-
-/*
-* returns -1 if data is external,
-* returns 0 if a is NULL array,
-* otherwise returns the positive number of vectors sharing
-* this data space.
-*/
-template <class T>
-int i_refvec<T>::ref_count() const
-{
- if (data_ == NULL)
- return 0;
- else
- return (ref_count_ != NULL ? *ref_count_ : -1) ;
-}
-
-template <class T>
-i_refvec<T>::~i_refvec()
-{
- if (ref_count_ != NULL)
- {
- (*ref_count_)--;
-
- if (*ref_count_ == 0)
- destroy();
- }
-}
-
-
-} /* namespace TNT */
-
-
-
-
-
-#endif
-/* TNT_I_REFVEC_H */
-
diff --git a/intern/smoke/intern/tnt/tnt_math_utils.h b/intern/smoke/intern/tnt/tnt_math_utils.h
deleted file mode 100644
index ed4a3b7f78f..00000000000
--- a/intern/smoke/intern/tnt/tnt_math_utils.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-#ifndef MATH_UTILS_H
-#define MATH_UTILS_H
-
-/* needed for fabs, sqrt() below */
-#include <cmath>
-
-namespace TNT
-{
-/**
- @returns hypotenuse of real (non-complex) scalars a and b by
- avoiding underflow/overflow
- using (a * sqrt( 1 + (b/a) * (b/a))), rather than
- sqrt(a*a + b*b).
-*/
-template <class Real>
-Real hypot(const Real &a, const Real &b)
-{
-
- if (a== 0)
- return fabs(b);
- else
- {
- Real c = b/a;
- return fabs(a) * sqrt(1 + c*c);
- }
-}
-} /* TNT namespace */
-
-
-
-#endif
-/* MATH_UTILS_H */
diff --git a/intern/smoke/intern/tnt/tnt_sparse_matrix_csr.h b/intern/smoke/intern/tnt/tnt_sparse_matrix_csr.h
deleted file mode 100644
index 61d52542641..00000000000
--- a/intern/smoke/intern/tnt/tnt_sparse_matrix_csr.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_SPARSE_MATRIX_CSR_H
-#define TNT_SPARSE_MATRIX_CSR_H
-
-#include "tnt_array1d.h"
-
-namespace TNT
-{
-
-
-/**
- Read-only view of a sparse matrix in compressed-row storage
- format. Neither array elements (nonzeros) nor sparsity
- structure can be modified. If modifications are required,
- create a new view.
-
- <p>
- Index values begin at 0.
-
- <p>
- <b>Storage requirements:</b> An (m x n) matrix with
- nz nonzeros requires no more than ((T+I)*nz + M*I)
- bytes, where T is the size of data elements and
- I is the size of integers.
-
-
-*/
-template <class T>
-class Sparse_Matrix_CompRow {
-
-private:
- Array1D<T> val_; // data values (nz_ elements)
- Array1D<int> rowptr_; // row_ptr (dim_[0]+1 elements)
- Array1D<int> colind_; // col_ind (nz_ elements)
-
- int dim1_; // number of rows
- int dim2_; // number of cols
-
-public:
-
- Sparse_Matrix_CompRow(const Sparse_Matrix_CompRow &S);
- Sparse_Matrix_CompRow(int M, int N, int nz, const T *val,
- const int *r, const int *c);
-
-
-
- inline const T& val(int i) const { return val_[i]; }
- inline const int& row_ptr(int i) const { return rowptr_[i]; }
- inline const int& col_ind(int i) const { return colind_[i];}
-
- inline int dim1() const {return dim1_;}
- inline int dim2() const {return dim2_;}
- int NumNonzeros() const {return val_.dim1();}
-
-
- Sparse_Matrix_CompRow& operator=(
- const Sparse_Matrix_CompRow &R);
-
-
-
-};
-
-/**
- Construct a read-only view of existing sparse matrix in
- compressed-row storage format.
-
- @param M the number of rows of sparse matrix
- @param N the number of columns of sparse matrix
- @param nz the number of nonzeros
- @param val a contiguous list of nonzero values
- @param r row-pointers: r[i] denotes the begining position of row i
- (i.e. the ith row begins at val[row[i]]).
- @param c column-indices: c[i] denotes the column location of val[i]
-*/
-template <class T>
-Sparse_Matrix_CompRow<T>::Sparse_Matrix_CompRow(int M, int N, int nz,
- const T *val, const int *r, const int *c) : val_(nz,val),
- rowptr_(M, r), colind_(nz, c), dim1_(M), dim2_(N) {}
-
-
-}
-// namespace TNT
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_stopwatch.h b/intern/smoke/intern/tnt/tnt_stopwatch.h
deleted file mode 100644
index a4eb09acbc4..00000000000
--- a/intern/smoke/intern/tnt/tnt_stopwatch.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef STOPWATCH_H
-#define STOPWATCH_H
-
-// for clock() and CLOCKS_PER_SEC
-#include <time.h>
-
-
-namespace TNT
-{
-
-inline static double seconds(void)
-{
- const double secs_per_tick = 1.0 / CLOCKS_PER_SEC;
- return ( (double) clock() ) * secs_per_tick;
-}
-
-class Stopwatch {
- private:
- int running_;
- double start_time_;
- double total_;
-
- public:
- inline Stopwatch();
- inline void start();
- inline double stop();
- inline double read();
- inline void resume();
- inline int running();
-};
-
-inline Stopwatch::Stopwatch() : running_(0), start_time_(0.0), total_(0.0) {}
-
-void Stopwatch::start()
-{
- running_ = 1;
- total_ = 0.0;
- start_time_ = seconds();
-}
-
-double Stopwatch::stop()
-{
- if (running_)
- {
- total_ += (seconds() - start_time_);
- running_ = 0;
- }
- return total_;
-}
-
-inline void Stopwatch::resume()
-{
- if (!running_)
- {
- start_time_ = seconds();
- running_ = 1;
- }
-}
-
-
-inline double Stopwatch::read()
-{
- if (running_)
- {
- stop();
- resume();
- }
- return total_;
-}
-
-
-} /* TNT namespace */
-#endif
-
-
-
diff --git a/intern/smoke/intern/tnt/tnt_subscript.h b/intern/smoke/intern/tnt/tnt_subscript.h
deleted file mode 100644
index 00cc0220bd1..00000000000
--- a/intern/smoke/intern/tnt/tnt_subscript.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-#ifndef TNT_SUBSCRPT_H
-#define TNT_SUBSCRPT_H
-
-
-//---------------------------------------------------------------------
-// This definition describes the default TNT data type used for
-// indexing into TNT matrices and vectors. The data type should
-// be wide enough to index into large arrays. It defaults to an
-// "int", but can be overriden at compile time redefining TNT_SUBSCRIPT_TYPE,
-// e.g.
-//
-// c++ -DTNT_SUBSCRIPT_TYPE='unsigned int' ...
-//
-//---------------------------------------------------------------------
-//
-
-#ifndef TNT_SUBSCRIPT_TYPE
-#define TNT_SUBSCRIPT_TYPE int
-#endif
-
-namespace TNT
-{
- typedef TNT_SUBSCRIPT_TYPE Subscript;
-} /* namespace TNT */
-
-
-// () indexing in TNT means 1-offset, i.e. x(1) and A(1,1) are the
-// first elements. This offset is left as a macro for future
-// purposes, but should not be changed in the current release.
-//
-//
-#define TNT_BASE_OFFSET (1)
-
-#endif
diff --git a/intern/smoke/intern/tnt/tnt_vec.h b/intern/smoke/intern/tnt/tnt_vec.h
deleted file mode 100644
index 77458c6b8c1..00000000000
--- a/intern/smoke/intern/tnt/tnt_vec.h
+++ /dev/null
@@ -1,407 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-
-
-#ifndef TNT_VEC_H
-#define TNT_VEC_H
-
-#include "tnt_subscript.h"
-#include <cstdlib>
-#include <cassert>
-#include <iostream>
-#include <sstream>
-
-namespace TNT
-{
-
-/**
- <b>[Deprecatred]</b> Value-based vector class from pre-1.0
- TNT version. Kept here for backward compatiblity, but should
- use the newer TNT::Array1D classes instead.
-
-*/
-
-template <class T>
-class Vector
-{
-
-
- public:
-
- typedef Subscript size_type;
- typedef T value_type;
- typedef T element_type;
- typedef T* pointer;
- typedef T* iterator;
- typedef T& reference;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
- Subscript lbound() const { return 1;}
-
- protected:
- T* v_;
- T* vm1_; // pointer adjustment for optimzied 1-offset indexing
- Subscript n_;
-
- // internal helper function to create the array
- // of row pointers
-
- void initialize(Subscript N)
- {
- // adjust pointers so that they are 1-offset:
- // v_[] is the internal contiguous array, it is still 0-offset
- //
- assert(v_ == NULL);
- v_ = new T[N];
- assert(v_ != NULL);
- vm1_ = v_-1;
- n_ = N;
- }
-
- void copy(const T* v)
- {
- Subscript N = n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = v[i];
- v_[i+1] = v[i+1];
- v_[i+2] = v[i+2];
- v_[i+3] = v[i+3];
- }
-
- for (i=N4; i< N; i++)
- v_[i] = v[i];
-#else
-
- for (i=0; i< N; i++)
- v_[i] = v[i];
-#endif
- }
-
- void set(const T& val)
- {
- Subscript N = n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = val;
- v_[i+1] = val;
- v_[i+2] = val;
- v_[i+3] = val;
- }
-
- for (i=N4; i< N; i++)
- v_[i] = val;
-#else
-
- for (i=0; i< N; i++)
- v_[i] = val;
-
-#endif
- }
-
-
-
- void destroy()
- {
- /* do nothing, if no memory has been previously allocated */
- if (v_ == NULL) return ;
-
- /* if we are here, then matrix was previously allocated */
- delete [] (v_);
-
- v_ = NULL;
- vm1_ = NULL;
- }
-
-
- public:
-
- // access
-
- iterator begin() { return v_;}
- iterator end() { return v_ + n_; }
- iterator begin() const { return v_;}
- iterator end() const { return v_ + n_; }
-
- // destructor
-
- ~Vector()
- {
- destroy();
- }
-
- // constructors
-
- Vector() : v_(0), vm1_(0), n_(0) {};
-
- Vector(const Vector<T> &A) : v_(0), vm1_(0), n_(0)
- {
- initialize(A.n_);
- copy(A.v_);
- }
-
- Vector(Subscript N, const T& value = T()) : v_(0), vm1_(0), n_(0)
- {
- initialize(N);
- set(value);
- }
-
- Vector(Subscript N, const T* v) : v_(0), vm1_(0), n_(0)
- {
- initialize(N);
- copy(v);
- }
-
- Vector(Subscript N, char *s) : v_(0), vm1_(0), n_(0)
- {
- initialize(N);
- std::istringstream ins(s);
-
- Subscript i;
-
- for (i=0; i<N; i++)
- ins >> v_[i];
- }
-
-
- // methods
- //
- Vector<T>& newsize(Subscript N)
- {
- if (n_ == N) return *this;
-
- destroy();
- initialize(N);
-
- return *this;
- }
-
-
- // assignments
- //
- Vector<T>& operator=(const Vector<T> &A)
- {
- if (v_ == A.v_)
- return *this;
-
- if (n_ == A.n_) // no need to re-alloc
- copy(A.v_);
-
- else
- {
- destroy();
- initialize(A.n_);
- copy(A.v_);
- }
-
- return *this;
- }
-
- Vector<T>& operator=(const T& scalar)
- {
- set(scalar);
- return *this;
- }
-
- inline Subscript dim() const
- {
- return n_;
- }
-
- inline Subscript size() const
- {
- return n_;
- }
-
-
- inline reference operator()(Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= n_) ;
-#endif
- return vm1_[i];
- }
-
- inline const_reference operator() (Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= n_) ;
-#endif
- return vm1_[i];
- }
-
- inline reference operator[](Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
- assert(i < n_) ;
-#endif
- return v_[i];
- }
-
- inline const_reference operator[](Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
-
-
-
-
-
-
- assert(i < n_) ;
-#endif
- return v_[i];
- }
-
-
-
-};
-
-
-/* *************************** I/O ********************************/
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Vector<T> &A)
-{
- Subscript N=A.dim();
-
- s << N << "\n";
-
- for (Subscript i=0; i<N; i++)
- s << A[i] << " " << "\n";
- s << "\n";
-
- return s;
-}
-
-template <class T>
-std::istream & operator>>(std::istream &s, Vector<T> &A)
-{
-
- Subscript N;
-
- s >> N;
-
- if ( !(N == A.size() ))
- {
- A.newsize(N);
- }
-
-
- for (Subscript i=0; i<N; i++)
- s >> A[i];
-
-
- return s;
-}
-
-// *******************[ basic matrix algorithms ]***************************
-
-
-template <class T>
-Vector<T> operator+(const Vector<T> &A,
- const Vector<T> &B)
-{
- Subscript N = A.dim();
-
- assert(N==B.dim());
-
- Vector<T> tmp(N);
- Subscript i;
-
- for (i=0; i<N; i++)
- tmp[i] = A[i] + B[i];
-
- return tmp;
-}
-
-template <class T>
-Vector<T> operator-(const Vector<T> &A,
- const Vector<T> &B)
-{
- Subscript N = A.dim();
-
- assert(N==B.dim());
-
- Vector<T> tmp(N);
- Subscript i;
-
- for (i=0; i<N; i++)
- tmp[i] = A[i] - B[i];
-
- return tmp;
-}
-
-template <class T>
-Vector<T> operator*(const Vector<T> &A,
- const Vector<T> &B)
-{
- Subscript N = A.dim();
-
- assert(N==B.dim());
-
- Vector<T> tmp(N);
- Subscript i;
-
- for (i=0; i<N; i++)
- tmp[i] = A[i] * B[i];
-
- return tmp;
-}
-
-
-template <class T>
-T dot_prod(const Vector<T> &A, const Vector<T> &B)
-{
- Subscript N = A.dim();
- assert(N == B.dim());
-
- Subscript i;
- T sum = 0;
-
- for (i=0; i<N; i++)
- sum += A[i] * B[i];
-
- return sum;
-}
-
-} /* namespace TNT */
-
-#endif
-// TNT_VEC_H
diff --git a/intern/smoke/intern/tnt/tnt_version.h b/intern/smoke/intern/tnt/tnt_version.h
deleted file mode 100644
index d770efb15c7..00000000000
--- a/intern/smoke/intern/tnt/tnt_version.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/** \file
- * \ingroup smoke
- */
-/*
-*
-* Template Numerical Toolkit (TNT)
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-*/
-
-#ifndef TNT_VERSION_H
-#define TNT_VERSION_H
-
-
-//---------------------------------------------------------------------
-// current version
-//---------------------------------------------------------------------
-
-
-#define TNT_MAJOR_VERSION '1'
-#define TNT_MINOR_VERSION '2'
-#define TNT_SUBMINOR_VERSION '6'
-#define TNT_VERSION_STRING "1.2.6"
-
-
-
-
-
-#endif
-// TNT_VERSION_H
diff --git a/release/datafiles/blender_icons16/icon16_mod_smoke.dat b/release/datafiles/blender_icons16/icon16_mod_manta.dat
index 0524059740d..0524059740d 100644
--- a/release/datafiles/blender_icons16/icon16_mod_smoke.dat
+++ b/release/datafiles/blender_icons16/icon16_mod_manta.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_mod_smoke.dat b/release/datafiles/blender_icons32/icon32_mod_manta.dat
index e3390d5f2ce..e3390d5f2ce 100644
--- a/release/datafiles/blender_icons32/icon32_mod_smoke.dat
+++ b/release/datafiles/blender_icons32/icon32_mod_manta.dat
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 0f771b0f380a1ae21d859416043c6119f66e40c
+Subproject 6625026f62f492dd677f5f29c68b9d70c96fb34
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject aa3366b7805bbe4d1afee890bda81b6d91bd47b
+Subproject 1b3bbeea01d4cb1aca3ccd2986fee85b253c8d3
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 0aa23a4d6177bed4c12392c81d0b767a8b35fe6
+Subproject b4fce25e94ec139554e821f58bbada3384b13af
diff --git a/release/scripts/presets/fluid/honey.py b/release/scripts/presets/fluid/honey.py
deleted file mode 100644
index fbeb7f2b286..00000000000
--- a/release/scripts/presets/fluid/honey.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import bpy
-bpy.context.fluid.settings.viscosity_base = 2.0
-bpy.context.fluid.settings.viscosity_exponent = 3
diff --git a/release/scripts/presets/fluid/oil.py b/release/scripts/presets/fluid/oil.py
deleted file mode 100644
index 3d73de9303a..00000000000
--- a/release/scripts/presets/fluid/oil.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import bpy
-bpy.context.fluid.settings.viscosity_base = 5.0
-bpy.context.fluid.settings.viscosity_exponent = 5
diff --git a/release/scripts/presets/fluid/water.py b/release/scripts/presets/fluid/water.py
deleted file mode 100644
index 0b68ad28c98..00000000000
--- a/release/scripts/presets/fluid/water.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import bpy
-bpy.context.fluid.settings.viscosity_base = 1.0
-bpy.context.fluid.settings.viscosity_exponent = 6
diff --git a/release/scripts/presets/mantaflow/honey.py b/release/scripts/presets/mantaflow/honey.py
new file mode 100644
index 00000000000..d1b9707c948
--- /dev/null
+++ b/release/scripts/presets/mantaflow/honey.py
@@ -0,0 +1,3 @@
+import bpy
+bpy.context.smoke.domain_settings.viscosity_base = 2.0
+bpy.context.smoke.domain_settings.viscosity_exponent = 3
diff --git a/release/scripts/presets/mantaflow/oil.py b/release/scripts/presets/mantaflow/oil.py
new file mode 100644
index 00000000000..6bbb84e6f0d
--- /dev/null
+++ b/release/scripts/presets/mantaflow/oil.py
@@ -0,0 +1,3 @@
+import bpy
+bpy.context.smoke.domain_settings.viscosity_base = 5.0
+bpy.context.smoke.domain_settings.viscosity_exponent = 5
diff --git a/release/scripts/presets/mantaflow/water.py b/release/scripts/presets/mantaflow/water.py
new file mode 100644
index 00000000000..17095ce7b7e
--- /dev/null
+++ b/release/scripts/presets/mantaflow/water.py
@@ -0,0 +1,3 @@
+import bpy
+bpy.context.smoke.domain_settings.viscosity_base = 1.0
+bpy.context.smoke.domain_settings.viscosity_exponent = 6
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index 0f6deea71eb..99d42a68653 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -349,8 +349,8 @@ class QuickSmoke(ObjectModeOperator, Operator):
)
def execute(self, context):
- if not bpy.app.build_options.mod_smoke:
- self.report({'ERROR'}, "Built without Smoke modifier support")
+ if not bpy.app.build_options.manta:
+ self.report({'ERROR'}, "Built without Fluid Mantaflow modifier")
return {'CANCELLED'}
fake_context = context.copy()
@@ -366,11 +366,14 @@ class QuickSmoke(ObjectModeOperator, Operator):
for obj in mesh_objects:
fake_context["object"] = obj
# make each selected object a smoke flow
- bpy.ops.object.modifier_add(fake_context, type='SMOKE')
- obj.modifiers[-1].smoke_type = 'FLOW'
+ bpy.ops.object.modifier_add(fake_context, type='MANTA')
+ obj.modifiers[-1].type = 'FLOW'
# set type
- obj.modifiers[-1].flow_settings.smoke_flow_type = self.style
+ obj.modifiers[-1].flow_settings.flow_type = self.style
+
+ # set flow behavior
+ obj.modifiers[-1].flow_settings.flow_behavior = 'INFLOW'
if not self.show_flows:
obj.display_type = 'WIRE'
@@ -388,10 +391,13 @@ class QuickSmoke(ObjectModeOperator, Operator):
obj.scale = 0.5 * (max_co - min_co) + Vector((1.0, 1.0, 2.0))
# setup smoke domain
- bpy.ops.object.modifier_add(type='SMOKE')
- obj.modifiers[-1].smoke_type = 'DOMAIN'
+ bpy.ops.object.modifier_add(type='MANTA')
+ obj.modifiers[-1].type = 'DOMAIN'
if self.style == 'FIRE' or self.style == 'BOTH':
- obj.modifiers[-1].domain_settings.use_high_resolution = True
+ obj.modifiers[-1].domain_settings.use_noise = True
+
+ # set correct cache file format for smoke
+ obj.modifiers[-1].domain_settings.cache_data_format = 'UNI'
# Setup material
@@ -566,9 +572,117 @@ class QuickFluid(ObjectModeOperator, Operator):
return {'FINISHED'}
+class QuickLiquid(Operator):
+ bl_idname = "object.quick_liquid"
+ bl_label = "Quick Liquid"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ show_flows: BoolProperty(
+ name="Render Liquid Objects",
+ description="Keep the liquid objects visible during rendering",
+ default=False,
+ )
+
+ def execute(self, context):
+ fake_context = context.copy()
+ mesh_objects = [obj for obj in context.selected_objects
+ if obj.type == 'MESH']
+ min_co = Vector((100000.0, 100000.0, 100000.0))
+ max_co = -min_co
+
+ if not mesh_objects:
+ self.report({'ERROR'}, "Select at least one mesh object")
+ return {'CANCELLED'}
+
+ for obj in mesh_objects:
+ fake_context["object"] = obj
+ # make each selected object a liquid flow
+ bpy.ops.object.modifier_add(fake_context, type='MANTA')
+ obj.modifiers[-1].type = 'FLOW'
+
+ # set type
+ obj.modifiers[-1].flow_settings.flow_type = 'LIQUID'
+
+ # set flow behavior
+ obj.modifiers[-1].flow_settings.flow_behavior = 'GEOMETRY'
+
+ if not self.show_flows:
+ obj.display_type = 'WIRE'
+
+ # store bounding box min/max for the domain object
+ obj_bb_minmax(obj, min_co, max_co)
+
+ # add the liquid domain object
+ bpy.ops.mesh.primitive_cube_add()
+ obj = context.active_object
+ obj.name = "Liquid Domain"
+
+ # give the liquid some room above the flows
+ obj.location = 0.5 * (max_co + min_co) + Vector((0.0, 0.0, -1.0))
+ obj.scale = 0.5 * (max_co - min_co) + Vector((1.0, 1.0, 2.0))
+
+ # setup liquid domain
+ bpy.ops.object.modifier_add(type='MANTA')
+ obj.modifiers[-1].type = 'DOMAIN'
+ obj.modifiers[-1].domain_settings.domain_type = 'LIQUID'
+ # set all domain borders to obstacle
+ obj.modifiers[-1].domain_settings.use_collision_border_front = True
+ obj.modifiers[-1].domain_settings.use_collision_border_back = True
+ obj.modifiers[-1].domain_settings.use_collision_border_right = True
+ obj.modifiers[-1].domain_settings.use_collision_border_left = True
+ obj.modifiers[-1].domain_settings.use_collision_border_top = True
+ obj.modifiers[-1].domain_settings.use_collision_border_bottom = True
+
+ # set correct cache file format for liquid
+ obj.modifiers[-1].domain_settings.cache_mesh_format = 'BOBJECT'
+
+ # allocate and show particle system for FLIP
+ obj.modifiers[-1].domain_settings.use_flip_particles = True
+
+ # make the domain smooth so it renders nicely
+ bpy.ops.object.shade_smooth()
+
+ # create a ray-transparent material for the domain
+ bpy.ops.object.material_slot_add()
+
+ mat = bpy.data.materials.new("Liquid Domain Material")
+ obj.material_slots[0].material = mat
+
+ # Make sure we use nodes
+ mat.use_nodes = True
+
+ # Set node variables and clear the default nodes
+ tree = mat.node_tree
+ nodes = tree.nodes
+ links = tree.links
+
+ nodes.clear()
+
+ # Create shader nodes
+
+ # Material output
+ node_out = nodes.new(type='ShaderNodeOutputMaterial')
+ node_out.location = grid_location(6, 1)
+
+ # Add Glass
+ node_glass = nodes.new(type='ShaderNodeBsdfGlass')
+ node_glass.location = grid_location(4, 1)
+ links.new(node_glass.outputs["BSDF"], node_out.inputs["Surface"])
+ node_glass.inputs["IOR"].default_value = 1.33
+
+ # Add Absorption
+ node_absorption = nodes.new(type='ShaderNodeVolumeAbsorption')
+ node_absorption.location = grid_location(4, 2)
+ links.new(node_absorption.outputs["Volume"], node_out.inputs["Volume"])
+ node_absorption.inputs["Color"].default_value = (0.8, 0.9, 1.0, 1.0)
+
+ return {'FINISHED'}
+
+
classes = (
QuickExplode,
QuickFluid,
QuickFur,
QuickSmoke,
+ QuickLiquid,
)
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index 097b93ea9ca..0c380c36f8f 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -390,6 +390,24 @@ class AddPresetFluid(AddPresetBase, Operator):
preset_subdir = "fluid"
+class AddPresetManta(AddPresetBase, Operator):
+ """Add or remove a Mantaflow Preset"""
+ bl_idname = "manta.preset_add"
+ bl_label = "Add Mantaflow Preset"
+ preset_menu = "MANTA_MT_presets"
+
+ preset_defines = [
+ "manta = bpy.context.smoke"
+ ]
+
+ preset_values = [
+ "manta.domain_settings.viscosity_base",
+ "manta.domain_settings.viscosity_exponent",
+ ]
+
+ preset_subdir = "mantaflow"
+
+
class AddPresetHairDynamics(AddPresetBase, Operator):
"""Add or remove a Hair Dynamics Preset"""
bl_idname = "particle.hair_dynamics_preset_add"
@@ -704,6 +722,7 @@ classes = (
AddPresetCamera,
AddPresetCloth,
AddPresetFluid,
+ AddPresetManta,
AddPresetHairDynamics,
AddPresetInterfaceTheme,
AddPresetKeyconfig,
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 44229b2afdf..0d846deb43f 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -54,10 +54,9 @@ _modules = [
"properties_physics_common",
"properties_physics_dynamicpaint",
"properties_physics_field",
- "properties_physics_fluid",
"properties_physics_rigidbody",
"properties_physics_rigidbody_constraint",
- "properties_physics_smoke",
+ "properties_physics_manta",
"properties_physics_softbody",
"properties_render",
"properties_output",
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index c4b6168be61..17dd7246783 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -55,7 +55,7 @@ def particle_panel_poll(cls, context):
if not settings:
return False
- return settings.is_fluid is False and (engine in cls.COMPAT_ENGINES)
+ return (settings.is_fluid is False) and (settings.is_manta is False) and (engine in cls.COMPAT_ENGINES)
def particle_get_settings(context):
@@ -190,7 +190,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
layout.template_ID(context.space_data, "pin_id")
- if part.is_fluid:
+ if part.is_fluid or part.is_manta:
layout.label(text="Settings used for fluid")
return
@@ -203,12 +203,12 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
col = layout.column()
- if part.is_fluid is False:
+ if (part.is_fluid is False) and (part.is_manta is False):
row = col.row()
row.enabled = particle_panel_enabled(context, psys)
row.template_ID(psys, "settings", new="particle.new")
- if part.is_fluid:
+ if part.is_fluid or part.is_manta:
layout.label(text=iface_("%d fluid particles for this frame") % part.count, translate=False)
return
@@ -253,7 +253,7 @@ class PARTICLE_PT_emission(ParticleButtonsPanel, Panel):
if settings is None:
return False
- if settings.is_fluid:
+ if settings.is_fluid or settings.is_manta:
return False
if particle_panel_poll(PARTICLE_PT_emission, context):
return psys is None or not context.particle_system.point_cache.use_external
@@ -485,7 +485,7 @@ class PARTICLE_PT_cache(ParticleButtonsPanel, Panel):
return False
if psys.settings is None:
return False
- if psys.settings.is_fluid:
+ if psys.settings.is_fluid or psys.settings.is_manta:
return False
phystype = psys.settings.physics_type
if phystype in {'NO', 'KEYED'}:
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index 9dbe11b0c70..7e40bf1efff 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -99,8 +99,7 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
physics_add(col, context.soft_body, "Soft Body", 'SOFT_BODY', 'MOD_SOFT', True)
if obj.type == 'MESH':
- physics_add(col, context.fluid, "Fluid", 'FLUID_SIMULATION', 'MOD_FLUIDSIM', True)
- physics_add(col, context.smoke, "Smoke", 'SMOKE', 'MOD_SMOKE', True)
+ physics_add(col, context.manta, "Fluid", 'MANTA', 'MOD_MANTA', True)
physics_add_special(
col, obj.rigid_body, "Rigid Body",
@@ -118,7 +117,7 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
)
-# cache-type can be 'PSYS' 'HAIR' 'SMOKE' etc.
+# cache-type can be 'PSYS' 'HAIR' 'MANTA' etc.
def point_cache_ui(self, cache, enabled, cachetype):
layout = self.layout
@@ -141,10 +140,10 @@ def point_cache_ui(self, cache, enabled, cachetype):
col.operator("ptcache.add", icon='ADD', text="")
col.operator("ptcache.remove", icon='REMOVE', text="")
- if cachetype in {'PSYS', 'HAIR', 'SMOKE'}:
+ if cachetype in {'PSYS', 'HAIR', 'MANTA'}:
col = layout.column()
- if cachetype == 'SMOKE':
+ if cachetype == 'MANTA':
col.prop(cache, "use_library_path", text="Use Library Path")
col.prop(cache, "use_external")
@@ -160,14 +159,14 @@ def point_cache_ui(self, cache, enabled, cachetype):
col.alignment = 'RIGHT'
col.label(text=cache_info)
else:
- if cachetype in {'SMOKE', 'DYNAMIC_PAINT'}:
+ if cachetype in {'MANTA', 'DYNAMIC_PAINT'}:
if not is_saved:
col = layout.column(align=True)
col.alignment = 'RIGHT'
col.label(text="Cache is disabled until the file is saved")
layout.enabled = False
- if not cache.use_external or cachetype == 'SMOKE':
+ if not cache.use_external or cachetype == 'MANTA':
col = layout.column(align=True)
if cachetype not in {'PSYS', 'DYNAMIC_PAINT'}:
@@ -175,18 +174,18 @@ def point_cache_ui(self, cache, enabled, cachetype):
col.prop(cache, "frame_start", text="Simulation Start")
col.prop(cache, "frame_end")
- if cachetype not in {'SMOKE', 'CLOTH', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
+ if cachetype not in {'MANTA', 'CLOTH', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
col.prop(cache, "frame_step")
cache_info = cache.info
- if cachetype != 'SMOKE' and cache_info: # avoid empty space.
+ if cachetype != 'MANTA' and cache_info: # avoid empty space.
col = layout.column(align=True)
col.alignment = 'RIGHT'
col.label(text=cache_info)
can_bake = True
- if cachetype not in {'SMOKE', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
+ if cachetype not in {'MANTA', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
if not is_saved:
col = layout.column(align=True)
col.alignment = 'RIGHT'
@@ -269,7 +268,7 @@ def effector_weights_ui(self, weights, weight_type):
col.prop(weights, "curve_guide", slider=True)
col.prop(weights, "texture", slider=True)
- if weight_type != 'SMOKE':
+ if weight_type != 'MANTA':
col.prop(weights, "smokeflow", slider=True)
col = flow.column()
diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py
deleted file mode 100644
index 8817d35b88a..00000000000
--- a/release/scripts/startup/bl_ui/properties_physics_fluid.py
+++ /dev/null
@@ -1,467 +0,0 @@
-# ##### 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.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-
-import bpy
-from bpy.types import (
- Panel,
-)
-from bpy.app.translations import pgettext_iface as iface_
-from bl_ui.utils import PresetPanel
-
-
-class FLUID_PT_presets(PresetPanel, Panel):
- bl_label = "Fluid Presets"
- preset_subdir = "fluid"
- preset_operator = "script.execute_preset"
- preset_add_operator = "fluid.preset_add"
-
-
-class PhysicButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "physics"
-
- @staticmethod
- def poll_fluid(context):
- ob = context.object
- if not ((ob and ob.type == 'MESH') and (context.fluid)):
- return False
-
- return (bpy.app.build_options.mod_fluid)
-
- @staticmethod
- def poll_fluid_settings(context):
- if not (PhysicButtonsPanel.poll_fluid(context)):
- return False
-
- md = context.fluid
- return md and md.settings and (md.settings.type != 'NONE')
-
- @staticmethod
- def poll_fluid_domain(context):
- if not PhysicButtonsPanel.poll_fluid(context):
- return False
-
- md = context.fluid
- return md and md.settings and (md.settings.type == 'DOMAIN')
-
-
-class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel):
- bl_label = "Fluid"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
-
- @classmethod
- def poll(cls, context):
- ob = context.object
- return (ob and ob.type == 'MESH') and context.engine in cls.COMPAT_ENGINES and (context.fluid)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- if not bpy.app.build_options.mod_fluid:
- col = layout.column()
- col.alignment = 'RIGHT'
- col.label(text="Built without fluids")
- return
-
- md = context.fluid
- fluid = md.settings
-
- col = layout.column()
- col.prop(fluid, "type")
-
-
-class PHYSICS_PT_fluid_flow(PhysicButtonsPanel, Panel):
- bl_label = "Flow"
- bl_parent_id = "PHYSICS_PT_fluid"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
-
- @classmethod
- def poll(cls, context):
- md = context.fluid
- fluid = md.settings
-
- if not PhysicButtonsPanel.poll_fluid_settings(context):
- return False
- return fluid.type in {'INFLOW', 'OUTFLOW', 'CONTROL'} and (context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.fluid
- fluid = md.settings
-
- self.layout.prop(fluid, "use", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.fluid
- fluid = md.settings
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- flow.active = fluid.use
-
- if fluid.type == 'INFLOW':
- col = flow.column()
- col.prop(fluid, "volume_initialization", text="Volume Initialization")
- col.prop(fluid, "use_animated_mesh")
-
- row = col.row()
- row.active = not fluid.use_animated_mesh
- row.prop(fluid, "use_local_coords")
-
- col = flow.column()
- col.prop(fluid, "inflow_velocity", text="Inflow Velocity")
-
- elif fluid.type == 'OUTFLOW':
- col = flow.column()
- col.prop(fluid, "volume_initialization", text="Volume Initialization")
-
- col = flow.column()
- col.prop(fluid, "use_animated_mesh")
-
- elif fluid.type == 'CONTROL':
- col = flow.column()
- col.prop(fluid, "quality", slider=True)
- col.prop(fluid, "use_reverse_frames")
-
- col = flow.column()
- col.prop(fluid, "start_time", text="Time Start")
- col.prop(fluid, "end_time", text="End")
-
- col.separator()
-
- col = flow.column()
- col.prop(fluid, "attraction_strength", text="Attraction Strength")
- col.prop(fluid, "attraction_radius", text="Radius")
-
- col.separator()
-
- col = flow.column(align=True)
- col.prop(fluid, "velocity_strength", text="Velocity Strength")
- col.prop(fluid, "velocity_radius", text="Radius")
-
-
-class PHYSICS_PT_fluid_settings(PhysicButtonsPanel, Panel):
- bl_label = "Settings"
- bl_parent_id = "PHYSICS_PT_fluid"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
-
- @classmethod
- def poll(cls, context):
- md = context.fluid
- fluid = md.settings
-
- if not PhysicButtonsPanel.poll_fluid_settings(context):
- return False
- return fluid.type in {'DOMAIN', 'FLUID', 'OBSTACLE', 'PARTICLE'} and (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.fluid
- fluid = md.settings
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- if fluid.type not in {'NONE', 'DOMAIN', 'PARTICLE', 'FLUID', 'OBSTACLE'}:
- flow.active = fluid.use
-
- if fluid.type == 'DOMAIN':
- col = flow.column()
-
- if bpy.app.build_options.openmp:
- col.prop(fluid, "threads", text="Simulation Threads")
- col.separator()
-
- col.prop(fluid, "resolution", text="Final Resolution")
- col.prop(fluid, "preview_resolution", text="Preview")
-
- col.separator()
-
- col = flow.column()
- col.prop(fluid, "render_display_mode", text="Render Display")
- col.prop(fluid, "viewport_display_mode", text="Viewport")
-
- col.separator()
-
- col = flow.column()
- sub = col.column(align=True)
- sub.prop(fluid, "start_time", text="Time Start")
- sub.prop(fluid, "end_time", text="End")
- col.prop(fluid, "simulation_rate", text="Speed")
-
- col = flow.column()
- col.prop(fluid, "use_speed_vectors")
- col.prop(fluid, "use_reverse_frames")
- col.prop(fluid, "frame_offset", text="Offset")
-
- elif fluid.type == 'FLUID':
- col = flow.column()
- col.prop(fluid, "volume_initialization", text="Volume Initialization")
- col.prop(fluid, "use_animated_mesh")
-
- col = flow.column()
- col.prop(fluid, "initial_velocity", text="Initial Velocity")
-
- elif fluid.type == 'OBSTACLE':
- col = flow.column()
- col.prop(fluid, "volume_initialization", text="Volume Initialization")
- col.prop(fluid, "use_animated_mesh")
-
- col = flow.column()
- subcol = col.column()
- subcol.enabled = not fluid.use_animated_mesh
- subcol.prop(fluid, "slip_type", text="Slip Type")
-
- if fluid.slip_type == 'PARTIALSLIP':
- subcol.prop(fluid, "partial_slip_factor", text="Amount", slider=True)
-
- col.prop(fluid, "impact_factor", text="Impact Factor")
-
- elif fluid.type == 'PARTICLE':
- col = flow.column()
- col.prop(fluid, "particle_influence", text="Influence Size")
- col.prop(fluid, "alpha_influence", text="Alpha")
-
- col = flow.column()
- col.prop(fluid, "use_drops")
- col.prop(fluid, "use_floats")
- col.prop(fluid, "show_tracer")
-
-
-class PHYSICS_PT_fluid_particle_cache(PhysicButtonsPanel, Panel):
- bl_label = "Cache"
- bl_parent_id = "PHYSICS_PT_fluid"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_fluid_settings(context):
- return False
-
- md = context.fluid
- return md and md.settings and (md.settings.type == 'PARTICLE') and (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- md = context.fluid
- fluid = md.settings
-
- layout.prop(fluid, "filepath", text="")
-
-
-class PHYSICS_PT_domain_bake(PhysicButtonsPanel, Panel):
- bl_label = "Bake"
- bl_parent_id = 'PHYSICS_PT_fluid'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_fluid_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- md = context.fluid
- fluid = md.settings
-
- row = layout.row(align=True)
- row.alignment = 'RIGHT'
- row.label(text="Cache Path")
-
- layout.prop(fluid, "filepath", text="")
-
- # odd formatting here so translation script can extract string
- layout.operator(
- "fluid.bake", text=iface_("Bake (Req. Memory: %s)") % fluid.memory_estimate,
- translate=False, icon='MOD_FLUIDSIM'
- )
-
-
-class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel):
- bl_label = "World"
- bl_parent_id = 'PHYSICS_PT_fluid'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_fluid_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- fluid = context.fluid.settings
- scene = context.scene
-
- col = layout.column()
-
- use_gravity = scene.use_gravity
- use_units = scene.unit_settings.system != 'NONE'
-
- if use_gravity or use_units:
- s_gravity = " Gravity" if use_gravity else ""
- s_units = " Units" if use_units else ""
- s_and = " and " if use_gravity and use_units else ""
- warn = f"Using {s_gravity}{s_and}{s_units} from Scene"
-
- sub = col.column()
- sub.alignment = 'RIGHT'
- sub.label(text=warn)
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- col = flow.column()
- sub = col.column()
- sub.enabled = not use_gravity
- sub.prop(fluid, "gravity", text="Gravity")
-
- sub = col.column()
- sub.enabled = not use_units
- sub.prop(fluid, "simulation_scale", text="Scene Size Meters" if use_units else "World Size Meters")
-
- col.separator()
-
- col = flow.column()
- col.prop(fluid, "grid_levels", text="Optimization", slider=True)
- col.prop(fluid, "compressibility", slider=True)
-
-
-class PHYSICS_PT_domain_viscosity(PhysicButtonsPanel, Panel):
- bl_label = "Viscosity"
- bl_parent_id = 'PHYSICS_PT_fluid'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_fluid_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw_header_preset(self, _context):
- FLUID_PT_presets.draw_panel_header(self.layout)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- fluid = context.fluid.settings
-
- col = flow.column()
- col.prop(fluid, "viscosity_base", text="Base")
-
- col = flow.column()
- col.prop(fluid, "viscosity_exponent", text="Exponent", slider=True)
-
-
-class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel):
- bl_label = "Boundary"
- bl_parent_id = 'PHYSICS_PT_fluid'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_fluid_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- fluid = context.fluid.settings
-
- col = flow.column()
- col.prop(fluid, "slip_type", text="Type")
-
- col.separator()
-
- if fluid.slip_type == 'PARTIALSLIP':
- col.prop(fluid, "partial_slip_factor", slider=True, text="Amount")
-
- col = flow.column()
- col.prop(fluid, "surface_smooth", text="Surface Smoothing")
- col.prop(fluid, "surface_subdivisions", text="Subdivisions")
- col.prop(fluid, "use_surface_noobs")
-
-
-class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel):
- bl_label = "Particles"
- bl_parent_id = 'PHYSICS_PT_fluid'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_fluid_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- fluid = context.fluid.settings
-
- col = flow.column()
- col.prop(fluid, "tracer_particles", text="Tracer")
-
- col = flow.column()
- col.prop(fluid, "generate_particles", text="Generate")
-
-
-classes = (
- FLUID_PT_presets,
- PHYSICS_PT_fluid,
- PHYSICS_PT_fluid_settings,
- PHYSICS_PT_fluid_flow,
- PHYSICS_PT_fluid_particle_cache,
- PHYSICS_PT_domain_bake,
- PHYSICS_PT_domain_boundary,
- PHYSICS_PT_domain_particles,
- PHYSICS_PT_domain_gravity,
- PHYSICS_PT_domain_viscosity,
-)
-
-if __name__ == "__main__": # only for live edit.
- from bpy.utils import register_class
- for cls in classes:
- register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_physics_manta.py b/release/scripts/startup/bl_ui/properties_physics_manta.py
new file mode 100644
index 00000000000..7191e6ab93e
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_physics_manta.py
@@ -0,0 +1,1178 @@
+# ##### 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from bpy.types import (
+ Panel,
+ Menu,
+)
+from .properties_physics_common import (
+ effector_weights_ui,
+)
+
+class MANTA_MT_presets(Menu):
+ bl_label = "Fluid Presets"
+ preset_subdir = "mantaflow"
+ preset_operator = "script.execute_preset"
+ draw = Menu.draw_preset
+
+class PhysicButtonsPanel:
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "physics"
+
+ @staticmethod
+ def poll_fluid(context):
+ ob = context.object
+ if not ((ob and ob.type == 'MESH') and (context.manta)):
+ return False
+
+ md = context.manta
+ return md and (context.manta.type != 'NONE') and (bpy.app.build_options.manta)
+
+ @staticmethod
+ def poll_fluid_domain(context):
+ if not PhysicButtonsPanel.poll_fluid(context):
+ return False
+
+ md = context.manta
+ return md and (md.type == 'DOMAIN')
+
+ @staticmethod
+ def poll_gas_domain(context):
+ if not PhysicButtonsPanel.poll_fluid(context):
+ return False
+
+ md = context.manta
+ if md and (md.type == 'DOMAIN'):
+ domain = md.domain_settings
+ return domain.domain_type in {'GAS'}
+ return False
+
+ @staticmethod
+ def poll_liquid_domain(context):
+ if not PhysicButtonsPanel.poll_fluid(context):
+ return False
+
+ md = context.manta
+ if md and (md.type == 'DOMAIN'):
+ domain = md.domain_settings
+ return domain.domain_type in {'LIQUID'}
+ return False
+
+ @staticmethod
+ def poll_fluid_flow(context):
+ if not PhysicButtonsPanel.poll_fluid(context):
+ return False
+
+ md = context.manta
+ return md and (md.type == 'FLOW')
+
+
+class PHYSICS_PT_manta(PhysicButtonsPanel, Panel):
+ bl_label = "Fluid"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.manta)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ if not bpy.app.build_options.manta:
+ col = layout.column(align=True)
+ col.alignment = 'RIGHT'
+ col.label(text="Built without Fluid modifier")
+ return
+
+ md = context.manta
+
+ layout.prop(md, "type")
+
+
+class PHYSICS_PT_manta_fluid(PhysicButtonsPanel, Panel):
+ bl_label = "Settings"
+ bl_parent_id = 'PHYSICS_PT_manta'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ md = context.manta
+ ob = context.object
+ scene = context.scene
+
+ if md.type == 'DOMAIN':
+ domain = md.domain_settings
+
+ # Deactivate UI if guiding is enabled but not baked yet
+ layout.active = not (domain.use_guiding and not domain.cache_baked_guiding and (domain.guiding_source == "EFFECTOR" or (domain.guiding_source == "DOMAIN" and not domain.guiding_parent)))
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding
+ baked_data = domain.cache_baked_data
+
+ row = layout.row()
+ row.enabled = not baking_any and not baked_data
+ row.prop(domain, "domain_type", expand=False)
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not baking_any and not baked_data
+
+ col = flow.column()
+ col.prop(domain, "resolution_max", text="Resolution Divisions")
+ col.prop(domain, "use_adaptive_stepping", text="Use Adaptive Stepping")
+ col.prop(domain, "time_scale", text="Time Scale")
+ col.prop(domain, "cfl_condition", text="CFL Number")
+
+ col.separator()
+
+ col = flow.column()
+ if scene.use_gravity:
+ sub = col.column()
+ sub.enabled = False
+ sub.prop(domain, "gravity", text="Using Scene Gravity", icon='SCENE_DATA')
+ else:
+ col.prop(domain, "gravity", text="Gravity")
+ # TODO (sebas): Clipping var useful for manta openvdb caching?
+ # col.prop(domain, "clipping", text="Empty Space")
+
+ col.separator()
+
+ split = layout.split()
+ bake_incomplete = (domain.cache_frame_pause_data < domain.cache_frame_end)
+ if domain.cache_baked_data and not domain.cache_baking_data and bake_incomplete:
+ col = split.column()
+ col.operator("manta.bake_data", text="Resume")
+ col = split.column()
+ col.operator("manta.free_data", text="Free")
+ elif domain.cache_baking_data and not domain.cache_baked_data:
+ split.enabled = False
+ split.operator("manta.pause_bake", text="Baking Data - ESC to pause")
+ elif not domain.cache_baked_data and not domain.cache_baking_data:
+ split.operator("manta.bake_data", text="Bake Data")
+ else:
+ split.operator("manta.free_data", text="Free Data")
+
+ elif md.type == 'FLOW':
+ flow = md.flow_settings
+
+ row = layout.row()
+ row.prop(flow, "flow_type", expand=False)
+
+ grid = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ col = grid.column()
+ col.prop(flow, "flow_behavior", expand=False)
+ if flow.flow_behavior in {'INFLOW'}:
+ col.prop(flow, "use_inflow", text="Use Inflow")
+
+ col.prop(flow, "subframes", text="Sampling Substeps")
+
+ if not flow.flow_behavior == 'OUTFLOW' and flow.flow_type in {'SMOKE', 'BOTH', 'FIRE'}:
+
+ if flow.flow_type in {'SMOKE', 'BOTH'}:
+ col.prop(flow, "smoke_color", text="Smoke Color")
+
+ col = grid.column(align=True)
+ col.prop(flow, "use_absolute", text="Absolute Density")
+
+ if flow.flow_type in {'SMOKE', 'BOTH'}:
+ col.prop(flow, "temperature", text="Initial Temperature")
+ col.prop(flow, "density", text="Density")
+
+ if flow.flow_type in {'FIRE', 'BOTH'}:
+ col.prop(flow, "fuel_amount", text="Fuel")
+
+ col.separator()
+ col.prop_search(flow, "density_vertex_group", ob, "vertex_groups", text="Vertex Group")
+
+ elif md.type == 'EFFECTOR':
+ effec = md.effec_settings
+
+ row = layout.row()
+ row.prop(effec, "effec_type")
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ col = flow.column()
+
+ col.prop(effec, "surface_distance", text="Surface Thickness")
+
+ if effec.effec_type == "GUIDE":
+ col.prop(effec, "velocity_factor", text="Velocity Factor")
+ col = flow.column()
+ col.prop(effec, "guiding_mode", text="Guiding Mode")
+
+class PHYSICS_PT_manta_borders(PhysicButtonsPanel, Panel):
+ bl_label = "Border Collisions"
+ bl_parent_id = 'PHYSICS_PT_manta_fluid'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ md = context.manta
+ domain = md.domain_settings
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding
+ baked_data = domain.cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not baking_any and not baked_data
+
+ col = flow.column()
+ col.prop(domain, "use_collision_border_front", text="Front")
+ col = flow.column()
+ col.prop(domain, "use_collision_border_back", text="Back")
+ col = flow.column()
+ col.prop(domain, "use_collision_border_right", text="Right")
+ col = flow.column()
+ col.prop(domain, "use_collision_border_left", text="Left")
+ col = flow.column()
+ col.prop(domain, "use_collision_border_top", text="Top")
+ col = flow.column()
+ col.prop(domain, "use_collision_border_bottom", text="Bottom")
+
+class PHYSICS_PT_manta_smoke(PhysicButtonsPanel, Panel):
+ bl_label = "Smoke"
+ bl_parent_id = 'PHYSICS_PT_manta_fluid'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_gas_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ md = context.manta
+ domain = md.domain_settings
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding
+ baked_data = domain.cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not baking_any and not baked_data
+
+ col = flow.column()
+ col.prop(domain, "alpha")
+ col.prop(domain, "beta", text="Temperature Diff.")
+ col = flow.column()
+ col.prop(domain, "vorticity")
+
+
+class PHYSICS_PT_manta_smoke_dissolve(PhysicButtonsPanel, Panel):
+ bl_label = "Dissolve"
+ bl_parent_id = 'PHYSICS_PT_manta_smoke'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_gas_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ md = context.manta
+ domain = md.domain_settings
+
+ self.layout.prop(domain, "use_dissolve_smoke", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ md = context.manta
+ domain = md.domain_settings
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding
+ baked_data = domain.cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not baking_any and not baked_data
+
+ layout.active = domain.use_dissolve_smoke
+
+ col = flow.column()
+ col.prop(domain, "dissolve_speed", text="Time")
+
+ col = flow.column()
+ col.prop(domain, "use_dissolve_smoke_log", text="Slow")
+
+
+class PHYSICS_PT_manta_fire(PhysicButtonsPanel, Panel):
+ bl_label = "Fire"
+ bl_parent_id = 'PHYSICS_PT_manta_fluid'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_gas_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ md = context.manta
+ domain = md.domain_settings
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding
+ baked_data = domain.cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not baking_any and not baked_data
+
+ col = flow.column()
+ col.prop(domain, "burning_rate", text="Reaction Speed")
+ col = flow.column()
+ col.prop(domain, "flame_smoke", text="Flame Smoke")
+ col = flow.column()
+ col.prop(domain, "flame_vorticity", text="Flame Vorticity")
+ col = flow.column()
+ col.prop(domain, "flame_ignition", text="Temperature Ignition")
+ col = flow.column()
+ col.prop(domain, "flame_max_temp", text="Maximum Temperature")
+ col = flow.column()
+ col.prop(domain, "flame_smoke_color", text="Flame Color")
+
+class PHYSICS_PT_manta_liquid(PhysicButtonsPanel, Panel):
+ bl_label = "Liquid"
+ bl_parent_id = 'PHYSICS_PT_manta_fluid'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_liquid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ md = context.manta
+ domain = md.domain_settings
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding
+ baked_data = domain.cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ col = flow.column()
+ col1 = col.column(align=True)
+ col1.enabled = not baking_any and not baked_data
+ col1.prop(domain, "particle_maximum", text="Particles Maximum")
+ col1.prop(domain, "particle_minimum", text="Minimum")
+
+ col1 = flow.column()
+ col1.enabled = not baking_any and not baked_data
+ col1.prop(domain, "particle_number", text="Particle Sampling Number")
+ col1.prop(domain, "particle_band_width", text="Narrow Band Width")
+ col1.prop(domain, "particle_randomness", text="Particle Randomness")
+ col2 = col.column()
+ col2.enabled = not baking_any
+ col2.prop(domain, "use_flip_particles", text="Show FLIP")
+
+class PHYSICS_PT_manta_flow_source(PhysicButtonsPanel, Panel):
+ bl_label = "Flow Source"
+ bl_parent_id = 'PHYSICS_PT_manta_fluid'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_flow(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ob = context.object
+ flow = context.manta.flow_settings
+
+ col = layout.column()
+ col.prop(flow, "flow_source", expand=False, text="Flow Source")
+ if flow.flow_source == 'PARTICLES':
+ col.prop_search(flow, "particle_system", ob, "particle_systems", text="Particle System")
+
+ grid = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ col = grid.column()
+ if flow.flow_source == 'MESH':
+ col.prop(flow, "surface_distance", text="Surface Thickness")
+ if flow.flow_type in {'SMOKE', 'BOTH', 'FIRE'}:
+ col = grid.column()
+ col.prop(flow, "volume_density", text="Volume Density")
+
+ if flow.flow_source == 'PARTICLES':
+ col.prop(flow, "use_particle_size", text="Set Size")
+ sub = col.column()
+ sub.active = flow.use_particle_size
+ sub.prop(flow, "particle_size")
+
+class PHYSICS_PT_manta_flow_initial_velocity(PhysicButtonsPanel, Panel):
+ bl_label = "Initial Velocity"
+ bl_parent_id = 'PHYSICS_PT_manta_fluid'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_flow(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ md = context.manta
+ flow_smoke = md.flow_settings
+
+ self.layout.prop(flow_smoke, "use_initial_velocity", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
+
+ md = context.manta
+ flow_smoke = md.flow_settings
+
+ flow.active = flow_smoke.use_initial_velocity
+
+ col = flow.column()
+ col.prop(flow_smoke, "velocity_factor")
+
+ if flow_smoke.flow_source == 'MESH':
+ col.prop(flow_smoke, "velocity_normal")
+ # col.prop(flow_smoke, "velocity_random")
+ col = flow.column()
+ col.prop(flow_smoke, "velocity_coord")
+
+
+class PHYSICS_PT_manta_flow_texture(PhysicButtonsPanel, Panel):
+ bl_label = "Texture"
+ bl_parent_id = 'PHYSICS_PT_manta_fluid'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_flow(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ md = context.manta
+ flow_smoke = md.flow_settings
+
+ self.layout.prop(flow_smoke, "use_texture", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ ob = context.object
+ flow_smoke = context.manta.flow_settings
+
+ sub = flow.column()
+ sub.active = flow_smoke.use_texture
+ sub.prop(flow_smoke, "noise_texture")
+ sub.prop(flow_smoke, "texture_map_type", text="Mapping")
+
+ col = flow.column()
+ sub = col.column()
+ sub.active = flow_smoke.use_texture
+
+ if flow_smoke.texture_map_type == 'UV':
+ sub.prop_search(flow_smoke, "uv_layer", ob.data, "uv_layers")
+
+ if flow_smoke.texture_map_type == 'AUTO':
+ sub.prop(flow_smoke, "texture_size")
+
+ sub.prop(flow_smoke, "texture_offset")
+
+class PHYSICS_PT_manta_adaptive_domain(PhysicButtonsPanel, Panel):
+ bl_label = "Adaptive Domain"
+ bl_parent_id = 'PHYSICS_PT_manta'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_gas_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ md = context.manta.domain_settings
+ domain = context.manta.domain_settings
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding
+ self.layout.enabled = not baking_any and not baked_any
+ self.layout.prop(md, "use_adaptive_domain", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.manta.domain_settings
+ layout.active = domain.use_adaptive_domain
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
+ flow.enabled = not baking_any and not baked_any
+
+ col = flow.column()
+ col.prop(domain, "additional_res", text="Add Resolution")
+ col.prop(domain, "adapt_margin")
+
+ col.separator()
+
+ col = flow.column()
+ col.prop(domain, "adapt_threshold", text="Threshold")
+
+class PHYSICS_PT_manta_noise(PhysicButtonsPanel, Panel):
+ bl_label = "Noise"
+ bl_parent_id = 'PHYSICS_PT_manta'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_gas_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ md = context.manta.domain_settings
+ domain = context.manta.domain_settings
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ self.layout.enabled = not baking_any
+ self.layout.prop(md, "use_noise", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.manta.domain_settings
+
+ # Deactivate UI if guiding is enabled but not baked yet
+ layout.active = domain.use_noise and not (domain.use_guiding and not domain.cache_baked_guiding and (domain.guiding_source == "EFFECTOR" or (domain.guiding_source == "DOMAIN" and not domain.guiding_parent)))
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_noise = domain.cache_baked_noise
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not baking_any and not baked_noise
+
+ col = flow.column()
+ col.prop(domain, "noise_scale", text="Upres Factor")
+ # TODO (sebbas): Mantaflow only supports wavelet noise. Maybe get rid of noise type field.
+ col.prop(domain, "noise_type", text="Noise Method")
+
+ col = flow.column()
+ col.prop(domain, "noise_strength", text="Strength")
+ col.prop(domain, "noise_pos_scale", text="Scale")
+ col.prop(domain, "noise_time_anim", text="Time")
+
+ col.separator()
+
+ split = layout.split()
+ split.enabled = domain.cache_baked_data
+ bake_incomplete = (domain.cache_frame_pause_noise < domain.cache_frame_end)
+ if domain.cache_baked_noise and not domain.cache_baking_noise and bake_incomplete:
+ col = split.column()
+ col.operator("manta.bake_noise", text="Resume")
+ col = split.column()
+ col.operator("manta.free_noise", text="Free")
+ elif not domain.cache_baked_noise and domain.cache_baking_noise:
+ split.enabled = False
+ split.operator("manta.pause_bake", text="Baking Noise - ESC to pause")
+ elif not domain.cache_baked_noise and not domain.cache_baking_noise:
+ split.operator("manta.bake_noise", text="Bake Noise")
+ else:
+ split.operator("manta.free_noise", text="Free Noise")
+
+class PHYSICS_PT_manta_mesh(PhysicButtonsPanel, Panel):
+ bl_label = "Mesh"
+ bl_parent_id = 'PHYSICS_PT_manta'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_liquid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ md = context.manta.domain_settings
+ domain = context.manta.domain_settings
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ self.layout.enabled = not baking_any
+ self.layout.prop(md, "use_mesh", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.manta.domain_settings
+
+ # Deactivate UI if guiding is enabled but not baked yet
+ layout.active = domain.use_mesh and not (domain.use_guiding and not domain.cache_baked_guiding and (domain.guiding_source == "EFFECTOR" or (domain.guiding_source == "DOMAIN" and not domain.guiding_parent)))
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_mesh = domain.cache_baked_mesh
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not baking_any and not baked_mesh
+
+ col = flow.column()
+
+ col.prop(domain, "mesh_scale", text="Upres Factor")
+ col.prop(domain, "particle_radius", text="Particle Radius")
+
+ col = flow.column()
+ col.prop(domain, "use_speed_vectors", text="Use Speed vectors")
+
+ col.separator()
+ col.prop(domain, "mesh_generator", text="Mesh Generator")
+
+ if domain.mesh_generator in {'IMPROVED'}:
+ col = flow.column(align=True)
+ col.prop(domain, "mesh_smoothen_pos", text="Smoothing Positive")
+ col.prop(domain, "mesh_smoothen_neg", text="Negative")
+
+ col = flow.column(align=True)
+ col.prop(domain, "mesh_concave_upper", text="Concavity Upper")
+ col.prop(domain, "mesh_concave_lower", text="Lower")
+
+ # TODO (sebbas): for now just interpolate any upres grids, ie not sampling highres grids
+ #col.prop(domain, "highres_sampling", text="Flow Sampling:")
+
+ col.separator()
+
+ split = layout.split()
+ split.enabled = domain.cache_baked_data
+ bake_incomplete = (domain.cache_frame_pause_mesh < domain.cache_frame_end)
+ if domain.cache_baked_mesh and not domain.cache_baking_mesh and bake_incomplete:
+ col = split.column()
+ col.operator("manta.bake_mesh", text="Resume")
+ col = split.column()
+ col.operator("manta.free_mesh", text="Free")
+ elif not domain.cache_baked_mesh and domain.cache_baking_mesh:
+ split.enabled = False
+ split.operator("manta.pause_bake", text="Baking Mesh - ESC to pause")
+ elif not domain.cache_baked_mesh and not domain.cache_baking_mesh:
+ split.operator("manta.bake_mesh", text="Bake Mesh")
+ else:
+ split.operator("manta.free_mesh", text="Free Mesh")
+
+class PHYSICS_PT_manta_particles(PhysicButtonsPanel, Panel):
+ bl_label = "Particles"
+ bl_parent_id = 'PHYSICS_PT_manta'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_liquid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.manta.domain_settings
+
+ # Deactivate UI if guiding is enabled but not baked yet
+ layout.active = not (domain.use_guiding and not domain.cache_baked_guiding and (domain.guiding_source == "EFFECTOR" or (domain.guiding_source == "DOMAIN" and not domain.guiding_parent)))
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_particles = domain.cache_baked_particles
+ using_particles = domain.use_spray_particles or domain.use_foam_particles or domain.use_bubble_particles
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not baking_any
+
+ subSpray = flow.column()
+ subSpray.enabled = (domain.sndparticle_combined_export == 'OFF') or (domain.sndparticle_combined_export == 'FOAM + BUBBLES')
+ subSpray.prop(domain, "use_spray_particles", text="Spray")
+ subFoam = flow.column()
+ subFoam.enabled = (domain.sndparticle_combined_export == 'OFF') or (domain.sndparticle_combined_export == 'SPRAY + BUBBLES')
+ subFoam.prop(domain, "use_foam_particles", text="Foam")
+ subBubbles = flow.column()
+ subBubbles.enabled = (domain.sndparticle_combined_export == 'OFF') or (domain.sndparticle_combined_export == 'SPRAY + FOAM')
+ subBubbles.prop(domain, "use_bubble_particles", text="Bubbles")
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not baking_any and not baked_particles and using_particles
+
+ col = flow.column()
+ col.prop(domain, "sndparticle_combined_export")
+ col.prop(domain, "particle_scale", text="Upres Factor")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_tau_max_wc", text="Wave Crest Potential Maximum")
+ col.prop(domain, "sndparticle_tau_min_wc", text="Minimum")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_tau_max_ta", text="Trapped Air Potential Maximum")
+ col.prop(domain, "sndparticle_tau_min_ta", text="Minimum")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_tau_max_k", text="Kinetic Energy Potential Maximum")
+ col.prop(domain, "sndparticle_tau_min_k", text="Minimum")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_potential_radius", text="Potential Radius")
+ col.prop(domain, "sndparticle_update_radius", text="Particle Update Radius")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_k_wc", text="Wave Crest Particle Sampling")
+ col.prop(domain, "sndparticle_k_ta", text="Trapped Air Particle Sampling")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_l_max", text="Particle Life Maximum")
+ col.prop(domain, "sndparticle_l_min", text="Minimum")
+ col.separator()
+
+ col = flow.column(align=True)
+ col.prop(domain, "sndparticle_k_b", text="Bubble Buoyancy")
+ col.prop(domain, "sndparticle_k_d", text="Bubble Drag")
+ col.separator()
+
+ col = flow.column()
+ col.prop(domain, "sndparticle_boundary", text="Particles in Boundary:")
+
+ col.separator()
+
+ split = layout.split()
+ split.enabled = domain.cache_baked_data and (domain.use_spray_particles or domain.use_bubble_particles or domain.use_foam_particles or domain.use_tracer_particles)
+ bake_incomplete = (domain.cache_frame_pause_particles < domain.cache_frame_end)
+ if domain.cache_baked_particles and not domain.cache_baking_particles and bake_incomplete:
+ col = split.column()
+ col.operator("manta.bake_particles", text="Resume")
+ col = split.column()
+ col.operator("manta.free_particles", text="Free")
+ elif not domain.cache_baked_particles and domain.cache_baking_particles:
+ split.enabled = False
+ split.operator("manta.pause_bake", text="Baking Particles - ESC to pause")
+ elif not domain.cache_baked_particles and not domain.cache_baking_particles:
+ split.operator("manta.bake_particles", text="Bake Particles")
+ else:
+ split.operator("manta.free_particles", text="Free Particles")
+
+class PHYSICS_PT_manta_diffusion(PhysicButtonsPanel, Panel):
+ bl_label = "Diffusion"
+ bl_parent_id = 'PHYSICS_PT_manta'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ # Fluid diffusion only enabled for liquids (surface tension and viscosity not relevant for smoke)
+ if not PhysicButtonsPanel.poll_liquid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.manta.domain_settings
+
+ # Deactivate UI if guiding is enabled but not baked yet
+ layout.active = not (domain.use_guiding and not domain.cache_baked_guiding and (domain.guiding_source == "EFFECTOR" or (domain.guiding_source == "DOMAIN" and not domain.guiding_parent)))
+
+ split = layout.split()
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding
+ baked_data = domain.cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not baking_any and not baked_any and not baked_data
+
+ row = flow.row()
+
+ col = row.column()
+ col.label(text="Viscosity Presets:")
+ col.menu("MANTA_MT_presets", text=bpy.types.MANTA_MT_presets.bl_label)
+
+ col = row.column(align=True)
+ col.operator("manta.preset_add", text="", icon='ADD')
+ col.operator("manta.preset_add", text="", icon='REMOVE').remove_active = True
+
+ col = flow.column(align=True)
+ col.prop(domain, "viscosity_base", text="Base")
+ col.prop(domain, "viscosity_exponent", text="Exponent", slider=True)
+
+ col = flow.column()
+ col.prop(domain, "domain_size", text="Real World Size")
+ col.prop(domain, "surface_tension", text="Surface tension")
+
+class PHYSICS_PT_manta_guiding(PhysicButtonsPanel, Panel):
+ bl_label = "Guiding"
+ bl_parent_id = 'PHYSICS_PT_manta'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ md = context.manta.domain_settings
+ domain = context.manta.domain_settings
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ self.layout.enabled = not baking_any
+ self.layout.prop(md, "use_guiding", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.manta.domain_settings
+
+ layout.active = domain.use_guiding
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_data = domain.cache_baked_data
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+ flow.enabled = not baking_any and not baked_data
+
+ col = flow.column()
+ col.prop(domain, "guiding_alpha", text="Weight")
+ col.prop(domain, "guiding_beta", text="Size")
+ col.prop(domain, "guiding_vel_factor", text="Velocity Factor")
+
+ col = flow.column()
+ col.prop(domain, "guiding_source", text="Velocity Source")
+ if domain.guiding_source == "DOMAIN":
+ col.prop(domain, "guiding_parent", text="Guiding parent")
+
+ col.separator()
+
+ if domain.guiding_source == "EFFECTOR":
+ split = layout.split()
+ bake_incomplete = (domain.cache_frame_pause_guiding < domain.cache_frame_end)
+ if domain.cache_baked_guiding and not domain.cache_baking_guiding and bake_incomplete:
+ col = split.column()
+ col.operator("manta.bake_guiding", text="Resume")
+ col = split.column()
+ col.operator("manta.free_guiding", text="Free")
+ elif not domain.cache_baked_guiding and domain.cache_baking_guiding:
+ split.operator("manta.pause_bake", text="Pause Guiding")
+ elif not domain.cache_baked_guiding and not domain.cache_baking_guiding:
+ split.operator("manta.bake_guiding", text="Bake Guiding")
+ else:
+ split.operator("manta.free_guiding", text="Free Guiding")
+
+class PHYSICS_PT_manta_collections(PhysicButtonsPanel, Panel):
+ bl_label = "Collections"
+ bl_parent_id = 'PHYSICS_PT_manta'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.manta.domain_settings
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ col = flow.column()
+ col.prop(domain, "fluid_group", text="Flow")
+
+ # col.prop(domain, "effector_group", text="Forces")
+ col.prop(domain, "collision_group", text="Effector")
+
+class PHYSICS_PT_manta_cache(PhysicButtonsPanel, Panel):
+ bl_label = "Cache"
+ bl_parent_id = 'PHYSICS_PT_manta'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ md = context.manta
+ domain = context.manta.domain_settings
+
+ baking_any = domain.cache_baking_data or domain.cache_baking_mesh or domain.cache_baking_particles or domain.cache_baking_noise or domain.cache_baking_guiding
+ baked_any = domain.cache_baked_data or domain.cache_baked_mesh or domain.cache_baked_particles or domain.cache_baked_noise or domain.cache_baked_guiding
+
+ col = layout.column()
+ col.prop(domain, "cache_directory", text="")
+ col.enabled = not baking_any
+
+ layout.use_property_split = True
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ col = flow.column(align=True)
+ col.separator()
+
+ col.prop(domain, "cache_frame_start", text="Frame Start")
+ col.prop(domain, "cache_frame_end", text="End")
+ col.enabled = not baking_any
+
+ col.separator()
+
+ col = flow.column()
+ col.enabled = not baking_any and not baked_any
+ col.prop(domain, "cache_data_format", text="Data file format")
+
+ if md.domain_settings.domain_type in {'GAS'}:
+ if domain.use_noise:
+ col.prop(domain, "cache_noise_format", text="Noise file format")
+
+ if md.domain_settings.domain_type in {'LIQUID'}:
+ # File format for all particle systemes (FLIP and secondary)
+ col.prop(domain, "cache_particle_format", text="Particle file format")
+
+ if domain.use_mesh:
+ col.prop(domain, "cache_mesh_format", text="Mesh file format")
+
+ col.prop(domain, "export_manta_script", text="Export Mantaflow Script")
+
+class PHYSICS_PT_manta_field_weights(PhysicButtonsPanel, Panel):
+ bl_label = "Field Weights"
+ bl_parent_id = 'PHYSICS_PT_manta'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ @classmethod
+ def poll(cls, context):
+ if not PhysicButtonsPanel.poll_fluid_domain(context):
+ return False
+
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ domain = context.manta.domain_settings
+ effector_weights_ui(self, domain.effector_weights, 'SMOKE')
+
+class PHYSICS_PT_manta_viewport_display(PhysicButtonsPanel, Panel):
+ bl_label = "Viewport Display"
+ bl_parent_id = 'PHYSICS_PT_manta'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return (PhysicButtonsPanel.poll_gas_domain(context))
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
+
+ domain = context.manta.domain_settings
+
+ col = flow.column()
+ col.prop(domain, "display_thickness")
+
+ col.separator()
+
+ col.prop(domain, "slice_method", text="Slicing")
+
+ slice_method = domain.slice_method
+ axis_slice_method = domain.axis_slice_method
+
+ do_axis_slicing = (slice_method == 'AXIS_ALIGNED')
+ do_full_slicing = (axis_slice_method == 'FULL')
+
+ col = col.column()
+ col.enabled = do_axis_slicing
+ col.prop(domain, "axis_slice_method")
+
+ col = flow.column()
+ sub = col.column()
+ sub.enabled = not do_full_slicing and do_axis_slicing
+ sub.prop(domain, "slice_axis")
+ sub.prop(domain, "slice_depth")
+
+ row = col.row()
+ row.enabled = do_full_slicing or not do_axis_slicing
+ row.prop(domain, "slice_per_voxel")
+
+ col.prop(domain, "display_interpolation")
+
+
+class PHYSICS_PT_manta_viewport_display_color(PhysicButtonsPanel, Panel):
+ bl_label = "Color Mapping"
+ bl_parent_id = 'PHYSICS_PT_manta_viewport_display'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return (PhysicButtonsPanel.poll_gas_domain(context))
+
+ def draw_header(self, context):
+ md = context.manta.domain_settings
+
+ self.layout.prop(md, "use_color_ramp", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ domain = context.manta.domain_settings
+ col = layout.column()
+ col.enabled = domain.use_color_ramp
+
+ col.prop(domain, "coba_field")
+
+ col.use_property_split = False
+
+ col = col.column()
+ col.template_color_ramp(domain, "color_ramp", expand=True)
+
+
+class PHYSICS_PT_manta_viewport_display_debug(PhysicButtonsPanel, Panel):
+ bl_label = "Debug Velocity"
+ bl_parent_id = 'PHYSICS_PT_manta_viewport_display'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return (PhysicButtonsPanel.poll_gas_domain(context))
+
+ def draw_header(self, context):
+ md = context.manta.domain_settings
+
+ self.layout.prop(md, "show_velocity", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
+
+ domain = context.manta.domain_settings
+
+ col = flow.column()
+ col.enabled = domain.show_velocity
+ col.prop(domain, "vector_display_type", text="Display As")
+ col.prop(domain, "vector_scale")
+
+
+classes = (
+ MANTA_MT_presets,
+ PHYSICS_PT_manta,
+ PHYSICS_PT_manta_fluid,
+ PHYSICS_PT_manta_borders,
+ PHYSICS_PT_manta_smoke,
+ PHYSICS_PT_manta_smoke_dissolve,
+ PHYSICS_PT_manta_fire,
+ PHYSICS_PT_manta_liquid,
+ PHYSICS_PT_manta_flow_source,
+ PHYSICS_PT_manta_flow_initial_velocity,
+ PHYSICS_PT_manta_flow_texture,
+ PHYSICS_PT_manta_adaptive_domain,
+ PHYSICS_PT_manta_noise,
+ PHYSICS_PT_manta_mesh,
+ PHYSICS_PT_manta_particles,
+ PHYSICS_PT_manta_diffusion,
+ PHYSICS_PT_manta_guiding,
+ PHYSICS_PT_manta_collections,
+ PHYSICS_PT_manta_cache,
+ PHYSICS_PT_manta_field_weights,
+ PHYSICS_PT_manta_viewport_display,
+ PHYSICS_PT_manta_viewport_display_color,
+ PHYSICS_PT_manta_viewport_display_debug,
+)
+
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py
deleted file mode 100644
index 057e7ddf211..00000000000
--- a/release/scripts/startup/bl_ui/properties_physics_smoke.py
+++ /dev/null
@@ -1,692 +0,0 @@
-# ##### 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.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-
-import bpy
-from bpy.types import (
- Panel,
-)
-from bl_ui.properties_physics_common import (
- point_cache_ui,
- effector_weights_ui,
-)
-
-
-class PhysicButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "physics"
-
- @staticmethod
- def poll_smoke(context):
- ob = context.object
- if not ((ob and ob.type == 'MESH') and (context.smoke)):
- return False
-
- md = context.smoke
- return md and (context.smoke.smoke_type != 'NONE') and (bpy.app.build_options.mod_smoke)
-
- @staticmethod
- def poll_smoke_domain(context):
- if not PhysicButtonsPanel.poll_smoke(context):
- return False
-
- md = context.smoke
- return md and (md.smoke_type == 'DOMAIN')
-
-
-class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
- bl_label = "Smoke"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- ob = context.object
- return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.smoke)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- if not bpy.app.build_options.mod_smoke:
- col = layout.column(align=True)
- col.alignment = 'RIGHT'
- col.label(text="Built without Smoke modifier")
- return
-
- md = context.smoke
-
- layout.prop(md, "smoke_type")
-
-
-class PHYSICS_PT_smoke_settings(PhysicButtonsPanel, Panel):
- bl_label = "Settings"
- bl_parent_id = 'PHYSICS_PT_smoke'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.smoke
- ob = context.object
-
- if md.smoke_type == 'DOMAIN':
- domain = md.domain_settings
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- col = flow.column()
- col.enabled = (not domain.point_cache.is_baked)
- col.prop(domain, "resolution_max", text="Resolution Divisions")
- col.prop(domain, "time_scale", text="Time Scale")
-
- col.separator()
-
- col = flow.column()
- sub = col.row()
- sub.enabled = (not domain.point_cache.is_baked)
- sub.prop(domain, "collision_extents", text="Border Collisions")
-
- # This can be tweaked after baking, for render.
- col.prop(domain, "clipping", text="Empty Space")
-
- elif md.smoke_type == 'FLOW':
- flow_smoke = md.flow_settings
-
- col = layout.column()
- col.prop(flow_smoke, "smoke_flow_type", expand=False)
-
- col.separator()
-
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
- col = flow.column()
-
- if flow_smoke.smoke_flow_type != 'OUTFLOW':
- col.prop(flow_smoke, "smoke_flow_source", expand=False, text="Flow Source")
-
- if flow_smoke.smoke_flow_source == 'PARTICLES':
- col.prop_search(
- flow_smoke, "particle_system", ob, "particle_systems",
- text="Particle System"
- )
- else:
- col.prop(flow_smoke, "surface_distance")
- col.prop(flow_smoke, "volume_density")
-
- col = flow.column()
- col.prop(flow_smoke, "use_absolute")
-
- if flow_smoke.smoke_flow_type in {'SMOKE', 'BOTH'}:
- col.prop(flow_smoke, "density")
- col.prop(flow_smoke, "temperature", text="Temperature Diff.")
-
- col.separator()
-
- col = flow.column()
- col.prop(flow_smoke, "smoke_color")
-
- if flow_smoke.smoke_flow_type in {'FIRE', 'BOTH'}:
- col.prop(flow_smoke, "fuel_amount")
-
- col.prop(flow_smoke, "subframes", text="Sampling Subframes")
-
- col.separator()
-
- col.prop_search(flow_smoke, "density_vertex_group", ob, "vertex_groups", text="Vertex Group")
-
- elif md.smoke_type == 'COLLISION':
- coll = md.coll_settings
-
- col = layout.column()
- col.prop(coll, "collision_type")
-
-
-class PHYSICS_PT_smoke_settings_initial_velocity(PhysicButtonsPanel, Panel):
- bl_label = "Initial Velocity"
- bl_parent_id = 'PHYSICS_PT_smoke_settings'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke(context):
- return False
-
- md = context.smoke
- return (md and (md.smoke_type == 'FLOW')
- and md.flow_settings and md.flow_settings.smoke_flow_type != 'OUTFLOW'
- and context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.smoke
- flow_smoke = md.flow_settings
-
- self.layout.prop(flow_smoke, "use_initial_velocity", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
-
- md = context.smoke
- flow_smoke = md.flow_settings
-
- flow.active = flow_smoke.use_initial_velocity
-
- col = flow.column(align=True)
- col.prop(flow_smoke, "velocity_factor")
-
- if flow_smoke.smoke_flow_source == 'MESH':
- col = flow.column()
- col.prop(flow_smoke, "velocity_normal")
- # sub.prop(flow_smoke, "velocity_random")
-
-
-class PHYSICS_PT_smoke_settings_particle_size(PhysicButtonsPanel, Panel):
- bl_label = "Particle Size"
- bl_parent_id = 'PHYSICS_PT_smoke_settings'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke(context):
- return False
-
- md = context.smoke
- return (md and (md.smoke_type == 'FLOW')
- and md.flow_settings and md.flow_settings.smoke_flow_type != 'OUTFLOW'
- and md.flow_settings.smoke_flow_source == 'PARTICLES'
- and context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.smoke
- flow_smoke = md.flow_settings
-
- self.layout.prop(flow_smoke, "use_particle_size", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.smoke
- flow_smoke = md.flow_settings
-
- layout.active = flow_smoke.use_particle_size
-
- layout.prop(flow_smoke, "particle_size")
-
-
-class PHYSICS_PT_smoke_behavior(PhysicButtonsPanel, Panel):
- bl_label = "Behavior"
- bl_parent_id = 'PHYSICS_PT_smoke_settings'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.smoke
- domain = md.domain_settings
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- flow.enabled = (not domain.point_cache.is_baked)
-
- col = flow.column()
- col.prop(domain, "alpha")
- col.prop(domain, "beta", text="Temperature Diff.")
- col = flow.column()
- col.prop(domain, "vorticity")
-
-
-class PHYSICS_PT_smoke_behavior_dissolve(PhysicButtonsPanel, Panel):
- bl_label = "Dissolve"
- bl_parent_id = 'PHYSICS_PT_smoke_behavior'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.smoke
- domain = md.domain_settings
-
- self.layout.prop(domain, "use_dissolve_smoke", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.smoke
- domain = md.domain_settings
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- flow.enabled = (not domain.point_cache.is_baked)
-
- layout.active = domain.use_dissolve_smoke
-
- col = flow.column()
- col.prop(domain, "dissolve_speed", text="Time")
-
- col = flow.column()
- col.prop(domain, "use_dissolve_smoke_log", text="Slow")
-
-
-class PHYSICS_PT_smoke_flow_texture(PhysicButtonsPanel, Panel):
- bl_label = "Texture"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke(context):
- return False
-
- md = context.smoke
- return (md and (md.smoke_type == 'FLOW')
- and (md.flow_settings.smoke_flow_source == 'MESH')
- and (context.engine in cls.COMPAT_ENGINES))
-
- def draw_header(self, context):
- md = context.smoke
- flow_smoke = md.flow_settings
-
- self.layout.prop(flow_smoke, "use_texture", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
-
- ob = context.object
- flow_smoke = context.smoke.flow_settings
-
- sub = flow.column()
- sub.active = flow_smoke.use_texture
- sub.prop(flow_smoke, "noise_texture")
- sub.prop(flow_smoke, "texture_map_type", text="Mapping")
-
- col = flow.column()
- sub = col.column()
- sub.active = flow_smoke.use_texture
-
- if flow_smoke.texture_map_type == 'UV':
- sub.prop_search(flow_smoke, "uv_layer", ob.data, "uv_layers")
-
- if flow_smoke.texture_map_type == 'AUTO':
- sub.prop(flow_smoke, "texture_size")
-
- sub.prop(flow_smoke, "texture_offset")
-
-
-class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel):
- bl_label = "Flames"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- domain = context.smoke.domain_settings
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- flow.enabled = (not domain.point_cache.is_baked)
-
- col = flow.column()
- col.prop(domain, "burning_rate", text="Reaction Speed")
- col.prop(domain, "flame_smoke")
- col.prop(domain, "flame_vorticity")
-
- col.separator()
-
- col = flow.column(align=True)
- col.prop(domain, "flame_ignition", text="Temperature Ignition")
- col.prop(domain, "flame_max_temp")
-
- col.separator()
-
- sub = col.column()
- sub.prop(domain, "flame_smoke_color")
-
-
-class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel):
- bl_label = "Adaptive Domain"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.smoke.domain_settings
-
- self.layout.prop(md, "use_adaptive_domain", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- domain = context.smoke.domain_settings
- layout.active = domain.use_adaptive_domain
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
- flow.enabled = (not domain.point_cache.is_baked)
-
- col = flow.column()
- col.prop(domain, "additional_res", text="Add Resolution")
- col.prop(domain, "adapt_margin")
-
- col.separator()
-
- col = flow.column()
- col.prop(domain, "adapt_threshold", text="Threshold")
-
-
-class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
- bl_label = "High Resolution"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- md = context.smoke.domain_settings
-
- self.layout.prop(md, "use_high_resolution", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- md = context.smoke.domain_settings
- layout.active = md.use_high_resolution
-
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- col = flow.column()
- col.enabled = not md.point_cache.is_baked
- col.prop(md, "amplify", text="Resolution Divisions")
- col.prop(md, "highres_sampling", text="Flow Sampling")
-
- col.separator()
-
- col = flow.column()
- col.enabled = not md.point_cache.is_baked
- col.prop(md, "noise_type", text="Noise Method")
- col.prop(md, "strength")
-
- layout.prop(md, "show_high_resolution")
-
-
-class PHYSICS_PT_smoke_collections(PhysicButtonsPanel, Panel):
- bl_label = "Collections"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- domain = context.smoke.domain_settings
-
- col = layout.column()
- col.prop(domain, "fluid_collection", text="Flow")
-
- # col = layout.column()
- # col.prop(domain, "effector_collection", text="Effector")
- col.prop(domain, "collision_collection", text="Collision")
-
-
-class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
- bl_label = "Cache"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- domain = context.smoke.domain_settings
- cache_file_format = domain.cache_file_format
-
- col = flow.column()
- col.prop(domain, "cache_file_format")
-
- if cache_file_format == 'POINTCACHE':
- col = flow.column()
- col.prop(domain, "point_cache_compress_type", text="Compression")
- col.separator()
-
- elif cache_file_format == 'OPENVDB':
- if not bpy.app.build_options.openvdb:
- row = layout.row(align=True)
- row.alignment = 'RIGHT'
- row.label(text="Built without OpenVDB support")
- return
-
- col = flow.column()
- col.prop(domain, "openvdb_cache_compress_type", text="Compression")
- col.prop(domain, "data_depth", text="Data Depth")
- col.separator()
-
- cache = domain.point_cache
- point_cache_ui(self, cache, (cache.is_baked is False), 'SMOKE')
-
-
-class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel):
- bl_label = "Field Weights"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
-
- @classmethod
- def poll(cls, context):
- if not PhysicButtonsPanel.poll_smoke_domain(context):
- return False
-
- return (context.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- domain = context.smoke.domain_settings
- effector_weights_ui(self, domain.effector_weights, 'SMOKE')
-
-
-class PHYSICS_PT_smoke_viewport_display(PhysicButtonsPanel, Panel):
- bl_label = "Viewport Display"
- bl_parent_id = 'PHYSICS_PT_smoke'
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- return (PhysicButtonsPanel.poll_smoke_domain(context))
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- domain = context.smoke.domain_settings
-
- col = flow.column()
- col.prop(domain, "display_thickness")
-
- col.separator()
-
- col.prop(domain, "slice_method", text="Slicing")
-
- slice_method = domain.slice_method
- axis_slice_method = domain.axis_slice_method
-
- do_axis_slicing = (slice_method == 'AXIS_ALIGNED')
- do_full_slicing = (axis_slice_method == 'FULL')
-
- col = col.column()
- col.enabled = do_axis_slicing
- col.prop(domain, "axis_slice_method")
-
- col = flow.column()
- sub = col.column()
- sub.enabled = not do_full_slicing and do_axis_slicing
- sub.prop(domain, "slice_axis")
- sub.prop(domain, "slice_depth")
-
- row = col.row()
- row.enabled = do_full_slicing or not do_axis_slicing
- row.prop(domain, "slice_per_voxel")
-
- col.prop(domain, "display_interpolation")
-
-
-class PHYSICS_PT_smoke_viewport_display_color(PhysicButtonsPanel, Panel):
- bl_label = "Color Mapping"
- bl_parent_id = 'PHYSICS_PT_smoke_viewport_display'
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- return (PhysicButtonsPanel.poll_smoke_domain(context))
-
- def draw_header(self, context):
- md = context.smoke.domain_settings
-
- self.layout.prop(md, "use_color_ramp", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- domain = context.smoke.domain_settings
- col = layout.column()
- col.enabled = domain.use_color_ramp
-
- col.prop(domain, "coba_field")
-
- col.use_property_split = False
-
- col = col.column()
- col.template_color_ramp(domain, "color_ramp", expand=True)
-
-
-class PHYSICS_PT_smoke_viewport_display_debug(PhysicButtonsPanel, Panel):
- bl_label = "Debug Velocity"
- bl_parent_id = 'PHYSICS_PT_smoke_viewport_display'
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- return (PhysicButtonsPanel.poll_smoke_domain(context))
-
- def draw_header(self, context):
- md = context.smoke.domain_settings
-
- self.layout.prop(md, "show_velocity", text="")
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
-
- domain = context.smoke.domain_settings
-
- col = flow.column()
- col.enabled = domain.show_velocity
- col.prop(domain, "vector_display_type", text="Display As")
- col.prop(domain, "vector_scale")
-
-
-classes = (
- PHYSICS_PT_smoke,
- PHYSICS_PT_smoke_settings,
- PHYSICS_PT_smoke_settings_initial_velocity,
- PHYSICS_PT_smoke_settings_particle_size,
- PHYSICS_PT_smoke_behavior,
- PHYSICS_PT_smoke_behavior_dissolve,
- PHYSICS_PT_smoke_adaptive_domain,
- PHYSICS_PT_smoke_cache,
- PHYSICS_PT_smoke_field_weights,
- PHYSICS_PT_smoke_fire,
- PHYSICS_PT_smoke_flow_texture,
- PHYSICS_PT_smoke_collections,
- PHYSICS_PT_smoke_highres,
- PHYSICS_PT_smoke_viewport_display,
- PHYSICS_PT_smoke_viewport_display_color,
- PHYSICS_PT_smoke_viewport_display_debug,
-)
-
-
-if __name__ == "__main__": # only for live edit.
- from bpy.utils import register_class
- for cls in classes:
- register_class(cls)
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index a94635c86f3..503c27cbe38 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2576,7 +2576,7 @@ class VIEW3D_MT_object_quick_effects(Menu):
layout.operator("object.quick_fur")
layout.operator("object.quick_explode")
layout.operator("object.quick_smoke")
- layout.operator("object.quick_fluid")
+ layout.operator("object.quick_liquid")
class VIEW3D_MT_object_showhide(Menu):
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 76442048594..bdd6e2186ad 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -53,6 +53,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_linestyle_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_listBase.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_mask_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_manta_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_material_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_mesh_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_meshdata_types.h
@@ -74,7 +75,6 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sdna_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sequence_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_shader_fx_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_smoke_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sound_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_space_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_speaker_types.h
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index 56fb5a68402..ea48801a4a1 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -42,6 +42,7 @@ extern "C" {
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_space_types.h" /* for FILE_MAX */
+#include "DNA_manta_types.h"
#include "BLI_string.h"
@@ -104,11 +105,12 @@ ExportSettings::ExportSettings()
static bool object_is_smoke_sim(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Manta);
if (md) {
- SmokeModifierData *smd = reinterpret_cast<SmokeModifierData *>(md);
- return (smd->type == MOD_SMOKE_TYPE_DOMAIN);
+ MantaModifierData *smd = reinterpret_cast<MantaModifierData *>(md);
+ return (smd->type == MOD_MANTA_TYPE_DOMAIN && smd->domain &&
+ smd->domain->type == FLUID_DOMAIN_TYPE_GAS);
}
return false;
@@ -559,7 +561,10 @@ void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *x
m_settings.export_child_hairs = true;
m_shapes.push_back(new AbcHairWriter(ob, xform, m_shape_sampling_index, m_settings, psys));
}
- else if (m_settings.export_particles && psys->part->type == PART_EMITTER) {
+ else if (m_settings.export_particles &&
+ (psys->part->type & PART_EMITTER || psys->part->type & PART_MANTA_FLIP ||
+ psys->part->type & PART_MANTA_SPRAY || psys->part->type & PART_MANTA_BUBBLE ||
+ psys->part->type & PART_MANTA_FOAM || psys->part->type & PART_MANTA_TRACER)) {
m_shapes.push_back(new AbcPointsWriter(ob, xform, m_shape_sampling_index, m_settings, psys));
}
}
diff --git a/source/blender/blenkernel/BKE_fluidsim.h b/source/blender/blenkernel/BKE_fluidsim.h
deleted file mode 100644
index d44c88c30a9..00000000000
--- a/source/blender/blenkernel/BKE_fluidsim.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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) Blender Foundation
- * All rights reserved.
- */
-
-#ifndef __BKE_FLUIDSIM_H__
-#define __BKE_FLUIDSIM_H__
-
-/** \file
- * \ingroup bke
- */
-
-struct Depsgraph;
-struct FluidsimSettings;
-struct MVert;
-struct Object;
-struct Scene;
-
-/* old interface */
-
-void initElbeemMesh(struct Depsgraph *depsgraph,
- struct Scene *scene,
- struct Object *ob,
- int *numVertices,
- float **vertices,
- int *numTriangles,
- int **triangles,
- int useGlobalCoords,
- int modifierIndex);
-
-/* bounding box & memory estimate */
-void fluid_get_bb(
- struct MVert *mvert, int totvert, float obmat[4][4], float start[3], float size[3]);
-
-void fluid_estimate_memory(struct Object *ob, struct FluidsimSettings *fss, char *value);
-
-#endif
diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_manta.h
index 10632d47203..0560f622f85 100644
--- a/source/blender/blenkernel/BKE_smoke.h
+++ b/source/blender/blenkernel/BKE_manta.h
@@ -17,46 +17,36 @@
* All rights reserved.
*/
-#ifndef __BKE_SMOKE_H__
-#define __BKE_SMOKE_H__
+#ifndef __BKE_MANTA_H__
+#define __BKE_MANTA_H__
/** \file
* \ingroup bke
*/
struct Scene;
-struct SmokeDomainSettings;
-struct SmokeModifierData;
+struct MantaDomainSettings;
+struct MantaModifierData;
typedef float (*bresenham_callback)(
float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
-struct Mesh *smokeModifier_do(struct SmokeModifierData *smd,
+struct Mesh *mantaModifier_do(struct MantaModifierData *mmd,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct Mesh *me);
-void smokeModifier_free(struct SmokeModifierData *smd);
-void smokeModifier_reset(struct SmokeModifierData *smd);
-void smokeModifier_reset_turbulence(struct SmokeModifierData *smd);
-void smokeModifier_createType(struct SmokeModifierData *smd);
-void smokeModifier_copy(const struct SmokeModifierData *smd,
- struct SmokeModifierData *tsmd,
+void mantaModifier_free(struct MantaModifierData *mmd);
+void mantaModifier_reset(struct MantaModifierData *mmd);
+void mantaModifier_createType(struct MantaModifierData *mmd);
+void mantaModifier_copy(const struct MantaModifierData *mmd,
+ struct MantaModifierData *tmmd,
const int flag);
-void BKE_smoke_reallocate_fluid(struct SmokeDomainSettings *sds,
- float dx,
- int res[3],
- int free_old);
-void BKE_smoke_reallocate_highres_fluid(struct SmokeDomainSettings *sds,
- float dx,
- int res[3],
- int free_old);
+void BKE_manta_reallocate_fluid(struct MantaDomainSettings *mds, int res[3], int free_old);
-float BKE_smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
-int BKE_smoke_get_data_flags(struct SmokeDomainSettings *sds);
+float BKE_manta_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
+int BKE_manta_get_data_flags(struct MantaDomainSettings *mds);
-bool BKE_smoke_show_highres(struct Scene *scene, struct SmokeDomainSettings *sds);
-
-#endif /* __BKE_SMOKE_H__ */
+#endif /* __BKE_MANTA_H__ */
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index 6ce60081f5b..d2e0dc7cd31 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -83,7 +83,7 @@ struct ParticleSystem;
struct PointCache;
struct RigidBodyWorld;
struct Scene;
-struct SmokeModifierData;
+struct MantaModifierData;
struct SoftBody;
struct ViewLayer;
@@ -286,7 +286,7 @@ void BKE_ptcache_make_particle_key(struct ParticleKey *key, int index, void **da
void BKE_ptcache_id_from_softbody(PTCacheID *pid, struct Object *ob, struct SoftBody *sb);
void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct ParticleSystem *psys);
void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd);
-void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd);
+void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct MantaModifierData *mmd);
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid,
struct Object *ob,
struct DynamicPaintSurface *surface);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index e564e91749c..dc75306143b 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -45,11 +45,11 @@ set(INC
../../../intern/atomic
../../../intern/clog
../../../intern/libmv
+ ../../../intern/mantaflow/extern
../../../intern/memutil
../../../intern/mikktspace
../../../intern/opensubdiv
../../../extern/curve_fit_nd
- ../../../intern/smoke/extern
)
set(INC_SYS
@@ -108,7 +108,6 @@ set(SRC
intern/editmesh_tangent.c
intern/effect.c
intern/fcurve.c
- intern/fluidsim.c
intern/fmodifier.c
intern/font.c
intern/freestyle.c
@@ -137,6 +136,7 @@ set(SRC
intern/lightprobe.c
intern/linestyle.c
intern/main.c
+ intern/manta.c
intern/mask.c
intern/mask_evaluate.c
intern/mask_rasterize.c
@@ -187,7 +187,6 @@ set(SRC
intern/sequencer.c
intern/shader_fx.c
intern/shrinkwrap.c
- intern/smoke.c
intern/softbody.c
intern/sound.c
intern/speaker.c
@@ -266,7 +265,6 @@ set(SRC
BKE_editmesh_tangent.h
BKE_effect.h
BKE_fcurve.h
- BKE_fluidsim.h
BKE_font.h
BKE_freestyle.h
BKE_global.h
@@ -291,6 +289,7 @@ set(SRC
BKE_lightprobe.h
BKE_linestyle.h
BKE_main.h
+ BKE_manta.h
BKE_mask.h
BKE_material.h
BKE_mball.h
@@ -323,7 +322,6 @@ set(SRC
BKE_sequencer.h
BKE_shader_fx.h
BKE_shrinkwrap.h
- BKE_smoke.h
BKE_softbody.h
BKE_sound.h
BKE_speaker.h
@@ -511,21 +509,11 @@ if(WITH_PYTHON)
endif()
endif()
-if(WITH_MOD_FLUID)
- list(APPEND INC
- ../../../intern/elbeem/extern
- )
- list(APPEND LIB
- bf_intern_elbeem
- )
- add_definitions(-DWITH_MOD_FLUID)
-endif()
-
-if(WITH_MOD_SMOKE)
+if(WITH_MOD_MANTA)
list(APPEND LIB
- bf_intern_smoke
+ bf_intern_mantaflow
)
- add_definitions(-DWITH_SMOKE)
+ add_definitions(-DWITH_MANTA)
endif()
if(WITH_MOD_OCEANSIM)
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index fa7af53df2d..36a237bc478 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -59,7 +59,7 @@
#include "DNA_texture_types.h"
#include "DNA_vfont_types.h"
#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_freestyle_types.h"
#include "BLI_blenlib.h"
@@ -497,10 +497,10 @@ void BKE_bpath_traverse_id(
rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data);
}
}
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- BPATH_TRAVERSE_POINTCACHE(smd->domain->ptcaches[0]);
+ else if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ if (mmd->type & MOD_MANTA_TYPE_DOMAIN && mmd->domain) {
+ rewrite_path_fixed(mmd->domain->cache_directory, visit_cb, absbase, bpath_user_data);
}
}
else if (md->type == eModifierType_Cloth) {
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 7e916feac24..06a1c068b81 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -6274,7 +6274,14 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph,
/* Apply brush on the surface depending on it's collision type */
if (brush->psys && brush->psys->part &&
- ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
+ ELEM(brush->psys->part->type,
+ PART_EMITTER,
+ PART_FLUID,
+ PART_MANTA_FLIP,
+ PART_MANTA_SPRAY,
+ PART_MANTA_BUBBLE,
+ PART_MANTA_FOAM,
+ PART_MANTA_TRACER) &&
psys_check_enabled(brushObj, brush->psys, for_render)) {
/* Paint a particle system */
dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 7cbd5b6b050..5b5a4c54628 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -62,7 +62,7 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
-#include "BKE_smoke.h"
+#include "BKE_manta.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_physics.h"
@@ -71,13 +71,6 @@
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
-/* fluid sim particle import */
-#ifdef WITH_MOD_FLUID
-# include "LBM_fluidsim.h"
-# include <zlib.h>
-# include <string.h>
-#endif // WITH_MOD_FLUID
-
EffectorWeights *BKE_effector_add_weights(Collection *collection)
{
EffectorWeights *weights = MEM_callocN(sizeof(EffectorWeights), "EffectorWeights");
@@ -1033,7 +1026,7 @@ static void do_physical_effector(EffectorCache *eff,
zero_v3(force);
if (pd->f_source) {
float density;
- if ((density = BKE_smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) {
+ if ((density = BKE_manta_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) {
float influence = strength * efd->falloff;
if (pd->flag & PFIELD_SMOKE_DENSITY) {
influence *= density;
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
deleted file mode 100644
index 994e00f227a..00000000000
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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) Blender Foundation
- * All rights reserved.
- */
-
-/** \file
- * \ingroup bke
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_math.h"
-
-#include "BKE_customdata.h"
-#include "BKE_fluidsim.h"
-#include "BKE_library.h"
-#include "BKE_mesh_runtime.h"
-
-/* ************************* fluidsim bobj file handling **************************** */
-
-//-------------------------------------------------------------------------------
-// file handling
-//-------------------------------------------------------------------------------
-
-void initElbeemMesh(struct Depsgraph *depsgraph,
- struct Scene *scene,
- struct Object *ob,
- int *numVertices,
- float **vertices,
- int *numTriangles,
- int **triangles,
- int useGlobalCoords,
- int modifierIndex)
-{
- Mesh *mesh;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *looptri, *lt;
- int i, mvert_num, looptri_num;
- float *verts;
- int *tris;
-
- mesh = mesh_create_eval_final_index_render(
- depsgraph, scene, ob, &CD_MASK_BAREMESH, modifierIndex);
-
- mvert = mesh->mvert;
- mloop = mesh->mloop;
- looptri = BKE_mesh_runtime_looptri_ensure(mesh);
- mvert_num = mesh->totvert;
- looptri_num = mesh->runtime.looptris.len;
-
- *numVertices = mvert_num;
- verts = MEM_mallocN(mvert_num * sizeof(float[3]), "elbeemmesh_vertices");
- for (i = 0; i < mvert_num; i++) {
- copy_v3_v3(&verts[i * 3], mvert[i].co);
- if (useGlobalCoords) {
- mul_m4_v3(ob->obmat, &verts[i * 3]);
- }
- }
- *vertices = verts;
-
- *numTriangles = looptri_num;
- tris = MEM_mallocN(looptri_num * sizeof(int[3]), "elbeemmesh_triangles");
- for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
- tris[(i * 3) + 0] = mloop[lt->tri[0]].v;
- tris[(i * 3) + 1] = mloop[lt->tri[1]].v;
- tris[(i * 3) + 2] = mloop[lt->tri[2]].v;
- }
- *triangles = tris;
-
- BKE_id_free(NULL, mesh);
-}
diff --git a/source/blender/blenkernel/intern/manta.c b/source/blender/blenkernel/intern/manta.c
new file mode 100644
index 00000000000..bcbf369d924
--- /dev/null
+++ b/source/blender/blenkernel/intern/manta.c
@@ -0,0 +1,4402 @@
+/*
+ * 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) Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+/* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
+
+#include "MEM_guardedalloc.h"
+
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h> /* memset */
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_light_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_manta_types.h"
+
+#include "BKE_appdir.h"
+#include "BKE_animsys.h"
+#include "BKE_armature.h"
+#include "BKE_bvhutils.h"
+#include "BKE_collision.h"
+#include "BKE_colortools.h"
+#include "BKE_constraint.h"
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_effect.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+#include "BKE_scene.h"
+#include "BKE_manta.h"
+#include "BKE_texture.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "RE_shader_ext.h"
+
+#include "GPU_glew.h"
+
+/* UNUSED so far, may be enabled later */
+/* #define USE_SMOKE_COLLISION_DM */
+
+//#define DEBUG_TIME
+
+#include "manta_fluid_API.h"
+
+#ifdef DEBUG_TIME
+# include "PIL_time.h"
+#endif
+
+# include "BLI_task.h"
+# include "BLI_kdtree.h"
+# include "BLI_voxel.h"
+
+static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER;
+
+struct Mesh;
+struct Object;
+struct Scene;
+struct MantaModifierData;
+
+// timestep default value for nice appearance 0.1f
+# define DT_DEFAULT 0.1f
+
+# define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b))))
+# define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b))))
+# define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b)))
+
+void BKE_manta_reallocate_fluid(MantaDomainSettings *mds, int res[3], int free_old)
+{
+ if (free_old && mds->fluid) {
+ manta_free(mds->fluid);
+ }
+ if (!min_iii(res[0], res[1], res[2])) {
+ mds->fluid = NULL;
+ return;
+ }
+
+ mds->fluid = manta_init(res, mds->mmd);
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ mds->res_noise[0] = res[0] * mds->noise_scale;
+ mds->res_noise[1] = res[1] * mds->noise_scale;
+ mds->res_noise[2] = res[2] * mds->noise_scale;
+ }
+}
+
+/* convert global position to domain cell space */
+static void manta_pos_to_cell(MantaDomainSettings *mds, float pos[3])
+{
+ mul_m4_v3(mds->imat, pos);
+ sub_v3_v3(pos, mds->p0);
+ pos[0] *= 1.0f / mds->cell_size[0];
+ pos[1] *= 1.0f / mds->cell_size[1];
+ pos[2] *= 1.0f / mds->cell_size[2];
+}
+
+/* set domain transformations and base resolution from object mesh */
+static void manta_set_domain_from_mesh(MantaDomainSettings *mds,
+ Object *ob,
+ Mesh *me,
+ bool init_resolution)
+{
+ size_t i;
+ float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+ float size[3];
+ MVert *verts = me->mvert;
+ float scale = 0.0;
+ int res;
+
+ res = mds->maxres;
+
+ // get BB of domain
+ for (i = 0; i < me->totvert; i++) {
+ // min BB
+ min[0] = MIN2(min[0], verts[i].co[0]);
+ min[1] = MIN2(min[1], verts[i].co[1]);
+ min[2] = MIN2(min[2], verts[i].co[2]);
+
+ // max BB
+ max[0] = MAX2(max[0], verts[i].co[0]);
+ max[1] = MAX2(max[1], verts[i].co[1]);
+ max[2] = MAX2(max[2], verts[i].co[2]);
+ }
+
+ /* set domain bounds */
+ copy_v3_v3(mds->p0, min);
+ copy_v3_v3(mds->p1, max);
+ mds->dx = 1.0f / res;
+
+ /* calculate domain dimensions */
+ sub_v3_v3v3(size, max, min);
+ if (init_resolution) {
+ zero_v3_int(mds->base_res);
+ copy_v3_v3(mds->cell_size, size);
+ }
+ /* apply object scale */
+ for (i = 0; i < 3; i++) {
+ size[i] = fabsf(size[i] * ob->scale[i]);
+ }
+ copy_v3_v3(mds->global_size, size);
+ copy_v3_v3(mds->dp0, min);
+
+ invert_m4_m4(mds->imat, ob->obmat);
+
+ // prevent crash when initializing a plane as domain
+ if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) ||
+ (size[2] < FLT_EPSILON)) {
+ return;
+ }
+
+ /* define grid resolutions from longest domain side */
+ if (size[0] >= MAX2(size[1], size[2])) {
+ scale = res / size[0];
+ mds->scale = size[0] / fabsf(ob->scale[0]);
+ mds->base_res[0] = res;
+ mds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
+ mds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
+ }
+ else if (size[1] >= MAX2(size[0], size[2])) {
+ scale = res / size[1];
+ mds->scale = size[1] / fabsf(ob->scale[1]);
+ mds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
+ mds->base_res[1] = res;
+ mds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
+ }
+ else {
+ scale = res / size[2];
+ mds->scale = size[2] / fabsf(ob->scale[2]);
+ mds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
+ mds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
+ mds->base_res[2] = res;
+ }
+
+ /* set cell size */
+ mds->cell_size[0] /= (float)mds->base_res[0];
+ mds->cell_size[1] /= (float)mds->base_res[1];
+ mds->cell_size[2] /= (float)mds->base_res[2];
+}
+
+static void manta_set_domain_gravity(Scene *scene, MantaDomainSettings *mds)
+{
+ float gravity[3] = {0.0f, 0.0f, -1.0f};
+ float gravity_mag;
+
+ /* use global gravity if enabled */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ copy_v3_v3(gravity, scene->physics_settings.gravity);
+ /* map default value to 1.0 */
+ mul_v3_fl(gravity, 1.0f / 9.810f);
+
+ /* convert gravity to domain space */
+ gravity_mag = len_v3(gravity);
+ mul_mat3_m4_v3(mds->imat, gravity);
+ normalize_v3(gravity);
+ mul_v3_fl(gravity, gravity_mag);
+
+ mds->gravity[0] = gravity[0];
+ mds->gravity[1] = gravity[1];
+ mds->gravity[2] = gravity[2];
+ }
+}
+
+static int mantaModifier_init(
+ MantaModifierData *mmd, Depsgraph *depsgraph, Object *ob, Scene *scene, Mesh *me)
+{
+ int scene_framenr = (int)DEG_get_ctime(depsgraph);
+
+ if ((mmd->type & MOD_MANTA_TYPE_DOMAIN) && mmd->domain && !mmd->domain->fluid) {
+ MantaDomainSettings *mds = mmd->domain;
+ int res[3];
+ /* set domain dimensions from mesh */
+ manta_set_domain_from_mesh(mds, ob, me, true);
+ /* set domain gravity */
+ manta_set_domain_gravity(scene, mds);
+ /* reset domain values */
+ zero_v3_int(mds->shift);
+ zero_v3(mds->shift_f);
+ add_v3_fl(mds->shift_f, 0.5f);
+ zero_v3(mds->prev_loc);
+ mul_m4_v3(ob->obmat, mds->prev_loc);
+ copy_m4_m4(mds->obmat, ob->obmat);
+
+ /* set resolutions */
+ if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS &&
+ mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN)
+ {
+ res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */
+ }
+ else {
+ copy_v3_v3_int(res, mds->base_res);
+ }
+ copy_v3_v3_int(mds->res, res);
+ mds->total_cells = mds->res[0] * mds->res[1] * mds->res[2];
+ mds->res_min[0] = mds->res_min[1] = mds->res_min[2] = 0;
+ copy_v3_v3_int(mds->res_max, res);
+
+ /* set time, frame length = 0.1 is at 25fps */
+ float fps = scene->r.frs_sec / scene->r.frs_sec_base;
+ mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale;
+ /* initially dt is equal to frame length (dt can change with adaptive-time stepping though) */
+ mds->dt = mds->frame_length;
+ mds->time_per_frame = 0;
+ mds->time_total = (scene_framenr-1) * mds->frame_length;
+
+ /* allocate fluid */
+ BKE_manta_reallocate_fluid(mds, mds->res, 0);
+
+ mmd->time = scene_framenr;
+
+ return 1;
+ }
+ else if (mmd->type & MOD_MANTA_TYPE_FLOW) {
+ if (!mmd->flow) {
+ mantaModifier_createType(mmd);
+ }
+ mmd->time = scene_framenr;
+ return 1;
+ }
+ else if (mmd->type & MOD_MANTA_TYPE_EFFEC) {
+ if (!mmd->effec) {
+ mantaModifier_createType(mmd);
+ }
+ mmd->time = scene_framenr;
+ return 1;
+ }
+ return 0;
+}
+
+static void mantaModifier_freeDomain(MantaModifierData *mmd)
+{
+ if (mmd->domain) {
+ if (mmd->domain->fluid) {
+ manta_free(mmd->domain->fluid);
+ }
+
+ if (mmd->domain->fluid_mutex) {
+ BLI_rw_mutex_free(mmd->domain->fluid_mutex);
+ }
+
+ if (mmd->domain->effector_weights) {
+ MEM_freeN(mmd->domain->effector_weights);
+ }
+ mmd->domain->effector_weights = NULL;
+
+ if (!(mmd->modifier.flag & eModifierFlag_SharedCaches)) {
+ BKE_ptcache_free_list(&(mmd->domain->ptcaches[0]));
+ mmd->domain->point_cache[0] = NULL;
+ }
+
+ if (mmd->domain->mesh_velocities) {
+ MEM_freeN(mmd->domain->mesh_velocities);
+ }
+ mmd->domain->mesh_velocities = NULL;
+
+ if (mmd->domain->coba) {
+ MEM_freeN(mmd->domain->coba);
+ }
+
+ MEM_freeN(mmd->domain);
+ mmd->domain = NULL;
+ }
+}
+
+static void mantaModifier_freeFlow(MantaModifierData *mmd)
+{
+ if (mmd->flow) {
+ if (mmd->flow->mesh) {
+ BKE_id_free(NULL, mmd->flow->mesh);
+ }
+ mmd->flow->mesh = NULL;
+
+ if (mmd->flow->verts_old) {
+ MEM_freeN(mmd->flow->verts_old);
+ }
+ mmd->flow->verts_old = NULL;
+ mmd->flow->numverts = 0;
+
+ MEM_freeN(mmd->flow);
+ mmd->flow = NULL;
+ }
+}
+
+static void mantaModifier_freeCollision(MantaModifierData *mmd)
+{
+ if (mmd->effec) {
+ if (mmd->effec->mesh) {
+ BKE_id_free(NULL, mmd->effec->mesh);
+ }
+ mmd->effec->mesh = NULL;
+
+ if (mmd->effec->verts_old) {
+ MEM_freeN(mmd->effec->verts_old);
+ }
+ mmd->effec->verts_old = NULL;
+ mmd->effec->numverts = 0;
+
+ MEM_freeN(mmd->effec);
+ mmd->effec = NULL;
+ }
+}
+
+static void mantaModifier_reset_ex(struct MantaModifierData *mmd, bool need_lock)
+{
+ if (mmd) {
+ if (mmd->domain) {
+ if (mmd->domain->fluid) {
+ if (need_lock) {
+ BLI_rw_mutex_lock(mmd->domain->fluid_mutex, THREAD_LOCK_WRITE);
+ }
+
+ manta_free(mmd->domain->fluid);
+ mmd->domain->fluid = NULL;
+
+ if (need_lock) {
+ BLI_rw_mutex_unlock(mmd->domain->fluid_mutex);
+ }
+ }
+
+ mmd->time = -1;
+ mmd->domain->total_cells = 0;
+ mmd->domain->active_fields = 0;
+ }
+ else if (mmd->flow) {
+ if (mmd->flow->verts_old) {
+ MEM_freeN(mmd->flow->verts_old);
+ }
+ mmd->flow->verts_old = NULL;
+ mmd->flow->numverts = 0;
+ }
+ else if (mmd->effec) {
+ if (mmd->effec->verts_old) {
+ MEM_freeN(mmd->effec->verts_old);
+ }
+ mmd->effec->verts_old = NULL;
+ mmd->effec->numverts = 0;
+ }
+ }
+}
+
+void mantaModifier_reset(struct MantaModifierData *mmd)
+{
+ mantaModifier_reset_ex(mmd, true);
+}
+
+void mantaModifier_free(MantaModifierData *mmd)
+{
+ if (mmd) {
+ mantaModifier_freeDomain(mmd);
+ mantaModifier_freeFlow(mmd);
+ mantaModifier_freeCollision(mmd);
+ }
+}
+
+void mantaModifier_createType(struct MantaModifierData *mmd)
+{
+ if (mmd) {
+ if (mmd->type & MOD_MANTA_TYPE_DOMAIN) {
+ if (mmd->domain) {
+ mantaModifier_freeDomain(mmd);
+ }
+
+ /* domain object data */
+ mmd->domain = MEM_callocN(sizeof(MantaDomainSettings), "MantaDomain");
+ mmd->domain->mmd = mmd;
+ mmd->domain->effector_weights = BKE_effector_add_weights(NULL);
+ mmd->domain->fluid = NULL;
+ mmd->domain->fluid_mutex = BLI_rw_mutex_alloc();
+ mmd->domain->eff_group = NULL;
+ mmd->domain->fluid_group = NULL;
+ mmd->domain->coll_group = NULL;
+
+ /* adaptive domain options */
+ mmd->domain->adapt_margin = 4;
+ mmd->domain->adapt_res = 0;
+ mmd->domain->adapt_threshold = 0.02f;
+
+ /* fluid domain options */
+ mmd->domain->maxres = 64;
+ mmd->domain->solver_res = 3;
+ mmd->domain->border_collisions = 0; // open domain
+ mmd->domain->flags = FLUID_DOMAIN_USE_DISSOLVE_LOG | FLUID_DOMAIN_USE_ADAPTIVE_TIME;
+ mmd->domain->gravity[0] = 0.0f;
+ mmd->domain->gravity[1] = 0.0f;
+ mmd->domain->gravity[2] = -1.0f;
+ mmd->domain->active_fields = 0;
+ mmd->domain->type = FLUID_DOMAIN_TYPE_GAS;
+ mmd->domain->boundary_width = 1;
+
+ /* smoke domain options */
+ mmd->domain->alpha = 1.0f;
+ mmd->domain->beta = 1.0f;
+ mmd->domain->diss_speed = 5;
+ mmd->domain->vorticity = 0;
+ mmd->domain->active_color[0] = 0.0f;
+ mmd->domain->active_color[1] = 0.0f;
+ mmd->domain->active_color[2] = 0.0f;
+ mmd->domain->highres_sampling = SM_HRES_FULLSAMPLE;
+
+ /* flame options */
+ mmd->domain->burning_rate = 0.75f;
+ mmd->domain->flame_smoke = 1.0f;
+ mmd->domain->flame_vorticity = 0.5f;
+ mmd->domain->flame_ignition = 1.5f;
+ mmd->domain->flame_max_temp = 3.0f;
+ mmd->domain->flame_smoke_color[0] = 0.7f;
+ mmd->domain->flame_smoke_color[1] = 0.7f;
+ mmd->domain->flame_smoke_color[2] = 0.7f;
+
+ /* noise options */
+ mmd->domain->noise_strength = 1.0;
+ mmd->domain->noise_pos_scale = 2.0f;
+ mmd->domain->noise_time_anim = 0.1f;
+ mmd->domain->noise_scale = 2;
+ mmd->domain->noise_type = FLUID_NOISE_TYPE_WAVELET;
+
+ /* liquid domain options */
+ mmd->domain->particle_randomness = 0.1f;
+ mmd->domain->particle_number = 2;
+ mmd->domain->particle_minimum = 8;
+ mmd->domain->particle_maximum = 16;
+ mmd->domain->particle_radius = 1.8f;
+ mmd->domain->particle_band_width = 3.0f;
+
+ /* diffusion options*/
+ mmd->domain->surface_tension = 0.0f;
+ mmd->domain->viscosity_base = 1.0f;
+ mmd->domain->viscosity_exponent = 6.0f;
+ mmd->domain->domain_size = 0.5f;
+
+ /* mesh options */
+ mmd->domain->mesh_velocities = NULL;
+ mmd->domain->mesh_concave_upper = 3.5f;
+ mmd->domain->mesh_concave_lower = 0.4f;
+ mmd->domain->mesh_smoothen_pos = 1;
+ mmd->domain->mesh_smoothen_neg = 1;
+ mmd->domain->mesh_scale = 2;
+ mmd->domain->totvert = 0;
+ mmd->domain->mesh_generator = FLUID_DOMAIN_MESH_IMPROVED;
+
+ /* secondary particle options */
+ mmd->domain->sndparticle_tau_min_wc = 2.0;
+ mmd->domain->sndparticle_tau_max_wc = 8.0;
+ mmd->domain->sndparticle_tau_min_ta = 5.0;
+ mmd->domain->sndparticle_tau_max_ta = 20.0;
+ mmd->domain->sndparticle_tau_min_k = 1.0;
+ mmd->domain->sndparticle_tau_max_k = 5.0;
+ mmd->domain->sndparticle_k_wc = 200;
+ mmd->domain->sndparticle_k_ta = 40;
+ mmd->domain->sndparticle_k_b = 0.5;
+ mmd->domain->sndparticle_k_d = 0.6;
+ mmd->domain->sndparticle_l_min = 10.0;
+ mmd->domain->sndparticle_l_max = 25.0;
+ mmd->domain->sndparticle_boundary = SNDPARTICLE_BOUNDARY_DELETE;
+ mmd->domain->sndparticle_combined_export = SNDPARTICLE_COMBINED_EXPORT_OFF;
+ mmd->domain->sndparticle_potential_radius = 2;
+ mmd->domain->sndparticle_update_radius = 2;
+ mmd->domain->particle_type = 0;
+ mmd->domain->particle_scale = 1;
+
+ /* fluid guiding options */
+ mmd->domain->guiding_parent = NULL;
+ mmd->domain->guiding_alpha = 2.0f;
+ mmd->domain->guiding_beta = 5;
+ mmd->domain->guiding_vel_factor = 2.0f;
+ mmd->domain->guide_res = NULL;
+ mmd->domain->guiding_source = FLUID_DOMAIN_GUIDING_SRC_DOMAIN;
+
+ /* cache options */
+ mmd->domain->cache_frame_start = 1;
+ mmd->domain->cache_frame_end = 50;
+ mmd->domain->cache_frame_pause_data = 0;
+ mmd->domain->cache_frame_pause_noise = 0;
+ mmd->domain->cache_frame_pause_mesh = 0;
+ mmd->domain->cache_frame_pause_particles = 0;
+ mmd->domain->cache_frame_pause_guiding = 0;
+ mmd->domain->cache_flag = 0;
+ mmd->domain->cache_mesh_format = FLUID_DOMAIN_FILE_BIN_OBJECT;
+ mmd->domain->cache_data_format = FLUID_DOMAIN_FILE_UNI;
+ mmd->domain->cache_particle_format = FLUID_DOMAIN_FILE_UNI;
+ mmd->domain->cache_noise_format = FLUID_DOMAIN_FILE_UNI;
+ modifier_path_init(mmd->domain->cache_directory,
+ sizeof(mmd->domain->cache_directory),
+ FLUID_DOMAIN_DIR_DEFAULT);
+
+ /* time options */
+ mmd->domain->time_scale = 1.0;
+ mmd->domain->cfl_condition = 4.0;
+
+ /* display options */
+ mmd->domain->slice_method = FLUID_DOMAIN_SLICE_VIEW_ALIGNED;
+ mmd->domain->axis_slice_method = AXIS_SLICE_FULL;
+ mmd->domain->slice_axis = 0;
+ mmd->domain->interp_method = 0;
+ mmd->domain->draw_velocity = false;
+ mmd->domain->slice_per_voxel = 5.0f;
+ mmd->domain->slice_depth = 0.5f;
+ mmd->domain->display_thickness = 1.0f;
+ mmd->domain->coba = NULL;
+ mmd->domain->vector_scale = 1.0f;
+ mmd->domain->vector_draw_type = VECTOR_DRAW_NEEDLE;
+ mmd->domain->use_coba = false;
+ mmd->domain->coba_field = FLUID_DOMAIN_FIELD_DENSITY;
+
+ /* -- Deprecated / unsed options (below)-- */
+
+ /* pointcache options */
+ BLI_listbase_clear(&mmd->domain->ptcaches[1]);
+ mmd->domain->point_cache[0] = BKE_ptcache_add(&(mmd->domain->ptcaches[0]));
+ mmd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE;
+ mmd->domain->point_cache[0]->step = 1;
+ mmd->domain->point_cache[1] = NULL; /* Deprecated */
+ mmd->domain->cache_comp = SM_CACHE_LIGHT;
+ mmd->domain->cache_high_comp = SM_CACHE_LIGHT;
+
+ /* OpenVDB cache options */
+#ifdef WITH_OPENVDB_BLOSC
+ mmd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC;
+#else
+ mmd->domain->openvdb_comp = VDB_COMPRESSION_ZIP;
+#endif
+ mmd->domain->clipping = 1e-3f;
+ mmd->domain->data_depth = 0;
+ }
+ else if (mmd->type & MOD_MANTA_TYPE_FLOW) {
+ if (mmd->flow) {
+ mantaModifier_freeFlow(mmd);
+ }
+
+ /* flow object data */
+ mmd->flow = MEM_callocN(sizeof(MantaFlowSettings), "MantaFlow");
+ mmd->flow->mmd = mmd;
+ mmd->flow->mesh = NULL;
+ mmd->flow->psys = NULL;
+ mmd->flow->noise_texture = NULL;
+
+ /* initial velocity */
+ mmd->flow->verts_old = NULL;
+ mmd->flow->numverts = 0;
+ mmd->flow->vel_multi = 1.0f;
+ mmd->flow->vel_normal = 0.0f;
+ mmd->flow->vel_random = 0.0f;
+ mmd->flow->vel_coord[0] = 0.0f;
+ mmd->flow->vel_coord[1] = 0.0f;
+ mmd->flow->vel_coord[2] = 0.0f;
+
+ /* emission */
+ mmd->flow->density = 1.0f;
+ mmd->flow->color[0] = 0.7f;
+ mmd->flow->color[1] = 0.7f;
+ mmd->flow->color[2] = 0.7f;
+ mmd->flow->fuel_amount = 1.0f;
+ mmd->flow->temp = 1.0f;
+ mmd->flow->volume_density = 0.0f;
+ mmd->flow->surface_distance = 1.5f;
+ mmd->flow->particle_size = 1.0f;
+ mmd->flow->subframes = 0;
+
+ /* texture control */
+ mmd->flow->source = FLUID_FLOW_SOURCE_MESH;
+ mmd->flow->texture_size = 1.0f;
+
+ mmd->flow->type = FLUID_FLOW_TYPE_SMOKE;
+ mmd->flow->behavior = FLUID_FLOW_BEHAVIOR_GEOMETRY;
+ mmd->flow->type = FLUID_FLOW_TYPE_SMOKE;
+ mmd->flow->flags = FLUID_FLOW_ABSOLUTE | FLUID_FLOW_USE_PART_SIZE | FLUID_FLOW_USE_INFLOW;
+ }
+ else if (mmd->type & MOD_MANTA_TYPE_EFFEC) {
+ if (mmd->effec) {
+ mantaModifier_freeCollision(mmd);
+ }
+
+ /* effector object data */
+ mmd->effec = MEM_callocN(sizeof(MantaCollSettings), "MantaColl");
+ mmd->effec->mmd = mmd;
+ mmd->effec->mesh = NULL;
+ mmd->effec->verts_old = NULL;
+ mmd->effec->numverts = 0;
+ mmd->effec->surface_distance = 0.5f;
+ mmd->effec->type = FLUID_EFFECTOR_TYPE_COLLISION;
+
+ /* guiding options */
+ mmd->effec->guiding_mode = FLUID_EFFECTOR_GUIDING_MAXIMUM;
+ mmd->effec->vel_multi = 1.0f;
+ }
+ }
+}
+
+void mantaModifier_copy(const struct MantaModifierData *mmd,
+ struct MantaModifierData *tmmd,
+ const int flag)
+{
+ tmmd->type = mmd->type;
+ tmmd->time = mmd->time;
+
+ mantaModifier_createType(tmmd);
+
+ if (tmmd->domain) {
+ MantaDomainSettings *tmds = tmmd->domain;
+ MantaDomainSettings *mds = mmd->domain;
+
+ /* domain object data */
+ tmds->fluid_group = mds->fluid_group;
+ tmds->eff_group = mds->eff_group;
+ tmds->coll_group = mds->coll_group;
+ MEM_freeN(tmds->effector_weights);
+ tmds->effector_weights = MEM_dupallocN(mds->effector_weights);
+
+ /* adaptive domain options */
+ tmds->adapt_margin = mds->adapt_margin;
+ tmds->adapt_res = mds->adapt_res;
+ tmds->adapt_threshold = mds->adapt_threshold;
+
+ /* fluid domain options */
+ tmds->maxres = mds->maxres;
+ tmds->solver_res = mds->solver_res;
+ tmds->border_collisions = mds->border_collisions;
+ tmds->flags = mds->flags;
+ tmds->gravity[0] = mds->gravity[0];
+ tmds->gravity[1] = mds->gravity[1];
+ tmds->gravity[2] = mds->gravity[2];
+ tmds->active_fields = mds->active_fields;
+ tmds->type = mds->type;
+ tmds->boundary_width = mds->boundary_width;
+
+ /* smoke domain options */
+ tmds->alpha = mds->alpha;
+ tmds->beta = mds->beta;
+ tmds->diss_speed = mds->diss_speed;
+ tmds->vorticity = mds->vorticity;
+ tmds->highres_sampling = mds->highres_sampling;
+
+ /* flame options */
+ tmds->burning_rate = mds->burning_rate;
+ tmds->flame_smoke = mds->flame_smoke;
+ tmds->flame_vorticity = mds->flame_vorticity;
+ tmds->flame_ignition = mds->flame_ignition;
+ tmds->flame_max_temp = mds->flame_max_temp;
+ copy_v3_v3(tmds->flame_smoke_color, mds->flame_smoke_color);
+
+ /* noise options */
+ tmds->noise_strength = mds->noise_strength;
+ tmds->noise_pos_scale = mds->noise_pos_scale;
+ tmds->noise_time_anim = mds->noise_time_anim;
+ tmds->noise_scale = mds->noise_scale;
+ tmds->noise_type = mds->noise_type;
+
+ /* liquid domain options */
+ tmds->particle_randomness = mds->particle_randomness;
+ tmds->particle_number = mds->particle_number;
+ tmds->particle_minimum = mds->particle_minimum;
+ tmds->particle_maximum = mds->particle_maximum;
+ tmds->particle_radius = mds->particle_radius;
+ tmds->particle_band_width = mds->particle_band_width;
+
+ /* diffusion options*/
+ tmds->surface_tension = mds->surface_tension;
+ tmds->viscosity_base = mds->viscosity_base;
+ tmds->viscosity_exponent = mds->viscosity_exponent;
+ tmds->domain_size = mds->domain_size;
+
+ /* mesh options */
+ if (mds->mesh_velocities) {
+ tmds->mesh_velocities = MEM_dupallocN(mds->mesh_velocities);
+ }
+ tmds->mesh_concave_upper = mds->mesh_concave_upper;
+ tmds->mesh_concave_lower = mds->mesh_concave_lower;
+ tmds->mesh_smoothen_pos = mds->mesh_smoothen_pos;
+ tmds->mesh_smoothen_neg = mds->mesh_smoothen_neg;
+ tmds->mesh_scale = mds->mesh_scale;
+ tmds->totvert = mds->totvert;
+ tmds->mesh_generator = mds->mesh_generator;
+
+ /* secondary particle options */
+ tmds->sndparticle_k_b = mds->sndparticle_k_b;
+ tmds->sndparticle_k_d = mds->sndparticle_k_d;
+ tmds->sndparticle_k_ta = mds->sndparticle_k_ta;
+ tmds->sndparticle_k_wc = mds->sndparticle_k_wc;
+ tmds->sndparticle_l_max = mds->sndparticle_l_max;
+ tmds->sndparticle_l_min = mds->sndparticle_l_min;
+ tmds->sndparticle_tau_max_k = mds->sndparticle_tau_max_k;
+ tmds->sndparticle_tau_max_ta = mds->sndparticle_tau_max_ta;
+ tmds->sndparticle_tau_max_wc = mds->sndparticle_tau_max_wc;
+ tmds->sndparticle_tau_min_k = mds->sndparticle_tau_min_k;
+ tmds->sndparticle_tau_min_ta = mds->sndparticle_tau_min_ta;
+ tmds->sndparticle_tau_min_wc = mds->sndparticle_tau_min_wc;
+ tmds->sndparticle_boundary = mds->sndparticle_boundary;
+ tmds->sndparticle_combined_export = mds->sndparticle_combined_export;
+ tmds->sndparticle_potential_radius = mds->sndparticle_potential_radius;
+ tmds->sndparticle_update_radius = mds->sndparticle_update_radius;
+ tmds->particle_type = mds->particle_type;
+ tmds->particle_scale = mds->particle_scale;
+
+ /* fluid guiding options */
+ tmds->guiding_parent = mds->guiding_parent;
+ tmds->guiding_alpha = mds->guiding_alpha;
+ tmds->guiding_beta = mds->guiding_beta;
+ tmds->guiding_vel_factor = mds->guiding_vel_factor;
+ tmds->guide_res = mds->guide_res;
+ tmds->guiding_source = mds->guiding_source;
+
+ /* cache options */
+ tmds->cache_frame_start = mds->cache_frame_start;
+ tmds->cache_frame_end = mds->cache_frame_end;
+ tmds->cache_frame_pause_data = mds->cache_frame_pause_data;
+ tmds->cache_frame_pause_noise = mds->cache_frame_pause_noise;
+ tmds->cache_frame_pause_mesh = mds->cache_frame_pause_mesh;
+ tmds->cache_frame_pause_particles = mds->cache_frame_pause_particles;
+ tmds->cache_frame_pause_guiding = mds->cache_frame_pause_guiding;
+ tmds->cache_flag = mds->cache_flag;
+ tmds->cache_mesh_format = mds->cache_mesh_format;
+ tmds->cache_data_format = mds->cache_data_format;
+ tmds->cache_particle_format = mds->cache_particle_format;
+ tmds->cache_noise_format = mds->cache_noise_format;
+ BLI_strncpy(tmds->cache_directory, mds->cache_directory, sizeof(tmds->cache_directory));
+
+ /* time options */
+ tmds->time_scale = mds->time_scale;
+ tmds->cfl_condition = mds->cfl_condition;
+
+ /* display options */
+ tmds->slice_method = mds->slice_method;
+ tmds->axis_slice_method = mds->axis_slice_method;
+ tmds->slice_axis = mds->slice_axis;
+ tmds->interp_method = mds->interp_method;
+ tmds->draw_velocity = mds->draw_velocity;
+ tmds->slice_per_voxel = mds->slice_per_voxel;
+ tmds->slice_depth = mds->slice_depth;
+ tmds->display_thickness = mds->display_thickness;
+ if (mds->coba) {
+ tmds->coba = MEM_dupallocN(mds->coba);
+ }
+ tmds->vector_scale = mds->vector_scale;
+ tmds->vector_draw_type = mds->vector_draw_type;
+ tmds->use_coba = mds->use_coba;
+ tmds->coba_field = mds->coba_field;
+
+ /* -- Deprecated / unsed options (below)-- */
+
+ /* pointcache options */
+ BKE_ptcache_free_list(&(tmds->ptcaches[0]));
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ /* Share the cache with the original object's modifier. */
+ tmmd->modifier.flag |= eModifierFlag_SharedCaches;
+ tmds->point_cache[0] = mds->point_cache[0];
+ tmds->ptcaches[0] = mds->ptcaches[0];
+ }
+ else {
+ tmds->point_cache[0] = BKE_ptcache_copy_list(
+ &(tmds->ptcaches[0]), &(mds->ptcaches[0]), flag);
+ }
+
+ /* OpenVDB cache options */
+ tmds->openvdb_comp = mds->openvdb_comp;
+ tmds->clipping = mds->clipping;
+ tmds->data_depth = mds->data_depth;
+ }
+ else if (tmmd->flow) {
+ MantaFlowSettings *tsfs = tmmd->flow;
+ MantaFlowSettings *sfs = mmd->flow;
+
+ tsfs->psys = sfs->psys;
+ tsfs->noise_texture = sfs->noise_texture;
+
+ /* initial velocity */
+ tsfs->vel_multi = sfs->vel_multi;
+ tsfs->vel_normal = sfs->vel_normal;
+ tsfs->vel_random = sfs->vel_random;
+ tsfs->vel_coord[0] = sfs->vel_coord[0];
+ tsfs->vel_coord[1] = sfs->vel_coord[1];
+ tsfs->vel_coord[2] = sfs->vel_coord[2];
+
+ /* emission */
+ tsfs->density = sfs->density;
+ copy_v3_v3(tsfs->color, sfs->color);
+ tsfs->fuel_amount = sfs->fuel_amount;
+ tsfs->temp = sfs->temp;
+ tsfs->volume_density = sfs->volume_density;
+ tsfs->surface_distance = sfs->surface_distance;
+ tsfs->particle_size = sfs->particle_size;
+ tsfs->subframes = sfs->subframes;
+
+ /* texture control */
+ tsfs->texture_size = sfs->texture_size;
+ tsfs->texture_offset = sfs->texture_offset;
+ BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name));
+ tsfs->vgroup_density = sfs->vgroup_density;
+
+ tsfs->type = sfs->type;
+ tsfs->behavior = sfs->behavior;
+ tsfs->source = sfs->source;
+ tsfs->texture_type = sfs->texture_type;
+ tsfs->flags = sfs->flags;
+ }
+ else if (tmmd->effec) {
+ MantaCollSettings *tscs = tmmd->effec;
+ MantaCollSettings *scs = mmd->effec;
+
+ tscs->surface_distance = scs->surface_distance;
+ tscs->type = scs->type;
+
+ /* guiding options */
+ tscs->guiding_mode = scs->guiding_mode;
+ tscs->vel_multi = scs->vel_multi;
+ }
+}
+
+// forward declaration
+static void manta_smoke_calc_transparency(MantaDomainSettings *mds, ViewLayer *view_layer);
+static float calc_voxel_transp(
+ float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
+static void update_mesh_distances(int index,
+ float *mesh_distances,
+ BVHTreeFromMesh *treeData,
+ const float ray_start[3],
+ float surface_thickness);
+
+static int get_light(ViewLayer *view_layer, float *light)
+{
+ Base *base_tmp = NULL;
+ int found_light = 0;
+
+ // try to find a lamp, preferably local
+ for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
+ if (base_tmp->object->type == OB_LAMP) {
+ Light *la = base_tmp->object->data;
+
+ if (la->type == LA_LOCAL) {
+ copy_v3_v3(light, base_tmp->object->obmat[3]);
+ return 1;
+ }
+ else if (!found_light) {
+ copy_v3_v3(light, base_tmp->object->obmat[3]);
+ found_light = 1;
+ }
+ }
+ }
+
+ return found_light;
+}
+
+/**********************************************************
+ * Obstacles
+ **********************************************************/
+
+typedef struct ObstaclesFromDMData {
+ MantaDomainSettings *mds;
+ MantaCollSettings *scs;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *looptri;
+ BVHTreeFromMesh *tree;
+
+ bool has_velocity;
+ float *vert_vel;
+ float *velocityX, *velocityY, *velocityZ;
+ int *num_objects;
+ float *distances_map;
+} ObstaclesFromDMData;
+
+static void obstacles_from_mesh_task_cb(void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ ObstaclesFromDMData *data = userdata;
+ MantaDomainSettings *mds = data->mds;
+
+ /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
+ const float surface_distance = 2.0f; //0.867f;
+ /* Note: Use larger surface distance to cover larger area with obvel. Manta will use these obvels and extrapolate them (inside and outside obstacle) */
+
+ for (int x = mds->res_min[0]; x < mds->res_max[0]; x++) {
+ for (int y = mds->res_min[1]; y < mds->res_max[1]; y++) {
+ const int index = manta_get_index(
+ x - mds->res_min[0], mds->res[0], y - mds->res_min[1], mds->res[1], z - mds->res_min[2]);
+
+ float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
+ BVHTreeNearest nearest = {0};
+ nearest.index = -1;
+ nearest.dist_sq = surface_distance *
+ surface_distance; /* find_nearest uses squared distance */
+ bool hasIncObj = false;
+
+ /* find the nearest point on the mesh */
+ if (BLI_bvhtree_find_nearest(
+ data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) !=
+ -1) {
+ const MLoopTri *lt = &data->looptri[nearest.index];
+ float weights[3];
+ int v1, v2, v3;
+
+ /* calculate barycentric weights for nearest point */
+ v1 = data->mloop[lt->tri[0]].v;
+ v2 = data->mloop[lt->tri[1]].v;
+ v3 = data->mloop[lt->tri[2]].v;
+ interp_weights_tri_v3(
+ weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
+
+ if (data->has_velocity) {
+ /* increase object count */
+ data->num_objects[index]++;
+ hasIncObj = true;
+
+ /* apply object velocity */
+ float hit_vel[3];
+ interp_v3_v3v3v3(hit_vel,
+ &data->vert_vel[v1 * 3],
+ &data->vert_vel[v2 * 3],
+ &data->vert_vel[v3 * 3],
+ weights);
+
+ /* Guiding has additional velocity multiplier */
+ if (data->scs->type == FLUID_EFFECTOR_TYPE_GUIDE) {
+ mul_v3_fl(hit_vel, data->scs->vel_multi);
+
+ switch (data->scs->guiding_mode) {
+ case FLUID_EFFECTOR_GUIDING_AVERAGED:
+ data->velocityX[index] = (data->velocityX[index] + hit_vel[0]) * 0.5f;
+ data->velocityY[index] = (data->velocityY[index] + hit_vel[1]) * 0.5f;
+ data->velocityZ[index] = (data->velocityZ[index] + hit_vel[2]) * 0.5f;
+ break;
+ case FLUID_EFFECTOR_GUIDING_OVERRIDE:
+ data->velocityX[index] = hit_vel[0];
+ data->velocityY[index] = hit_vel[1];
+ data->velocityZ[index] = hit_vel[2];
+ break;
+ case FLUID_EFFECTOR_GUIDING_MINIMUM:
+ data->velocityX[index] = MIN2(fabsf(hit_vel[0]), fabsf(data->velocityX[index]));
+ data->velocityY[index] = MIN2(fabsf(hit_vel[1]), fabsf(data->velocityY[index]));
+ data->velocityZ[index] = MIN2(fabsf(hit_vel[2]), fabsf(data->velocityZ[index]));
+ break;
+ case FLUID_EFFECTOR_GUIDING_MAXIMUM:
+ default:
+ data->velocityX[index] = MAX2(fabsf(hit_vel[0]), fabsf(data->velocityX[index]));
+ data->velocityY[index] = MAX2(fabsf(hit_vel[1]), fabsf(data->velocityY[index]));
+ data->velocityZ[index] = MAX2(fabsf(hit_vel[2]), fabsf(data->velocityZ[index]));
+ break;
+ }
+ }
+ else {
+ /* Apply (i.e. add) effector object velocity */
+ data->velocityX[index] += (data->scs->type == FLUID_EFFECTOR_TYPE_GUIDE) ?
+ hit_vel[0] * data->scs->vel_multi :
+ hit_vel[0];
+ data->velocityY[index] += (data->scs->type == FLUID_EFFECTOR_TYPE_GUIDE) ?
+ hit_vel[1] * data->scs->vel_multi :
+ hit_vel[1];
+ data->velocityZ[index] += (data->scs->type == FLUID_EFFECTOR_TYPE_GUIDE) ?
+ hit_vel[2] * data->scs->vel_multi :
+ hit_vel[2];
+ //printf("adding effector object vel: [%f, %f, %f], dx is: %f\n", hit_vel[0], hit_vel[1], hit_vel[2], mds->dx);
+ }
+ }
+ }
+
+ /* Get distance to mesh surface from both within and outside grid (mantaflow phi grid) */
+ if (data->distances_map) {
+ update_mesh_distances(
+ index, data->distances_map, data->tree, ray_start, data->scs->surface_distance);
+
+ /* Ensure that num objects are also counted inside object. But dont count twice (see object inc for nearest point) */
+ if (data->distances_map[index] < 0 && !hasIncObj) {
+ data->num_objects[index]++;
+ }
+ }
+ }
+ }
+}
+
+static void obstacles_from_mesh(Object *coll_ob,
+ MantaDomainSettings *mds,
+ MantaCollSettings *scs,
+ float *distances_map,
+ float *velocityX,
+ float *velocityY,
+ float *velocityZ,
+ int *num_objects,
+ float dt)
+{
+ if (!scs->mesh) {
+ return;
+ }
+ {
+ Mesh *me = NULL;
+ MVert *mvert = NULL;
+ const MLoopTri *looptri;
+ const MLoop *mloop;
+ BVHTreeFromMesh treeData = {NULL};
+ int numverts, i;
+
+ float *vert_vel = NULL;
+ bool has_velocity = false;
+
+ me = BKE_mesh_copy_for_eval(scs->mesh, true);
+
+ /* Duplicate vertices to modify. */
+ if (me->mvert) {
+ me->mvert = MEM_dupallocN(me->mvert);
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+ }
+
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ mloop = me->mloop;
+ looptri = BKE_mesh_runtime_looptri_ensure(me);
+ numverts = me->totvert;
+
+ /* TODO (sebbas):
+ * Make vert_vel init optional?
+ * code is in trouble if the object moves but is declared as "does not move" */
+ {
+ vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "manta_obs_velocity");
+
+ if (scs->numverts != numverts || !scs->verts_old) {
+ if (scs->verts_old) {
+ MEM_freeN(scs->verts_old);
+ }
+
+ scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "manta_obs_verts_old");
+ scs->numverts = numverts;
+ }
+ else {
+ has_velocity = true;
+ }
+ }
+
+ /* Transform collider vertices to
+ * domain grid space for fast lookups */
+ for (i = 0; i < numverts; i++) {
+ float n[3];
+ float co[3];
+
+ /* vert pos */
+ mul_m4_v3(coll_ob->obmat, mvert[i].co);
+ manta_pos_to_cell(mds, mvert[i].co);
+
+ /* vert normal */
+ normal_short_to_float_v3(n, mvert[i].no);
+ mul_mat3_m4_v3(coll_ob->obmat, n);
+ mul_mat3_m4_v3(mds->imat, n);
+ normalize_v3(n);
+ normal_float_to_short_v3(mvert[i].no, n);
+
+ /* vert velocity */
+ add_v3fl_v3fl_v3i(co, mvert[i].co, mds->shift);
+ if (has_velocity) {
+ sub_v3_v3v3(&vert_vel[i * 3], co, &scs->verts_old[i * 3]);
+ mul_v3_fl(&vert_vel[i * 3], mds->dx / dt);
+ }
+ copy_v3_v3(&scs->verts_old[i * 3], co);
+ }
+
+ if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
+ ObstaclesFromDMData data = {.mds = mds,
+ .scs = scs,
+ .mvert = mvert,
+ .mloop = mloop,
+ .looptri = looptri,
+ .tree = &treeData,
+ .has_velocity = has_velocity,
+ .vert_vel = vert_vel,
+ .velocityX = velocityX,
+ .velocityY = velocityY,
+ .velocityZ = velocityZ,
+ .num_objects = num_objects,
+ .distances_map = distances_map};
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(
+ mds->res_min[2], mds->res_max[2], &data, obstacles_from_mesh_task_cb, &settings);
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+ BKE_id_free(NULL, me);
+
+ if (vert_vel) {
+ MEM_freeN(vert_vel);
+ }
+ if (me->mvert) {
+ MEM_freeN(me->mvert);
+ }
+ }
+}
+
+static void update_obstacleflags(MantaDomainSettings *mds, Object **collobjs, int numcollobj)
+{
+ int active_fields = mds->active_fields;
+ unsigned int collIndex;
+
+ /* Monitor active fields based on flow settings */
+ for (collIndex = 0; collIndex < numcollobj; collIndex++) {
+ Object *collob = collobjs[collIndex];
+ MantaModifierData *mmd2 = (MantaModifierData *)modifiers_findByType(collob,
+ eModifierType_Manta);
+
+ if ((mmd2->type & MOD_MANTA_TYPE_EFFEC) && mmd2->effec) {
+ MantaCollSettings *scs = mmd2->effec;
+ if (!scs) {
+ break;
+ }
+ if (scs->type == FLUID_EFFECTOR_TYPE_COLLISION) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_OBSTACLE;
+ }
+ if (scs->type == FLUID_EFFECTOR_TYPE_GUIDE) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_GUIDING;
+ }
+ }
+ }
+ /* Finally, initialize new data fields if any */
+ if (active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) {
+ manta_ensure_obstacle(mds->fluid, mds->mmd);
+ }
+ if (active_fields & FLUID_DOMAIN_ACTIVE_GUIDING) {
+ manta_ensure_guiding(mds->fluid, mds->mmd);
+ }
+ mds->active_fields = active_fields;
+}
+
+/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */
+static void update_obstacles(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ MantaDomainSettings *mds,
+ float time_per_frame,
+ float frame_length,
+ int frame,
+ float dt)
+{
+ Object **collobjs = NULL;
+ unsigned int numcollobj = 0, collIndex = 0;
+
+ collobjs = BKE_collision_objects_create(
+ depsgraph, ob, mds->coll_group, &numcollobj, eModifierType_Manta);
+
+ /* Update all flow related flags and ensure that corresponding grids get initialized */
+ update_obstacleflags(mds, collobjs, numcollobj);
+
+ float *velx = manta_get_ob_velocity_x(mds->fluid);
+ float *vely = manta_get_ob_velocity_y(mds->fluid);
+ float *velz = manta_get_ob_velocity_z(mds->fluid);
+ float *velxGuide = manta_get_guide_velocity_x(mds->fluid);
+ float *velyGuide = manta_get_guide_velocity_y(mds->fluid);
+ float *velzGuide = manta_get_guide_velocity_z(mds->fluid);
+ float *velxOrig = manta_get_velocity_x(mds->fluid);
+ float *velyOrig = manta_get_velocity_y(mds->fluid);
+ float *velzOrig = manta_get_velocity_z(mds->fluid);
+ float *density = manta_smoke_get_density(mds->fluid);
+ float *fuel = manta_smoke_get_fuel(mds->fluid);
+ float *flame = manta_smoke_get_flame(mds->fluid);
+ float *r = manta_smoke_get_color_r(mds->fluid);
+ float *g = manta_smoke_get_color_g(mds->fluid);
+ float *b = manta_smoke_get_color_b(mds->fluid);
+ float *phiObsIn = manta_get_phiobs_in(mds->fluid);
+ float *phiGuideIn = manta_get_phiguide_in(mds->fluid);
+ int *obstacles = manta_smoke_get_obstacle(mds->fluid);
+ int *num_obstacles = manta_get_num_obstacle(mds->fluid);
+ int *num_guides = manta_get_num_guide(mds->fluid);
+ unsigned int z;
+
+ /* Grid reset before writing again */
+ for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) {
+ if (phiObsIn) {
+ phiObsIn[z] = 9999;
+ }
+ if (phiGuideIn) {
+ phiGuideIn[z] = 9999;
+ }
+ if (num_obstacles) {
+ num_obstacles[z] = 0;
+ }
+ if (num_guides) {
+ num_guides[z] = 0;
+ }
+
+ if (velx && vely && velz) {
+ velx[z] = 0.0f;
+ vely[z] = 0.0f;
+ velz[z] = 0.0f;
+ }
+ if (velxGuide && velyGuide && velzGuide) {
+ velxGuide[z] = 0.0f;
+ velyGuide[z] = 0.0f;
+ velzGuide[z] = 0.0f;
+ }
+ }
+
+ /* Prepare grids from effector objects */
+ for (collIndex = 0; collIndex < numcollobj; collIndex++) {
+ Object *collob = collobjs[collIndex];
+ MantaModifierData *mmd2 = (MantaModifierData *)modifiers_findByType(collob,
+ eModifierType_Manta);
+
+ // DG TODO: check if modifier is active?
+ if ((mmd2->type & MOD_MANTA_TYPE_EFFEC) && mmd2->effec) {
+ MantaCollSettings *scs = mmd2->effec;
+
+ /* Length of one frame. If using adaptive stepping, length is smaller than actual frame length */
+ float adaptframe_length = time_per_frame / frame_length;
+
+ /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene subframe parameter */
+ if (time_per_frame < frame_length) {
+ scene->r.subframe = adaptframe_length;
+ scene->r.cfra = frame - 1;
+ }
+ /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe parameter to 0 and advance current scene frame */
+ else {
+ scene->r.subframe = 0.0f;
+ scene->r.cfra = frame;
+ }
+ //printf("effector: frame: %d // scene current frame: %d // scene current subframe: %f\n", frame, scene->r.cfra, scene->r.subframe);
+
+ /* TODO (sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph) as subframes dont work with the latter yet */
+ BKE_object_modifier_update_subframe(
+ depsgraph, scene, collob, true, 5, BKE_scene_frame_get(scene), eModifierType_Manta);
+
+ if (scs && (scs->type == FLUID_EFFECTOR_TYPE_COLLISION)) {
+ obstacles_from_mesh(collob, mds, scs, phiObsIn, velx, vely, velz, num_obstacles, dt);
+ }
+ if (scs && (scs->type == FLUID_EFFECTOR_TYPE_GUIDE)) {
+ obstacles_from_mesh(
+ collob, mds, scs, phiGuideIn, velxGuide, velyGuide, velzGuide, num_guides, dt);
+ }
+ }
+ }
+
+ BKE_collision_objects_free(collobjs);
+
+ /* obstacle cells should not contain any velocity from the smoke simulation */
+ for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) {
+ if (obstacles[z] & 2) // mantaflow convention: FlagObstacle
+ {
+ if (velxOrig && velyOrig && velzOrig) {
+ velxOrig[z] = 0;
+ velyOrig[z] = 0;
+ velzOrig[z] = 0;
+ }
+ if (density) {
+ density[z] = 0;
+ }
+ if (fuel) {
+ fuel[z] = 0;
+ flame[z] = 0;
+ }
+ if (r) {
+ r[z] = 0;
+ g[z] = 0;
+ b[z] = 0;
+ }
+ }
+ /* average velocities from multiple obstacles in one cell */
+ if (num_obstacles && num_obstacles[z]) {
+ velx[z] /= num_obstacles[z];
+ vely[z] /= num_obstacles[z];
+ velz[z] /= num_obstacles[z];
+ }
+ /* average velocities from multiple guides in one cell */
+ if (num_guides && num_guides[z]) {
+ velxGuide[z] /= num_guides[z];
+ velyGuide[z] /= num_guides[z];
+ velzGuide[z] /= num_guides[z];
+ }
+ }
+}
+
+/**********************************************************
+ * Flow emission code
+ **********************************************************/
+
+typedef struct EmissionMap {
+ float *influence;
+ float *influence_high;
+ float *velocity;
+ float *distances;
+ float *distances_high;
+ int min[3], max[3], res[3];
+ int hmin[3], hmax[3], hres[3];
+ int total_cells, valid;
+} EmissionMap;
+
+static void em_boundInsert(EmissionMap *em, float point[3])
+{
+ int i = 0;
+ if (!em->valid) {
+ for (; i < 3; i++) {
+ em->min[i] = (int)floor(point[i]);
+ em->max[i] = (int)ceil(point[i]);
+ }
+ em->valid = 1;
+ }
+ else {
+ for (; i < 3; i++) {
+ if (point[i] < em->min[i]) {
+ em->min[i] = (int)floor(point[i]);
+ }
+ if (point[i] > em->max[i]) {
+ em->max[i] = (int)ceil(point[i]);
+ }
+ }
+ }
+}
+
+static void clampBoundsInDomain(MantaDomainSettings *mds,
+ int min[3],
+ int max[3],
+ float *min_vel,
+ float *max_vel,
+ int margin,
+ float dt)
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ int adapt = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) ? mds->adapt_res : 0;
+ /* add margin */
+ min[i] -= margin;
+ max[i] += margin;
+
+ /* adapt to velocity */
+ if (min_vel && min_vel[i] < 0.0f) {
+ min[i] += (int)floor(min_vel[i] * dt);
+ }
+ if (max_vel && max_vel[i] > 0.0f) {
+ max[i] += (int)ceil(max_vel[i] * dt);
+ }
+
+ /* clamp within domain max size */
+ CLAMP(min[i], -adapt, mds->base_res[i] + adapt);
+ CLAMP(max[i], -adapt, mds->base_res[i] + adapt);
+ }
+}
+
+static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
+{
+ int i, res[3];
+
+ for (i = 0; i < 3; i++) {
+ res[i] = em->max[i] - em->min[i];
+ if (res[i] <= 0) {
+ return;
+ }
+ }
+ em->total_cells = res[0] * res[1] * res[2];
+ copy_v3_v3_int(em->res, res);
+
+ em->influence = MEM_callocN(sizeof(float) * em->total_cells, "manta_flow_influence");
+ if (use_velocity) {
+ em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "manta_flow_velocity");
+ }
+
+ em->distances = MEM_callocN(sizeof(float) * em->total_cells, "fluid_flow_distances");
+ memset(em->distances, 0x7f7f7f7f, sizeof(float) * em->total_cells); // init to inf
+
+ /* allocate high resolution map if required */
+ if (hires_mul > 1) {
+ int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul);
+
+ for (i = 0; i < 3; i++) {
+ em->hmin[i] = em->min[i] * hires_mul;
+ em->hmax[i] = em->max[i] * hires_mul;
+ em->hres[i] = em->res[i] * hires_mul;
+ }
+
+ em->influence_high = MEM_callocN(sizeof(float) * total_cells_high,
+ "manta_flow_influence_high");
+ em->distances_high = MEM_callocN(sizeof(float) * total_cells_high,
+ "manta_flow_distances_high");
+ memset(em->distances_high, 0x7f7f7f7f, sizeof(float) * total_cells_high); // init to inf
+ }
+ em->valid = 1;
+}
+
+static void em_freeData(EmissionMap *em)
+{
+ if (em->influence) {
+ MEM_freeN(em->influence);
+ }
+ if (em->influence_high) {
+ MEM_freeN(em->influence_high);
+ }
+ if (em->velocity) {
+ MEM_freeN(em->velocity);
+ }
+ if (em->distances) {
+ MEM_freeN(em->distances);
+ }
+ if (em->distances_high) {
+ MEM_freeN(em->distances_high);
+ }
+}
+
+static void em_combineMaps(
+ EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size)
+{
+ int i, x, y, z;
+
+ /* copyfill input 1 struct and clear output for new allocation */
+ EmissionMap em1;
+ memcpy(&em1, output, sizeof(EmissionMap));
+ memset(output, 0, sizeof(EmissionMap));
+
+ for (i = 0; i < 3; i++) {
+ if (em1.valid) {
+ output->min[i] = MIN2(em1.min[i], em2->min[i]);
+ output->max[i] = MAX2(em1.max[i], em2->max[i]);
+ }
+ else {
+ output->min[i] = em2->min[i];
+ output->max[i] = em2->max[i];
+ }
+ }
+ /* allocate output map */
+ em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier);
+
+ /* base resolution inputs */
+ for (x = output->min[0]; x < output->max[0]; x++) {
+ for (y = output->min[1]; y < output->max[1]; y++) {
+ for (z = output->min[2]; z < output->max[2]; z++) {
+ int index_out = manta_get_index(x - output->min[0],
+ output->res[0],
+ y - output->min[1],
+ output->res[1],
+ z - output->min[2]);
+
+ /* initialize with first input if in range */
+ if (x >= em1.min[0] && x < em1.max[0] && y >= em1.min[1] && y < em1.max[1] &&
+ z >= em1.min[2] && z < em1.max[2]) {
+ int index_in = manta_get_index(
+ x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]);
+
+ /* values */
+ output->influence[index_out] = em1.influence[index_in];
+ output->distances[index_out] = em1.distances[index_in];
+ if (output->velocity && em1.velocity) {
+ copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]);
+ }
+ }
+
+ /* apply second input if in range */
+ if (x >= em2->min[0] && x < em2->max[0] && y >= em2->min[1] && y < em2->max[1] &&
+ z >= em2->min[2] && z < em2->max[2]) {
+ int index_in = manta_get_index(
+ x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]);
+
+ /* values */
+ if (additive) {
+ output->influence[index_out] += em2->influence[index_in] * sample_size;
+ }
+ else {
+ output->influence[index_out] = MAX2(em2->influence[index_in],
+ output->influence[index_out]);
+ }
+ output->distances[index_out] = MIN2(em2->distances[index_in],
+ output->distances[index_out]);
+ if (output->velocity && em2->velocity) {
+ /* last sample replaces the velocity */
+ output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3],
+ em2->velocity[index_in * 3]);
+ output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1],
+ em2->velocity[index_in * 3 + 1]);
+ output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2],
+ em2->velocity[index_in * 3 + 2]);
+ }
+ }
+ } // low res loop
+ }
+ }
+
+ /* initialize high resolution input if available */
+ if (output->influence_high) {
+ for (x = output->hmin[0]; x < output->hmax[0]; x++) {
+ for (y = output->hmin[1]; y < output->hmax[1]; y++) {
+ for (z = output->hmin[2]; z < output->hmax[2]; z++) {
+ int index_out = manta_get_index(x - output->hmin[0],
+ output->hres[0],
+ y - output->hmin[1],
+ output->hres[1],
+ z - output->hmin[2]);
+
+ /* initialize with first input if in range */
+ if (x >= em1.hmin[0] && x < em1.hmax[0] && y >= em1.hmin[1] && y < em1.hmax[1] &&
+ z >= em1.hmin[2] && z < em1.hmax[2]) {
+ int index_in = manta_get_index(
+ x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]);
+ /* values */
+ output->influence_high[index_out] = em1.influence_high[index_in];
+ }
+
+ /* apply second input if in range */
+ if (x >= em2->hmin[0] && x < em2->hmax[0] && y >= em2->hmin[1] && y < em2->hmax[1] &&
+ z >= em2->hmin[2] && z < em2->hmax[2]) {
+ int index_in = manta_get_index(
+ x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]);
+
+ /* values */
+ if (additive) {
+ output->influence_high[index_out] += em2->distances_high[index_in] * sample_size;
+ }
+ else {
+ output->distances_high[index_out] = MAX2(em2->distances_high[index_in],
+ output->distances_high[index_out]);
+ }
+ output->distances_high[index_out] = MIN2(em2->distances_high[index_in],
+ output->distances_high[index_out]);
+ }
+ } // high res loop
+ }
+ }
+ }
+
+ /* free original data */
+ em_freeData(&em1);
+}
+
+typedef struct EmitFromParticlesData {
+ MantaFlowSettings *sfs;
+ KDTree_3d *tree;
+ int hires_multiplier;
+
+ EmissionMap *em;
+ float *particle_vel;
+ float hr;
+
+ int *min, *max, *res;
+
+ float solid;
+ float smooth;
+ float hr_smooth;
+} EmitFromParticlesData;
+
+static void emit_from_particles_task_cb(void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ EmitFromParticlesData *data = userdata;
+ MantaFlowSettings *sfs = data->sfs;
+ EmissionMap *em = data->em;
+ const int hires_multiplier = data->hires_multiplier;
+
+ for (int x = data->min[0]; x < data->max[0]; x++) {
+ for (int y = data->min[1]; y < data->max[1]; y++) {
+ /* take low res samples where possible */
+ if (hires_multiplier <= 1 ||
+ !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
+ /* get low res space coordinates */
+ const int lx = x / hires_multiplier;
+ const int ly = y / hires_multiplier;
+ const int lz = z / hires_multiplier;
+
+ const int index = manta_get_index(
+ lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
+ const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
+
+ /* find particle distance from the kdtree */
+ KDTreeNearest_3d nearest;
+ const float range = data->solid + data->smooth;
+ BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
+
+ if (nearest.dist < range) {
+ em->influence[index] = (nearest.dist < data->solid) ?
+ 1.0f :
+ (1.0f - (nearest.dist - data->solid) / data->smooth);
+ /* Uses particle velocity as initial velocity for smoke */
+ if (sfs->flags & FLUID_FLOW_INITVELOCITY &&
+ (sfs->psys->part->phystype != PART_PHYS_NO)) {
+ madd_v3_v3fl(
+ &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], sfs->vel_multi);
+ }
+ }
+ }
+
+ /* take high res samples if required */
+ if (hires_multiplier > 1) {
+ /* get low res space coordinates */
+ const float lx = ((float)x) * data->hr;
+ const float ly = ((float)y) * data->hr;
+ const float lz = ((float)z) * data->hr;
+
+ const int index = manta_get_index(
+ x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
+ const float ray_start[3] = {
+ lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
+
+ /* find particle distance from the kdtree */
+ KDTreeNearest_3d nearest;
+ const float range = data->solid + data->hr_smooth;
+ BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
+
+ if (nearest.dist < range) {
+ em->influence_high[index] = (nearest.dist < data->solid) ?
+ 1.0f :
+ (1.0f - (nearest.dist - data->solid) / data->smooth);
+ }
+ }
+ }
+ }
+}
+
+static void emit_from_particles(Object *flow_ob,
+ MantaDomainSettings *mds,
+ MantaFlowSettings *sfs,
+ EmissionMap *em,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ float dt)
+{
+ if (sfs && sfs->psys && sfs->psys->part &&
+ ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected
+ {
+ ParticleSimulationData sim;
+ ParticleSystem *psys = sfs->psys;
+ float *particle_pos;
+ float *particle_vel;
+ int totpart = psys->totpart, totchild;
+ int p = 0;
+ int valid_particles = 0;
+ int bounds_margin = 1;
+
+ /* radius based flow */
+ const float solid = sfs->particle_size * 0.5f;
+ const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
+ int hires_multiplier = 1;
+ KDTree_3d *tree = NULL;
+
+ sim.depsgraph = depsgraph;
+ sim.scene = scene;
+ sim.ob = flow_ob;
+ sim.psys = psys;
+ sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+
+ /* prepare curvemapping tables */
+ if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) {
+ curvemapping_changed_all(psys->part->clumpcurve);
+ }
+ if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) {
+ curvemapping_changed_all(psys->part->roughcurve);
+ }
+ if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) {
+ curvemapping_changed_all(psys->part->twistcurve);
+ }
+
+ /* initialize particle cache */
+ if (psys->part->type == PART_HAIR) {
+ // TODO: PART_HAIR not supported whatsoever
+ totchild = 0;
+ }
+ else {
+ totchild = psys->totchild * psys->part->disp / 100;
+ }
+
+ particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "manta_flow_particles");
+ particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "manta_flow_particles");
+
+ /* setup particle radius emission if enabled */
+ if (sfs->flags & FLUID_FLOW_USE_PART_SIZE) {
+ tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild);
+
+ /* check need for high resolution map */
+ if ((mds->flags & FLUID_DOMAIN_USE_NOISE) && (mds->highres_sampling == SM_HRES_FULLSAMPLE)) {
+ hires_multiplier = mds->noise_scale;
+ }
+
+ bounds_margin = (int)ceil(solid + smooth);
+ }
+
+ /* calculate local position for each particle */
+ for (p = 0; p < totpart + totchild; p++) {
+ ParticleKey state;
+ float *pos;
+ if (p < totpart) {
+ if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
+ continue;
+ }
+ }
+ else {
+ /* handle child particle */
+ ChildParticle *cpa = &psys->child[p - totpart];
+ if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
+ continue;
+ }
+ }
+
+ state.time = DEG_get_ctime(depsgraph); /* use depsgraph time */
+ if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
+ continue;
+ }
+
+ /* location */
+ pos = &particle_pos[valid_particles * 3];
+ copy_v3_v3(pos, state.co);
+ manta_pos_to_cell(mds, pos);
+
+ /* velocity */
+ copy_v3_v3(&particle_vel[valid_particles * 3], state.vel);
+ mul_mat3_m4_v3(mds->imat, &particle_vel[valid_particles * 3]);
+
+ if (sfs->flags & FLUID_FLOW_USE_PART_SIZE) {
+ BLI_kdtree_3d_insert(tree, valid_particles, pos);
+ }
+
+ /* calculate emission map bounds */
+ em_boundInsert(em, pos);
+ valid_particles++;
+ }
+
+ /* set emission map */
+ clampBoundsInDomain(mds, em->min, em->max, NULL, NULL, bounds_margin, dt);
+ em_allocateData(em, sfs->flags & FLUID_FLOW_INITVELOCITY, hires_multiplier);
+
+ if (!(sfs->flags & FLUID_FLOW_USE_PART_SIZE)) {
+ for (p = 0; p < valid_particles; p++) {
+ int cell[3];
+ size_t i = 0;
+ size_t index = 0;
+ int badcell = 0;
+
+ /* 1. get corresponding cell */
+ cell[0] = floor(particle_pos[p * 3]) - em->min[0];
+ cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1];
+ cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2];
+ /* check if cell is valid (in the domain boundary) */
+ for (i = 0; i < 3; i++) {
+ if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) {
+ badcell = 1;
+ break;
+ }
+ }
+ if (badcell) {
+ continue;
+ }
+ /* get cell index */
+ index = manta_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]);
+ /* Add influence to emission map */
+ em->influence[index] = 1.0f;
+ /* Uses particle velocity as initial velocity for smoke */
+ if (sfs->flags & FLUID_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) {
+ madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi);
+ }
+ } // particles loop
+ }
+ else if (valid_particles > 0) { // FLUID_FLOW_USE_PART_SIZE
+ int min[3], max[3], res[3];
+ const float hr = 1.0f / ((float)hires_multiplier);
+ /* slightly adjust high res antialias smoothness based on number of divisions
+ * to allow smaller details but yet not differing too much from the low res size */
+ const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f);
+
+ /* setup loop bounds */
+ for (int i = 0; i < 3; i++) {
+ min[i] = em->min[i] * hires_multiplier;
+ max[i] = em->max[i] * hires_multiplier;
+ res[i] = em->res[i] * hires_multiplier;
+ }
+
+ BLI_kdtree_3d_balance(tree);
+
+ EmitFromParticlesData data = {
+ .sfs = sfs,
+ .tree = tree,
+ .hires_multiplier = hires_multiplier,
+ .hr = hr,
+ .em = em,
+ .particle_vel = particle_vel,
+ .min = min,
+ .max = max,
+ .res = res,
+ .solid = solid,
+ .smooth = smooth,
+ .hr_smooth = hr_smooth,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, &settings);
+ }
+
+ if (sfs->flags & FLUID_FLOW_USE_PART_SIZE) {
+ BLI_kdtree_3d_free(tree);
+ }
+
+ /* free data */
+ if (particle_pos) {
+ MEM_freeN(particle_pos);
+ }
+ if (particle_vel) {
+ MEM_freeN(particle_vel);
+ }
+ }
+}
+
+/* Calculate map of (minimum) distances to flow/obstacle surface. Distances outside mesh are positive, inside negative */
+static void update_mesh_distances(int index,
+ float *mesh_distances,
+ BVHTreeFromMesh *treeData,
+ const float ray_start[3],
+ float surface_thickness)
+{
+
+ /* First pass: Raycasts in 26 directions (6 main axis + 12 quadrant diagonals (2D) + 8 octant diagonals (3D)) */
+ float ray_dirs[26][3] = {
+ {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f},
+ {-1.0f, 1.0f, 0.0f}, {-1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f},
+ {-1.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 1.0f}, {0.0f, 1.0f, -1.0f},
+ {0.0f, -1.0f, 1.0f}, {0.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {1.0f, -1.0f, -1.0f},
+ {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}};
+ size_t ray_cnt = sizeof ray_dirs / sizeof ray_dirs[0];
+
+ /* Count for ray misses (no face hit) and cases where ray direction matches face normal direction. */
+ int miss_cnt = 0;
+ int dir_cnt = 0;
+
+ for (int i = 0; i < ray_cnt; i++) {
+ BVHTreeRayHit hit_tree = {0};
+ hit_tree.index = -1;
+ hit_tree.dist = 9999;
+
+ normalize_v3(ray_dirs[i]);
+ BLI_bvhtree_ray_cast(treeData->tree,
+ ray_start,
+ ray_dirs[i],
+ 0.0f,
+ &hit_tree,
+ treeData->raycast_callback,
+ treeData);
+
+ /* Ray did not hit mesh. Current point definitely not inside mesh. Inside mesh all rays have to hit. */
+ if (hit_tree.index == -1) {
+ miss_cnt++;
+ continue;
+ }
+
+ /* Ray and normal are in pointing opposite directions. */
+ if (dot_v3v3(ray_dirs[i], hit_tree.no) <= 0) {
+ dir_cnt++;
+ }
+ }
+
+ /* Initialize grid points to -0.5 inside and 0.5 outside mesh.
+ * Inside mesh: All rays have to hit (no misses) or all face normals have to match ray direction */
+ if (mesh_distances[index] != -0.5f) {
+ mesh_distances[index] = (miss_cnt > 0 || dir_cnt == ray_cnt) ? 0.5f : -0.5f;
+ }
+
+ /* Second pass: Ensure that single planes get initialized. */
+ BVHTreeNearest nearest = {0};
+ nearest.index = -1;
+ nearest.dist_sq = surface_thickness * surface_thickness; /* find_nearest uses squared distance */
+
+ if (BLI_bvhtree_find_nearest(
+ treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
+ if (mesh_distances[index] != -0.5f) {
+ mesh_distances[index] = -0.5f;
+ }
+ }
+}
+
+static void sample_mesh(MantaFlowSettings *sfs,
+ const MVert *mvert,
+ const MLoop *mloop,
+ const MLoopTri *mlooptri,
+ const MLoopUV *mloopuv,
+ float *influence_map,
+ float *velocity_map,
+ int index,
+ const int base_res[3],
+ float flow_center[3],
+ BVHTreeFromMesh *treeData,
+ const float ray_start[3],
+ const float *vert_vel,
+ bool has_velocity,
+ int defgrp_index,
+ MDeformVert *dvert,
+ float x,
+ float y,
+ float z)
+{
+ float ray_dir[3] = {1.0f, 0.0f, 0.0f};
+ BVHTreeRayHit hit = {0};
+ BVHTreeNearest nearest = {0};
+
+ float volume_factor = 0.0f;
+ float sample_str = 0.0f;
+
+ hit.index = -1;
+ hit.dist = 9999;
+ nearest.index = -1;
+ nearest.dist_sq = sfs->surface_distance *
+ sfs->surface_distance; /* find_nearest uses squared distance */
+
+ /* Check volume collision */
+ if (sfs->volume_density) {
+ if (BLI_bvhtree_ray_cast(treeData->tree,
+ ray_start,
+ ray_dir,
+ 0.0f,
+ &hit,
+ treeData->raycast_callback,
+ treeData) != -1) {
+ float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
+ /* If ray and hit face normal are facing same direction
+ * hit point is inside a closed mesh. */
+ if (dot >= 0) {
+ /* Also cast a ray in opposite direction to make sure
+ * point is at least surrounded by two faces */
+ negate_v3(ray_dir);
+ hit.index = -1;
+ hit.dist = 9999;
+
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData);
+ if (hit.index != -1) {
+ volume_factor = sfs->volume_density;
+ }
+ }
+ }
+ }
+
+ /* find the nearest point on the mesh */
+ if (BLI_bvhtree_find_nearest(
+ treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
+ float weights[3];
+ int v1, v2, v3, f_index = nearest.index;
+ float n1[3], n2[3], n3[3], hit_normal[3];
+
+ /* emit from surface based on distance */
+ if (sfs->surface_distance) {
+ sample_str = sqrtf(nearest.dist_sq) / sfs->surface_distance;
+ CLAMP(sample_str, 0.0f, 1.0f);
+ sample_str = pow(1.0f - sample_str, 0.5f);
+ }
+ else {
+ sample_str = 0.0f;
+ }
+
+ /* calculate barycentric weights for nearest point */
+ v1 = mloop[mlooptri[f_index].tri[0]].v;
+ v2 = mloop[mlooptri[f_index].tri[1]].v;
+ v3 = mloop[mlooptri[f_index].tri[2]].v;
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
+
+ if (sfs->flags & FLUID_FLOW_INITVELOCITY && velocity_map) {
+ /* apply normal directional velocity */
+ if (sfs->vel_normal) {
+ /* interpolate vertex normal vectors to get nearest point normal */
+ normal_short_to_float_v3(n1, mvert[v1].no);
+ normal_short_to_float_v3(n2, mvert[v2].no);
+ normal_short_to_float_v3(n3, mvert[v3].no);
+ interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
+ normalize_v3(hit_normal);
+ /* apply normal directional and random velocity
+ * - TODO: random disabled for now since it doesn't really work well
+ * as pressure calc smoothens it out. */
+ velocity_map[index * 3] += hit_normal[0] * sfs->vel_normal * 0.25f;
+ velocity_map[index * 3 + 1] += hit_normal[1] * sfs->vel_normal * 0.25f;
+ velocity_map[index * 3 + 2] += hit_normal[2] * sfs->vel_normal * 0.25f;
+ /* TODO: for fire emitted from mesh surface we can use
+ * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */
+ }
+ /* apply object velocity */
+ if (has_velocity && sfs->vel_multi) {
+ float hit_vel[3];
+ interp_v3_v3v3v3(
+ hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
+ velocity_map[index * 3] += hit_vel[0] * sfs->vel_multi;
+ velocity_map[index * 3 + 1] += hit_vel[1] * sfs->vel_multi;
+ velocity_map[index * 3 + 2] += hit_vel[2] * sfs->vel_multi;
+ //printf("adding flow object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]);
+ }
+ velocity_map[index * 3] += sfs->vel_coord[0];
+ velocity_map[index * 3 + 1] += sfs->vel_coord[1];
+ velocity_map[index * 3 + 2] += sfs->vel_coord[2];
+ }
+
+ /* apply vertex group influence if used */
+ if (defgrp_index != -1 && dvert) {
+ float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
+ defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
+ defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
+ sample_str *= weight_mask;
+ }
+
+ /* apply emission texture */
+ if ((sfs->flags & FLUID_FLOW_TEXTUREEMIT) && sfs->noise_texture) {
+ float tex_co[3] = {0};
+ TexResult texres;
+
+ if (sfs->texture_type == FLUID_FLOW_TEXTURE_MAP_AUTO) {
+ tex_co[0] = ((x - flow_center[0]) / base_res[0]) / sfs->texture_size;
+ tex_co[1] = ((y - flow_center[1]) / base_res[1]) / sfs->texture_size;
+ tex_co[2] = ((z - flow_center[2]) / base_res[2] - sfs->texture_offset) / sfs->texture_size;
+ }
+ else if (mloopuv) {
+ const float *uv[3];
+ uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
+ uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
+ uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
+
+ interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
+
+ /* map between -1.0f and 1.0f */
+ tex_co[0] = tex_co[0] * 2.0f - 1.0f;
+ tex_co[1] = tex_co[1] * 2.0f - 1.0f;
+ tex_co[2] = sfs->texture_offset;
+ }
+ texres.nor = NULL;
+ BKE_texture_get_value(NULL, sfs->noise_texture, tex_co, &texres, false);
+ sample_str *= texres.tin;
+ }
+ }
+
+ /* multiply initial velocity by emitter influence */
+ if (sfs->flags & FLUID_FLOW_INITVELOCITY && velocity_map) {
+ mul_v3_fl(&velocity_map[index * 3], sample_str);
+ }
+
+ /* apply final influence based on volume factor */
+ influence_map[index] = MAX2(volume_factor, sample_str);
+}
+
+typedef struct EmitFromDMData {
+ MantaDomainSettings *mds;
+ MantaFlowSettings *sfs;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *mlooptri;
+ const MLoopUV *mloopuv;
+ MDeformVert *dvert;
+ int defgrp_index;
+
+ BVHTreeFromMesh *tree;
+ int hires_multiplier;
+ float hr;
+
+ EmissionMap *em;
+ bool has_velocity;
+ float *vert_vel;
+
+ float *flow_center;
+ int *min, *max, *res;
+} EmitFromDMData;
+
+static void emit_from_mesh_task_cb(void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ EmitFromDMData *data = userdata;
+ EmissionMap *em = data->em;
+ const int hires_multiplier = data->hires_multiplier;
+
+ for (int x = data->min[0]; x < data->max[0]; x++) {
+ for (int y = data->min[1]; y < data->max[1]; y++) {
+ /* take low res samples where possible */
+ if (hires_multiplier <= 1 ||
+ !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
+ /* get low res space coordinates */
+ const int lx = x / hires_multiplier;
+ const int ly = y / hires_multiplier;
+ const int lz = z / hires_multiplier;
+
+ const int index = manta_get_index(
+ lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
+ const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
+
+ /* Emission for smoke and fire. Result in em->influence. Also, calculate invels */
+ sample_mesh(data->sfs,
+ data->mvert,
+ data->mloop,
+ data->mlooptri,
+ data->mloopuv,
+ em->influence,
+ em->velocity,
+ index,
+ data->mds->base_res,
+ data->flow_center,
+ data->tree,
+ ray_start,
+ data->vert_vel,
+ data->has_velocity,
+ data->defgrp_index,
+ data->dvert,
+ (float)lx,
+ (float)ly,
+ (float)lz);
+
+ /* Calculate levelset from meshes. Result in em->distances */
+ update_mesh_distances(
+ index, em->distances, data->tree, ray_start, data->sfs->surface_distance);
+ }
+
+ /* take high res samples if required */
+ if (hires_multiplier > 1) {
+ /* get low res space coordinates */
+ const float lx = ((float)x) * data->hr;
+ const float ly = ((float)y) * data->hr;
+ const float lz = ((float)z) * data->hr;
+
+ const int index = manta_get_index(
+ x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
+ const float ray_start[3] = {
+ lx + 0.5f * data->hr,
+ ly + 0.5f * data->hr,
+ lz + 0.5f * data->hr,
+ };
+
+ /* Emission for smoke and fire high. Result in em->influence_high */
+ if (data->sfs->type == FLUID_FLOW_TYPE_SMOKE || data->sfs->type == FLUID_FLOW_TYPE_FIRE ||
+ data->sfs->type == FLUID_FLOW_TYPE_SMOKEFIRE) {
+ sample_mesh(data->sfs,
+ data->mvert,
+ data->mloop,
+ data->mlooptri,
+ data->mloopuv,
+ em->influence_high,
+ NULL,
+ index,
+ data->mds->base_res,
+ data->flow_center,
+ data->tree,
+ ray_start,
+ data->vert_vel,
+ data->has_velocity,
+ data->defgrp_index,
+ data->dvert,
+ /* x,y,z needs to be always lowres */
+ lx,
+ ly,
+ lz);
+ }
+ }
+ }
+ }
+}
+
+static void emit_from_mesh(
+ Object *flow_ob, MantaDomainSettings *mds, MantaFlowSettings *sfs, EmissionMap *em, float dt)
+{
+ if (sfs->mesh) {
+ Mesh *me = NULL;
+ MVert *mvert = NULL;
+ const MLoopTri *mlooptri = NULL;
+ const MLoop *mloop = NULL;
+ const MLoopUV *mloopuv = NULL;
+ MDeformVert *dvert = NULL;
+ BVHTreeFromMesh treeData = {NULL};
+ int numverts, i;
+
+ float *vert_vel = NULL;
+ bool has_velocity = false;
+
+ int defgrp_index = sfs->vgroup_density - 1;
+ float flow_center[3] = {0};
+ int min[3], max[3], res[3];
+ int hires_multiplier = 1;
+
+ /* copy mesh for thread safety because we modify it,
+ * main issue is its VertArray being modified, then replaced and freed
+ */
+ me = BKE_mesh_copy_for_eval(sfs->mesh, true);
+
+ /* Duplicate vertices to modify. */
+ if (me->mvert) {
+ me->mvert = MEM_dupallocN(me->mvert);
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+ }
+
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ mloop = me->mloop;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(me);
+ numverts = me->totvert;
+ dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
+ mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name);
+
+ if (sfs->flags & FLUID_FLOW_INITVELOCITY) {
+ vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "manta_flow_velocity");
+
+ if (sfs->numverts != numverts || !sfs->verts_old) {
+ if (sfs->verts_old) {
+ MEM_freeN(sfs->verts_old);
+ }
+ sfs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "manta_flow_verts_old");
+ sfs->numverts = numverts;
+ }
+ else {
+ has_velocity = true;
+ }
+ }
+
+ /* Transform mesh vertices to
+ * domain grid space for fast lookups */
+ for (i = 0; i < numverts; i++) {
+ float n[3];
+
+ /* vert pos */
+ mul_m4_v3(flow_ob->obmat, mvert[i].co);
+ manta_pos_to_cell(mds, mvert[i].co);
+
+ /* vert normal */
+ normal_short_to_float_v3(n, mvert[i].no);
+ mul_mat3_m4_v3(flow_ob->obmat, n);
+ mul_mat3_m4_v3(mds->imat, n);
+ normalize_v3(n);
+ normal_float_to_short_v3(mvert[i].no, n);
+
+ /* vert velocity */
+ if (sfs->flags & FLUID_FLOW_INITVELOCITY) {
+ float co[3];
+ add_v3fl_v3fl_v3i(co, mvert[i].co, mds->shift);
+ if (has_velocity) {
+ sub_v3_v3v3(&vert_vel[i * 3], co, &sfs->verts_old[i * 3]);
+ mul_v3_fl(&vert_vel[i * 3], mds->dx / dt);
+ }
+ copy_v3_v3(&sfs->verts_old[i * 3], co);
+ }
+
+ /* calculate emission map bounds */
+ em_boundInsert(em, mvert[i].co);
+ }
+ mul_m4_v3(flow_ob->obmat, flow_center);
+ manta_pos_to_cell(mds, flow_center);
+
+ /* check need for high resolution map */
+ if ((mds->flags & FLUID_DOMAIN_USE_NOISE) && (mds->highres_sampling == SM_HRES_FULLSAMPLE)) {
+ hires_multiplier = mds->noise_scale;
+ }
+
+ /* set emission map */
+ clampBoundsInDomain(mds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt);
+ em_allocateData(em, sfs->flags & FLUID_FLOW_INITVELOCITY, hires_multiplier);
+
+ /* setup loop bounds */
+ for (i = 0; i < 3; i++) {
+ min[i] = em->min[i] * hires_multiplier;
+ max[i] = em->max[i] * hires_multiplier;
+ res[i] = em->res[i] * hires_multiplier;
+ }
+
+ if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
+ const float hr = 1.0f / ((float)hires_multiplier);
+
+ EmitFromDMData data = {
+ .mds = mds,
+ .sfs = sfs,
+ .mvert = mvert,
+ .mloop = mloop,
+ .mlooptri = mlooptri,
+ .mloopuv = mloopuv,
+ .dvert = dvert,
+ .defgrp_index = defgrp_index,
+ .tree = &treeData,
+ .hires_multiplier = hires_multiplier,
+ .hr = hr,
+ .em = em,
+ .has_velocity = has_velocity,
+ .vert_vel = vert_vel,
+ .flow_center = flow_center,
+ .min = min,
+ .max = max,
+ .res = res,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings);
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+
+ if (vert_vel) {
+ MEM_freeN(vert_vel);
+ }
+
+ if (me->mvert) {
+ MEM_freeN(me->mvert);
+ }
+ BKE_id_free(NULL, me);
+ }
+}
+
+/**********************************************************
+ * Smoke step
+ **********************************************************/
+
+static void adaptiveDomainCopy(MantaDomainSettings *mds,
+ int o_res[3],
+ int n_res[3],
+ int o_min[3],
+ int n_min[3],
+ int o_max[3],
+ int o_shift[3],
+ int n_shift[3],
+ int isNoise)
+{
+ int x, y, z;
+ struct MANTA *fluid_old = mds->fluid;
+ const int block_size = mds->noise_scale;
+ int new_shift[3] = {0};
+ sub_v3_v3v3_int(new_shift, n_shift, o_shift);
+
+ /* allocate new fluid data */
+ BKE_manta_reallocate_fluid(mds, n_res, 0);
+
+ int o_total_cells = o_res[0] * o_res[1] * o_res[2];
+ int n_total_cells = n_res[0] * n_res[1] * n_res[2];
+
+ /* boundary cells will be skipped when copying data */
+ int bwidth = mds->boundary_width;
+
+ /* copy values from old fluid to new */
+ if (o_total_cells > 1 && n_total_cells > 1) {
+ /* base smoke */
+ float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_vx, *o_vy, *o_vz,
+ *o_r, *o_g, *o_b;
+ float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_vx, *n_vy, *n_vz,
+ *n_r, *n_g, *n_b;
+ float dummy, *dummy_s;
+ int *dummy_p;
+ /* noise smoke */
+ int wt_res_old[3];
+ float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw,
+ *o_wt_tcu2, *o_wt_tcv2, *o_wt_tcw2, *o_wt_r, *o_wt_g, *o_wt_b;
+ float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw,
+ *n_wt_tcu2, *n_wt_tcv2, *n_wt_tcw2, *n_wt_r, *n_wt_g, *n_wt_b;
+
+ if (isNoise && mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ manta_smoke_turbulence_export(fluid_old,
+ &o_wt_dens,
+ &o_wt_react,
+ &o_wt_flame,
+ &o_wt_fuel,
+ &o_wt_r,
+ &o_wt_g,
+ &o_wt_b,
+ &o_wt_tcu,
+ &o_wt_tcv,
+ &o_wt_tcw,
+ &o_wt_tcu2,
+ &o_wt_tcv2,
+ &o_wt_tcw2);
+ manta_smoke_turbulence_get_res(fluid_old, wt_res_old);
+ manta_smoke_turbulence_export(mds->fluid,
+ &n_wt_dens,
+ &n_wt_react,
+ &n_wt_flame,
+ &n_wt_fuel,
+ &n_wt_r,
+ &n_wt_g,
+ &n_wt_b,
+ &n_wt_tcu,
+ &n_wt_tcv,
+ &n_wt_tcw,
+ &n_wt_tcu2,
+ &n_wt_tcv2,
+ &n_wt_tcw2);
+ }
+ else {
+ manta_smoke_export(fluid_old,
+ &dummy,
+ &dummy,
+ &o_dens,
+ &o_react,
+ &o_flame,
+ &o_fuel,
+ &o_heat,
+ &o_vx,
+ &o_vy,
+ &o_vz,
+ &o_r,
+ &o_g,
+ &o_b,
+ &dummy_p,
+ &dummy_s);
+ manta_smoke_export(mds->fluid,
+ &dummy,
+ &dummy,
+ &n_dens,
+ &n_react,
+ &n_flame,
+ &n_fuel,
+ &n_heat,
+ &n_vx,
+ &n_vy,
+ &n_vz,
+ &n_r,
+ &n_g,
+ &n_b,
+ &dummy_p,
+ &dummy_s);
+ }
+
+ for (x = o_min[0]; x < o_max[0]; x++) {
+ for (y = o_min[1]; y < o_max[1]; y++) {
+ for (z = o_min[2]; z < o_max[2]; z++) {
+ /* old grid index */
+ int xo = x - o_min[0];
+ int yo = y - o_min[1];
+ int zo = z - o_min[2];
+ int index_old = manta_get_index(xo, o_res[0], yo, o_res[1], zo);
+ /* new grid index */
+ int xn = x - n_min[0] - new_shift[0];
+ int yn = y - n_min[1] - new_shift[1];
+ int zn = z - n_min[2] - new_shift[2];
+ int index_new = manta_get_index(xn, n_res[0], yn, n_res[1], zn);
+
+ /* skip if outside new domain */
+ if (xn < 0 || xn >= n_res[0] || yn < 0 || yn >= n_res[1] || zn < 0 || zn >= n_res[2]) {
+ continue;
+ }
+ /* skip if trying to copy from old boundary cell */
+ if (xo < bwidth || yo < bwidth || zo < bwidth ||
+ xo >= o_res[0]-bwidth || yo >= o_res[1]-bwidth || zo >= o_res[2]-bwidth) {
+ continue;
+ }
+ /* skip if trying to copy into new boundary cell */
+ if (xn < bwidth || yn < bwidth || zn < bwidth ||
+ xn >= n_res[0]-bwidth || yn >= n_res[1]-bwidth || zn >= n_res[2]-bwidth) {
+ continue;
+ }
+
+ /* copy data */
+ if (isNoise && mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ int i, j, k;
+ /* old grid index */
+ int xx_o = xo * block_size;
+ int yy_o = yo * block_size;
+ int zz_o = zo * block_size;
+ /* new grid index */
+ int xx_n = xn * block_size;
+ int yy_n = yn * block_size;
+ int zz_n = zn * block_size;
+
+ /* insert old texture values into new texture grids */
+ n_wt_tcu[index_new] = o_wt_tcu[index_old];
+ n_wt_tcv[index_new] = o_wt_tcv[index_old];
+ n_wt_tcw[index_new] = o_wt_tcw[index_old];
+
+ n_wt_tcu2[index_new] = o_wt_tcu2[index_old];
+ n_wt_tcv2[index_new] = o_wt_tcv2[index_old];
+ n_wt_tcw2[index_new] = o_wt_tcw2[index_old];
+
+ for (i = 0; i < block_size; i++) {
+ for (j = 0; j < block_size; j++) {
+ for (k = 0; k < block_size; k++) {
+ int big_index_old = manta_get_index(
+ xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k);
+ int big_index_new = manta_get_index(
+ xx_n + i, mds->res_noise[0], yy_n + j, mds->res_noise[1], zz_n + k);
+ /* copy data */
+ n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
+ if (n_wt_flame && o_wt_flame) {
+ n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
+ n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
+ n_wt_react[big_index_new] = o_wt_react[big_index_old];
+ }
+ if (n_wt_r && o_wt_r) {
+ n_wt_r[big_index_new] = o_wt_r[big_index_old];
+ n_wt_g[big_index_new] = o_wt_g[big_index_old];
+ n_wt_b[big_index_new] = o_wt_b[big_index_old];
+ }
+ }
+ }
+ }
+ }
+ else {
+ n_dens[index_new] = o_dens[index_old];
+ /* heat */
+ if (n_heat && o_heat) {
+ n_heat[index_new] = o_heat[index_old];
+ }
+ /* fuel */
+ if (n_fuel && o_fuel) {
+ n_flame[index_new] = o_flame[index_old];
+ n_fuel[index_new] = o_fuel[index_old];
+ n_react[index_new] = o_react[index_old];
+ }
+ /* color */
+ if (o_r && n_r) {
+ n_r[index_new] = o_r[index_old];
+ n_g[index_new] = o_g[index_old];
+ n_b[index_new] = o_b[index_old];
+ }
+ n_vx[index_new] = o_vx[index_old];
+ n_vy[index_new] = o_vy[index_old];
+ n_vz[index_new] = o_vz[index_old];
+ }
+ }
+ }
+ }
+ }
+ manta_free(fluid_old);
+}
+
+static void adaptiveDomainAdjust(MantaDomainSettings *mds,
+ Object *ob,
+ EmissionMap *emaps,
+ unsigned int numflowobj,
+ float dt)
+{
+ /* calculate domain shift for current frame */
+ int new_shift[3] = {0};
+ int total_shift[3];
+ float frame_shift_f[3];
+ float ob_loc[3] = {0};
+
+ mul_m4_v3(ob->obmat, ob_loc);
+
+ sub_v3_v3v3(frame_shift_f, ob_loc, mds->prev_loc);
+ copy_v3_v3(mds->prev_loc, ob_loc);
+ /* convert global space shift to local "cell" space */
+ mul_mat3_m4_v3(mds->imat, frame_shift_f);
+ frame_shift_f[0] = frame_shift_f[0] / mds->cell_size[0];
+ frame_shift_f[1] = frame_shift_f[1] / mds->cell_size[1];
+ frame_shift_f[2] = frame_shift_f[2] / mds->cell_size[2];
+ /* add to total shift */
+ add_v3_v3(mds->shift_f, frame_shift_f);
+ /* convert to integer */
+ total_shift[0] = (int)(floorf(mds->shift_f[0]));
+ total_shift[1] = (int)(floorf(mds->shift_f[1]));
+ total_shift[2] = (int)(floorf(mds->shift_f[2]));
+ int tmpShift[3];
+ copy_v3_v3_int(tmpShift, mds->shift);
+ sub_v3_v3v3_int(new_shift, total_shift, mds->shift);
+ copy_v3_v3_int(mds->shift, total_shift);
+
+ /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */
+ mds->p0[0] = mds->dp0[0] - mds->cell_size[0] * (mds->shift_f[0] - total_shift[0] - 0.5f);
+ mds->p0[1] = mds->dp0[1] - mds->cell_size[1] * (mds->shift_f[1] - total_shift[1] - 0.5f);
+ mds->p0[2] = mds->dp0[2] - mds->cell_size[2] * (mds->shift_f[2] - total_shift[2] - 0.5f);
+ mds->p1[0] = mds->p0[0] + mds->cell_size[0] * mds->base_res[0];
+ mds->p1[1] = mds->p0[1] + mds->cell_size[1] * mds->base_res[1];
+ mds->p1[2] = mds->p0[2] + mds->cell_size[2] * mds->base_res[2];
+
+ /* adjust domain resolution */
+ const int block_size = mds->noise_scale;
+ int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3];
+ int total_cells = 1, res_changed = 0, shift_changed = 0;
+ float min_vel[3], max_vel[3];
+ int x, y, z;
+ float *density = manta_smoke_get_density(mds->fluid);
+ float *fuel = manta_smoke_get_fuel(mds->fluid);
+ float *bigdensity = manta_smoke_turbulence_get_density(mds->fluid);
+ float *bigfuel = manta_smoke_turbulence_get_fuel(mds->fluid);
+ float *vx = manta_get_velocity_x(mds->fluid);
+ float *vy = manta_get_velocity_y(mds->fluid);
+ float *vz = manta_get_velocity_z(mds->fluid);
+ int wt_res[3];
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) {
+ manta_smoke_turbulence_get_res(mds->fluid, wt_res);
+ }
+
+ INIT_MINMAX(min_vel, max_vel);
+
+ /* Calculate bounds for current domain content */
+ for (x = mds->res_min[0]; x < mds->res_max[0]; x++) {
+ for (y = mds->res_min[1]; y < mds->res_max[1]; y++) {
+ for (z = mds->res_min[2]; z < mds->res_max[2]; z++) {
+ int xn = x - new_shift[0];
+ int yn = y - new_shift[1];
+ int zn = z - new_shift[2];
+ int index;
+ float max_den;
+
+ /* skip if cell already belongs to new area */
+ if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] &&
+ zn <= max[2]) {
+ continue;
+ }
+
+ index = manta_get_index(x - mds->res_min[0],
+ mds->res[0],
+ y - mds->res_min[1],
+ mds->res[1],
+ z - mds->res_min[2]);
+ max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
+
+ /* check high resolution bounds if max density isnt already high enough */
+ if (max_den < mds->adapt_threshold && mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) {
+ int i, j, k;
+ /* high res grid index */
+ int xx = (x - mds->res_min[0]) * block_size;
+ int yy = (y - mds->res_min[1]) * block_size;
+ int zz = (z - mds->res_min[2]) * block_size;
+
+ for (i = 0; i < block_size; i++) {
+ for (j = 0; j < block_size; j++) {
+ for (k = 0; k < block_size; k++) {
+ int big_index = manta_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k);
+ float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) :
+ bigdensity[big_index];
+ if (den > max_den) {
+ max_den = den;
+ }
+ }
+ }
+ }
+ }
+
+ /* content bounds (use shifted coordinates) */
+ if (max_den >= mds->adapt_threshold) {
+ if (min[0] > xn) {
+ min[0] = xn;
+ }
+ if (min[1] > yn) {
+ min[1] = yn;
+ }
+ if (min[2] > zn) {
+ min[2] = zn;
+ }
+ if (max[0] < xn) {
+ max[0] = xn;
+ }
+ if (max[1] < yn) {
+ max[1] = yn;
+ }
+ if (max[2] < zn) {
+ max[2] = zn;
+ }
+ }
+
+ /* velocity bounds */
+ if (min_vel[0] > vx[index]) {
+ min_vel[0] = vx[index];
+ }
+ if (min_vel[1] > vy[index]) {
+ min_vel[1] = vy[index];
+ }
+ if (min_vel[2] > vz[index]) {
+ min_vel[2] = vz[index];
+ }
+ if (max_vel[0] < vx[index]) {
+ max_vel[0] = vx[index];
+ }
+ if (max_vel[1] < vy[index]) {
+ max_vel[1] = vy[index];
+ }
+ if (max_vel[2] < vz[index]) {
+ max_vel[2] = vz[index];
+ }
+ }
+ }
+ }
+
+ /* also apply emission maps */
+ for (int i = 0; i < numflowobj; i++) {
+ EmissionMap *em = &emaps[i];
+
+ for (x = em->min[0]; x < em->max[0]; x++) {
+ for (y = em->min[1]; y < em->max[1]; y++) {
+ for (z = em->min[2]; z < em->max[2]; z++) {
+ int index = manta_get_index(
+ x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]);
+ float max_den = em->influence[index];
+
+ /* density bounds */
+ if (max_den >= mds->adapt_threshold) {
+ if (min[0] > x) {
+ min[0] = x;
+ }
+ if (min[1] > y) {
+ min[1] = y;
+ }
+ if (min[2] > z) {
+ min[2] = z;
+ }
+ if (max[0] < x) {
+ max[0] = x;
+ }
+ if (max[1] < y) {
+ max[1] = y;
+ }
+ if (max[2] < z) {
+ max[2] = z;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* calculate new bounds based on these values */
+ clampBoundsInDomain(mds, min, max, min_vel, max_vel, mds->adapt_margin + 1, dt);
+
+ for (int i = 0; i < 3; i++) {
+ /* calculate new resolution */
+ res[i] = max[i] - min[i];
+ total_cells *= res[i];
+
+ if (new_shift[i]) {
+ shift_changed = 1;
+ }
+
+ /* if no content set minimum dimensions */
+ if (res[i] <= 0) {
+ int j;
+ for (j = 0; j < 3; j++) {
+ min[j] = 0;
+ max[j] = 1;
+ res[j] = 1;
+ }
+ res_changed = 1;
+ total_cells = 1;
+ break;
+ }
+ if (min[i] != mds->res_min[i] || max[i] != mds->res_max[i]) {
+ res_changed = 1;
+ }
+ }
+
+ if (res_changed || shift_changed) {
+ adaptiveDomainCopy(mds, mds->res, res, mds->res_min, min, mds->res_max, tmpShift, total_shift, 0);
+
+ /* set new domain dimensions */
+ copy_v3_v3_int(mds->res_min, min);
+ copy_v3_v3_int(mds->res_max, max);
+ copy_v3_v3_int(mds->res, res);
+ mds->total_cells = total_cells;
+
+ /* Redo adapt time step in manta to refresh solver state (ie time variables) */
+ manta_adapt_timestep(mds->fluid);
+ }
+
+ /* update global size field with new bbox size */
+ /* volume bounds */
+ float minf[3], maxf[3], size[3];
+ madd_v3fl_v3fl_v3fl_v3i(minf, mds->p0, mds->cell_size, mds->res_min);
+ madd_v3fl_v3fl_v3fl_v3i(maxf, mds->p0, mds->cell_size, mds->res_max);
+ /* calculate domain dimensions */
+ sub_v3_v3v3(size, maxf, minf);
+ /* apply object scale */
+ for (int i = 0; i < 3; i++) {
+ size[i] = fabsf(size[i] * ob->scale[i]);
+ }
+ copy_v3_v3(mds->global_size, size);
+}
+
+BLI_INLINE void apply_outflow_fields(int index,
+ float distance_value,
+ float *density,
+ float *heat,
+ float *fuel,
+ float *react,
+ float *color_r,
+ float *color_g,
+ float *color_b,
+ float *phiout)
+{
+ /* determine outflow cells - phiout used in smoke and liquids */
+ if (phiout) {
+ phiout[index] = distance_value;
+ }
+
+ /* set smoke outflow */
+ if (density) {
+ density[index] = 0.f;
+ }
+ if (heat) {
+ heat[index] = 0.f;
+ }
+ if (fuel) {
+ fuel[index] = 0.f;
+ react[index] = 0.f;
+ }
+ if (color_r) {
+ color_r[index] = 0.f;
+ color_g[index] = 0.f;
+ color_b[index] = 0.f;
+ }
+}
+
+BLI_INLINE void apply_inflow_fields(MantaFlowSettings *sfs,
+ float emission_value,
+ float distance_value,
+ int index,
+ float *density,
+ float *heat,
+ float *fuel,
+ float *react,
+ float *color_r,
+ float *color_g,
+ float *color_b,
+ float *phi,
+ float *emission)
+{
+ /* add inflow */
+ if (phi) {
+ phi[index] = distance_value;
+ }
+
+ /* save emission value for manta inflow */
+ if (emission) {
+ emission[index] = emission_value;
+ }
+
+ /* add smoke inflow */
+ int absolute_flow = (sfs->flags & FLUID_FLOW_ABSOLUTE);
+ float dens_old = (density) ? density[index] : 0.0;
+ // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
+ float dens_flow = (sfs->type == FLUID_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density;
+ float fuel_flow = (fuel) ? emission_value * sfs->fuel_amount : 0.0f;
+ /* add heat */
+ if (heat && emission_value > 0.0f) {
+ heat[index] = ADD_IF_LOWER(heat[index], sfs->temp);
+ }
+
+ /* set density and fuel - absolute mode */
+ if (absolute_flow) {
+ if (density && sfs->type != FLUID_FLOW_TYPE_FIRE) {
+ if (dens_flow > density[index]) {
+ density[index] = dens_flow;
+ }
+ }
+ if (fuel && sfs->type != FLUID_FLOW_TYPE_SMOKE && fuel_flow) {
+ if (fuel_flow > fuel[index]) {
+ fuel[index] = fuel_flow;
+ }
+ }
+ }
+ /* set density and fuel - additive mode */
+ else {
+ if (density && sfs->type != FLUID_FLOW_TYPE_FIRE) {
+ density[index] += dens_flow;
+ CLAMP(density[index], 0.0f, 1.0f);
+ }
+ if (fuel && sfs->type != FLUID_FLOW_TYPE_SMOKE && sfs->fuel_amount) {
+ fuel[index] += fuel_flow;
+ CLAMP(fuel[index], 0.0f, 10.0f);
+ }
+ }
+
+ /* set color */
+ if (color_r && dens_flow) {
+ float total_dens = density[index] / (dens_old + dens_flow);
+ color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens;
+ color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens;
+ color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens;
+ }
+
+ /* set fire reaction coordinate */
+ if (fuel && fuel[index] > FLT_EPSILON) {
+ /* instead of using 1.0 for all new fuel add slight falloff
+ * to reduce flow blockiness */
+ float value = 1.0f - pow2f(1.0f - emission_value);
+
+ if (value > react[index]) {
+ float f = fuel_flow / fuel[index];
+ react[index] = value * f + (1.0f - f) * react[index];
+ CLAMP(react[index], 0.0f, value);
+ }
+ }
+}
+
+static void update_flowsflags(MantaDomainSettings *mds, Object **flowobjs, int numflowobj)
+{
+ int active_fields = mds->active_fields;
+ unsigned int flowIndex;
+
+ /* Monitor active fields based on flow settings */
+ for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) {
+ Object *collob = flowobjs[flowIndex];
+ MantaModifierData *mmd2 = (MantaModifierData *)modifiers_findByType(collob,
+ eModifierType_Manta);
+
+ // Sanity check
+ if (!mmd2) {
+ continue;
+ }
+
+ if ((mmd2->type & MOD_MANTA_TYPE_FLOW) && mmd2->flow) {
+ MantaFlowSettings *sfs = mmd2->flow;
+ if (!sfs) {
+ break;
+ }
+ if (sfs->flags & FLUID_FLOW_INITVELOCITY) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_INVEL;
+ }
+ if (sfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_OUTFLOW;
+ }
+ /* liquids done from here */
+ if (mds->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ continue;
+ }
+
+ /* activate heat field if flow produces any heat */
+ if (sfs->temp) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_HEAT;
+ }
+ /* activate fuel field if flow adds any fuel */
+ if (sfs->fuel_amount &&
+ (sfs->type == FLUID_FLOW_TYPE_FIRE || sfs->type == FLUID_FLOW_TYPE_SMOKEFIRE)) {
+ active_fields |= FLUID_DOMAIN_ACTIVE_FIRE;
+ }
+ /* activate color field if flows add smoke with varying colors */
+ if (sfs->density &&
+ (sfs->type == FLUID_FLOW_TYPE_SMOKE || sfs->type == FLUID_FLOW_TYPE_SMOKEFIRE)) {
+ if (!(active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET)) {
+ copy_v3_v3(mds->active_color, sfs->color);
+ active_fields |= FLUID_DOMAIN_ACTIVE_COLOR_SET;
+ }
+ else if (!equals_v3v3(mds->active_color, sfs->color)) {
+ copy_v3_v3(mds->active_color, sfs->color);
+ active_fields |= FLUID_DOMAIN_ACTIVE_COLORS;
+ }
+ }
+ }
+ }
+ /* Monitor active fields based on domain settings */
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS && active_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ /* heat is always needed for fire */
+ active_fields |= FLUID_DOMAIN_ACTIVE_HEAT;
+ /* also activate colors if domain smoke color differs from active color */
+ if (!(active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET)) {
+ copy_v3_v3(mds->active_color, mds->flame_smoke_color);
+ active_fields |= FLUID_DOMAIN_ACTIVE_COLOR_SET;
+ }
+ else if (!equals_v3v3(mds->active_color, mds->flame_smoke_color)) {
+ copy_v3_v3(mds->active_color, mds->flame_smoke_color);
+ active_fields |= FLUID_DOMAIN_ACTIVE_COLORS;
+ }
+ }
+ /* Finally, initialize new data fields if any */
+ if (active_fields & FLUID_DOMAIN_ACTIVE_INVEL) {
+ manta_ensure_invelocity(mds->fluid, mds->mmd);
+ }
+ if (active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) {
+ manta_ensure_outflow(mds->fluid, mds->mmd);
+ }
+ if (active_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
+ manta_smoke_ensure_heat(mds->fluid, mds->mmd);
+ }
+ if (active_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ manta_smoke_ensure_fire(mds->fluid, mds->mmd);
+ }
+ if (active_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
+ /* initialize all smoke with "active_color" */
+ manta_smoke_ensure_colors(mds->fluid, mds->mmd);
+ }
+ if (mds->type == FLUID_DOMAIN_TYPE_LIQUID &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY ||
+ mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM ||
+ mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER)) {
+ manta_liquid_ensure_sndparts(mds->fluid, mds->mmd);
+ }
+ mds->active_fields = active_fields;
+}
+
+static void update_flowsfluids(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ MantaDomainSettings *mds,
+ float time_per_frame,
+ float frame_length,
+ int frame,
+ float dt)
+{
+ EmissionMap *emaps = NULL;
+ Object **flowobjs = NULL;
+ unsigned int numflowobj = 0, flowIndex = 0;
+ bool is_first_frame = (frame == mds->cache_frame_start);
+
+ flowobjs = BKE_collision_objects_create(
+ depsgraph, ob, mds->fluid_group, &numflowobj, eModifierType_Manta);
+
+ /* Update all flow related flags and ensure that corresponding grids get initialized */
+ update_flowsflags(mds, flowobjs, numflowobj);
+
+ /* init emission maps for each flow */
+ emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "manta_flow_maps");
+
+ /* Prepare flow emission maps */
+ for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) {
+ Object *flowobj = flowobjs[flowIndex];
+ MantaModifierData *mmd2 = (MantaModifierData *)modifiers_findByType(flowobj,
+ eModifierType_Manta);
+
+ /* Check for initialized smoke object */
+ if ((mmd2->type & MOD_MANTA_TYPE_FLOW) && mmd2->flow) {
+ MantaFlowSettings *sfs = mmd2->flow;
+ int subframes = sfs->subframes;
+ EmissionMap *em = &emaps[flowIndex];
+
+ /* Length of one adaptive frame. If using adaptive stepping, length is smaller than actual frame length */
+ float adaptframe_length = time_per_frame / frame_length;
+ /* Adaptive frame length as percentage */
+ CLAMP(adaptframe_length, 0.0f, 1.0f);
+
+ /* Further splitting because of emission subframe: If no subframes present, sample_size is 1 */
+ float sample_size = 1.0f / (float)(subframes + 1);
+ int hires_multiplier = 1;
+
+ /* First frame cannot have any subframes because there is (obviously) no previous frame from where subframes could come from */
+ if (is_first_frame) {
+ subframes = 0;
+ }
+
+ int subframe;
+ float subframe_dt = dt * sample_size;
+
+ /* Emission loop. When not using subframes this will loop only once. */
+ for (subframe = subframes; subframe >= 0; subframe--) {
+
+ /* Temporary emission map used when subframes are enabled, i.e. at least one subframe */
+ EmissionMap em_temp = {NULL};
+
+ /* Set scene time */
+ /* Handle emission subframe */
+ if (subframe > 0 && !is_first_frame) {
+ scene->r.subframe = adaptframe_length - sample_size * (float)(subframe) * (dt / frame_length);
+ scene->r.cfra = frame - 1;
+ }
+ /* Last frame in this loop (subframe == suframes). Can be real end frame or in between frames (adaptive frame) */
+ else {
+ /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene subframe parameter */
+ if (time_per_frame < frame_length) {
+ scene->r.subframe = adaptframe_length;
+ scene->r.cfra = frame - 1;
+ }
+ /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe parameter to 0 and advance current scene frame */
+ else {
+ scene->r.subframe = 0.0f;
+ scene->r.cfra = frame;
+ }
+ }
+ /* Sanity check: subframe portion must be between 0 and 1 */
+ CLAMP(scene->r.subframe, 0.0f, 1.0f);
+ //printf("flow: frame (is first: %d): %d // scene current frame: %d // scene current subframe: %f\n", is_first_frame, frame, scene->r.cfra, scene->r.subframe);
+
+ /* Emission from particles */
+ if (sfs->source == FLUID_FLOW_SOURCE_PARTICLES) {
+ /* emit_from_particles() updates timestep internally */
+ if (subframes) {
+ emit_from_particles(flowobj, mds, sfs, &em_temp, depsgraph, scene, subframe_dt);
+ }
+ else {
+ emit_from_particles(flowobj, mds, sfs, em, depsgraph, scene, subframe_dt);
+ }
+
+ if (!(sfs->flags & FLUID_FLOW_USE_PART_SIZE)) {
+ hires_multiplier = 1;
+ }
+ }
+ /* Emission from mesh */
+ else if (sfs->source == FLUID_FLOW_SOURCE_MESH) {
+ /* Update flow object frame */
+ // BLI_mutex_lock() called in manta_step(), so safe to update subframe here
+
+ /* TODO (sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph) as subframes dont work with the latter yet */
+ BKE_object_modifier_update_subframe(
+ depsgraph, scene, flowobj, true, 5, BKE_scene_frame_get(scene), eModifierType_Manta);
+
+ /* Apply flow */
+ if (subframes) {
+ emit_from_mesh(flowobj, mds, sfs, &em_temp, subframe_dt);
+ }
+ else {
+ emit_from_mesh(flowobj, mds, sfs, em, subframe_dt);
+ }
+ }
+ else {
+ printf("Error: unknown flow emission source\n");
+ }
+
+ /* If this we emitted with temp emission map in this loop (subframe emission), we combine the temp map with the original emission map */
+ if (subframes) {
+ /* Combine emission maps */
+ em_combineMaps(
+ em, &em_temp, hires_multiplier, !(sfs->flags & FLUID_FLOW_ABSOLUTE), sample_size);
+ em_freeData(&em_temp);
+ }
+ }
+ }
+ }
+
+// printf("flow: frame: %d // time per frame: %f // frame length: %f // dt: %f\n", frame, time_per_frame, frame_length, dt);
+
+ /* Adjust domain size if needed. Only do this once for every frame */
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS &&
+ mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN)
+ {
+ adaptiveDomainAdjust(mds, ob, emaps, numflowobj, dt);
+ }
+
+ float *phi_in = manta_get_phi_in(mds->fluid);
+ float *phiout_in = manta_get_phiout_in(mds->fluid);
+ float *density = manta_smoke_get_density(mds->fluid);
+ float *color_r = manta_smoke_get_color_r(mds->fluid);
+ float *color_g = manta_smoke_get_color_g(mds->fluid);
+ float *color_b = manta_smoke_get_color_b(mds->fluid);
+ float *fuel = manta_smoke_get_fuel(mds->fluid);
+ float *heat = manta_smoke_get_heat(mds->fluid);
+ float *react = manta_smoke_get_react(mds->fluid);
+
+ float *density_in = manta_smoke_get_density_in(mds->fluid);
+ float *heat_in = manta_smoke_get_heat_in(mds->fluid);
+ float *color_r_in = manta_smoke_get_color_r_in(mds->fluid);
+ float *color_g_in = manta_smoke_get_color_g_in(mds->fluid);
+ float *color_b_in = manta_smoke_get_color_b_in(mds->fluid);
+ float *fuel_in = manta_smoke_get_fuel_in(mds->fluid);
+ float *react_in = manta_smoke_get_react_in(mds->fluid);
+ float *emission_in = manta_smoke_get_emission_in(mds->fluid);
+
+ float *velx_initial = manta_get_in_velocity_x(mds->fluid);
+ float *vely_initial = manta_get_in_velocity_y(mds->fluid);
+ float *velz_initial = manta_get_in_velocity_z(mds->fluid);
+ unsigned int z;
+
+ /* Grid reset before writing again */
+ for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) {
+ if (phi_in) {
+ phi_in[z] = 9999.0f;
+ }
+ if (phiout_in) {
+ phiout_in[z] = 9999.0f;
+ }
+ if (density_in) {
+ density_in[z] = 0.0f;
+ }
+ if (heat_in) {
+ heat_in[z] = 0.0f;
+ }
+ if (color_r_in) {
+ color_r_in[z] = 0.0f;
+ color_g_in[z] = 0.0f;
+ color_b_in[z] = 0.0f;
+ }
+ if (fuel_in) {
+ fuel_in[z] = 0.0f;
+ react_in[z] = 0.0f;
+ }
+ if (emission_in) {
+ emission_in[z] = 0.0f;
+ }
+ if (velx_initial) {
+ velx_initial[z] = 0.0f;
+ vely_initial[z] = 0.0f;
+ velz_initial[z] = 0.0f;
+ }
+ }
+
+ /* Apply emission data */
+ for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) {
+ Object *flowobj = flowobjs[flowIndex];
+ MantaModifierData *mmd2 = (MantaModifierData *)modifiers_findByType(flowobj,
+ eModifierType_Manta);
+
+ // check for initialized flow object
+ if ((mmd2->type & MOD_MANTA_TYPE_FLOW) && mmd2->flow) {
+ MantaFlowSettings *sfs = mmd2->flow;
+ EmissionMap *em = &emaps[flowIndex];
+ float *velocity_map = em->velocity;
+ float *emission_map = em->influence;
+ float *distance_map = em->distances;
+
+ int gx, gy, gz, ex, ey, ez, dx, dy, dz;
+ size_t e_index, d_index;
+
+ // loop through every emission map cell
+ for (gx = em->min[0]; gx < em->max[0]; gx++) {
+ for (gy = em->min[1]; gy < em->max[1]; gy++) {
+ for (gz = em->min[2]; gz < em->max[2]; gz++) {
+ /* get emission map index */
+ ex = gx - em->min[0];
+ ey = gy - em->min[1];
+ ez = gz - em->min[2];
+ e_index = manta_get_index(ex, em->res[0], ey, em->res[1], ez);
+
+ /* get domain index */
+ dx = gx - mds->res_min[0];
+ dy = gy - mds->res_min[1];
+ dz = gz - mds->res_min[2];
+ d_index = manta_get_index(dx, mds->res[0], dy, mds->res[1], dz);
+ /* make sure emission cell is inside the new domain boundary */
+ if (dx < 0 || dy < 0 || dz < 0 || dx >= mds->res[0] || dy >= mds->res[1] ||
+ dz >= mds->res[2]) {
+ continue;
+ }
+
+ /* sync inflow grids with actual simulation grids, inflow computation needs information from actual simulation */
+ if (emission_map[e_index] && density) {
+ density_in[d_index] = density[d_index];
+ }
+ if (emission_map[e_index] && heat) {
+ heat_in[d_index] = heat[d_index];
+ }
+ if (emission_map[e_index] && color_r) {
+ color_r_in[d_index] = color_r[d_index];
+ color_g_in[d_index] = color_g[d_index];
+ color_b_in[d_index] = color_b[d_index];
+ }
+ if (emission_map[e_index] && fuel) {
+ fuel_in[d_index] = fuel[d_index];
+ react_in[d_index] = react[d_index];
+ }
+
+ if (sfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) { // outflow
+ apply_outflow_fields(d_index,
+ distance_map[e_index],
+ density_in,
+ heat_in,
+ fuel_in,
+ react_in,
+ color_r_in,
+ color_g_in,
+ color_b_in,
+ phiout_in);
+ }
+ else if (sfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY && mmd2->time > 2) {
+ apply_inflow_fields(sfs,
+ 0.0f,
+ 9999.0f,
+ d_index,
+ density_in,
+ heat_in,
+ fuel_in,
+ react_in,
+ color_r_in,
+ color_g_in,
+ color_b_in,
+ phi_in,
+ emission_in);
+ }
+ else if (sfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW ||
+ sfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY) { // inflow
+ /* only apply inflow if enabled */
+ if (sfs->flags & FLUID_FLOW_USE_INFLOW) {
+ apply_inflow_fields(sfs,
+ emission_map[e_index],
+ distance_map[e_index],
+ d_index,
+ density_in,
+ heat_in,
+ fuel_in,
+ react_in,
+ color_r_in,
+ color_g_in,
+ color_b_in,
+ phi_in,
+ emission_in);
+ /* initial velocity */
+ if (sfs->flags & FLUID_FLOW_INITVELOCITY) {
+ velx_initial[d_index] = velocity_map[e_index * 3];
+ vely_initial[d_index] = velocity_map[e_index * 3 + 1];
+ velz_initial[d_index] = velocity_map[e_index * 3 + 2];
+ }
+ }
+ }
+ } // low res loop
+ }
+ }
+
+ // free emission maps
+ em_freeData(em);
+
+ } // end emission
+ }
+
+ BKE_collision_objects_free(flowobjs);
+ if (emaps) {
+ MEM_freeN(emaps);
+ }
+}
+
+typedef struct UpdateEffectorsData {
+ Scene *scene;
+ MantaDomainSettings *mds;
+ ListBase *effectors;
+
+ float *density;
+ float *fuel;
+ float *force_x;
+ float *force_y;
+ float *force_z;
+ float *velocity_x;
+ float *velocity_y;
+ float *velocity_z;
+ int *flags;
+ float *phiObsIn;
+} UpdateEffectorsData;
+
+static void update_effectors_task_cb(void *__restrict userdata,
+ const int x,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ UpdateEffectorsData *data = userdata;
+ MantaDomainSettings *mds = data->mds;
+
+ for (int y = 0; y < mds->res[1]; y++) {
+ for (int z = 0; z < mds->res[2]; z++) {
+ EffectedPoint epoint;
+ float mag;
+ float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
+ const unsigned int index = manta_get_index(x, mds->res[0], y, mds->res[1], z);
+
+ if ((data->fuel && MAX2(data->density[index], data->fuel[index]) < FLT_EPSILON) ||
+ (data->density && data->density[index] < FLT_EPSILON) ||
+ (data->phiObsIn && data->phiObsIn[index] < 0.0f) ||
+ data->flags[index] & 2) // mantaflow convention: 2 == FlagObstacle
+ {
+ continue;
+ }
+
+ /* get velocities from manta grid space and convert to blender units */
+ vel[0] = data->velocity_x[index];
+ vel[1] = data->velocity_y[index];
+ vel[2] = data->velocity_z[index];
+ mul_v3_fl(vel, mds->dx);
+
+ /* convert vel to global space */
+ mag = len_v3(vel);
+ mul_mat3_m4_v3(mds->obmat, vel);
+ normalize_v3(vel);
+ mul_v3_fl(vel, mag);
+
+ voxelCenter[0] = mds->p0[0] + mds->cell_size[0] * ((float)(x + mds->res_min[0]) + 0.5f);
+ voxelCenter[1] = mds->p0[1] + mds->cell_size[1] * ((float)(y + mds->res_min[1]) + 0.5f);
+ voxelCenter[2] = mds->p0[2] + mds->cell_size[2] * ((float)(z + mds->res_min[2]) + 0.5f);
+ mul_m4_v3(mds->obmat, voxelCenter);
+
+ /* do effectors */
+ pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
+ BKE_effectors_apply(data->effectors, NULL, mds->effector_weights, &epoint, retvel, NULL);
+
+ /* convert retvel to local space */
+ mag = len_v3(retvel);
+ mul_mat3_m4_v3(mds->imat, retvel);
+ normalize_v3(retvel);
+ mul_v3_fl(retvel, mag);
+
+ /* constrain forces to interval -1 to 1 */
+ data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f);
+ data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f);
+ data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f);
+ }
+ }
+}
+
+static void update_effectors(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, MantaDomainSettings *mds, float UNUSED(dt))
+{
+ ListBase *effectors;
+ /* make sure smoke flow influence is 0.0f */
+ mds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, mds->effector_weights);
+
+ if (effectors) {
+ // precalculate wind forces
+ UpdateEffectorsData data;
+ data.scene = scene;
+ data.mds = mds;
+ data.effectors = effectors;
+ data.density = manta_smoke_get_density(mds->fluid);
+ data.fuel = manta_smoke_get_fuel(mds->fluid);
+ data.force_x = manta_get_force_x(mds->fluid);
+ data.force_y = manta_get_force_y(mds->fluid);
+ data.force_z = manta_get_force_z(mds->fluid);
+ data.velocity_x = manta_get_velocity_x(mds->fluid);
+ data.velocity_y = manta_get_velocity_y(mds->fluid);
+ data.velocity_z = manta_get_velocity_z(mds->fluid);
+ data.flags = manta_smoke_get_obstacle(mds->fluid);
+ data.phiObsIn = manta_get_phiobs_in(mds->fluid);
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, mds->res[0], &data, update_effectors_task_cb, &settings);
+ }
+
+ BKE_effectors_free(effectors);
+}
+
+static Mesh *createLiquidGeometry(MantaDomainSettings *mds, Mesh *orgmesh, Object *ob)
+{
+ Mesh *me;
+ MVert *mverts;
+ MPoly *mpolys;
+ MLoop *mloops;
+ short *normals, *no_s;
+ float no[3];
+ float min[3];
+ float max[3];
+ float size[3];
+ float cell_size_scaled[3];
+
+ /* assign material + flags to new dm
+ * if there's no faces in original dm, keep materials and flags unchanged */
+ MPoly *mpoly;
+ MPoly mp_example = {0};
+ mpoly = orgmesh->mpoly;
+ if (mpoly) {
+ mp_example = *mpoly;
+ }
+ /* else leave NULL'd */
+
+ const short mp_mat_nr = mp_example.mat_nr;
+ const char mp_flag = mp_example.flag;
+
+ int i;
+ int num_verts, num_normals, num_faces;
+
+ if (!mds->fluid) {
+ return NULL;
+ }
+
+ num_verts = manta_liquid_get_num_verts(mds->fluid);
+ num_normals = manta_liquid_get_num_normals(mds->fluid);
+ num_faces = manta_liquid_get_num_triangles(mds->fluid);
+
+ //printf("num_verts: %d, num_normals: %d, num_faces: %d\n", num_verts, num_normals, num_faces);
+
+ if (!num_verts || !num_faces) {
+ return NULL;
+ }
+
+ me = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 3, num_faces);
+ mverts = me->mvert;
+ mpolys = me->mpoly;
+ mloops = me->mloop;
+ if (!me) {
+ return NULL;
+ }
+
+ // Get size (dimension) but considering scaling scaling
+ copy_v3_v3(cell_size_scaled, mds->cell_size);
+ mul_v3_v3(cell_size_scaled, ob->scale);
+ madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, cell_size_scaled, mds->res_min);
+ madd_v3fl_v3fl_v3fl_v3i(max, mds->p0, cell_size_scaled, mds->res_max);
+ sub_v3_v3v3(size, max, min);
+
+ // Biggest dimension will be used for upscaling
+ float max_size = MAX3(size[0], size[1], size[2]);
+
+ // Vertices
+ for (i = 0; i < num_verts; i++, mverts++) {
+ // read raw data. is normalized cube around domain origin
+ mverts->co[0] = manta_liquid_get_vertex_x_at(mds->fluid, i);
+ mverts->co[1] = manta_liquid_get_vertex_y_at(mds->fluid, i);
+ mverts->co[2] = manta_liquid_get_vertex_z_at(mds->fluid, i);
+
+ // if reading raw data directly from manta, normalize now
+ if ((mds->cache_flag & FLUID_DOMAIN_BAKED_MESH) == 0) {
+ // normalize to unit cube around 0
+ mverts->co[0] -= ((float)mds->res[0] * mds->mesh_scale) * 0.5f;
+ mverts->co[1] -= ((float)mds->res[1] * mds->mesh_scale) * 0.5f;
+ mverts->co[2] -= ((float)mds->res[2] * mds->mesh_scale) * 0.5f;
+ mverts->co[0] *= mds->dx / mds->mesh_scale;
+ mverts->co[1] *= mds->dx / mds->mesh_scale;
+ mverts->co[2] *= mds->dx / mds->mesh_scale;
+ }
+
+ mverts->co[0] *= max_size / fabsf(ob->scale[0]);
+ mverts->co[1] *= max_size / fabsf(ob->scale[1]);
+ mverts->co[2] *= max_size / fabsf(ob->scale[2]);
+
+ //printf("mverts->co[0]: %f, mverts->co[1]: %f, mverts->co[2]: %f\n", mverts->co[0], mverts->co[1], mverts->co[2]);
+ }
+
+ // Normals
+ normals = MEM_callocN(sizeof(short) * num_normals * 3, "Fluidmesh_tmp_normals");
+
+ for (i = 0, no_s = normals; i < num_normals; no_s += 3, i++) {
+ no[0] = manta_liquid_get_normal_x_at(mds->fluid, i);
+ no[1] = manta_liquid_get_normal_y_at(mds->fluid, i);
+ no[2] = manta_liquid_get_normal_z_at(mds->fluid, i);
+
+ normal_float_to_short_v3(no_s, no);
+
+ //printf("no_s[0]: %d, no_s[1]: %d, no_s[2]: %d\n", no_s[0], no_s[1], no_s[2]);
+ }
+
+ // Triangles
+ for (i = 0; i < num_faces; i++, mpolys++, mloops += 3) {
+ /* initialize from existing face */
+ mpolys->mat_nr = mp_mat_nr;
+ mpolys->flag = mp_flag;
+
+ mpolys->loopstart = i * 3;
+ mpolys->totloop = 3;
+
+ mloops[0].v = manta_liquid_get_triangle_x_at(mds->fluid, i);
+ mloops[1].v = manta_liquid_get_triangle_y_at(mds->fluid, i);
+ mloops[2].v = manta_liquid_get_triangle_z_at(mds->fluid, i);
+
+ //printf("mloops[0].v: %d, mloops[1].v: %d, mloops[2].v: %d\n", mloops[0].v, mloops[1].v, mloops[2].v);
+ }
+
+ BKE_mesh_ensure_normals(me);
+ BKE_mesh_calc_edges(me, false, false);
+ BKE_mesh_apply_vert_normals(me, (short(*)[3])normals);
+
+ MEM_freeN(normals);
+
+ /* return early if no mesh vert velocities required */
+ if ((mds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) == 0) {
+ return me;
+ }
+
+ if (mds->mesh_velocities) {
+ MEM_freeN(mds->mesh_velocities);
+ }
+
+ mds->mesh_velocities = MEM_calloc_arrayN(
+ num_verts, sizeof(MantaVertexVelocity), "Fluidmesh_vertvelocities");
+ mds->totvert = num_verts;
+
+ MantaVertexVelocity *velarray = NULL;
+ velarray = mds->mesh_velocities;
+
+ float time_mult = 25.f * DT_DEFAULT;
+
+ for (i = 0; i < num_verts; i++, mverts++) {
+ velarray[i].vel[0] = manta_liquid_get_vertvel_x_at(mds->fluid, i) * (mds->dx / time_mult);
+ velarray[i].vel[1] = manta_liquid_get_vertvel_y_at(mds->fluid, i) * (mds->dx / time_mult);
+ velarray[i].vel[2] = manta_liquid_get_vertvel_z_at(mds->fluid, i) * (mds->dx / time_mult);
+
+ //printf("velarray[%d].vel[0]: %f, velarray[%d].vel[1]: %f, velarray[%d].vel[2]: %f\n", i, velarray[i].vel[0], i, velarray[i].vel[1], i, velarray[i].vel[2]);
+ }
+
+ return me;
+}
+
+static Mesh *createSmokeGeometry(MantaDomainSettings *mds, Mesh *orgmesh, Object *ob)
+{
+ Mesh *result;
+ MVert *mverts;
+ MPoly *mpolys;
+ MLoop *mloops;
+ float min[3];
+ float max[3];
+ float *co;
+ MPoly *mp;
+ MLoop *ml;
+
+ int num_verts = 8;
+ int num_faces = 6;
+ int i;
+ float ob_loc[3] = {0};
+ float ob_cache_loc[3] = {0};
+
+ /* just copy existing mesh if there is no content or if the adaptive domain is not being used */
+ if (mds->total_cells <= 1 || (mds-> flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0) {
+ return BKE_mesh_copy_for_eval(orgmesh, false);
+ }
+
+ result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
+ mverts = result->mvert;
+ mpolys = result->mpoly;
+ mloops = result->mloop;
+
+ if (num_verts) {
+ /* volume bounds */
+ madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, mds->cell_size, mds->res_min);
+ madd_v3fl_v3fl_v3fl_v3i(max, mds->p0, mds->cell_size, mds->res_max);
+
+ /* set vertices */
+ /* top slab */
+ co = mverts[0].co;
+ co[0] = min[0];
+ co[1] = min[1];
+ co[2] = max[2];
+ co = mverts[1].co;
+ co[0] = max[0];
+ co[1] = min[1];
+ co[2] = max[2];
+ co = mverts[2].co;
+ co[0] = max[0];
+ co[1] = max[1];
+ co[2] = max[2];
+ co = mverts[3].co;
+ co[0] = min[0];
+ co[1] = max[1];
+ co[2] = max[2];
+ /* bottom slab */
+ co = mverts[4].co;
+ co[0] = min[0];
+ co[1] = min[1];
+ co[2] = min[2];
+ co = mverts[5].co;
+ co[0] = max[0];
+ co[1] = min[1];
+ co[2] = min[2];
+ co = mverts[6].co;
+ co[0] = max[0];
+ co[1] = max[1];
+ co[2] = min[2];
+ co = mverts[7].co;
+ co[0] = min[0];
+ co[1] = max[1];
+ co[2] = min[2];
+
+ /* create faces */
+ /* top */
+ mp = &mpolys[0];
+ ml = &mloops[0 * 4];
+ mp->loopstart = 0 * 4;
+ mp->totloop = 4;
+ ml[0].v = 0;
+ ml[1].v = 1;
+ ml[2].v = 2;
+ ml[3].v = 3;
+ /* right */
+ mp = &mpolys[1];
+ ml = &mloops[1 * 4];
+ mp->loopstart = 1 * 4;
+ mp->totloop = 4;
+ ml[0].v = 2;
+ ml[1].v = 1;
+ ml[2].v = 5;
+ ml[3].v = 6;
+ /* bottom */
+ mp = &mpolys[2];
+ ml = &mloops[2 * 4];
+ mp->loopstart = 2 * 4;
+ mp->totloop = 4;
+ ml[0].v = 7;
+ ml[1].v = 6;
+ ml[2].v = 5;
+ ml[3].v = 4;
+ /* left */
+ mp = &mpolys[3];
+ ml = &mloops[3 * 4];
+ mp->loopstart = 3 * 4;
+ mp->totloop = 4;
+ ml[0].v = 0;
+ ml[1].v = 3;
+ ml[2].v = 7;
+ ml[3].v = 4;
+ /* front */
+ mp = &mpolys[4];
+ ml = &mloops[4 * 4];
+ mp->loopstart = 4 * 4;
+ mp->totloop = 4;
+ ml[0].v = 3;
+ ml[1].v = 2;
+ ml[2].v = 6;
+ ml[3].v = 7;
+ /* back */
+ mp = &mpolys[5];
+ ml = &mloops[5 * 4];
+ mp->loopstart = 5 * 4;
+ mp->totloop = 4;
+ ml[0].v = 1;
+ ml[1].v = 0;
+ ml[2].v = 4;
+ ml[3].v = 5;
+
+ /* calculate required shift to match domain's global position
+ * it was originally simulated at (if object moves without manta step) */
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->obmat, ob_loc);
+ mul_m4_v3(mds->obmat, ob_cache_loc);
+ sub_v3_v3v3(mds->obj_shift_f, ob_cache_loc, ob_loc);
+ /* convert shift to local space and apply to vertices */
+ mul_mat3_m4_v3(ob->imat, mds->obj_shift_f);
+ /* apply */
+ for (i = 0; i < num_verts; i++) {
+ add_v3_v3(mverts[i].co, mds->obj_shift_f);
+ }
+ }
+
+ BKE_mesh_calc_edges(result, false, false);
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ return result;
+}
+
+static void manta_step(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *me,
+ MantaModifierData *mmd,
+ int frame)
+{
+ MantaDomainSettings *mds = mmd->domain;
+ float dt, frame_length, time_total;
+ float time_per_frame;
+ bool init_resolution = true;
+
+ /* update object state */
+ invert_m4_m4(mds->imat, ob->obmat);
+ copy_m4_m4(mds->obmat, ob->obmat);
+
+ /* gas domain might use adaptive domain */
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS) {
+ init_resolution = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) != 0;
+ }
+ manta_set_domain_from_mesh(mds, ob, me, init_resolution);
+
+ /* use local variables for adaptive loop, dt can change */
+ frame_length = mds->frame_length;
+ dt = mds->dt;
+ time_per_frame = 0;
+ time_total = mds->time_total;
+
+ BLI_mutex_lock(&object_update_lock);
+
+ /* loop as long as time_per_frame (sum of sub dt's) does not exceed actual framelength */
+ while (time_per_frame < frame_length) {
+ manta_adapt_timestep(mds->fluid);
+ dt = manta_get_timestep(mds->fluid);
+
+ /* save adapted dt so that MANTA object can access it (important when adaptive domain creates new MANTA object) */
+ mds->dt = dt;
+
+ /* count for how long this while loop is running */
+ time_per_frame += dt;
+ time_total += dt;
+
+ /* Calculate inflow geometry */
+ update_flowsfluids(depsgraph, scene, ob, mds, time_per_frame, frame_length, frame, dt);
+
+
+ manta_update_variables(mds->fluid, mmd);
+
+ /* Calculate obstacle geometry */
+ update_obstacles(depsgraph, scene, ob, mds, time_per_frame, frame_length, frame, dt);
+
+ if (mds->total_cells > 1) {
+ update_effectors(
+ depsgraph,
+ scene,
+ ob,
+ mds,
+ dt);
+ manta_bake_data(mds->fluid, mmd, frame);
+
+ mds->time_per_frame = time_per_frame;
+ mds->time_total = time_total;
+ }
+ }
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS) {
+ manta_smoke_calc_transparency(mds, DEG_get_evaluated_view_layer(depsgraph));
+ }
+ BLI_mutex_unlock(&object_update_lock);
+}
+
+static void manta_guiding(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, MantaModifierData *mmd, int frame)
+{
+ MantaDomainSettings *mds = mmd->domain;
+ float fps = scene->r.frs_sec / scene->r.frs_sec_base;
+ float dt = DT_DEFAULT * (25.0f / fps) * mds->time_scale;;
+
+ BLI_mutex_lock(&object_update_lock);
+
+ update_obstacles(depsgraph, scene, ob, mds, dt, dt, frame, dt);
+ manta_bake_guiding(mds->fluid, mmd, frame);
+
+ BLI_mutex_unlock(&object_update_lock);
+}
+
+static void mantaModifier_process(
+ MantaModifierData *mmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
+{
+ const int scene_framenr = (int)DEG_get_ctime(depsgraph);
+
+ if ((mmd->type & MOD_MANTA_TYPE_FLOW)) {
+ if (scene_framenr >= mmd->time) {
+ mantaModifier_init(mmd, depsgraph, ob, scene, me);
+ }
+
+ if (mmd->flow) {
+ if (mmd->flow->mesh) {
+ BKE_id_free(NULL, mmd->flow->mesh);
+ }
+ mmd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
+ }
+
+ if (scene_framenr > mmd->time) {
+ mmd->time = scene_framenr;
+ }
+ else if (scene_framenr < mmd->time) {
+ mmd->time = scene_framenr;
+ mantaModifier_reset_ex(mmd, false);
+ }
+ }
+ else if (mmd->type & MOD_MANTA_TYPE_EFFEC) {
+ if (scene_framenr >= mmd->time) {
+ mantaModifier_init(mmd, depsgraph, ob, scene, me);
+ }
+
+ if (mmd->effec) {
+ if (mmd->effec->mesh) {
+ BKE_id_free(NULL, mmd->effec->mesh);
+ }
+ mmd->effec->mesh = BKE_mesh_copy_for_eval(me, false);
+ }
+
+ if (scene_framenr > mmd->time) {
+ mmd->time = scene_framenr;
+ }
+ else if (scene_framenr < mmd->time) {
+ mmd->time = scene_framenr;
+ mantaModifier_reset_ex(mmd, false);
+ }
+ }
+ else if (mmd->type & MOD_MANTA_TYPE_DOMAIN) {
+ MantaDomainSettings *mds = mmd->domain;
+ int startframe, endframe;
+ Object *guiding_parent = NULL;
+ Object **objs = NULL;
+ unsigned int numobj = 0;
+ MantaModifierData *mmd_parent = NULL;
+ startframe = mds->cache_frame_start;
+ endframe = mds->cache_frame_end;
+
+ bool is_baking = (mds->cache_flag & (FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKING_NOISE |
+ FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKING_PARTICLES |
+ FLUID_DOMAIN_BAKING_GUIDING));
+ bool is_baked = (mds->cache_flag & (FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_BAKED_NOISE |
+ FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_BAKED_PARTICLES |
+ FLUID_DOMAIN_BAKED_GUIDING));
+
+ /* Reset fluid if no fluid present (obviously)
+ * or if timeline gets reset to startframe when no (!) baking is running
+ * or if no baking is running and also there is no baked data present */
+ if (!mds->fluid || (scene_framenr == startframe && !is_baking) || (!is_baking && !is_baked)) {
+ mantaModifier_reset_ex(mmd, false);
+ }
+
+ mantaModifier_init(mmd, depsgraph, ob, scene, me);
+
+ /* ensure that time parameters are initialized correctly before every step */
+ float fps = scene->r.frs_sec / scene->r.frs_sec_base;
+ mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale;
+ mds->dt = mds->frame_length;
+ mds->time_per_frame = 0;
+ mds->time_total = (scene_framenr-1) * mds->frame_length;
+
+ /* Guiding parent res pointer needs initialization */
+ guiding_parent = mds->guiding_parent;
+ if (guiding_parent) {
+ mmd_parent = (MantaModifierData *)modifiers_findByType(guiding_parent, eModifierType_Manta);
+ if (mmd_parent->domain) {
+ mds->guide_res = mmd_parent->domain->res;
+ }
+ }
+
+ /* Cache does not keep track of active fields yet. So refresh them here */
+ objs = BKE_collision_objects_create(
+ depsgraph, ob, mds->fluid_group, &numobj, eModifierType_Manta);
+ update_flowsflags(mds, objs, numobj);
+ if (objs) {
+ MEM_freeN(objs);
+ }
+
+ objs = BKE_collision_objects_create(
+ depsgraph, ob, mds->coll_group, &numobj, eModifierType_Manta);
+ update_obstacleflags(mds, objs, numobj);
+ if (objs) {
+ MEM_freeN(objs);
+ }
+
+ /* Read cache. For liquids update data directly (i.e. not via python) */
+ if (!is_baking) {
+ if (mds->cache_flag & FLUID_DOMAIN_BAKED_DATA)
+ {
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS) {
+ if (manta_read_config(mds->fluid, mmd, scene_framenr)) {
+ /* Adaptive domain might have changed resolution */
+ if (manta_needs_realloc(mds->fluid, mmd)) {
+ BKE_manta_reallocate_fluid(mds, mds->res, 1);
+ }
+ manta_read_data(mds->fluid, mmd, scene_framenr);
+ }
+ }
+ if (mds->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ manta_update_liquid_structures(mds->fluid, mmd, scene_framenr);
+ }
+ }
+ if (mds->cache_flag & FLUID_DOMAIN_BAKED_NOISE)
+ {
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS) {
+ if (manta_read_config(mds->fluid, mmd, scene_framenr)) {
+ if (manta_needs_realloc(mds->fluid, mmd)) {
+ BKE_manta_reallocate_fluid(mds, mds->res, 1);
+ }
+ manta_read_noise(mds->fluid, mmd, scene_framenr);
+ }
+ }
+ }
+ if (mds->cache_flag & FLUID_DOMAIN_BAKED_MESH)
+ {
+ //if (mds->type == FLUID_DOMAIN_TYPE_GAS)
+ // TODO (sebbas): smoke as mesh
+ if (mds->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ manta_update_mesh_structures(mds->fluid, mmd, scene_framenr);
+ }
+ }
+ if (mds->cache_flag & FLUID_DOMAIN_BAKED_PARTICLES)
+ {
+ //if (mds->type == FLUID_DOMAIN_TYPE_GAS)
+ // TODO (sebbas): fire particles
+ if (mds->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ manta_update_particle_structures(mds->fluid, mmd, scene_framenr);
+ }
+ }
+ }
+
+ /* Simulate step and write cache. Optionally also read py objects once from previous frame (bake started from resume operator) */
+ if (is_baking) {
+ /* Ensure fresh variables at every animation step */
+ manta_update_variables(mds->fluid, mmd);
+
+ /* Export mantaflow python script on first frame (once only) and for any bake type */
+ if ((mds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT) &&
+ scene_framenr == mds->cache_frame_start)
+ {
+ if (mmd->domain && mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
+ manta_smoke_export_script(mmd->domain->fluid, mmd);
+ }
+ if (mmd->domain && mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ manta_liquid_export_script(mmd->domain->fluid, mmd);
+ }
+ }
+
+ if (mds->cache_flag & FLUID_DOMAIN_BAKING_DATA)
+ {
+ if (mds->flags & FLUID_DOMAIN_USE_GUIDING) {
+ /* Load guiding vel from flow object (only if baked) or else from domain object */
+ if (mds->guiding_source == FLUID_DOMAIN_GUIDING_SRC_EFFECTOR &&
+ mds->cache_flag & FLUID_DOMAIN_BAKED_GUIDING) {
+ manta_read_guiding(mds->fluid, mmd, scene_framenr, false);
+ }
+ else if (mds->guiding_source == FLUID_DOMAIN_GUIDING_SRC_DOMAIN && mmd_parent) {
+ manta_read_guiding(mds->fluid, mmd_parent, scene_framenr, true);
+ }
+ }
+
+ /* Refresh all objects if we start baking from a resumed frame */
+ if (mds->cache_frame_start != scene_framenr &&
+ mds->cache_frame_pause_data == scene_framenr) {
+ /* Adaptive domain might have changed resolution */
+ manta_read_config(mds->fluid, mmd, scene_framenr - 1);
+ if (manta_needs_realloc(mds->fluid, mmd)) {
+ BKE_manta_reallocate_fluid(mds, mds->res, 1);
+ }
+ manta_read_data(mds->fluid, mmd, scene_framenr - 1);
+ }
+
+ /* Base step needs separated bake and write calls as transparency calculation happens after fluid step */
+ manta_step(depsgraph, scene, ob, me, mmd, scene_framenr);
+ manta_write_config(mds->fluid, mmd, scene_framenr);
+ manta_write_data(mds->fluid, mmd, scene_framenr);
+ }
+ if (mds->cache_flag & FLUID_DOMAIN_BAKING_NOISE)
+ {
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS) {
+ /* Refresh all objects if we start baking from a resumed frame */
+ if (mds->cache_frame_start != scene_framenr &&
+ mds->cache_frame_pause_noise == scene_framenr) {
+ /* Adaptive domain might have changed resolution */
+ manta_read_config(mds->fluid, mmd, scene_framenr - 1);
+ if (manta_needs_realloc(mds->fluid, mmd)) {
+ BKE_manta_reallocate_fluid(mds, mds->res, 1);
+ }
+ manta_read_data(mds->fluid, mmd, scene_framenr - 1);
+ manta_read_noise(mds->fluid, mmd, scene_framenr - 1);
+ }
+ if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
+ int o_res[3], o_min[3], o_max[3], o_shift[3];
+ copy_v3_v3_int(o_res, mds->res);
+ copy_v3_v3_int(o_min, mds->res_min);
+ copy_v3_v3_int(o_max, mds->res_max);
+ copy_v3_v3_int(o_shift, mds->shift);
+ manta_read_config(mds->fluid, mmd, scene_framenr);
+ if (manta_needs_realloc(mds->fluid, mmd)) {
+ /* Copy function also handles realloc of MANTA object */
+ adaptiveDomainCopy(mds, o_res, mds->res, o_min, mds->res_min, o_max, o_shift, mds->shift, 1);
+ }
+ }
+ manta_bake_noise(mds->fluid, mmd, scene_framenr);
+ }
+ }
+ if (mds->cache_flag & FLUID_DOMAIN_BAKING_MESH)
+ {
+ if (mds->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ /* Note: Mesh bake does not need object refresh from cache */
+ manta_bake_mesh(mds->fluid, mmd, scene_framenr);
+ }
+ }
+ if (mds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES)
+ {
+ if (mds->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ /* Refresh all objects if we start baking from a resumed frame */
+ if (mds->cache_frame_start != scene_framenr &&
+ mds->cache_frame_pause_particles == scene_framenr) {
+ manta_read_particles(mds->fluid, mmd, scene_framenr - 1);
+ }
+ manta_bake_particles(mds->fluid, mmd, scene_framenr);
+ }
+ }
+ if (mds->cache_flag & FLUID_DOMAIN_BAKING_GUIDING)
+ {
+ manta_guiding(depsgraph, scene, ob, mmd, scene_framenr);
+ }
+ }
+ mmd->time = scene_framenr;
+ }
+}
+
+struct Mesh *mantaModifier_do(
+ MantaModifierData *mmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
+{
+ /* lock so preview render does not read smoke data while it gets modified */
+ if ((mmd->type & MOD_MANTA_TYPE_DOMAIN) && mmd->domain) {
+ BLI_rw_mutex_lock(mmd->domain->fluid_mutex, THREAD_LOCK_WRITE);
+ }
+
+ mantaModifier_process(mmd, depsgraph, scene, ob, me);
+
+ if ((mmd->type & MOD_MANTA_TYPE_DOMAIN) && mmd->domain) {
+ BLI_rw_mutex_unlock(mmd->domain->fluid_mutex);
+ }
+
+ /* return generated geometry for adaptive domain */
+ Mesh *result = NULL;
+ if (mmd->type & MOD_MANTA_TYPE_DOMAIN && mmd->domain)
+ {
+ if (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ result = createLiquidGeometry(mmd->domain, me, ob);
+ }
+ if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
+ result = createSmokeGeometry(mmd->domain, me, ob);
+ }
+ }
+ if (!result) {
+ result = BKE_mesh_copy_for_eval(me, false);
+ }
+ /* XXX This is really not a nice hack, but until root of the problem is understood,
+ * this should be an acceptable workaround I think.
+ * See T58492 for details on the issue. */
+ result->texflag |= ME_AUTOSPACE;
+ return result;
+}
+
+static float calc_voxel_transp(
+ float *result, float *input, int res[3], int *pixel, float *tRay, float correct)
+{
+ const size_t index = manta_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
+
+ // T_ray *= T_vox
+ *tRay *= expf(input[index] * correct);
+
+ if (result[index] < 0.0f) {
+ result[index] = *tRay;
+ }
+
+ return *tRay;
+}
+
+static void bresenham_linie_3D(int x1,
+ int y1,
+ int z1,
+ int x2,
+ int y2,
+ int z2,
+ float *tRay,
+ bresenham_callback cb,
+ float *result,
+ float *input,
+ int res[3],
+ float correct)
+{
+ int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
+ int pixel[3];
+
+ pixel[0] = x1;
+ pixel[1] = y1;
+ pixel[2] = z1;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dz = z2 - z1;
+
+ x_inc = (dx < 0) ? -1 : 1;
+ l = abs(dx);
+ y_inc = (dy < 0) ? -1 : 1;
+ m = abs(dy);
+ z_inc = (dz < 0) ? -1 : 1;
+ n = abs(dz);
+ dx2 = l << 1;
+ dy2 = m << 1;
+ dz2 = n << 1;
+
+ if ((l >= m) && (l >= n)) {
+ err_1 = dy2 - l;
+ err_2 = dz2 - l;
+ for (i = 0; i < l; i++) {
+ if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) {
+ break;
+ }
+ if (err_1 > 0) {
+ pixel[1] += y_inc;
+ err_1 -= dx2;
+ }
+ if (err_2 > 0) {
+ pixel[2] += z_inc;
+ err_2 -= dx2;
+ }
+ err_1 += dy2;
+ err_2 += dz2;
+ pixel[0] += x_inc;
+ }
+ }
+ else if ((m >= l) && (m >= n)) {
+ err_1 = dx2 - m;
+ err_2 = dz2 - m;
+ for (i = 0; i < m; i++) {
+ if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) {
+ break;
+ }
+ if (err_1 > 0) {
+ pixel[0] += x_inc;
+ err_1 -= dy2;
+ }
+ if (err_2 > 0) {
+ pixel[2] += z_inc;
+ err_2 -= dy2;
+ }
+ err_1 += dx2;
+ err_2 += dz2;
+ pixel[1] += y_inc;
+ }
+ }
+ else {
+ err_1 = dy2 - n;
+ err_2 = dx2 - n;
+ for (i = 0; i < n; i++) {
+ if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) {
+ break;
+ }
+ if (err_1 > 0) {
+ pixel[1] += y_inc;
+ err_1 -= dz2;
+ }
+ if (err_2 > 0) {
+ pixel[0] += x_inc;
+ err_2 -= dz2;
+ }
+ err_1 += dy2;
+ err_2 += dx2;
+ pixel[2] += z_inc;
+ }
+ }
+ cb(result, input, res, pixel, tRay, correct);
+}
+
+static void manta_smoke_calc_transparency(MantaDomainSettings *mds, ViewLayer *view_layer)
+{
+ float bv[6] = {0};
+ float light[3];
+ int a, z, slabsize = mds->res[0] * mds->res[1], size = mds->res[0] * mds->res[1] * mds->res[2];
+ float *density = manta_smoke_get_density(mds->fluid);
+ float *shadow = manta_smoke_get_shadow(mds->fluid);
+ float correct = -7.0f * mds->dx;
+
+ if (!get_light(view_layer, light)) {
+ return;
+ }
+
+ /* convert light pos to sim cell space */
+ mul_m4_v3(mds->imat, light);
+ light[0] = (light[0] - mds->p0[0]) / mds->cell_size[0] - 0.5f - (float)mds->res_min[0];
+ light[1] = (light[1] - mds->p0[1]) / mds->cell_size[1] - 0.5f - (float)mds->res_min[1];
+ light[2] = (light[2] - mds->p0[2]) / mds->cell_size[2] - 0.5f - (float)mds->res_min[2];
+
+ for (a = 0; a < size; a++) {
+ shadow[a] = -1.0f;
+ }
+
+ /* calculate domain bounds in sim cell space */
+ // 0,2,4 = 0.0f
+ bv[1] = (float)mds->res[0]; // x
+ bv[3] = (float)mds->res[1]; // y
+ bv[5] = (float)mds->res[2]; // z
+
+ for (z = 0; z < mds->res[2]; z++) {
+ size_t index = z * slabsize;
+ int x, y;
+
+ for (y = 0; y < mds->res[1]; y++) {
+ for (x = 0; x < mds->res[0]; x++, index++) {
+ float voxelCenter[3];
+ float pos[3];
+ int cell[3];
+ float tRay = 1.0;
+
+ if (shadow[index] >= 0.0f) {
+ continue;
+ }
+ voxelCenter[0] = (float)x;
+ voxelCenter[1] = (float)y;
+ voxelCenter[2] = (float)z;
+
+ // get starting cell (light pos)
+ if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) {
+ // we're ouside -> use point on side of domain
+ cell[0] = (int)floor(pos[0]);
+ cell[1] = (int)floor(pos[1]);
+ cell[2] = (int)floor(pos[2]);
+ }
+ else {
+ // we're inside -> use light itself
+ cell[0] = (int)floor(light[0]);
+ cell[1] = (int)floor(light[1]);
+ cell[2] = (int)floor(light[2]);
+ }
+ /* clamp within grid bounds */
+ CLAMP(cell[0], 0, mds->res[0] - 1);
+ CLAMP(cell[1], 0, mds->res[1] - 1);
+ CLAMP(cell[2], 0, mds->res[2] - 1);
+
+ bresenham_linie_3D(cell[0],
+ cell[1],
+ cell[2],
+ x,
+ y,
+ z,
+ &tRay,
+ calc_voxel_transp,
+ shadow,
+ density,
+ mds->res,
+ correct);
+
+ // convention -> from a RGBA float array, use G value for tRay
+ shadow[index] = tRay;
+ }
+ }
+ }
+}
+
+/* get smoke velocity and density at given coordinates
+ * returns fluid density or -1.0f if outside domain. */
+float BKE_manta_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
+{
+ MantaModifierData *mmd = (MantaModifierData *)modifiers_findByType(ob, eModifierType_Manta);
+ zero_v3(velocity);
+
+ if (mmd && (mmd->type & MOD_MANTA_TYPE_DOMAIN) && mmd->domain && mmd->domain->fluid) {
+ MantaDomainSettings *mds = mmd->domain;
+ float time_mult = 25.f * DT_DEFAULT;
+ float vel_mag;
+ float *velX = manta_get_velocity_x(mds->fluid);
+ float *velY = manta_get_velocity_y(mds->fluid);
+ float *velZ = manta_get_velocity_z(mds->fluid);
+ float density = 0.0f, fuel = 0.0f;
+ float pos[3];
+ copy_v3_v3(pos, position);
+ manta_pos_to_cell(mds, pos);
+
+ /* check if point is outside domain max bounds */
+ if (pos[0] < mds->res_min[0] || pos[1] < mds->res_min[1] || pos[2] < mds->res_min[2]) {
+ return -1.0f;
+ }
+ if (pos[0] > mds->res_max[0] || pos[1] > mds->res_max[1] || pos[2] > mds->res_max[2]) {
+ return -1.0f;
+ }
+
+ /* map pos between 0.0 - 1.0 */
+ pos[0] = (pos[0] - mds->res_min[0]) / ((float)mds->res[0]);
+ pos[1] = (pos[1] - mds->res_min[1]) / ((float)mds->res[1]);
+ pos[2] = (pos[2] - mds->res_min[2]) / ((float)mds->res[2]);
+
+ /* check if point is outside active area */
+ if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS &&
+ mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN)
+ {
+ if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) {
+ return 0.0f;
+ }
+ if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) {
+ return 0.0f;
+ }
+ }
+
+ /* get interpolated velocity */
+ velocity[0] = BLI_voxel_sample_trilinear(velX, mds->res, pos) * mds->global_size[0] *
+ time_mult;
+ velocity[1] = BLI_voxel_sample_trilinear(velY, mds->res, pos) * mds->global_size[1] *
+ time_mult;
+ velocity[2] = BLI_voxel_sample_trilinear(velZ, mds->res, pos) * mds->global_size[2] *
+ time_mult;
+
+ /* convert velocity direction to global space */
+ vel_mag = len_v3(velocity);
+ mul_mat3_m4_v3(mds->obmat, velocity);
+ normalize_v3(velocity);
+ mul_v3_fl(velocity, vel_mag);
+
+ /* use max value of fuel or smoke density */
+ density = BLI_voxel_sample_trilinear(manta_smoke_get_density(mds->fluid), mds->res, pos);
+ if (manta_smoke_has_fuel(mds->fluid)) {
+ fuel = BLI_voxel_sample_trilinear(manta_smoke_get_fuel(mds->fluid), mds->res, pos);
+ }
+ return MAX2(density, fuel);
+ }
+ return -1.0f;
+}
+
+int BKE_manta_get_data_flags(MantaDomainSettings *mds)
+{
+ int flags = 0;
+
+ if (mds->fluid) {
+ if (manta_smoke_has_heat(mds->fluid)) {
+ flags |= FLUID_DOMAIN_ACTIVE_HEAT;
+ }
+ if (manta_smoke_has_fuel(mds->fluid)) {
+ flags |= FLUID_DOMAIN_ACTIVE_FIRE;
+ }
+ if (manta_smoke_has_colors(mds->fluid)) {
+ flags |= FLUID_DOMAIN_ACTIVE_COLORS;
+ }
+ }
+
+ return flags;
+}
+
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index d7256cc9604..e968a626574 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -39,6 +39,7 @@
#include "DNA_key_types.h"
#include "DNA_light_types.h"
#include "DNA_lattice_types.h"
+#include "DNA_manta_types.h"
#include "DNA_material_types.h"
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
@@ -48,7 +49,6 @@
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
-#include "DNA_smoke_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
@@ -121,10 +121,6 @@
#include "DRW_engine.h"
-#ifdef WITH_MOD_FLUID
-# include "LBM_fluidsim.h"
-#endif
-
#ifdef WITH_PYTHON
# include "BPY_extern.h"
#endif
@@ -859,9 +855,6 @@ void BKE_object_init(Object *ob)
ob->preview = NULL;
ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
- /* NT fluid sim defaults */
- ob->fluidsimSettings = NULL;
-
BLI_listbase_clear(&ob->pc_ids);
/* Animation Visualization defaults */
@@ -1122,13 +1115,13 @@ void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const
}
}
}
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ else if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
- if (smd->type == MOD_SMOKE_TYPE_FLOW) {
- if (smd->flow) {
- if (smd->flow->psys == psys) {
- smd->flow->psys = npsys;
+ if (mmd->type == MOD_MANTA_TYPE_FLOW) {
+ if (mmd->flow) {
+ if (mmd->flow->psys == psys) {
+ mmd->flow->psys = npsys;
}
}
}
@@ -4352,10 +4345,10 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
return true;
}
}
- else if (type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ else if (type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) != 0) {
+ if (mmd && (mmd->type & MOD_MANTA_TYPE_DOMAIN) != 0) {
return true;
}
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 079a348745c..0ef4bf7ab3d 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -34,7 +34,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_particle_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_scene_types.h"
#include "DNA_dynamicpaint_types.h"
@@ -3576,12 +3576,12 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
return;
}
- /* clear all other appearances of this pointer (like on smoke flow modifier) */
- if ((md = modifiers_findByType(ob, eModifierType_Smoke))) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if ((smd->type == MOD_SMOKE_TYPE_FLOW) && smd->flow && smd->flow->psys) {
- if (smd->flow->psys == psys) {
- smd->flow->psys = NULL;
+ /* clear all other appearances of this pointer (like on manta flow modifier) */
+ if ((md = modifiers_findByType(ob, eModifierType_Manta))) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ if ((mmd->type == MOD_MANTA_TYPE_FLOW) && mmd->flow && mmd->flow->psys) {
+ if (mmd->flow->psys == psys) {
+ mmd->flow->psys = NULL;
}
}
}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 27722aab2d9..b30dfe896cf 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -85,14 +85,11 @@
#include "RE_shader_ext.h"
-/* fluid sim particle import */
-#ifdef WITH_MOD_FLUID
-# include "DNA_object_fluidsim_types.h"
-# include "LBM_fluidsim.h"
-# include <zlib.h>
-# include <string.h>
-
-#endif // WITH_MOD_FLUID
+/* manta sim particle import */
+#ifdef WITH_MANTA
+# include "DNA_manta_types.h"
+# include "manta_fluid_API.h"
+#endif // WITH_MANTA
static ThreadRWMutex psys_bvhtree_rwlock = BLI_RWLOCK_INITIALIZER;
@@ -581,21 +578,17 @@ static void initialize_particle_texture(ParticleSimulationData *sim, ParticleDat
psys_get_texture(sim, pa, &ptex, PAMAP_INIT, 0.f);
- switch (part->type) {
- case PART_EMITTER:
- if (ptex.exist < psys_frand(psys, p + 125)) {
- pa->flag |= PARS_UNEXIST;
- }
- pa->time = part->sta + (part->end - part->sta) * ptex.time;
- break;
- case PART_HAIR:
- if (ptex.exist < psys_frand(psys, p + 125)) {
- pa->flag |= PARS_UNEXIST;
- }
- pa->time = 0.f;
- break;
- case PART_FLUID:
- break;
+ if (part->type & PART_EMITTER) {
+ if (ptex.exist < psys_frand(psys, p + 125)) {
+ pa->flag |= PARS_UNEXIST;
+ }
+ pa->time = part->sta + (part->end - part->sta) * ptex.time;
+ }
+ if (part->type & PART_HAIR) {
+ if (ptex.exist < psys_frand(psys, p + 125)) {
+ pa->flag |= PARS_UNEXIST;
+ }
+ pa->time = 0.f;
}
}
@@ -4116,7 +4109,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_
}
}
-static void particles_fluid_step(ParticleSimulationData *sim,
+static void particles_manta_step(ParticleSimulationData *sim,
int UNUSED(cfra),
const bool use_render_params)
{
@@ -4127,80 +4120,202 @@ static void particles_fluid_step(ParticleSimulationData *sim,
psys->totpart = 0;
}
- /* fluid sim particle import handling, actual loading of particles from file */
-#ifdef WITH_MOD_FLUID
+#ifdef WITH_MANTA
{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- sim->ob, eModifierType_Fluidsim);
+ Object *ob = sim->ob;
+ MantaModifierData *mmd = (MantaModifierData *)modifiers_findByType(ob, eModifierType_Manta);
+
+ if (mmd && mmd->domain && mmd->domain->fluid) {
+ MantaDomainSettings *mds = mmd->domain;
- if (fluidmd && fluidmd->fss) {
- FluidsimSettings *fss = fluidmd->fss;
ParticleSettings *part = psys->part;
ParticleData *pa = NULL;
- char filename[256];
- char debugStrBuffer[256];
- int curFrame = sim->scene->r.cfra - 1; // warning - sync with derived mesh fsmesh loading
- int p, j, totpart;
- int readMask, activeParts = 0, fileParts = 0;
- gzFile gzf;
-
- // XXX if (ob==G.obedit) // off...
- // return;
- // ok, start loading
- BLI_join_dirfile(
- filename, sizeof(filename), fss->surfdataPath, OB_FLUIDSIM_SURF_PARTICLES_FNAME);
-
- BLI_path_abs(filename, modifier_path_relbase_from_global(sim->ob));
-
- BLI_path_frame(filename, curFrame, 0); // fixed #frame-no
+ int p, totpart, tottypepart = 0;
+ int flagActivePart, activeParts = 0;
+ float posX, posY, posZ, velX, velY, velZ;
+ float resX, resY, resZ;
+ int upres = 1;
+ char debugStrBuffer[256];
- gzf = BLI_gzopen(filename, "rb");
- if (!gzf) {
+ /* Helper variables for scaling */
+ float min[3], max[3], size[3], cell_size_scaled[3], max_size;
+
+ /* Sanity check: parts also enabled in fluid domain? */
+ if ((part->type & PART_MANTA_FLIP &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_FLIP) == 0) ||
+ (part->type & PART_MANTA_SPRAY &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) == 0) ||
+ (part->type & PART_MANTA_BUBBLE &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) == 0) ||
+ (part->type & PART_MANTA_FOAM &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) == 0) ||
+ (part->type & PART_MANTA_TRACER &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) == 0)) {
BLI_snprintf(debugStrBuffer,
sizeof(debugStrBuffer),
- "readFsPartData::error - Unable to open file for reading '%s'\n",
- filename);
- // XXX bad level call elbeemDebugOut(debugStrBuffer);
+ "particles_manta_step::error - found particle system that is not enabled in "
+ "fluid domain\n");
return;
}
- gzread(gzf, &totpart, sizeof(totpart));
- totpart = (use_render_params) ? totpart : (part->disp * totpart) / 100;
+ /* Count particle amount. tottypepart only important for snd particles */
+ if (part->type & PART_MANTA_FLIP) {
+ tottypepart = totpart = manta_liquid_get_num_flip_particles(mds->fluid);
+ }
+ if (part->type &
+ (PART_MANTA_SPRAY | PART_MANTA_BUBBLE | PART_MANTA_FOAM | PART_MANTA_TRACER)) {
+ totpart = manta_liquid_get_num_snd_particles(mds->fluid);
+
+ /* tottypepart is the amount of particles of a snd particle type */
+ for (p = 0; p < totpart; p++) {
+ flagActivePart = manta_liquid_get_snd_particle_flag_at(mds->fluid, p);
+ if ((part->type & PART_MANTA_SPRAY) && (flagActivePart & PSPRAY))
+ tottypepart++;
+ if ((part->type & PART_MANTA_BUBBLE) && (flagActivePart & PBUBBLE))
+ tottypepart++;
+ if ((part->type & PART_MANTA_FOAM) && (flagActivePart & PFOAM))
+ tottypepart++;
+ if ((part->type & PART_MANTA_TRACER) && (flagActivePart & PTRACER))
+ tottypepart++;
+ }
+ }
+ /* Sanity check: no particles present */
+ if (!totpart || !tottypepart)
+ return;
+
+ /* How many particles to display? */
+ tottypepart = (use_render_params) ? tottypepart : (part->disp * tottypepart) / 100;
- part->totpart = totpart;
+ part->totpart = tottypepart;
part->sta = part->end = 1.0f;
part->lifetime = sim->scene->r.efra + 1;
- /* allocate particles */
+ /* Allocate particles */
realloc_particles(sim, part->totpart);
- // set up reading mask
- readMask = fss->typeFlags;
+ /* Randomness when choosing which particles to display */
+ srand(123456789); // set seed
+ double r, dispProb = (double)part->disp / 100.0;
+
+ /* Loop over *all* particles. Will break out of loop before tottypepart amount exceeded */
+ for (p = 0, pa = psys->particles; p < totpart; p++) {
+
+ /* Apply some randomness and determine which particles to skip */
+ r = (double)rand() / (double)RAND_MAX;
+ if (r > dispProb)
+ continue;
+
+ /* flag, res, upres, pos, vel for FLIP and snd particles have different getterss */
+ if (part->type & PART_MANTA_FLIP) {
+ flagActivePart = manta_liquid_get_flip_particle_flag_at(mds->fluid, p);
- for (p = 0, pa = psys->particles; p < totpart; p++, pa++) {
- int ptype = 0;
+ resX = (float)manta_get_res_x(mds->fluid);
+ resY = (float)manta_get_res_y(mds->fluid);
+ resZ = (float)manta_get_res_z(mds->fluid);
- gzread(gzf, &ptype, sizeof(ptype));
- if (ptype & readMask) {
+ upres = 1;
+
+ posX = manta_liquid_get_flip_particle_position_x_at(mds->fluid, p);
+ posY = manta_liquid_get_flip_particle_position_y_at(mds->fluid, p);
+ posZ = manta_liquid_get_flip_particle_position_z_at(mds->fluid, p);
+
+ velX = manta_liquid_get_flip_particle_velocity_x_at(mds->fluid, p);
+ velY = manta_liquid_get_flip_particle_velocity_y_at(mds->fluid, p);
+ velZ = manta_liquid_get_flip_particle_velocity_z_at(mds->fluid, p);
+ }
+ else if (part->type &
+ (PART_MANTA_SPRAY | PART_MANTA_BUBBLE | PART_MANTA_FOAM | PART_MANTA_TRACER)) {
+ flagActivePart = manta_liquid_get_snd_particle_flag_at(mds->fluid, p);
+
+ resX = (float)manta_liquid_get_particle_res_x(mds->fluid);
+ resY = (float)manta_liquid_get_particle_res_y(mds->fluid);
+ resZ = (float)manta_liquid_get_particle_res_z(mds->fluid);
+
+ upres = manta_liquid_get_particle_upres(mds->fluid);
+
+ posX = manta_liquid_get_snd_particle_position_x_at(mds->fluid, p);
+ posY = manta_liquid_get_snd_particle_position_y_at(mds->fluid, p);
+ posZ = manta_liquid_get_snd_particle_position_z_at(mds->fluid, p);
+
+ velX = manta_liquid_get_snd_particle_velocity_x_at(mds->fluid, p);
+ velY = manta_liquid_get_snd_particle_velocity_y_at(mds->fluid, p);
+ velZ = manta_liquid_get_snd_particle_velocity_z_at(mds->fluid, p);
+ }
+ else {
+ BLI_snprintf(debugStrBuffer,
+ sizeof(debugStrBuffer),
+ "particles_manta_step::error - unknown particle system type\n");
+ return;
+ }
+ // printf("part->type: %d, flagActivePart: %d\n", part->type, flagActivePart);
+
+ /* Type of particle must matche current particle system type (only important for snd particles) */
+ if ((flagActivePart & PSPRAY) && (part->type & PART_MANTA_SPRAY) == 0)
+ continue;
+ if ((flagActivePart & PBUBBLE) && (part->type & PART_MANTA_BUBBLE) == 0)
+ continue;
+ if ((flagActivePart & PFOAM) && (part->type & PART_MANTA_FOAM) == 0)
+ continue;
+ if ((flagActivePart & PTRACER) && (part->type & PART_MANTA_TRACER) == 0)
+ continue;
+
+ // printf("system type is %d and particle type is %d\n", part->type, flagActivePart);
+
+ /* Particle system has allocated tottypeparts particles - so break early before exceeded */
+ if (activeParts >= tottypepart)
+ break;
+
+ /* Only show active particles, i.e. filter out dead particles that just Mantaflow needs
+ * Mantaflow convention: PDELETE == inactive particle */
+ if ((flagActivePart & PDELETE) == 0) {
activeParts++;
- gzread(gzf, &(pa->size), sizeof(float));
+ /* Use particle system settings for particle size */
+ pa->size = part->size;
+ if (part->randsize > 0.0f)
+ pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
- pa->size /= 10.0f;
+ /* Get size (dimension) but considering scaling */
+ copy_v3_v3(cell_size_scaled, mds->cell_size);
+ mul_v3_v3(cell_size_scaled, ob->scale);
+ madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, cell_size_scaled, mds->res_min);
+ madd_v3fl_v3fl_v3fl_v3i(max, mds->p0, cell_size_scaled, mds->res_max);
+ sub_v3_v3v3(size, max, min);
- for (j = 0; j < 3; j++) {
- float wrf;
- gzread(gzf, &wrf, sizeof(wrf));
- pa->state.co[j] = wrf;
- // fprintf(stderr,"Rj%d ",j);
- }
- for (j = 0; j < 3; j++) {
- float wrf;
- gzread(gzf, &wrf, sizeof(wrf));
- pa->state.vel[j] = wrf;
- }
+ /* Biggest dimension will be used for upscaling */
+ max_size = MAX3(size[0] / (float)upres, size[1] / (float)upres, size[2] / (float)upres);
+
+ /* Set particle position */
+ pa->state.co[0] = posX;
+ pa->state.co[1] = posY;
+ pa->state.co[2] = posZ;
+
+ /* Normalize to unit cube around 0 */
+ pa->state.co[0] -= resX * 0.5f;
+ pa->state.co[1] -= resY * 0.5f;
+ pa->state.co[2] -= resZ * 0.5f;
+ mul_v3_fl(pa->state.co, mds->dx);
+
+ /* Match domain dimension / size */
+ pa->state.co[0] *= max_size / fabsf(ob->scale[0]);
+ pa->state.co[1] *= max_size / fabsf(ob->scale[1]);
+ pa->state.co[2] *= max_size / fabsf(ob->scale[2]);
+
+ /* Match domain scale */
+ mul_m4_v3(ob->obmat, pa->state.co);
+
+ // printf("pa->state.co[0]: %f, pa->state.co[1]: %f, pa->state.co[2]: %f\n", pa->state.co[0], pa->state.co[1], pa->state.co[2]);
+
+ /* Set particle velocity */
+ pa->state.vel[0] = velX;
+ pa->state.vel[1] = velY;
+ pa->state.vel[2] = velZ;
+ mul_v3_fl(pa->state.vel, mds->dx);
+
+ // printf("pa->state.vel[0]: %f, pa->state.vel[1]: %f, pa->state.vel[2]: %f\n", pa->state.vel[0], pa->state.vel[1], pa->state.vel[2]);
+ /* Set default angular velocity and particle rotation */
zero_v3(pa->state.ave);
unit_qt(pa->state.rot);
@@ -4208,46 +4323,19 @@ static void particles_fluid_step(ParticleSimulationData *sim,
pa->dietime = sim->scene->r.efra + 1;
pa->lifetime = sim->scene->r.efra;
pa->alive = PARS_ALIVE;
-# if 0
- if (a < 25) {
- fprintf(stderr,
- "FSPARTICLE debug set %s, a%d = %f,%f,%f, life=%f\n",
- filename,
- a,
- pa->co[0],
- pa->co[1],
- pa->co[2],
- pa->lifetime);
- }
-# endif
- }
- else {
- // skip...
- for (j = 0; j < 2 * 3 + 1; j++) {
- float wrf;
- gzread(gzf, &wrf, sizeof(wrf));
- }
+
+ /* Increasing particle settings pointer only for active particles */
+ pa++;
}
- fileParts++;
}
- gzclose(gzf);
-
- totpart = psys->totpart = activeParts;
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d\n",
- psys->totpart,
- activeParts,
- fileParts,
- readMask);
- // bad level call
- // XXX elbeemDebugOut(debugStrBuffer);
+ // printf("active parts: %d\n", activeParts);
+ totpart = psys->totpart = part->totpart = activeParts;
- } // fluid sim particles done
+ } // manta sim particles done
}
#else
UNUSED_VARS(use_render_params);
-#endif // WITH_MOD_FLUID
+#endif // WITH_MANTA
}
static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNUSED(cfra))
@@ -4628,128 +4716,124 @@ void particle_system_update(struct Depsgraph *depsgraph,
/* setup necessary physics type dependent additional data if it doesn't yet exist */
psys_prepare_physics(&sim);
- switch (part->type) {
- case PART_HAIR: {
- /* nothing to do so bail out early */
- if (psys->totpart == 0 && part->totpart == 0) {
- psys_free_path_cache(psys, NULL);
- free_hair(ob, psys, 0);
- psys->flag |= PSYS_HAIR_DONE;
- }
- /* (re-)create hair */
- else if (hair_needs_recalc(psys)) {
- float hcfra = 0.0f;
- int i, recalc = psys->recalc;
+ if (part->type & PART_HAIR) {
+ /* nothing to do so bail out early */
+ if (psys->totpart == 0 && part->totpart == 0) {
+ psys_free_path_cache(psys, NULL);
+ free_hair(ob, psys, 0);
+ psys->flag |= PSYS_HAIR_DONE;
+ }
+ /* (re-)create hair */
+ else if (hair_needs_recalc(psys)) {
+ float hcfra = 0.0f;
+ int i, recalc = psys->recalc;
- free_hair(ob, psys, 0);
+ free_hair(ob, psys, 0);
- if (psys_orig->edit && psys_orig->free_edit) {
- psys_orig->free_edit(psys_orig->edit);
- psys_orig->edit = NULL;
- psys_orig->free_edit = NULL;
- }
-
- /* first step is negative so particles get killed and reset */
- psys->cfra = 1.0f;
+ if (psys_orig->edit && psys_orig->free_edit) {
+ psys_orig->free_edit(psys_orig->edit);
+ psys_orig->edit = NULL;
+ psys_orig->free_edit = NULL;
+ }
- ParticleSettings *part_local = part;
- if ((part->flag & PART_HAIR_REGROW) == 0) {
- part_local = particle_settings_localize(part);
- psys->part = part_local;
- }
+ /* first step is negative so particles get killed and reset */
+ psys->cfra = 1.0f;
- for (i = 0; i <= part->hair_step; i++) {
- hcfra = 100.0f * (float)i / (float)psys->part->hair_step;
- if ((part->flag & PART_HAIR_REGROW) == 0) {
- BKE_animsys_evaluate_animdata(
- depsgraph, scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM);
- }
- system_step(&sim, hcfra, use_render_params);
- psys->cfra = hcfra;
- psys->recalc = 0;
- save_hair(&sim, hcfra);
- }
+ ParticleSettings *part_local = part;
+ if ((part->flag & PART_HAIR_REGROW) == 0) {
+ part_local = particle_settings_localize(part);
+ psys->part = part_local;
+ }
- if (part_local != part) {
- particle_settings_free_local(part_local);
- psys->part = part;
+ for (i = 0; i <= part->hair_step; i++) {
+ hcfra = 100.0f * (float)i / (float)psys->part->hair_step;
+ if ((part->flag & PART_HAIR_REGROW) == 0) {
+ BKE_animsys_evaluate_animdata(
+ depsgraph, scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM);
}
-
- psys->flag |= PSYS_HAIR_DONE;
- psys->recalc = recalc;
- }
- else if (psys->flag & PSYS_EDITED) {
- psys->flag |= PSYS_HAIR_DONE;
+ system_step(&sim, hcfra, use_render_params);
+ psys->cfra = hcfra;
+ psys->recalc = 0;
+ save_hair(&sim, hcfra);
}
- if (psys->flag & PSYS_HAIR_DONE) {
- hair_step(&sim, cfra, use_render_params);
+ if (part_local != part) {
+ particle_settings_free_local(part_local);
+ psys->part = part;
}
- break;
+
+ psys->flag |= PSYS_HAIR_DONE;
+ psys->recalc = recalc;
}
- case PART_FLUID: {
- particles_fluid_step(&sim, (int)cfra, use_render_params);
- break;
+ else if (psys->flag & PSYS_EDITED) {
+ psys->flag |= PSYS_HAIR_DONE;
}
- default: {
- switch (part->phystype) {
- case PART_PHYS_NO:
- case PART_PHYS_KEYED: {
- PARTICLE_P;
- float disp = psys_get_current_display_percentage(psys, use_render_params);
- bool free_unexisting = false;
-
- /* Particles without dynamics haven't been reset yet because they don't use pointcache */
- if (psys->recalc & ID_RECALC_PSYS_RESET) {
- psys_reset(psys, PSYS_RESET_ALL);
- }
- if (emit_particles(&sim, NULL, cfra) || (psys->recalc & ID_RECALC_PSYS_RESET)) {
- free_keyed_keys(psys);
- distribute_particles(&sim, part->from);
- initialize_all_particles(&sim);
- free_unexisting = true;
+ if (psys->flag & PSYS_HAIR_DONE) {
+ hair_step(&sim, cfra, use_render_params);
+ }
+ }
+ else if (part->type & (PART_MANTA_FLIP | PART_MANTA_BUBBLE | PART_MANTA_BUBBLE |
+ PART_MANTA_FOAM | PART_MANTA_TRACER)) {
+ particles_manta_step(&sim, (int)cfra, use_render_params);
+ }
+ else {
+ switch (part->phystype) {
+ case PART_PHYS_NO:
+ case PART_PHYS_KEYED: {
+ PARTICLE_P;
+ float disp = psys_get_current_display_percentage(psys, use_render_params);
+ bool free_unexisting = false;
+
+ /* Particles without dynamics haven't been reset yet because they don't use pointcache */
+ if (psys->recalc & ID_RECALC_PSYS_RESET) {
+ psys_reset(psys, PSYS_RESET_ALL);
+ }
- /* flag for possible explode modifiers after this system */
- sim.psmd->flag |= eParticleSystemFlag_Pars;
- }
+ if (emit_particles(&sim, NULL, cfra) || (psys->recalc & ID_RECALC_PSYS_RESET)) {
+ free_keyed_keys(psys);
+ distribute_particles(&sim, part->from);
+ initialize_all_particles(&sim);
+ free_unexisting = true;
- LOOP_EXISTING_PARTICLES
- {
- pa->size = part->size;
- if (part->randsize > 0.0f) {
- pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
- }
-
- reset_particle(&sim, pa, 0.0, cfra);
-
- if (psys_frand(psys, p) > disp) {
- pa->flag |= PARS_NO_DISP;
- }
- else {
- pa->flag &= ~PARS_NO_DISP;
- }
- }
+ /* flag for possible explode modifiers after this system */
+ sim.psmd->flag |= eParticleSystemFlag_Pars;
+ }
- /* free unexisting after resetting particles */
- if (free_unexisting) {
- free_unexisting_particles(&sim);
+ LOOP_EXISTING_PARTICLES
+ {
+ pa->size = part->size;
+ if (part->randsize > 0.0f) {
+ pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
}
- if (part->phystype == PART_PHYS_KEYED) {
- psys_count_keyed_targets(&sim);
- set_keyed_keys(&sim);
- psys_update_path_cache(&sim, (int)cfra, use_render_params);
+ reset_particle(&sim, pa, 0.0, cfra);
+
+ if (psys_frand(psys, p) > disp) {
+ pa->flag |= PARS_NO_DISP;
+ }
+ else {
+ pa->flag &= ~PARS_NO_DISP;
}
- break;
}
- default: {
- /* the main dynamic particle system step */
- system_step(&sim, cfra, use_render_params);
- break;
+
+ /* free unexisting after resetting particles */
+ if (free_unexisting) {
+ free_unexisting_particles(&sim);
}
+
+ if (part->phystype == PART_PHYS_KEYED) {
+ psys_count_keyed_targets(&sim);
+ set_keyed_keys(&sim);
+ psys_update_path_cache(&sim, (int)cfra, use_render_params);
+ }
+ break;
+ }
+ default: {
+ /* the main dynamic particle system step */
+ system_step(&sim, cfra, use_render_params);
+ break;
}
- break;
}
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index b577efd2a22..ff51c6f5f19 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -40,7 +40,7 @@
#include "DNA_particle_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -64,7 +64,7 @@
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
-#include "BKE_smoke.h"
+#include "BKE_manta.h"
#include "BKE_softbody.h"
#include "BIK_api.h"
@@ -591,11 +591,11 @@ static void ptcache_cloth_error(void *cloth_v, const char *message)
/* Smoke functions */
static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
+ MantaModifierData *mmd = (MantaModifierData *)smoke_v;
+ MantaDomainSettings *mds = mmd->domain;
- if (sds->fluid) {
- return sds->base_res[0] * sds->base_res[1] * sds->base_res[2];
+ if (mds->fluid) {
+ return mds->base_res[0] * mds->base_res[1] * mds->base_res[2];
}
else {
return 0;
@@ -604,28 +604,28 @@ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
static void ptcache_smoke_error(void *smoke_v, const char *message)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- modifier_setError(&smd->modifier, "%s", message);
+ MantaModifierData *mmd = (MantaModifierData *)smoke_v;
+ modifier_setError(&mmd->modifier, "%s", message);
}
# define SMOKE_CACHE_VERSION "1.04"
static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
+ MantaModifierData *mmd = (MantaModifierData *)smoke_v;
+ MantaDomainSettings *mds = mmd->domain;
int ret = 0;
- int fluid_fields = BKE_smoke_get_data_flags(sds);
+ int fluid_fields = BKE_manta_get_data_flags(mds);
/* version header */
ptcache_file_write(pf, SMOKE_CACHE_VERSION, 4, sizeof(char));
ptcache_file_write(pf, &fluid_fields, 1, sizeof(int));
- ptcache_file_write(pf, &sds->active_fields, 1, sizeof(int));
- ptcache_file_write(pf, &sds->res, 3, sizeof(int));
- ptcache_file_write(pf, &sds->dx, 1, sizeof(float));
+ ptcache_file_write(pf, &mds->active_fields, 1, sizeof(int));
+ ptcache_file_write(pf, &mds->res, 3, sizeof(int));
+ ptcache_file_write(pf, &mds->dx, 1, sizeof(float));
- if (sds->fluid) {
- size_t res = sds->res[0] * sds->res[1] * sds->res[2];
+ if (mds->fluid) {
+ size_t res = mds->res[0] * mds->res[1] * mds->res[2];
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
unsigned int in_len = sizeof(float) * (unsigned int)res;
@@ -633,11 +633,11 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
"pointcache_lzo_buffer");
// int mode = res >= 1000000 ? 2 : 1;
int mode = 1; // light
- if (sds->cache_comp == SM_CACHE_HEAVY) {
+ if (mds->cache_comp == SM_CACHE_HEAVY) {
mode = 2; // heavy
}
- smoke_export(sds->fluid,
+ smoke_export(mds->fluid,
&dt,
&dx,
&dens,
@@ -652,20 +652,21 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
&r,
&g,
&b,
- &obstacles);
+ &obstacles,
+ NULL);
- ptcache_file_compressed_write(pf, (unsigned char *)sds->shadow, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)mds->shadow, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len, out, mode);
- if (fluid_fields & SM_ACTIVE_HEAT) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
ptcache_file_compressed_write(pf, (unsigned char *)heat, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)heatold, in_len, out, mode);
}
- if (fluid_fields & SM_ACTIVE_FIRE) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)react, in_len, out, mode);
}
- if (fluid_fields & SM_ACTIVE_COLORS) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
ptcache_file_compressed_write(pf, (unsigned char *)r, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)g, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)b, in_len, out, mode);
@@ -676,52 +677,52 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
ptcache_file_compressed_write(pf, (unsigned char *)obstacles, (unsigned int)res, out, mode);
ptcache_file_write(pf, &dt, 1, sizeof(float));
ptcache_file_write(pf, &dx, 1, sizeof(float));
- ptcache_file_write(pf, &sds->p0, 3, sizeof(float));
- ptcache_file_write(pf, &sds->p1, 3, sizeof(float));
- ptcache_file_write(pf, &sds->dp0, 3, sizeof(float));
- ptcache_file_write(pf, &sds->shift, 3, sizeof(int));
- ptcache_file_write(pf, &sds->obj_shift_f, 3, sizeof(float));
- ptcache_file_write(pf, &sds->obmat, 16, sizeof(float));
- ptcache_file_write(pf, &sds->base_res, 3, sizeof(int));
- ptcache_file_write(pf, &sds->res_min, 3, sizeof(int));
- ptcache_file_write(pf, &sds->res_max, 3, sizeof(int));
- ptcache_file_write(pf, &sds->active_color, 3, sizeof(float));
+ ptcache_file_write(pf, &mds->p0, 3, sizeof(float));
+ ptcache_file_write(pf, &mds->p1, 3, sizeof(float));
+ ptcache_file_write(pf, &mds->dp0, 3, sizeof(float));
+ ptcache_file_write(pf, &mds->shift, 3, sizeof(int));
+ ptcache_file_write(pf, &mds->obj_shift_f, 3, sizeof(float));
+ ptcache_file_write(pf, &mds->obmat, 16, sizeof(float));
+ ptcache_file_write(pf, &mds->base_res, 3, sizeof(int));
+ ptcache_file_write(pf, &mds->res_min, 3, sizeof(int));
+ ptcache_file_write(pf, &mds->res_max, 3, sizeof(int));
+ ptcache_file_write(pf, &mds->active_color, 3, sizeof(float));
MEM_freeN(out);
ret = 1;
}
- if (sds->wt) {
+ if (mds->wt) {
int res_big_array[3];
int res_big;
- int res = sds->res[0] * sds->res[1] * sds->res[2];
+ int res = mds->res[0] * mds->res[1] * mds->res[2];
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
unsigned int in_len = sizeof(float) * (unsigned int)res;
unsigned int in_len_big;
unsigned char *out;
int mode;
- smoke_turbulence_get_res(sds->wt, res_big_array);
+ smoke_turbulence_get_res(mds->wt, res_big_array);
res_big = res_big_array[0] * res_big_array[1] * res_big_array[2];
// mode = res_big >= 1000000 ? 2 : 1;
mode = 1; // light
- if (sds->cache_high_comp == SM_CACHE_HEAVY) {
+ if (mds->cache_high_comp == SM_CACHE_HEAVY) {
mode = 2; // heavy
}
in_len_big = sizeof(float) * (unsigned int)res_big;
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+ smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len_big), "pointcache_lzo_buffer");
ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len_big, out, mode);
- if (fluid_fields & SM_ACTIVE_FIRE) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)react, in_len_big, out, mode);
}
- if (fluid_fields & SM_ACTIVE_COLORS) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
ptcache_file_compressed_write(pf, (unsigned char *)r, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)g, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)b, in_len_big, out, mode);
@@ -743,24 +744,24 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
/* read old smoke cache from 2.64 */
static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
+ MantaModifierData *mmd = (MantaModifierData *)smoke_v;
+ MantaDomainSettings *mds = mmd->domain;
- if (sds->fluid) {
- const size_t res = sds->res[0] * sds->res[1] * sds->res[2];
+ if (mds->fluid) {
+ const size_t res = mds->res[0] * mds->res[1] * mds->res[2];
const unsigned int out_len = (unsigned int)res * sizeof(float);
float dt, dx, *dens, *heat, *heatold, *vx, *vy, *vz;
unsigned char *obstacles;
float *tmp_array = MEM_callocN(out_len, "Smoke old cache tmp");
- int fluid_fields = BKE_smoke_get_data_flags(sds);
+ int fluid_fields = BKE_manta_get_data_flags(mds);
/* Part part of the new cache header */
- sds->active_color[0] = 0.7f;
- sds->active_color[1] = 0.7f;
- sds->active_color[2] = 0.7f;
+ mds->active_color[0] = 0.7f;
+ mds->active_color[1] = 0.7f;
+ mds->active_color[2] = 0.7f;
- smoke_export(sds->fluid,
+ smoke_export(mds->fluid,
&dt,
&dx,
&dens,
@@ -775,13 +776,14 @@ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v)
NULL,
NULL,
NULL,
- &obstacles);
+ &obstacles,
+ NULL);
- ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)mds->shadow, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)tmp_array, out_len);
- if (fluid_fields & SM_ACTIVE_HEAT) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
ptcache_file_compressed_read(pf, (unsigned char *)heat, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)heatold, out_len);
}
@@ -801,19 +803,19 @@ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v)
MEM_freeN(tmp_array);
- if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
+ if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && mds->wt) {
int res_big, res_big_array[3];
float *tcu, *tcv, *tcw;
unsigned int out_len_big;
unsigned char *tmp_array_big;
- smoke_turbulence_get_res(sds->wt, res_big_array);
+ smoke_turbulence_get_res(mds->wt, res_big_array);
res_big = res_big_array[0] * res_big_array[1] * res_big_array[2];
out_len_big = sizeof(float) * (unsigned int)res_big;
tmp_array_big = MEM_callocN(out_len_big, "Smoke old cache tmp");
smoke_turbulence_export(
- sds->wt, &dens, NULL, NULL, NULL, NULL, NULL, NULL, &tcu, &tcv, &tcw);
+ mds->wt, &dens, NULL, NULL, NULL, NULL, NULL, NULL, &tcu, &tcv, &tcw);
ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char *)tmp_array_big, out_len_big);
@@ -831,12 +833,12 @@ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v)
static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
+ MantaModifierData *mmd = (MantaModifierData *)smoke_v;
+ MantaDomainSettings *mds = mmd->domain;
char version[4];
int ch_res[3];
float ch_dx;
- int fluid_fields = BKE_smoke_get_data_flags(sds);
+ int fluid_fields = BKE_manta_get_data_flags(mds);
int cache_fields = 0;
int active_fields = 0;
int reallocate = 0;
@@ -856,8 +858,8 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
ptcache_file_read(pf, &ch_dx, 1, sizeof(float));
/* check if resolution has changed */
- if (sds->res[0] != ch_res[0] || sds->res[1] != ch_res[1] || sds->res[2] != ch_res[2]) {
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ if (mds->res[0] != ch_res[0] || mds->res[1] != ch_res[1] || mds->res[2] != ch_res[2]) {
+ if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
reallocate = 1;
}
else {
@@ -865,29 +867,26 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
}
}
/* check if active fields have changed */
- if (fluid_fields != cache_fields || active_fields != sds->active_fields) {
+ if (fluid_fields != cache_fields || active_fields != mds->active_fields) {
reallocate = 1;
}
/* reallocate fluid if needed*/
if (reallocate) {
- sds->active_fields = active_fields | cache_fields;
- BKE_smoke_reallocate_fluid(sds, ch_dx, ch_res, 1);
- sds->dx = ch_dx;
- copy_v3_v3_int(sds->res, ch_res);
- sds->total_cells = ch_res[0] * ch_res[1] * ch_res[2];
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, ch_dx, ch_res, 1);
- }
+ mds->active_fields = active_fields | cache_fields;
+ BKE_manta_reallocate_fluid(mds, ch_res, 1);
+ mds->dx = ch_dx;
+ copy_v3_v3_int(mds->res, ch_res);
+ mds->total_cells = ch_res[0] * ch_res[1] * ch_res[2];
}
- if (sds->fluid) {
- size_t res = sds->res[0] * sds->res[1] * sds->res[2];
+ if (mds->fluid) {
+ size_t res = mds->res[0] * mds->res[1] * mds->res[2];
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
unsigned int out_len = (unsigned int)res * sizeof(float);
- smoke_export(sds->fluid,
+ smoke_export(mds->fluid,
&dt,
&dx,
&dens,
@@ -902,20 +901,21 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
&r,
&g,
&b,
- &obstacles);
+ &obstacles,
+ NULL);
- ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)mds->shadow, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len);
- if (cache_fields & SM_ACTIVE_HEAT) {
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
ptcache_file_compressed_read(pf, (unsigned char *)heat, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)heatold, out_len);
}
- if (cache_fields & SM_ACTIVE_FIRE) {
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
ptcache_file_compressed_read(pf, (unsigned char *)flame, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)fuel, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)react, out_len);
}
- if (cache_fields & SM_ACTIVE_COLORS) {
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
ptcache_file_compressed_read(pf, (unsigned char *)r, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)g, out_len);
ptcache_file_compressed_read(pf, (unsigned char *)b, out_len);
@@ -926,38 +926,38 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
ptcache_file_compressed_read(pf, (unsigned char *)obstacles, (unsigned int)res);
ptcache_file_read(pf, &dt, 1, sizeof(float));
ptcache_file_read(pf, &dx, 1, sizeof(float));
- ptcache_file_read(pf, &sds->p0, 3, sizeof(float));
- ptcache_file_read(pf, &sds->p1, 3, sizeof(float));
- ptcache_file_read(pf, &sds->dp0, 3, sizeof(float));
- ptcache_file_read(pf, &sds->shift, 3, sizeof(int));
- ptcache_file_read(pf, &sds->obj_shift_f, 3, sizeof(float));
- ptcache_file_read(pf, &sds->obmat, 16, sizeof(float));
- ptcache_file_read(pf, &sds->base_res, 3, sizeof(int));
- ptcache_file_read(pf, &sds->res_min, 3, sizeof(int));
- ptcache_file_read(pf, &sds->res_max, 3, sizeof(int));
- ptcache_file_read(pf, &sds->active_color, 3, sizeof(float));
- }
-
- if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
- int res = sds->res[0] * sds->res[1] * sds->res[2];
+ ptcache_file_read(pf, &mds->p0, 3, sizeof(float));
+ ptcache_file_read(pf, &mds->p1, 3, sizeof(float));
+ ptcache_file_read(pf, &mds->dp0, 3, sizeof(float));
+ ptcache_file_read(pf, &mds->shift, 3, sizeof(int));
+ ptcache_file_read(pf, &mds->obj_shift_f, 3, sizeof(float));
+ ptcache_file_read(pf, &mds->obmat, 16, sizeof(float));
+ ptcache_file_read(pf, &mds->base_res, 3, sizeof(int));
+ ptcache_file_read(pf, &mds->res_min, 3, sizeof(int));
+ ptcache_file_read(pf, &mds->res_max, 3, sizeof(int));
+ ptcache_file_read(pf, &mds->active_color, 3, sizeof(float));
+ }
+
+ if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && mds->wt) {
+ int res = mds->res[0] * mds->res[1] * mds->res[2];
int res_big, res_big_array[3];
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
unsigned int out_len = sizeof(float) * (unsigned int)res;
unsigned int out_len_big;
- smoke_turbulence_get_res(sds->wt, res_big_array);
+ smoke_turbulence_get_res(mds->wt, res_big_array);
res_big = res_big_array[0] * res_big_array[1] * res_big_array[2];
out_len_big = sizeof(float) * (unsigned int)res_big;
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+ smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len_big);
- if (cache_fields & SM_ACTIVE_FIRE) {
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
ptcache_file_compressed_read(pf, (unsigned char *)flame, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char *)fuel, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char *)react, out_len_big);
}
- if (cache_fields & SM_ACTIVE_COLORS) {
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
ptcache_file_compressed_read(pf, (unsigned char *)r, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char *)g, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char *)b, out_len_big);
@@ -984,101 +984,101 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
* with `vs` = voxel size, and `px, py, pz`,
* the min position of the domain's bounding box.
*/
-static void compute_fluid_matrices(SmokeDomainSettings *sds)
+static void compute_fluid_matrices(MantaDomainSettings *mds)
{
float bbox_min[3];
- copy_v3_v3(bbox_min, sds->p0);
+ copy_v3_v3(bbox_min, mds->p0);
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- bbox_min[0] += (sds->cell_size[0] * (float)sds->res_min[0]);
- bbox_min[1] += (sds->cell_size[1] * (float)sds->res_min[1]);
- bbox_min[2] += (sds->cell_size[2] * (float)sds->res_min[2]);
- add_v3_v3(bbox_min, sds->obj_shift_f);
+ if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
+ bbox_min[0] += (mds->cell_size[0] * (float)mds->res_min[0]);
+ bbox_min[1] += (mds->cell_size[1] * (float)mds->res_min[1]);
+ bbox_min[2] += (mds->cell_size[2] * (float)mds->res_min[2]);
+ add_v3_v3(bbox_min, mds->obj_shift_f);
}
/* construct low res matrix */
- size_to_mat4(sds->fluidmat, sds->cell_size);
- copy_v3_v3(sds->fluidmat[3], bbox_min);
+ size_to_mat4(mds->fluidmat, mds->cell_size);
+ copy_v3_v3(mds->fluidmat[3], bbox_min);
/* The smoke simulator stores voxels cell-centered, whilst VDB is node
* centered, so we offset the matrix by half a voxel to compensate. */
- madd_v3_v3fl(sds->fluidmat[3], sds->cell_size, 0.5f);
+ madd_v3_v3fl(mds->fluidmat[3], mds->cell_size, 0.5f);
- mul_m4_m4m4(sds->fluidmat, sds->obmat, sds->fluidmat);
+ mul_m4_m4m4(mds->fluidmat, mds->obmat, mds->fluidmat);
- if (sds->wt) {
+ if (mds->wt) {
float voxel_size_high[3];
/* construct high res matrix */
- mul_v3_v3fl(voxel_size_high, sds->cell_size, 1.0f / (float)(sds->amplify + 1));
- size_to_mat4(sds->fluidmat_wt, voxel_size_high);
- copy_v3_v3(sds->fluidmat_wt[3], bbox_min);
+ mul_v3_v3fl(voxel_size_high, mds->cell_size, 1.0f / (float)(mds->amplify + 1));
+ size_to_mat4(mds->fluidmat_wt, voxel_size_high);
+ copy_v3_v3(mds->fluidmat_wt[3], bbox_min);
/* Same here, add half a voxel to adjust the position of the fluid. */
- madd_v3_v3fl(sds->fluidmat_wt[3], voxel_size_high, 0.5f);
+ madd_v3_v3fl(mds->fluidmat_wt[3], voxel_size_high, 0.5f);
- mul_m4_m4m4(sds->fluidmat_wt, sds->obmat, sds->fluidmat_wt);
+ mul_m4_m4m4(mds->fluidmat_wt, mds->obmat, mds->fluidmat_wt);
}
}
static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
-
- OpenVDBWriter_set_flags(writer, sds->openvdb_comp, (sds->data_depth == 16));
-
- OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", sds->active_fields);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", sds->res);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", sds->res_min);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", sds->res_max);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", sds->base_res);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", sds->p0);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", sds->p1);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", sds->dp0);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", sds->shift);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", sds->obj_shift_f);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", sds->active_color);
- OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", sds->obmat);
-
- int fluid_fields = BKE_smoke_get_data_flags(sds);
+ MantaModifierData *mmd = (MantaModifierData *)smoke_v;
+ MantaDomainSettings *mds = mmd->domain;
+
+ OpenVDBWriter_set_flags(writer, mds->openvdb_comp, (mds->data_depth == 16));
+
+ OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", mds->active_fields);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", mds->res);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", mds->res_min);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", mds->res_max);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", mds->base_res);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", mds->p0);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", mds->p1);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", mds->dp0);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", mds->shift);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", mds->obj_shift_f);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", mds->active_color);
+ OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", mds->obmat);
+
+ int fluid_fields = BKE_manta_get_data_flags(mds);
struct OpenVDBFloatGrid *clip_grid = NULL;
- compute_fluid_matrices(sds);
+ compute_fluid_matrices(mds);
OpenVDBWriter_add_meta_int(writer, "blender/smoke/fluid_fields", fluid_fields);
- if (sds->wt) {
+ if (mds->wt) {
struct OpenVDBFloatGrid *wt_density_grid;
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+ smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
wt_density_grid = OpenVDB_export_grid_fl(
- writer, "density", dens, sds->res_wt, sds->fluidmat_wt, sds->clipping, NULL);
+ writer, "density", dens, mds->res_wt, mds->fluidmat_wt, mds->clipping, NULL);
clip_grid = wt_density_grid;
- if (fluid_fields & SM_ACTIVE_FIRE) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
OpenVDB_export_grid_fl(
- writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
+ writer, "flame", flame, mds->res_wt, mds->fluidmat_wt, mds->clipping, wt_density_grid);
OpenVDB_export_grid_fl(
- writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
+ writer, "fuel", fuel, mds->res_wt, mds->fluidmat_wt, mds->clipping, wt_density_grid);
OpenVDB_export_grid_fl(
- writer, "react", react, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
+ writer, "react", react, mds->res_wt, mds->fluidmat_wt, mds->clipping, wt_density_grid);
}
- if (fluid_fields & SM_ACTIVE_COLORS) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
OpenVDB_export_grid_vec(writer,
"color",
r,
g,
b,
- sds->res_wt,
- sds->fluidmat_wt,
+ mds->res_wt,
+ mds->fluidmat_wt,
VEC_INVARIANT,
true,
- sds->clipping,
+ mds->clipping,
wt_density_grid);
}
@@ -1087,20 +1087,20 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke
tcu,
tcv,
tcw,
- sds->res,
- sds->fluidmat,
+ mds->res,
+ mds->fluidmat,
VEC_INVARIANT,
false,
- sds->clipping,
+ mds->clipping,
wt_density_grid);
}
- if (sds->fluid) {
+ if (mds->fluid) {
struct OpenVDBFloatGrid *density_grid;
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
- smoke_export(sds->fluid,
+ smoke_export(mds->fluid,
&dt,
&dx,
&dens,
@@ -1115,50 +1115,51 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke
&r,
&g,
&b,
- &obstacles);
+ &obstacles,
+ NULL);
OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dx", dx);
OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dt", dt);
- const char *name = (!sds->wt) ? "density" : "density_low";
+ const char *name = (!mds->wt) ? "density" : "density_low";
density_grid = OpenVDB_export_grid_fl(
- writer, name, dens, sds->res, sds->fluidmat, sds->clipping, NULL);
- clip_grid = sds->wt ? clip_grid : density_grid;
+ writer, name, dens, mds->res, mds->fluidmat, mds->clipping, NULL);
+ clip_grid = mds->wt ? clip_grid : density_grid;
OpenVDB_export_grid_fl(
- writer, "shadow", sds->shadow, sds->res, sds->fluidmat, sds->clipping, NULL);
+ writer, "shadow", mds->shadow, mds->res, mds->fluidmat, mds->clipping, NULL);
- if (fluid_fields & SM_ACTIVE_HEAT) {
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
OpenVDB_export_grid_fl(
- writer, "heat", heat, sds->res, sds->fluidmat, sds->clipping, clip_grid);
+ writer, "heat", heat, mds->res, mds->fluidmat, mds->clipping, clip_grid);
OpenVDB_export_grid_fl(
- writer, "heat_old", heatold, sds->res, sds->fluidmat, sds->clipping, clip_grid);
+ writer, "heat_old", heatold, mds->res, mds->fluidmat, mds->clipping, clip_grid);
}
- if (fluid_fields & SM_ACTIVE_FIRE) {
- name = (!sds->wt) ? "flame" : "flame_low";
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ name = (!mds->wt) ? "flame" : "flame_low";
OpenVDB_export_grid_fl(
- writer, name, flame, sds->res, sds->fluidmat, sds->clipping, density_grid);
- name = (!sds->wt) ? "fuel" : "fuel_low";
+ writer, name, flame, mds->res, mds->fluidmat, mds->clipping, density_grid);
+ name = (!mds->wt) ? "fuel" : "fuel_low";
OpenVDB_export_grid_fl(
- writer, name, fuel, sds->res, sds->fluidmat, sds->clipping, density_grid);
- name = (!sds->wt) ? "react" : "react_low";
+ writer, name, fuel, mds->res, mds->fluidmat, mds->clipping, density_grid);
+ name = (!mds->wt) ? "react" : "react_low";
OpenVDB_export_grid_fl(
- writer, name, react, sds->res, sds->fluidmat, sds->clipping, density_grid);
+ writer, name, react, mds->res, mds->fluidmat, mds->clipping, density_grid);
}
- if (fluid_fields & SM_ACTIVE_COLORS) {
- name = (!sds->wt) ? "color" : "color_low";
+ if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
+ name = (!mds->wt) ? "color" : "color_low";
OpenVDB_export_grid_vec(writer,
name,
r,
g,
b,
- sds->res,
- sds->fluidmat,
+ mds->res,
+ mds->fluidmat,
VEC_INVARIANT,
true,
- sds->clipping,
+ mds->clipping,
density_grid);
}
@@ -1167,14 +1168,14 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke
vx,
vy,
vz,
- sds->res,
- sds->fluidmat,
+ mds->res,
+ mds->fluidmat,
VEC_CONTRAVARIANT_RELATIVE,
false,
- sds->clipping,
+ mds->clipping,
clip_grid);
OpenVDB_export_grid_ch(
- writer, "obstacles", obstacles, sds->res, sds->fluidmat, sds->clipping, NULL);
+ writer, "obstacles", obstacles, mds->res, mds->fluidmat, mds->clipping, NULL);
}
return 1;
@@ -1182,38 +1183,38 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke
static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
+ MantaModifierData *mmd = (MantaModifierData *)smoke_v;
- if (!smd) {
+ if (!mmd) {
return 0;
}
- SmokeDomainSettings *sds = smd->domain;
+ MantaDomainSettings *mds = mmd->domain;
- int fluid_fields = BKE_smoke_get_data_flags(sds);
+ int fluid_fields = BKE_manta_get_data_flags(mds);
int active_fields, cache_fields = 0;
int cache_res[3];
float cache_dx;
bool reallocate = false;
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", sds->res_min);
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", sds->res_max);
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", sds->base_res);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", sds->p0);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", sds->p1);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", sds->dp0);
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", sds->shift);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", sds->obj_shift_f);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", sds->active_color);
- OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", sds->obmat);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", mds->res_min);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", mds->res_max);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", mds->base_res);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", mds->p0);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", mds->p1);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", mds->dp0);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", mds->shift);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", mds->obj_shift_f);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", mds->active_color);
+ OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", mds->obmat);
OpenVDBReader_get_meta_int(reader, "blender/smoke/fluid_fields", &cache_fields);
OpenVDBReader_get_meta_int(reader, "blender/smoke/active_fields", &active_fields);
OpenVDBReader_get_meta_fl(reader, "blender/smoke/dx", &cache_dx);
OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/resolution", cache_res);
/* check if resolution has changed */
- if (sds->res[0] != cache_res[0] || sds->res[1] != cache_res[1] || sds->res[2] != cache_res[2]) {
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ if (mds->res[0] != cache_res[0] || mds->res[1] != cache_res[1] || mds->res[2] != cache_res[2]) {
+ if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
reallocate = true;
}
else {
@@ -1222,28 +1223,24 @@ static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_
}
/* check if active fields have changed */
- if ((fluid_fields != cache_fields) || (active_fields != sds->active_fields)) {
+ if ((fluid_fields != cache_fields) || (active_fields != mds->active_fields)) {
reallocate = true;
}
/* reallocate fluid if needed*/
if (reallocate) {
- sds->active_fields = active_fields | cache_fields;
- BKE_smoke_reallocate_fluid(sds, cache_dx, cache_res, 1);
- sds->dx = cache_dx;
- copy_v3_v3_int(sds->res, cache_res);
- sds->total_cells = cache_res[0] * cache_res[1] * cache_res[2];
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, cache_dx, cache_res, 1);
- }
+ mds->active_fields = active_fields | cache_fields;
+ BKE_manta_reallocate_fluid(mds, cache_dx, cache_res, 1);
+ mds->dx = cache_dx;
+ copy_v3_v3_int(mds->res, cache_res);
+ mds->total_cells = cache_res[0] * cache_res[1] * cache_res[2];
}
- if (sds->fluid) {
+ if (mds->fluid) {
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
- smoke_export(sds->fluid,
+ smoke_export(mds->fluid,
&dt,
&dx,
&dens,
@@ -1258,56 +1255,57 @@ static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_
&r,
&g,
&b,
- &obstacles);
+ &obstacles,
+ NULL);
OpenVDBReader_get_meta_fl(reader, "blender/smoke/dt", &dt);
- OpenVDB_import_grid_fl(reader, "shadow", &sds->shadow, sds->res);
+ OpenVDB_import_grid_fl(reader, "shadow", &mds->shadow, mds->res);
- const char *name = (!sds->wt) ? "density" : "density_low";
- OpenVDB_import_grid_fl(reader, name, &dens, sds->res);
+ const char *name = (!mds->wt) ? "density" : "density_low";
+ OpenVDB_import_grid_fl(reader, name, &dens, mds->res);
- if (cache_fields & SM_ACTIVE_HEAT) {
- OpenVDB_import_grid_fl(reader, "heat", &heat, sds->res);
- OpenVDB_import_grid_fl(reader, "heat_old", &heatold, sds->res);
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
+ OpenVDB_import_grid_fl(reader, "heat", &heat, mds->res);
+ OpenVDB_import_grid_fl(reader, "heat_old", &heatold, mds->res);
}
- if (cache_fields & SM_ACTIVE_FIRE) {
- name = (!sds->wt) ? "flame" : "flame_low";
- OpenVDB_import_grid_fl(reader, name, &flame, sds->res);
- name = (!sds->wt) ? "fuel" : "fuel_low";
- OpenVDB_import_grid_fl(reader, name, &fuel, sds->res);
- name = (!sds->wt) ? "react" : "react_low";
- OpenVDB_import_grid_fl(reader, name, &react, sds->res);
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ name = (!mds->wt) ? "flame" : "flame_low";
+ OpenVDB_import_grid_fl(reader, name, &flame, mds->res);
+ name = (!mds->wt) ? "fuel" : "fuel_low";
+ OpenVDB_import_grid_fl(reader, name, &fuel, mds->res);
+ name = (!mds->wt) ? "react" : "react_low";
+ OpenVDB_import_grid_fl(reader, name, &react, mds->res);
}
- if (cache_fields & SM_ACTIVE_COLORS) {
- name = (!sds->wt) ? "color" : "color_low";
- OpenVDB_import_grid_vec(reader, name, &r, &g, &b, sds->res);
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
+ name = (!mds->wt) ? "color" : "color_low";
+ OpenVDB_import_grid_vec(reader, name, &r, &g, &b, mds->res);
}
- OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, sds->res);
- OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, sds->res);
+ OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, mds->res);
+ OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, mds->res);
}
- if (sds->wt) {
+ if (mds->wt) {
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+ smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
- OpenVDB_import_grid_fl(reader, "density", &dens, sds->res_wt);
+ OpenVDB_import_grid_fl(reader, "density", &dens, mds->res_wt);
- if (cache_fields & SM_ACTIVE_FIRE) {
- OpenVDB_import_grid_fl(reader, "flame", &flame, sds->res_wt);
- OpenVDB_import_grid_fl(reader, "fuel", &fuel, sds->res_wt);
- OpenVDB_import_grid_fl(reader, "react", &react, sds->res_wt);
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ OpenVDB_import_grid_fl(reader, "flame", &flame, mds->res_wt);
+ OpenVDB_import_grid_fl(reader, "fuel", &fuel, mds->res_wt);
+ OpenVDB_import_grid_fl(reader, "react", &react, mds->res_wt);
}
- if (cache_fields & SM_ACTIVE_COLORS) {
- OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, sds->res_wt);
+ if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
+ OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, mds->res_wt);
}
- OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, sds->res);
+ OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, mds->res);
}
OpenVDBReader_free(reader);
@@ -1698,21 +1696,21 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl
pid->max_step = 1;
pid->file_type = PTCACHE_FILE_PTCACHE;
}
-void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd)
+void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct MantaModifierData *mmd)
{
- SmokeDomainSettings *sds = smd->domain;
+ MantaDomainSettings *mds = mmd->domain;
memset(pid, 0, sizeof(PTCacheID));
pid->ob = ob;
- pid->calldata = smd;
+ pid->calldata = mmd;
pid->type = PTCACHE_TYPE_SMOKE_DOMAIN;
- pid->stack_index = sds->point_cache[0]->index;
+ pid->stack_index = mds->point_cache[0]->index;
- pid->cache = sds->point_cache[0];
- pid->cache_ptr = &(sds->point_cache[0]);
- pid->ptcaches = &(sds->ptcaches[0]);
+ pid->cache = mds->point_cache[0];
+ pid->cache_ptr = &(mds->point_cache[0]);
+ pid->ptcaches = &(mds->ptcaches[0]);
pid->totpoint = pid->totwrite = ptcache_smoke_totpoint;
pid->error = ptcache_smoke_error;
@@ -1737,16 +1735,19 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo
pid->data_types = 0;
pid->info_types = 0;
- if (sds->fluid) {
+ if (mds->fluid) {
pid->data_types |= (1 << BPHYS_DATA_SMOKE_LOW);
- }
- if (sds->wt) {
- pid->data_types |= (1 << BPHYS_DATA_SMOKE_HIGH);
+ // (sebbas): Option deprecated in manta cache
+ // if (mds->wt) {
+ // pid->data_types |= (1<<BPHYS_DATA_SMOKE_HIGH);
+ // }
}
pid->default_step = 1;
pid->max_step = 1;
- pid->file_type = smd->domain->cache_file_format;
+
+ // (sebbas): Option deprecated in manta cache
+ // pid->file_type = mmd->domain->cache_file_format;
}
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSurface *surface)
@@ -1904,10 +1905,10 @@ static bool foreach_object_modifier_ptcache(Object *object,
return false;
}
}
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- BKE_ptcache_id_from_smoke(&pid, object, (SmokeModifierData *)md);
+ else if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ if (mmd->type & MOD_MANTA_TYPE_DOMAIN) {
+ BKE_ptcache_id_from_smoke(&pid, object, (MantaModifierData *)md);
if (!callback(&pid, callback_user_data)) {
return false;
}
@@ -3738,10 +3739,10 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData *)md);
reset |= BKE_ptcache_id_reset(scene, &pid, mode);
}
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- BKE_ptcache_id_from_smoke(&pid, ob, (SmokeModifierData *)md);
+ if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ if (mmd->type & MOD_MANTA_TYPE_DOMAIN) {
+ BKE_ptcache_id_from_smoke(&pid, ob, (MantaModifierData *)md);
reset |= BKE_ptcache_id_reset(scene, &pid, mode);
}
}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
deleted file mode 100644
index bb8fd18ea58..00000000000
--- a/source/blender/blenkernel/intern/smoke.c
+++ /dev/null
@@ -1,3658 +0,0 @@
-/*
- * 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) Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup bke
- */
-
-/* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
-
-#include "MEM_guardedalloc.h"
-
-#include <float.h>
-#include <math.h>
-#include <stdio.h>
-#include <string.h> /* memset */
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_kdopbvh.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_customdata_types.h"
-#include "DNA_light_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_particle_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
-
-#include "BKE_appdir.h"
-#include "BKE_animsys.h"
-#include "BKE_armature.h"
-#include "BKE_bvhutils.h"
-#include "BKE_collision.h"
-#include "BKE_colortools.h"
-#include "BKE_constraint.h"
-#include "BKE_customdata.h"
-#include "BKE_deform.h"
-#include "BKE_effect.h"
-#include "BKE_library.h"
-#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
-#include "BKE_modifier.h"
-#include "BKE_object.h"
-#include "BKE_particle.h"
-#include "BKE_pointcache.h"
-#include "BKE_scene.h"
-#include "BKE_smoke.h"
-#include "BKE_texture.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
-
-#include "RE_shader_ext.h"
-
-#include "GPU_glew.h"
-
-/* UNUSED so far, may be enabled later */
-/* #define USE_SMOKE_COLLISION_DM */
-
-//#define DEBUG_TIME
-
-#include "smoke_API.h"
-
-#ifdef DEBUG_TIME
-# include "PIL_time.h"
-#endif
-
-#ifdef WITH_SMOKE
-# include "BLI_task.h"
-# include "BLI_kdtree.h"
-# include "BLI_voxel.h"
-
-static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER;
-
-struct Mesh;
-struct Object;
-struct Scene;
-struct SmokeModifierData;
-
-// timestep default value for nice appearance 0.1f
-# define DT_DEFAULT 0.1f
-
-# define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b))))
-# define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b))))
-# define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b)))
-
-#else /* WITH_SMOKE */
-
-/* Stubs to use when smoke is disabled */
-struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res),
- int UNUSED(amplify),
- int UNUSED(noisetype),
- const char *UNUSED(noisefile_path),
- int UNUSED(use_fire),
- int UNUSED(use_colors))
-{
- return NULL;
-}
-
-void smoke_free(struct FLUID_3D *UNUSED(fluid))
-{
-}
-float *smoke_get_density(struct FLUID_3D *UNUSED(fluid))
-{
- return NULL;
-}
-void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt))
-{
-}
-void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength))
-{
-}
-void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid),
- float *UNUSED(alpha),
- float *UNUSED(beta),
- float *UNUSED(dt_factor),
- float *UNUSED(vorticity),
- int *UNUSED(border_colli),
- float *UNUSED(burning_rate),
- float *UNUSED(flame_smoke),
- float *UNUSED(flame_smoke_color),
- float *UNUSED(flame_vorticity),
- float *UNUSED(flame_ignition_temp),
- float *UNUSED(flame_max_temp))
-{
-}
-struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd),
- Depsgraph *UNUSED(depsgraph),
- Scene *UNUSED(scene),
- Object *UNUSED(ob),
- Mesh *UNUSED(me))
-{
- return NULL;
-}
-float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob),
- float UNUSED(position[3]),
- float UNUSED(velocity[3]))
-{
- return 0.0f;
-}
-
-#endif /* WITH_SMOKE */
-
-#ifdef WITH_SMOKE
-
-void BKE_smoke_reallocate_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old)
-{
- int use_heat = (sds->active_fields & SM_ACTIVE_HEAT);
- int use_fire = (sds->active_fields & SM_ACTIVE_FIRE);
- int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
-
- if (free_old && sds->fluid) {
- smoke_free(sds->fluid);
- }
- if (!min_iii(res[0], res[1], res[2])) {
- sds->fluid = NULL;
- return;
- }
- sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors);
- smoke_initBlenderRNA(sds->fluid,
- &(sds->alpha),
- &(sds->beta),
- &(sds->time_scale),
- &(sds->vorticity),
- &(sds->border_collisions),
- &(sds->burning_rate),
- &(sds->flame_smoke),
- sds->flame_smoke_color,
- &(sds->flame_vorticity),
- &(sds->flame_ignition),
- &(sds->flame_max_temp));
-
- /* reallocate shadow buffer */
- if (sds->shadow) {
- MEM_freeN(sds->shadow);
- }
- sds->shadow = MEM_callocN(sizeof(float) * res[0] * res[1] * res[2], "SmokeDomainShadow");
-}
-
-void BKE_smoke_reallocate_highres_fluid(SmokeDomainSettings *sds,
- float dx,
- int res[3],
- int free_old)
-{
- int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE));
- int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
-
- if (free_old && sds->wt) {
- smoke_turbulence_free(sds->wt);
- }
- if (!min_iii(res[0], res[1], res[2])) {
- sds->wt = NULL;
- return;
- }
-
- /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */
- BLI_thread_lock(LOCK_FFTW);
-
- sds->wt = smoke_turbulence_init(
- res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors);
-
- BLI_thread_unlock(LOCK_FFTW);
-
- sds->res_wt[0] = res[0] * (sds->amplify + 1);
- sds->res_wt[1] = res[1] * (sds->amplify + 1);
- sds->res_wt[2] = res[2] * (sds->amplify + 1);
- sds->dx_wt = dx / (sds->amplify + 1);
- smoke_initWaveletBlenderRNA(sds->wt, &(sds->strength));
-}
-
-/* convert global position to domain cell space */
-static void smoke_pos_to_cell(SmokeDomainSettings *sds, float pos[3])
-{
- mul_m4_v3(sds->imat, pos);
- sub_v3_v3(pos, sds->p0);
- pos[0] *= 1.0f / sds->cell_size[0];
- pos[1] *= 1.0f / sds->cell_size[1];
- pos[2] *= 1.0f / sds->cell_size[2];
-}
-
-/* set domain transformations and base resolution from object mesh */
-static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds,
- Object *ob,
- Mesh *me,
- bool init_resolution)
-{
- size_t i;
- float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- float size[3];
- MVert *verts = me->mvert;
- float scale = 0.0;
- int res;
-
- res = sds->maxres;
-
- // get BB of domain
- for (i = 0; i < me->totvert; i++) {
- // min BB
- min[0] = MIN2(min[0], verts[i].co[0]);
- min[1] = MIN2(min[1], verts[i].co[1]);
- min[2] = MIN2(min[2], verts[i].co[2]);
-
- // max BB
- max[0] = MAX2(max[0], verts[i].co[0]);
- max[1] = MAX2(max[1], verts[i].co[1]);
- max[2] = MAX2(max[2], verts[i].co[2]);
- }
-
- /* set domain bounds */
- copy_v3_v3(sds->p0, min);
- copy_v3_v3(sds->p1, max);
- sds->dx = 1.0f / res;
-
- /* calculate domain dimensions */
- sub_v3_v3v3(size, max, min);
- if (init_resolution) {
- zero_v3_int(sds->base_res);
- copy_v3_v3(sds->cell_size, size);
- }
- /* apply object scale */
- for (i = 0; i < 3; i++) {
- size[i] = fabsf(size[i] * ob->scale[i]);
- }
- copy_v3_v3(sds->global_size, size);
- copy_v3_v3(sds->dp0, min);
-
- invert_m4_m4(sds->imat, ob->obmat);
-
- // prevent crash when initializing a plane as domain
- if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) ||
- (size[2] < FLT_EPSILON)) {
- return;
- }
-
- /* define grid resolutions from longest domain side */
- if (size[0] >= MAX2(size[1], size[2])) {
- scale = res / size[0];
- sds->scale = size[0] / fabsf(ob->scale[0]);
- sds->base_res[0] = res;
- sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
- sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
- }
- else if (size[1] >= MAX2(size[0], size[2])) {
- scale = res / size[1];
- sds->scale = size[1] / fabsf(ob->scale[1]);
- sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
- sds->base_res[1] = res;
- sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
- }
- else {
- scale = res / size[2];
- sds->scale = size[2] / fabsf(ob->scale[2]);
- sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
- sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
- sds->base_res[2] = res;
- }
-
- /* set cell size */
- sds->cell_size[0] /= (float)sds->base_res[0];
- sds->cell_size[1] /= (float)sds->base_res[1];
- sds->cell_size[2] /= (float)sds->base_res[2];
-}
-
-static int smokeModifier_init(SmokeModifierData *smd, Object *ob, int scene_framenr, Mesh *me)
-{
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) {
- SmokeDomainSettings *sds = smd->domain;
- int res[3];
- /* set domain dimensions from mesh */
- smoke_set_domain_from_mesh(sds, ob, me, true);
- /* reset domain values */
- zero_v3_int(sds->shift);
- zero_v3(sds->shift_f);
- add_v3_fl(sds->shift_f, 0.5f);
- zero_v3(sds->prev_loc);
- mul_m4_v3(ob->obmat, sds->prev_loc);
- copy_m4_m4(sds->obmat, ob->obmat);
-
- /* set resolutions */
- if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */
- }
- else {
- copy_v3_v3_int(res, sds->base_res);
- }
- copy_v3_v3_int(sds->res, res);
- sds->total_cells = sds->res[0] * sds->res[1] * sds->res[2];
- sds->res_min[0] = sds->res_min[1] = sds->res_min[2] = 0;
- copy_v3_v3_int(sds->res_max, res);
-
- /* allocate fluid */
- BKE_smoke_reallocate_fluid(sds, sds->dx, sds->res, 0);
-
- smd->time = scene_framenr;
-
- /* allocate highres fluid */
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, sds->dx, sds->res, 0);
- }
- /* allocate shadow buffer */
- if (!sds->shadow) {
- sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2],
- "SmokeDomainShadow");
- }
- return 1;
- }
- else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
- smd->time = scene_framenr;
-
- return 1;
- }
- else if ((smd->type & MOD_SMOKE_TYPE_COLL)) {
- if (!smd->coll) {
- smokeModifier_createType(smd);
- }
-
- smd->time = scene_framenr;
-
- return 1;
- }
-
- return 2;
-}
-
-#endif /* WITH_SMOKE */
-
-static void smokeModifier_freeDomain(SmokeModifierData *smd)
-{
- if (smd->domain) {
- if (smd->domain->shadow) {
- MEM_freeN(smd->domain->shadow);
- }
- smd->domain->shadow = NULL;
-
- if (smd->domain->fluid) {
- smoke_free(smd->domain->fluid);
- }
-
- if (smd->domain->fluid_mutex) {
- BLI_rw_mutex_free(smd->domain->fluid_mutex);
- }
-
- if (smd->domain->wt) {
- smoke_turbulence_free(smd->domain->wt);
- }
-
- if (smd->domain->effector_weights) {
- MEM_freeN(smd->domain->effector_weights);
- }
- smd->domain->effector_weights = NULL;
-
- if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) {
- BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
- smd->domain->point_cache[0] = NULL;
- }
-
- if (smd->domain->coba) {
- MEM_freeN(smd->domain->coba);
- }
-
- MEM_freeN(smd->domain);
- smd->domain = NULL;
- }
-}
-
-static void smokeModifier_freeFlow(SmokeModifierData *smd)
-{
- if (smd->flow) {
- if (smd->flow->mesh) {
- BKE_id_free(NULL, smd->flow->mesh);
- }
- if (smd->flow->verts_old) {
- MEM_freeN(smd->flow->verts_old);
- }
- MEM_freeN(smd->flow);
- smd->flow = NULL;
- }
-}
-
-static void smokeModifier_freeCollision(SmokeModifierData *smd)
-{
- if (smd->coll) {
- SmokeCollSettings *scs = smd->coll;
-
- if (scs->numverts) {
- if (scs->verts_old) {
- MEM_freeN(scs->verts_old);
- scs->verts_old = NULL;
- }
- }
-
- if (smd->coll->mesh) {
- BKE_id_free(NULL, smd->coll->mesh);
- }
- smd->coll->mesh = NULL;
-
- MEM_freeN(smd->coll);
- smd->coll = NULL;
- }
-}
-
-void smokeModifier_reset_turbulence(struct SmokeModifierData *smd)
-{
- if (smd && smd->domain && smd->domain->wt) {
- smoke_turbulence_free(smd->domain->wt);
- smd->domain->wt = NULL;
- }
-}
-
-static void smokeModifier_reset_ex(struct SmokeModifierData *smd, bool need_lock)
-{
- if (smd) {
- if (smd->domain) {
- if (smd->domain->shadow) {
- MEM_freeN(smd->domain->shadow);
- }
- smd->domain->shadow = NULL;
-
- if (smd->domain->fluid) {
- if (need_lock) {
- BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
- }
-
- smoke_free(smd->domain->fluid);
- smd->domain->fluid = NULL;
-
- if (need_lock) {
- BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
- }
- }
-
- smokeModifier_reset_turbulence(smd);
-
- smd->time = -1;
- smd->domain->total_cells = 0;
- smd->domain->active_fields = 0;
- }
- else if (smd->flow) {
- if (smd->flow->verts_old) {
- MEM_freeN(smd->flow->verts_old);
- }
- smd->flow->verts_old = NULL;
- smd->flow->numverts = 0;
- }
- else if (smd->coll) {
- SmokeCollSettings *scs = smd->coll;
-
- if (scs->numverts && scs->verts_old) {
- MEM_freeN(scs->verts_old);
- scs->verts_old = NULL;
- }
- }
- }
-}
-
-void smokeModifier_reset(struct SmokeModifierData *smd)
-{
- smokeModifier_reset_ex(smd, true);
-}
-
-void smokeModifier_free(SmokeModifierData *smd)
-{
- if (smd) {
- smokeModifier_freeDomain(smd);
- smokeModifier_freeFlow(smd);
- smokeModifier_freeCollision(smd);
- }
-}
-
-void smokeModifier_createType(struct SmokeModifierData *smd)
-{
- if (smd) {
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- if (smd->domain) {
- smokeModifier_freeDomain(smd);
- }
-
- smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
-
- smd->domain->smd = smd;
-
- smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0]));
- smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE;
- smd->domain->point_cache[0]->step = 1;
-
- /* Deprecated */
- smd->domain->point_cache[1] = NULL;
- BLI_listbase_clear(&smd->domain->ptcaches[1]);
- /* set some standard values */
- smd->domain->fluid = NULL;
- smd->domain->fluid_mutex = BLI_rw_mutex_alloc();
- smd->domain->wt = NULL;
- smd->domain->eff_group = NULL;
- smd->domain->fluid_group = NULL;
- smd->domain->coll_group = NULL;
- smd->domain->maxres = 32;
- smd->domain->amplify = 1;
- smd->domain->alpha = -0.001;
- smd->domain->beta = 0.1;
- smd->domain->time_scale = 1.0;
- smd->domain->vorticity = 2.0;
- smd->domain->border_collisions = SM_BORDER_OPEN; // open domain
- smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG;
- smd->domain->highres_sampling = SM_HRES_FULLSAMPLE;
- smd->domain->strength = 2.0;
- smd->domain->noise = MOD_SMOKE_NOISEWAVE;
- smd->domain->diss_speed = 5;
- smd->domain->active_fields = 0;
-
- smd->domain->adapt_margin = 4;
- smd->domain->adapt_res = 0;
- smd->domain->adapt_threshold = 0.02f;
-
- smd->domain->burning_rate = 0.75f;
- smd->domain->flame_smoke = 1.0f;
- smd->domain->flame_vorticity = 0.5f;
- smd->domain->flame_ignition = 1.5f;
- smd->domain->flame_max_temp = 3.0f;
- /* color */
- smd->domain->flame_smoke_color[0] = 0.7f;
- smd->domain->flame_smoke_color[1] = 0.7f;
- smd->domain->flame_smoke_color[2] = 0.7f;
-
- smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOW_HIGHRES;
- smd->domain->effector_weights = BKE_effector_add_weights(NULL);
-
-#ifdef WITH_OPENVDB_BLOSC
- smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC;
-#else
- smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP;
-#endif
- smd->domain->data_depth = 0;
- smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE;
-
- smd->domain->display_thickness = 1.0f;
- smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED;
- smd->domain->axis_slice_method = AXIS_SLICE_FULL;
- smd->domain->slice_per_voxel = 5.0f;
- smd->domain->slice_depth = 0.5f;
- smd->domain->slice_axis = 0;
- smd->domain->vector_scale = 1.0f;
-
- smd->domain->coba = NULL;
- smd->domain->coba_field = FLUID_FIELD_DENSITY;
-
- smd->domain->clipping = 1e-3f;
- }
- else if (smd->type & MOD_SMOKE_TYPE_FLOW) {
- if (smd->flow) {
- smokeModifier_freeFlow(smd);
- }
-
- smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
-
- smd->flow->smd = smd;
-
- /* set some standard values */
- smd->flow->density = 1.0f;
- smd->flow->fuel_amount = 1.0f;
- smd->flow->temp = 1.0f;
- smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE | MOD_SMOKE_FLOW_USE_PART_SIZE;
- smd->flow->vel_multi = 1.0f;
- smd->flow->volume_density = 0.0f;
- smd->flow->surface_distance = 1.5f;
- smd->flow->source = MOD_SMOKE_FLOW_SOURCE_MESH;
- smd->flow->texture_size = 1.0f;
- smd->flow->particle_size = 1.0f;
- smd->flow->subframes = 0;
-
- smd->flow->color[0] = 0.7f;
- smd->flow->color[1] = 0.7f;
- smd->flow->color[2] = 0.7f;
-
- smd->flow->mesh = NULL;
- smd->flow->psys = NULL;
- }
- else if (smd->type & MOD_SMOKE_TYPE_COLL) {
- if (smd->coll) {
- smokeModifier_freeCollision(smd);
- }
-
- smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
-
- smd->coll->smd = smd;
- smd->coll->verts_old = NULL;
- smd->coll->numverts = 0;
- smd->coll->type = 0; // static obstacle
- smd->coll->mesh = NULL;
- }
- }
-}
-
-void smokeModifier_copy(const struct SmokeModifierData *smd,
- struct SmokeModifierData *tsmd,
- const int flag)
-{
- tsmd->type = smd->type;
- tsmd->time = smd->time;
-
- smokeModifier_createType(tsmd);
-
- if (tsmd->domain) {
- SmokeDomainSettings *tsds = tsmd->domain;
- SmokeDomainSettings *sds = smd->domain;
-
- BKE_ptcache_free_list(&(tsds->ptcaches[0]));
-
- if (flag & LIB_ID_CREATE_NO_MAIN) {
- /* Share the cache with the original object's modifier. */
- tsmd->modifier.flag |= eModifierFlag_SharedCaches;
- tsds->point_cache[0] = sds->point_cache[0];
- tsds->ptcaches[0] = sds->ptcaches[0];
- }
- else {
- tsds->point_cache[0] = BKE_ptcache_copy_list(
- &(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag);
- }
-
- tsds->fluid_group = sds->fluid_group;
- tsds->coll_group = sds->coll_group;
-
- tsds->adapt_margin = sds->adapt_margin;
- tsds->adapt_res = sds->adapt_res;
- tsds->adapt_threshold = sds->adapt_threshold;
-
- tsds->alpha = sds->alpha;
- tsds->beta = sds->beta;
- tsds->amplify = sds->amplify;
- tsds->maxres = sds->maxres;
- tsds->flags = sds->flags;
- tsds->highres_sampling = sds->highres_sampling;
- tsds->viewsettings = sds->viewsettings;
- tsds->noise = sds->noise;
- tsds->diss_speed = sds->diss_speed;
- tsds->strength = sds->strength;
-
- tsds->border_collisions = sds->border_collisions;
- tsds->vorticity = sds->vorticity;
- tsds->time_scale = sds->time_scale;
-
- tsds->burning_rate = sds->burning_rate;
- tsds->flame_smoke = sds->flame_smoke;
- tsds->flame_vorticity = sds->flame_vorticity;
- tsds->flame_ignition = sds->flame_ignition;
- tsds->flame_max_temp = sds->flame_max_temp;
- copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color);
-
- MEM_freeN(tsds->effector_weights);
- tsds->effector_weights = MEM_dupallocN(sds->effector_weights);
- tsds->openvdb_comp = sds->openvdb_comp;
- tsds->data_depth = sds->data_depth;
- tsds->cache_file_format = sds->cache_file_format;
-
- tsds->display_thickness = sds->display_thickness;
- tsds->slice_method = sds->slice_method;
- tsds->axis_slice_method = sds->axis_slice_method;
- tsds->slice_per_voxel = sds->slice_per_voxel;
- tsds->slice_depth = sds->slice_depth;
- tsds->slice_axis = sds->slice_axis;
- tsds->interp_method = sds->interp_method;
- tsds->draw_velocity = sds->draw_velocity;
- tsds->vector_draw_type = sds->vector_draw_type;
- tsds->vector_scale = sds->vector_scale;
-
- tsds->use_coba = sds->use_coba;
- tsds->coba_field = sds->coba_field;
- if (sds->coba) {
- tsds->coba = MEM_dupallocN(sds->coba);
- }
-
- tsds->clipping = sds->clipping;
- }
- else if (tsmd->flow) {
- SmokeFlowSettings *tsfs = tsmd->flow;
- SmokeFlowSettings *sfs = smd->flow;
-
- tsfs->psys = sfs->psys;
- tsfs->noise_texture = sfs->noise_texture;
-
- tsfs->vel_multi = sfs->vel_multi;
- tsfs->vel_normal = sfs->vel_normal;
- tsfs->vel_random = sfs->vel_random;
-
- tsfs->density = sfs->density;
- copy_v3_v3(tsfs->color, sfs->color);
- tsfs->fuel_amount = sfs->fuel_amount;
- tsfs->temp = sfs->temp;
- tsfs->volume_density = sfs->volume_density;
- tsfs->surface_distance = sfs->surface_distance;
- tsfs->particle_size = sfs->particle_size;
- tsfs->subframes = sfs->subframes;
-
- tsfs->texture_size = sfs->texture_size;
- tsfs->texture_offset = sfs->texture_offset;
- BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name));
- tsfs->vgroup_density = sfs->vgroup_density;
-
- tsfs->type = sfs->type;
- tsfs->source = sfs->source;
- tsfs->texture_type = sfs->texture_type;
- tsfs->flags = sfs->flags;
- }
- else if (tsmd->coll) {
- /* leave it as initialized, collision settings is mostly caches */
- }
-}
-
-#ifdef WITH_SMOKE
-
-// forward declaration
-static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer);
-static float calc_voxel_transp(
- float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
-
-static int get_light(ViewLayer *view_layer, float *light)
-{
- Base *base_tmp = NULL;
- int found_light = 0;
-
- // try to find a lamp, preferably local
- for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
- if (base_tmp->object->type == OB_LAMP) {
- Light *la = base_tmp->object->data;
-
- if (la->type == LA_LOCAL) {
- copy_v3_v3(light, base_tmp->object->obmat[3]);
- return 1;
- }
- else if (!found_light) {
- copy_v3_v3(light, base_tmp->object->obmat[3]);
- found_light = 1;
- }
- }
- }
-
- return found_light;
-}
-
-/**********************************************************
- * Obstacles
- **********************************************************/
-
-typedef struct ObstaclesFromDMData {
- SmokeDomainSettings *sds;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *looptri;
- BVHTreeFromMesh *tree;
- unsigned char *obstacle_map;
-
- bool has_velocity;
- float *vert_vel;
- float *velocityX, *velocityY, *velocityZ;
- int *num_obstacles;
-} ObstaclesFromDMData;
-
-static void obstacles_from_mesh_task_cb(void *__restrict userdata,
- const int z,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- ObstaclesFromDMData *data = userdata;
- SmokeDomainSettings *sds = data->sds;
-
- /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
- const float surface_distance = 0.867f;
-
- for (int x = sds->res_min[0]; x < sds->res_max[0]; x++) {
- for (int y = sds->res_min[1]; y < sds->res_max[1]; y++) {
- const int index = smoke_get_index(
- x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]);
-
- float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
- BVHTreeNearest nearest = {0};
- nearest.index = -1;
- nearest.dist_sq = surface_distance *
- surface_distance; /* find_nearest uses squared distance */
-
- /* find the nearest point on the mesh */
- if (BLI_bvhtree_find_nearest(
- data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) !=
- -1) {
- const MLoopTri *lt = &data->looptri[nearest.index];
- float weights[3];
- int v1, v2, v3;
-
- /* calculate barycentric weights for nearest point */
- v1 = data->mloop[lt->tri[0]].v;
- v2 = data->mloop[lt->tri[1]].v;
- v3 = data->mloop[lt->tri[2]].v;
- interp_weights_tri_v3(
- weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
-
- // DG TODO
- if (data->has_velocity) {
- /* apply object velocity */
- {
- float hit_vel[3];
- interp_v3_v3v3v3(hit_vel,
- &data->vert_vel[v1 * 3],
- &data->vert_vel[v2 * 3],
- &data->vert_vel[v3 * 3],
- weights);
- data->velocityX[index] += hit_vel[0];
- data->velocityY[index] += hit_vel[1];
- data->velocityZ[index] += hit_vel[2];
- }
- }
-
- /* tag obstacle cells */
- data->obstacle_map[index] = 1;
-
- if (data->has_velocity) {
- data->obstacle_map[index] |= 8;
- data->num_obstacles[index]++;
- }
- }
- }
- }
-}
-
-static void obstacles_from_mesh(Object *coll_ob,
- SmokeDomainSettings *sds,
- SmokeCollSettings *scs,
- unsigned char *obstacle_map,
- float *velocityX,
- float *velocityY,
- float *velocityZ,
- int *num_obstacles,
- float dt)
-{
- if (!scs->mesh) {
- return;
- }
- {
- Mesh *me = NULL;
- MVert *mvert = NULL;
- const MLoopTri *looptri;
- const MLoop *mloop;
- BVHTreeFromMesh treeData = {NULL};
- int numverts, i;
-
- float *vert_vel = NULL;
- bool has_velocity = false;
-
- me = BKE_mesh_copy_for_eval(scs->mesh, true);
- BKE_mesh_ensure_normals(me);
- mvert = me->mvert;
- mloop = me->mloop;
- looptri = BKE_mesh_runtime_looptri_ensure(me);
- numverts = me->totvert;
-
- // DG TODO
- // if (scs->type > SM_COLL_STATIC)
- // if line above is used, the code is in trouble if the object moves
- // but is declared as "does not move".
-
- {
- vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_velocity");
-
- if (scs->numverts != numverts || !scs->verts_old) {
- if (scs->verts_old) {
- MEM_freeN(scs->verts_old);
- }
-
- scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_verts_old");
- scs->numverts = numverts;
- }
- else {
- has_velocity = true;
- }
- }
-
- /* Transform collider vertices to
- * domain grid space for fast lookups */
- for (i = 0; i < numverts; i++) {
- float n[3];
- float co[3];
-
- /* vert pos */
- mul_m4_v3(coll_ob->obmat, mvert[i].co);
- smoke_pos_to_cell(sds, mvert[i].co);
-
- /* vert normal */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(coll_ob->obmat, n);
- mul_mat3_m4_v3(sds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
-
- /* vert velocity */
- add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
- if (has_velocity) {
- sub_v3_v3v3(&vert_vel[i * 3], co, &scs->verts_old[i * 3]);
- mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
- }
- copy_v3_v3(&scs->verts_old[i * 3], co);
- }
-
- if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
- ObstaclesFromDMData data = {
- .sds = sds,
- .mvert = mvert,
- .mloop = mloop,
- .looptri = looptri,
- .tree = &treeData,
- .obstacle_map = obstacle_map,
- .has_velocity = has_velocity,
- .vert_vel = vert_vel,
- .velocityX = velocityX,
- .velocityY = velocityY,
- .velocityZ = velocityZ,
- .num_obstacles = num_obstacles,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(
- sds->res_min[2], sds->res_max[2], &data, obstacles_from_mesh_task_cb, &settings);
- }
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
- BKE_id_free(NULL, me);
-
- if (vert_vel) {
- MEM_freeN(vert_vel);
- }
- }
-}
-
-/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */
-static void update_obstacles(Depsgraph *depsgraph,
- Object *ob,
- SmokeDomainSettings *sds,
- float dt,
- int UNUSED(substep),
- int UNUSED(totalsteps))
-{
- Object **collobjs = NULL;
- unsigned int numcollobj = 0;
-
- unsigned int collIndex;
- unsigned char *obstacles = smoke_get_obstacle(sds->fluid);
- float *velx = NULL;
- float *vely = NULL;
- float *velz = NULL;
- float *velxOrig = smoke_get_velocity_x(sds->fluid);
- float *velyOrig = smoke_get_velocity_y(sds->fluid);
- float *velzOrig = smoke_get_velocity_z(sds->fluid);
- float *density = smoke_get_density(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *flame = smoke_get_flame(sds->fluid);
- float *r = smoke_get_color_r(sds->fluid);
- float *g = smoke_get_color_g(sds->fluid);
- float *b = smoke_get_color_b(sds->fluid);
- unsigned int z;
-
- int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2],
- "smoke_num_obstacles");
-
- smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
-
- // TODO: delete old obstacle flags
- for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) {
- if (obstacles[z] & 8) // Do not delete static obstacles
- {
- obstacles[z] = 0;
- }
-
- velx[z] = 0;
- vely[z] = 0;
- velz[z] = 0;
- }
-
- collobjs = BKE_collision_objects_create(
- depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
-
- // update obstacle tags in cells
- for (collIndex = 0; collIndex < numcollobj; collIndex++) {
- Object *collob = collobjs[collIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
- eModifierType_Smoke);
-
- // DG TODO: check if modifier is active?
-
- if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
- SmokeCollSettings *scs = smd2->coll;
- obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
- }
- }
-
- BKE_collision_objects_free(collobjs);
-
- /* obstacle cells should not contain any velocity from the smoke simulation */
- for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) {
- if (obstacles[z]) {
- velxOrig[z] = 0;
- velyOrig[z] = 0;
- velzOrig[z] = 0;
- density[z] = 0;
- if (fuel) {
- fuel[z] = 0;
- flame[z] = 0;
- }
- if (r) {
- r[z] = 0;
- g[z] = 0;
- b[z] = 0;
- }
- }
- /* average velocities from multiple obstacles in one cell */
- if (num_obstacles[z]) {
- velx[z] /= num_obstacles[z];
- vely[z] /= num_obstacles[z];
- velz[z] /= num_obstacles[z];
- }
- }
-
- MEM_freeN(num_obstacles);
-}
-
-/**********************************************************
- * Flow emission code
- **********************************************************/
-
-typedef struct EmissionMap {
- float *influence;
- float *influence_high;
- float *velocity;
- int min[3], max[3], res[3];
- int hmin[3], hmax[3], hres[3];
- int total_cells, valid;
-} EmissionMap;
-
-static void em_boundInsert(EmissionMap *em, float point[3])
-{
- int i = 0;
- if (!em->valid) {
- for (; i < 3; i++) {
- em->min[i] = (int)floor(point[i]);
- em->max[i] = (int)ceil(point[i]);
- }
- em->valid = 1;
- }
- else {
- for (; i < 3; i++) {
- if (point[i] < em->min[i]) {
- em->min[i] = (int)floor(point[i]);
- }
- if (point[i] > em->max[i]) {
- em->max[i] = (int)ceil(point[i]);
- }
- }
- }
-}
-
-static void clampBoundsInDomain(SmokeDomainSettings *sds,
- int min[3],
- int max[3],
- float *min_vel,
- float *max_vel,
- int margin,
- float dt)
-{
- int i;
- for (i = 0; i < 3; i++) {
- int adapt = (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) ? sds->adapt_res : 0;
- /* add margin */
- min[i] -= margin;
- max[i] += margin;
-
- /* adapt to velocity */
- if (min_vel && min_vel[i] < 0.0f) {
- min[i] += (int)floor(min_vel[i] * dt);
- }
- if (max_vel && max_vel[i] > 0.0f) {
- max[i] += (int)ceil(max_vel[i] * dt);
- }
-
- /* clamp within domain max size */
- CLAMP(min[i], -adapt, sds->base_res[i] + adapt);
- CLAMP(max[i], -adapt, sds->base_res[i] + adapt);
- }
-}
-
-static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
-{
- int i, res[3];
-
- for (i = 0; i < 3; i++) {
- res[i] = em->max[i] - em->min[i];
- if (res[i] <= 0) {
- return;
- }
- }
- em->total_cells = res[0] * res[1] * res[2];
- copy_v3_v3_int(em->res, res);
-
- em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence");
- if (use_velocity) {
- em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity");
- }
-
- /* allocate high resolution map if required */
- if (hires_mul > 1) {
- int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul);
-
- for (i = 0; i < 3; i++) {
- em->hmin[i] = em->min[i] * hires_mul;
- em->hmax[i] = em->max[i] * hires_mul;
- em->hres[i] = em->res[i] * hires_mul;
- }
-
- em->influence_high = MEM_callocN(sizeof(float) * total_cells_high,
- "smoke_flow_influence_high");
- }
- em->valid = 1;
-}
-
-static void em_freeData(EmissionMap *em)
-{
- if (em->influence) {
- MEM_freeN(em->influence);
- }
- if (em->influence_high) {
- MEM_freeN(em->influence_high);
- }
- if (em->velocity) {
- MEM_freeN(em->velocity);
- }
-}
-
-static void em_combineMaps(
- EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size)
-{
- int i, x, y, z;
-
- /* copyfill input 1 struct and clear output for new allocation */
- EmissionMap em1;
- memcpy(&em1, output, sizeof(EmissionMap));
- memset(output, 0, sizeof(EmissionMap));
-
- for (i = 0; i < 3; i++) {
- if (em1.valid) {
- output->min[i] = MIN2(em1.min[i], em2->min[i]);
- output->max[i] = MAX2(em1.max[i], em2->max[i]);
- }
- else {
- output->min[i] = em2->min[i];
- output->max[i] = em2->max[i];
- }
- }
- /* allocate output map */
- em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier);
-
- /* base resolution inputs */
- for (x = output->min[0]; x < output->max[0]; x++) {
- for (y = output->min[1]; y < output->max[1]; y++) {
- for (z = output->min[2]; z < output->max[2]; z++) {
- int index_out = smoke_get_index(x - output->min[0],
- output->res[0],
- y - output->min[1],
- output->res[1],
- z - output->min[2]);
-
- /* initialize with first input if in range */
- if (x >= em1.min[0] && x < em1.max[0] && y >= em1.min[1] && y < em1.max[1] &&
- z >= em1.min[2] && z < em1.max[2]) {
- int index_in = smoke_get_index(
- x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]);
-
- /* values */
- output->influence[index_out] = em1.influence[index_in];
- if (output->velocity && em1.velocity) {
- copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]);
- }
- }
-
- /* apply second input if in range */
- if (x >= em2->min[0] && x < em2->max[0] && y >= em2->min[1] && y < em2->max[1] &&
- z >= em2->min[2] && z < em2->max[2]) {
- int index_in = smoke_get_index(
- x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]);
-
- /* values */
- if (additive) {
- output->influence[index_out] += em2->influence[index_in] * sample_size;
- }
- else {
- output->influence[index_out] = MAX2(em2->influence[index_in],
- output->influence[index_out]);
- }
- if (output->velocity && em2->velocity) {
- /* last sample replaces the velocity */
- output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3],
- em2->velocity[index_in * 3]);
- output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1],
- em2->velocity[index_in * 3 + 1]);
- output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2],
- em2->velocity[index_in * 3 + 2]);
- }
- }
- } // low res loop
- }
- }
-
- /* initialize high resolution input if available */
- if (output->influence_high) {
- for (x = output->hmin[0]; x < output->hmax[0]; x++) {
- for (y = output->hmin[1]; y < output->hmax[1]; y++) {
- for (z = output->hmin[2]; z < output->hmax[2]; z++) {
- int index_out = smoke_get_index(x - output->hmin[0],
- output->hres[0],
- y - output->hmin[1],
- output->hres[1],
- z - output->hmin[2]);
-
- /* initialize with first input if in range */
- if (x >= em1.hmin[0] && x < em1.hmax[0] && y >= em1.hmin[1] && y < em1.hmax[1] &&
- z >= em1.hmin[2] && z < em1.hmax[2]) {
- int index_in = smoke_get_index(
- x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]);
- /* values */
- output->influence_high[index_out] = em1.influence_high[index_in];
- }
-
- /* apply second input if in range */
- if (x >= em2->hmin[0] && x < em2->hmax[0] && y >= em2->hmin[1] && y < em2->hmax[1] &&
- z >= em2->hmin[2] && z < em2->hmax[2]) {
- int index_in = smoke_get_index(
- x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]);
-
- /* values */
- if (additive) {
- output->influence_high[index_out] += em2->influence_high[index_in] * sample_size;
- }
- else {
- output->influence_high[index_out] = MAX2(em2->influence_high[index_in],
- output->influence_high[index_out]);
- }
- }
- } // high res loop
- }
- }
- }
-
- /* free original data */
- em_freeData(&em1);
-}
-
-typedef struct EmitFromParticlesData {
- SmokeFlowSettings *sfs;
- KDTree_3d *tree;
- int hires_multiplier;
-
- EmissionMap *em;
- float *particle_vel;
- float hr;
-
- int *min, *max, *res;
-
- float solid;
- float smooth;
- float hr_smooth;
-} EmitFromParticlesData;
-
-static void emit_from_particles_task_cb(void *__restrict userdata,
- const int z,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- EmitFromParticlesData *data = userdata;
- SmokeFlowSettings *sfs = data->sfs;
- EmissionMap *em = data->em;
- const int hires_multiplier = data->hires_multiplier;
-
- for (int x = data->min[0]; x < data->max[0]; x++) {
- for (int y = data->min[1]; y < data->max[1]; y++) {
- /* take low res samples where possible */
- if (hires_multiplier <= 1 ||
- !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* get low res space coordinates */
- const int lx = x / hires_multiplier;
- const int ly = y / hires_multiplier;
- const int lz = z / hires_multiplier;
-
- const int index = smoke_get_index(
- lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- /* find particle distance from the kdtree */
- KDTreeNearest_3d nearest;
- const float range = data->solid + data->smooth;
- BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence[index] = (nearest.dist < data->solid) ?
- 1.0f :
- (1.0f - (nearest.dist - data->solid) / data->smooth);
- /* Uses particle velocity as initial velocity for smoke */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY &&
- (sfs->psys->part->phystype != PART_PHYS_NO)) {
- madd_v3_v3fl(
- &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], sfs->vel_multi);
- }
- }
- }
-
- /* take high res samples if required */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- const float lx = ((float)x) * data->hr;
- const float ly = ((float)y) * data->hr;
- const float lz = ((float)z) * data->hr;
-
- const int index = smoke_get_index(
- x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
- const float ray_start[3] = {
- lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
-
- /* find particle distance from the kdtree */
- KDTreeNearest_3d nearest;
- const float range = data->solid + data->hr_smooth;
- BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence_high[index] = (nearest.dist < data->solid) ?
- 1.0f :
- (1.0f - (nearest.dist - data->solid) / data->smooth);
- }
- }
- }
- }
-}
-
-static void emit_from_particles(Object *flow_ob,
- SmokeDomainSettings *sds,
- SmokeFlowSettings *sfs,
- EmissionMap *em,
- Depsgraph *depsgraph,
- Scene *scene,
- float dt)
-{
- /* Is particle system selected. */
- if (sfs && sfs->psys && sfs->psys->part &&
- ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) {
- ParticleSimulationData sim;
- ParticleSystem *psys = sfs->psys;
- float *particle_pos;
- float *particle_vel;
- int totpart = psys->totpart, totchild;
- int p = 0;
- int valid_particles = 0;
- int bounds_margin = 1;
-
- /* radius based flow */
- const float solid = sfs->particle_size * 0.5f;
- const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
- int hires_multiplier = 1;
- KDTree_3d *tree = NULL;
-
- sim.depsgraph = depsgraph;
- sim.scene = scene;
- sim.ob = flow_ob;
- sim.psys = psys;
- sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
-
- /* prepare curvemapping tables */
- if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) {
- curvemapping_changed_all(psys->part->clumpcurve);
- }
- if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) {
- curvemapping_changed_all(psys->part->roughcurve);
- }
- if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) {
- curvemapping_changed_all(psys->part->twistcurve);
- }
-
- /* initialize particle cache */
- if (psys->part->type == PART_HAIR) {
- // TODO: PART_HAIR not supported whatsoever
- totchild = 0;
- }
- else {
- totchild = psys->totchild * psys->part->disp / 100;
- }
-
- particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
- particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
-
- /* setup particle radius emission if enabled */
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild);
-
- /* check need for high resolution map */
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- bounds_margin = (int)ceil(solid + smooth);
- }
-
- /* calculate local position for each particle */
- for (p = 0; p < totpart + totchild; p++) {
- ParticleKey state;
- float *pos;
- if (p < totpart) {
- if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
- continue;
- }
- }
- else {
- /* handle child particle */
- ChildParticle *cpa = &psys->child[p - totpart];
- if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
- continue;
- }
- }
-
- state.time = DEG_get_ctime(depsgraph); /* use depsgraph time */
- if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
- continue;
- }
-
- /* location */
- pos = &particle_pos[valid_particles * 3];
- copy_v3_v3(pos, state.co);
- smoke_pos_to_cell(sds, pos);
-
- /* velocity */
- copy_v3_v3(&particle_vel[valid_particles * 3], state.vel);
- mul_mat3_m4_v3(sds->imat, &particle_vel[valid_particles * 3]);
-
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- BLI_kdtree_3d_insert(tree, valid_particles, pos);
- }
-
- /* calculate emission map bounds */
- em_boundInsert(em, pos);
- valid_particles++;
- }
-
- /* set emission map */
- clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, bounds_margin, dt);
- em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
-
- if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
- for (p = 0; p < valid_particles; p++) {
- int cell[3];
- size_t i = 0;
- size_t index = 0;
- int badcell = 0;
-
- /* 1. get corresponding cell */
- cell[0] = floor(particle_pos[p * 3]) - em->min[0];
- cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1];
- cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2];
- /* check if cell is valid (in the domain boundary) */
- for (i = 0; i < 3; i++) {
- if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) {
- badcell = 1;
- break;
- }
- }
- if (badcell) {
- continue;
- }
- /* get cell index */
- index = smoke_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]);
- /* Add influence to emission map */
- em->influence[index] = 1.0f;
- /* Uses particle velocity as initial velocity for smoke */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) {
- madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi);
- }
- } // particles loop
- }
- else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE
- int min[3], max[3], res[3];
- const float hr = 1.0f / ((float)hires_multiplier);
- /* slightly adjust high res antialias smoothness based on number of divisions
- * to allow smaller details but yet not differing too much from the low res size */
- const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f);
-
- /* setup loop bounds */
- for (int i = 0; i < 3; i++) {
- min[i] = em->min[i] * hires_multiplier;
- max[i] = em->max[i] * hires_multiplier;
- res[i] = em->res[i] * hires_multiplier;
- }
-
- BLI_kdtree_3d_balance(tree);
-
- EmitFromParticlesData data = {
- .sfs = sfs,
- .tree = tree,
- .hires_multiplier = hires_multiplier,
- .hr = hr,
- .em = em,
- .particle_vel = particle_vel,
- .min = min,
- .max = max,
- .res = res,
- .solid = solid,
- .smooth = smooth,
- .hr_smooth = hr_smooth,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, &settings);
- }
-
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- BLI_kdtree_3d_free(tree);
- }
-
- /* free data */
- if (particle_pos) {
- MEM_freeN(particle_pos);
- }
- if (particle_vel) {
- MEM_freeN(particle_vel);
- }
- }
-}
-
-static void sample_mesh(SmokeFlowSettings *sfs,
- const MVert *mvert,
- const MLoop *mloop,
- const MLoopTri *mlooptri,
- const MLoopUV *mloopuv,
- float *influence_map,
- float *velocity_map,
- int index,
- const int base_res[3],
- float flow_center[3],
- BVHTreeFromMesh *treeData,
- const float ray_start[3],
- const float *vert_vel,
- bool has_velocity,
- int defgrp_index,
- MDeformVert *dvert,
- float x,
- float y,
- float z)
-{
- float ray_dir[3] = {1.0f, 0.0f, 0.0f};
- BVHTreeRayHit hit = {0};
- BVHTreeNearest nearest = {0};
-
- float volume_factor = 0.0f;
- float sample_str = 0.0f;
-
- hit.index = -1;
- hit.dist = 9999;
- nearest.index = -1;
- nearest.dist_sq = sfs->surface_distance *
- sfs->surface_distance; /* find_nearest uses squared distance */
-
- /* Check volume collision */
- if (sfs->volume_density) {
- if (BLI_bvhtree_ray_cast(treeData->tree,
- ray_start,
- ray_dir,
- 0.0f,
- &hit,
- treeData->raycast_callback,
- treeData) != -1) {
- float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
- /* If ray and hit face normal are facing same direction
- * hit point is inside a closed mesh. */
- if (dot >= 0) {
- /* Also cast a ray in opposite direction to make sure
- * point is at least surrounded by two faces */
- negate_v3(ray_dir);
- hit.index = -1;
- hit.dist = 9999;
-
- BLI_bvhtree_ray_cast(
- treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData);
- if (hit.index != -1) {
- volume_factor = sfs->volume_density;
- }
- }
- }
- }
-
- /* find the nearest point on the mesh */
- if (BLI_bvhtree_find_nearest(
- treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
- float weights[3];
- int v1, v2, v3, f_index = nearest.index;
- float n1[3], n2[3], n3[3], hit_normal[3];
-
- /* emit from surface based on distance */
- if (sfs->surface_distance) {
- sample_str = sqrtf(nearest.dist_sq) / sfs->surface_distance;
- CLAMP(sample_str, 0.0f, 1.0f);
- sample_str = pow(1.0f - sample_str, 0.5f);
- }
- else {
- sample_str = 0.0f;
- }
-
- /* calculate barycentric weights for nearest point */
- v1 = mloop[mlooptri[f_index].tri[0]].v;
- v2 = mloop[mlooptri[f_index].tri[1]].v;
- v3 = mloop[mlooptri[f_index].tri[2]].v;
- interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
-
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
- /* apply normal directional velocity */
- if (sfs->vel_normal) {
- /* interpolate vertex normal vectors to get nearest point normal */
- normal_short_to_float_v3(n1, mvert[v1].no);
- normal_short_to_float_v3(n2, mvert[v2].no);
- normal_short_to_float_v3(n3, mvert[v3].no);
- interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
- normalize_v3(hit_normal);
- /* apply normal directional and random velocity
- * - TODO: random disabled for now since it doesn't really work well
- * as pressure calc smoothens it out. */
- velocity_map[index * 3] += hit_normal[0] * sfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 1] += hit_normal[1] * sfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 2] += hit_normal[2] * sfs->vel_normal * 0.25f;
- /* TODO: for fire emitted from mesh surface we can use
- * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */
- }
- /* apply object velocity */
- if (has_velocity && sfs->vel_multi) {
- float hit_vel[3];
- interp_v3_v3v3v3(
- hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
- velocity_map[index * 3] += hit_vel[0] * sfs->vel_multi;
- velocity_map[index * 3 + 1] += hit_vel[1] * sfs->vel_multi;
- velocity_map[index * 3 + 2] += hit_vel[2] * sfs->vel_multi;
- }
- }
-
- /* apply vertex group influence if used */
- if (defgrp_index != -1 && dvert) {
- float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
- defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
- defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
- sample_str *= weight_mask;
- }
-
- /* apply emission texture */
- if ((sfs->flags & MOD_SMOKE_FLOW_TEXTUREEMIT) && sfs->noise_texture) {
- float tex_co[3] = {0};
- TexResult texres;
-
- if (sfs->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO) {
- tex_co[0] = ((x - flow_center[0]) / base_res[0]) / sfs->texture_size;
- tex_co[1] = ((y - flow_center[1]) / base_res[1]) / sfs->texture_size;
- tex_co[2] = ((z - flow_center[2]) / base_res[2] - sfs->texture_offset) / sfs->texture_size;
- }
- else if (mloopuv) {
- const float *uv[3];
- uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
- uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
- uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
-
- interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
-
- /* map between -1.0f and 1.0f */
- tex_co[0] = tex_co[0] * 2.0f - 1.0f;
- tex_co[1] = tex_co[1] * 2.0f - 1.0f;
- tex_co[2] = sfs->texture_offset;
- }
- texres.nor = NULL;
- BKE_texture_get_value(NULL, sfs->noise_texture, tex_co, &texres, false);
- sample_str *= texres.tin;
- }
- }
-
- /* multiply initial velocity by emitter influence */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
- mul_v3_fl(&velocity_map[index * 3], sample_str);
- }
-
- /* apply final influence based on volume factor */
- influence_map[index] = MAX2(volume_factor, sample_str);
-}
-
-typedef struct EmitFromDMData {
- SmokeDomainSettings *sds;
- SmokeFlowSettings *sfs;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *mlooptri;
- const MLoopUV *mloopuv;
- MDeformVert *dvert;
- int defgrp_index;
-
- BVHTreeFromMesh *tree;
- int hires_multiplier;
- float hr;
-
- EmissionMap *em;
- bool has_velocity;
- float *vert_vel;
-
- float *flow_center;
- int *min, *max, *res;
-} EmitFromDMData;
-
-static void emit_from_mesh_task_cb(void *__restrict userdata,
- const int z,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- EmitFromDMData *data = userdata;
- EmissionMap *em = data->em;
- const int hires_multiplier = data->hires_multiplier;
-
- for (int x = data->min[0]; x < data->max[0]; x++) {
- for (int y = data->min[1]; y < data->max[1]; y++) {
- /* take low res samples where possible */
- if (hires_multiplier <= 1 ||
- !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* get low res space coordinates */
- const int lx = x / hires_multiplier;
- const int ly = y / hires_multiplier;
- const int lz = z / hires_multiplier;
-
- const int index = smoke_get_index(
- lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- sample_mesh(data->sfs,
- data->mvert,
- data->mloop,
- data->mlooptri,
- data->mloopuv,
- em->influence,
- em->velocity,
- index,
- data->sds->base_res,
- data->flow_center,
- data->tree,
- ray_start,
- data->vert_vel,
- data->has_velocity,
- data->defgrp_index,
- data->dvert,
- (float)lx,
- (float)ly,
- (float)lz);
- }
-
- /* take high res samples if required */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- const float lx = ((float)x) * data->hr;
- const float ly = ((float)y) * data->hr;
- const float lz = ((float)z) * data->hr;
-
- const int index = smoke_get_index(
- x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
- const float ray_start[3] = {
- lx + 0.5f * data->hr,
- ly + 0.5f * data->hr,
- lz + 0.5f * data->hr,
- };
-
- sample_mesh(data->sfs,
- data->mvert,
- data->mloop,
- data->mlooptri,
- data->mloopuv,
- em->influence_high,
- NULL,
- index,
- data->sds->base_res,
- data->flow_center,
- data->tree,
- ray_start,
- data->vert_vel,
- data->has_velocity,
- data->defgrp_index,
- data->dvert,
- /* x,y,z needs to be always lowres */
- lx,
- ly,
- lz);
- }
- }
- }
-}
-
-static void emit_from_mesh(
- Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
-{
- if (sfs->mesh) {
- Mesh *me;
- int defgrp_index = sfs->vgroup_density - 1;
- MDeformVert *dvert = NULL;
- MVert *mvert = NULL;
- const MLoopTri *mlooptri = NULL;
- const MLoopUV *mloopuv = NULL;
- const MLoop *mloop = NULL;
- BVHTreeFromMesh treeData = {NULL};
- int numOfVerts, i;
- float flow_center[3] = {0};
-
- float *vert_vel = NULL;
- int has_velocity = 0;
- int min[3], max[3], res[3];
- int hires_multiplier = 1;
-
- /* copy mesh for thread safety because we modify it,
- * main issue is its VertArray being modified, then replaced and freed
- */
- me = BKE_mesh_copy_for_eval(sfs->mesh, true);
-
- /* Duplicate vertices to modify. */
- if (me->mvert) {
- me->mvert = MEM_dupallocN(me->mvert);
- CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
- }
-
- BKE_mesh_ensure_normals(me);
- mvert = me->mvert;
- numOfVerts = me->totvert;
- dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
- mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name);
- mloop = me->mloop;
- mlooptri = BKE_mesh_runtime_looptri_ensure(me);
-
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity");
-
- if (sfs->numverts != numOfVerts || !sfs->verts_old) {
- if (sfs->verts_old) {
- MEM_freeN(sfs->verts_old);
- }
- sfs->verts_old = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_verts_old");
- sfs->numverts = numOfVerts;
- }
- else {
- has_velocity = 1;
- }
- }
-
- /* Transform mesh vertices to
- * domain grid space for fast lookups */
- for (i = 0; i < numOfVerts; i++) {
- float n[3];
- /* vert pos */
- mul_m4_v3(flow_ob->obmat, mvert[i].co);
- smoke_pos_to_cell(sds, mvert[i].co);
- /* vert normal */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(flow_ob->obmat, n);
- mul_mat3_m4_v3(sds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
- /* vert velocity */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- float co[3];
- add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
- if (has_velocity) {
- sub_v3_v3v3(&vert_vel[i * 3], co, &sfs->verts_old[i * 3]);
- mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
- }
- copy_v3_v3(&sfs->verts_old[i * 3], co);
- }
-
- /* calculate emission map bounds */
- em_boundInsert(em, mvert[i].co);
- }
- mul_m4_v3(flow_ob->obmat, flow_center);
- smoke_pos_to_cell(sds, flow_center);
-
- /* check need for high resolution map */
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- /* set emission map */
- clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt);
- em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
-
- /* setup loop bounds */
- for (i = 0; i < 3; i++) {
- min[i] = em->min[i] * hires_multiplier;
- max[i] = em->max[i] * hires_multiplier;
- res[i] = em->res[i] * hires_multiplier;
- }
-
- if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
- const float hr = 1.0f / ((float)hires_multiplier);
-
- EmitFromDMData data = {
- .sds = sds,
- .sfs = sfs,
- .mvert = mvert,
- .mloop = mloop,
- .mlooptri = mlooptri,
- .mloopuv = mloopuv,
- .dvert = dvert,
- .defgrp_index = defgrp_index,
- .tree = &treeData,
- .hires_multiplier = hires_multiplier,
- .hr = hr,
- .em = em,
- .has_velocity = has_velocity,
- .vert_vel = vert_vel,
- .flow_center = flow_center,
- .min = min,
- .max = max,
- .res = res,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings);
- }
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
-
- if (vert_vel) {
- MEM_freeN(vert_vel);
- }
-
- if (me->mvert) {
- MEM_freeN(me->mvert);
- }
- BKE_id_free(NULL, me);
- }
-}
-
-/**********************************************************
- * Smoke step
- **********************************************************/
-
-static void adjustDomainResolution(SmokeDomainSettings *sds,
- int new_shift[3],
- EmissionMap *emaps,
- unsigned int numflowobj,
- float dt)
-{
- const int block_size = sds->amplify + 1;
- int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3];
- int total_cells = 1, res_changed = 0, shift_changed = 0;
- float min_vel[3], max_vel[3];
- int x, y, z;
- float *density = smoke_get_density(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *bigdensity = smoke_turbulence_get_density(sds->wt);
- float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
- float *vx = smoke_get_velocity_x(sds->fluid);
- float *vy = smoke_get_velocity_y(sds->fluid);
- float *vz = smoke_get_velocity_z(sds->fluid);
- int wt_res[3];
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- smoke_turbulence_get_res(sds->wt, wt_res);
- }
-
- INIT_MINMAX(min_vel, max_vel);
-
- /* Calculate bounds for current domain content */
- for (x = sds->res_min[0]; x < sds->res_max[0]; x++) {
- for (y = sds->res_min[1]; y < sds->res_max[1]; y++) {
- for (z = sds->res_min[2]; z < sds->res_max[2]; z++) {
- int xn = x - new_shift[0];
- int yn = y - new_shift[1];
- int zn = z - new_shift[2];
- int index;
- float max_den;
-
- /* skip if cell already belongs to new area */
- if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] &&
- zn <= max[2]) {
- continue;
- }
-
- index = smoke_get_index(x - sds->res_min[0],
- sds->res[0],
- y - sds->res_min[1],
- sds->res[1],
- z - sds->res_min[2]);
- max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
-
- /* check high resolution bounds if max density isnt already high enough */
- if (max_den < sds->adapt_threshold && sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- int i, j, k;
- /* high res grid index */
- int xx = (x - sds->res_min[0]) * block_size;
- int yy = (y - sds->res_min[1]) * block_size;
- int zz = (z - sds->res_min[2]) * block_size;
-
- for (i = 0; i < block_size; i++) {
- for (j = 0; j < block_size; j++) {
- for (k = 0; k < block_size; k++) {
- int big_index = smoke_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k);
- float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) :
- bigdensity[big_index];
- if (den > max_den) {
- max_den = den;
- }
- }
- }
- }
- }
-
- /* content bounds (use shifted coordinates) */
- if (max_den >= sds->adapt_threshold) {
- if (min[0] > xn) {
- min[0] = xn;
- }
- if (min[1] > yn) {
- min[1] = yn;
- }
- if (min[2] > zn) {
- min[2] = zn;
- }
- if (max[0] < xn) {
- max[0] = xn;
- }
- if (max[1] < yn) {
- max[1] = yn;
- }
- if (max[2] < zn) {
- max[2] = zn;
- }
- }
-
- /* velocity bounds */
- if (min_vel[0] > vx[index]) {
- min_vel[0] = vx[index];
- }
- if (min_vel[1] > vy[index]) {
- min_vel[1] = vy[index];
- }
- if (min_vel[2] > vz[index]) {
- min_vel[2] = vz[index];
- }
- if (max_vel[0] < vx[index]) {
- max_vel[0] = vx[index];
- }
- if (max_vel[1] < vy[index]) {
- max_vel[1] = vy[index];
- }
- if (max_vel[2] < vz[index]) {
- max_vel[2] = vz[index];
- }
- }
- }
- }
-
- /* also apply emission maps */
- for (int i = 0; i < numflowobj; i++) {
- EmissionMap *em = &emaps[i];
-
- for (x = em->min[0]; x < em->max[0]; x++) {
- for (y = em->min[1]; y < em->max[1]; y++) {
- for (z = em->min[2]; z < em->max[2]; z++) {
- int index = smoke_get_index(
- x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]);
- float max_den = em->influence[index];
-
- /* density bounds */
- if (max_den >= sds->adapt_threshold) {
- if (min[0] > x) {
- min[0] = x;
- }
- if (min[1] > y) {
- min[1] = y;
- }
- if (min[2] > z) {
- min[2] = z;
- }
- if (max[0] < x) {
- max[0] = x;
- }
- if (max[1] < y) {
- max[1] = y;
- }
- if (max[2] < z) {
- max[2] = z;
- }
- }
- }
- }
- }
- }
-
- /* calculate new bounds based on these values */
- mul_v3_fl(min_vel, 1.0f / sds->dx);
- mul_v3_fl(max_vel, 1.0f / sds->dx);
- clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin + 1, dt);
-
- for (int i = 0; i < 3; i++) {
- /* calculate new resolution */
- res[i] = max[i] - min[i];
- total_cells *= res[i];
-
- if (new_shift[i]) {
- shift_changed = 1;
- }
-
- /* if no content set minimum dimensions */
- if (res[i] <= 0) {
- int j;
- for (j = 0; j < 3; j++) {
- min[j] = 0;
- max[j] = 1;
- res[j] = 1;
- }
- res_changed = 1;
- total_cells = 1;
- break;
- }
- if (min[i] != sds->res_min[i] || max[i] != sds->res_max[i]) {
- res_changed = 1;
- }
- }
-
- if (res_changed || shift_changed) {
- struct FLUID_3D *fluid_old = sds->fluid;
- struct WTURBULENCE *turb_old = sds->wt;
- /* allocate new fluid data */
- BKE_smoke_reallocate_fluid(sds, sds->dx, res, 0);
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, sds->dx, res, 0);
- }
-
- /* copy values from old fluid to new */
- if (sds->total_cells > 1 && total_cells > 1) {
- /* low res smoke */
- float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_heatold, *o_vx, *o_vy, *o_vz, *o_r,
- *o_g, *o_b;
- float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_heatold, *n_vx, *n_vy, *n_vz, *n_r,
- *n_g, *n_b;
- float dummy;
- unsigned char *dummy_p;
- /* high res smoke */
- int wt_res_old[3];
- float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw,
- *o_wt_r, *o_wt_g, *o_wt_b;
- float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw,
- *n_wt_r, *n_wt_g, *n_wt_b;
-
- smoke_export(fluid_old,
- &dummy,
- &dummy,
- &o_dens,
- &o_react,
- &o_flame,
- &o_fuel,
- &o_heat,
- &o_heatold,
- &o_vx,
- &o_vy,
- &o_vz,
- &o_r,
- &o_g,
- &o_b,
- &dummy_p);
- smoke_export(sds->fluid,
- &dummy,
- &dummy,
- &n_dens,
- &n_react,
- &n_flame,
- &n_fuel,
- &n_heat,
- &n_heatold,
- &n_vx,
- &n_vy,
- &n_vz,
- &n_r,
- &n_g,
- &n_b,
- &dummy_p);
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- smoke_turbulence_export(turb_old,
- &o_wt_dens,
- &o_wt_react,
- &o_wt_flame,
- &o_wt_fuel,
- &o_wt_r,
- &o_wt_g,
- &o_wt_b,
- &o_wt_tcu,
- &o_wt_tcv,
- &o_wt_tcw);
- smoke_turbulence_get_res(turb_old, wt_res_old);
- smoke_turbulence_export(sds->wt,
- &n_wt_dens,
- &n_wt_react,
- &n_wt_flame,
- &n_wt_fuel,
- &n_wt_r,
- &n_wt_g,
- &n_wt_b,
- &n_wt_tcu,
- &n_wt_tcv,
- &n_wt_tcw);
- }
-
- for (x = sds->res_min[0]; x < sds->res_max[0]; x++) {
- for (y = sds->res_min[1]; y < sds->res_max[1]; y++) {
- for (z = sds->res_min[2]; z < sds->res_max[2]; z++) {
- /* old grid index */
- int xo = x - sds->res_min[0];
- int yo = y - sds->res_min[1];
- int zo = z - sds->res_min[2];
- int index_old = smoke_get_index(xo, sds->res[0], yo, sds->res[1], zo);
- /* new grid index */
- int xn = x - min[0] - new_shift[0];
- int yn = y - min[1] - new_shift[1];
- int zn = z - min[2] - new_shift[2];
- int index_new = smoke_get_index(xn, res[0], yn, res[1], zn);
-
- /* skip if outside new domain */
- if (xn < 0 || xn >= res[0] || yn < 0 || yn >= res[1] || zn < 0 || zn >= res[2]) {
- continue;
- }
-
- /* copy data */
- n_dens[index_new] = o_dens[index_old];
- /* heat */
- if (n_heat && o_heat) {
- n_heat[index_new] = o_heat[index_old];
- n_heatold[index_new] = o_heatold[index_old];
- }
- /* fuel */
- if (n_fuel && o_fuel) {
- n_flame[index_new] = o_flame[index_old];
- n_fuel[index_new] = o_fuel[index_old];
- n_react[index_new] = o_react[index_old];
- }
- /* color */
- if (o_r && n_r) {
- n_r[index_new] = o_r[index_old];
- n_g[index_new] = o_g[index_old];
- n_b[index_new] = o_b[index_old];
- }
- n_vx[index_new] = o_vx[index_old];
- n_vy[index_new] = o_vy[index_old];
- n_vz[index_new] = o_vz[index_old];
-
- if (sds->flags & MOD_SMOKE_HIGHRES && turb_old) {
- int i, j, k;
- /* old grid index */
- int xx_o = xo * block_size;
- int yy_o = yo * block_size;
- int zz_o = zo * block_size;
- /* new grid index */
- int xx_n = xn * block_size;
- int yy_n = yn * block_size;
- int zz_n = zn * block_size;
-
- n_wt_tcu[index_new] = o_wt_tcu[index_old];
- n_wt_tcv[index_new] = o_wt_tcv[index_old];
- n_wt_tcw[index_new] = o_wt_tcw[index_old];
-
- for (i = 0; i < block_size; i++) {
- for (j = 0; j < block_size; j++) {
- for (k = 0; k < block_size; k++) {
- int big_index_old = smoke_get_index(
- xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k);
- int big_index_new = smoke_get_index(
- xx_n + i, sds->res_wt[0], yy_n + j, sds->res_wt[1], zz_n + k);
- /* copy data */
- n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
- if (n_wt_flame && o_wt_flame) {
- n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
- n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
- n_wt_react[big_index_new] = o_wt_react[big_index_old];
- }
- if (n_wt_r && o_wt_r) {
- n_wt_r[big_index_new] = o_wt_r[big_index_old];
- n_wt_g[big_index_new] = o_wt_g[big_index_old];
- n_wt_b[big_index_new] = o_wt_b[big_index_old];
- }
- }
- }
- }
- }
- }
- }
- }
- }
- smoke_free(fluid_old);
- if (turb_old) {
- smoke_turbulence_free(turb_old);
- }
-
- /* set new domain dimensions */
- copy_v3_v3_int(sds->res_min, min);
- copy_v3_v3_int(sds->res_max, max);
- copy_v3_v3_int(sds->res, res);
- sds->total_cells = total_cells;
- }
-}
-
-BLI_INLINE void apply_outflow_fields(int index,
- float *density,
- float *heat,
- float *fuel,
- float *react,
- float *color_r,
- float *color_g,
- float *color_b)
-{
- density[index] = 0.f;
- if (heat) {
- heat[index] = 0.f;
- }
- if (fuel) {
- fuel[index] = 0.f;
- react[index] = 0.f;
- }
- if (color_r) {
- color_r[index] = 0.f;
- color_g[index] = 0.f;
- color_b[index] = 0.f;
- }
-}
-
-BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs,
- float emission_value,
- int index,
- float *density,
- float *heat,
- float *fuel,
- float *react,
- float *color_r,
- float *color_g,
- float *color_b)
-{
- int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
- float dens_old = density[index];
- // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
- float dens_flow = (sfs->type == MOD_SMOKE_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density;
- float fuel_flow = emission_value * sfs->fuel_amount;
- /* add heat */
- if (heat && emission_value > 0.0f) {
- heat[index] = ADD_IF_LOWER(heat[index], sfs->temp);
- }
- /* absolute */
- if (absolute_flow) {
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
- if (dens_flow > density[index]) {
- density[index] = dens_flow;
- }
- }
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && fuel_flow) {
- if (fuel_flow > fuel[index]) {
- fuel[index] = fuel_flow;
- }
- }
- }
- /* additive */
- else {
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
- density[index] += dens_flow;
- CLAMP(density[index], 0.0f, 1.0f);
- }
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && sfs->fuel_amount) {
- fuel[index] += fuel_flow;
- CLAMP(fuel[index], 0.0f, 10.0f);
- }
- }
-
- /* set color */
- if (color_r && dens_flow) {
- float total_dens = density[index] / (dens_old + dens_flow);
- color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens;
- color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens;
- color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens;
- }
-
- /* set fire reaction coordinate */
- if (fuel && fuel[index] > FLT_EPSILON) {
- /* instead of using 1.0 for all new fuel add slight falloff
- * to reduce flow blockiness */
- float value = 1.0f - pow2f(1.0f - emission_value);
-
- if (value > react[index]) {
- float f = fuel_flow / fuel[index];
- react[index] = value * f + (1.0f - f) * react[index];
- CLAMP(react[index], 0.0f, value);
- }
- }
-}
-
-static void update_flowsfluids(
- Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
-{
- Object **flowobjs = NULL;
- EmissionMap *emaps = NULL;
- unsigned int numflowobj = 0;
- unsigned int flowIndex;
- int new_shift[3] = {0};
- int active_fields = sds->active_fields;
-
- /* calculate domain shift for current frame if using adaptive domain */
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- int total_shift[3];
- float frame_shift_f[3];
- float ob_loc[3] = {0};
-
- mul_m4_v3(ob->obmat, ob_loc);
-
- sub_v3_v3v3(frame_shift_f, ob_loc, sds->prev_loc);
- copy_v3_v3(sds->prev_loc, ob_loc);
- /* convert global space shift to local "cell" space */
- mul_mat3_m4_v3(sds->imat, frame_shift_f);
- frame_shift_f[0] = frame_shift_f[0] / sds->cell_size[0];
- frame_shift_f[1] = frame_shift_f[1] / sds->cell_size[1];
- frame_shift_f[2] = frame_shift_f[2] / sds->cell_size[2];
- /* add to total shift */
- add_v3_v3(sds->shift_f, frame_shift_f);
- /* convert to integer */
- total_shift[0] = (int)(floorf(sds->shift_f[0]));
- total_shift[1] = (int)(floorf(sds->shift_f[1]));
- total_shift[2] = (int)(floorf(sds->shift_f[2]));
- sub_v3_v3v3_int(new_shift, total_shift, sds->shift);
- copy_v3_v3_int(sds->shift, total_shift);
-
- /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */
- sds->p0[0] = sds->dp0[0] - sds->cell_size[0] * (sds->shift_f[0] - total_shift[0] - 0.5f);
- sds->p0[1] = sds->dp0[1] - sds->cell_size[1] * (sds->shift_f[1] - total_shift[1] - 0.5f);
- sds->p0[2] = sds->dp0[2] - sds->cell_size[2] * (sds->shift_f[2] - total_shift[2] - 0.5f);
- sds->p1[0] = sds->p0[0] + sds->cell_size[0] * sds->base_res[0];
- sds->p1[1] = sds->p0[1] + sds->cell_size[1] * sds->base_res[1];
- sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2];
- }
-
- flowobjs = BKE_collision_objects_create(
- depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
-
- /* init emission maps for each flow */
- emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps");
-
- /* Prepare flow emission maps */
- for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) {
- Object *collob = flowobjs[flowIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
- eModifierType_Smoke);
-
- // check for initialized smoke object
- if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
- // we got nice flow object
- SmokeFlowSettings *sfs = smd2->flow;
- int subframes = sfs->subframes;
- EmissionMap *em = &emaps[flowIndex];
-
- /* just sample flow directly to emission map if no subframes */
- if (!subframes) {
- if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
- emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt);
- }
- else {
- emit_from_mesh(collob, sds, sfs, em, dt);
- }
- }
- /* sample subframes */
- else {
-# if 0
- int scene_frame = (int)DEG_get_ctime(depsgraph);
-# endif
- // float scene_subframe = scene->r.subframe; // UNUSED
- int subframe;
- for (subframe = 0; subframe <= subframes; subframe++) {
- EmissionMap em_temp = {NULL};
- float sample_size = 1.0f / (float)(subframes + 1);
-# if 0
- float prev_frame_pos = sample_size * (float)(subframe + 1);
-# endif
- float sdt = dt * sample_size;
- int hires_multiplier = 1;
-
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- /* TODO: setting the scene frame no longer works with the new depsgraph. */
-# if 0
- /* set scene frame to match previous frame + subframe
- * or use current frame for last sample */
- if (subframe < subframes) {
- scene->r.cfra = scene_frame - 1;
- scene->r.subframe = prev_frame_pos;
- }
- else {
- scene->r.cfra = scene_frame;
- scene->r.subframe = 0.0f;
- }
-# endif
-
- if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
- /* emit_from_particles() updates timestep internally */
- emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt);
- if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
- hires_multiplier = 1;
- }
- }
- else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
- /* update flow object frame */
- BLI_mutex_lock(&object_update_lock);
- BKE_object_modifier_update_subframe(
- depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke);
- BLI_mutex_unlock(&object_update_lock);
-
- /* apply flow */
- emit_from_mesh(collob, sds, sfs, &em_temp, sdt);
- }
-
- /* combine emission maps */
- em_combineMaps(em,
- &em_temp,
- hires_multiplier,
- !(sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE),
- sample_size);
- em_freeData(&em_temp);
- }
- }
-
- /* update required data fields */
- if (em->total_cells && sfs->type != MOD_SMOKE_FLOW_TYPE_OUTFLOW) {
- /* activate heat field if flow produces any heat */
- if (sfs->temp) {
- active_fields |= SM_ACTIVE_HEAT;
- }
- /* activate fuel field if flow adds any fuel */
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && sfs->fuel_amount) {
- active_fields |= SM_ACTIVE_FIRE;
- }
- /* activate color field if flows add smoke with varying colors */
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) {
- if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
- copy_v3_v3(sds->active_color, sfs->color);
- active_fields |= SM_ACTIVE_COLOR_SET;
- }
- else if (!equals_v3v3(sds->active_color, sfs->color)) {
- copy_v3_v3(sds->active_color, sfs->color);
- active_fields |= SM_ACTIVE_COLORS;
- }
- }
- }
- }
- }
-
- /* monitor active fields based on domain settings */
- /* if domain has fire, activate new fields if required */
- if (active_fields & SM_ACTIVE_FIRE) {
- /* heat is always needed for fire */
- active_fields |= SM_ACTIVE_HEAT;
- /* also activate colors if domain smoke color differs from active color */
- if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
- copy_v3_v3(sds->active_color, sds->flame_smoke_color);
- active_fields |= SM_ACTIVE_COLOR_SET;
- }
- else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) {
- copy_v3_v3(sds->active_color, sds->flame_smoke_color);
- active_fields |= SM_ACTIVE_COLORS;
- }
- }
-
- /* Adjust domain size if needed */
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- adjustDomainResolution(sds, new_shift, emaps, numflowobj, dt);
- }
-
- /* Initialize new data fields if any */
- if (active_fields & SM_ACTIVE_HEAT) {
- smoke_ensure_heat(sds->fluid);
- }
- if (active_fields & SM_ACTIVE_FIRE) {
- smoke_ensure_fire(sds->fluid, sds->wt);
- }
- if (active_fields & SM_ACTIVE_COLORS) {
- /* initialize all smoke with "active_color" */
- smoke_ensure_colors(
- sds->fluid, sds->wt, sds->active_color[0], sds->active_color[1], sds->active_color[2]);
- }
- sds->active_fields = active_fields;
-
- /* Apply emission data */
- if (sds->fluid) {
- for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) {
- Object *collob = flowobjs[flowIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
- eModifierType_Smoke);
-
- // check for initialized smoke object
- if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
- // we got nice flow object
- SmokeFlowSettings *sfs = smd2->flow;
- EmissionMap *em = &emaps[flowIndex];
-
- float *density = smoke_get_density(sds->fluid);
- float *color_r = smoke_get_color_r(sds->fluid);
- float *color_g = smoke_get_color_g(sds->fluid);
- float *color_b = smoke_get_color_b(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *react = smoke_get_react(sds->fluid);
- float *bigdensity = smoke_turbulence_get_density(sds->wt);
- float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
- float *bigreact = smoke_turbulence_get_react(sds->wt);
- float *bigcolor_r = smoke_turbulence_get_color_r(sds->wt);
- float *bigcolor_g = smoke_turbulence_get_color_g(sds->wt);
- float *bigcolor_b = smoke_turbulence_get_color_b(sds->wt);
- float *heat = smoke_get_heat(sds->fluid);
- float *velocity_x = smoke_get_velocity_x(sds->fluid);
- float *velocity_y = smoke_get_velocity_y(sds->fluid);
- float *velocity_z = smoke_get_velocity_z(sds->fluid);
- // unsigned char *obstacle = smoke_get_obstacle(sds->fluid);
- // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid);
- int bigres[3];
- float *velocity_map = em->velocity;
- float *emission_map = em->influence;
- float *emission_map_high = em->influence_high;
-
- int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size;
- size_t e_index, d_index, index_big;
-
- // loop through every emission map cell
- for (gx = em->min[0]; gx < em->max[0]; gx++) {
- for (gy = em->min[1]; gy < em->max[1]; gy++) {
- for (gz = em->min[2]; gz < em->max[2]; gz++) {
- /* get emission map index */
- ex = gx - em->min[0];
- ey = gy - em->min[1];
- ez = gz - em->min[2];
- e_index = smoke_get_index(ex, em->res[0], ey, em->res[1], ez);
-
- /* get domain index */
- dx = gx - sds->res_min[0];
- dy = gy - sds->res_min[1];
- dz = gz - sds->res_min[2];
- d_index = smoke_get_index(dx, sds->res[0], dy, sds->res[1], dz);
- /* make sure emission cell is inside the new domain boundary */
- if (dx < 0 || dy < 0 || dz < 0 || dx >= sds->res[0] || dy >= sds->res[1] ||
- dz >= sds->res[2]) {
- continue;
- }
-
- if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
- apply_outflow_fields(
- d_index, density, heat, fuel, react, color_r, color_g, color_b);
- }
- else { // inflow
- apply_inflow_fields(sfs,
- emission_map[e_index],
- d_index,
- density,
- heat,
- fuel,
- react,
- color_r,
- color_g,
- color_b);
-
- /* initial velocity */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- velocity_x[d_index] = ADD_IF_LOWER(velocity_x[d_index],
- velocity_map[e_index * 3]);
- velocity_y[d_index] = ADD_IF_LOWER(velocity_y[d_index],
- velocity_map[e_index * 3 + 1]);
- velocity_z[d_index] = ADD_IF_LOWER(velocity_z[d_index],
- velocity_map[e_index * 3 + 2]);
- }
- }
-
- /* loop through high res blocks if high res enabled */
- if (bigdensity) {
- /* Neighbor cell emission densities
- * (for high resolution smoke smooth interpolation). */
- float c000, c001, c010, c011, c100, c101, c110, c111;
-
- smoke_turbulence_get_res(sds->wt, bigres);
- block_size = sds->amplify + 1; // high res block size
-
- c000 = (ex > 0 && ey > 0 && ez > 0) ?
- emission_map[smoke_get_index(
- ex - 1, em->res[0], ey - 1, em->res[1], ez - 1)] :
- 0;
- c001 =
- (ex > 0 && ey > 0) ?
- emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez)] :
- 0;
- c010 =
- (ex > 0 && ez > 0) ?
- emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1)] :
- 0;
- c011 = (ex > 0) ?
- emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez)] :
- 0;
-
- c100 =
- (ey > 0 && ez > 0) ?
- emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1)] :
- 0;
- c101 = (ey > 0) ?
- emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez)] :
- 0;
- c110 = (ez > 0) ?
- emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1)] :
- 0;
- c111 = emission_map[smoke_get_index(
- ex, em->res[0], ey, em->res[1], ez)]; // this cell
-
- for (ii = 0; ii < block_size; ii++) {
- for (jj = 0; jj < block_size; jj++) {
- for (kk = 0; kk < block_size; kk++) {
-
- float fx, fy, fz, interpolated_value;
- int shift_x = 0, shift_y = 0, shift_z = 0;
-
- /* Use full sample emission map if enabled and available */
- if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) {
- interpolated_value =
- emission_map_high[smoke_get_index(ex * block_size + ii,
- em->res[0] * block_size,
- ey * block_size + jj,
- em->res[1] * block_size,
- ez * block_size + kk)]; // this cell
- }
- else if (sds->highres_sampling == SM_HRES_NEAREST) {
- /* without interpolation use same low resolution
- * block value for all hi-res blocks */
- interpolated_value = c111;
- }
- /* Fall back to interpolated */
- else {
- /* get relative block position
- * for interpolation smoothing */
- fx = (float)ii / block_size + 0.5f / block_size;
- fy = (float)jj / block_size + 0.5f / block_size;
- fz = (float)kk / block_size + 0.5f / block_size;
-
- /* calculate trilinear interpolation */
- interpolated_value = c000 * (1 - fx) * (1 - fy) * (1 - fz) +
- c100 * fx * (1 - fy) * (1 - fz) +
- c010 * (1 - fx) * fy * (1 - fz) +
- c001 * (1 - fx) * (1 - fy) * fz +
- c101 * fx * (1 - fy) * fz +
- c011 * (1 - fx) * fy * fz +
- c110 * fx * fy * (1 - fz) + c111 * fx * fy * fz;
-
- /* add some contrast / sharpness
- * depending on hi-res block size */
- interpolated_value = (interpolated_value - 0.4f) * (block_size / 2) + 0.4f;
- CLAMP(interpolated_value, 0.0f, 1.0f);
-
- /* shift smoke block index
- * (because pixel center is actually
- * in halfway of the low res block) */
- shift_x = (dx < 1) ? 0 : block_size / 2;
- shift_y = (dy < 1) ? 0 : block_size / 2;
- shift_z = (dz < 1) ? 0 : block_size / 2;
- }
-
- /* get shifted index for current high resolution block */
- index_big = smoke_get_index(block_size * dx + ii - shift_x,
- bigres[0],
- block_size * dy + jj - shift_y,
- bigres[1],
- block_size * dz + kk - shift_z);
-
- if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
- if (interpolated_value) {
- apply_outflow_fields(index_big,
- bigdensity,
- NULL,
- bigfuel,
- bigreact,
- bigcolor_r,
- bigcolor_g,
- bigcolor_b);
- }
- }
- else { // inflow
- apply_inflow_fields(sfs,
- interpolated_value,
- index_big,
- bigdensity,
- NULL,
- bigfuel,
- bigreact,
- bigcolor_r,
- bigcolor_g,
- bigcolor_b);
- }
- } // hires loop
- }
- }
- } // bigdensity
- } // low res loop
- }
- }
-
- // free emission maps
- em_freeData(em);
-
- } // end emission
- }
- }
-
- BKE_collision_objects_free(flowobjs);
- if (emaps) {
- MEM_freeN(emaps);
- }
-}
-
-typedef struct UpdateEffectorsData {
- Scene *scene;
- SmokeDomainSettings *sds;
- ListBase *effectors;
-
- float *density;
- float *fuel;
- float *force_x;
- float *force_y;
- float *force_z;
- float *velocity_x;
- float *velocity_y;
- float *velocity_z;
- unsigned char *obstacle;
-} UpdateEffectorsData;
-
-static void update_effectors_task_cb(void *__restrict userdata,
- const int x,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- UpdateEffectorsData *data = userdata;
- SmokeDomainSettings *sds = data->sds;
-
- for (int y = 0; y < sds->res[1]; y++) {
- for (int z = 0; z < sds->res[2]; z++) {
- EffectedPoint epoint;
- float mag;
- float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
- const unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
-
- if (((data->fuel ? MAX2(data->density[index], data->fuel[index]) : data->density[index]) <
- FLT_EPSILON) ||
- data->obstacle[index]) {
- continue;
- }
-
- vel[0] = data->velocity_x[index];
- vel[1] = data->velocity_y[index];
- vel[2] = data->velocity_z[index];
-
- /* convert vel to global space */
- mag = len_v3(vel);
- mul_mat3_m4_v3(sds->obmat, vel);
- normalize_v3(vel);
- mul_v3_fl(vel, mag);
-
- voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x + sds->res_min[0]) + 0.5f);
- voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y + sds->res_min[1]) + 0.5f);
- voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z + sds->res_min[2]) + 0.5f);
- mul_m4_v3(sds->obmat, voxelCenter);
-
- pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
- BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
-
- /* convert retvel to local space */
- mag = len_v3(retvel);
- mul_mat3_m4_v3(sds->imat, retvel);
- normalize_v3(retvel);
- mul_v3_fl(retvel, mag);
-
- // TODO dg - do in force!
- data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f);
- data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f);
- data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f);
- }
- }
-}
-
-static void update_effectors(
- Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
-{
- ListBase *effectors;
- /* make sure smoke flow influence is 0.0f */
- sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
- effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights);
-
- if (effectors) {
- // precalculate wind forces
- UpdateEffectorsData data;
- data.scene = scene;
- data.sds = sds;
- data.effectors = effectors;
- data.density = smoke_get_density(sds->fluid);
- data.fuel = smoke_get_fuel(sds->fluid);
- data.force_x = smoke_get_force_x(sds->fluid);
- data.force_y = smoke_get_force_y(sds->fluid);
- data.force_z = smoke_get_force_z(sds->fluid);
- data.velocity_x = smoke_get_velocity_x(sds->fluid);
- data.velocity_y = smoke_get_velocity_y(sds->fluid);
- data.velocity_z = smoke_get_velocity_z(sds->fluid);
- data.obstacle = smoke_get_obstacle(sds->fluid);
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(0, sds->res[0], &data, update_effectors_task_cb, &settings);
- }
-
- BKE_effectors_free(effectors);
-}
-
-static void step(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- SmokeModifierData *smd,
- Mesh *domain_me,
- float fps)
-{
- SmokeDomainSettings *sds = smd->domain;
- /* stability values copied from wturbulence.cpp */
- const int maxSubSteps = 25;
- float maxVel;
- // maxVel should be 1.5 (1.5 cell max movement) * dx (cell size)
-
- float dt;
- float maxVelMag = 0.0f;
- int totalSubsteps;
- int substep = 0;
- float dtSubdiv;
- float gravity[3] = {0.0f, 0.0f, -1.0f};
- float gravity_mag;
-
- /* update object state */
- invert_m4_m4(sds->imat, ob->obmat);
- copy_m4_m4(sds->obmat, ob->obmat);
- smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0);
-
- /* use global gravity if enabled */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- /* map default value to 1.0 */
- mul_v3_fl(gravity, 1.0f / 9.810f);
- }
- /* convert gravity to domain space */
- gravity_mag = len_v3(gravity);
- mul_mat3_m4_v3(sds->imat, gravity);
- normalize_v3(gravity);
- mul_v3_fl(gravity, gravity_mag);
-
- /* adapt timestep for different framerates, dt = 0.1 is at 25fps */
- dt = DT_DEFAULT * (25.0f / fps);
- // maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel
- maxVel = (sds->dx * 5.0f);
-
- maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale;
- totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */
- totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
- totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
-
- /* Disable substeps for now, since it results in numerical instability */
- totalSubsteps = 1.0f;
-
- dtSubdiv = (float)dt / (float)totalSubsteps;
-
- // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt);
-
- for (substep = 0; substep < totalSubsteps; substep++) {
- // calc animated obstacle velocities
- update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv);
- update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps);
-
- if (sds->total_cells > 1) {
- // DG TODO? problem --> uses forces instead of velocity,
- // need to check how they need to be changed with variable dt.
- update_effectors(depsgraph, scene, ob, sds, dtSubdiv);
- smoke_step(sds->fluid, gravity, dtSubdiv);
- }
- }
-}
-
-static Mesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
-{
- Mesh *result;
- MVert *mverts;
- MPoly *mpolys;
- MLoop *mloops;
- float min[3];
- float max[3];
- float *co;
- MPoly *mp;
- MLoop *ml;
-
- int num_verts = 8;
- int num_faces = 6;
- int i;
- float ob_loc[3] = {0};
- float ob_cache_loc[3] = {0};
-
- /* dont generate any mesh if there isnt any content */
- if (sds->total_cells <= 1) {
- num_verts = 0;
- num_faces = 0;
- }
-
- result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
- mverts = result->mvert;
- mpolys = result->mpoly;
- mloops = result->mloop;
-
- if (num_verts) {
- /* volume bounds */
- madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min);
- madd_v3fl_v3fl_v3fl_v3i(max, sds->p0, sds->cell_size, sds->res_max);
-
- /* set vertices */
- /* top slab */
- co = mverts[0].co;
- co[0] = min[0];
- co[1] = min[1];
- co[2] = max[2];
- co = mverts[1].co;
- co[0] = max[0];
- co[1] = min[1];
- co[2] = max[2];
- co = mverts[2].co;
- co[0] = max[0];
- co[1] = max[1];
- co[2] = max[2];
- co = mverts[3].co;
- co[0] = min[0];
- co[1] = max[1];
- co[2] = max[2];
- /* bottom slab */
- co = mverts[4].co;
- co[0] = min[0];
- co[1] = min[1];
- co[2] = min[2];
- co = mverts[5].co;
- co[0] = max[0];
- co[1] = min[1];
- co[2] = min[2];
- co = mverts[6].co;
- co[0] = max[0];
- co[1] = max[1];
- co[2] = min[2];
- co = mverts[7].co;
- co[0] = min[0];
- co[1] = max[1];
- co[2] = min[2];
-
- /* create faces */
- /* top */
- mp = &mpolys[0];
- ml = &mloops[0 * 4];
- mp->loopstart = 0 * 4;
- mp->totloop = 4;
- ml[0].v = 0;
- ml[1].v = 1;
- ml[2].v = 2;
- ml[3].v = 3;
- /* right */
- mp = &mpolys[1];
- ml = &mloops[1 * 4];
- mp->loopstart = 1 * 4;
- mp->totloop = 4;
- ml[0].v = 2;
- ml[1].v = 1;
- ml[2].v = 5;
- ml[3].v = 6;
- /* bottom */
- mp = &mpolys[2];
- ml = &mloops[2 * 4];
- mp->loopstart = 2 * 4;
- mp->totloop = 4;
- ml[0].v = 7;
- ml[1].v = 6;
- ml[2].v = 5;
- ml[3].v = 4;
- /* left */
- mp = &mpolys[3];
- ml = &mloops[3 * 4];
- mp->loopstart = 3 * 4;
- mp->totloop = 4;
- ml[0].v = 0;
- ml[1].v = 3;
- ml[2].v = 7;
- ml[3].v = 4;
- /* front */
- mp = &mpolys[4];
- ml = &mloops[4 * 4];
- mp->loopstart = 4 * 4;
- mp->totloop = 4;
- ml[0].v = 3;
- ml[1].v = 2;
- ml[2].v = 6;
- ml[3].v = 7;
- /* back */
- mp = &mpolys[5];
- ml = &mloops[5 * 4];
- mp->loopstart = 5 * 4;
- mp->totloop = 4;
- ml[0].v = 1;
- ml[1].v = 0;
- ml[2].v = 4;
- ml[3].v = 5;
-
- /* calculate required shift to match domain's global position
- * it was originally simulated at (if object moves without smoke step) */
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->obmat, ob_loc);
- mul_m4_v3(sds->obmat, ob_cache_loc);
- sub_v3_v3v3(sds->obj_shift_f, ob_cache_loc, ob_loc);
- /* convert shift to local space and apply to vertices */
- mul_mat3_m4_v3(ob->imat, sds->obj_shift_f);
- /* apply */
- for (i = 0; i < num_verts; i++) {
- add_v3_v3(mverts[i].co, sds->obj_shift_f);
- }
- }
-
- BKE_mesh_calc_edges(result, false, false);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
- return result;
-}
-
-static void smokeModifier_process(
- SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
-{
- const int scene_framenr = (int)DEG_get_ctime(depsgraph);
-
- if ((smd->type & MOD_SMOKE_TYPE_FLOW)) {
- if (scene_framenr >= smd->time) {
- smokeModifier_init(smd, ob, scene_framenr, me);
- }
-
- if (smd->flow->mesh) {
- BKE_id_free(NULL, smd->flow->mesh);
- }
- smd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
-
- if (scene_framenr > smd->time) {
- smd->time = scene_framenr;
- }
- else if (scene_framenr < smd->time) {
- smd->time = scene_framenr;
- smokeModifier_reset_ex(smd, false);
- }
- }
- else if (smd->type & MOD_SMOKE_TYPE_COLL) {
- if (scene_framenr >= smd->time) {
- smokeModifier_init(smd, ob, scene_framenr, me);
- }
-
- if (smd->coll) {
- if (smd->coll->mesh) {
- BKE_id_free(NULL, smd->coll->mesh);
- }
-
- smd->coll->mesh = BKE_mesh_copy_for_eval(me, false);
- }
-
- smd->time = scene_framenr;
- if (scene_framenr < smd->time) {
- smokeModifier_reset_ex(smd, false);
- }
- }
- else if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- SmokeDomainSettings *sds = smd->domain;
- PointCache *cache = NULL;
- PTCacheID pid;
- int startframe, endframe, framenr;
- float timescale;
-
- framenr = scene_framenr;
-
- cache = sds->point_cache[0];
- BKE_ptcache_id_from_smoke(&pid, ob, smd);
- BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
-
- if (!smd->domain->fluid || framenr == startframe) {
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- smokeModifier_reset_ex(smd, false);
- BKE_ptcache_validate(cache, framenr);
- cache->flag &= ~PTCACHE_REDO_NEEDED;
- }
-
- if (!smd->domain->fluid && (framenr != startframe) &&
- (smd->domain->flags & MOD_SMOKE_FILE_LOAD) == 0 && (cache->flag & PTCACHE_BAKED) == 0) {
- return;
- }
-
- smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD;
- CLAMP(framenr, startframe, endframe);
-
- /* If already viewing a pre/after frame, no need to reload */
- if ((smd->time == framenr) && (framenr != scene_framenr)) {
- return;
- }
-
- if (smokeModifier_init(smd, ob, scene_framenr, me) == 0) {
- printf("bad smokeModifier_init\n");
- return;
- }
-
- /* only calculate something when we advanced a single frame */
- /* don't simulate if viewing start frame, but scene frame is not real start frame */
- bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr);
-
- /* try to read from cache */
- if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) {
- BKE_ptcache_validate(cache, framenr);
- smd->time = framenr;
- return;
- }
-
- if (!can_simulate) {
- return;
- }
-
-# ifdef DEBUG_TIME
- double start = PIL_check_seconds_timer();
-# endif
-
- /* if on second frame, write cache for first frame */
- if ((int)smd->time == startframe &&
- (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
- BKE_ptcache_write(&pid, startframe);
- }
-
- // set new time
- smd->time = scene_framenr;
-
- /* do simulation */
-
- // simulate the actual smoke (c++ code in intern/smoke)
- // DG: interesting commenting this line + deactivating loading of noise files
- if (framenr != startframe) {
- if (sds->flags & MOD_SMOKE_DISSOLVE) {
- /* low res dissolve */
- smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
- /* high res dissolve */
- if (sds->wt) {
- smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
- }
- }
-
- step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base);
- }
-
- // create shadows before writing cache so they get stored
- smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph));
-
- if (sds->wt && sds->total_cells > 1) {
- smoke_turbulence_step(sds->wt, sds->fluid);
- }
-
- BKE_ptcache_validate(cache, framenr);
- if (framenr != startframe) {
- BKE_ptcache_write(&pid, framenr);
- }
-
-# ifdef DEBUG_TIME
- double end = PIL_check_seconds_timer();
- printf("Frame: %d, Time: %f\n\n", (int)smd->time, (float)(end - start));
-# endif
- }
-}
-
-struct Mesh *smokeModifier_do(
- SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
-{
- /* lock so preview render does not read smoke data while it gets modified */
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
- }
-
- smokeModifier_process(smd, depsgraph, scene, ob, me);
-
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
- }
-
- /* return generated geometry for adaptive domain */
- Mesh *result;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
- smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && smd->domain->base_res[0]) {
- result = createDomainGeometry(smd->domain, ob);
- }
- else {
- result = BKE_mesh_copy_for_eval(me, false);
- }
- /* XXX This is really not a nice hack, but until root of the problem is understood,
- * this should be an acceptable workaround I think.
- * See T58492 for details on the issue. */
- result->texflag |= ME_AUTOSPACE;
- return result;
-}
-
-static float calc_voxel_transp(
- float *result, float *input, int res[3], int *pixel, float *tRay, float correct)
-{
- const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
-
- // T_ray *= T_vox
- *tRay *= expf(input[index] * correct);
-
- if (result[index] < 0.0f) {
- result[index] = *tRay;
- }
-
- return *tRay;
-}
-
-static void bresenham_linie_3D(int x1,
- int y1,
- int z1,
- int x2,
- int y2,
- int z2,
- float *tRay,
- bresenham_callback cb,
- float *result,
- float *input,
- int res[3],
- float correct)
-{
- int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
- int pixel[3];
-
- pixel[0] = x1;
- pixel[1] = y1;
- pixel[2] = z1;
-
- dx = x2 - x1;
- dy = y2 - y1;
- dz = z2 - z1;
-
- x_inc = (dx < 0) ? -1 : 1;
- l = abs(dx);
- y_inc = (dy < 0) ? -1 : 1;
- m = abs(dy);
- z_inc = (dz < 0) ? -1 : 1;
- n = abs(dz);
- dx2 = l << 1;
- dy2 = m << 1;
- dz2 = n << 1;
-
- if ((l >= m) && (l >= n)) {
- err_1 = dy2 - l;
- err_2 = dz2 - l;
- for (i = 0; i < l; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) {
- break;
- }
- if (err_1 > 0) {
- pixel[1] += y_inc;
- err_1 -= dx2;
- }
- if (err_2 > 0) {
- pixel[2] += z_inc;
- err_2 -= dx2;
- }
- err_1 += dy2;
- err_2 += dz2;
- pixel[0] += x_inc;
- }
- }
- else if ((m >= l) && (m >= n)) {
- err_1 = dx2 - m;
- err_2 = dz2 - m;
- for (i = 0; i < m; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) {
- break;
- }
- if (err_1 > 0) {
- pixel[0] += x_inc;
- err_1 -= dy2;
- }
- if (err_2 > 0) {
- pixel[2] += z_inc;
- err_2 -= dy2;
- }
- err_1 += dx2;
- err_2 += dz2;
- pixel[1] += y_inc;
- }
- }
- else {
- err_1 = dy2 - n;
- err_2 = dx2 - n;
- for (i = 0; i < n; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) {
- break;
- }
- if (err_1 > 0) {
- pixel[1] += y_inc;
- err_1 -= dz2;
- }
- if (err_2 > 0) {
- pixel[0] += x_inc;
- err_2 -= dz2;
- }
- err_1 += dy2;
- err_2 += dx2;
- pixel[2] += z_inc;
- }
- }
- cb(result, input, res, pixel, tRay, correct);
-}
-
-static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer)
-{
- float bv[6] = {0};
- float light[3];
- int a, z, slabsize = sds->res[0] * sds->res[1], size = sds->res[0] * sds->res[1] * sds->res[2];
- float *density = smoke_get_density(sds->fluid);
- float correct = -7.0f * sds->dx;
-
- if (!get_light(view_layer, light)) {
- return;
- }
-
- /* convert light pos to sim cell space */
- mul_m4_v3(sds->imat, light);
- light[0] = (light[0] - sds->p0[0]) / sds->cell_size[0] - 0.5f - (float)sds->res_min[0];
- light[1] = (light[1] - sds->p0[1]) / sds->cell_size[1] - 0.5f - (float)sds->res_min[1];
- light[2] = (light[2] - sds->p0[2]) / sds->cell_size[2] - 0.5f - (float)sds->res_min[2];
-
- for (a = 0; a < size; a++) {
- sds->shadow[a] = -1.0f;
- }
-
- /* calculate domain bounds in sim cell space */
- // 0,2,4 = 0.0f
- bv[1] = (float)sds->res[0]; // x
- bv[3] = (float)sds->res[1]; // y
- bv[5] = (float)sds->res[2]; // z
-
- for (z = 0; z < sds->res[2]; z++) {
- size_t index = z * slabsize;
- int x, y;
-
- for (y = 0; y < sds->res[1]; y++) {
- for (x = 0; x < sds->res[0]; x++, index++) {
- float voxelCenter[3];
- float pos[3];
- int cell[3];
- float tRay = 1.0;
-
- if (sds->shadow[index] >= 0.0f) {
- continue;
- }
- voxelCenter[0] = (float)x;
- voxelCenter[1] = (float)y;
- voxelCenter[2] = (float)z;
-
- // get starting cell (light pos)
- if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) {
- // we're ouside -> use point on side of domain
- cell[0] = (int)floor(pos[0]);
- cell[1] = (int)floor(pos[1]);
- cell[2] = (int)floor(pos[2]);
- }
- else {
- // we're inside -> use light itself
- cell[0] = (int)floor(light[0]);
- cell[1] = (int)floor(light[1]);
- cell[2] = (int)floor(light[2]);
- }
- /* clamp within grid bounds */
- CLAMP(cell[0], 0, sds->res[0] - 1);
- CLAMP(cell[1], 0, sds->res[1] - 1);
- CLAMP(cell[2], 0, sds->res[2] - 1);
-
- bresenham_linie_3D(cell[0],
- cell[1],
- cell[2],
- x,
- y,
- z,
- &tRay,
- calc_voxel_transp,
- sds->shadow,
- density,
- sds->res,
- correct);
-
- // convention -> from a RGBA float array, use G value for tRay
- sds->shadow[index] = tRay;
- }
- }
- }
-}
-
-/* get smoke velocity and density at given coordinates
- * returns fluid density or -1.0f if outside domain. */
-float BKE_smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
-{
- SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke);
- zero_v3(velocity);
-
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && smd->domain->fluid) {
- SmokeDomainSettings *sds = smd->domain;
- float time_mult = 25.f * DT_DEFAULT;
- float vel_mag;
- float *velX = smoke_get_velocity_x(sds->fluid);
- float *velY = smoke_get_velocity_y(sds->fluid);
- float *velZ = smoke_get_velocity_z(sds->fluid);
- float density = 0.0f, fuel = 0.0f;
- float pos[3];
- copy_v3_v3(pos, position);
- smoke_pos_to_cell(sds, pos);
-
- /* check if point is outside domain max bounds */
- if (pos[0] < sds->res_min[0] || pos[1] < sds->res_min[1] || pos[2] < sds->res_min[2]) {
- return -1.0f;
- }
- if (pos[0] > sds->res_max[0] || pos[1] > sds->res_max[1] || pos[2] > sds->res_max[2]) {
- return -1.0f;
- }
-
- /* map pos between 0.0 - 1.0 */
- pos[0] = (pos[0] - sds->res_min[0]) / ((float)sds->res[0]);
- pos[1] = (pos[1] - sds->res_min[1]) / ((float)sds->res[1]);
- pos[2] = (pos[2] - sds->res_min[2]) / ((float)sds->res[2]);
-
- /* check if point is outside active area */
- if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) {
- return 0.0f;
- }
- if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) {
- return 0.0f;
- }
- }
-
- /* get interpolated velocity */
- velocity[0] = BLI_voxel_sample_trilinear(velX, sds->res, pos) * sds->global_size[0] *
- time_mult;
- velocity[1] = BLI_voxel_sample_trilinear(velY, sds->res, pos) * sds->global_size[1] *
- time_mult;
- velocity[2] = BLI_voxel_sample_trilinear(velZ, sds->res, pos) * sds->global_size[2] *
- time_mult;
-
- /* convert velocity direction to global space */
- vel_mag = len_v3(velocity);
- mul_mat3_m4_v3(sds->obmat, velocity);
- normalize_v3(velocity);
- mul_v3_fl(velocity, vel_mag);
-
- /* use max value of fuel or smoke density */
- density = BLI_voxel_sample_trilinear(smoke_get_density(sds->fluid), sds->res, pos);
- if (smoke_has_fuel(sds->fluid)) {
- fuel = BLI_voxel_sample_trilinear(smoke_get_fuel(sds->fluid), sds->res, pos);
- }
- return MAX2(density, fuel);
- }
- return -1.0f;
-}
-
-int BKE_smoke_get_data_flags(SmokeDomainSettings *sds)
-{
- int flags = 0;
-
- if (sds->fluid) {
- if (smoke_has_heat(sds->fluid)) {
- flags |= SM_ACTIVE_HEAT;
- }
- if (smoke_has_fuel(sds->fluid)) {
- flags |= SM_ACTIVE_FIRE;
- }
- if (smoke_has_colors(sds->fluid)) {
- flags |= SM_ACTIVE_COLORS;
- }
- }
-
- return flags;
-}
-
-#endif /* WITH_SMOKE */
-
-bool BKE_smoke_show_highres(Scene *scene, SmokeDomainSettings *sds)
-{
- if ((sds->viewsettings & MOD_SMOKE_VIEW_SHOW_HIGHRES) == 0) {
- return false;
- }
- if (scene->r.mode & R_SIMPLIFY) {
- return !scene->r.simplify_smoke_ignore_highres;
- }
- return true;
-}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 44039ad59ee..a89788b2177 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -85,7 +85,7 @@
#include "DNA_sdna_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_speaker_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
@@ -5342,12 +5342,12 @@ static void lib_link_object(FileData *fd, Main *main)
}
{
- SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob,
- eModifierType_Smoke);
+ MantaModifierData *mmd = (MantaModifierData *)modifiers_findByType(ob,
+ eModifierType_Manta);
- if (smd && (smd->type == MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- smd->domain->flags |=
- MOD_SMOKE_FILE_LOAD; /* flag for refreshing the simulation after loading */
+ if (mmd && (mmd->type == MOD_MANTA_TYPE_DOMAIN) && mmd->domain) {
+ mmd->domain->flags |=
+ FLUID_DOMAIN_FILE_LOAD; /* flag for refreshing the simulation after loading */
}
}
@@ -5516,82 +5516,81 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
fluidmd->fss->meshVelocities = NULL;
}
}
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
-
- if (smd->type == MOD_SMOKE_TYPE_DOMAIN) {
- smd->flow = NULL;
- smd->coll = NULL;
- smd->domain = newdataadr(fd, smd->domain);
- smd->domain->smd = smd;
-
- smd->domain->fluid = NULL;
- smd->domain->fluid_mutex = BLI_rw_mutex_alloc();
- smd->domain->wt = NULL;
- smd->domain->shadow = NULL;
- smd->domain->tex = NULL;
- smd->domain->tex_shadow = NULL;
- smd->domain->tex_flame = NULL;
- smd->domain->tex_flame_coba = NULL;
- smd->domain->tex_coba = NULL;
- smd->domain->tex_field = NULL;
- smd->domain->tex_velocity_x = NULL;
- smd->domain->tex_velocity_y = NULL;
- smd->domain->tex_velocity_z = NULL;
- smd->domain->tex_wt = NULL;
- smd->domain->coba = newdataadr(fd, smd->domain->coba);
-
- smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights);
- if (!smd->domain->effector_weights) {
- smd->domain->effector_weights = BKE_effector_add_weights(NULL);
+ else if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+
+ if (mmd->type == MOD_MANTA_TYPE_DOMAIN) {
+ mmd->flow = NULL;
+ mmd->effec = NULL;
+ mmd->domain = newdataadr(fd, mmd->domain);
+ mmd->domain->mmd = mmd;
+
+ mmd->domain->fluid = NULL;
+ mmd->domain->fluid_mutex = BLI_rw_mutex_alloc();
+ mmd->domain->tex = NULL;
+ mmd->domain->tex_shadow = NULL;
+ mmd->domain->tex_flame = NULL;
+ mmd->domain->tex_flame_coba = NULL;
+ mmd->domain->tex_coba = NULL;
+ mmd->domain->tex_field = NULL;
+ mmd->domain->tex_velocity_x = NULL;
+ mmd->domain->tex_velocity_y = NULL;
+ mmd->domain->tex_velocity_z = NULL;
+ mmd->domain->tex_wt = NULL;
+ mmd->domain->mesh_velocities = NULL;
+ mmd->domain->coba = newdataadr(fd, mmd->domain->coba);
+
+ mmd->domain->effector_weights = newdataadr(fd, mmd->domain->effector_weights);
+ if (!mmd->domain->effector_weights) {
+ mmd->domain->effector_weights = BKE_effector_add_weights(NULL);
}
direct_link_pointcache_list(
- fd, &(smd->domain->ptcaches[0]), &(smd->domain->point_cache[0]), 1);
+ fd, &(mmd->domain->ptcaches[0]), &(mmd->domain->point_cache[0]), 1);
- /* Smoke uses only one cache from now on, so store pointer convert */
- if (smd->domain->ptcaches[1].first || smd->domain->point_cache[1]) {
- if (smd->domain->point_cache[1]) {
- PointCache *cache = newdataadr(fd, smd->domain->point_cache[1]);
+ /* Manta sim uses only one cache from now on, so store pointer convert */
+ if (mmd->domain->ptcaches[1].first || mmd->domain->point_cache[1]) {
+ if (mmd->domain->point_cache[1]) {
+ PointCache *cache = newdataadr(fd, mmd->domain->point_cache[1]);
if (cache->flag & PTCACHE_FAKE_SMOKE) {
- /* Smoke was already saved in "new format" and this cache is a fake one. */
+ /* Mantasim / smoke was already saved in "new format" and this cache is a fake one. */
}
else {
printf(
- "High resolution smoke cache not available due to pointcache update. Please "
+ "High resolution manta cache not available due to pointcache update. Please "
"reset the simulation.\n");
}
BKE_ptcache_free(cache);
}
- BLI_listbase_clear(&smd->domain->ptcaches[1]);
- smd->domain->point_cache[1] = NULL;
- }
- }
- else if (smd->type == MOD_SMOKE_TYPE_FLOW) {
- smd->domain = NULL;
- smd->coll = NULL;
- smd->flow = newdataadr(fd, smd->flow);
- smd->flow->smd = smd;
- smd->flow->mesh = NULL;
- smd->flow->verts_old = NULL;
- smd->flow->numverts = 0;
- smd->flow->psys = newdataadr(fd, smd->flow->psys);
- }
- else if (smd->type == MOD_SMOKE_TYPE_COLL) {
- smd->flow = NULL;
- smd->domain = NULL;
- smd->coll = newdataadr(fd, smd->coll);
- if (smd->coll) {
- smd->coll->smd = smd;
- smd->coll->verts_old = NULL;
- smd->coll->numverts = 0;
- smd->coll->mesh = NULL;
+ BLI_listbase_clear(&mmd->domain->ptcaches[1]);
+ mmd->domain->point_cache[1] = NULL;
+ }
+ }
+ else if (mmd->type == MOD_MANTA_TYPE_FLOW) {
+ mmd->domain = NULL;
+ mmd->effec = NULL;
+ mmd->flow = newdataadr(fd, mmd->flow);
+ mmd->flow->mmd = mmd;
+ mmd->flow->mesh = NULL;
+ mmd->flow->verts_old = NULL;
+ mmd->flow->numverts = 0;
+ mmd->flow->psys = newdataadr(fd, mmd->flow->psys);
+ }
+ else if (mmd->type == MOD_MANTA_TYPE_EFFEC) {
+ mmd->flow = NULL;
+ mmd->domain = NULL;
+ mmd->effec = newdataadr(fd, mmd->effec);
+ if (mmd->effec) {
+ mmd->effec->mmd = mmd;
+ mmd->effec->verts_old = NULL;
+ mmd->effec->numverts = 0;
+ mmd->effec->mesh = NULL;
}
else {
- smd->type = 0;
- smd->flow = NULL;
- smd->domain = NULL;
- smd->coll = NULL;
+ mmd->type = 0;
+ mmd->flow = NULL;
+ mmd->domain = NULL;
+ mmd->effec = NULL;
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 17facb3ae20..9b337569cde 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -50,7 +50,7 @@
#include "DNA_screen_types.h"
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_world_types.h"
@@ -1789,19 +1789,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- smd->domain->vorticity = 2.0f;
- smd->domain->time_scale = 1.0f;
+ if ((mmd->type & MOD_MANTA_TYPE_DOMAIN) && mmd->domain) {
+ mmd->domain->vorticity = 2.0f;
+ mmd->domain->time_scale = 1.0f;
- if (!(smd->domain->flags & (1 << 4))) {
+ if (!(mmd->domain->flags & (1 << 4))) {
continue;
}
/* delete old MOD_SMOKE_INITVELOCITY flag */
- smd->domain->flags &= ~(1 << 4);
+ mmd->domain->flags &= ~(1 << 4);
/* for now just add it to all flow objects in the scene */
{
@@ -1809,19 +1809,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
for (ob2 = bmain->objects.first; ob2; ob2 = ob2->id.next) {
ModifierData *md2;
for (md2 = ob2->modifiers.first; md2; md2 = md2->next) {
- if (md2->type == eModifierType_Smoke) {
- SmokeModifierData *smd2 = (SmokeModifierData *)md2;
+ if (md2->type == eModifierType_Manta) {
+ MantaModifierData *mmd2 = (MantaModifierData *)md2;
- if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
- smd2->flow->flags |= MOD_SMOKE_FLOW_INITVELOCITY;
+ if ((mmd2->type & MOD_MANTA_TYPE_FLOW) && mmd2->flow) {
+ mmd2->flow->flags |= FLUID_FLOW_INITVELOCITY;
}
}
}
}
}
}
- else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
- smd->flow->vel_multi = 1.0f;
+ else if ((mmd->type & MOD_MANTA_TYPE_FLOW) && mmd->flow) {
+ mmd->flow->vel_multi = 1.0f;
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 7b0aab99aea..aca866d50b4 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -39,7 +39,7 @@
#include "DNA_view3d_types.h"
#include "DNA_screen_types.h"
#include "DNA_sdna_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_space_types.h"
#include "MEM_guardedalloc.h"
@@ -1284,12 +1284,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- int maxres = max_iii(smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]);
- smd->domain->scale = smd->domain->dx * maxres;
- smd->domain->dx = 1.0f / smd->domain->scale;
+ if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ if ((mmd->type & MOD_MANTA_TYPE_DOMAIN) && mmd->domain) {
+ int maxres = max_iii(mmd->domain->res[0], mmd->domain->res[1], mmd->domain->res[2]);
+ mmd->domain->scale = mmd->domain->dx * maxres;
+ mmd->domain->dx = 1.0f / mmd->domain->scale;
}
}
}
@@ -1602,31 +1602,31 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
+ if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ if ((mmd->type & MOD_MANTA_TYPE_DOMAIN) && mmd->domain) {
/* keep branch saves if possible */
- if (!smd->domain->flame_max_temp) {
- smd->domain->burning_rate = 0.75f;
- smd->domain->flame_smoke = 1.0f;
- smd->domain->flame_vorticity = 0.5f;
- smd->domain->flame_ignition = 1.25f;
- smd->domain->flame_max_temp = 1.75f;
- smd->domain->adapt_threshold = 0.02f;
- smd->domain->adapt_margin = 4;
- smd->domain->flame_smoke_color[0] = 0.7f;
- smd->domain->flame_smoke_color[1] = 0.7f;
- smd->domain->flame_smoke_color[2] = 0.7f;
+ if (!mmd->domain->flame_max_temp) {
+ mmd->domain->burning_rate = 0.75f;
+ mmd->domain->flame_smoke = 1.0f;
+ mmd->domain->flame_vorticity = 0.5f;
+ mmd->domain->flame_ignition = 1.25f;
+ mmd->domain->flame_max_temp = 1.75f;
+ mmd->domain->adapt_threshold = 0.02f;
+ mmd->domain->adapt_margin = 4;
+ mmd->domain->flame_smoke_color[0] = 0.7f;
+ mmd->domain->flame_smoke_color[1] = 0.7f;
+ mmd->domain->flame_smoke_color[2] = 0.7f;
}
}
- else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
- if (!smd->flow->texture_size) {
- smd->flow->fuel_amount = 1.0;
- smd->flow->surface_distance = 1.5;
- smd->flow->color[0] = 0.7f;
- smd->flow->color[1] = 0.7f;
- smd->flow->color[2] = 0.7f;
- smd->flow->texture_size = 1.0f;
+ else if ((mmd->type & MOD_MANTA_TYPE_FLOW) && mmd->flow) {
+ if (!mmd->flow->texture_size) {
+ mmd->flow->fuel_amount = 1.0;
+ mmd->flow->surface_distance = 1.5;
+ mmd->flow->color[0] = 0.7f;
+ mmd->flow->color[1] = 0.7f;
+ mmd->flow->color[2] = 0.7f;
+ mmd->flow->texture_size = 1.0f;
}
}
}
@@ -2132,14 +2132,14 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- if (smd->domain->flags & MOD_SMOKE_HIGH_SMOOTH) {
- smd->domain->highres_sampling = SM_HRES_LINEAR;
+ if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ if ((mmd->type & MOD_MANTA_TYPE_DOMAIN) && mmd->domain) {
+ if (mmd->domain->flags & FLUID_DOMAIN_USE_HIGH_SMOOTH) {
+ mmd->domain->highres_sampling = SM_HRES_LINEAR;
}
else {
- smd->domain->highres_sampling = SM_HRES_NEAREST;
+ mmd->domain->highres_sampling = SM_HRES_NEAREST;
}
}
}
@@ -2199,11 +2199,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
- if (!smd->flow->particle_size) {
- smd->flow->particle_size = 1.0f;
+ if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ if ((mmd->type & MOD_MANTA_TYPE_FLOW) && mmd->flow) {
+ if (!mmd->flow->particle_size) {
+ mmd->flow->particle_size = 1.0f;
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 9d9906fc3e0..1b41c0cf1b1 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -46,7 +46,7 @@
#include "DNA_particle_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_view3d_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_genfile.h"
@@ -1547,18 +1547,18 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- if (!DNA_struct_elem_find(fd->filesdna, "SmokeModifierData", "float", "slice_per_voxel")) {
+ if (!DNA_struct_elem_find(fd->filesdna, "MantaModifierData", "float", "slice_per_voxel")) {
Object *ob;
ModifierData *md;
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->domain) {
- smd->domain->slice_per_voxel = 5.0f;
- smd->domain->slice_depth = 0.5f;
- smd->domain->display_thickness = 1.0f;
+ if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ if (mmd->domain) {
+ mmd->domain->slice_per_voxel = 5.0f;
+ mmd->domain->slice_depth = 0.5f;
+ mmd->domain->display_thickness = 1.0f;
}
}
}
@@ -1717,16 +1717,16 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 279, 3)) {
- if (!DNA_struct_elem_find(fd->filesdna, "SmokeDomainSettings", "float", "clipping")) {
+ if (!DNA_struct_elem_find(fd->filesdna, "MantaDomainSettings", "float", "clipping")) {
Object *ob;
ModifierData *md;
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->domain) {
- smd->domain->clipping = 1e-3f;
+ if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ if (mmd->domain) {
+ mmd->domain->clipping = 1e-3f;
}
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 5954ba9cf8e..3a0886412fa 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -125,7 +125,7 @@
#include "DNA_scene_types.h"
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
@@ -1615,38 +1615,38 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
writestruct(wd, DATA, EffectorWeights, 1, clmd->sim_parms->effector_weights);
write_pointcaches(wd, &clmd->ptcaches);
}
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ else if (md->type == eModifierType_Manta) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain);
+ if (mmd->type & MOD_MANTA_TYPE_DOMAIN) {
+ writestruct(wd, DATA, MantaDomainSettings, 1, mmd->domain);
- if (smd->domain) {
- write_pointcaches(wd, &(smd->domain->ptcaches[0]));
+ if (mmd->domain) {
+ write_pointcaches(wd, &(mmd->domain->ptcaches[0]));
/* create fake pointcache so that old blender versions can read it */
- smd->domain->point_cache[1] = BKE_ptcache_add(&smd->domain->ptcaches[1]);
- smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE;
- smd->domain->point_cache[1]->step = 1;
+ mmd->domain->point_cache[1] = BKE_ptcache_add(&mmd->domain->ptcaches[1]);
+ mmd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE;
+ mmd->domain->point_cache[1]->step = 1;
- write_pointcaches(wd, &(smd->domain->ptcaches[1]));
+ write_pointcaches(wd, &(mmd->domain->ptcaches[1]));
- if (smd->domain->coba) {
- writestruct(wd, DATA, ColorBand, 1, smd->domain->coba);
+ if (mmd->domain->coba) {
+ writestruct(wd, DATA, ColorBand, 1, mmd->domain->coba);
}
/* cleanup the fake pointcache */
- BKE_ptcache_free_list(&smd->domain->ptcaches[1]);
- smd->domain->point_cache[1] = NULL;
+ BKE_ptcache_free_list(&mmd->domain->ptcaches[1]);
+ mmd->domain->point_cache[1] = NULL;
- writestruct(wd, DATA, EffectorWeights, 1, smd->domain->effector_weights);
+ writestruct(wd, DATA, EffectorWeights, 1, mmd->domain->effector_weights);
}
}
- else if (smd->type & MOD_SMOKE_TYPE_FLOW) {
- writestruct(wd, DATA, SmokeFlowSettings, 1, smd->flow);
+ else if (mmd->type & MOD_MANTA_TYPE_FLOW) {
+ writestruct(wd, DATA, MantaFlowSettings, 1, mmd->flow);
}
- else if (smd->type & MOD_SMOKE_TYPE_COLL) {
- writestruct(wd, DATA, SmokeCollSettings, 1, smd->coll);
+ else if (mmd->type & MOD_MANTA_TYPE_EFFEC) {
+ writestruct(wd, DATA, MantaCollSettings, 1, mmd->effec);
}
}
else if (md->type == eModifierType_Fluidsim) {
diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc
index 3f81e49b170..ae3ccc23ea1 100644
--- a/source/blender/depsgraph/intern/depsgraph_physics.cc
+++ b/source/blender/depsgraph/intern/depsgraph_physics.cc
@@ -54,7 +54,7 @@ static ePhysicsRelationType modifier_to_relation_type(unsigned int modifier_type
switch (modifier_type) {
case eModifierType_Collision:
return DEG_PHYSICS_COLLISION;
- case eModifierType_Smoke:
+ case eModifierType_Manta:
return DEG_PHYSICS_SMOKE_COLLISION;
case eModifierType_DynamicPaint:
return DEG_PHYSICS_DYNAMIC_BRUSH;
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index f85c30044a9..7237ac5bdd6 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -28,12 +28,12 @@
#include "BLI_string_utils.h"
#include "DNA_object_force_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_world_types.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
-#include "BKE_smoke.h"
+#include "BKE_manta.h"
#include "ED_screen.h"
@@ -63,7 +63,7 @@ static struct {
GPUTexture *dummy_scatter;
GPUTexture *dummy_transmit;
- /* List of all smoke domains rendered within this frame. */
+ /* List of all fluid simulation / smoke domains rendered within this frame. */
ListBase smoke_domains;
} e_data = {NULL}; /* Engine data */
@@ -423,41 +423,41 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
/* Smoke Simulation */
if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (md = modifiers_findByType(ob, eModifierType_Manta)) &&
(modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- ((SmokeModifierData *)md)->domain != NULL) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- SmokeDomainSettings *sds = smd->domain;
+ ((MantaModifierData *)md)->domain != NULL) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ MantaDomainSettings *mds = mmd->domain;
/* Don't show smoke before simulation starts, this could be made an option in the future. */
- const bool show_smoke = ((int)DEG_get_ctime(draw_ctx->depsgraph) >=
- sds->point_cache[0]->startframe);
+ /* (sebbas): Always show smoke for manta */
+ /* const bool show_smoke = ((int)DEG_get_ctime(draw_ctx->depsgraph) >= mds->point_cache[0]->startframe); */
- if (sds->fluid && show_smoke) {
- const bool show_highres = BKE_smoke_show_highres(scene, sds);
- if (!sds->wt || !show_highres) {
- GPU_create_smoke(smd, 0);
+ if (mds->fluid && (mds->type == FLUID_DOMAIN_TYPE_GAS) /* && show_smoke */) {
+ if (!(mds->flags & FLUID_DOMAIN_USE_NOISE)) {
+ GPU_create_smoke(mmd, 0);
}
- else if (sds->wt && show_highres) {
- GPU_create_smoke(smd, 1);
+ else if (mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ GPU_create_smoke(mmd, 1);
}
- BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(smd));
+ BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(mmd));
}
DRW_shgroup_uniform_texture_ref(
- grp, "sampdensity", sds->tex ? &sds->tex : &e_data.dummy_density);
+ grp, "sampdensity", mds->tex ? &mds->tex : &e_data.dummy_density);
DRW_shgroup_uniform_texture_ref(
- grp, "sampflame", sds->tex_flame ? &sds->tex_flame : &e_data.dummy_flame);
+ grp, "sampflame", mds->tex_flame ? &mds->tex_flame : &e_data.dummy_flame);
/* Constant Volume color. */
- bool use_constant_color = ((sds->active_fields & SM_ACTIVE_COLORS) == 0 &&
- (sds->active_fields & SM_ACTIVE_COLOR_SET) != 0);
+ static float white[3] = {1.0f, 1.0f, 1.0f};
+ bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
+ (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
DRW_shgroup_uniform_vec3(
- grp, "volumeColor", (use_constant_color) ? sds->active_color : white, 1);
+ grp, "volumeColor", (use_constant_color) ? mds->active_color : white, 1);
/* Output is such that 0..1 maps to 0..1000K */
- DRW_shgroup_uniform_vec2(grp, "unftemperature", &sds->flame_ignition, 1);
+ DRW_shgroup_uniform_vec2(grp, "unftemperature", &mds->flame_ignition, 1);
}
else {
DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density);
@@ -653,8 +653,8 @@ void EEVEE_volumes_free_smoke_textures(void)
{
/* Free Smoke Textures after rendering */
for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) {
- SmokeModifierData *smd = (SmokeModifierData *)link->data;
- GPU_free_smoke(smd);
+ MantaModifierData *mmd = (MantaModifierData *)link->data;
+ GPU_free_smoke(mmd);
}
BLI_freelistN(&e_data.smoke_domains);
}
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index 735a0dcf7a0..1c2b56af3c7 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -1004,9 +1004,9 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
ModifierData *md;
if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (md = modifiers_findByType(ob, eModifierType_Manta)) &&
(modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- (((SmokeModifierData *)md)->domain != NULL)) {
+ (((MantaModifierData *)md)->domain != NULL)) {
workbench_volume_cache_populate(vedata, scene, ob, md);
return; /* Do not draw solid in this case. */
}
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index 4c1fce550e8..af32122fa50 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -609,9 +609,9 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
ModifierData *md;
if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (md = modifiers_findByType(ob, eModifierType_Manta)) &&
(modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- (((SmokeModifierData *)md)->domain != NULL)) {
+ (((MantaModifierData *)md)->domain != NULL)) {
workbench_volume_cache_populate(vedata, scene, ob, md);
return; /* Do not draw solid in this case. */
}
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 575da1f9683..cacb5927307 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -23,14 +23,14 @@
#include "workbench_private.h"
#include "BKE_object.h"
-#include "BKE_smoke.h"
+#include "BKE_manta.h"
#include "BLI_rand.h"
#include "BLI_dynstr.h"
#include "DNA_modifier_types.h"
#include "DNA_object_force_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "GPU_draw.h"
@@ -119,53 +119,52 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
Object *ob,
ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
- SmokeDomainSettings *sds = smd->domain;
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ MantaDomainSettings *mds = mmd->domain;
WORKBENCH_PrivateData *wpd = vedata->stl->g_data;
WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
DRWShadingGroup *grp = NULL;
- /* Don't show smoke before simulation starts, this could be made an option in the future. */
- if (!sds->fluid || CFRA < sds->point_cache[0]->startframe) {
+ /* Don't try to show liquid domains here */
+ if (!mds->fluid || !(mds->type == FLUID_DOMAIN_TYPE_GAS)) {
return;
}
wpd->volumes_do = true;
- const bool show_highres = BKE_smoke_show_highres(scene, sds);
- if (sds->use_coba) {
- GPU_create_smoke_coba_field(smd);
+ if (mds->use_coba) {
+ GPU_create_smoke_coba_field(mmd);
}
- else if (!sds->wt || !show_highres) {
- GPU_create_smoke(smd, 0);
+ else if (!(mds->flags & FLUID_DOMAIN_USE_NOISE)) {
+ GPU_create_smoke(mmd, 0);
}
- else if (sds->wt && show_highres) {
- GPU_create_smoke(smd, 1);
+ else if (mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ GPU_create_smoke(mmd, 1);
}
- if ((!sds->use_coba && sds->tex == NULL) || (sds->use_coba && sds->tex_field == NULL)) {
+ if ((!mds->use_coba && mds->tex == NULL) || (mds->use_coba && mds->tex_field == NULL)) {
return;
}
- const bool use_slice = (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
- sds->axis_slice_method == AXIS_SLICE_SINGLE);
- const bool cubic_interp = (sds->interp_method == VOLUME_INTERP_CUBIC);
- GPUShader *sh = volume_shader_get(use_slice, sds->use_coba, cubic_interp);
+ const bool use_slice = (mds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED &&
+ mds->axis_slice_method == AXIS_SLICE_SINGLE);
+ const bool cubic_interp = (mds->interp_method == VOLUME_INTERP_CUBIC);
+ GPUShader *sh = volume_shader_get(use_slice, mds->use_coba, cubic_interp);
if (use_slice) {
float invviewmat[4][4];
DRW_view_viewmat_get(NULL, invviewmat, true);
- const int axis = (sds->slice_axis == SLICE_AXIS_AUTO) ?
+ const int axis = (mds->slice_axis == SLICE_AXIS_AUTO) ?
axis_dominant_v3_single(invviewmat[2]) :
- sds->slice_axis - 1;
+ mds->slice_axis - 1;
float dim[3];
BKE_object_dimensions_get(ob, dim);
/* 0.05f to acheive somewhat the same opacity as the full view. */
float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
- DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth);
+ DRW_shgroup_uniform_float_copy(grp, "slicePosition", mds->slice_depth);
DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
DRW_shgroup_state_disable(grp, DRW_STATE_CULL_FRONT);
@@ -174,8 +173,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
double noise_ofs;
BLI_halton_1d(3, 0.0, effect_info->jitter_index, &noise_ofs);
float dim[3], step_length, max_slice;
- float slice_ct[3] = {sds->res[0], sds->res[1], sds->res[2]};
- mul_v3_fl(slice_ct, max_ff(0.001f, sds->slice_per_voxel));
+ float slice_ct[3] = {mds->res[0], mds->res[1], mds->res[2]};
+ mul_v3_fl(slice_ct, max_ff(0.001f, mds->slice_per_voxel));
max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]);
BKE_object_dimensions_get(ob, dim);
invert_v3(slice_ct);
@@ -190,25 +189,25 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
}
- if (sds->use_coba) {
- DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex_field);
- DRW_shgroup_uniform_texture(grp, "transferTexture", sds->tex_coba);
+ if (mds->use_coba) {
+ DRW_shgroup_uniform_texture(grp, "densityTexture", mds->tex_field);
+ DRW_shgroup_uniform_texture(grp, "transferTexture", mds->tex_coba);
}
else {
static float white[3] = {1.0f, 1.0f, 1.0f};
- bool use_constant_color = ((sds->active_fields & SM_ACTIVE_COLORS) == 0 &&
- (sds->active_fields & SM_ACTIVE_COLOR_SET) != 0);
- DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex);
- DRW_shgroup_uniform_texture(grp, "shadowTexture", sds->tex_shadow);
+ bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
+ (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
+ DRW_shgroup_uniform_texture(grp, "densityTexture", mds->tex);
+ DRW_shgroup_uniform_texture(grp, "shadowTexture", mds->tex_shadow);
DRW_shgroup_uniform_texture(
- grp, "flameTexture", (sds->tex_flame) ? sds->tex_flame : e_data.dummy_tex);
+ grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : e_data.dummy_tex);
DRW_shgroup_uniform_texture(
- grp, "flameColorTexture", (sds->tex_flame) ? sds->tex_flame_coba : e_data.dummy_coba_tex);
+ grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : e_data.dummy_coba_tex);
DRW_shgroup_uniform_vec3(
- grp, "activeColor", (use_constant_color) ? sds->active_color : white, 1);
+ grp, "activeColor", (use_constant_color) ? mds->active_color : white, 1);
}
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
- DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * sds->display_thickness);
+ DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * mds->display_thickness);
if (use_slice) {
DRW_shgroup_call(grp, DRW_cache_quad_get(), ob);
@@ -217,7 +216,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
DRW_shgroup_call(grp, DRW_cache_cube_get(), ob);
}
- BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(smd));
+ BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(mmd));
}
void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
@@ -229,8 +228,8 @@ void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
* modifier is not used for display. We should share them for
* all viewport in a redraw at least. */
for (LinkData *link = wpd->smoke_domains.first; link; link = link->next) {
- SmokeModifierData *smd = (SmokeModifierData *)link->data;
- GPU_free_smoke(smd);
+ MantaModifierData *mmd = (MantaModifierData *)link->data;
+ GPU_free_smoke(mmd);
}
BLI_freelistN(&wpd->smoke_domains);
}
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index 9fc11e4f36f..2b86747fdc2 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -36,7 +36,7 @@
#include "DNA_lightprobe_types.h"
#include "DNA_particle_types.h"
#include "DNA_rigidbody_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_view3d_types.h"
#include "DNA_screen_types.h"
#include "DNA_world_types.h"
@@ -2690,63 +2690,71 @@ static void DRW_shgroup_volume_extra(OBJECT_ShadingGroupList *sgl,
Scene *scene,
ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
- SmokeDomainSettings *sds = smd->domain;
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ MantaDomainSettings *mds = mmd->domain;
float *color;
float one = 1.0f;
- if (sds == NULL) {
+ if (mds == NULL) {
return;
}
DRW_object_wire_theme_get(ob, view_layer, &color);
- /* Small cube showing voxel size. */
+ /* Small cube showing voxel size (adjusts with adaptive domain) */
+ float min[3], max[3], size[3];
+ madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, mds->cell_size, mds->res_min);
+ madd_v3fl_v3fl_v3fl_v3i(max, mds->p0, mds->cell_size, mds->res_max);
+ sub_v3_v3v3(size, max, min);
float voxel_cubemat[4][4] = {{0.0f}};
- voxel_cubemat[0][0] = 1.0f / (float)sds->res[0];
- voxel_cubemat[1][1] = 1.0f / (float)sds->res[1];
- voxel_cubemat[2][2] = 1.0f / (float)sds->res[2];
- voxel_cubemat[3][0] = voxel_cubemat[3][1] = voxel_cubemat[3][2] = -1.0f;
+ /* scale small cube */
+ voxel_cubemat[0][0] = (1.0f / (float)mds->res[0]) * size[0] * ob->obmat[0][0] * 0.5;
+ voxel_cubemat[1][1] = (1.0f / (float)mds->res[1]) * size[1] * ob->obmat[1][1] * 0.5;
+ voxel_cubemat[2][2] = (1.0f / (float)mds->res[2]) * size[2] * ob->obmat[2][2] * 0.5;
+ /* translate small cube */
+ voxel_cubemat[3][0] = min[0] * ob->obmat[0][0] + ob->obmat[3][0];
+ voxel_cubemat[3][1] = min[1] * ob->obmat[1][1] + ob->obmat[3][1];
+ voxel_cubemat[3][2] = min[2] * ob->obmat[2][2] + ob->obmat[3][2];
voxel_cubemat[3][3] = 1.0f;
+ /* move small cube into the domain (before centered on vertex) */
translate_m4(voxel_cubemat, 1.0f, 1.0f, 1.0f);
- mul_m4_m4m4(voxel_cubemat, ob->obmat, voxel_cubemat);
DRW_buffer_add_entry(sgl->empties.cube, color, &one, voxel_cubemat);
/* Don't show smoke before simulation starts, this could be made an option in the future. */
- if (!sds->draw_velocity || !sds->fluid || CFRA < sds->point_cache[0]->startframe) {
+ if (!mds->draw_velocity || !mds->fluid || CFRA < mds->point_cache[0]->startframe) {
return;
}
- const bool use_needle = (sds->vector_draw_type == VECTOR_DRAW_NEEDLE);
+ const bool use_needle = (mds->vector_draw_type == VECTOR_DRAW_NEEDLE);
int line_count = (use_needle) ? 6 : 1;
int slice_axis = -1;
- line_count *= sds->res[0] * sds->res[1] * sds->res[2];
+ line_count *= mds->res[0] * mds->res[1] * mds->res[2];
- if (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
- sds->axis_slice_method == AXIS_SLICE_SINGLE) {
+ if (mds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED &&
+ mds->axis_slice_method == AXIS_SLICE_SINGLE) {
float viewinv[4][4];
DRW_view_viewmat_get(NULL, viewinv, true);
- const int axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewinv[2]) :
- sds->slice_axis - 1;
+ const int axis = (mds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewinv[2]) :
+ mds->slice_axis - 1;
slice_axis = axis;
- line_count /= sds->res[axis];
+ line_count /= mds->res[axis];
}
- GPU_create_smoke_velocity(smd);
+ GPU_create_smoke_velocity(mmd);
DRWShadingGroup *grp = DRW_shgroup_create(volume_velocity_shader_get(use_needle),
sgl->non_meshes);
- DRW_shgroup_uniform_texture(grp, "velocityX", sds->tex_velocity_x);
- DRW_shgroup_uniform_texture(grp, "velocityY", sds->tex_velocity_y);
- DRW_shgroup_uniform_texture(grp, "velocityZ", sds->tex_velocity_z);
- DRW_shgroup_uniform_float_copy(grp, "displaySize", sds->vector_scale);
- DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth);
+ DRW_shgroup_uniform_texture(grp, "velocityX", mds->tex_velocity_x);
+ DRW_shgroup_uniform_texture(grp, "velocityY", mds->tex_velocity_y);
+ DRW_shgroup_uniform_texture(grp, "velocityZ", mds->tex_velocity_z);
+ DRW_shgroup_uniform_float_copy(grp, "displaySize", mds->vector_scale);
+ DRW_shgroup_uniform_float_copy(grp, "slicePosition", mds->slice_depth);
DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis);
DRW_shgroup_call_procedural_lines(grp, ob, line_count);
- BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(smd));
+ BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(mmd));
}
static void volumes_free_smoke_textures(void)
@@ -2758,8 +2766,8 @@ static void volumes_free_smoke_textures(void)
* modifier is not used for display. We should share them for
* all viewport in a redraw at least. */
for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) {
- SmokeModifierData *smd = (SmokeModifierData *)link->data;
- GPU_free_smoke_velocity(smd);
+ MantaModifierData *mmd = (MantaModifierData *)link->data;
+ GPU_free_smoke_velocity(mmd);
}
BLI_freelistN(&e_data.smoke_domains);
}
@@ -3746,9 +3754,9 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
DRW_buffer_add_entry(sgl->empties.empty_axes, color, &axes_size, ob->obmat);
}
- if ((md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ if ((md = modifiers_findByType(ob, eModifierType_Manta)) &&
(modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- (((SmokeModifierData *)md)->domain != NULL)) {
+ (((MantaModifierData *)md)->domain != NULL)) {
DRW_shgroup_volume_extra(sgl, ob, view_layer, scene, md);
}
}
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 69738d2e008..a5897afb548 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -385,9 +385,8 @@ set(ICON_NAMES
mod_mask
mod_cloth
mod_explode
- mod_fluidsim
mod_multires
- mod_smoke
+ mod_manta
mod_solidify
mod_screw
mod_vertex_weight
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 47cf827ed66..5ebad4c3b06 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -557,7 +557,7 @@ DEF_ICON_MODIFIER(MOD_CLOTH)
DEF_ICON_MODIFIER(MOD_EXPLODE)
DEF_ICON_MODIFIER(MOD_FLUIDSIM)
DEF_ICON_MODIFIER(MOD_MULTIRES)
-DEF_ICON_MODIFIER(MOD_SMOKE)
+DEF_ICON_MODIFIER(MOD_MANTA)
DEF_ICON_MODIFIER(MOD_SOLIDIFY)
DEF_ICON_MODIFIER(MOD_SCREW)
DEF_ICON_MODIFIER(MOD_VERTEX_WEIGHT)
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 1fc1af9815f..760d8a42468 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -1749,7 +1749,13 @@ static int modifier_can_delete(ModifierData *md)
{
/* fluid particle modifier can't be deleted here */
if (md->type == eModifierType_ParticleSystem) {
- if (((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID) {
+ if ( ((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID ||
+ ((ParticleSystemModifierData *)md)->psys->part->type == PART_MANTA_FLIP ||
+ ((ParticleSystemModifierData *)md)->psys->part->type == PART_MANTA_FOAM ||
+ ((ParticleSystemModifierData *)md)->psys->part->type == PART_MANTA_SPRAY ||
+ ((ParticleSystemModifierData *)md)->psys->part->type == PART_MANTA_BUBBLE ||
+ ((ParticleSystemModifierData *)md)->psys->part->type == PART_MANTA_BUBBLE)
+ {
return 0;
}
}
@@ -1766,7 +1772,7 @@ static int modifier_is_simulation(ModifierData *md)
eModifierType_Cloth,
eModifierType_Collision,
eModifierType_Fluidsim,
- eModifierType_Smoke,
+ eModifierType_Manta,
eModifierType_Softbody,
eModifierType_Surface,
eModifierType_DynamicPaint)) {
@@ -1999,7 +2005,7 @@ static uiLayout *draw_modifier(uiLayout *layout,
eModifierType_Softbody,
eModifierType_ParticleSystem,
eModifierType_Cloth,
- eModifierType_Smoke)) {
+ eModifierType_Manta)) {
uiItemO(row,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"),
ICON_NONE,
diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt
index 021c17a94c2..740f81c108e 100644
--- a/source/blender/editors/physics/CMakeLists.txt
+++ b/source/blender/editors/physics/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
+ ../../../../intern/mantaflow/extern
)
set(INC_SYS
@@ -39,7 +40,7 @@ set(SRC
particle_edit.c
particle_edit_undo.c
particle_object.c
- physics_fluid.c
+ physics_manta.c
physics_ops.c
physics_pointcache.c
rigidbody_constraint.c
@@ -55,19 +56,9 @@ set(LIB
bf_blenlib
)
-if(WITH_MOD_FLUID)
- list(APPEND INC
- ../../../../intern/elbeem/extern
- )
- list(APPEND LIB
- bf_intern_elbeem
- )
- add_definitions(-DWITH_MOD_FLUID)
-endif()
-
-if(WITH_MOD_SMOKE)
+if(WITH_MOD_MANTA)
list(APPEND LIB
- bf_intern_smoke
+ bf_intern_mantaflow
)
endif()
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index b03ec56c7e4..6b7d02f4def 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -1067,7 +1067,7 @@ static void remove_particle_systems_from_object(Object *ob_to)
if (ELEM(md->type,
eModifierType_ParticleSystem,
eModifierType_DynamicPaint,
- eModifierType_Smoke)) {
+ eModifierType_Manta)) {
BLI_remlink(&ob_to->modifiers, md);
modifier_free(md);
}
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
deleted file mode 100644
index dc3673c972f..00000000000
--- a/source/blender/editors/physics/physics_fluid.c
+++ /dev/null
@@ -1,1247 +0,0 @@
-/*
- * 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) Blender Foundation
- * All rights reserved.
- */
-
-/** \file
- * \ingroup edphys
- */
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include "MEM_guardedalloc.h"
-
-/* types */
-#include "DNA_action_types.h"
-#include "DNA_object_types.h"
-#include "DNA_object_fluidsim_types.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_context.h"
-#include "BKE_customdata.h"
-#include "BKE_fluidsim.h"
-#include "BKE_modifier.h"
-#include "BKE_object.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
-
-#include "DEG_depsgraph.h"
-
-#include "ED_screen.h"
-#include "ED_object.h"
-
-#include "WM_types.h"
-#include "WM_api.h"
-
-#include "physics_intern.h" // own include
-
-/* enable/disable overall compilation */
-#ifdef WITH_MOD_FLUID
-
-# include "LBM_fluidsim.h"
-
-# include "BLI_blenlib.h"
-# include "BLI_path_util.h"
-# include "BLI_math.h"
-
-# include "BKE_global.h"
-# include "BKE_main.h"
-
-# include "WM_api.h"
-
-# include "DNA_scene_types.h"
-# include "DNA_mesh_types.h"
-
-static float get_fluid_viscosity(FluidsimSettings *settings)
-{
- return (1.0f / powf(10.0f, settings->viscosityExponent)) * settings->viscosityValue;
-}
-
-static float get_fluid_rate(FluidsimSettings *settings)
-{
- float rate = 1.0f; /* default rate if not animated... */
-
- rate = settings->animRate;
-
- if (rate < 0.0f) {
- rate = 0.0f;
- }
-
- return rate;
-}
-
-static void get_fluid_gravity(float *gravity, Scene *scene, FluidsimSettings *fss)
-{
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- }
- else {
- copy_v3_v3(gravity, fss->grav);
- }
-}
-
-static float get_fluid_size_m(Scene *scene, Object *domainob, FluidsimSettings *fss)
-{
- if (!scene->unit.system) {
- return fss->realsize;
- }
- else {
- float dim[3];
- float longest_axis;
-
- BKE_object_dimensions_get(domainob, dim);
- longest_axis = max_fff(dim[0], dim[1], dim[2]);
-
- return longest_axis * scene->unit.scale_length;
- }
-}
-
-static bool fluid_is_animated_mesh(FluidsimSettings *fss)
-{
- return ((fss->type == OB_FLUIDSIM_CONTROL) || fss->domainNovecgen);
-}
-
-/* ********************** fluid sim settings struct functions ********************** */
-
-# if 0
-/* helper function */
-void fluidsimGetGeometryObjFilename(Object *ob, char *dst) //, char *srcname)
-{
- //BLI_snprintf(dst, FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name);
- BLI_snprintf(dst, FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name);
-}
-# endif
-
-/* ********************** fluid sim channel helper functions ********************** */
-
-typedef struct FluidAnimChannels {
- int length;
-
- double aniFrameTime;
-
- float *timeAtFrame;
- float *DomainTime;
- float *DomainGravity;
- float *DomainViscosity;
-} FluidAnimChannels;
-
-typedef struct FluidObject {
- struct FluidObject *next, *prev;
-
- struct Object *object;
-
- float *Translation;
- float *Rotation;
- float *Scale;
- float *Active;
-
- float *InitialVelocity;
-
- float *AttractforceStrength;
- float *AttractforceRadius;
- float *VelocityforceStrength;
- float *VelocityforceRadius;
-
- float *VertexCache;
- int numVerts, numTris;
-} FluidObject;
-
-// no. of entries for the two channel sizes
-# define CHANNEL_FLOAT 1
-# define CHANNEL_VEC 3
-
-// simplify channels before printing
-// for API this is done anyway upon init
-# if 0
-static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char *str, int entries)
-{
- int i, j;
- int channelSize = paramsize;
-
- if (entries == 3) {
- elbeemSimplifyChannelVec3(channel, &channelSize);
- }
- else if (entries == 1) {
- elbeemSimplifyChannelFloat(channel, &channelSize);
- }
- else {
- /* invalid, cant happen? */
- }
-
- fprintf(file, " CHANNEL %s =\n", str);
- for (i = 0; i < channelSize; i++) {
- fprintf(file, " ");
- for (j = 0; j <= entries; j++) { // also print time value
- fprintf(file, " %f ", channel[i * (entries + 1) + j]);
- if (j == entries - 1) {
- fprintf(file, " ");
- }
- }
- fprintf(file, "\n");
- }
-
- fprintf(file, " ;\n");
-}
-# endif
-
-/* Note: fluid anim channel data layout
- * ------------------------------------
- * CHANNEL_FLOAT:
- * frame 1 |frame 2
- * [dataF][time][dataF][time]
- *
- * CHANNEL_VEC:
- * frame 1 |frame 2
- * [dataX][dataY][dataZ][time][dataX][dataY][dataZ][time]
- */
-
-static void init_time(FluidsimSettings *domainSettings, FluidAnimChannels *channels)
-{
- int i;
-
- channels->timeAtFrame = MEM_callocN((channels->length + 1) * sizeof(float),
- "timeAtFrame channel");
-
- channels->timeAtFrame[0] = channels->timeAtFrame[1] =
- domainSettings->animStart; // start at index 1
-
- for (i = 2; i <= channels->length; i++) {
- channels->timeAtFrame[i] = channels->timeAtFrame[i - 1] + (float)channels->aniFrameTime;
- }
-}
-
-/* if this is slow, can replace with faster, less readable code */
-static void set_channel(float *channel, float time, float *value, int i, int size)
-{
- if (size == CHANNEL_FLOAT) {
- channel[(i * 2) + 0] = value[0];
- channel[(i * 2) + 1] = time;
- }
- else if (size == CHANNEL_VEC) {
- channel[(i * 4) + 0] = value[0];
- channel[(i * 4) + 1] = value[1];
- channel[(i * 4) + 2] = value[2];
- channel[(i * 4) + 3] = time;
- }
-}
-
-static void set_vertex_channel(Depsgraph *depsgraph,
- float *channel,
- float time,
- struct Scene *scene,
- struct FluidObject *fobj,
- int i)
-{
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- float *verts;
- int *tris = NULL, numVerts = 0, numTris = 0;
- int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd);
- int framesize = (3 * fobj->numVerts) + 1;
- int j;
-
- if (channel == NULL) {
- return;
- }
-
- initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex);
-
- /* don't allow mesh to change number of verts in anim sequence */
- if (numVerts != fobj->numVerts) {
- MEM_freeN(channel);
- channel = NULL;
- return;
- }
-
- /* fill frame of channel with vertex locations */
- for (j = 0; j < (3 * numVerts); j++) {
- channel[i * framesize + j] = verts[j];
- }
- channel[i * framesize + framesize - 1] = time;
-
- MEM_freeN(verts);
- MEM_freeN(tris);
-}
-
-static void free_domain_channels(FluidAnimChannels *channels)
-{
- if (!channels->timeAtFrame) {
- return;
- }
- MEM_freeN(channels->timeAtFrame);
- channels->timeAtFrame = NULL;
- MEM_freeN(channels->DomainGravity);
- channels->DomainGravity = NULL;
- MEM_freeN(channels->DomainViscosity);
- channels->DomainViscosity = NULL;
- MEM_freeN(channels->DomainTime);
- channels->DomainTime = NULL;
-}
-
-static void free_all_fluidobject_channels(ListBase *fobjects)
-{
- FluidObject *fobj;
-
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- if (fobj->Translation) {
- MEM_freeN(fobj->Translation);
- fobj->Translation = NULL;
- MEM_freeN(fobj->Rotation);
- fobj->Rotation = NULL;
- MEM_freeN(fobj->Scale);
- fobj->Scale = NULL;
- MEM_freeN(fobj->Active);
- fobj->Active = NULL;
- MEM_freeN(fobj->InitialVelocity);
- fobj->InitialVelocity = NULL;
- }
-
- if (fobj->AttractforceStrength) {
- MEM_freeN(fobj->AttractforceStrength);
- fobj->AttractforceStrength = NULL;
- MEM_freeN(fobj->AttractforceRadius);
- fobj->AttractforceRadius = NULL;
- MEM_freeN(fobj->VelocityforceStrength);
- fobj->VelocityforceStrength = NULL;
- MEM_freeN(fobj->VelocityforceRadius);
- fobj->VelocityforceRadius = NULL;
- }
-
- if (fobj->VertexCache) {
- MEM_freeN(fobj->VertexCache);
- fobj->VertexCache = NULL;
- }
- }
-}
-
-static void fluid_init_all_channels(bContext *C,
- Object *UNUSED(fsDomain),
- FluidsimSettings *domainSettings,
- FluidAnimChannels *channels,
- ListBase *fobjects)
-{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Base *base;
- int i;
- int length = channels->length;
- float eval_time;
-
- /* init time values (assuming that time moves at a constant speed; may be overridden later) */
- init_time(domainSettings, channels);
-
- /* allocate domain animation channels */
- channels->DomainGravity = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "channel DomainGravity");
- channels->DomainViscosity = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "channel DomainViscosity");
- channels->DomainTime = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "channel DomainTime");
-
- /* allocate fluid objects */
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
- Object *ob = base->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
-
- if (fluidmd) {
- FluidObject *fobj = MEM_callocN(sizeof(FluidObject), "Fluid Object");
- fobj->object = ob;
-
- if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- BLI_addtail(fobjects, fobj);
- continue;
- }
-
- fobj->Translation = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject Translation");
- fobj->Rotation = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject Rotation");
- fobj->Scale = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float), "fluidobject Scale");
- fobj->Active = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject Active");
- fobj->InitialVelocity = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject InitialVelocity");
-
- if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) {
- fobj->AttractforceStrength = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject AttractforceStrength");
- fobj->AttractforceRadius = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject AttractforceRadius");
- fobj->VelocityforceStrength = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject VelocityforceStrength");
- fobj->VelocityforceRadius = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject VelocityforceRadius");
- }
-
- if (fluid_is_animated_mesh(fluidmd->fss)) {
- float *verts = NULL;
- int *tris = NULL, modifierIndex = BLI_findindex(&ob->modifiers, (ModifierData *)fluidmd);
-
- initElbeemMesh(depsgraph,
- scene,
- ob,
- &fobj->numVerts,
- &verts,
- &fobj->numTris,
- &tris,
- 0,
- modifierIndex);
- fobj->VertexCache = MEM_callocN(length * ((fobj->numVerts * CHANNEL_VEC) + 1) *
- sizeof(float),
- "fluidobject VertexCache");
-
- MEM_freeN(verts);
- MEM_freeN(tris);
- }
-
- BLI_addtail(fobjects, fobj);
- }
- }
-
- /* now we loop over the frames and fill the allocated channels with data */
- for (i = 0; i < channels->length; i++) {
- FluidObject *fobj;
- float viscosity, gravity[3];
- float timeAtFrame, time;
-
- eval_time = domainSettings->bakeStart + i;
-
- /* Modifying the global scene isn't nice, but we can do it in
- * this part of the process before a threaded job is created */
- scene->r.cfra = (int)eval_time;
- ED_update_for_newframe(CTX_data_main(C), depsgraph);
-
- /* now scene data should be current according to animation system, so we fill the channels */
-
- /* Domain time */
- /* TODO: have option for not running sim, time mangling,
- * in which case second case comes in handy. */
- if (channels->DomainTime) {
- time = get_fluid_rate(domainSettings) * (float)channels->aniFrameTime;
- timeAtFrame = channels->timeAtFrame[i] + time;
-
- channels->timeAtFrame[i + 1] = timeAtFrame;
- set_channel(channels->DomainTime, i, &time, i, CHANNEL_FLOAT);
- }
- else {
- timeAtFrame = channels->timeAtFrame[i + 1];
- }
-
- /* Domain properties - gravity/viscosity */
- get_fluid_gravity(gravity, scene, domainSettings);
- set_channel(channels->DomainGravity, timeAtFrame, gravity, i, CHANNEL_VEC);
- viscosity = get_fluid_viscosity(domainSettings);
- set_channel(channels->DomainViscosity, timeAtFrame, &viscosity, i, CHANNEL_FLOAT);
-
- /* object movement */
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- float active = (float)((fluidmd->fss->flag & OB_FLUIDSIM_ACTIVE) ? 1 : 0);
- float rot_d[3] = {0.f, 0.f, 0.f}, old_rot[3] = {0.f, 0.f, 0.f};
-
- if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- continue;
- }
-
- /* init euler rotation values and convert to elbeem format */
- /* get the rotation from ob->obmat rather than ob->rot to account for parent animations */
- if (i) {
- copy_v3_v3(old_rot, fobj->Rotation + 4 * (i - 1));
- mul_v3_fl(old_rot, (float)-M_PI / 180.f);
- }
-
- mat4_to_compatible_eulO(rot_d, old_rot, 0, ob->obmat);
- mul_v3_fl(rot_d, -180.0f / (float)M_PI);
-
- set_channel(fobj->Translation, timeAtFrame, ob->loc, i, CHANNEL_VEC);
- set_channel(fobj->Rotation, timeAtFrame, rot_d, i, CHANNEL_VEC);
- set_channel(fobj->Scale, timeAtFrame, ob->scale, i, CHANNEL_VEC);
- set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT);
- set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC);
-
- // printf("Active: %f, Frame: %f\n", active, timeAtFrame);
-
- if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) {
- set_channel(fobj->AttractforceStrength,
- timeAtFrame,
- &fluidmd->fss->attractforceStrength,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->AttractforceRadius,
- timeAtFrame,
- &fluidmd->fss->attractforceRadius,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->VelocityforceStrength,
- timeAtFrame,
- &fluidmd->fss->velocityforceStrength,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->VelocityforceRadius,
- timeAtFrame,
- &fluidmd->fss->velocityforceRadius,
- i,
- CHANNEL_FLOAT);
- }
-
- if (fluid_is_animated_mesh(fluidmd->fss)) {
- set_vertex_channel(depsgraph, fobj->VertexCache, timeAtFrame, scene, fobj, i);
- }
- }
- }
-}
-
-static void export_fluid_objects(const bContext *C, ListBase *fobjects, Scene *scene, int length)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- FluidObject *fobj;
-
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd);
-
- float *verts = NULL;
- int *tris = NULL;
- int numVerts = 0, numTris = 0;
- bool deform = fluid_is_animated_mesh(fluidmd->fss);
-
- elbeemMesh fsmesh;
-
- if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- continue;
- }
-
- elbeemResetMesh(&fsmesh);
-
- fsmesh.type = fluidmd->fss->type;
- fsmesh.name = ob->id.name;
-
- initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 0, modifierIndex);
-
- fsmesh.numVertices = numVerts;
- fsmesh.numTriangles = numTris;
- fsmesh.vertices = verts;
- fsmesh.triangles = tris;
-
- fsmesh.channelSizeTranslation = fsmesh.channelSizeRotation = fsmesh.channelSizeScale =
- fsmesh.channelSizeInitialVel = fsmesh.channelSizeActive = length;
-
- fsmesh.channelTranslation = fobj->Translation;
- fsmesh.channelRotation = fobj->Rotation;
- fsmesh.channelScale = fobj->Scale;
- fsmesh.channelActive = fobj->Active;
-
- if (ELEM(fsmesh.type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) {
- fsmesh.channelInitialVel = fobj->InitialVelocity;
- fsmesh.localInivelCoords = ((fluidmd->fss->typeFlags & OB_FSINFLOW_LOCALCOORD) ? 1 : 0);
- }
-
- if (fluidmd->fss->typeFlags & OB_FSBND_NOSLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- else if (fluidmd->fss->typeFlags & OB_FSBND_PARTSLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP;
- }
- else if (fluidmd->fss->typeFlags & OB_FSBND_FREESLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP;
- }
-
- fsmesh.obstaclePartslip = fluidmd->fss->partSlipValue;
- fsmesh.volumeInitType = fluidmd->fss->volumeInitType;
- fsmesh.obstacleImpactFactor = fluidmd->fss->surfaceSmoothing; // misused value
-
- if (fsmesh.type == OB_FLUIDSIM_CONTROL) {
- fsmesh.cpsTimeStart = fluidmd->fss->cpsTimeStart;
- fsmesh.cpsTimeEnd = fluidmd->fss->cpsTimeEnd;
- fsmesh.cpsQuality = fluidmd->fss->cpsQuality;
- fsmesh.obstacleType = (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE);
-
- fsmesh.channelSizeAttractforceRadius = fsmesh.channelSizeVelocityforceStrength =
- fsmesh.channelSizeVelocityforceRadius = fsmesh.channelSizeAttractforceStrength = length;
-
- fsmesh.channelAttractforceStrength = fobj->AttractforceStrength;
- fsmesh.channelAttractforceRadius = fobj->AttractforceRadius;
- fsmesh.channelVelocityforceStrength = fobj->VelocityforceStrength;
- fsmesh.channelVelocityforceRadius = fobj->VelocityforceRadius;
- }
- else {
- fsmesh.channelAttractforceStrength = fsmesh.channelAttractforceRadius =
- fsmesh.channelVelocityforceStrength = fsmesh.channelVelocityforceRadius = NULL;
- }
-
- /* animated meshes */
- if (deform) {
- fsmesh.channelSizeVertices = length;
- fsmesh.channelVertices = fobj->VertexCache;
-
- /* remove channels */
- fsmesh.channelTranslation = fsmesh.channelRotation = fsmesh.channelScale = NULL;
-
- /* Override user settings, only noslip is supported here! */
- if (fsmesh.type != OB_FLUIDSIM_CONTROL) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- }
-
- elbeemAddMesh(&fsmesh);
-
- if (verts) {
- MEM_freeN(verts);
- }
- if (tris) {
- MEM_freeN(tris);
- }
- }
-}
-
-static int fluid_validate_scene(ReportList *reports, ViewLayer *view_layer, Object *fsDomain)
-{
- Base *base;
- Object *newdomain = NULL;
- int channelObjCount = 0;
- int fluidInputCount = 0;
-
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
- Object *ob = base->object;
- FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
-
- /* only find objects with fluid modifiers */
- if (!fluidmdtmp || ob->type != OB_MESH) {
- continue;
- }
-
- if (fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) {
- /* if no initial domain object given, find another potential domain */
- if (!fsDomain) {
- newdomain = ob;
- }
- /* if there's more than one domain, cancel */
- else if (fsDomain && ob != fsDomain) {
- BKE_report(reports, RPT_ERROR, "There should be only one domain object");
- return 0;
- }
- }
-
- /* count number of objects needed for animation channels */
- if (!ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- channelObjCount++;
- }
-
- /* count number of fluid input objects */
- if (ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) {
- fluidInputCount++;
- }
- }
-
- if (newdomain) {
- fsDomain = newdomain;
- }
-
- if (!fsDomain) {
- BKE_report(reports, RPT_ERROR, "No domain object found");
- return 0;
- }
-
- if (channelObjCount >= 255) {
- BKE_report(reports, RPT_ERROR, "Cannot bake with more than 256 objects");
- return 0;
- }
-
- if (fluidInputCount == 0) {
- BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene");
- return 0;
- }
-
- return 1;
-}
-
-# define FLUID_SUFFIX_CONFIG "fluidsim.cfg"
-# define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp")
-# define FLUID_SUFFIX_SURFACE "fluidsurface"
-
-static bool fluid_init_filepaths(Main *bmain,
- ReportList *reports,
- FluidsimSettings *domainSettings,
- Object *fsDomain,
- char *targetDir,
- char *targetFile)
-{
- const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
-
- /* prepare names... */
- const char *relbase = modifier_path_relbase(bmain, fsDomain);
-
- /* We do not accept empty paths, they can end in random places silently, see T51176. */
- if (domainSettings->surfdataPath[0] == '\0') {
- modifier_path_init(domainSettings->surfdataPath,
- sizeof(domainSettings->surfdataPath),
- OB_FLUIDSIM_SURF_DIR_DEFAULT);
- BKE_reportf(reports,
- RPT_WARNING,
- "Fluidsim: empty cache path, reset to default '%s'",
- domainSettings->surfdataPath);
- }
-
- BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
- BLI_path_abs(targetDir, relbase);
-
- /* .tmp: don't overwrite/delete original file */
- BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
-
- /* Ensure whole path exists and is wirtable. */
- const bool dir_exists = BLI_dir_create_recursive(targetDir);
- const bool is_writable = BLI_file_is_writable(targetFile);
-
- /* We change path to some presumably valid default value,
- * but do not allow bake process to continue,
- * this gives user chance to set manually another path. */
- if (!dir_exists || !is_writable) {
- modifier_path_init(domainSettings->surfdataPath,
- sizeof(domainSettings->surfdataPath),
- OB_FLUIDSIM_SURF_DIR_DEFAULT);
-
- if (!dir_exists) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: could not create cache directory '%s', reset to default '%s'",
- targetDir,
- domainSettings->surfdataPath);
- }
- else {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: cache directory '%s' is not writable, reset to default '%s'",
- targetDir,
- domainSettings->surfdataPath);
- }
-
- BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
- BLI_path_abs(targetDir, relbase);
-
- /* .tmp: don't overwrite/delete original file */
- BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
-
- /* Ensure whole path exists and is wirtable. */
- if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: could not use default cache directory '%s', "
- "please define a valid cache path manually",
- targetDir);
- }
- return false;
- }
-
- return true;
-}
-
-/* ******************************************************************************** */
-/* ********************** write fluidsim config to file ************************* */
-/* ******************************************************************************** */
-
-typedef struct FluidBakeJob {
- /* from wmJob */
- void *owner;
- short *stop, *do_update;
- float *progress;
- int current_frame;
- elbeemSimulationSettings *settings;
-} FluidBakeJob;
-
-static void fluidbake_free(void *customdata)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
- MEM_freeN(fb);
-}
-
-/* called by fluidbake, only to check job 'stop' value */
-static int fluidbake_breakjob(void *customdata)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
-
- if (fb->stop && *(fb->stop)) {
- return 1;
- }
-
- /* this is not nice yet, need to make the jobs list template better
- * for identifying/acting upon various different jobs */
- /* but for now we'll reuse the render break... */
- return (G.is_break);
-}
-
-/* called by fluidbake, wmJob sends notifier */
-static void fluidbake_updatejob(void *customdata, float progress)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
-
- *(fb->do_update) = true;
- *(fb->progress) = progress;
-}
-
-static void fluidbake_startjob(void *customdata, short *stop, short *do_update, float *progress)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
-
- fb->stop = stop;
- fb->do_update = do_update;
- fb->progress = progress;
-
- G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
-
- elbeemSimulate();
- *do_update = true;
- *stop = 0;
-}
-
-static void fluidbake_endjob(void *customdata)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
-
- if (fb->settings) {
- MEM_freeN(fb->settings);
- fb->settings = NULL;
- }
-}
-
-static int runSimulationCallback(void *data, int status, int frame)
-{
- FluidBakeJob *fb = (FluidBakeJob *)data;
- elbeemSimulationSettings *settings = fb->settings;
-
- if (status == FLUIDSIM_CBSTATUS_NEWFRAME) {
- fluidbake_updatejob(fb, frame / (float)settings->noOfFrames);
-# if 0
- printf("elbeem blender cb s%d, f%d, domainid:%d noOfFrames: %d\n",
- status,
- frame,
- settings->domainId,
- settings->noOfFrames); // DEBUG
-# endif
- }
-
- if (fluidbake_breakjob(fb)) {
- return FLUIDSIM_CBRET_ABORT;
- }
-
- return FLUIDSIM_CBRET_CONTINUE;
-}
-
-static void fluidbake_free_data(FluidAnimChannels *channels,
- ListBase *fobjects,
- elbeemSimulationSettings *fsset,
- FluidBakeJob *fb)
-{
- free_domain_channels(channels);
- MEM_freeN(channels);
- channels = NULL;
-
- free_all_fluidobject_channels(fobjects);
- BLI_freelistN(fobjects);
- MEM_freeN(fobjects);
- fobjects = NULL;
-
- if (fsset) {
- MEM_freeN(fsset);
- fsset = NULL;
- }
-
- if (fb) {
- MEM_freeN(fb);
- fb = NULL;
- }
-}
-
-/* copied from rna_fluidsim.c: fluidsim_find_lastframe() */
-static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *relbase)
-{
- char targetDir[FILE_MAX], targetFile[FILE_MAX];
- char targetDirVel[FILE_MAX], targetFileVel[FILE_MAX];
- char previewDir[FILE_MAX], previewFile[FILE_MAX];
- int curFrame = 1, exists = 0;
-
- BLI_join_dirfile(
- targetDir, sizeof(targetDir), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
- BLI_join_dirfile(
- targetDirVel, sizeof(targetDirVel), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_VEL_FNAME);
- BLI_join_dirfile(
- previewDir, sizeof(previewDir), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
-
- BLI_path_abs(targetDir, relbase);
- BLI_path_abs(targetDirVel, relbase);
- BLI_path_abs(previewDir, relbase);
-
- do {
- BLI_strncpy(targetFile, targetDir, sizeof(targetFile));
- BLI_strncpy(targetFileVel, targetDirVel, sizeof(targetFileVel));
- BLI_strncpy(previewFile, previewDir, sizeof(previewFile));
-
- BLI_path_frame(targetFile, curFrame, 0);
- BLI_path_frame(targetFileVel, curFrame, 0);
- BLI_path_frame(previewFile, curFrame, 0);
-
- curFrame++;
-
- if ((exists = BLI_exists(targetFile))) {
- BLI_delete(targetFile, false, false);
- BLI_delete(targetFileVel, false, false);
- BLI_delete(previewFile, false, false);
- }
- } while (exists);
-
- return;
-}
-
-static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int i;
- FluidsimSettings *domainSettings;
-
- char debugStrBuffer[256];
-
- int gridlevels = 0;
- const char *relbase = modifier_path_relbase(bmain, fsDomain);
- const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
- const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
- const char *suffixSurface = FLUID_SUFFIX_SURFACE;
-
- char targetDir[FILE_MAX]; // store & modify output settings
- char targetFile[FILE_MAX]; // temp. store filename from targetDir for access
-
- float domainMat[4][4];
- float invDomMat[4][4];
-
- int noFrames;
- int origFrame = scene->r.cfra;
-
- FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels),
- "fluid domain animation channels");
- ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects");
- FluidsimModifierData *fluidmd = NULL;
- Mesh *mesh = NULL;
-
- FluidBakeJob *fb;
- elbeemSimulationSettings *fsset = MEM_callocN(sizeof(elbeemSimulationSettings),
- "Fluid sim settings");
-
- fb = MEM_callocN(sizeof(FluidBakeJob), "fluid bake job");
-
- if (BLI_getenv(strEnvName)) {
- int dlevel = atoi(BLI_getenv(strEnvName));
- elbeemSetDebugLevel(dlevel);
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",
- strEnvName);
- elbeemDebugOut(debugStrBuffer);
- }
-
- /* Make sure it corresponds to startFrame setting
- * (old: noFrames = scene->r.efra - scene->r.sfra +1). */
-
- noFrames = scene->r.efra - 0;
- if (noFrames <= 0) {
- BKE_report(reports, RPT_ERROR, "No frames to export (check your animation range settings)");
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
- }
-
- /* check scene for sane object/modifier settings */
- if (!fluid_validate_scene(reports, view_layer, fsDomain)) {
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
- }
-
- /* these both have to be valid, otherwise we wouldn't be here */
- fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim);
- domainSettings = fluidmd->fss;
- mesh = fsDomain->data;
-
- domainSettings->bakeStart = 1;
- domainSettings->bakeEnd = scene->r.efra;
-
- // calculate bounding box
- fluid_get_bb(mesh->mvert,
- mesh->totvert,
- fsDomain->obmat,
- domainSettings->bbStart,
- domainSettings->bbSize);
-
- // reset last valid frame
- domainSettings->lastgoodframe = -1;
-
- /* delete old baked files */
- fluidsim_delete_until_lastframe(domainSettings, relbase);
-
- /* rough check of settings... */
- if (domainSettings->previewresxyz > domainSettings->resolutionxyz) {
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n",
- domainSettings->previewresxyz,
- domainSettings->resolutionxyz);
- elbeemDebugOut(debugStrBuffer);
- domainSettings->previewresxyz = domainSettings->resolutionxyz;
- }
- // set adaptive coarsening according to resolutionxyz
- // this should do as an approximation, with in/outflow
- // doing this more accurate would be overkill
- // perhaps add manual setting?
- if (domainSettings->maxRefine < 0) {
- if (domainSettings->resolutionxyz > 128) {
- gridlevels = 2;
- }
- else if (domainSettings->resolutionxyz > 64) {
- gridlevels = 1;
- }
- else {
- gridlevels = 0;
- }
- }
- else {
- gridlevels = domainSettings->maxRefine;
- }
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "fluidsimBake::msg: Baking %s, refine: %d\n",
- fsDomain->id.name,
- gridlevels);
- elbeemDebugOut(debugStrBuffer);
-
- /* ******** prepare output file paths ******** */
- if (!fluid_init_filepaths(bmain, reports, domainSettings, fsDomain, targetDir, targetFile)) {
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return false;
- }
-
- /* DG TODO: why using endframe and not "noFrames" here?
- * because "noFrames" is buggy too? (not using sfra) */
- channels->length = scene->r.efra;
- channels->aniFrameTime = (double)((double)domainSettings->animEnd -
- (double)domainSettings->animStart) /
- (double)noFrames;
-
- /* ******** initialize and allocate animation channels ******** */
- fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects);
-
- /* reset to original current frame */
- scene->r.cfra = origFrame;
- ED_update_for_newframe(CTX_data_main(C), depsgraph);
-
- /* ******** init domain object's matrix ******** */
- copy_m4_m4(domainMat, fsDomain->obmat);
- if (!invert_m4_m4(invDomMat, domainMat)) {
- BLI_snprintf(
- debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n");
- elbeemDebugOut(debugStrBuffer);
- BKE_report(reports, RPT_ERROR, "Invalid object matrix");
-
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
- }
-
- /* ******** start writing / exporting ******** */
- // use .tmp, don't overwrite/delete original file
- BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp);
-
- /* ******** export domain to elbeem ******** */
- elbeemResetSettings(fsset);
- fsset->version = 1;
- fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) :
- domainSettings->threads;
- // setup global settings
- copy_v3_v3(fsset->geoStart, domainSettings->bbStart);
- copy_v3_v3(fsset->geoSize, domainSettings->bbSize);
-
- // simulate with 50^3
- fsset->resolutionxyz = (int)domainSettings->resolutionxyz;
- fsset->previewresxyz = (int)domainSettings->previewresxyz;
-
- fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings);
- fsset->viscosity = get_fluid_viscosity(domainSettings);
- get_fluid_gravity(fsset->gravity, scene, domainSettings);
-
- // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz
- fsset->animStart = domainSettings->animStart;
- fsset->aniFrameTime = channels->aniFrameTime;
- fsset->noOfFrames = noFrames; // is otherwise subtracted in parser
-
- BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface);
-
- // defaults for compressibility and adaptive grids
- fsset->gstar = domainSettings->gstar;
- fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels
- fsset->generateParticles = domainSettings->generateParticles;
- fsset->numTracerParticles = domainSettings->generateTracers;
- fsset->surfaceSmoothing = domainSettings->surfaceSmoothing;
- fsset->surfaceSubdivs = domainSettings->surfaceSubdivs;
- fsset->farFieldSize = domainSettings->farFieldSize;
- BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath));
-
- // domain channels
- fsset->channelSizeFrameTime = fsset->channelSizeViscosity = fsset->channelSizeGravity =
- channels->length;
- fsset->channelFrameTime = channels->DomainTime;
- fsset->channelViscosity = channels->DomainViscosity;
- fsset->channelGravity = channels->DomainGravity;
-
- fsset->runsimCallback = &runSimulationCallback;
- fsset->runsimUserData = fb;
-
- if (domainSettings->typeFlags & OB_FSBND_NOSLIP) {
- fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- else if (domainSettings->typeFlags & OB_FSBND_PARTSLIP) {
- fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP;
- }
- else if (domainSettings->typeFlags & OB_FSBND_FREESLIP) {
- fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP;
- }
- fsset->domainobsPartslip = domainSettings->partSlipValue;
-
- /* use domainobsType also for surface generation flag (bit: >=64) */
- if (domainSettings->typeFlags & OB_FSSG_NOOBS) {
- fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS;
- }
- else {
- fsset->mFsSurfGenSetting = 0; // "normal" mode
- }
-
- fsset->generateVertexVectors = (domainSettings->domainNovecgen == 0);
-
- // init blender domain transform matrix
- {
- int j;
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++) {
- fsset->surfaceTrafo[i * 4 + j] = invDomMat[j][i];
- }
- }
- }
-
- /* ******** init solver with settings ******** */
- elbeemInit();
- elbeemAddDomain(fsset);
-
- /* ******** export all fluid objects to elbeem ******** */
- export_fluid_objects(C, fobjects, scene, channels->length);
-
- /* custom data for fluid bake job */
- fb->settings = fsset;
-
- if (do_job) {
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- scene,
- "Fluid Simulation",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_OBJECT_SIM_FLUID);
-
- /* setup job */
- WM_jobs_customdata_set(wm_job, fb, fluidbake_free);
- WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
- WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob);
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
- }
- else {
- short dummy_stop = 0, dummy_do_update = 0;
- float dummy_progress = 0.0f;
-
- /* blocking, use with exec() */
- fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress);
- fluidbake_endjob((void *)fb);
- fluidbake_free((void *)fb);
- }
-
- /* ******** free stored animation data ******** */
- fluidbake_free_data(channels, fobjects, NULL, NULL);
-
- // elbeemFree();
- return 1;
-}
-
-static void UNUSED_FUNCTION(fluidsimFreeBake)(Object *UNUSED(ob))
-{
- /* not implemented yet */
-}
-
-#else /* WITH_MOD_FLUID */
-
-/* only compile dummy functions */
-static int fluidsimBake(bContext *UNUSED(C),
- ReportList *UNUSED(reports),
- Object *UNUSED(ob),
- short UNUSED(do_job))
-{
- return 0;
-}
-
-#endif /* WITH_MOD_FLUID */
-
-/***************************** Operators ******************************/
-
-static int fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- /* only one bake job at a time */
- if (WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) {
- return OPERATOR_CANCELLED;
- }
-
- if (!fluidsimBake(C, op->reports, ED_object_context(C), true)) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
-}
-
-static int fluid_bake_exec(bContext *C, wmOperator *op)
-{
- if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), false)) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
-}
-
-void FLUID_OT_bake(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Fluid Simulation Bake";
- ot->description = "Bake fluid simulation";
- ot->idname = "FLUID_OT_bake";
-
- /* api callbacks */
- ot->invoke = fluid_bake_invoke;
- ot->exec = fluid_bake_exec;
- ot->poll = ED_operator_object_active_editable;
-}
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index bb7cfe9b1a3..52bda0d0e0b 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -103,8 +103,18 @@ void BOID_OT_state_del(struct wmOperatorType *ot);
void BOID_OT_state_move_up(struct wmOperatorType *ot);
void BOID_OT_state_move_down(struct wmOperatorType *ot);
-/* physics_fluid.c */
-void FLUID_OT_bake(struct wmOperatorType *ot);
+/* physics_manta.c */
+void MANTA_OT_bake_data(struct wmOperatorType *ot);
+void MANTA_OT_free_data(struct wmOperatorType *ot);
+void MANTA_OT_bake_noise(struct wmOperatorType *ot);
+void MANTA_OT_free_noise(struct wmOperatorType *ot);
+void MANTA_OT_bake_mesh(struct wmOperatorType *ot);
+void MANTA_OT_free_mesh(struct wmOperatorType *ot);
+void MANTA_OT_bake_particles(struct wmOperatorType *ot);
+void MANTA_OT_free_particles(struct wmOperatorType *ot);
+void MANTA_OT_bake_guiding(struct wmOperatorType *ot);
+void MANTA_OT_free_guiding(struct wmOperatorType *ot);
+void MANTA_OT_pause_bake(struct wmOperatorType *ot);
/* dynamicpaint.c */
void DPAINT_OT_bake(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_manta.c b/source/blender/editors/physics/physics_manta.c
new file mode 100644
index 00000000000..1b215ca2aa6
--- /dev/null
+++ b/source/blender/editors/physics/physics_manta.c
@@ -0,0 +1,802 @@
+/*
+ * ***** 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) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/physics/physics_manta.c
+ * \ingroup edphys
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "MEM_guardedalloc.h"
+
+/* types */
+#include "DNA_action_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_path_util.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_manta.h"
+#include "BKE_global.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_screen.h"
+#include "PIL_time.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#include "physics_intern.h" // own include
+#include "manta_fluid_API.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_manta_types.h"
+#include "DNA_mesh_types.h"
+
+typedef struct FluidMantaflowJob {
+ /* from wmJob */
+ void *owner;
+ short *stop, *do_update;
+ float *progress;
+ const char *type;
+ const char *name;
+
+ struct Main *bmain;
+ Scene *scene;
+ Depsgraph *depsgraph;
+ Object *ob;
+
+ MantaModifierData *mmd;
+
+ int success;
+ double start;
+
+ int *pause_frame;
+} FluidMantaflowJob;
+
+
+static bool fluid_manta_initjob(
+ bContext *C, FluidMantaflowJob *job, wmOperator *op, char *error_msg, int error_size)
+{
+ MantaModifierData *mmd = NULL;
+ MantaDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
+
+ mmd = (MantaModifierData *)modifiers_findByType(ob, eModifierType_Manta);
+ if (!mmd) {
+ BLI_strncpy(error_msg, N_("Bake failed: no Fluid modifier found"), error_size);
+ return false;
+ }
+ mds = mmd->domain;
+ if (!mds) {
+ BLI_strncpy(error_msg, N_("Bake failed: invalid domain"), error_size);
+ return false;
+ }
+
+ job->bmain = CTX_data_main(C);
+ job->scene = CTX_data_scene(C);
+ job->depsgraph = CTX_data_depsgraph(C);
+ job->ob = CTX_data_active_object(C);
+ job->mmd = mmd;
+ job->type = op->type->idname;
+ job->name = op->type->name;
+
+ return true;
+}
+
+static bool fluid_manta_initpaths(FluidMantaflowJob *job, ReportList *reports)
+{
+ MantaDomainSettings *mds = job->mmd->domain;
+ char tmpDir[FILE_MAX];
+ tmpDir[0] = '\0';
+
+ const char *relbase = modifier_path_relbase(job->bmain, job->ob);
+
+ /* We do not accept empty paths, they can end in random places silently, see T51176. */
+ if (mds->cache_directory[0] == '\0') {
+ modifier_path_init(
+ mds->cache_directory, sizeof(mds->cache_directory), FLUID_DOMAIN_DIR_DEFAULT);
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Fluid Mantaflow: Empty cache path, reset to default '%s'",
+ mds->cache_directory);
+ }
+
+ BLI_strncpy(tmpDir, mds->cache_directory, FILE_MAXDIR);
+ BLI_path_abs(tmpDir, relbase);
+
+ /* Ensure whole path exists */
+ const bool dir_exists = BLI_dir_create_recursive(tmpDir);
+
+ /* We change path to some presumably valid default value, but do not allow bake process to continue,
+ * this gives user chance to set manually another path. */
+ if (!dir_exists) {
+ modifier_path_init(
+ mds->cache_directory, sizeof(mds->cache_directory), FLUID_DOMAIN_DIR_DEFAULT);
+
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Fluid Mantaflow: Could not create cache directory '%s', reset to default '%s'",
+ tmpDir,
+ mds->cache_directory);
+
+ BLI_strncpy(tmpDir, mds->cache_directory, FILE_MAXDIR);
+ BLI_path_abs(tmpDir, relbase);
+
+ /* Ensure whole path exists and is wirtable. */
+ if (!BLI_dir_create_recursive(tmpDir)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Fluid Mantaflow: Could not use default cache directory '%s', "
+ "please define a valid cache path manually",
+ tmpDir);
+ }
+ return false;
+ }
+
+ /* Copy final dir back into domain settings */
+ BLI_strncpy(mds->cache_directory, tmpDir, FILE_MAXDIR);
+ return true;
+}
+
+static void fluid_manta_bake_free(void *customdata)
+{
+ FluidMantaflowJob *job = customdata;
+ MEM_freeN(job);
+}
+
+static void fluid_manta_bake_sequence(FluidMantaflowJob *job)
+{
+ MantaDomainSettings *mds = job->mmd->domain;
+ Scene *scene = job->scene;
+ int frame = 1, orig_frame;
+ int frames;
+ int *pause_frame = NULL;
+ bool is_first_frame;
+
+ frames = mds->cache_frame_end - mds->cache_frame_start + 1;
+
+ if (frames <= 0) {
+ BLI_strncpy(mds->error, N_("No frames to bake"), sizeof(mds->error));
+ return;
+ }
+
+ /* Show progress bar. */
+ if (job->do_update)
+ *(job->do_update) = true;
+
+ /* Get current pause frame (pointer) - depending on bake type */
+ pause_frame = job->pause_frame;
+
+ /* Set frame to start point (depending on current pause frame value) */
+ is_first_frame = ((*pause_frame) == 0);
+ frame = is_first_frame ? mds->cache_frame_start : (*pause_frame);
+
+ /* Save orig frame and update scene frame */
+ orig_frame = CFRA;
+ CFRA = frame;
+
+ /* Loop through selected frames */
+ for (; frame <= mds->cache_frame_end; frame++) {
+ const float progress = (frame - mds->cache_frame_start) / (float)frames;
+
+ /* Keep track of pause frame - needed to init future loop */
+ (*pause_frame) = frame;
+
+ /* If user requested stop, quit baking */
+ if (G.is_break) {
+ job->success = 0;
+ return;
+ }
+
+ /* Update progress bar */
+ if (job->do_update)
+ *(job->do_update) = true;
+ if (job->progress)
+ *(job->progress) = progress;
+
+ CFRA = frame;
+
+ /* Update animation system */
+ ED_update_for_newframe(job->bmain, job->depsgraph);
+ }
+
+ /* Restore frame position that we were on before bake */
+ CFRA = orig_frame;
+}
+
+static void fluid_manta_bake_endjob(void *customdata)
+{
+ FluidMantaflowJob *job = customdata;
+ MantaDomainSettings *mds = job->mmd->domain;
+
+ if (STREQ(job->type, "MANTA_OT_bake_data")) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_DATA;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_DATA;
+ }
+ else if (STREQ(job->type, "MANTA_OT_bake_noise")) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_NOISE;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_NOISE;
+ }
+ else if (STREQ(job->type, "MANTA_OT_bake_mesh")) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_MESH;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_MESH;
+ }
+ else if (STREQ(job->type, "MANTA_OT_bake_particles")) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_PARTICLES;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_PARTICLES;
+ }
+ else if (STREQ(job->type, "MANTA_OT_bake_guiding")) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_GUIDING;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_GUIDING;
+ }
+ DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
+
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+ WM_set_locked_interface(G_MAIN->wm.first, false);
+
+ /* Bake was successful:
+ * Report for ended bake and how long it took */
+ if (job->success) {
+ /* Show bake info */
+ WM_reportf(RPT_INFO,
+ "Fluid Mantaflow: %s complete! (%.2f)",
+ job->name,
+ PIL_check_seconds_timer() - job->start);
+ }
+ else {
+ if (strlen(mds->error)) { /* If an error occurred */
+ WM_reportf(RPT_ERROR, "Fluid Mantaflow: %s failed: %s", job->name, mds->error);
+ }
+ else { /* User canceled the bake */
+ WM_reportf(RPT_WARNING, "Fluid Mantaflow: %s canceled!", job->name);
+ }
+ }
+}
+
+static void fluid_manta_bake_startjob(void *customdata,
+ short *stop,
+ short *do_update,
+ float *progress)
+{
+ FluidMantaflowJob *job = customdata;
+ MantaDomainSettings *mds = job->mmd->domain;
+
+ char tmpDir[FILE_MAX];
+ tmpDir[0] = '\0';
+
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
+ job->start = PIL_check_seconds_timer();
+ job->success = 1;
+
+ G.is_break = false;
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
+
+ if (STREQ(job->type, "MANTA_OT_bake_data")) {
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'config' subdir if it does not exist already */
+ tmpDir[0] = '\0';
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'data' subdir if it does not exist already */
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKED_DATA;
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_DATA;
+ job->pause_frame = &mds->cache_frame_pause_data;
+
+ if (mds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT) {
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'script' subdir if it does not exist already */
+ }
+ }
+ else if (STREQ(job->type, "MANTA_OT_bake_noise")) {
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'noise' subdir if it does not exist already */
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKED_NOISE;
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_NOISE;
+ job->pause_frame = &mds->cache_frame_pause_noise;
+ }
+ else if (STREQ(job->type, "MANTA_OT_bake_mesh")) {
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'mesh' subdir if it does not exist already */
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKED_MESH;
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_MESH;
+ job->pause_frame = &mds->cache_frame_pause_mesh;
+ }
+ else if (STREQ(job->type, "MANTA_OT_bake_particles")) {
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'particles' subdir if it does not exist already */
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKED_PARTICLES;
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_PARTICLES;
+ job->pause_frame = &mds->cache_frame_pause_particles;
+ }
+ else if (STREQ(job->type, "MANTA_OT_bake_guiding")) {
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDING, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'guiding' subdir if it does not exist already */
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKED_GUIDING;
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_GUIDING;
+ job->pause_frame = &mds->cache_frame_pause_guiding;
+ }
+ DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
+
+ fluid_manta_bake_sequence(job);
+
+ if (do_update)
+ *do_update = true;
+ if (stop)
+ *stop = 0;
+}
+
+static void fluid_manta_free_endjob(void *customdata)
+{
+ FluidMantaflowJob *job = customdata;
+ MantaDomainSettings *mds = job->mmd->domain;
+
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+ WM_set_locked_interface(G_MAIN->wm.first, false);
+
+ /* Free was successful:
+ * Report for ended free job and how long it took */
+ if (job->success) {
+ /* Show free job info */
+ WM_reportf(RPT_INFO,
+ "Fluid Mantaflow: %s complete! (%.2f)",
+ job->name,
+ PIL_check_seconds_timer() - job->start);
+ }
+ else {
+ if (strlen(mds->error)) { /* If an error occurred */
+ WM_reportf(RPT_ERROR, "Fluid Mantaflow: %s failed: %s", job->name, mds->error);
+ }
+ else { /* User canceled the free job */
+ WM_reportf(RPT_WARNING, "Fluid Mantaflow: %s canceled!", job->name);
+ }
+ }
+}
+
+static void fluid_manta_free_startjob(void *customdata,
+ short *stop,
+ short *do_update,
+ float *progress)
+{
+ FluidMantaflowJob *job = customdata;
+ MantaDomainSettings *mds = job->mmd->domain;
+ Scene *scene = job->scene;
+
+ char tmpDir[FILE_MAX];
+ tmpDir[0] = '\0';
+
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
+ job->start = PIL_check_seconds_timer();
+ job->success = 1;
+
+ G.is_break = false;
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
+
+ if (STREQ(job->type, "MANTA_OT_free_data")) {
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA |
+ FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKED_NOISE |
+ FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKED_MESH |
+ FLUID_DOMAIN_BAKING_PARTICLES | FLUID_DOMAIN_BAKED_PARTICLES);
+
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ if (BLI_exists(tmpDir))
+ BLI_delete(tmpDir, true, true);
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ if (BLI_exists(tmpDir))
+ BLI_delete(tmpDir, true, true);
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ if (BLI_exists(tmpDir))
+ BLI_delete(tmpDir, true, true);
+
+ /* Free optional mesh and particles as well - otherwise they would not be in sync with data cache */
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ if (BLI_exists(tmpDir))
+ BLI_delete(tmpDir, true, true);
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ if (BLI_exists(tmpDir))
+ BLI_delete(tmpDir, true, true);
+
+ /* Free optional mantaflow script */
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ if (BLI_exists(tmpDir))
+ BLI_delete(tmpDir, true, true);
+
+ /* Reset pause frame */
+ mds->cache_frame_pause_data = 0;
+ }
+ else if (STREQ(job->type, "MANTA_OT_free_noise")) {
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKED_NOISE);
+
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ if (BLI_exists(tmpDir))
+ BLI_delete(tmpDir, true, true);
+
+ /* Reset pause frame */
+ mds->cache_frame_pause_noise = 0;
+ }
+ else if (STREQ(job->type, "MANTA_OT_free_mesh")) {
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKED_MESH);
+
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ if (BLI_exists(tmpDir))
+ BLI_delete(tmpDir, true, true);
+
+ /* Reset pause frame */
+ mds->cache_frame_pause_mesh = 0;
+ }
+ else if (STREQ(job->type, "MANTA_OT_free_particles")) {
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKING_PARTICLES | FLUID_DOMAIN_BAKED_PARTICLES);
+
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ if (BLI_exists(tmpDir))
+ BLI_delete(tmpDir, true, true);
+
+ /* Reset pause frame */
+ mds->cache_frame_pause_particles = 0;
+ }
+ else if (STREQ(job->type, "MANTA_OT_free_guiding")) {
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKING_GUIDING | FLUID_DOMAIN_BAKED_GUIDING);
+
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDING, NULL);
+ if (BLI_exists(tmpDir))
+ BLI_delete(tmpDir, true, true);
+
+ /* Reset pause frame */
+ mds->cache_frame_pause_guiding = 0;
+ }
+ DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
+
+ *do_update = true;
+ *stop = 0;
+
+ /* Reset scene frame to cache frame start */
+ CFRA = mds->cache_frame_start;
+
+ /* Update scene so that viewport shows freed up scene */
+ ED_update_for_newframe(job->bmain, job->depsgraph);
+}
+
+
+/***************************** Operators ******************************/
+
+static int fluid_manta_bake_exec(struct bContext *C, struct wmOperator *op)
+{
+ FluidMantaflowJob *job = MEM_mallocN(sizeof(FluidMantaflowJob), "FluidMantaflowJob");
+ char error_msg[256] = "\0";
+
+ if (!fluid_manta_initjob(C, job, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
+ }
+ fluid_manta_bake_free(job);
+ return OPERATOR_CANCELLED;
+ }
+ fluid_manta_initpaths(job, op->reports);
+ fluid_manta_bake_startjob(job, NULL, NULL, NULL);
+ fluid_manta_bake_endjob(job);
+ fluid_manta_bake_free(job);
+
+ return OPERATOR_FINISHED;
+}
+
+static int fluid_manta_bake_invoke(struct bContext *C,
+ struct wmOperator *op,
+ const wmEvent *UNUSED(_event))
+{
+ Scene *scene = CTX_data_scene(C);
+ FluidMantaflowJob *job = MEM_mallocN(sizeof(FluidMantaflowJob), "FluidMantaflowJob");
+ char error_msg[256] = "\0";
+
+ if (!fluid_manta_initjob(C, job, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
+ }
+ fluid_manta_bake_free(job);
+ return OPERATOR_CANCELLED;
+ }
+
+ fluid_manta_initpaths(job, op->reports);
+
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ scene,
+ "Fluid Mantaflow Bake",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_OBJECT_SIM_MANTA);
+
+ WM_jobs_customdata_set(wm_job, job, fluid_manta_bake_free);
+ WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
+ WM_jobs_callbacks(wm_job, fluid_manta_bake_startjob, NULL, NULL, fluid_manta_bake_endjob);
+
+ WM_set_locked_interface(CTX_wm_manager(C), true);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int fluid_manta_bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ /* no running blender, remove handler and pass through */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_MANTA))
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+
+ switch (event->type) {
+ case ESCKEY:
+ return OPERATOR_RUNNING_MODAL;
+ }
+ return OPERATOR_PASS_THROUGH;
+}
+
+static int fluid_manta_free_exec(struct bContext *C, struct wmOperator *op)
+{
+ MantaModifierData *mmd = NULL;
+ MantaDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+
+ /*
+ * Get modifier data
+ */
+ mmd = (MantaModifierData *)modifiers_findByType(ob, eModifierType_Manta);
+ if (!mmd) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
+ return OPERATOR_CANCELLED;
+ }
+ mds = mmd->domain;
+ if (!mds) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Cannot free data if other bakes currently working */
+ if (mmd->domain->cache_flag & (FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKING_NOISE |
+ FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKING_PARTICLES)) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: pending bake jobs found");
+ return OPERATOR_CANCELLED;
+ }
+
+ FluidMantaflowJob *job = MEM_mallocN(sizeof(FluidMantaflowJob), "FluidMantaflowJob");
+ job->bmain = CTX_data_main(C);
+ job->scene = scene;
+ job->depsgraph = CTX_data_depsgraph(C);
+ job->ob = ob;
+ job->mmd = mmd;
+ job->type = op->type->idname;
+ job->name = op->type->name;
+
+ fluid_manta_initpaths(job, op->reports);
+
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ scene,
+ "Fluid Mantaflow Free",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_OBJECT_SIM_MANTA);
+
+ WM_jobs_customdata_set(wm_job, job, fluid_manta_bake_free);
+ WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
+ WM_jobs_callbacks(wm_job, fluid_manta_free_startjob, NULL, NULL, fluid_manta_free_endjob);
+
+ WM_set_locked_interface(CTX_wm_manager(C), true);
+
+ /* Free Fluid Geometry */
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+
+ return OPERATOR_FINISHED;
+}
+
+static int fluid_manta_pause_exec(struct bContext *C, struct wmOperator *op)
+{
+ MantaModifierData *mmd = NULL;
+ MantaDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
+
+ /*
+ * Get modifier data
+ */
+ mmd = (MantaModifierData *)modifiers_findByType(ob, eModifierType_Manta);
+ if (!mmd) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
+ return OPERATOR_CANCELLED;
+ }
+ mds = mmd->domain;
+ if (!mds) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
+ return OPERATOR_CANCELLED;
+ }
+
+ G.is_break = true;
+
+ return OPERATOR_FINISHED;
+}
+
+void MANTA_OT_bake_data(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Data";
+ ot->description = "Bake Fluid Data";
+ ot->idname = "MANTA_OT_bake_data";
+
+ /* api callbacks */
+ ot->exec = fluid_manta_bake_exec;
+ ot->invoke = fluid_manta_bake_invoke;
+ ot->modal = fluid_manta_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+void MANTA_OT_free_data(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free Data";
+ ot->description = "Free Fluid Data";
+ ot->idname = "MANTA_OT_free_data";
+
+ /* api callbacks */
+ ot->exec = fluid_manta_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+void MANTA_OT_bake_noise(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Noise";
+ ot->description = "Bake Fluid Noise";
+ ot->idname = "MANTA_OT_bake_noise";
+
+ /* api callbacks */
+ ot->exec = fluid_manta_bake_exec;
+ ot->invoke = fluid_manta_bake_invoke;
+ ot->modal = fluid_manta_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+void MANTA_OT_free_noise(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free Noise";
+ ot->description = "Free Fluid Noise";
+ ot->idname = "MANTA_OT_free_noise";
+
+ /* api callbacks */
+ ot->exec = fluid_manta_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+void MANTA_OT_bake_mesh(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Mesh";
+ ot->description = "Bake Fluid Mesh";
+ ot->idname = "MANTA_OT_bake_mesh";
+
+ /* api callbacks */
+ ot->exec = fluid_manta_bake_exec;
+ ot->invoke = fluid_manta_bake_invoke;
+ ot->modal = fluid_manta_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+void MANTA_OT_free_mesh(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free Mesh";
+ ot->description = "Free Fluid Mesh";
+ ot->idname = "MANTA_OT_free_mesh";
+
+ /* api callbacks */
+ ot->exec = fluid_manta_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+void MANTA_OT_bake_particles(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Particles";
+ ot->description = "Bake Fluid Particles";
+ ot->idname = "MANTA_OT_bake_particles";
+
+ /* api callbacks */
+ ot->exec = fluid_manta_bake_exec;
+ ot->invoke = fluid_manta_bake_invoke;
+ ot->modal = fluid_manta_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+void MANTA_OT_free_particles(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free Particles";
+ ot->description = "Free Fluid Particles";
+ ot->idname = "MANTA_OT_free_particles";
+
+ /* api callbacks */
+ ot->exec = fluid_manta_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+void MANTA_OT_bake_guiding(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Guiding";
+ ot->description = "Bake Fluid Guiding";
+ ot->idname = "MANTA_OT_bake_guiding";
+
+ /* api callbacks */
+ ot->exec = fluid_manta_bake_exec;
+ ot->invoke = fluid_manta_bake_invoke;
+ ot->modal = fluid_manta_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+void MANTA_OT_free_guiding(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free Guiding";
+ ot->description = "Free Fluid Guiding";
+ ot->idname = "MANTA_OT_free_guiding";
+
+ /* api callbacks */
+ ot->exec = fluid_manta_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+void MANTA_OT_pause_bake(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Pause Bake";
+ ot->description = "Pause Bake";
+ ot->idname = "MANTA_OT_pause_bake";
+
+ /* api callbacks */
+ ot->exec = fluid_manta_pause_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index b1b3927d05e..da03e098bf5 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -122,11 +122,21 @@ static void operatortypes_boids(void)
WM_operatortype_append(BOID_OT_state_move_down);
}
-/********************************* fluid ***********************************/
+/********************************* mantaflow ***********************************/
-static void operatortypes_fluid(void)
+static void operatortypes_manta(void)
{
- WM_operatortype_append(FLUID_OT_bake);
+ WM_operatortype_append(MANTA_OT_bake_data);
+ WM_operatortype_append(MANTA_OT_free_data);
+ WM_operatortype_append(MANTA_OT_bake_noise);
+ WM_operatortype_append(MANTA_OT_free_noise);
+ WM_operatortype_append(MANTA_OT_bake_mesh);
+ WM_operatortype_append(MANTA_OT_free_mesh);
+ WM_operatortype_append(MANTA_OT_bake_particles);
+ WM_operatortype_append(MANTA_OT_free_particles);
+ WM_operatortype_append(MANTA_OT_bake_guiding);
+ WM_operatortype_append(MANTA_OT_free_guiding);
+ WM_operatortype_append(MANTA_OT_pause_bake);
}
/**************************** point cache **********************************/
@@ -159,7 +169,7 @@ void ED_operatortypes_physics(void)
{
operatortypes_particle();
operatortypes_boids();
- operatortypes_fluid();
+ operatortypes_manta();
operatortypes_pointcache();
operatortypes_dynamicpaint();
}
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index fde8b8f85f8..e7f919ff83d 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -769,8 +769,7 @@ const char *buttons_context_dir[] = {
"particle_settings",
"cloth",
"soft_body",
- "fluid",
- "smoke",
+ "manta",
"collision",
"brush",
"dynamic_paint",
@@ -1018,24 +1017,14 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
return 1;
}
}
- else if (CTX_data_equals(member, "fluid")) {
- PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
-
- if (ptr && ptr->data) {
- Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim);
- CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
- return 1;
- }
- }
- else if (CTX_data_equals(member, "smoke")) {
+ else if (CTX_data_equals(member, "manta")) {
PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
- CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Manta);
+ CTX_data_pointer_set(result, &ob->id, &RNA_MantaModifier, md);
return 1;
}
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 55130ae8894..ec0100b74f9 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1991,8 +1991,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eModifierType_Multires:
data.icon = ICON_MOD_MULTIRES;
break;
- case eModifierType_Smoke:
- data.icon = ICON_MOD_SMOKE;
+ case eModifierType_Manta:
+ data.icon = ICON_MOD_MANTA;
break;
case eModifierType_Solidify:
data.icon = ICON_MOD_SOLIDIFY;
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index dc375958eb4..f15cccd5dcd 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -32,7 +32,7 @@ set(INC
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
- ../../../../intern/smoke/extern
+ ../../../../intern/mantaflow/extern
)
set(INC_SYS
@@ -91,8 +91,8 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
-if(WITH_MOD_SMOKE)
- add_definitions(-DWITH_SMOKE)
+if(WITH_MOD_MANTA)
+ add_definitions(-DWITH_MANTA)
endif()
blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 3a6825aacb4..42b40fa2d4f 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -36,7 +36,7 @@ struct Depsgraph;
struct GPUBatch;
struct Mesh;
struct Object;
-struct SmokeDomainSettings;
+struct MantaDomainSettings;
struct ViewLayer;
struct bAnimVizSettings;
struct bContext;
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 41543448a15..5c4731f7623 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -30,7 +30,6 @@ set(INC
../makesdna
../makesrna
../render/extern/include
- ../../../intern/elbeem/extern
../../../intern/eigen
../../../intern/guardedalloc
)
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index f30eff1484b..57e5790ca24 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -44,7 +44,7 @@ set(INC
../../../intern/glew-mx
../../../intern/guardedalloc
- ../../../intern/smoke/extern
+ ../../../intern/mantaflow/extern
)
set(INC_SYS
@@ -245,8 +245,8 @@ data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC)
-if(WITH_MOD_SMOKE)
- add_definitions(-DWITH_SMOKE)
+if(WITH_MOD_MANTA)
+ add_definitions(-DWITH_MANTA)
endif()
add_definitions(${GL_DEFINITIONS})
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 507baa9531e..64e6ff8511e 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -36,7 +36,7 @@ struct Main;
struct Object;
struct RegionView3D;
struct Scene;
-struct SmokeModifierData;
+struct MantaModifierData;
struct View3D;
struct ViewLayer;
@@ -90,11 +90,11 @@ void GPU_free_images_anim(struct Main *bmain);
void GPU_free_images_old(struct Main *bmain);
/* smoke drawing functions */
-void GPU_free_smoke(struct SmokeModifierData *smd);
-void GPU_free_smoke_velocity(struct SmokeModifierData *smd);
-void GPU_create_smoke(struct SmokeModifierData *smd, int highres);
-void GPU_create_smoke_coba_field(struct SmokeModifierData *smd);
-void GPU_create_smoke_velocity(struct SmokeModifierData *smd);
+void GPU_free_smoke(struct MantaModifierData *mmd);
+void GPU_free_smoke_velocity(struct MantaModifierData *mmd);
+void GPU_create_smoke(struct MantaModifierData *mmd, int highres);
+void GPU_create_smoke_coba_field(struct MantaModifierData *mmd);
+void GPU_create_smoke_velocity(struct MantaModifierData *mmd);
/* Delayed free of OpenGL buffers by main thread */
void GPU_free_unused_buffers(struct Main *bmain);
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index be3655648f5..b5c1148ea77 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -44,7 +44,7 @@
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_view3d_types.h"
#include "DNA_particle_types.h"
@@ -73,9 +73,7 @@
#include "PIL_time.h"
-#ifdef WITH_SMOKE
-# include "smoke_API.h"
-#endif
+#include "manta_fluid_API.h"
static void gpu_free_image_immediate(Image *ima);
@@ -932,7 +930,6 @@ enum {
#define TFUNC_WIDTH 256
-#ifdef WITH_SMOKE
static void create_flame_spectrum_texture(float *data)
{
# define FIRE_THRESH 7
@@ -1009,71 +1006,71 @@ static void swizzle_texture_channel_rrrr(GPUTexture *tex)
GPU_texture_unbind(tex);
}
-static GPUTexture *create_field_texture(SmokeDomainSettings *sds)
+static GPUTexture *create_field_texture(MantaDomainSettings *mds)
{
float *field = NULL;
- switch (sds->coba_field) {
- case FLUID_FIELD_DENSITY:
- field = smoke_get_density(sds->fluid);
+ switch (mds->coba_field) {
+ case FLUID_DOMAIN_FIELD_DENSITY:
+ field = manta_smoke_get_density(mds->fluid);
break;
- case FLUID_FIELD_HEAT:
- field = smoke_get_heat(sds->fluid);
+ case FLUID_DOMAIN_FIELD_HEAT:
+ field = manta_smoke_get_heat(mds->fluid);
break;
- case FLUID_FIELD_FUEL:
- field = smoke_get_fuel(sds->fluid);
+ case FLUID_DOMAIN_FIELD_FUEL:
+ field = manta_smoke_get_fuel(mds->fluid);
break;
- case FLUID_FIELD_REACT:
- field = smoke_get_react(sds->fluid);
+ case FLUID_DOMAIN_FIELD_REACT:
+ field = manta_smoke_get_react(mds->fluid);
break;
- case FLUID_FIELD_FLAME:
- field = smoke_get_flame(sds->fluid);
+ case FLUID_DOMAIN_FIELD_FLAME:
+ field = manta_smoke_get_flame(mds->fluid);
break;
- case FLUID_FIELD_VELOCITY_X:
- field = smoke_get_velocity_x(sds->fluid);
+ case FLUID_DOMAIN_FIELD_VELOCITY_X:
+ field = manta_get_velocity_x(mds->fluid);
break;
- case FLUID_FIELD_VELOCITY_Y:
- field = smoke_get_velocity_y(sds->fluid);
+ case FLUID_DOMAIN_FIELD_VELOCITY_Y:
+ field = manta_get_velocity_y(mds->fluid);
break;
- case FLUID_FIELD_VELOCITY_Z:
- field = smoke_get_velocity_z(sds->fluid);
+ case FLUID_DOMAIN_FIELD_VELOCITY_Z:
+ field = manta_get_velocity_z(mds->fluid);
break;
- case FLUID_FIELD_COLOR_R:
- field = smoke_get_color_r(sds->fluid);
+ case FLUID_DOMAIN_FIELD_COLOR_R:
+ field = manta_smoke_get_color_r(mds->fluid);
break;
- case FLUID_FIELD_COLOR_G:
- field = smoke_get_color_g(sds->fluid);
+ case FLUID_DOMAIN_FIELD_COLOR_G:
+ field = manta_smoke_get_color_g(mds->fluid);
break;
- case FLUID_FIELD_COLOR_B:
- field = smoke_get_color_b(sds->fluid);
+ case FLUID_DOMAIN_FIELD_COLOR_B:
+ field = manta_smoke_get_color_b(mds->fluid);
break;
- case FLUID_FIELD_FORCE_X:
- field = smoke_get_force_x(sds->fluid);
+ case FLUID_DOMAIN_FIELD_FORCE_X:
+ field = manta_get_force_x(mds->fluid);
break;
- case FLUID_FIELD_FORCE_Y:
- field = smoke_get_force_y(sds->fluid);
+ case FLUID_DOMAIN_FIELD_FORCE_Y:
+ field = manta_get_force_y(mds->fluid);
break;
- case FLUID_FIELD_FORCE_Z:
- field = smoke_get_force_z(sds->fluid);
+ case FLUID_DOMAIN_FIELD_FORCE_Z:
+ field = manta_get_force_z(mds->fluid);
break;
default:
return NULL;
}
GPUTexture *tex = GPU_texture_create_nD(
- sds->res[0], sds->res[1], sds->res[2], 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
+ mds->res[0], mds->res[1], mds->res[2], 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
swizzle_texture_channel_rrrr(tex);
return tex;
}
-static GPUTexture *create_density_texture(SmokeDomainSettings *sds, int highres)
+static GPUTexture *create_density_texture(MantaDomainSettings *mds, int highres)
{
float *data = NULL, *source;
- int cell_count = (highres) ? smoke_turbulence_get_cells(sds->wt) : sds->total_cells;
- const bool has_color = (highres) ? smoke_turbulence_has_colors(sds->wt) :
- smoke_has_colors(sds->fluid);
- int *dim = (highres) ? sds->res_wt : sds->res;
+ int cell_count = (highres) ? manta_smoke_turbulence_get_cells(mds->fluid) : mds->total_cells;
+ const bool has_color = (highres) ? manta_smoke_turbulence_has_colors(mds->fluid) :
+ manta_smoke_has_colors(mds->fluid);
+ int *dim = (highres) ? mds->res_noise : mds->res;
eGPUTextureFormat format = (has_color) ? GPU_RGBA8 : GPU_R8;
if (has_color) {
@@ -1082,18 +1079,18 @@ static GPUTexture *create_density_texture(SmokeDomainSettings *sds, int highres)
if (highres) {
if (has_color) {
- smoke_turbulence_get_rgba(sds->wt, data, 0);
+ manta_smoke_turbulence_get_rgba(mds->fluid, data, 0);
}
else {
- source = smoke_turbulence_get_density(sds->wt);
+ source = manta_smoke_turbulence_get_density(mds->fluid);
}
}
else {
if (has_color) {
- smoke_get_rgba(sds->fluid, data, 0);
+ manta_smoke_get_rgba(mds->fluid, data, 0);
}
else {
- source = smoke_get_density(sds->fluid);
+ source = manta_smoke_get_density(mds->fluid);
}
}
@@ -1120,22 +1117,22 @@ static GPUTexture *create_density_texture(SmokeDomainSettings *sds, int highres)
return tex;
}
-static GPUTexture *create_flame_texture(SmokeDomainSettings *sds, int highres)
+static GPUTexture *create_flame_texture(MantaDomainSettings *mds, int highres)
{
float *source = NULL;
- const bool has_fuel = (highres) ? smoke_turbulence_has_fuel(sds->wt) :
- smoke_has_fuel(sds->fluid);
- int *dim = (highres) ? sds->res_wt : sds->res;
+ const bool has_fuel = (highres) ? manta_smoke_turbulence_has_fuel(mds->fluid) :
+ manta_smoke_has_fuel(mds->fluid);
+ int *dim = (highres) ? mds->res_noise : mds->res;
if (!has_fuel) {
return NULL;
}
if (highres) {
- source = smoke_turbulence_get_flame(sds->wt);
+ source = manta_smoke_turbulence_get_flame(mds->fluid);
}
else {
- source = smoke_get_flame(sds->fluid);
+ source = manta_smoke_get_flame(mds->fluid);
}
GPUTexture *tex = GPU_texture_create_nD(
@@ -1145,82 +1142,76 @@ static GPUTexture *create_flame_texture(SmokeDomainSettings *sds, int highres)
return tex;
}
-#endif /* WITH_SMOKE */
-void GPU_free_smoke(SmokeModifierData *smd)
+void GPU_free_smoke(MantaModifierData *mmd)
{
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
- if (smd->domain->tex) {
- GPU_texture_free(smd->domain->tex);
+ if (mmd->type & MOD_MANTA_TYPE_DOMAIN && mmd->domain) {
+ if (mmd->domain->tex) {
+ GPU_texture_free(mmd->domain->tex);
}
- smd->domain->tex = NULL;
+ mmd->domain->tex = NULL;
- if (smd->domain->tex_shadow) {
- GPU_texture_free(smd->domain->tex_shadow);
+ if (mmd->domain->tex_shadow) {
+ GPU_texture_free(mmd->domain->tex_shadow);
}
- smd->domain->tex_shadow = NULL;
+ mmd->domain->tex_shadow = NULL;
- if (smd->domain->tex_flame) {
- GPU_texture_free(smd->domain->tex_flame);
+ if (mmd->domain->tex_flame) {
+ GPU_texture_free(mmd->domain->tex_flame);
}
- smd->domain->tex_flame = NULL;
+ mmd->domain->tex_flame = NULL;
- if (smd->domain->tex_flame_coba) {
- GPU_texture_free(smd->domain->tex_flame_coba);
+ if (mmd->domain->tex_flame_coba) {
+ GPU_texture_free(mmd->domain->tex_flame_coba);
}
- smd->domain->tex_flame_coba = NULL;
+ mmd->domain->tex_flame_coba = NULL;
- if (smd->domain->tex_coba) {
- GPU_texture_free(smd->domain->tex_coba);
+ if (mmd->domain->tex_coba) {
+ GPU_texture_free(mmd->domain->tex_coba);
}
- smd->domain->tex_coba = NULL;
+ mmd->domain->tex_coba = NULL;
- if (smd->domain->tex_field) {
- GPU_texture_free(smd->domain->tex_field);
+ if (mmd->domain->tex_field) {
+ GPU_texture_free(mmd->domain->tex_field);
}
- smd->domain->tex_field = NULL;
+ mmd->domain->tex_field = NULL;
}
}
-void GPU_create_smoke_coba_field(SmokeModifierData *smd)
+void GPU_create_smoke_coba_field(MantaModifierData *mmd)
{
-#ifdef WITH_SMOKE
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- SmokeDomainSettings *sds = smd->domain;
+ if (mmd->type & MOD_MANTA_TYPE_DOMAIN) {
+ MantaDomainSettings *mds = mmd->domain;
- if (!sds->tex_field) {
- sds->tex_field = create_field_texture(sds);
+ if (!mds->tex_field) {
+ mds->tex_field = create_field_texture(mds);
}
- if (!sds->tex_coba) {
- sds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, sds->coba);
+ if (!mds->tex_coba) {
+ mds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, mds->coba);
}
}
-#else // WITH_SMOKE
- smd->domain->tex_field = NULL;
-#endif // WITH_SMOKE
}
-void GPU_create_smoke(SmokeModifierData *smd, int highres)
+void GPU_create_smoke(MantaModifierData *mmd, int highres)
{
-#ifdef WITH_SMOKE
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- SmokeDomainSettings *sds = smd->domain;
+ if (mmd->type & MOD_MANTA_TYPE_DOMAIN) {
+ MantaDomainSettings *mds = mmd->domain;
- if (!sds->tex) {
- sds->tex = create_density_texture(sds, highres);
+ if (!mds->tex) {
+ mds->tex = create_density_texture(mds, highres);
}
- if (!sds->tex_flame) {
- sds->tex_flame = create_flame_texture(sds, highres);
+ if (!mds->tex_flame) {
+ mds->tex_flame = create_flame_texture(mds, highres);
}
- if (!sds->tex_flame_coba && sds->tex_flame) {
- sds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL);
+ if (!mds->tex_flame_coba && mds->tex_flame) {
+ mds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL);
}
- if (!sds->tex_shadow) {
- sds->tex_shadow = GPU_texture_create_nD(sds->res[0],
- sds->res[1],
- sds->res[2],
+ if (!mds->tex_shadow) {
+ mds->tex_shadow = GPU_texture_create_nD(mds->res[0],
+ mds->res[1],
+ mds->res[2],
3,
- sds->shadow,
+ manta_smoke_get_shadow(mds->fluid),
GPU_R8,
GPU_DATA_FLOAT,
0,
@@ -1228,64 +1219,51 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
NULL);
}
}
-#else // WITH_SMOKE
- (void)highres;
- smd->domain->tex = NULL;
- smd->domain->tex_flame = NULL;
- smd->domain->tex_flame_coba = NULL;
- smd->domain->tex_shadow = NULL;
-#endif // WITH_SMOKE
}
-void GPU_create_smoke_velocity(SmokeModifierData *smd)
+void GPU_create_smoke_velocity(MantaModifierData *mmd)
{
-#ifdef WITH_SMOKE
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- SmokeDomainSettings *sds = smd->domain;
+ if (mmd->type & MOD_MANTA_TYPE_DOMAIN) {
+ MantaDomainSettings *mds = mmd->domain;
- const float *vel_x = smoke_get_velocity_x(sds->fluid);
- const float *vel_y = smoke_get_velocity_y(sds->fluid);
- const float *vel_z = smoke_get_velocity_z(sds->fluid);
+ const float *vel_x = manta_get_velocity_x(mds->fluid);
+ const float *vel_y = manta_get_velocity_y(mds->fluid);
+ const float *vel_z = manta_get_velocity_z(mds->fluid);
if (ELEM(NULL, vel_x, vel_y, vel_z)) {
return;
}
- if (!sds->tex_velocity_x) {
- sds->tex_velocity_x = GPU_texture_create_3d(
- sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_x, NULL);
- sds->tex_velocity_y = GPU_texture_create_3d(
- sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_y, NULL);
- sds->tex_velocity_z = GPU_texture_create_3d(
- sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_z, NULL);
+ if (!mds->tex_velocity_x) {
+ mds->tex_velocity_x = GPU_texture_create_3d(
+ mds->res[0], mds->res[1], mds->res[2], GPU_R16F, vel_x, NULL);
+ mds->tex_velocity_y = GPU_texture_create_3d(
+ mds->res[0], mds->res[1], mds->res[2], GPU_R16F, vel_y, NULL);
+ mds->tex_velocity_z = GPU_texture_create_3d(
+ mds->res[0], mds->res[1], mds->res[2], GPU_R16F, vel_z, NULL);
}
}
-#else // WITH_SMOKE
- smd->domain->tex_velocity_x = NULL;
- smd->domain->tex_velocity_y = NULL;
- smd->domain->tex_velocity_z = NULL;
-#endif // WITH_SMOKE
}
/* TODO Unify with the other GPU_free_smoke. */
-void GPU_free_smoke_velocity(SmokeModifierData *smd)
+void GPU_free_smoke_velocity(MantaModifierData *mmd)
{
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
- if (smd->domain->tex_velocity_x) {
- GPU_texture_free(smd->domain->tex_velocity_x);
+ if (mmd->type & MOD_MANTA_TYPE_DOMAIN && mmd->domain) {
+ if (mmd->domain->tex_velocity_x) {
+ GPU_texture_free(mmd->domain->tex_velocity_x);
}
- if (smd->domain->tex_velocity_y) {
- GPU_texture_free(smd->domain->tex_velocity_y);
+ if (mmd->domain->tex_velocity_y) {
+ GPU_texture_free(mmd->domain->tex_velocity_y);
}
- if (smd->domain->tex_velocity_z) {
- GPU_texture_free(smd->domain->tex_velocity_z);
+ if (mmd->domain->tex_velocity_z) {
+ GPU_texture_free(mmd->domain->tex_velocity_z);
}
- smd->domain->tex_velocity_x = NULL;
- smd->domain->tex_velocity_y = NULL;
- smd->domain->tex_velocity_z = NULL;
+ mmd->domain->tex_velocity_x = NULL;
+ mmd->domain->tex_velocity_y = NULL;
+ mmd->domain->tex_velocity_z = NULL;
}
}
diff --git a/source/blender/makesdna/DNA_manta_types.h b/source/blender/makesdna/DNA_manta_types.h
new file mode 100644
index 00000000000..b145eaa4abe
--- /dev/null
+++ b/source/blender/makesdna/DNA_manta_types.h
@@ -0,0 +1,501 @@
+/*
+ * 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) 2006 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_MANTA_TYPES_H__
+#define __DNA_MANTA_TYPES_H__
+
+/* flags */
+enum {
+ FLUID_DOMAIN_USE_NOISE = (1 << 1), /* use noise */
+ FLUID_DOMAIN_USE_DISSOLVE = (1 << 2), /* let smoke dissolve */
+ FLUID_DOMAIN_USE_DISSOLVE_LOG = (1 << 3), /* using 1/x for dissolve */
+
+#ifdef DNA_DEPRECATED
+ FLUID_DOMAIN_USE_HIGH_SMOOTH = (1 << 5), /* -- Deprecated -- */
+#endif
+ FLUID_DOMAIN_FILE_LOAD = (1 << 6), /* flag for file load */
+ FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN = (1 << 7),
+ FLUID_DOMAIN_USE_ADAPTIVE_TIME = (1 << 8), /* adaptive time stepping in domain */
+ FLUID_DOMAIN_USE_MESH = (1 << 9), /* use mesh */
+ FLUID_DOMAIN_USE_GUIDING = (1 << 10), /* use guiding */
+ FLUID_DOMAIN_USE_SPEED_VECTORS = (1 << 11), /* generate mesh speed vectors */
+ FLUID_DOMAIN_EXPORT_MANTA_SCRIPT = (1 << 12), /* export mantaflow script during bake */
+};
+
+/* border collisions */
+enum {
+ FLUID_DOMAIN_BORDER_FRONT = (1 << 1),
+ FLUID_DOMAIN_BORDER_BACK = (1 << 2),
+ FLUID_DOMAIN_BORDER_RIGHT = (1 << 3),
+ FLUID_DOMAIN_BORDER_LEFT = (1 << 4),
+ FLUID_DOMAIN_BORDER_TOP = (1 << 5),
+ FLUID_DOMAIN_BORDER_BOTTOM = (1 << 6),
+};
+
+/* cache file formats */
+enum {
+ FLUID_DOMAIN_FILE_UNI = (1 << 0),
+ FLUID_DOMAIN_FILE_OPENVDB = (1 << 1),
+ FLUID_DOMAIN_FILE_RAW = (1 << 2),
+ FLUID_DOMAIN_FILE_OBJECT = (1 << 3),
+ FLUID_DOMAIN_FILE_BIN_OBJECT = (1 << 4),
+};
+
+/* slice method */
+enum {
+ FLUID_DOMAIN_SLICE_VIEW_ALIGNED = 0,
+ FLUID_DOMAIN_SLICE_AXIS_ALIGNED = 1,
+};
+
+/* axis aligned method */
+enum {
+ AXIS_SLICE_FULL = 0,
+ AXIS_SLICE_SINGLE = 1,
+};
+
+/* single slice direction */
+enum {
+ SLICE_AXIS_AUTO = 0,
+ SLICE_AXIS_X = 1,
+ SLICE_AXIS_Y = 2,
+ SLICE_AXIS_Z = 3,
+};
+
+/* axis aligned method */
+enum {
+ VOLUME_INTERP_LINEAR = 0,
+ VOLUME_INTERP_CUBIC = 1,
+};
+
+enum {
+ VECTOR_DRAW_NEEDLE = 0,
+ VECTOR_DRAW_STREAMLINE = 1,
+};
+
+enum {
+ SNDPARTICLE_BOUNDARY_DELETE = 0,
+ SNDPARTICLE_BOUNDARY_PUSHOUT = 1,
+};
+
+enum {
+ SNDPARTICLE_COMBINED_EXPORT_OFF = 0,
+ SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM = 1,
+ SNDPARTICLE_COMBINED_EXPORT_SPRAY_BUBBLE = 2,
+ SNDPARTICLE_COMBINED_EXPORT_FOAM_BUBBLE = 3,
+ SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM_BUBBLE = 4,
+};
+
+enum {
+ FLUID_DOMAIN_FIELD_DENSITY = 0,
+ FLUID_DOMAIN_FIELD_HEAT = 1,
+ FLUID_DOMAIN_FIELD_FUEL = 2,
+ FLUID_DOMAIN_FIELD_REACT = 3,
+ FLUID_DOMAIN_FIELD_FLAME = 4,
+ FLUID_DOMAIN_FIELD_VELOCITY_X = 5,
+ FLUID_DOMAIN_FIELD_VELOCITY_Y = 6,
+ FLUID_DOMAIN_FIELD_VELOCITY_Z = 7,
+ FLUID_DOMAIN_FIELD_COLOR_R = 8,
+ FLUID_DOMAIN_FIELD_COLOR_G = 9,
+ FLUID_DOMAIN_FIELD_COLOR_B = 10,
+ FLUID_DOMAIN_FIELD_FORCE_X = 11,
+ FLUID_DOMAIN_FIELD_FORCE_Y = 12,
+ FLUID_DOMAIN_FIELD_FORCE_Z = 13,
+};
+
+/* domain types */
+#define FLUID_DOMAIN_TYPE_GAS 0
+#define FLUID_DOMAIN_TYPE_LIQUID 1
+
+/* noise */
+#define FLUID_NOISE_TYPE_WAVELET (1 << 0)
+
+/* mesh levelset generator types */
+#define FLUID_DOMAIN_MESH_IMPROVED 0
+#define FLUID_DOMAIN_MESH_UNION 1
+
+/* guiding velocity source */
+#define FLUID_DOMAIN_GUIDING_SRC_DOMAIN 0
+#define FLUID_DOMAIN_GUIDING_SRC_EFFECTOR 1
+
+/* fluid data fields (active_fields) */
+#define FLUID_DOMAIN_ACTIVE_HEAT (1 << 0)
+#define FLUID_DOMAIN_ACTIVE_FIRE (1 << 1)
+#define FLUID_DOMAIN_ACTIVE_COLORS (1 << 2)
+#define FLUID_DOMAIN_ACTIVE_COLOR_SET (1 << 3)
+#define FLUID_DOMAIN_ACTIVE_OBSTACLE (1 << 4)
+#define FLUID_DOMAIN_ACTIVE_GUIDING (1 << 5)
+#define FLUID_DOMAIN_ACTIVE_INVEL (1 << 6)
+#define FLUID_DOMAIN_ACTIVE_OUTFLOW (1 << 7)
+
+/* particle types */
+#define FLUID_DOMAIN_PARTICLE_FLIP (1 << 0)
+#define FLUID_DOMAIN_PARTICLE_SPRAY (1 << 1)
+#define FLUID_DOMAIN_PARTICLE_BUBBLE (1 << 2)
+#define FLUID_DOMAIN_PARTICLE_FOAM (1 << 3)
+#define FLUID_DOMAIN_PARTICLE_TRACER (1 << 4)
+
+/* cache options */
+#define FLUID_DOMAIN_BAKING_DATA 1
+#define FLUID_DOMAIN_BAKED_DATA 2
+#define FLUID_DOMAIN_BAKING_NOISE 4
+#define FLUID_DOMAIN_BAKED_NOISE 8
+#define FLUID_DOMAIN_BAKING_MESH 16
+#define FLUID_DOMAIN_BAKED_MESH 32
+#define FLUID_DOMAIN_BAKING_PARTICLES 64
+#define FLUID_DOMAIN_BAKED_PARTICLES 128
+#define FLUID_DOMAIN_BAKING_GUIDING 256
+#define FLUID_DOMAIN_BAKED_GUIDING 512
+
+#define FLUID_DOMAIN_DIR_DEFAULT "cache_fluid"
+#define FLUID_DOMAIN_DIR_CONFIG "config"
+#define FLUID_DOMAIN_DIR_DATA "data"
+#define FLUID_DOMAIN_DIR_NOISE "noise"
+#define FLUID_DOMAIN_DIR_MESH "mesh"
+#define FLUID_DOMAIN_DIR_PARTICLES "particles"
+#define FLUID_DOMAIN_DIR_GUIDING "guiding"
+#define FLUID_DOMAIN_DIR_SCRIPT "script"
+#define FLUID_DOMAIN_SMOKE_SCRIPT "smoke_script.py"
+#define FLUID_DOMAIN_LIQUID_SCRIPT "liquid_script.py"
+
+/* Deprecated values (i.e. all defines and enums below this line up until typedefs)*/
+/* cache compression */
+#define SM_CACHE_LIGHT 0
+#define SM_CACHE_HEAVY 1
+
+/* high resolution sampling types */
+#define SM_HRES_NEAREST 0
+#define SM_HRES_LINEAR 1
+#define SM_HRES_FULLSAMPLE 2
+
+enum {
+ VDB_COMPRESSION_BLOSC = 0,
+ VDB_COMPRESSION_ZIP = 1,
+ VDB_COMPRESSION_NONE = 2,
+};
+
+typedef struct MantaVertexVelocity {
+ float vel[3];
+} MantaVertexVelocity;
+
+typedef struct MantaDomainSettings {
+ struct MantaModifierData *mmd; /* for fast RNA access */
+ struct MANTA *fluid;
+ struct MANTA *fluid_old; /* adaptive domain needs access to old fluid state */
+ void *fluid_mutex;
+ struct Collection *fluid_group;
+ struct Collection *eff_group; // UNUSED
+ struct Collection *coll_group; // collision objects group
+ struct GPUTexture *tex;
+ struct GPUTexture *tex_wt;
+ struct GPUTexture *tex_shadow;
+ struct GPUTexture *tex_flame;
+ struct GPUTexture *tex_flame_coba;
+ struct GPUTexture *tex_coba;
+ struct GPUTexture *tex_field;
+ struct GPUTexture *tex_velocity_x;
+ struct GPUTexture *tex_velocity_y;
+ struct GPUTexture *tex_velocity_z;
+ struct Object *guiding_parent;
+ struct MantaVertexVelocity *mesh_velocities; /* vertex velocities of simulated fluid mesh */
+ struct EffectorWeights *effector_weights;
+
+ /* domain object data */
+ float p0[3]; /* start point of BB in local space (includes sub-cell shift for adaptive domain)*/
+ float p1[3]; /* end point of BB in local space */
+ float dp0[3]; /* difference from object center to grid start point */
+ float cell_size[3]; /* size of simulation cell in local space */
+ float global_size[3]; /* global size of domain axises */
+ float prev_loc[3];
+ int shift[3]; /* current domain shift in simulation cells */
+ float shift_f[3]; /* exact domain shift */
+ float obj_shift_f[3]; /* how much object has shifted since previous smoke frame (used to "lock"
+ domain while drawing) */
+ float imat[4][4]; /* domain object imat */
+ float obmat[4][4]; /* domain obmat */
+ float fluidmat[4][4]; /* low res fluid matrix */
+ float fluidmat_wt[4][4]; /* high res fluid matrix */
+ int base_res[3]; /* initial "non-adapted" resolution */
+ int res_min[3]; /* cell min */
+ int res_max[3]; /* cell max */
+ int res[3]; /* data resolution (res_max-res_min) */
+ int total_cells;
+ float dx; /* 1.0f / res */
+ float scale; /* largest domain size */
+ int boundary_width; /* usually this is just 1 */
+
+ /* adaptive domain options */
+ int adapt_margin;
+ int adapt_res;
+ float adapt_threshold;
+ char _pad1[4]; /* unused */
+
+ /* fluid domain options */
+ int maxres; /* longest axis on the BB gets this resolution assigned */
+ int solver_res; /* dimension of manta solver, 2d or 3d */
+ int border_collisions; /* How domain border collisions are handled */
+ int flags; /* use-mesh, use-noise, etc. */
+ float gravity[3];
+ int active_fields;
+ short type; /* gas, liquid */
+ char _pad2[6]; /* unused */
+
+ /* smoke domain options */
+ float alpha;
+ float beta;
+ int diss_speed; /* in frames */
+ float vorticity;
+ float active_color[3]; /* monitor smoke color */
+ int highres_sampling;
+
+ /* flame options */
+ float burning_rate, flame_smoke, flame_vorticity;
+ float flame_ignition, flame_max_temp;
+ float flame_smoke_color[3];
+
+ /* noise options */
+ float noise_strength;
+ float noise_pos_scale;
+ float noise_time_anim;
+ int res_noise[3];
+ int noise_scale;
+ short noise_type; /* noise type: wave, curl, anisotropic */
+ char _pad3[2]; /* unused */
+
+ /* liquid domain options */
+ float particle_randomness;
+ int particle_number;
+ int particle_minimum;
+ int particle_maximum;
+ float particle_radius;
+ float particle_band_width;
+
+ /* diffusion options*/
+ float surface_tension;
+ float viscosity_base;
+ int viscosity_exponent;
+ float domain_size;
+
+ /* mesh options */
+ float mesh_concave_upper;
+ float mesh_concave_lower;
+ int mesh_smoothen_pos;
+ int mesh_smoothen_neg;
+ int mesh_scale;
+ int totvert;
+ short mesh_generator;
+ char _pad4[6]; /* unused */
+
+ /* secondary particle options */
+ int particle_type;
+ int particle_scale;
+ float sndparticle_tau_min_wc;
+ float sndparticle_tau_max_wc;
+ float sndparticle_tau_min_ta;
+ float sndparticle_tau_max_ta;
+ float sndparticle_tau_min_k;
+ float sndparticle_tau_max_k;
+ int sndparticle_k_wc;
+ int sndparticle_k_ta;
+ float sndparticle_k_b;
+ float sndparticle_k_d;
+ float sndparticle_l_min;
+ float sndparticle_l_max;
+ int sndparticle_potential_radius;
+ int sndparticle_update_radius;
+ char sndparticle_boundary;
+ char sndparticle_combined_export;
+ char _pad5[6]; /* unused */
+
+ /* fluid guiding options */
+ float guiding_alpha; /* guiding weight scalar (determines strength) */
+ int guiding_beta; /* guiding blur radius (affects size of vortices) */
+ float guiding_vel_factor; /* multiply guiding velocity by this factor */
+ int *guide_res; /* res for velocity guide grids - independent from base res */
+ short guiding_source;
+ char _pad6[6]; /* unused */
+
+ /* cache options */
+ int cache_frame_start;
+ int cache_frame_end;
+ int cache_frame_pause_data;
+ int cache_frame_pause_noise;
+ int cache_frame_pause_mesh;
+ int cache_frame_pause_particles;
+ int cache_frame_pause_guiding;
+ int cache_flag;
+ char cache_mesh_format;
+ char cache_data_format;
+ char cache_particle_format;
+ char cache_noise_format;
+ char cache_directory[1024];
+ char error[64]; /* Bake error description */
+ char _pad7[4]; /* unused */
+
+ /* time options */
+ float dt;
+ float time_total;
+ float time_per_frame;
+ float frame_length;
+ float time_scale;
+ float cfl_condition;
+
+ /* display options */
+ char slice_method, axis_slice_method;
+ char slice_axis, draw_velocity;
+ float slice_per_voxel;
+ float slice_depth;
+ float display_thickness;
+ struct ColorBand *coba;
+ float vector_scale;
+ char vector_draw_type;
+ char use_coba;
+ char coba_field; /* simulation field used for the color mapping */
+ char interp_method;
+
+ /* -- Deprecated / unsed options (below)-- */
+
+ /* view options */
+ int viewsettings;
+ char _pad8[4]; /* unused */
+
+ /* OpenVDB cache options */
+ int openvdb_comp;
+ float clipping;
+ char data_depth;
+ char _pad9[7]; /* unused */
+
+ /* pointcache options */
+ /* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading
+ * old files. */
+ struct PointCache *point_cache[2]; /* definition is in DNA_object_force_types.h */
+ struct ListBase ptcaches[2];
+ int cache_comp;
+ int cache_high_comp;
+
+} MantaDomainSettings;
+
+/* type */
+#define FLUID_FLOW_TYPE_SMOKE 1
+#define FLUID_FLOW_TYPE_FIRE 2
+#define FLUID_FLOW_TYPE_SMOKEFIRE 3
+#define FLUID_FLOW_TYPE_LIQUID 4
+
+/* behavior */
+#define FLUID_FLOW_BEHAVIOR_INFLOW 0
+#define FLUID_FLOW_BEHAVIOR_OUTFLOW 1
+#define FLUID_FLOW_BEHAVIOR_GEOMETRY 2
+
+/* flow source */
+#define FLUID_FLOW_SOURCE_PARTICLES 0
+#define FLUID_FLOW_SOURCE_MESH 1
+
+/* flow texture type */
+#define FLUID_FLOW_TEXTURE_MAP_AUTO 0
+#define FLUID_FLOW_TEXTURE_MAP_UV 1
+
+/* flags */
+enum {
+ /** Old style emission. */
+ FLUID_FLOW_ABSOLUTE = (1 << 1),
+ /** Passes particles speed to the smoke. */
+ FLUID_FLOW_INITVELOCITY = (1 << 2),
+ /** Use texture to control emission speed. */
+ FLUID_FLOW_TEXTUREEMIT = (1 << 3),
+ /** Use specific size for particles instead of closest cell. */
+ FLUID_FLOW_USE_PART_SIZE = (1 << 4),
+ /* Control when to apply inflow. */
+ FLUID_FLOW_USE_INFLOW = (1 << 5),
+};
+
+typedef struct MantaFlowSettings {
+ /** For fast RNA access. */
+ struct MantaModifierData *mmd;
+ struct Mesh *mesh;
+ struct ParticleSystem *psys;
+ struct Tex *noise_texture;
+
+ /* initial velocity */
+ /** Previous vertex positions in domain space. */
+ float *verts_old;
+ int numverts;
+ float vel_multi; // Multiplier for inherited velocity
+ float vel_normal;
+ float vel_random;
+ float vel_coord[3];
+ char _pad1[4];
+
+ /* emission */
+ float density;
+ float color[3];
+ float fuel_amount;
+ /** Delta temperature (temp - ambient temp). */
+ float temp;
+ /** Density emitted within mesh volume. */
+ float volume_density;
+ /** Maximum emission distance from mesh surface. */
+ float surface_distance;
+ float particle_size;
+ int subframes;
+
+ /* texture control */
+ float texture_size;
+ float texture_offset;
+ char _pad2[4];
+ /** MAX_CUSTOMDATA_LAYER_NAME. */
+ char uvlayer_name[64];
+ short vgroup_density;
+
+ short type; /* smoke, flames, both, outflow, liquid */
+ short behavior; /* inflow, outflow, static */
+ short source;
+ short texture_type;
+ short _pad3[3];
+ int flags; /* absolute emission etc*/
+} MantaFlowSettings;
+
+/* effector types */
+#define FLUID_EFFECTOR_TYPE_COLLISION 0
+#define FLUID_EFFECTOR_TYPE_GUIDE 1
+
+/* guiding velocity modes */
+#define FLUID_EFFECTOR_GUIDING_MAXIMUM 0
+#define FLUID_EFFECTOR_GUIDING_MINIMUM 1
+#define FLUID_EFFECTOR_GUIDING_OVERRIDE 2
+#define FLUID_EFFECTOR_GUIDING_AVERAGED 3
+
+/* collision objects (filled with smoke) */
+typedef struct MantaCollSettings {
+ /** For fast RNA access. */
+ struct MantaModifierData *mmd;
+ struct Mesh *mesh;
+ float *verts_old;
+ int numverts;
+ float surface_distance; /* thickness of mesh surface, used in obstacle sdf */
+ short type;
+
+ /* guiding options */
+ short guiding_mode;
+ float vel_multi; // Multiplier for object velocity
+} MantaCollSettings;
+
+#endif
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index a81bff60146..7955d2d29d8 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -64,7 +64,7 @@ typedef enum ModifierType {
eModifierType_SimpleDeform = 28,
eModifierType_Multires = 29,
eModifierType_Surface = 30,
- eModifierType_Smoke = 31,
+ eModifierType_Manta = 31,
eModifierType_ShapeKey = 32,
eModifierType_Solidify = 33,
eModifierType_Screw = 34,
@@ -441,24 +441,24 @@ enum {
MOD_BEVEL_MITER_ARC,
};
-typedef struct SmokeModifierData {
+typedef struct MantaModifierData {
ModifierData modifier;
- struct SmokeDomainSettings *domain;
+ struct MantaDomainSettings *domain;
/** Inflow, outflow, smoke objects. */
- struct SmokeFlowSettings *flow;
- /** Collision objects. */
- struct SmokeCollSettings *coll;
+ struct MantaFlowSettings *flow;
+ /** Effector objects (collision, guiding). */
+ struct MantaCollSettings *effec;
float time;
/** Domain, inflow, outflow, .... */
int type;
-} SmokeModifierData;
+} MantaModifierData;
-/* Smoke modifier flags */
+/* Manta modifier flags */
enum {
- MOD_SMOKE_TYPE_DOMAIN = (1 << 0),
- MOD_SMOKE_TYPE_FLOW = (1 << 1),
- MOD_SMOKE_TYPE_COLL = (1 << 2),
+ MOD_MANTA_TYPE_DOMAIN = (1 << 0),
+ MOD_MANTA_TYPE_FLOW = (1 << 1),
+ MOD_MANTA_TYPE_EFFEC = (1 << 2),
};
typedef struct DisplaceModifierData {
@@ -967,6 +967,7 @@ typedef enum {
eMultiresModifierFlag_UseCrease = (1 << 2),
} MultiresModifierFlag;
+/* DEPRECATED, only used for versioning. */
typedef struct FluidsimModifierData {
ModifierData modifier;
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 13b7a0a7600..f0cee3e450f 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -364,7 +364,8 @@ typedef struct Object {
struct Collection *instance_collection;
/** If fluidsim enabled, store additional settings. */
- struct FluidsimSettings *fluidsimSettings;
+ struct FluidsimSettings *fluidsimSettings
+ DNA_DEPRECATED; // XXX deprecated... replaced by mantaflow, keep for readfile
struct DerivedMesh *derivedDeform, *derivedFinal;
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index 4aaa1fe32f6..2c62ba72f39 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -432,10 +432,25 @@ typedef enum eParticleDrawFlag {
/* part->type */
/* hair is always baked static in object/geometry space */
/* other types (normal particles) are in global space and not static baked */
-#define PART_EMITTER 0
-//#define PART_REACTOR 1
-#define PART_HAIR 2
-#define PART_FLUID 3
+#define PART_EMITTER (1 << 0)
+//#define PART_REACTOR (1<<0)
+#define PART_HAIR (1 << 2)
+#define PART_FLUID (1 << 3) /* deprecated (belonged to elbeem) */
+#define PART_MANTA_FLIP (1 << 4)
+#define PART_MANTA_SPRAY (1 << 5)
+#define PART_MANTA_BUBBLE (1 << 6)
+#define PART_MANTA_FOAM (1 << 7)
+#define PART_MANTA_TRACER (1 << 8)
+
+/* mirroring mantaflow particle types from particle.h */
+#define PNONE (0 << 0)
+#define PNEW (1 << 0)
+#define PSPRAY (1 << 1)
+#define PBUBBLE (1 << 2)
+#define PFOAM (1 << 3)
+#define PTRACER (1 << 4)
+#define PDELETE (1 << 10)
+#define PINVALID (1 << 30)
/* part->flag */
#define PART_REACT_STA_END 1
diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h
deleted file mode 100644
index d795800df2f..00000000000
--- a/source/blender/makesdna/DNA_smoke_types.h
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * 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) 2006 by NaN Holding BV.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup DNA
- */
-
-#ifndef __DNA_SMOKE_TYPES_H__
-#define __DNA_SMOKE_TYPES_H__
-
-/* flags */
-enum {
- MOD_SMOKE_HIGHRES = (1 << 1), /* enable high resolution */
- MOD_SMOKE_DISSOLVE = (1 << 2), /* let smoke dissolve */
- MOD_SMOKE_DISSOLVE_LOG = (1 << 3), /* using 1/x for dissolve */
-
-#ifdef DNA_DEPRECATED
- MOD_SMOKE_HIGH_SMOOTH = (1 << 5), /* -- Deprecated -- */
-#endif
- MOD_SMOKE_FILE_LOAD = (1 << 6), /* flag for file load */
- MOD_SMOKE_ADAPTIVE_DOMAIN = (1 << 7),
-};
-
-/* noise */
-#define MOD_SMOKE_NOISEWAVE (1 << 0)
-#define MOD_SMOKE_NOISEFFT (1 << 1)
-#define MOD_SMOKE_NOISECURL (1 << 2)
-/* viewsettings */
-#define MOD_SMOKE_VIEW_SHOW_HIGHRES (1 << 0)
-
-/* slice method */
-enum {
- MOD_SMOKE_SLICE_VIEW_ALIGNED = 0,
- MOD_SMOKE_SLICE_AXIS_ALIGNED = 1,
-};
-
-/* axis aligned method */
-enum {
- AXIS_SLICE_FULL = 0,
- AXIS_SLICE_SINGLE = 1,
-};
-
-/* single slice direction */
-enum {
- SLICE_AXIS_AUTO = 0,
- SLICE_AXIS_X = 1,
- SLICE_AXIS_Y = 2,
- SLICE_AXIS_Z = 3,
-};
-
-/* axis aligned method */
-enum {
- VOLUME_INTERP_LINEAR = 0,
- VOLUME_INTERP_CUBIC = 1,
-};
-
-enum {
- VECTOR_DRAW_NEEDLE = 0,
- VECTOR_DRAW_STREAMLINE = 1,
-};
-
-enum {
- FLUID_FIELD_DENSITY = 0,
- FLUID_FIELD_HEAT = 1,
- FLUID_FIELD_FUEL = 2,
- FLUID_FIELD_REACT = 3,
- FLUID_FIELD_FLAME = 4,
- FLUID_FIELD_VELOCITY_X = 5,
- FLUID_FIELD_VELOCITY_Y = 6,
- FLUID_FIELD_VELOCITY_Z = 7,
- FLUID_FIELD_COLOR_R = 8,
- FLUID_FIELD_COLOR_G = 9,
- FLUID_FIELD_COLOR_B = 10,
- FLUID_FIELD_FORCE_X = 11,
- FLUID_FIELD_FORCE_Y = 12,
- FLUID_FIELD_FORCE_Z = 13,
-};
-
-/* cache compression */
-#define SM_CACHE_LIGHT 0
-#define SM_CACHE_HEAVY 1
-
-/* domain border collision */
-#define SM_BORDER_OPEN 0
-#define SM_BORDER_VERTICAL 1
-#define SM_BORDER_CLOSED 2
-
-/* collision types */
-#define SM_COLL_STATIC 0
-#define SM_COLL_RIGID 1
-#define SM_COLL_ANIMATED 2
-
-/* high resolution sampling types */
-#define SM_HRES_NEAREST 0
-#define SM_HRES_LINEAR 1
-#define SM_HRES_FULLSAMPLE 2
-
-/* smoke data fields (active_fields) */
-#define SM_ACTIVE_HEAT (1 << 0)
-#define SM_ACTIVE_FIRE (1 << 1)
-#define SM_ACTIVE_COLORS (1 << 2)
-#define SM_ACTIVE_COLOR_SET (1 << 3)
-
-enum {
- VDB_COMPRESSION_BLOSC = 0,
- VDB_COMPRESSION_ZIP = 1,
- VDB_COMPRESSION_NONE = 2,
-};
-
-typedef struct SmokeDomainSettings {
- /** For fast RNA access. */
- struct SmokeModifierData *smd;
- struct FLUID_3D *fluid;
- void *fluid_mutex;
- struct Collection *fluid_group;
- struct Collection *eff_group; // UNUSED
- struct Collection *coll_group; // collision objects group
- struct WTURBULENCE *wt; // WTURBULENCE object, if active
- struct GPUTexture *tex;
- struct GPUTexture *tex_wt;
- struct GPUTexture *tex_shadow;
- struct GPUTexture *tex_flame;
- struct GPUTexture *tex_flame_coba;
- struct GPUTexture *tex_coba;
- struct GPUTexture *tex_field;
- struct GPUTexture *tex_velocity_x;
- struct GPUTexture *tex_velocity_y;
- struct GPUTexture *tex_velocity_z;
- float *shadow;
-
- /* simulation data */
- /** Start point of BB in local space (includes sub-cell shift for adaptive domain.)*/
- float p0[3];
- /** End point of BB in local space. */
- float p1[3];
- /** Difference from object center to grid start point. */
- float dp0[3];
- /** Size of simulation cell in local space. */
- float cell_size[3];
- /** Global size of domain axises. */
- float global_size[3];
- float prev_loc[3];
- /** Current domain shift in simulation cells. */
- int shift[3];
- /** Exact domain shift. */
- float shift_f[3];
- /**
- * How much object has shifted since previous smoke frame
- * (used to "lock" domain while drawing).
- */
- float obj_shift_f[3];
- /** Domain object imat. */
- float imat[4][4];
- /** Domain obmat. */
- float obmat[4][4];
- /** Low res fluid matrix. */
- float fluidmat[4][4];
- /** High res fluid matrix. */
- float fluidmat_wt[4][4];
-
- /** Initial "non-adapted" resolution. */
- int base_res[3];
- /** Cell min. */
- int res_min[3];
- /** Cell max. */
- int res_max[3];
- /** Data resolution (res_max-res_min). */
- int res[3];
- int total_cells;
- /** 1.0f / res. */
- float dx;
- /** Largest domain size. */
- float scale;
-
- /* user settings */
- int adapt_margin;
- int adapt_res;
- float adapt_threshold;
-
- float alpha;
- float beta;
- /** Wavelet amplification. */
- int amplify;
- /** Longest axis on the BB gets this resolution assigned. */
- int maxres;
- /** Show up-res or low res, etc. */
- int flags;
- int viewsettings;
- /** Noise type: wave, curl, anisotropic. */
- short noise;
- short diss_percent;
- /** In frames. */
- int diss_speed;
- float strength;
- int res_wt[3];
- float dx_wt;
- /* point cache options */
- int cache_comp;
- int cache_high_comp;
- /* OpenVDB cache options */
- int openvdb_comp;
- char cache_file_format;
- char data_depth;
- char _pad[2];
-
- /* Smoke uses only one cache from now on (index [0]),
- * but keeping the array for now for reading old files. */
- /** Definition is in DNA_object_force_types.h. */
- struct PointCache *point_cache[2];
- struct ListBase ptcaches[2];
- struct EffectorWeights *effector_weights;
- /** How domain border collisions are handled. */
- int border_collisions;
- float time_scale;
- float vorticity;
- int active_fields;
- /** Monitor color situation of simulation. */
- float active_color[3];
- int highres_sampling;
-
- /* flame parameters */
- float burning_rate, flame_smoke, flame_vorticity;
- float flame_ignition, flame_max_temp;
- float flame_smoke_color[3];
-
- /* Display settings */
- char slice_method, axis_slice_method;
- char slice_axis, draw_velocity;
- float slice_per_voxel;
- float slice_depth;
- float display_thickness;
-
- struct ColorBand *coba;
- float vector_scale;
- char vector_draw_type;
- char use_coba;
- /** Simulation field used for the color mapping. */
- char coba_field;
- char interp_method;
-
- float clipping;
- char _pad3[4];
-} SmokeDomainSettings;
-
-/* inflow / outflow */
-
-/* type */
-#define MOD_SMOKE_FLOW_TYPE_SMOKE 0
-#define MOD_SMOKE_FLOW_TYPE_FIRE 1
-#define MOD_SMOKE_FLOW_TYPE_OUTFLOW 2
-#define MOD_SMOKE_FLOW_TYPE_SMOKEFIRE 3
-
-/* flow source */
-#define MOD_SMOKE_FLOW_SOURCE_PARTICLES 0
-#define MOD_SMOKE_FLOW_SOURCE_MESH 1
-
-/* flow texture type */
-#define MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO 0
-#define MOD_SMOKE_FLOW_TEXTURE_MAP_UV 1
-
-/* flags */
-enum {
- /** Old style emission. */
- MOD_SMOKE_FLOW_ABSOLUTE = (1 << 1),
- /** Passes particles speed to the smoke. */
- MOD_SMOKE_FLOW_INITVELOCITY = (1 << 2),
- /** Use texture to control emission speed. */
- MOD_SMOKE_FLOW_TEXTUREEMIT = (1 << 3),
- /** Use specific size for particles instead of closest cell. */
- MOD_SMOKE_FLOW_USE_PART_SIZE = (1 << 4),
-};
-
-typedef struct SmokeFlowSettings {
- /** For fast RNA access. */
- struct SmokeModifierData *smd;
- struct Mesh *mesh;
- struct ParticleSystem *psys;
- struct Tex *noise_texture;
-
- /* initial velocity */
- /** Previous vertex positions in domain space. */
- float *verts_old;
- int numverts;
- float vel_multi; // Multiplier for inherited velocity
- float vel_normal;
- float vel_random;
- /* emission */
- float density;
- float color[3];
- float fuel_amount;
- /** Delta temperature (temp - ambient temp). */
- float temp;
- /** Density emitted within mesh volume. */
- float volume_density;
- /** Maximum emission distance from mesh surface. */
- float surface_distance;
- float particle_size;
- int subframes;
- /* texture control */
- float texture_size;
- float texture_offset;
- char _pad[4];
- /** MAX_CUSTOMDATA_LAYER_NAME. */
- char uvlayer_name[64];
- short vgroup_density;
-
- /** Smoke, flames, both, outflow. */
- short type;
- short source;
- short texture_type;
- /** Absolute emission et.c*/
- int flags;
-} SmokeFlowSettings;
-
-// struct BVHTreeFromMesh *bvh;
-// float mat[4][4];
-// float mat_old[4][4];
-
-/* collision objects (filled with smoke) */
-typedef struct SmokeCollSettings {
- /** For fast RNA access. */
- struct SmokeModifierData *smd;
- struct Mesh *mesh;
- float *verts_old;
- int numverts;
- short type; // static = 0, rigid = 1, dynamic = 2
- char _pad[2];
-} SmokeCollSettings;
-
-#endif
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 80d37d89f14..e052196ea2b 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -118,7 +118,7 @@ static const char *includefiles[] = {
"DNA_windowmanager_types.h",
"DNA_anim_types.h",
"DNA_boid_types.h",
- "DNA_smoke_types.h",
+ "DNA_manta_types.h",
"DNA_speaker_types.h",
"DNA_movieclip_types.h",
"DNA_tracking_types.h",
@@ -1577,7 +1577,7 @@ int main(int argc, char **argv)
#include "DNA_windowmanager_types.h"
#include "DNA_anim_types.h"
#include "DNA_boid_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_speaker_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_tracking_types.h"
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 30e24917b83..29a9cb141a1 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -259,7 +259,6 @@ extern StructRNA RNA_FloatProperty;
extern StructRNA RNA_FloorConstraint;
extern StructRNA RNA_FluidFluidSettings;
extern StructRNA RNA_FluidSettings;
-extern StructRNA RNA_FluidSimulationModifier;
extern StructRNA RNA_FollowPathConstraint;
extern StructRNA RNA_FreestyleLineSet;
extern StructRNA RNA_FreestyleLineStyle;
@@ -589,10 +588,10 @@ extern StructRNA RNA_ShrinkwrapModifier;
extern StructRNA RNA_SimpleDeformModifier;
extern StructRNA RNA_SimplifyGpencilModifier;
extern StructRNA RNA_SkinModifier;
-extern StructRNA RNA_SmokeCollSettings;
-extern StructRNA RNA_SmokeDomainSettings;
-extern StructRNA RNA_SmokeFlowSettings;
-extern StructRNA RNA_SmokeModifier;
+extern StructRNA RNA_MantaCollSettings;
+extern StructRNA RNA_MantaDomainSettings;
+extern StructRNA RNA_MantaFlowSettings;
+extern StructRNA RNA_MantaModifier;
extern StructRNA RNA_SmoothGpencilModifier;
extern StructRNA RNA_SmoothModifier;
extern StructRNA RNA_SoftBodyModifier;
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 7c31f078b6d..3235845d99f 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -43,7 +43,6 @@ set(DEFSRC
rna_depsgraph.c
rna_dynamicpaint.c
rna_fcurve.c
- rna_fluidsim.c
rna_gpencil.c
rna_gpencil_modifier.c
rna_image.c
@@ -54,6 +53,7 @@ set(DEFSRC
rna_lightprobe.c
rna_linestyle.c
rna_main.c
+ rna_manta.c
rna_mask.c
rna_material.c
rna_mesh.c
@@ -76,7 +76,6 @@ set(DEFSRC
rna_sculpt_paint.c
rna_sequencer.c
rna_shader_fx.c
- rna_smoke.c
rna_sound.c
rna_space.c
rna_speaker.c
@@ -231,16 +230,12 @@ if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
endif()
-if(WITH_MOD_FLUID)
- add_definitions(-DWITH_MOD_FLUID)
-endif()
-
if(WITH_FFTW3)
add_definitions(-DWITH_FFTW3)
endif()
-if(WITH_MOD_SMOKE)
- add_definitions(-DWITH_SMOKE)
+if(WITH_MOD_MANTA)
+ add_definitions(-DWITH_MANTA)
endif()
if(WITH_MOD_OCEANSIM)
@@ -338,7 +333,7 @@ blender_include_dirs(
../../../../intern/glew-mx
../../../../intern/guardedalloc
../../../../intern/memutil
- ../../../../intern/smoke/extern
+ ../../../../intern/mantaflow/extern
)
blender_include_dirs_sys(
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 3b9fa40fcae..d7df9e70ffa 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -4218,7 +4218,6 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_curve.c", "rna_curve_api.c", RNA_def_curve},
{"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint},
{"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve},
- {"rna_fluidsim.c", NULL, RNA_def_fluidsim},
{"rna_gpencil.c", NULL, RNA_def_gpencil},
{"rna_image.c", "rna_image_api.c", RNA_def_image},
{"rna_key.c", NULL, RNA_def_key},
@@ -4227,6 +4226,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_layer.c", NULL, RNA_def_view_layer},
{"rna_linestyle.c", NULL, RNA_def_linestyle},
{"rna_main.c", "rna_main_api.c", RNA_def_main},
+ {"rna_manta.c", NULL, RNA_def_manta},
{"rna_material.c", "rna_material_api.c", RNA_def_material},
{"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh},
{"rna_meta.c", "rna_meta_api.c", RNA_def_meta},
@@ -4249,7 +4249,6 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_screen.c", NULL, RNA_def_screen},
{"rna_sculpt_paint.c", NULL, RNA_def_sculpt_paint},
{"rna_sequencer.c", "rna_sequencer_api.c", RNA_def_sequencer},
- {"rna_smoke.c", NULL, RNA_def_smoke},
{"rna_space.c", "rna_space_api.c", RNA_def_space},
{"rna_speaker.c", NULL, RNA_def_speaker},
{"rna_test.c", NULL, RNA_def_test},
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
deleted file mode 100644
index 45361702384..00000000000
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * 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.
- */
-
-/** \file
- * \ingroup RNA
- */
-
-#include <stdlib.h>
-
-#include "DNA_object_fluidsim_types.h"
-
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
-
-#include "RNA_define.h"
-
-#include "rna_internal.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#ifdef RNA_RUNTIME
-
-# include "MEM_guardedalloc.h"
-
-# include "DNA_scene_types.h"
-# include "DNA_particle_types.h"
-
-# include "BKE_fluidsim.h"
-# include "BKE_global.h"
-# include "BKE_main.h"
-# include "BKE_modifier.h"
-# include "BKE_particle.h"
-# include "BKE_pointcache.h"
-
-# include "DEG_depsgraph.h"
-
-static StructRNA *rna_FluidSettings_refine(struct PointerRNA *ptr)
-{
- FluidsimSettings *fss = (FluidsimSettings *)ptr->data;
-
- switch (fss->type) {
- case OB_FLUIDSIM_DOMAIN:
- return &RNA_DomainFluidSettings;
- case OB_FLUIDSIM_FLUID:
- return &RNA_FluidFluidSettings;
- case OB_FLUIDSIM_OBSTACLE:
- return &RNA_ObstacleFluidSettings;
- case OB_FLUIDSIM_INFLOW:
- return &RNA_InflowFluidSettings;
- case OB_FLUIDSIM_OUTFLOW:
- return &RNA_OutflowFluidSettings;
- case OB_FLUIDSIM_PARTICLE:
- return &RNA_ParticleFluidSettings;
- case OB_FLUIDSIM_CONTROL:
- return &RNA_ControlFluidSettings;
- default:
- return &RNA_FluidSettings;
- }
-}
-
-static void rna_fluid_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- Object *ob = ptr->id.data;
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
-}
-
-static int fluidsim_find_lastframe(Main *bmain, Object *ob, FluidsimSettings *fss)
-{
- char targetFileTest[FILE_MAX];
- char targetFile[FILE_MAX];
- int curFrame = 1;
-
- BLI_join_dirfile(
- targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
- BLI_path_abs(targetFile, modifier_path_relbase(bmain, ob));
-
- do {
- BLI_strncpy(targetFileTest, targetFile, sizeof(targetFileTest));
- BLI_path_frame(targetFileTest, curFrame++, 0);
- } while (BLI_exists(targetFileTest));
-
- return curFrame - 1;
-}
-
-static void rna_fluid_find_enframe(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Object *ob = ptr->id.data;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
-
- if (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE) {
- fluidmd->fss->lastgoodframe = fluidsim_find_lastframe(bmain, ob, fluidmd->fss);
- }
- else {
- fluidmd->fss->lastgoodframe = -1;
- }
- rna_fluid_update(bmain, scene, ptr);
-}
-
-static void rna_FluidSettings_update_type(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->id.data;
- FluidsimModifierData *fluidmd;
- ParticleSystemModifierData *psmd;
- ParticleSystem *psys, *next_psys;
- ParticleSettings *part;
-
- fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
- fluidmd->fss->flag &= ~OB_FLUIDSIM_REVERSE; /* clear flag */
-
- /* remove fluidsim particle system */
- if (fluidmd->fss->type & OB_FLUIDSIM_PARTICLE) {
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (psys->part->type == PART_FLUID) {
- break;
- }
- }
-
- if (ob->type == OB_MESH && !psys) {
- /* add particle system */
- part = BKE_particlesettings_add(bmain, "ParticleSettings");
- psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
-
- part->type = PART_FLUID;
- psys->part = part;
- psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
- BLI_strncpy(psys->name, "FluidParticles", sizeof(psys->name));
- BLI_addtail(&ob->particlesystem, psys);
-
- /* add modifier */
- psmd = (ParticleSystemModifierData *)modifier_new(eModifierType_ParticleSystem);
- BLI_strncpy(psmd->modifier.name, "FluidParticleSystem", sizeof(psmd->modifier.name));
- psmd->psys = psys;
- BLI_addtail(&ob->modifiers, psmd);
- modifier_unique_name(&ob->modifiers, (ModifierData *)psmd);
- }
- }
- else {
- for (psys = ob->particlesystem.first; psys; psys = next_psys) {
- next_psys = psys->next;
- if (psys->part->type == PART_FLUID) {
- /* clear modifier */
- psmd = psys_get_modifier(ob, psys);
- BLI_remlink(&ob->modifiers, psmd);
- modifier_free((ModifierData *)psmd);
-
- /* clear particle system */
- BLI_remlink(&ob->particlesystem, psys);
- psys_free(ob, psys);
- }
- }
- }
-
- rna_fluid_update(bmain, scene, ptr);
-}
-
-static void rna_DomainFluidSettings_memory_estimate_get(PointerRNA *ptr, char *value)
-{
-# ifndef WITH_MOD_FLUID
- (void)ptr;
- value[0] = '\0';
-# else
- Object *ob = (Object *)ptr->id.data;
- FluidsimSettings *fss = (FluidsimSettings *)ptr->data;
-
- fluid_estimate_memory(ob, fss, value);
-# endif
-}
-
-static int rna_DomainFluidSettings_memory_estimate_length(PointerRNA *ptr)
-{
-# ifndef WITH_MOD_FLUID
- UNUSED_VARS(ptr);
- return 0;
-# else
- char value[32];
-
- rna_DomainFluidSettings_memory_estimate_get(ptr, value);
- return strlen(value);
-# endif
-}
-
-static char *rna_FluidSettings_path(PointerRNA *ptr)
-{
- FluidsimSettings *fss = (FluidsimSettings *)ptr->data;
- ModifierData *md = (ModifierData *)fss->fmd;
- char name_esc[sizeof(md->name) * 2];
-
- BLI_strescape(name_esc, md->name, sizeof(name_esc));
- return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc);
-}
-
-#else
-
-static void rna_def_fluidsim_slip(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- static const EnumPropertyItem slip_items[] = {
- {OB_FSBND_NOSLIP,
- "NOSLIP",
- 0,
- "No Slip",
- "Obstacle causes zero normal and tangential velocity (=sticky), default for all "
- "(only option for moving objects)"},
- {OB_FSBND_PARTSLIP,
- "PARTIALSLIP",
- 0,
- "Partial Slip",
- "Mix between no-slip and free-slip (non moving objects only!)"},
- {OB_FSBND_FREESLIP,
- "FREESLIP",
- 0,
- "Free Slip",
- "Obstacle only causes zero normal velocity (=not sticky, non moving objects only!)"},
- {0, NULL, 0, NULL, NULL},
- };
-
- prop = RNA_def_property(srna, "slip_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "typeFlags");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_enum_items(prop, slip_items);
- RNA_def_property_ui_text(prop, "Slip Type", "");
-
- prop = RNA_def_property(srna, "partial_slip_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "partSlipValue");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(
- prop,
- "Partial Slip Amount",
- "Amount of mixing between no- and free-slip, 0 is no slip and 1 is free slip");
-}
-
-static void rna_def_fluid_mesh_vertices(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "FluidVertexVelocity", NULL);
- RNA_def_struct_ui_text(srna, "Fluid Mesh Velocity", "Velocity of a simulated fluid mesh");
- RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL);
-
- prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY);
- RNA_def_property_array(prop, 3);
- RNA_def_property_float_sdna(prop, NULL, "vel");
- RNA_def_property_ui_text(prop, "Velocity", "");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-}
-
-static void rna_def_fluidsim_domain(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem quality_items[] = {
- {OB_FSDOM_GEOM, "GEOMETRY", 0, "Geometry", "Display geometry"},
- {OB_FSDOM_PREVIEW, "PREVIEW", 0, "Preview", "Display preview quality results"},
- {OB_FSDOM_FINAL, "FINAL", 0, "Final", "Display final quality results"},
- {0, NULL, 0, NULL, NULL},
- };
-
- srna = RNA_def_struct(brna, "DomainFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(srna,
- "Domain Fluid Simulation Settings",
- "Fluid simulation settings for the domain of a fluid simulation");
-
- /* standard settings */
-
- prop = RNA_def_property(srna, "threads", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "threads");
- RNA_def_property_range(prop, 0, BLENDER_MAX_THREADS);
- RNA_def_property_ui_text(
- prop, "Simulation Threads", "Override number of threads for the simulation, 0 is automatic");
-
- prop = RNA_def_property(srna, "resolution", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "resolutionxyz");
- RNA_def_property_range(prop, 1, 1024);
- RNA_def_property_ui_text(prop, "Resolution", "Domain resolution in X,Y and Z direction");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
- prop = RNA_def_property(srna, "preview_resolution", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "previewresxyz");
- RNA_def_property_range(prop, 1, 100);
- RNA_def_property_ui_text(
- prop, "Preview Resolution", "Preview resolution in X,Y and Z direction");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
- prop = RNA_def_property(srna, "viewport_display_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "guiDisplayMode");
- RNA_def_property_enum_items(prop, quality_items);
- RNA_def_property_ui_text(
- prop, "Viewport Display Mode", "How to display the mesh in the viewport");
- RNA_def_property_update(prop, 0, "rna_fluid_update");
-
- prop = RNA_def_property(srna, "render_display_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "renderDisplayMode");
- RNA_def_property_enum_items(prop, quality_items);
- RNA_def_property_ui_text(prop, "Render Display Mode", "How to display the mesh for rendering");
-
- prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_REVERSE);
- RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse fluid frames");
- RNA_def_property_update(prop, 0, "rna_fluid_find_enframe");
-
- prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
- RNA_def_property_string_maxlength(prop, FILE_MAX);
- RNA_def_property_string_sdna(prop, NULL, "surfdataPath");
- RNA_def_property_ui_text(
- prop, "Path", "Directory (and/or filename prefix) to store baked fluid simulation files in");
- RNA_def_property_update(prop, 0, "rna_fluid_update");
-
- prop = RNA_def_property(srna, "memory_estimate", PROP_STRING, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_string_funcs(prop,
- "rna_DomainFluidSettings_memory_estimate_get",
- "rna_DomainFluidSettings_memory_estimate_length",
- NULL);
- RNA_def_property_ui_text(
- prop, "Memory Estimate", "Estimated amount of memory needed for baking the domain");
-
- /* advanced settings */
- prop = RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION);
- RNA_def_property_float_sdna(prop, NULL, "grav");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, -1000.1, 1000.1);
- RNA_def_property_ui_text(prop, "Gravity", "Gravity in X, Y and Z direction");
-
- prop = RNA_def_property(srna, "use_time_override", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_OVERRIDE_TIME);
- RNA_def_property_ui_text(
- prop,
- "Override Time",
- "Use a custom start and end time (in seconds) instead of the scene's timeline");
-
- prop = RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME);
- RNA_def_property_float_sdna(prop, NULL, "animStart");
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_text(
- prop, "Start Time", "Simulation time of the first blender frame (in seconds)");
-
- prop = RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME);
- RNA_def_property_float_sdna(prop, NULL, "animEnd");
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_text(
- prop, "End Time", "Simulation time of the last blender frame (in seconds)");
-
- prop = RNA_def_property(srna, "frame_offset", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "frameOffset");
- RNA_def_property_ui_text(prop, "Cache Offset", "Offset when reading baked cache");
- RNA_def_property_update(prop, NC_OBJECT, "rna_fluid_update");
-
- prop = RNA_def_property(srna, "simulation_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "realsize");
- RNA_def_property_range(prop, 0.001, 10);
- RNA_def_property_ui_text(prop, "Real World Size", "Size of the simulation domain in meters");
-
- prop = RNA_def_property(srna, "simulation_rate", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "animRate");
- RNA_def_property_range(prop, 0.0, 100.0);
- RNA_def_property_ui_text(
- prop, "Simulation Speed", "Fluid motion rate (0 = stationary, 1 = normal speed)");
-
- prop = RNA_def_property(srna, "viscosity_base", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "viscosityValue");
- RNA_def_property_range(prop, 0, 10);
- RNA_def_property_ui_text(
- prop,
- "Viscosity Base",
- "Viscosity setting: value that is multiplied by 10 to the power of (exponent*-1)");
-
- prop = RNA_def_property(srna, "viscosity_exponent", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "viscosityExponent");
- RNA_def_property_range(prop, 0, 10);
- RNA_def_property_ui_text(
- prop,
- "Viscosity Exponent",
- "Negative exponent for the viscosity value (to simplify entering small values "
- "e.g. 5*10^-6)");
-
- prop = RNA_def_property(srna, "grid_levels", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "maxRefine");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, -1, 4);
- RNA_def_property_ui_text(
- prop, "Grid Levels", "Number of coarsened grids to use (-1 for automatic)");
-
- prop = RNA_def_property(srna, "compressibility", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "gstar");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0.001, 0.1);
- RNA_def_property_ui_text(prop,
- "Compressibility",
- "Allowed compressibility due to gravitational force for standing fluid "
- "(directly affects simulation step size)");
-
- /* domain boundary settings */
-
- rna_def_fluidsim_slip(srna);
-
- prop = RNA_def_property(srna, "surface_smooth", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "surfaceSmoothing");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0.0, 5.0);
- RNA_def_property_ui_text(
- prop,
- "Surface Smoothing",
- "Amount of surface smoothing (a value of 0 is off, 1 is normal smoothing and "
- "more than 1 is extra smoothing)");
-
- prop = RNA_def_property(srna, "surface_subdivisions", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "surfaceSubdivs");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0, 5);
- RNA_def_property_ui_text(
- prop,
- "Surface Subdivisions",
- "Number of isosurface subdivisions (this is necessary for the inclusion of particles "
- "into the surface generation - WARNING: can lead to longer computation times !)");
-
- prop = RNA_def_property(srna, "use_speed_vectors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "domainNovecgen", 0);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(
- prop, "Generate Speed Vectors", "Generate speed vectors for vector blur");
-
- /* no collision object surface */
- prop = RNA_def_property(srna, "use_surface_noobs", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSSG_NOOBS);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(
- prop,
- "Remove air bubbles",
- "Removes the air gap between fluid surface and obstacles - WARNING: Can result "
- "in a dissolving surface in other areas");
-
- /* particles */
-
- prop = RNA_def_property(srna, "tracer_particles", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "generateTracers");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0, 10000);
- RNA_def_property_ui_text(prop, "Tracer Particles", "Number of tracer particles to generate");
-
- prop = RNA_def_property(srna, "generate_particles", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "generateParticles");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop, "Generate Particles", "Amount of particles to generate (0=off, 1=normal, >1=more)");
-
- /* simulated fluid mesh data */
- prop = RNA_def_property(srna, "fluid_mesh_vertices", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "meshVelocities", "totvert");
- RNA_def_property_struct_type(prop, "FluidVertexVelocity");
- RNA_def_property_ui_text(
- prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation");
-
- rna_def_fluid_mesh_vertices(brna);
-}
-
-static void rna_def_fluidsim_volume(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- static const EnumPropertyItem volume_type_items[] = {
- {1, "VOLUME", 0, "Volume", "Use only the inner volume of the mesh"},
- {2, "SHELL", 0, "Shell", "Use only the outer shell of the mesh"},
- {3, "BOTH", 0, "Both", "Use both the inner volume and the outer shell of the mesh"},
- {0, NULL, 0, NULL, NULL},
- };
-
- prop = RNA_def_property(srna, "volume_initialization", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "volumeInitType");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_enum_items(prop, volume_type_items);
- RNA_def_property_ui_text(
- prop,
- "Volume Initialization",
- "Volume initialization type "
- "(WARNING: complex volumes might require too much memory and break simulation)");
-
- prop = RNA_def_property(srna, "use_animated_mesh", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "domainNovecgen", 0);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(
- prop,
- "Export Animated Mesh",
- "Export this mesh as an animated one (slower and enforces No Slip, only use if really "
- "necessary [e.g. armatures or parented objects], animated pos/rot/scale F-Curves "
- "do not require it)");
-}
-
-static void rna_def_fluidsim_active(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_ACTIVE);
- RNA_def_property_ui_text(prop, "Enabled", "Object contributes to the fluid simulation");
-}
-
-static void rna_def_fluidsim_fluid(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "FluidFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(srna,
- "Fluid Fluid Simulation Settings",
- "Fluid simulation settings for the fluid in the simulation");
-
- rna_def_fluidsim_active(srna);
- rna_def_fluidsim_volume(srna);
-
- prop = RNA_def_property(srna, "initial_velocity", PROP_FLOAT, PROP_VELOCITY);
- RNA_def_property_float_sdna(prop, NULL, "iniVelx");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, -1000.1, 1000.1);
- RNA_def_property_ui_text(prop, "Initial Velocity", "Initial velocity of fluid");
-}
-
-static void rna_def_fluidsim_obstacle(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "ObstacleFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(srna,
- "Obstacle Fluid Simulation Settings",
- "Fluid simulation settings for obstacles in the simulation");
-
- rna_def_fluidsim_active(srna);
- rna_def_fluidsim_volume(srna);
- rna_def_fluidsim_slip(srna);
-
- prop = RNA_def_property(srna, "impact_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "surfaceSmoothing");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, -2.0, 10.0);
- RNA_def_property_ui_text(
- prop,
- "Impact Factor",
- "This is an unphysical value for moving objects - it controls the impact an obstacle "
- "has on the fluid, =0 behaves a bit like outflow (deleting fluid), =1 is default, "
- "while >1 results in high forces (can be used to tweak total mass)");
-}
-
-static void rna_def_fluidsim_inflow(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "InflowFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(srna,
- "Inflow Fluid Simulation Settings",
- "Fluid simulation settings for objects adding fluids in the simulation");
-
- rna_def_fluidsim_active(srna);
- rna_def_fluidsim_volume(srna);
-
- prop = RNA_def_property(srna, "inflow_velocity", PROP_FLOAT, PROP_VELOCITY);
- RNA_def_property_float_sdna(prop, NULL, "iniVelx");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, -1000.1, 1000.1);
- RNA_def_property_ui_text(prop, "Inflow Velocity", "Initial velocity of fluid");
-
- prop = RNA_def_property(srna, "use_local_coords", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSINFLOW_LOCALCOORD);
- RNA_def_property_ui_text(
- prop, "Local Coordinates", "Use local coordinates for inflow (e.g. for rotating objects)");
-}
-
-static void rna_def_fluidsim_outflow(BlenderRNA *brna)
-{
- StructRNA *srna;
-
- srna = RNA_def_struct(brna, "OutflowFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(
- srna,
- "Outflow Fluid Simulation Settings",
- "Fluid simulation settings for objects removing fluids from the simulation");
-
- rna_def_fluidsim_active(srna);
- rna_def_fluidsim_volume(srna);
-}
-
-static void rna_def_fluidsim_particle(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "ParticleFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(srna,
- "Particle Fluid Simulation Settings",
- "Fluid simulation settings for objects storing fluid particles generated"
- " by the simulation");
-
- prop = RNA_def_property(srna, "use_drops", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSPART_DROP);
- RNA_def_property_ui_text(prop, "Drops", "Show drop particles");
-
- prop = RNA_def_property(srna, "use_floats", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSPART_FLOAT);
- RNA_def_property_ui_text(prop, "Floats", "Show floating foam particles");
-
- prop = RNA_def_property(srna, "show_tracer", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSPART_TRACER);
- RNA_def_property_ui_text(prop, "Tracer", "Show tracer particles");
-
- prop = RNA_def_property(srna, "particle_influence", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "particleInfSize");
- RNA_def_property_range(prop, 0.0, 2.0);
- RNA_def_property_ui_text(
- prop,
- "Particle Influence",
- "Amount of particle size scaling: 0=off (all same size), 1=full (range 0.2-2.0), "
- ">1=stronger");
-
- prop = RNA_def_property(srna, "alpha_influence", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "particleInfAlpha");
- RNA_def_property_range(prop, 0.0, 2.0);
- RNA_def_property_ui_text(
- prop,
- "Alpha Influence",
- "Amount of particle alpha change, inverse of size influence: 0=off (all same alpha), "
- "1=full (larger particles get lower alphas, smaller ones higher values)");
-
- prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
- RNA_def_property_string_maxlength(prop, FILE_MAX);
- RNA_def_property_string_sdna(prop, NULL, "surfdataPath");
- RNA_def_property_ui_text(
- prop, "Path", "Directory (and/or filename prefix) to store and load particles from");
- RNA_def_property_update(prop, 0, "rna_fluid_update");
-}
-
-static void rna_def_fluidsim_control(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "ControlFluidSettings", "FluidSettings");
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_ui_text(
- srna,
- "Control Fluid Simulation Settings",
- "Fluid simulation settings for objects controlling the motion of fluid in the simulation");
-
- rna_def_fluidsim_active(srna);
-
- prop = RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME);
- RNA_def_property_float_sdna(prop, NULL, "cpsTimeStart");
- RNA_def_property_range(prop, 0.0, FLT_MAX);
- RNA_def_property_ui_text(prop, "Start Time", "Time when the control particles are activated");
-
- prop = RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME);
- RNA_def_property_float_sdna(prop, NULL, "cpsTimeEnd");
- RNA_def_property_range(prop, 0.0, FLT_MAX);
- RNA_def_property_ui_text(prop, "End Time", "Time when the control particles are deactivated");
-
- prop = RNA_def_property(srna, "attraction_strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "attractforceStrength");
- RNA_def_property_range(prop, -10.0, 10.0);
- RNA_def_property_ui_text(prop,
- "Attraction Strength",
- "Force strength for directional attraction towards the control object");
-
- prop = RNA_def_property(srna, "attraction_radius", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "attractforceRadius");
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop, "Attraction Radius", "Force field radius around the control object");
-
- prop = RNA_def_property(srna, "velocity_strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "velocityforceStrength");
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop,
- "Velocity Strength",
- "Force strength of how much of the control object's velocity is influencing the "
- "fluid velocity");
-
- prop = RNA_def_property(srna, "velocity_radius", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "velocityforceRadius");
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop, "Velocity Radius", "Force field radius around the control object");
-
- prop = RNA_def_property(srna, "quality", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "cpsQuality");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 5.0, 100.0);
- RNA_def_property_ui_text(
- prop, "Quality", "Quality which is used for object sampling (higher = better but slower)");
-
- prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_REVERSE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse control object movement");
- RNA_def_property_update(prop, 0, "rna_fluid_find_enframe");
-}
-
-void RNA_def_fluidsim(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_fluid_type_items[] = {
- {OB_FLUIDSIM_ENABLE, "NONE", 0, "None", ""},
- {OB_FLUIDSIM_DOMAIN,
- "DOMAIN",
- 0,
- "Domain",
- "Bounding box of this object represents the computational domain of the "
- "fluid simulation"},
- {OB_FLUIDSIM_FLUID,
- "FLUID",
- 0,
- "Fluid",
- "Object represents a volume of fluid in the simulation"},
- {OB_FLUIDSIM_OBSTACLE, "OBSTACLE", 0, "Obstacle", "Object is a fixed obstacle"},
- {OB_FLUIDSIM_INFLOW, "INFLOW", 0, "Inflow", "Object adds fluid to the simulation"},
- {OB_FLUIDSIM_OUTFLOW, "OUTFLOW", 0, "Outflow", "Object removes fluid from the simulation"},
- {OB_FLUIDSIM_PARTICLE,
- "PARTICLE",
- 0,
- "Particle",
- "Object is made a particle system to display particles generated by a "
- "fluidsim domain object"},
- {OB_FLUIDSIM_CONTROL,
- "CONTROL",
- 0,
- "Control",
- "Object is made a fluid control mesh, which influences the fluid"},
- {0, NULL, 0, NULL, NULL},
- };
-
- srna = RNA_def_struct(brna, "FluidSettings", NULL);
- RNA_def_struct_sdna(srna, "FluidsimSettings");
- RNA_def_struct_refine_func(srna, "rna_FluidSettings_refine");
- RNA_def_struct_path_func(srna, "rna_FluidSettings_path");
- RNA_def_struct_ui_text(srna,
- "Fluid Simulation Settings",
- "Fluid simulation settings for an object taking part in the simulation");
-
- prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_fluid_type_items);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Type", "Type of participation in the fluid simulation");
- RNA_def_property_update(prop, 0, "rna_FluidSettings_update_type");
-
-# if 0
- prop = RNA_def_property(srna, "ipo", PROP_POINTER, PROP_NONE);
- RNA_def_property_ui_text(prop, "IPO Curves", "IPO curves used by fluid simulation settings");
-# endif
-
- /* types */
-
- rna_def_fluidsim_domain(brna);
- rna_def_fluidsim_fluid(brna);
- rna_def_fluidsim_obstacle(brna);
- rna_def_fluidsim_inflow(brna);
- rna_def_fluidsim_outflow(brna);
- rna_def_fluidsim_particle(brna);
- rna_def_fluidsim_control(brna);
-}
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 2b89225d34d..e089280eb00 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -43,7 +43,7 @@
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
-#include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */
+#include "BKE_manta.h" /* For mantaModifier_free & mantaModifier_createType */
#include "RNA_access.h"
#include "RNA_define.h"
@@ -159,7 +159,7 @@ static const EnumPropertyItem rna_enum_time_mode_items[] = {
# include "DNA_particle_types.h"
# include "DNA_curve_types.h"
-# include "DNA_smoke_types.h"
+# include "DNA_manta_types.h"
# include "BKE_cachefile.h"
# include "BKE_context.h"
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 3db41a9a6ea..1a3e9cdf359 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -153,7 +153,6 @@ void RNA_def_controller(struct BlenderRNA *brna);
void RNA_def_curve(struct BlenderRNA *brna);
void RNA_def_depsgraph(struct BlenderRNA *brna);
void RNA_def_dynamic_paint(struct BlenderRNA *brna);
-void RNA_def_fluidsim(struct BlenderRNA *brna);
void RNA_def_fcurve(struct BlenderRNA *brna);
void RNA_def_gpencil(struct BlenderRNA *brna);
void RNA_def_greasepencil_modifier(struct BlenderRNA *brna);
@@ -185,7 +184,7 @@ void RNA_def_view_layer(struct BlenderRNA *brna);
void RNA_def_screen(struct BlenderRNA *brna);
void RNA_def_sculpt_paint(struct BlenderRNA *brna);
void RNA_def_sequencer(struct BlenderRNA *brna);
-void RNA_def_smoke(struct BlenderRNA *brna);
+void RNA_def_manta(struct BlenderRNA *brna);
void RNA_def_space(struct BlenderRNA *brna);
void RNA_def_speaker(struct BlenderRNA *brna);
void RNA_def_test(struct BlenderRNA *brna);
diff --git a/source/blender/makesrna/intern/rna_manta.c b/source/blender/makesrna/intern/rna_manta.c
new file mode 100644
index 00000000000..2da5760e400
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_manta.c
@@ -0,0 +1,2476 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
+#include "BLI_sys_types.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "BKE_modifier.h"
+#include "BKE_manta.h"
+#include "BKE_pointcache.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_manta_types.h"
+#include "DNA_particle_types.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#ifdef RNA_RUNTIME
+
+# include "BLI_threads.h"
+
+# include "BKE_colorband.h"
+# include "BKE_context.h"
+# include "BKE_particle.h"
+
+# include "DEG_depsgraph.h"
+# include "DEG_depsgraph_build.h"
+
+# include "manta_fluid_API.h"
+
+static void rna_Manta_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ DEG_id_tag_update(ptr->id.data, ID_RECALC_GEOMETRY);
+
+ // Needed for liquid domain objects
+ Object *ob = ptr->id.data;
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
+}
+
+static void rna_Manta_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ rna_Manta_update(bmain, scene, ptr);
+ DEG_relations_tag_update(bmain);
+}
+
+static void rna_Manta_resetCache(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+ if (settings->mmd && settings->mmd->domain)
+ settings->point_cache[0]->flag |= PTCACHE_OUTDATED;
+ DEG_id_tag_update(ptr->id.data, ID_RECALC_GEOMETRY);
+}
+static void rna_Manta_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+
+ mantaModifier_reset(settings->mmd);
+ rna_Manta_resetCache(bmain, scene, ptr);
+
+ rna_Manta_update(bmain, scene, ptr);
+}
+
+static void rna_Manta_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+
+ mantaModifier_reset(settings->mmd);
+
+ if (settings->mmd && settings->mmd->domain)
+ settings->mmd->domain->point_cache[0]->flag |= PTCACHE_OUTDATED;
+
+ rna_Manta_dependency_update(bmain, scene, ptr);
+}
+
+static void rna_Manta_parts_create(Main *bmain,
+ PointerRNA *ptr,
+ char *pset_name,
+ char *parts_name,
+ char *psys_name,
+ int psys_type)
+{
+ Object *ob = (Object *)ptr->id.data;
+ ParticleSystemModifierData *pmmd;
+ ParticleSystem *psys;
+ ParticleSettings *part;
+
+ /* add particle system */
+ part = BKE_particlesettings_add(bmain, pset_name);
+ psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
+
+ part->type = psys_type;
+ part->totpart = 0;
+ part->draw_size = 0.05f; // make fluid particles more subtle in viewport
+ part->draw_col = PART_DRAW_COL_VEL;
+ psys->part = part;
+ psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
+ BLI_strncpy(psys->name, parts_name, sizeof(psys->name));
+ BLI_addtail(&ob->particlesystem, psys);
+
+ /* add modifier */
+ pmmd = (ParticleSystemModifierData *)modifier_new(eModifierType_ParticleSystem);
+ BLI_strncpy(pmmd->modifier.name, psys_name, sizeof(pmmd->modifier.name));
+ pmmd->psys = psys;
+ BLI_addtail(&ob->modifiers, pmmd);
+ modifier_unique_name(&ob->modifiers, (ModifierData *)pmmd);
+}
+
+static void rna_Manta_parts_delete(PointerRNA *ptr, int ptype)
+{
+ Object *ob = (Object *)ptr->id.data;
+ ParticleSystemModifierData *pmmd;
+ ParticleSystem *psys, *next_psys;
+
+ for (psys = ob->particlesystem.first; psys; psys = next_psys) {
+ next_psys = psys->next;
+ if (psys->part->type == ptype) {
+ /* clear modifier */
+ pmmd = psys_get_modifier(ob, psys);
+ BLI_remlink(&ob->modifiers, pmmd);
+ modifier_free((ModifierData *)pmmd);
+
+ /* clear particle system */
+ BLI_remlink(&ob->particlesystem, psys);
+ psys_free(ob, psys);
+ }
+ }
+}
+
+static bool rna_Manta_parts_exists(PointerRNA *ptr, int ptype)
+{
+ Object *ob = (Object *)ptr->id.data;
+ ParticleSystem *psys;
+
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ if (psys->part->type == ptype)
+ return true;
+ }
+ return false;
+}
+
+static void rna_Manta_draw_type_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ struct PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+
+ /* Wireframe mode more convenient when particles present */
+ if (settings->particle_type == 0) {
+ ob->dt = OB_SOLID;
+ }
+ else {
+ ob->dt = OB_WIRE;
+ }
+}
+
+static void rna_Manta_flip_parts_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+ MantaModifierData *mmd;
+ mmd = (MantaModifierData *)modifiers_findByType(ob, eModifierType_Manta);
+ bool exists = rna_Manta_parts_exists(ptr, PART_MANTA_FLIP);
+
+ if (ob->type == OB_MESH && !exists) {
+ rna_Manta_parts_create(bmain,
+ ptr,
+ "FlipParticleSettings",
+ "FLIP Particles",
+ "FLIP Particle System",
+ PART_MANTA_FLIP);
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FLIP;
+ }
+ else {
+ rna_Manta_parts_delete(ptr, PART_MANTA_FLIP);
+ rna_Manta_resetCache(NULL, NULL, ptr);
+
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP;
+ }
+ rna_Manta_draw_type_update(NULL, NULL, ptr);
+ rna_Manta_reset(NULL, NULL, ptr);
+}
+
+static void rna_Manta_spray_parts_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+ MantaModifierData *mmd;
+ mmd = (MantaModifierData *)modifiers_findByType(ob, eModifierType_Manta);
+ bool exists = rna_Manta_parts_exists(ptr, PART_MANTA_SPRAY);
+
+ if (ob->type == OB_MESH && !exists) {
+ rna_Manta_parts_create(bmain,
+ ptr,
+ "SprayParticleSettings",
+ "Spray Particles",
+ "Spray Particle System",
+ PART_MANTA_SPRAY);
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
+ }
+ else {
+ rna_Manta_parts_delete(ptr, PART_MANTA_SPRAY);
+ rna_Manta_resetCache(NULL, NULL, ptr);
+
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_SPRAY;
+ }
+ rna_Manta_draw_type_update(NULL, NULL, ptr);
+ rna_Manta_reset(NULL, NULL, ptr);
+}
+
+static void rna_Manta_bubble_parts_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+ MantaModifierData *mmd;
+ mmd = (MantaModifierData *)modifiers_findByType(ob, eModifierType_Manta);
+ bool exists = rna_Manta_parts_exists(ptr, PART_MANTA_BUBBLE);
+
+ if (ob->type == OB_MESH && !exists) {
+ rna_Manta_parts_create(bmain,
+ ptr,
+ "BubbleParticleSettings",
+ "Bubble Particles",
+ "Bubble Particle System",
+ PART_MANTA_BUBBLE);
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
+ }
+ else {
+ rna_Manta_parts_delete(ptr, PART_MANTA_BUBBLE);
+ rna_Manta_resetCache(NULL, NULL, ptr);
+
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_BUBBLE;
+ }
+ rna_Manta_draw_type_update(NULL, NULL, ptr);
+ rna_Manta_reset(NULL, NULL, ptr);
+}
+
+static void rna_Manta_foam_parts_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+ MantaModifierData *mmd;
+ mmd = (MantaModifierData *)modifiers_findByType(ob, eModifierType_Manta);
+ bool exists = rna_Manta_parts_exists(ptr, PART_MANTA_FOAM);
+
+ if (ob->type == OB_MESH && !exists) {
+ rna_Manta_parts_create(bmain,
+ ptr,
+ "FoamParticleSettings",
+ "Foam Particles",
+ "Foam Particle System",
+ PART_MANTA_FOAM);
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
+ }
+ else {
+ rna_Manta_parts_delete(ptr, PART_MANTA_FOAM);
+ rna_Manta_resetCache(NULL, NULL, ptr);
+
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FOAM;
+ }
+ rna_Manta_draw_type_update(NULL, NULL, ptr);
+ rna_Manta_reset(NULL, NULL, ptr);
+}
+
+static void rna_Manta_tracer_parts_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+ MantaModifierData *mmd;
+ mmd = (MantaModifierData *)modifiers_findByType(ob, eModifierType_Manta);
+ bool exists = rna_Manta_parts_exists(ptr, PART_MANTA_TRACER);
+
+ if (ob->type == OB_MESH && !exists) {
+ rna_Manta_parts_create(bmain,
+ ptr,
+ "TracerParticleSettings",
+ "Tracer Particles",
+ "Tracer Particle System",
+ PART_MANTA_TRACER);
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_TRACER;
+ }
+ else {
+ rna_Manta_parts_delete(ptr, PART_MANTA_TRACER);
+ rna_Manta_resetCache(NULL, NULL, ptr);
+
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_TRACER;
+ }
+ rna_Manta_draw_type_update(NULL, NULL, ptr);
+ rna_Manta_reset(NULL, NULL, ptr);
+}
+
+static void rna_Manta_combined_export_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+ MantaModifierData *mmd;
+ mmd = (MantaModifierData *)modifiers_findByType(ob, eModifierType_Manta);
+
+ if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_OFF) {
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_FOAM));
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_BUBBLE));
+ rna_Manta_parts_delete(ptr, (PART_MANTA_FOAM | PART_MANTA_BUBBLE));
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_FOAM | PART_MANTA_BUBBLE));
+
+ // re-add each particle type if enabled
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) != 0) {
+ rna_Manta_spray_parts_update(bmain, scene, ptr);
+ }
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) != 0) {
+ rna_Manta_foam_parts_update(bmain, scene, ptr);
+ }
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) != 0) {
+ rna_Manta_bubble_parts_update(bmain, scene, ptr);
+ }
+ }
+ else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM) {
+ if (ob->type == OB_MESH && !rna_Manta_parts_exists(ptr, (PART_MANTA_SPRAY | PART_MANTA_FOAM)))
+ rna_Manta_parts_create(bmain,
+ ptr,
+ "SprayFoamParticleSettings",
+ "Spray + Foam Particles",
+ "Spray + Foam Particle System",
+ (PART_MANTA_SPRAY | PART_MANTA_FOAM));
+ rna_Manta_parts_delete(ptr, PART_MANTA_SPRAY);
+ rna_Manta_parts_delete(ptr, PART_MANTA_FOAM);
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_BUBBLE));
+ rna_Manta_parts_delete(ptr, (PART_MANTA_FOAM | PART_MANTA_BUBBLE));
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_FOAM | PART_MANTA_BUBBLE));
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
+
+ // re-add bubbles if enabled
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) != 0) {
+ rna_Manta_bubble_parts_update(bmain, scene, ptr);
+ }
+ }
+ else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_SPRAY_BUBBLE) {
+ if (ob->type == OB_MESH &&
+ !rna_Manta_parts_exists(ptr, (PART_MANTA_SPRAY | PART_MANTA_BUBBLE)))
+ rna_Manta_parts_create(bmain,
+ ptr,
+ "SprayBubbleParticleSettings",
+ "Spray + Bubble Particles",
+ "Spray + Bubble Particle System",
+ (PART_MANTA_SPRAY | PART_MANTA_BUBBLE));
+ rna_Manta_parts_delete(ptr, PART_MANTA_SPRAY);
+ rna_Manta_parts_delete(ptr, PART_MANTA_BUBBLE);
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_FOAM));
+ rna_Manta_parts_delete(ptr, (PART_MANTA_FOAM | PART_MANTA_BUBBLE));
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_FOAM | PART_MANTA_BUBBLE));
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
+
+ // re-add foam if enabled
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) != 0) {
+ rna_Manta_foam_parts_update(bmain, scene, ptr);
+ }
+ }
+ else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_FOAM_BUBBLE) {
+ if (ob->type == OB_MESH && !rna_Manta_parts_exists(ptr, (PART_MANTA_FOAM | PART_MANTA_BUBBLE)))
+ rna_Manta_parts_create(bmain,
+ ptr,
+ "FoamBubbleParticleSettings",
+ "Foam + Bubble Particles",
+ "Foam + Bubble Particle System",
+ (PART_MANTA_FOAM | PART_MANTA_BUBBLE));
+ rna_Manta_parts_delete(ptr, PART_MANTA_FOAM);
+ rna_Manta_parts_delete(ptr, PART_MANTA_BUBBLE);
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_FOAM));
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_BUBBLE));
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_FOAM | PART_MANTA_BUBBLE));
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
+
+ // re-add spray if enabled
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) != 0) {
+ rna_Manta_spray_parts_update(bmain, scene, ptr);
+ }
+ }
+ else if (mmd->domain->sndparticle_combined_export ==
+ SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM_BUBBLE) {
+ if (ob->type == OB_MESH &&
+ !rna_Manta_parts_exists(ptr, (PART_MANTA_SPRAY | PART_MANTA_FOAM | PART_MANTA_BUBBLE)))
+ rna_Manta_parts_create(bmain,
+ ptr,
+ "SprayFoamBubbleParticleSettings",
+ "Spray + Foam + Bubble Particles",
+ "Spray + Foam + Bubble Particle System",
+ (PART_MANTA_SPRAY | PART_MANTA_FOAM | PART_MANTA_BUBBLE));
+ rna_Manta_parts_delete(ptr, PART_MANTA_SPRAY);
+ rna_Manta_parts_delete(ptr, PART_MANTA_FOAM);
+ rna_Manta_parts_delete(ptr, PART_MANTA_BUBBLE);
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_FOAM));
+ rna_Manta_parts_delete(ptr, (PART_MANTA_SPRAY | PART_MANTA_BUBBLE));
+ rna_Manta_parts_delete(ptr, (PART_MANTA_FOAM | PART_MANTA_BUBBLE));
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
+ }
+ else {
+ // sanity check, should not occur
+ printf("ERROR: Unexpected combined export setting encountered!");
+ }
+ rna_Manta_resetCache(NULL, NULL, ptr);
+ rna_Manta_draw_type_update(NULL, NULL, ptr);
+}
+
+static void rna_Manta_cachetype_mesh_set(struct PointerRNA *ptr, int value)
+{
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+
+ if (value != settings->cache_mesh_format) {
+ /* TODO (sebbas): Clear old caches. */
+ settings->cache_mesh_format = value;
+ }
+}
+
+static void rna_Manta_cachetype_data_set(struct PointerRNA *ptr, int value)
+{
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+
+ if (value != settings->cache_data_format) {
+ /* TODO (sebbas): Clear old caches. */
+ settings->cache_data_format = value;
+ }
+}
+
+static void rna_Manta_cachetype_particle_set(struct PointerRNA *ptr, int value)
+{
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+
+ if (value != settings->cache_particle_format) {
+ /* TODO (sebbas): Clear old caches. */
+ settings->cache_particle_format = value;
+ }
+}
+
+static void rna_Manta_cachetype_noise_set(struct PointerRNA *ptr, int value)
+{
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+
+ if (value != settings->cache_noise_format) {
+ /* TODO (sebbas): Clear old caches. */
+ settings->cache_noise_format = value;
+ }
+}
+
+static void rna_Manta_guiding_parent_set(struct PointerRNA *ptr,
+ struct PointerRNA value,
+ struct ReportList *UNUSED(reports))
+{
+ MantaDomainSettings *mds = (MantaDomainSettings *)ptr->data;
+ Object *par = (Object *)value.data;
+
+ MantaModifierData *mmd_par = NULL;
+
+ if (par != NULL) {
+ mmd_par = (MantaModifierData *)modifiers_findByType(par, eModifierType_Manta);
+ if (mmd_par && mmd_par->domain) {
+ mds->guiding_parent = value.data;
+ mds->guide_res = mmd_par->domain->res;
+ }
+ }
+ else {
+ mds->guiding_parent = NULL;
+ mds->guide_res = NULL;
+ }
+}
+
+static const EnumPropertyItem *rna_Manta_cachetype_mesh_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ int totitem = 0;
+
+ tmp.value = FLUID_DOMAIN_FILE_BIN_OBJECT;
+ tmp.identifier = "BOBJECT";
+ tmp.name = "Binary Object files";
+ tmp.description = "Binary object file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ tmp.value = FLUID_DOMAIN_FILE_OBJECT;
+ tmp.identifier = "OBJECT";
+ tmp.name = "Object files";
+ tmp.description = "Object file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static const EnumPropertyItem *rna_Manta_cachetype_volume_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ int totitem = 0;
+
+ tmp.value = FLUID_DOMAIN_FILE_UNI;
+ tmp.identifier = "UNI";
+ tmp.name = "Uni Cache";
+ tmp.description = "Uni file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+# ifdef WITH_OPENVDB
+ tmp.value = FLUID_DOMAIN_FILE_OPENVDB;
+ tmp.identifier = "OPENVDB";
+ tmp.name = "OpenVDB";
+ tmp.description = "OpenVDB file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+# endif
+
+ tmp.value = FLUID_DOMAIN_FILE_RAW;
+ tmp.identifier = "RAW";
+ tmp.name = "Raw Cache";
+ tmp.description = "Raw file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static const EnumPropertyItem *rna_Manta_cachetype_particle_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ int totitem = 0;
+
+ tmp.value = FLUID_DOMAIN_FILE_UNI;
+ tmp.identifier = "UNI";
+ tmp.name = "Uni Cache";
+ tmp.description = "Uni file format";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static void rna_Manta_collisionextents_set(struct PointerRNA *ptr, int value, bool clear)
+{
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+ if (clear) {
+ settings->border_collisions &= value;
+ }
+ else {
+ settings->border_collisions |= value;
+ }
+}
+
+static void rna_Manta_cache_directory_set(struct PointerRNA *ptr, const char *value)
+{
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+
+ if (STREQ(settings->cache_directory, value)) {
+ return;
+ }
+
+ BLI_strncpy(settings->cache_directory, value, sizeof(settings->cache_directory));
+
+ /* TODO (sebbas): Read cache state in order to set cache bake flags and cache pause frames correctly */
+ //settings->cache_flag = 0;
+}
+
+static void rna_Manta_domaintype_set(struct PointerRNA *ptr, int value)
+{
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+ Object *ob = (Object *)ptr->id.data;
+
+ if (value != settings->type) {
+ /* Set common values for liquid/smoke domain: cache type, border collision and viewport drawtype. */
+ if (value == FLUID_DOMAIN_TYPE_GAS) {
+ rna_Manta_cachetype_mesh_set(ptr, FLUID_DOMAIN_FILE_BIN_OBJECT);
+ rna_Manta_cachetype_data_set(ptr, FLUID_DOMAIN_FILE_UNI);
+ rna_Manta_cachetype_particle_set(ptr, FLUID_DOMAIN_FILE_UNI);
+ rna_Manta_cachetype_noise_set(ptr, FLUID_DOMAIN_FILE_UNI);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_FRONT, 1);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_BACK, 1);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_RIGHT, 1);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_LEFT, 1);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_TOP, 1);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_BOTTOM, 1);
+ ob->dt = OB_WIRE;
+ }
+ else if (value == FLUID_DOMAIN_TYPE_LIQUID) {
+ rna_Manta_cachetype_mesh_set(ptr, FLUID_DOMAIN_FILE_BIN_OBJECT);
+ rna_Manta_cachetype_data_set(ptr, FLUID_DOMAIN_FILE_UNI);
+ rna_Manta_cachetype_particle_set(ptr, FLUID_DOMAIN_FILE_UNI);
+ rna_Manta_cachetype_noise_set(ptr, FLUID_DOMAIN_FILE_UNI);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_FRONT, 0);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_BACK, 0);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_RIGHT, 0);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_LEFT, 0);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_TOP, 0);
+ rna_Manta_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_BOTTOM, 0);
+ ob->dt = OB_SOLID;
+ }
+
+ /* Set actual domain type */
+ settings->type = value;
+ }
+}
+
+static char *rna_MantaDomainSettings_path(PointerRNA *ptr)
+{
+ MantaDomainSettings *settings = (MantaDomainSettings *)ptr->data;
+ ModifierData *md = (ModifierData *)settings->mmd;
+ char name_esc[sizeof(md->name) * 2];
+
+ BLI_strescape(name_esc, md->name, sizeof(name_esc));
+ return BLI_sprintfN("modifiers[\"%s\"].domain_settings", name_esc);
+}
+
+static char *rna_MantaFlowSettings_path(PointerRNA *ptr)
+{
+ MantaFlowSettings *settings = (MantaFlowSettings *)ptr->data;
+ ModifierData *md = (ModifierData *)settings->mmd;
+ char name_esc[sizeof(md->name) * 2];
+
+ BLI_strescape(name_esc, md->name, sizeof(name_esc));
+ return BLI_sprintfN("modifiers[\"%s\"].flow_settings", name_esc);
+}
+
+static char *rna_MantaCollSettings_path(PointerRNA *ptr)
+{
+ MantaCollSettings *settings = (MantaCollSettings *)ptr->data;
+ ModifierData *md = (ModifierData *)settings->mmd;
+ char name_esc[sizeof(md->name) * 2];
+
+ BLI_strescape(name_esc, md->name, sizeof(name_esc));
+ return BLI_sprintfN("modifiers[\"%s\"].effec_settings", name_esc);
+}
+
+static int rna_MantaModifier_grid_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ MantaDomainSettings *mds = (MantaDomainSettings *)ptr->data;
+ float *density = NULL;
+ int size = 0;
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) {
+ /* high resolution smoke */
+ int res[3];
+
+ manta_smoke_turbulence_get_res(mds->fluid, res);
+ size = res[0] * res[1] * res[2];
+
+ density = manta_smoke_turbulence_get_density(mds->fluid);
+ }
+ else if (mds->fluid) {
+ /* regular resolution */
+ size = mds->res[0] * mds->res[1] * mds->res[2];
+ density = manta_smoke_get_density(mds->fluid);
+ }
+
+ length[0] = (density) ? size : 0;
+ return length[0];
+}
+
+static int rna_MantaModifier_color_grid_get_length(PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ rna_MantaModifier_grid_get_length(ptr, length);
+
+ length[0] *= 4;
+ return length[0];
+}
+
+static int rna_MantaModifier_velocity_grid_get_length(PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ MantaDomainSettings *mds = (MantaDomainSettings *)ptr->data;
+ float *vx = NULL;
+ float *vy = NULL;
+ float *vz = NULL;
+ int size = 0;
+
+ /* Velocity data is always low-resolution. */
+ if (mds->fluid) {
+ size = 3 * mds->res[0] * mds->res[1] * mds->res[2];
+ vx = manta_get_velocity_x(mds->fluid);
+ vy = manta_get_velocity_y(mds->fluid);
+ vz = manta_get_velocity_z(mds->fluid);
+ }
+
+ length[0] = (vx && vy && vz) ? size : 0;
+ return length[0];
+}
+
+static int rna_MantaModifier_heat_grid_get_length(PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ MantaDomainSettings *mds = (MantaDomainSettings *)ptr->data;
+ float *heat = NULL;
+ int size = 0;
+
+ /* Heat data is always low-resolution. */
+ if (mds->fluid) {
+ size = mds->res[0] * mds->res[1] * mds->res[2];
+ heat = manta_smoke_get_heat(mds->fluid);
+ }
+
+ length[0] = (heat) ? size : 0;
+ return length[0];
+}
+
+static void rna_MantaModifier_density_grid_get(PointerRNA *ptr, float *values)
+{
+ MantaDomainSettings *mds = (MantaDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_MantaModifier_grid_get_length(ptr, length);
+ float *density;
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid)
+ density = manta_smoke_turbulence_get_density(mds->fluid);
+ else
+ density = manta_smoke_get_density(mds->fluid);
+
+ memcpy(values, density, size * sizeof(float));
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+
+static void rna_MantaModifier_velocity_grid_get(PointerRNA *ptr, float *values)
+{
+ MantaDomainSettings *mds = (MantaDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_MantaModifier_velocity_grid_get_length(ptr, length);
+ float *vx, *vy, *vz;
+ int i;
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ vx = manta_get_velocity_x(mds->fluid);
+ vy = manta_get_velocity_y(mds->fluid);
+ vz = manta_get_velocity_z(mds->fluid);
+
+ for (i = 0; i < size; i += 3) {
+ *(values++) = *(vx++);
+ *(values++) = *(vy++);
+ *(values++) = *(vz++);
+ }
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+
+static void rna_MantaModifier_color_grid_get(PointerRNA *ptr, float *values)
+{
+ MantaDomainSettings *mds = (MantaDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_MantaModifier_grid_get_length(ptr, length);
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ if (!mds->fluid) {
+ memset(values, 0, size * sizeof(float));
+ }
+ else {
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE) {
+ if (manta_smoke_turbulence_has_colors(mds->fluid))
+ manta_smoke_turbulence_get_rgba(mds->fluid, values, 0);
+ else
+ manta_smoke_turbulence_get_rgba_from_density(mds->fluid, mds->active_color, values, 0);
+ }
+ else {
+ if (manta_smoke_has_colors(mds->fluid))
+ manta_smoke_get_rgba(mds->fluid, values, 0);
+ else
+ manta_smoke_get_rgba_from_density(mds->fluid, mds->active_color, values, 0);
+ }
+ }
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+
+static void rna_MantaModifier_flame_grid_get(PointerRNA *ptr, float *values)
+{
+ MantaDomainSettings *mds = (MantaDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_MantaModifier_grid_get_length(ptr, length);
+ float *flame;
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid)
+ flame = manta_smoke_turbulence_get_flame(mds->fluid);
+ else
+ flame = manta_smoke_get_flame(mds->fluid);
+
+ if (flame)
+ memcpy(values, flame, size * sizeof(float));
+ else
+ memset(values, 0, size * sizeof(float));
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+
+static void rna_MantaModifier_heat_grid_get(PointerRNA *ptr, float *values)
+{
+ MantaDomainSettings *mds = (MantaDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_MantaModifier_heat_grid_get_length(ptr, length);
+ float *heat;
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ heat = manta_smoke_get_heat(mds->fluid);
+
+ if (heat != NULL) {
+ /* scale heat values from -2.0-2.0 to -1.0-1.0. */
+ for (int i = 0; i < size; i++) {
+ values[i] = heat[i] * 0.5f;
+ }
+ }
+ else {
+ memset(values, 0, size * sizeof(float));
+ }
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+
+static void rna_MantaModifier_temperature_grid_get(PointerRNA *ptr, float *values)
+{
+ MantaDomainSettings *mds = (MantaDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_MantaModifier_grid_get_length(ptr, length);
+ float *flame;
+
+ BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ);
+
+ if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) {
+ flame = manta_smoke_turbulence_get_flame(mds->fluid);
+ }
+ else {
+ flame = manta_smoke_get_flame(mds->fluid);
+ }
+
+ if (flame) {
+ /* Output is such that 0..1 maps to 0..1000K */
+ float offset = mds->flame_ignition;
+ float scale = mds->flame_max_temp - mds->flame_ignition;
+
+ for (int i = 0; i < size; i++) {
+ values[i] = (flame[i] > 0.01f) ? offset + flame[i] * scale : 0.0f;
+ }
+ }
+ else {
+ memset(values, 0, size * sizeof(float));
+ }
+
+ BLI_rw_mutex_unlock(mds->fluid_mutex);
+}
+
+static void rna_MantaFlow_density_vgroup_get(PointerRNA *ptr, char *value)
+{
+ MantaFlowSettings *flow = (MantaFlowSettings *)ptr->data;
+ rna_object_vgroup_name_index_get(ptr, value, flow->vgroup_density);
+}
+
+static int rna_MantaFlow_density_vgroup_length(PointerRNA *ptr)
+{
+ MantaFlowSettings *flow = (MantaFlowSettings *)ptr->data;
+ return rna_object_vgroup_name_index_length(ptr, flow->vgroup_density);
+}
+
+static void rna_MantaFlow_density_vgroup_set(struct PointerRNA *ptr, const char *value)
+{
+ MantaFlowSettings *flow = (MantaFlowSettings *)ptr->data;
+ rna_object_vgroup_name_index_set(ptr, value, &flow->vgroup_density);
+}
+
+static void rna_MantaFlow_uvlayer_set(struct PointerRNA *ptr, const char *value)
+{
+ MantaFlowSettings *flow = (MantaFlowSettings *)ptr->data;
+ rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name));
+}
+
+static void rna_Manta_use_color_ramp_set(struct PointerRNA *ptr, bool value)
+{
+ MantaDomainSettings *mds = (MantaDomainSettings *)ptr->data;
+
+ mds->use_coba = value;
+
+ if (value && mds->coba == NULL) {
+ mds->coba = BKE_colorband_add(false);
+ }
+}
+
+static void rna_Manta_flowsource_set(struct PointerRNA *ptr, int value)
+{
+ MantaFlowSettings *settings = (MantaFlowSettings *)ptr->data;
+
+ if (value != settings->source) {
+ settings->source = value;
+ }
+}
+
+static const EnumPropertyItem *rna_Manta_flowsource_itemf(bContext *UNUSED(C),
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ MantaFlowSettings *settings = (MantaFlowSettings *)ptr->data;
+
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ int totitem = 0;
+
+ tmp.value = FLUID_FLOW_SOURCE_MESH;
+ tmp.identifier = "MESH";
+ tmp.icon = ICON_META_CUBE;
+ tmp.name = "Mesh";
+ tmp.description = "Emit fluid from mesh surface or volume";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ if (settings->type != FLUID_FLOW_TYPE_LIQUID) {
+ tmp.value = FLUID_FLOW_SOURCE_PARTICLES;
+ tmp.identifier = "PARTICLES";
+ tmp.icon = ICON_PARTICLES;
+ tmp.name = "Particle System";
+ tmp.description = "Emit smoke from particles";
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static void rna_Manta_flowtype_set(struct PointerRNA *ptr, int value)
+{
+ MantaFlowSettings *settings = (MantaFlowSettings *)ptr->data;
+
+ if (value != settings->type) {
+ settings->type = value;
+
+ /* Force flow source to mesh */
+ if (value == FLUID_FLOW_TYPE_LIQUID) {
+ rna_Manta_flowsource_set(ptr, FLUID_FLOW_SOURCE_MESH);
+ settings->surface_distance = 0.5f;
+ }
+ else {
+ settings->surface_distance = 1.5f;
+ }
+ }
+}
+
+#else
+
+static void rna_def_manta_mesh_vertices(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MantaVertexVelocity", NULL);
+ RNA_def_struct_ui_text(srna, "Fluid Mesh Velocity", "Velocity of a simulated fluid mesh");
+ RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL);
+
+ prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_float_sdna(prop, NULL, "vel");
+ RNA_def_property_ui_text(prop, "Velocity", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+}
+
+static void rna_def_manta_domain_settings(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem domain_types[] = {
+ {FLUID_DOMAIN_TYPE_GAS, "GAS", 0, "Gas", "Create domain for gases"},
+ {FLUID_DOMAIN_TYPE_LIQUID, "LIQUID", 0, "Liquid", "Create domain for liquids"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem prop_noise_type_items[] = {
+ {FLUID_NOISE_TYPE_WAVELET, "NOISEWAVE", 0, "Wavelet", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem prop_compression_items[] = {
+ {VDB_COMPRESSION_ZIP, "ZIP", 0, "Zip", "Effective but slow compression"},
+# ifdef WITH_OPENVDB_BLOSC
+ {VDB_COMPRESSION_BLOSC,
+ "BLOSC",
+ 0,
+ "Blosc",
+ "Multithreaded compression, similar in size and quality as 'Zip'"},
+# endif
+ {VDB_COMPRESSION_NONE, "NONE", 0, "None", "Do not use any compression"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem cache_comp_items[] = {
+ {SM_CACHE_LIGHT, "CACHELIGHT", 0, "Lite", "Fast but not so effective compression"},
+ {SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem smoke_highres_sampling_items[] = {
+ {SM_HRES_FULLSAMPLE, "FULLSAMPLE", 0, "Full Sample", ""},
+ {SM_HRES_LINEAR, "LINEAR", 0, "Linear", ""},
+ {SM_HRES_NEAREST, "NEAREST", 0, "Nearest", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem smoke_data_depth_items[] = {
+ {16, "16", 0, "Float (Half)", "Half float (16 bit data)"},
+ {0, "32", 0, "Float (Full)", "Full float (32 bit data)"}, /* default */
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static EnumPropertyItem fluid_mesh_quality_items[] = {
+ {FLUID_DOMAIN_MESH_IMPROVED,
+ "IMPROVED",
+ 0,
+ "Final",
+ "Use improved particle levelset (slower but more precise and with mesh smoothening "
+ "options)"},
+ {FLUID_DOMAIN_MESH_UNION,
+ "UNION",
+ 0,
+ "Preview",
+ "Use union particle levelset (faster but lower quality)"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static EnumPropertyItem fluid_guiding_source_items[] = {
+ {FLUID_DOMAIN_GUIDING_SRC_DOMAIN,
+ "DOMAIN",
+ 0,
+ "Domain",
+ "Use a fluid domain for guiding (domain needs to be baked already so that velocities can "
+ "be extracted but can be of any type)"},
+ {FLUID_DOMAIN_GUIDING_SRC_EFFECTOR,
+ "EFFECTOR",
+ 0,
+ "Effector",
+ "Use guiding (effector) objects to create fluid guiding (guiding objects should be "
+ "animated and baked once set up completely)"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* Cache type - generated dynamically based on domain type */
+ static EnumPropertyItem cache_file_type_items[] = {
+ {0, "NONE", 0, "", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem view_items[] = {
+ {FLUID_DOMAIN_SLICE_VIEW_ALIGNED,
+ "VIEW_ALIGNED",
+ 0,
+ "View",
+ "Slice volume parallel to the view plane"},
+ {FLUID_DOMAIN_SLICE_AXIS_ALIGNED,
+ "AXIS_ALIGNED",
+ 0,
+ "Axis",
+ "Slice volume parallel to the major axis"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem axis_slice_method_items[] = {
+ {AXIS_SLICE_FULL, "FULL", 0, "Full", "Slice the whole domain object"},
+ {AXIS_SLICE_SINGLE, "SINGLE", 0, "Single", "Perform a single slice of the domain object"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem interp_method_item[] = {
+ {VOLUME_INTERP_LINEAR, "LINEAR", 0, "Linear", "Good smoothness and speed"},
+ {VOLUME_INTERP_CUBIC,
+ "CUBIC",
+ 0,
+ "Cubic",
+ "Smoothed high quality interpolation, but slower"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem axis_slice_position_items[] = {
+ {SLICE_AXIS_AUTO,
+ "AUTO",
+ 0,
+ "Auto",
+ "Adjust slice direction according to the view direction"},
+ {SLICE_AXIS_X, "X", 0, "X", "Slice along the X axis"},
+ {SLICE_AXIS_Y, "Y", 0, "Y", "Slice along the Y axis"},
+ {SLICE_AXIS_Z, "Z", 0, "Z", "Slice along the Z axis"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem vector_draw_items[] = {
+ {VECTOR_DRAW_NEEDLE, "NEEDLE", 0, "Needle", "Display vectors as needles"},
+ {VECTOR_DRAW_STREAMLINE, "STREAMLINE", 0, "Streamlines", "Display vectors as streamlines"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem sndparticle_boundary_items[] = {
+ {SNDPARTICLE_BOUNDARY_DELETE,
+ "DELETE",
+ 0,
+ "Delete",
+ "Delete secondary particles that are inside obstacles or left the domain"},
+ {SNDPARTICLE_BOUNDARY_PUSHOUT,
+ "PUSHOUT",
+ 0,
+ "Push Out",
+ "Push secondary particles that left the domain back into the domain"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem sndparticle_combined_export_items[] = {
+ {SNDPARTICLE_COMBINED_EXPORT_OFF,
+ "OFF",
+ 0,
+ "Off",
+ "Create a seperate particle system for every secondary particle type"},
+ {SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM,
+ "SPRAY_FOAM",
+ 0,
+ "Spray + Foam",
+ "Spray and foam particles are saved in the same particle system"},
+ {SNDPARTICLE_COMBINED_EXPORT_SPRAY_BUBBLE,
+ "SPRAY_BUBBLES",
+ 0,
+ "Spray + Bubbles",
+ "Spray and bubble particles are saved in the same particle system"},
+ {SNDPARTICLE_COMBINED_EXPORT_FOAM_BUBBLE,
+ "FOAM_BUBBLES",
+ 0,
+ "Foam + Bubbles",
+ "Foam and bubbles particles are saved in the same particle system"},
+ {SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM_BUBBLE,
+ "SPRAY_FOAM_BUBBLES",
+ 0,
+ "Spray + Foam + Bubbles",
+ "Create one particle system that contains all three secondary particle types"},
+ {0, NULL, 0, NULL, NULL}};
+
+ srna = RNA_def_struct(brna, "MantaDomainSettings", NULL);
+ RNA_def_struct_ui_text(srna, "Domain Settings", "Fluid domain settings");
+ RNA_def_struct_sdna(srna, "MantaDomainSettings");
+ RNA_def_struct_path_func(srna, "rna_MantaDomainSettings_path");
+
+ prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "EffectorWeights");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Effector Weights", "");
+
+ /* object collections */
+
+ prop = RNA_def_property(srna, "collision_group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "coll_group");
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Collision Collection", "Limit collisions to this collection");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset_dependency");
+
+ prop = RNA_def_property(srna, "fluid_group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "fluid_group");
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Fluid Collection", "Limit fluid objects to this collection");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset_dependency");
+
+ prop = RNA_def_property(srna, "effector_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "eff_group");
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Effector Collection", "Limit effectors to this collection");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset_dependency");
+
+ /* grid access */
+
+ prop = RNA_def_property(srna, "density_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_MantaModifier_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_MantaModifier_density_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Density Grid", "Smoke density grid");
+
+ prop = RNA_def_property(srna, "velocity_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_MantaModifier_velocity_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_MantaModifier_velocity_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Velocity Grid", "Smoke velocity grid");
+
+ prop = RNA_def_property(srna, "flame_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_MantaModifier_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_MantaModifier_flame_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Flame Grid", "Smoke flame grid");
+
+ prop = RNA_def_property(srna, "color_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_MantaModifier_color_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_MantaModifier_color_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Color Grid", "Smoke color grid");
+
+ prop = RNA_def_property(srna, "heat_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_MantaModifier_heat_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_MantaModifier_heat_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Heat Grid", "Smoke heat grid");
+
+ prop = RNA_def_property(srna, "temperature_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_MantaModifier_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_MantaModifier_temperature_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(
+ prop, "Temperature Grid", "Smoke temperature grid, range 0..1 represents 0..1000K");
+
+ /* domain object data */
+
+ prop = RNA_def_property(srna,
+ "start_point",
+ PROP_FLOAT,
+ PROP_XYZ); /* can change each frame when using adaptive domain */
+ RNA_def_property_float_sdna(prop, NULL, "p0");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "p0", "Start point");
+
+ prop = RNA_def_property(srna,
+ "cell_size",
+ PROP_FLOAT,
+ PROP_XYZ); /* can change each frame when using adaptive domain */
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "cell_size", "Cell Size");
+
+ prop = RNA_def_property(srna,
+ "domain_resolution",
+ PROP_INT,
+ PROP_XYZ); /* can change each frame when using adaptive domain */
+ RNA_def_property_int_sdna(prop, NULL, "res");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "res", "Smoke Grid Resolution");
+
+ /* adaptive domain options */
+
+ prop = RNA_def_property(srna, "additional_res", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "adapt_res");
+ RNA_def_property_range(prop, 0, 512);
+ RNA_def_property_ui_text(prop, "Additional", "Maximum number of additional cells");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "adapt_margin", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "adapt_margin");
+ RNA_def_property_range(prop, 2, 24);
+ RNA_def_property_ui_text(
+ prop, "Margin", "Margin added around fluid to minimize boundary interference");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "adapt_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.01, 0.5);
+ RNA_def_property_ui_text(
+ prop, "Threshold", "Maximum amount of fluid cell can contain before it is considered empty");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "use_adaptive_domain", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
+ RNA_def_property_ui_text(
+ prop, "Adaptive Domain", "Adapt simulation resolution and size to fluid");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ /* fluid domain options */
+
+ prop = RNA_def_property(srna, "resolution_max", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "maxres");
+ RNA_def_property_range(prop, 6, 10000);
+ RNA_def_property_ui_range(prop, 24, 10000, 2, -1);
+ RNA_def_property_ui_text(prop, "Max Res", "Resolution used for the fluid domain");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_front", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_FRONT);
+ RNA_def_property_ui_text(prop, "Front", "Enable collisons with front domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_back", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_BACK);
+ RNA_def_property_ui_text(prop, "Back", "Enable collisons with back domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_right", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_RIGHT);
+ RNA_def_property_ui_text(prop, "Right", "Enable collisons with right domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_left", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_LEFT);
+ RNA_def_property_ui_text(prop, "Left", "Enable collisons with left domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_top", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_TOP);
+ RNA_def_property_ui_text(prop, "Top", "Enable collisons with top domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_collision_border_bottom", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_BOTTOM);
+ RNA_def_property_ui_text(prop, "Bottom", "Enable collisons with bottom domain border");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION);
+ RNA_def_property_float_sdna(prop, NULL, "gravity");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, -1000.1, 1000.1);
+ RNA_def_property_ui_text(prop, "Gravity", "Gravity in X, Y and Z direction");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "domain_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, domain_types);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_Manta_domaintype_set", NULL);
+ RNA_def_property_ui_text(prop, "Domain Type", "Change domain type of the simulation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Manta_reset");
+
+ /* smoke domain options */
+
+ prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "alpha");
+ RNA_def_property_range(prop, -5.0, 5.0);
+ RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
+ RNA_def_property_ui_text(
+ prop,
+ "Density",
+ "How much density affects smoke motion (higher value results in faster rising smoke)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "beta", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "beta");
+ RNA_def_property_range(prop, -5.0, 5.0);
+ RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
+ RNA_def_property_ui_text(
+ prop,
+ "Heat",
+ "How much heat affects smoke motion (higher value results in faster rising smoke)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "dissolve_speed", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "diss_speed");
+ RNA_def_property_range(prop, 1.0, 10000.0);
+ RNA_def_property_ui_range(prop, 1.0, 10000.0, 1, -1);
+ RNA_def_property_ui_text(prop, "Dissolve Speed", "Dissolve Speed");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "vorticity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vorticity");
+ RNA_def_property_range(prop, 0.0, 4.0);
+ RNA_def_property_ui_text(prop, "Vorticity", "Amount of turbulence/rotation in fluid");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "highres_sampling", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, smoke_highres_sampling_items);
+ RNA_def_property_ui_text(prop, "Emitter", "Method for sampling the high resolution flow");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "use_dissolve_smoke", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_DISSOLVE);
+ RNA_def_property_ui_text(prop, "Dissolve Smoke", "Enable smoke to disappear over time");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_DISSOLVE_LOG);
+ RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x ");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ /* flame options */
+
+ prop = RNA_def_property(srna, "burning_rate", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.01, 4.0);
+ RNA_def_property_ui_range(prop, 0.01, 2.0, 1.0, 5);
+ RNA_def_property_ui_text(
+ prop, "Speed", "Speed of the burning reaction (use larger values for smaller flame)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "flame_smoke", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 8.0);
+ RNA_def_property_ui_range(prop, 0.0, 4.0, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Smoke", "Amount of smoke created by burning fuel");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "flame_vorticity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Vorticity", "Additional vorticity for the flames");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "flame_ignition", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.5, 5.0);
+ RNA_def_property_ui_range(prop, 0.5, 2.5, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Ignition", "Minimum temperature of flames");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "flame_max_temp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 1.0, 10.0);
+ RNA_def_property_ui_range(prop, 1.0, 5.0, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Maximum", "Maximum temperature of flames");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "flame_smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke emitted from burning fuel");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ /* noise options */
+
+ prop = RNA_def_property(srna, "noise_strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "noise_strength");
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_range(prop, 0.0, 10.0, 1, 2);
+ RNA_def_property_ui_text(prop, "Strength", "Strength of noise");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "noise_pos_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "noise_pos_scale");
+ RNA_def_property_range(prop, 0.0001, 10.0);
+ RNA_def_property_ui_text(
+ prop, "Scale", "Scale of noise (higher value results in larger vortices)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "noise_time_anim", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "noise_time_anim");
+ RNA_def_property_range(prop, 0.0001, 10.0);
+ RNA_def_property_ui_text(prop, "Time", "Animation time of noise");
+
+ prop = RNA_def_property(srna, "noise_scale", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "noise_scale");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_range(prop, 1, 10, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Noise scale",
+ "Scale underlying noise grids by this factor. Noise grids have size "
+ "factor times base resolution");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "noise_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "noise_type");
+ RNA_def_property_enum_items(prop, prop_noise_type_items);
+ RNA_def_property_ui_text(
+ prop, "Noise Method", "Noise method which is used for creating the high resolution");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_noise", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_NOISE);
+ RNA_def_property_ui_text(prop, "Use Noise", "Enable fluid noise (using amplification)");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ /* liquid domain options */
+
+ prop = RNA_def_property(srna, "particle_randomness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(prop, "Randomness", "Randomness factor for particle sampling");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "particle_number", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, 5);
+ RNA_def_property_ui_text(
+ prop, "Number", "Particle number factor (higher value results in more particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "particle_minimum", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 1000);
+ RNA_def_property_ui_text(prop,
+ "Minimum",
+ "Minimum number of particles per cell (ensures that each cell has at "
+ "least this amount of particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "particle_maximum", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 1000);
+ RNA_def_property_ui_text(prop,
+ "Maximum",
+ "Maximum number of particles per cell (ensures that each cell has at "
+ "most this amount of particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "particle_radius", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(
+ prop, "Radius", "Particle radius factor (higher value results in larger particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "particle_band_width", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Width",
+ "Particle (narrow) band width (higher value results in thicker band and more particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "use_flip_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_FLIP);
+ RNA_def_property_ui_text(prop, "FLIP", "Create FLIP particle system");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Manta_flip_parts_update");
+
+ /* diffusion options */
+
+ prop = RNA_def_property(srna, "surface_tension", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Tension",
+ "Surface tension of liquid (higher value results in greater hydrophobic behaviour)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "viscosity_base", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "viscosity_base");
+ RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_ui_text(
+ prop,
+ "Viscosity Base",
+ "Viscosity setting: value that is multiplied by 10 to the power of (exponent*-1)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "viscosity_exponent", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "viscosity_exponent");
+ RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_ui_text(
+ prop,
+ "Viscosity Exponent",
+ "Negative exponent for the viscosity value (to simplify entering small values "
+ "e.g. 5*10^-6)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "domain_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.001, 10000.0);
+ RNA_def_property_ui_text(prop, "Meters", "Domain size in meters (longest domain side)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ /* mesh options options */
+
+ prop = RNA_def_property(srna, "mesh_concave_upper", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Upper Concavity",
+ "Upper mesh concavity bound (high values tend to smoothen and fill out concave regions)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "mesh_concave_lower", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Lower Concavity",
+ "Lower mesh concavity bound (high values tend to smoothen and fill out concave regions)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "mesh_smoothen_pos", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Smoothen Pos", "Positive mesh smoothening");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "mesh_smoothen_neg", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Smoothen Neg", "Negative mesh smoothening");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "mesh_scale", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "mesh_scale");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_range(prop, 1, 10, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Mesh scale",
+ "Scale underlying mesh grids by this factor. Mesh grids have size "
+ "factor times base resolution");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "mesh_generator", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mesh_generator");
+ RNA_def_property_enum_items(prop, fluid_mesh_quality_items);
+ RNA_def_property_ui_text(prop, "Mesh generator", "Which particle levelset generator to use");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Manta_update");
+
+ prop = RNA_def_property(srna, "mesh_vertices", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "mesh_velocities", "totvert");
+ RNA_def_property_struct_type(prop, "MantaVertexVelocity");
+ RNA_def_property_ui_text(
+ prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation");
+
+ rna_def_manta_mesh_vertices(brna);
+
+ prop = RNA_def_property(srna, "use_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_MESH);
+ RNA_def_property_ui_text(prop, "Use Mesh", "Enable fluid mesh (using amplification)");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_speed_vectors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_SPEED_VECTORS);
+ RNA_def_property_ui_text(
+ prop,
+ "Speed Vectors",
+ "Generate speed vectors (will be loaded automatically during render for motion blur)");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ /* secondary particles options */
+
+ prop = RNA_def_property(srna, "sndparticle_tau_min_wc", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
+ RNA_def_property_ui_text(prop,
+ "tauMin_wc",
+ "Lower clamping threshold for marking fluid cells as wave crests "
+ "(lower values result in more marked cells)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_tau_max_wc", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
+ RNA_def_property_ui_text(prop,
+ "tauMax_wc",
+ "Upper clamping threshold for marking fluid cells as wave crests "
+ "(higher values result in less marked cells)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_tau_min_ta", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 3);
+ RNA_def_property_ui_text(prop,
+ "tauMin_ta",
+ "Lower clamping threshold for marking fluid cells where air is trapped "
+ "(lower values result in more marked cells)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_tau_max_ta", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
+ RNA_def_property_ui_text(prop,
+ "tauMax_ta",
+ "Upper clamping threshold for marking fluid cells where air is trapped "
+ "(higher values result in less marked cells)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_tau_min_k", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
+ RNA_def_property_ui_text(
+ prop,
+ "tauMin_k",
+ "Lower clamping threshold that indicates the fluid speed where cells start to emit "
+ "particles (lower values result in generally more particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_tau_max_k", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
+ RNA_def_property_ui_text(
+ prop,
+ "tauMax_k",
+ "Upper clamping threshold that indicates the fluid speed where cells no longer emit more "
+ "particles (higher values result in generally less particles)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_k_wc", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 10000);
+ RNA_def_property_ui_range(prop, 0, 10000, 1.0, -1);
+ RNA_def_property_ui_text(prop,
+ "Wave Crest Sampling",
+ "Maximum number of particles generated per wave crest cell per frame");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_k_ta", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 10000);
+ RNA_def_property_ui_range(prop, 0, 10000, 1.0, -1);
+ RNA_def_property_ui_text(prop,
+ "Trapped Air Sampling",
+ "Maximum number of particles generated per trapped air cell per frame");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_k_b", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 10.0, 2);
+ RNA_def_property_ui_text(prop,
+ "Buoyancy",
+ "Amount of buoyancy force that rises bubbles (high values result in "
+ "bubble movement mainly upwards)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_k_d", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 10.0, 2);
+ RNA_def_property_ui_text(prop,
+ "Drag",
+ "Amount of drag force that moves bubbles along with the fluid (high "
+ "values result in bubble movement mainly along with the fluid)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_l_min", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10000.0);
+ RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 1);
+ RNA_def_property_ui_text(prop, "Lifetime(min)", "Lowest possible particle lifetime");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_l_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10000.0);
+ RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 1);
+ RNA_def_property_ui_text(prop, "Lifetime(max)", "Highest possible particle lifetime");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_boundary", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "sndparticle_boundary");
+ RNA_def_property_enum_items(prop, sndparticle_boundary_items);
+ RNA_def_property_ui_text(
+ prop, "Particles in Boundary", "How particles that left the domain are treated");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "sndparticle_combined_export", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "sndparticle_combined_export");
+ RNA_def_property_enum_items(prop, sndparticle_combined_export_items);
+ RNA_def_property_ui_text(
+ prop,
+ "Combined Export",
+ "Determines which particle systems are created from secondary particles");
+ RNA_def_property_update(prop, 0, "rna_Manta_combined_export_update");
+
+ prop = RNA_def_property(srna, "sndparticle_potential_radius", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "sndparticle_potential_radius");
+ RNA_def_property_range(prop, 1, 4);
+ RNA_def_property_ui_range(prop, 1, 4, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Potential Radius",
+ "Radius to compute potential for each cell (higher values are slower "
+ "but create smoother potential grids)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "sndparticle_update_radius", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "sndparticle_update_radius");
+ RNA_def_property_range(prop, 1, 4);
+ RNA_def_property_ui_range(prop, 1, 4, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Update Radius",
+ "Radius to compute position update for each particle (higher values "
+ "are slower but particles move less chaotic)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "particle_scale", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "particle_scale");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_range(prop, 1, 10, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Mesh scale",
+ "Scale underlying particle grids by this factor. Particle grids have "
+ "size factor times base resolution");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_spray_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_SPRAY);
+ RNA_def_property_ui_text(prop, "Spray", "Create spray particle system");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Manta_spray_parts_update");
+
+ prop = RNA_def_property(srna, "use_bubble_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_BUBBLE);
+ RNA_def_property_ui_text(prop, "Bubble", "Create bubble particle system");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Manta_bubble_parts_update");
+
+ prop = RNA_def_property(srna, "use_foam_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_FOAM);
+ RNA_def_property_ui_text(prop, "Foam", "Create foam particle system");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Manta_foam_parts_update");
+
+ prop = RNA_def_property(srna, "use_tracer_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_TRACER);
+ RNA_def_property_ui_text(prop, "Tracer", "Create tracer particle system");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Manta_tracer_parts_update");
+
+ /* fluid guiding options */
+
+ prop = RNA_def_property(srna, "guiding_alpha", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "guiding_alpha");
+ RNA_def_property_range(prop, 1.0, 100.0);
+ RNA_def_property_ui_text(prop, "Weight", "Guiding weight (higher value results in greater lag)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "guiding_beta", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "guiding_beta");
+ RNA_def_property_range(prop, 1, 50);
+ RNA_def_property_ui_text(prop, "Size", "Guiding size (higher value results in larger vortices)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "guiding_vel_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "guiding_vel_factor");
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_text(
+ prop,
+ "Weight",
+ "Guiding velocity factor (higher value results in bigger guiding velocities)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "guiding_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "guiding_source");
+ RNA_def_property_enum_items(prop, fluid_guiding_source_items);
+ RNA_def_property_ui_text(prop, "Guiding source", "Choose where to get guiding velocities from");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Manta_update");
+
+ prop = RNA_def_property(srna, "guiding_parent", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "guiding_parent");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_Manta_guiding_parent_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop,
+ "",
+ "Use velocities from this object for the guiding effect (object needs "
+ "to have fluid modifier and be of type domain))");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Manta_update");
+
+ prop = RNA_def_property(srna, "use_guiding", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_GUIDING);
+ RNA_def_property_ui_text(prop, "Use Guiding", "Enable fluid guiding");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ /* cache options */
+
+ prop = RNA_def_property(srna, "cache_frame_start", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_start");
+ RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
+ RNA_def_property_ui_range(prop, 1, MAXFRAME, 1, 1);
+ RNA_def_property_ui_text(prop, "Start", "Frame on which the simulation starts");
+
+ prop = RNA_def_property(srna, "cache_frame_end", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_end");
+ RNA_def_property_range(prop, 1, MAXFRAME);
+ RNA_def_property_ui_text(prop, "End", "Frame on which the simulation stops");
+
+ prop = RNA_def_property(srna, "cache_frame_pause_data", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_data");
+
+ prop = RNA_def_property(srna, "cache_frame_pause_noise", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_noise");
+
+ prop = RNA_def_property(srna, "cache_frame_pause_mesh", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_mesh");
+
+ prop = RNA_def_property(srna, "cache_frame_pause_particles", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_particles");
+
+ prop = RNA_def_property(srna, "cache_frame_pause_guiding", PROP_INT, PROP_TIME);
+ RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_guiding");
+
+ prop = RNA_def_property(srna, "cache_mesh_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_mesh_format");
+ RNA_def_property_enum_items(prop, cache_file_type_items);
+ RNA_def_property_enum_funcs(
+ prop, NULL, "rna_Manta_cachetype_mesh_set", "rna_Manta_cachetype_mesh_itemf");
+ RNA_def_property_ui_text(
+ prop, "File Format", "Select the file format to be used for caching surface data");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "cache_data_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_data_format");
+ RNA_def_property_enum_items(prop, cache_file_type_items);
+ RNA_def_property_enum_funcs(
+ prop, NULL, "rna_Manta_cachetype_data_set", "rna_Manta_cachetype_volume_itemf");
+ RNA_def_property_ui_text(
+ prop, "File Format", "Select the file format to be used for caching volumetric data");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "cache_particle_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_particle_format");
+ RNA_def_property_enum_items(prop, cache_file_type_items);
+ RNA_def_property_enum_funcs(
+ prop, NULL, "rna_Manta_cachetype_particle_set", "rna_Manta_cachetype_particle_itemf");
+ RNA_def_property_ui_text(
+ prop, "File Format", "Select the file format to be used for caching particle data");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "cache_noise_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_noise_format");
+ RNA_def_property_enum_items(prop, cache_file_type_items);
+ RNA_def_property_enum_funcs(
+ prop, NULL, "rna_Manta_cachetype_noise_set", "rna_Manta_cachetype_volume_itemf");
+ RNA_def_property_ui_text(
+ prop, "File Format", "Select the file format to be used for caching noise data");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "cache_directory", PROP_STRING, PROP_DIRPATH);
+ RNA_def_property_string_maxlength(prop, FILE_MAX);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Manta_cache_directory_set");
+ RNA_def_property_string_sdna(prop, NULL, "cache_directory");
+ RNA_def_property_ui_text(prop, "Cache directory", "Directory that contains fluid cache files");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "cache_baking_data", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_DATA);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "cache_baked_data", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_DATA);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "cache_baking_noise", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_NOISE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "cache_baked_noise", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_NOISE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "cache_baking_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_MESH);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "cache_baked_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_MESH);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "cache_baking_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_PARTICLES);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "cache_baked_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_PARTICLES);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "cache_baking_guiding", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_GUIDING);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "cache_baked_guiding", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_GUIDING);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "export_manta_script", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_EXPORT_MANTA_SCRIPT);
+ RNA_def_property_ui_text(
+ prop,
+ "Export Mantaflow Script",
+ "Generate and export Mantaflow script from current domain settings during bake");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ /* time options */
+
+ prop = RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "time_scale");
+ RNA_def_property_range(prop, 0.0001, 10.0);
+ RNA_def_property_ui_text(prop, "Time Scale", "Adjust simulation speed");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "cfl_condition", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "cfl_condition");
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(
+ prop, "CFL", "Maximal velocity per cell (higher value results in larger timesteps)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ prop = RNA_def_property(srna, "use_adaptive_stepping", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_ADAPTIVE_TIME);
+ RNA_def_property_ui_text(prop, "Adaptive stepping", "Enable adaptive time-stepping");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_resetCache");
+
+ /* display settings */
+
+ prop = RNA_def_property(srna, "slice_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "slice_method");
+ RNA_def_property_enum_items(prop, view_items);
+ RNA_def_property_ui_text(prop, "View Method", "How to slice the volume for viewport rendering");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "axis_slice_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "axis_slice_method");
+ RNA_def_property_enum_items(prop, axis_slice_method_items);
+ RNA_def_property_ui_text(prop, "Method", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "slice_axis");
+ RNA_def_property_enum_items(prop, axis_slice_position_items);
+ RNA_def_property_ui_text(prop, "Axis", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_per_voxel", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "slice_per_voxel");
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 5.0, 0.1, 1);
+ RNA_def_property_ui_text(
+ prop, "Slice Per Voxel", "How many slices per voxel should be generated");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_depth", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "slice_depth");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Position", "Position of the slice");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "display_thickness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "display_thickness");
+ RNA_def_property_range(prop, 0.001, 1000.0);
+ RNA_def_property_ui_range(prop, 0.1, 100.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "display_interpolation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "interp_method");
+ RNA_def_property_enum_items(prop, interp_method_item);
+ RNA_def_property_ui_text(
+ prop, "Interpolation", "Interpolation method to use for smoke/fire volumes in solid mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "show_velocity", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "draw_velocity", 0);
+ RNA_def_property_ui_text(
+ prop, "Display Velocity", "Toggle visualization of the velocity field as needles");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "vector_display_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "vector_draw_type");
+ RNA_def_property_enum_items(prop, vector_draw_items);
+ RNA_def_property_ui_text(prop, "Display Type", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "vector_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vector_scale");
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ /* --------- Color mapping. --------- */
+
+ prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_Manta_use_color_ramp_set");
+ RNA_def_property_ui_text(
+ prop,
+ "Use Color Ramp",
+ "Render a simulation field while mapping its voxels values to the colors of a ramp");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ static const EnumPropertyItem coba_field_items[] = {
+ {FLUID_DOMAIN_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"},
+ {FLUID_DOMAIN_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"},
+ {FLUID_DOMAIN_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"},
+ {FLUID_DOMAIN_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"},
+ {FLUID_DOMAIN_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"},
+ {FLUID_DOMAIN_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"},
+ {FLUID_DOMAIN_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"},
+ {FLUID_DOMAIN_FIELD_VELOCITY_X,
+ "VELOCITY_X",
+ 0,
+ "X Velocity",
+ "X component of the velocity field"},
+ {FLUID_DOMAIN_FIELD_VELOCITY_Y,
+ "VELOCITY_Y",
+ 0,
+ "Y Velocity",
+ "Y component of the velocity field"},
+ {FLUID_DOMAIN_FIELD_VELOCITY_Z,
+ "VELOCITY_Z",
+ 0,
+ "Z Velocity",
+ "Z component of the velocity field"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "coba_field");
+ RNA_def_property_enum_items(prop, coba_field_items);
+ RNA_def_property_ui_text(prop, "Field", "Simulation field to color map");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "coba");
+ RNA_def_property_struct_type(prop, "ColorRamp");
+ RNA_def_property_ui_text(prop, "Color Ramp", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "clipping", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "clipping");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
+ RNA_def_property_ui_text(
+ prop,
+ "Clipping",
+ "Value under which voxels are considered empty space to optimize caching and rendering");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ /* -- Deprecated / unsed options (below)-- */
+
+ /* pointcache options */
+
+ prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "point_cache[0]");
+ RNA_def_property_struct_type(prop, "PointCache");
+ RNA_def_property_ui_text(prop, "Point Cache", "");
+
+ prop = RNA_def_property(srna, "point_cache_compress_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_comp");
+ RNA_def_property_enum_items(prop, cache_comp_items);
+ RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used");
+
+ /* OpenVDB options */
+
+ prop = RNA_def_property(srna, "openvdb_cache_compress_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "openvdb_comp");
+ RNA_def_property_enum_items(prop, prop_compression_items);
+ RNA_def_property_ui_text(prop, "Compression", "Compression method to be used");
+
+ prop = RNA_def_property(srna, "data_depth", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_depth");
+ RNA_def_property_enum_items(prop, smoke_data_depth_items);
+ RNA_def_property_ui_text(prop,
+ "Data Depth",
+ "Bit depth for writing all scalar (including vector) "
+ "lower values reduce file size");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+}
+
+static void rna_def_manta_flow_settings(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem flow_types[] = {
+ {FLUID_FLOW_TYPE_SMOKE, "SMOKE", 0, "Smoke", "Add smoke"},
+ {FLUID_FLOW_TYPE_SMOKEFIRE, "BOTH", 0, "Fire + Smoke", "Add fire and smoke"},
+ {FLUID_FLOW_TYPE_FIRE, "FIRE", 0, "Fire", "Add fire"},
+ {FLUID_FLOW_TYPE_LIQUID, "LIQUID", 0, "Liquid", "Add liquid"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static EnumPropertyItem flow_behaviors[] = {
+ {FLUID_FLOW_BEHAVIOR_INFLOW, "INFLOW", 0, "Inflow", "Add fluid to simulation"},
+ {FLUID_FLOW_BEHAVIOR_OUTFLOW, "OUTFLOW", 0, "Outflow", "Delete fluid from simulation"},
+ {FLUID_FLOW_BEHAVIOR_GEOMETRY,
+ "GEOMETRY",
+ 0,
+ "Geometry",
+ "Only use given geometry for fluid"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* Flow source - generated dynamically based on flow type */
+ static EnumPropertyItem flow_sources[] = {
+ {0, "NONE", 0, "", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem flow_texture_types[] = {
+ {FLUID_FLOW_TEXTURE_MAP_AUTO,
+ "AUTO",
+ 0,
+ "Generated",
+ "Generated coordinates centered to flow object"},
+ {FLUID_FLOW_TEXTURE_MAP_UV, "UV", 0, "UV", "Use UV layer for texture coordinates"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "MantaFlowSettings", NULL);
+ RNA_def_struct_ui_text(srna, "Flow Settings", "Fluid flow settings");
+ RNA_def_struct_sdna(srna, "MantaFlowSettings");
+ RNA_def_struct_path_func(srna, "rna_MantaFlowSettings_path");
+
+ prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "density");
+ RNA_def_property_range(prop, 0.0, 1);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 4);
+ RNA_def_property_ui_text(prop, "Density", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "color");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "fuel_amount", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10);
+ RNA_def_property_ui_range(prop, 0.0, 5.0, 1.0, 4);
+ RNA_def_property_ui_text(prop, "Flame Rate", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "temperature", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "temp");
+ RNA_def_property_range(prop, -10, 10);
+ RNA_def_property_ui_range(prop, -10, 10, 1, 1);
+ RNA_def_property_ui_text(prop, "Temp. Diff.", "Temperature difference to ambient temperature");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "psys");
+ RNA_def_property_struct_type(prop, "ParticleSystem");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Particle Systems", "Particle systems emitted from the object");
+ RNA_def_property_update(prop, 0, "rna_Manta_reset_dependency");
+
+ prop = RNA_def_property(srna, "flow_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, flow_types);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_Manta_flowtype_set", NULL);
+ RNA_def_property_ui_text(prop, "Flow Type", "Change type of fluid in the simulation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "flow_behavior", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "behavior");
+ RNA_def_property_enum_items(prop, flow_behaviors);
+ RNA_def_property_ui_text(prop, "Flow Behavior", "Change flow behavior in the simulation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "flow_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "source");
+ RNA_def_property_enum_items(prop, flow_sources);
+ RNA_def_property_enum_funcs(
+ prop, NULL, "rna_Manta_flowsource_set", "rna_Manta_flowsource_itemf");
+ RNA_def_property_ui_text(prop, "Source", "Change how fluid is emitted");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_absolute", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_ABSOLUTE);
+ RNA_def_property_ui_text(prop,
+ "Absolute Density",
+ "Only allow given density value in emitter area and will not add up");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_initial_velocity", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_INITVELOCITY);
+ RNA_def_property_ui_text(
+ prop, "Initial Velocity", "Fluid has some initial velocity when it is emitted");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vel_multi");
+ RNA_def_property_range(prop, -100.0, 100.0);
+ RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
+ RNA_def_property_ui_text(prop,
+ "Source",
+ "Multiplier of source velocity passed to fluid (source velocity is "
+ "non-zero only if object is moving)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "velocity_normal", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vel_normal");
+ RNA_def_property_range(prop, -100.0, 100.0);
+ RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Normal", "Amount of normal directional velocity");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "velocity_random", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vel_random");
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_range(prop, 0.0, 2.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Random", "Amount of random velocity");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "velocity_coord", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "vel_coord");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, -1000.1, 1000.1);
+ RNA_def_property_ui_text(prop, "Initial", "Initial velocity in X, Y and Z direction");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "volume_density", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Volume", "Factor for smoke emitted from inside the mesh volume");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Surface", "Maximum distance from mesh surface to emit fluid");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "particle_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.1, 20.0);
+ RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Size", "Particle size in simulation cells");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_particle_size", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_PART_SIZE);
+ RNA_def_property_ui_text(
+ prop, "Set Size", "Set particle size in simulation cells or use nearest cell");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_inflow", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_INFLOW);
+ RNA_def_property_ui_text(prop, "Enabled", "Control when to apply inflow");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "subframes", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 50);
+ RNA_def_property_ui_range(prop, 0, 10, 1, -1);
+ RNA_def_property_ui_text(prop,
+ "Subframes",
+ "Number of additional samples to take between frames to improve "
+ "quality of fast moving flows");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "density_vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop,
+ "rna_MantaFlow_density_vgroup_get",
+ "rna_MantaFlow_density_vgroup_length",
+ "rna_MantaFlow_density_vgroup_set");
+ RNA_def_property_ui_text(
+ prop, "Vertex Group", "Name of vertex group which determines surface emission rate");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "use_texture", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_TEXTUREEMIT);
+ RNA_def_property_ui_text(prop, "Use Texture", "Use a texture to control emission strength");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "texture_map_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "texture_type");
+ RNA_def_property_enum_items(prop, flow_texture_types);
+ RNA_def_property_ui_text(prop, "Mapping", "Texture mapping type");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "uvlayer_name");
+ RNA_def_property_ui_text(prop, "UV Map", "UV map name");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MantaFlow_uvlayer_set");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "noise_texture", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Texture", "Texture that controls emission strength");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "texture_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.01, 10.0);
+ RNA_def_property_ui_range(prop, 0.1, 5.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Size", "Size of texture mapping");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 200.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Offset", "Z-offset of texture mapping");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+}
+
+static void rna_def_manta_effec_settings(BlenderRNA *brna)
+{
+ static EnumPropertyItem effec_type_items[] = {
+ {FLUID_EFFECTOR_TYPE_COLLISION, "COLLISION", 0, "Collision", "Create collision object"},
+ {FLUID_EFFECTOR_TYPE_GUIDE, "GUIDE", 0, "Guide", "Create guiding object"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static EnumPropertyItem fluid_guiding_mode_items[] = {
+ {FLUID_EFFECTOR_GUIDING_MAXIMUM,
+ "MAXIMUM",
+ 0,
+ "Maximize",
+ "Compare velocities from previous frame with new velocities from current frame and keep "
+ "the maximum"},
+ {FLUID_EFFECTOR_GUIDING_MINIMUM,
+ "MINIMUM",
+ 0,
+ "Minimize",
+ "Compare velocities from previous frame with new velocities from current frame and keep "
+ "the minimum"},
+ {FLUID_EFFECTOR_GUIDING_OVERRIDE,
+ "OVERRIDE",
+ 0,
+ "Override",
+ "Always write new guiding velocities for every frame (each frame only contains current "
+ "velocities from guiding objects)"},
+ {FLUID_EFFECTOR_GUIDING_AVERAGED,
+ "AVERAGED",
+ 0,
+ "Averaged",
+ "Take average of velocities from previous frame and new velocities from current frame"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MantaCollSettings", NULL);
+ RNA_def_struct_ui_text(srna, "Collision Settings", "Smoke collision settings");
+ RNA_def_struct_sdna(srna, "MantaCollSettings");
+ RNA_def_struct_path_func(srna, "rna_MantaCollSettings_path");
+
+ prop = RNA_def_property(srna, "effec_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, effec_type_items);
+ RNA_def_property_ui_text(prop, "Effector Type", "Change type of effector in the simulation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_text(
+ prop, "Distance", "Distance around mesh surface to consider as effector");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vel_multi");
+ RNA_def_property_range(prop, -100.0, 100.0);
+ RNA_def_property_ui_text(prop, "Source", "Multiplier of obstacle velocity");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Manta_reset");
+
+ prop = RNA_def_property(srna, "guiding_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "guiding_mode");
+ RNA_def_property_enum_items(prop, fluid_guiding_mode_items);
+ RNA_def_property_ui_text(prop, "Guiding mode", "How to create guiding velocities");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Manta_update");
+}
+
+void RNA_def_manta(BlenderRNA *brna)
+{
+ rna_def_manta_domain_settings(brna);
+ rna_def_manta_flow_settings(brna);
+ rna_def_manta_effec_settings(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 6cd4be81a56..8b2472cf326 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -44,7 +44,7 @@
#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
#include "BKE_ocean.h"
-#include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */
+#include "BKE_manta.h" /* For mantaModifier_free & mantaModifier_createType */
#include "RNA_access.h"
#include "RNA_define.h"
@@ -134,7 +134,6 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
{eModifierType_Collision, "COLLISION", ICON_MOD_PHYSICS, "Collision", ""},
{eModifierType_DynamicPaint, "DYNAMIC_PAINT", ICON_MOD_DYNAMICPAINT, "Dynamic Paint", ""},
{eModifierType_Explode, "EXPLODE", ICON_MOD_EXPLODE, "Explode", ""},
- {eModifierType_Fluidsim, "FLUID_SIMULATION", ICON_MOD_FLUIDSIM, "Fluid Simulation", ""},
{eModifierType_Ocean, "OCEAN", ICON_MOD_OCEAN, "Ocean", ""},
{eModifierType_ParticleInstance,
"PARTICLE_INSTANCE",
@@ -142,7 +141,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
"Particle Instance",
""},
{eModifierType_ParticleSystem, "PARTICLE_SYSTEM", ICON_MOD_PARTICLES, "Particle System", ""},
- {eModifierType_Smoke, "SMOKE", ICON_MOD_SMOKE, "Smoke", ""},
+ {eModifierType_Manta, "MANTA", ICON_MOD_MANTA, "Fluid Simulation", ""},
{eModifierType_Softbody, "SOFT_BODY", ICON_MOD_SOFT, "Soft Body", ""},
{eModifierType_Surface, "SURFACE", ICON_MODIFIER, "Surface", ""},
{0, NULL, 0, NULL, NULL},
@@ -436,7 +435,7 @@ const EnumPropertyItem rna_enum_axis_flag_xyz_items[] = {
# include "DNA_particle_types.h"
# include "DNA_curve_types.h"
-# include "DNA_smoke_types.h"
+# include "DNA_manta_types.h"
# include "BKE_cachefile.h"
# include "BKE_context.h"
@@ -517,8 +516,6 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_BevelModifier;
case eModifierType_Shrinkwrap:
return &RNA_ShrinkwrapModifier;
- case eModifierType_Fluidsim:
- return &RNA_FluidSimulationModifier;
case eModifierType_Mask:
return &RNA_MaskModifier;
case eModifierType_SimpleDeform:
@@ -527,8 +524,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_MultiresModifier;
case eModifierType_Surface:
return &RNA_SurfaceModifier;
- case eModifierType_Smoke:
- return &RNA_SmokeModifier;
+ case eModifierType_Manta:
+ return &RNA_MantaModifier;
case eModifierType_Solidify:
return &RNA_SolidifyModifier;
case eModifierType_Screw:
@@ -574,6 +571,7 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
case eModifierType_WeightedNormal:
return &RNA_WeightedNormalModifier;
/* Default */
+ case eModifierType_Fluidsim: /* deprecated */
case eModifierType_None:
case eModifierType_ShapeKey:
case NUM_MODIFIER_TYPES:
@@ -841,25 +839,25 @@ static void rna_UVProjector_object_set(PointerRNA *ptr,
/* Other rna callbacks */
-static void rna_Smoke_set_type(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_manta_set_type(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- SmokeModifierData *smd = (SmokeModifierData *)ptr->data;
+ MantaModifierData *mmd = (MantaModifierData *)ptr->data;
Object *ob = (Object *)ptr->id.data;
/* nothing changed */
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
+ if ((mmd->type & MOD_MANTA_TYPE_DOMAIN) && mmd->domain) {
return;
}
- smokeModifier_free(smd); /* XXX TODO: completely free all 3 pointers */
- smokeModifier_createType(smd); /* create regarding of selected type */
+ mantaModifier_free(mmd); /* XXX TODO: completely free all 3 pointers */
+ mantaModifier_createType(mmd); /* create regarding of selected type */
- switch (smd->type) {
- case MOD_SMOKE_TYPE_DOMAIN:
+ switch (mmd->type) {
+ case MOD_MANTA_TYPE_DOMAIN:
ob->dt = OB_WIRE;
break;
- case MOD_SMOKE_TYPE_FLOW:
- case MOD_SMOKE_TYPE_COLL:
+ case MOD_MANTA_TYPE_FLOW:
+ case MOD_MANTA_TYPE_EFFEC:
case 0:
default:
break;
@@ -3388,23 +3386,23 @@ static void rna_def_modifier_cloth(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Hair Grid Resolution", "");
}
-static void rna_def_modifier_smoke(BlenderRNA *brna)
+static void rna_def_modifier_manta(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem prop_smoke_type_items[] = {
+ static const EnumPropertyItem prop_manta_type_items[] = {
{0, "NONE", 0, "None", ""},
- {MOD_SMOKE_TYPE_DOMAIN, "DOMAIN", 0, "Domain", ""},
- {MOD_SMOKE_TYPE_FLOW, "FLOW", 0, "Flow", "Inflow/Outflow"},
- {MOD_SMOKE_TYPE_COLL, "COLLISION", 0, "Collision", ""},
+ {MOD_MANTA_TYPE_DOMAIN, "DOMAIN", 0, "Domain", ""},
+ {MOD_MANTA_TYPE_FLOW, "FLOW", 0, "Flow", "Inflow/Outflow"},
+ {MOD_MANTA_TYPE_EFFEC, "EFFECTOR", 0, "Effector", ""},
{0, NULL, 0, NULL, NULL},
};
- srna = RNA_def_struct(brna, "SmokeModifier", "Modifier");
- RNA_def_struct_ui_text(srna, "Smoke Modifier", "Smoke simulation modifier");
- RNA_def_struct_sdna(srna, "SmokeModifierData");
- RNA_def_struct_ui_icon(srna, ICON_MOD_SMOKE);
+ srna = RNA_def_struct(brna, "MantaModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Manta Modifier", "Fluid simulation modifier");
+ RNA_def_struct_sdna(srna, "MantaModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_MANTA);
prop = RNA_def_property(srna, "domain_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "domain");
@@ -3414,16 +3412,16 @@ static void rna_def_modifier_smoke(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "flow");
RNA_def_property_ui_text(prop, "Flow Settings", "");
- prop = RNA_def_property(srna, "coll_settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "coll");
- RNA_def_property_ui_text(prop, "Collision Settings", "");
+ prop = RNA_def_property(srna, "effec_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "effec");
+ RNA_def_property_ui_text(prop, "Effector Settings", "");
- prop = RNA_def_property(srna, "smoke_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_smoke_type_items);
+ RNA_def_property_enum_items(prop, prop_manta_type_items);
RNA_def_property_ui_text(prop, "Type", "");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, 0, "rna_Smoke_set_type");
+ RNA_def_property_update(prop, 0, "rna_manta_set_type");
}
static void rna_def_modifier_dynamic_paint(BlenderRNA *brna)
@@ -3813,23 +3811,6 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
-static void rna_def_modifier_fluidsim(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "FluidSimulationModifier", "Modifier");
- RNA_def_struct_ui_text(srna, "Fluid Simulation Modifier", "Fluid simulation modifier");
- RNA_def_struct_sdna(srna, "FluidsimModifierData");
- RNA_def_struct_ui_icon(srna, ICON_MOD_FLUIDSIM);
-
- prop = RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "fss");
- RNA_def_property_ui_text(
- prop, "Settings", "Settings for how this object is used in the fluid simulation");
-}
-
static void rna_def_modifier_mask(BlenderRNA *brna)
{
StructRNA *srna;
@@ -6013,13 +5994,12 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_collision(brna);
rna_def_modifier_bevel(brna);
rna_def_modifier_shrinkwrap(brna);
- rna_def_modifier_fluidsim(brna);
rna_def_modifier_mask(brna);
rna_def_modifier_simpledeform(brna);
rna_def_modifier_warp(brna);
rna_def_modifier_multires(brna);
rna_def_modifier_surface(brna);
- rna_def_modifier_smoke(brna);
+ rna_def_modifier_manta(brna);
rna_def_modifier_solidify(brna);
rna_def_modifier_screw(brna);
rna_def_modifier_uvwarp(brna);
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index ab6cffe615d..a36b10982c1 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -25,7 +25,7 @@
#include "DNA_object_force_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -669,10 +669,10 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr)
}
/* check smoke modifier */
- md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke);
+ md = (ModifierData *)modifiers_findByType(ob, eModifierType_Manta);
if (md) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->domain->effector_weights == ew) {
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ if (mmd->domain->effector_weights == ew) {
char name_esc[sizeof(md->name) * 2];
BLI_strescape(name_esc, md->name, sizeof(name_esc));
return BLI_sprintfN("modifiers[\"%s\"].settings.effector_weights", name_esc);
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index a96e85473a2..894bbeb8dc6 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -948,11 +948,12 @@ static float rna_PartSetting_linelenhead_get(struct PointerRNA *ptr)
return settings->draw_line[1];
}
-static bool rna_PartSettings_is_fluid_get(PointerRNA *ptr)
+static int rna_PartSettings_is_manta_get(PointerRNA *ptr)
{
ParticleSettings *part = (ParticleSettings *)ptr->data;
- return part->type == PART_FLUID;
+ return (part->type & (PART_MANTA_FLIP | PART_MANTA_SPRAY | PART_MANTA_BUBBLE | PART_MANTA_FOAM |
+ PART_MANTA_TRACER));
}
static void rna_ParticleSettings_use_clump_curve_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -2344,9 +2345,9 @@ static void rna_def_particle_settings(BlenderRNA *brna)
/* Fluid particle type can't be checked from the type value in RNA
* as it's not shown in the menu. */
- prop = RNA_def_property(srna, "is_fluid", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "is_manta", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_boolean_funcs(prop, "rna_PartSettings_is_fluid_get", NULL);
+ RNA_def_property_boolean_funcs(prop, "rna_PartSettings_is_manta_get", NULL);
RNA_def_property_ui_text(prop, "Fluid", "Particles were created by a fluid simulation");
/* flag */
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
deleted file mode 100644
index 5c04802ac3c..00000000000
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ /dev/null
@@ -1,1218 +0,0 @@
-/*
- * 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.
- */
-
-/** \file
- * \ingroup RNA
- */
-
-#include <stdlib.h>
-#include <limits.h>
-
-#include "BLI_sys_types.h"
-
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
-#include "rna_internal.h"
-
-#include "BKE_modifier.h"
-#include "BKE_smoke.h"
-#include "BKE_pointcache.h"
-
-#include "DNA_modifier_types.h"
-#include "DNA_object_force_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
-
-#include "WM_types.h"
-
-#ifdef RNA_RUNTIME
-
-# include "BLI_threads.h"
-
-# include "BKE_colorband.h"
-# include "BKE_context.h"
-# include "BKE_particle.h"
-
-# include "DEG_depsgraph.h"
-# include "DEG_depsgraph_build.h"
-
-# include "smoke_API.h"
-
-static void rna_Smoke_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- DEG_id_tag_update(ptr->id.data, ID_RECALC_GEOMETRY);
-}
-
-static void rna_Smoke_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- rna_Smoke_update(bmain, scene, ptr);
- DEG_relations_tag_update(bmain);
-}
-
-static void rna_Smoke_resetCache(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
- if (settings->smd && settings->smd->domain) {
- settings->point_cache[0]->flag |= PTCACHE_OUTDATED;
- }
- DEG_id_tag_update(ptr->id.data, ID_RECALC_GEOMETRY);
-}
-
-static void rna_Smoke_cachetype_set(struct PointerRNA *ptr, int value)
-{
- SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
- Object *ob = (Object *)ptr->id.data;
-
- if (value != settings->cache_file_format) {
- /* Clear old caches. */
- PTCacheID id;
- BKE_ptcache_id_from_smoke(&id, ob, settings->smd);
- BKE_ptcache_id_clear(&id, PTCACHE_CLEAR_ALL, 0);
-
- settings->cache_file_format = value;
- }
-}
-
-static void rna_Smoke_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
-
- smokeModifier_reset(settings->smd);
- rna_Smoke_resetCache(bmain, scene, ptr);
-
- rna_Smoke_update(bmain, scene, ptr);
-}
-
-static void rna_Smoke_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
-
- smokeModifier_reset(settings->smd);
-
- if (settings->smd && settings->smd->domain) {
- settings->smd->domain->point_cache[0]->flag |= PTCACHE_OUTDATED;
- }
-
- rna_Smoke_dependency_update(bmain, scene, ptr);
-}
-
-static char *rna_SmokeDomainSettings_path(PointerRNA *ptr)
-{
- SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->smd;
- char name_esc[sizeof(md->name) * 2];
-
- BLI_strescape(name_esc, md->name, sizeof(name_esc));
- return BLI_sprintfN("modifiers[\"%s\"].domain_settings", name_esc);
-}
-
-static char *rna_SmokeFlowSettings_path(PointerRNA *ptr)
-{
- SmokeFlowSettings *settings = (SmokeFlowSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->smd;
- char name_esc[sizeof(md->name) * 2];
-
- BLI_strescape(name_esc, md->name, sizeof(name_esc));
- return BLI_sprintfN("modifiers[\"%s\"].flow_settings", name_esc);
-}
-
-static char *rna_SmokeCollSettings_path(PointerRNA *ptr)
-{
- SmokeCollSettings *settings = (SmokeCollSettings *)ptr->data;
- ModifierData *md = (ModifierData *)settings->smd;
- char name_esc[sizeof(md->name) * 2];
-
- BLI_strescape(name_esc, md->name, sizeof(name_esc));
- return BLI_sprintfN("modifiers[\"%s\"].coll_settings", name_esc);
-}
-
-static int rna_SmokeModifier_grid_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- float *density = NULL;
- int size = 0;
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- /* high resolution smoke */
- int res[3];
-
- smoke_turbulence_get_res(sds->wt, res);
- size = res[0] * res[1] * res[2];
-
- density = smoke_turbulence_get_density(sds->wt);
- }
- else if (sds->fluid) {
- /* regular resolution */
- size = sds->res[0] * sds->res[1] * sds->res[2];
- density = smoke_get_density(sds->fluid);
- }
-
- length[0] = (density) ? size : 0;
-# else
- (void)ptr;
- length[0] = 0;
-# endif
- return length[0];
-}
-
-static int rna_SmokeModifier_color_grid_get_length(PointerRNA *ptr,
- int length[RNA_MAX_ARRAY_DIMENSION])
-{
- rna_SmokeModifier_grid_get_length(ptr, length);
-
- length[0] *= 4;
- return length[0];
-}
-
-static int rna_SmokeModifier_velocity_grid_get_length(PointerRNA *ptr,
- int length[RNA_MAX_ARRAY_DIMENSION])
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- float *vx = NULL;
- float *vy = NULL;
- float *vz = NULL;
- int size = 0;
-
- /* Velocity data is always low-resolution. */
- if (sds->fluid) {
- size = 3 * sds->res[0] * sds->res[1] * sds->res[2];
- vx = smoke_get_velocity_x(sds->fluid);
- vy = smoke_get_velocity_y(sds->fluid);
- vz = smoke_get_velocity_z(sds->fluid);
- }
-
- length[0] = (vx && vy && vz) ? size : 0;
-# else
- (void)ptr;
- length[0] = 0;
-# endif
- return length[0];
-}
-
-static int rna_SmokeModifier_heat_grid_get_length(PointerRNA *ptr,
- int length[RNA_MAX_ARRAY_DIMENSION])
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- float *heat = NULL;
- int size = 0;
-
- /* Heat data is always low-resolution. */
- if (sds->fluid) {
- size = sds->res[0] * sds->res[1] * sds->res[2];
- heat = smoke_get_heat(sds->fluid);
- }
-
- length[0] = (heat) ? size : 0;
-# else
- (void)ptr;
- length[0] = 0;
-# endif
- return length[0];
-}
-
-static void rna_SmokeModifier_density_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_grid_get_length(ptr, length);
- float *density;
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- density = smoke_turbulence_get_density(sds->wt);
- }
- else {
- density = smoke_get_density(sds->fluid);
- }
-
- memcpy(values, density, size * sizeof(float));
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeModifier_velocity_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_velocity_grid_get_length(ptr, length);
- float *vx, *vy, *vz;
- int i;
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- vx = smoke_get_velocity_x(sds->fluid);
- vy = smoke_get_velocity_y(sds->fluid);
- vz = smoke_get_velocity_z(sds->fluid);
-
- for (i = 0; i < size; i += 3) {
- *(values++) = *(vx++);
- *(values++) = *(vy++);
- *(values++) = *(vz++);
- }
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeModifier_color_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_grid_get_length(ptr, length);
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- if (!sds->fluid) {
- memset(values, 0, size * sizeof(float));
- }
- else {
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- if (smoke_turbulence_has_colors(sds->wt)) {
- smoke_turbulence_get_rgba(sds->wt, values, 0);
- }
- else {
- smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, values, 0);
- }
- }
- else {
- if (smoke_has_colors(sds->fluid)) {
- smoke_get_rgba(sds->fluid, values, 0);
- }
- else {
- smoke_get_rgba_from_density(sds->fluid, sds->active_color, values, 0);
- }
- }
- }
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeModifier_flame_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_grid_get_length(ptr, length);
- float *flame;
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- flame = smoke_turbulence_get_flame(sds->wt);
- }
- else {
- flame = smoke_get_flame(sds->fluid);
- }
-
- if (flame) {
- memcpy(values, flame, size * sizeof(float));
- }
- else {
- memset(values, 0, size * sizeof(float));
- }
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeModifier_heat_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_heat_grid_get_length(ptr, length);
- float *heat;
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- heat = smoke_get_heat(sds->fluid);
-
- if (heat != NULL) {
- /* scale heat values from -2.0-2.0 to -1.0-1.0. */
- for (int i = 0; i < size; i++) {
- values[i] = heat[i] * 0.5f;
- }
- }
- else {
- memset(values, 0, size * sizeof(float));
- }
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeModifier_temperature_grid_get(PointerRNA *ptr, float *values)
-{
-# ifdef WITH_SMOKE
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
- int length[RNA_MAX_ARRAY_DIMENSION];
- int size = rna_SmokeModifier_grid_get_length(ptr, length);
- float *flame;
-
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- flame = smoke_turbulence_get_flame(sds->wt);
- }
- else {
- flame = smoke_get_flame(sds->fluid);
- }
-
- if (flame) {
- /* Output is such that 0..1 maps to 0..1000K */
- float offset = sds->flame_ignition;
- float scale = sds->flame_max_temp - sds->flame_ignition;
-
- for (int i = 0; i < size; i++) {
- values[i] = (flame[i] > 0.01f) ? offset + flame[i] * scale : 0.0f;
- }
- }
- else {
- memset(values, 0, size * sizeof(float));
- }
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
-# else
- UNUSED_VARS(ptr, values);
-# endif
-}
-
-static void rna_SmokeFlow_density_vgroup_get(PointerRNA *ptr, char *value)
-{
- SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
- rna_object_vgroup_name_index_get(ptr, value, flow->vgroup_density);
-}
-
-static int rna_SmokeFlow_density_vgroup_length(PointerRNA *ptr)
-{
- SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
- return rna_object_vgroup_name_index_length(ptr, flow->vgroup_density);
-}
-
-static void rna_SmokeFlow_density_vgroup_set(PointerRNA *ptr, const char *value)
-{
- SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
- rna_object_vgroup_name_index_set(ptr, value, &flow->vgroup_density);
-}
-
-static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value)
-{
- SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
- rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name));
-}
-
-static void rna_Smoke_use_color_ramp_set(PointerRNA *ptr, bool value)
-{
- SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
-
- sds->use_coba = value;
-
- if (value && sds->coba == NULL) {
- sds->coba = BKE_colorband_add(false);
- }
-}
-
-#else
-
-static void rna_def_smoke_domain_settings(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_noise_type_items[] = {
- {MOD_SMOKE_NOISEWAVE, "NOISEWAVE", 0, "Wavelet", ""},
-# ifdef WITH_FFTW3
- {MOD_SMOKE_NOISEFFT, "NOISEFFT", 0, "FFT", ""},
-# endif
- /* {MOD_SMOKE_NOISECURL, "NOISECURL", 0, "Curl", ""}, */
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem prop_compression_items[] = {
- {VDB_COMPRESSION_ZIP, "ZIP", 0, "Zip", "Effective but slow compression"},
-# ifdef WITH_OPENVDB_BLOSC
- {VDB_COMPRESSION_BLOSC,
- "BLOSC",
- 0,
- "Blosc",
- "Multithreaded compression, similar in size and quality as 'Zip'"},
-# endif
- {VDB_COMPRESSION_NONE, "NONE", 0, "None", "Do not use any compression"},
- {0, NULL, 0, NULL, NULL}};
-
- static const EnumPropertyItem smoke_cache_comp_items[] = {
- {SM_CACHE_LIGHT, "CACHELIGHT", 0, "Lite", "Fast but not so effective compression"},
- {SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_highres_sampling_items[] = {
- {SM_HRES_FULLSAMPLE, "FULLSAMPLE", 0, "Full Sample", ""},
- {SM_HRES_LINEAR, "LINEAR", 0, "Linear", ""},
- {SM_HRES_NEAREST, "NEAREST", 0, "Nearest", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_data_depth_items[] = {
- {16, "16", 0, "Float (Half)", "Half float (16 bit data)"},
- {0, "32", 0, "Float (Full)", "Full float (32 bit data)"}, /* default */
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_domain_colli_items[] = {
- {SM_BORDER_OPEN, "BORDEROPEN", 0, "Open", "Smoke doesn't collide with any border"},
- {SM_BORDER_VERTICAL,
- "BORDERVERTICAL",
- 0,
- "Vertically Open",
- "Smoke doesn't collide with top and bottom sides"},
- {SM_BORDER_CLOSED, "BORDERCLOSED", 0, "Collide All", "Smoke collides with every side"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem cache_file_type_items[] = {
- {PTCACHE_FILE_PTCACHE,
- "POINTCACHE",
- 0,
- "Point Cache",
- "Blender specific point cache file format"},
-# ifdef WITH_OPENVDB
- {PTCACHE_FILE_OPENVDB, "OPENVDB", 0, "OpenVDB", "OpenVDB file format"},
-# endif
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_view_items[] = {
- {MOD_SMOKE_SLICE_VIEW_ALIGNED,
- "VIEW_ALIGNED",
- 0,
- "View",
- "Slice volume parallel to the view plane"},
- {MOD_SMOKE_SLICE_AXIS_ALIGNED,
- "AXIS_ALIGNED",
- 0,
- "Axis",
- "Slice volume parallel to the major axis"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem axis_slice_method_items[] = {
- {AXIS_SLICE_FULL, "FULL", 0, "Full", "Slice the whole domain object"},
- {AXIS_SLICE_SINGLE, "SINGLE", 0, "Single", "Perform a single slice of the domain object"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem interp_method_item[] = {
- {VOLUME_INTERP_LINEAR, "LINEAR", 0, "Linear", "Good smoothness and speed"},
- {VOLUME_INTERP_CUBIC,
- "CUBIC",
- 0,
- "Cubic",
- "Smoothed high quality interpolation, but slower"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem axis_slice_position_items[] = {
- {SLICE_AXIS_AUTO,
- "AUTO",
- 0,
- "Auto",
- "Adjust slice direction according to the view direction"},
- {SLICE_AXIS_X, "X", 0, "X", "Slice along the X axis"},
- {SLICE_AXIS_Y, "Y", 0, "Y", "Slice along the Y axis"},
- {SLICE_AXIS_Z, "Z", 0, "Z", "Slice along the Z axis"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem vector_draw_items[] = {
- {VECTOR_DRAW_NEEDLE, "NEEDLE", 0, "Needle", "Display vectors as needles"},
- {VECTOR_DRAW_STREAMLINE, "STREAMLINE", 0, "Streamlines", "Display vectors as streamlines"},
- {0, NULL, 0, NULL, NULL},
- };
-
- srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL);
- RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings");
- RNA_def_struct_sdna(srna, "SmokeDomainSettings");
- RNA_def_struct_path_func(srna, "rna_SmokeDomainSettings_path");
-
- prop = RNA_def_property(srna, "resolution_max", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "maxres");
- RNA_def_property_range(prop, 6, 512);
- RNA_def_property_ui_range(prop, 24, 512, 2, -1);
- RNA_def_property_ui_text(prop, "Max Res", "Maximal resolution used in the fluid domain");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "amplify", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "amplify");
- RNA_def_property_range(prop, 1, 10);
- RNA_def_property_ui_range(prop, 1, 10, 1, -1);
- RNA_def_property_ui_text(
- prop, "Amplification", "Enhance the resolution of smoke by this factor using noise");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "use_high_resolution", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGHRES);
- RNA_def_property_ui_text(prop, "High res", "Enable high resolution (using amplification)");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "show_high_resolution", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "viewsettings", MOD_SMOKE_VIEW_SHOW_HIGHRES);
- RNA_def_property_ui_text(
- prop, "Show High Resolution", "Show high resolution (using amplification)");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "noise_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "noise");
- RNA_def_property_enum_items(prop, prop_noise_type_items);
- RNA_def_property_ui_text(
- prop, "Noise Method", "Noise method which is used for creating the high resolution");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "alpha");
- RNA_def_property_range(prop, -5.0, 5.0);
- RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
- RNA_def_property_ui_text(
- prop,
- "Density",
- "How much density affects smoke motion (higher value results in faster rising smoke)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "beta", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "beta");
- RNA_def_property_range(prop, -5.0, 5.0);
- RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
- RNA_def_property_ui_text(
- prop,
- "Heat",
- "How much heat affects smoke motion (higher value results in faster rising smoke)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "collision_collection", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "coll_group");
- RNA_def_property_struct_type(prop, "Collection");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Collision Collection", "Limit collisions to this collection");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency");
-
- prop = RNA_def_property(srna, "fluid_collection", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "fluid_group");
- RNA_def_property_struct_type(prop, "Collection");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Fluid Collection", "Limit fluid objects to this collection");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency");
-
- prop = RNA_def_property(srna, "effector_collection", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "eff_group");
- RNA_def_property_struct_type(prop, "Collection");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Effector Collection", "Limit effectors to this collection");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency");
-
- prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "strength");
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_range(prop, 0.0, 10.0, 1, 2);
- RNA_def_property_ui_text(prop, "Strength", "Strength of noise");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "dissolve_speed", PROP_INT, PROP_TIME);
- RNA_def_property_int_sdna(prop, NULL, "diss_speed");
- RNA_def_property_range(prop, 1.0, 10000.0);
- RNA_def_property_ui_range(prop, 1.0, 10000.0, 1, -1);
- RNA_def_property_ui_text(prop, "Dissolve Speed", "Dissolve Speed");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "use_dissolve_smoke", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE);
- RNA_def_property_ui_text(prop, "Dissolve Smoke", "Enable smoke to disappear over time");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE_LOG);
- RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x ");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "point_cache[0]");
- RNA_def_property_struct_type(prop, "PointCache");
- RNA_def_property_ui_text(prop, "Point Cache", "");
-
- prop = RNA_def_property(srna, "point_cache_compress_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "cache_comp");
- RNA_def_property_enum_items(prop, smoke_cache_comp_items);
- RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used");
-
- prop = RNA_def_property(srna, "openvdb_cache_compress_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "openvdb_comp");
- RNA_def_property_enum_items(prop, prop_compression_items);
- RNA_def_property_ui_text(prop, "Compression", "Compression method to be used");
-
- prop = RNA_def_property(srna, "data_depth", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_depth");
- RNA_def_property_enum_items(prop, smoke_data_depth_items);
- RNA_def_property_ui_text(prop,
- "Data Depth",
- "Bit depth for writing all scalar (including vector) "
- "lower values reduce file size");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
-
- prop = RNA_def_property(srna, "collision_extents", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "border_collisions");
- RNA_def_property_enum_items(prop, smoke_domain_colli_items);
- RNA_def_property_ui_text(
- prop, "Border Collisions", "Select which domain border will be treated as collision object");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "EffectorWeights");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Effector Weights", "");
-
- prop = RNA_def_property(srna, "highres_sampling", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, smoke_highres_sampling_items);
- RNA_def_property_ui_text(prop, "Emitter", "Method for sampling the high resolution flow");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "time_scale");
- RNA_def_property_range(prop, 0.2, 1.5);
- RNA_def_property_ui_range(prop, 0.2, 1.5, 0.02, 5);
- RNA_def_property_ui_text(prop, "Time Scale", "Adjust simulation speed");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "vorticity", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "vorticity");
- RNA_def_property_range(prop, 0.01, 4.0);
- RNA_def_property_ui_range(prop, 0.01, 4.0, 0.02, 5);
- RNA_def_property_ui_text(prop, "Vorticity", "Amount of turbulence/rotation in fluid");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "density_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_density_grid_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Density Grid", "Smoke density grid");
-
- prop = RNA_def_property(srna, "velocity_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_velocity_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_velocity_grid_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Velocity Grid", "Smoke velocity grid");
-
- prop = RNA_def_property(srna, "flame_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_flame_grid_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Flame Grid", "Smoke flame grid");
-
- prop = RNA_def_property(srna, "color_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_color_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_color_grid_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Color Grid", "Smoke color grid");
-
- prop = RNA_def_property(srna, "heat_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_heat_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_heat_grid_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Heat Grid", "Smoke heat grid");
-
- prop = RNA_def_property(srna, "temperature_grid", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 32);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_grid_get_length");
- RNA_def_property_float_funcs(prop, "rna_SmokeModifier_temperature_grid_get", NULL, NULL);
- RNA_def_property_ui_text(
- prop, "Temperature Grid", "Smoke temperature grid, range 0..1 represents 0..1000K");
-
- prop = RNA_def_property(srna,
- "cell_size",
- PROP_FLOAT,
- PROP_XYZ); /* can change each frame when using adaptive domain */
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "cell_size", "Cell Size");
-
- prop = RNA_def_property(srna,
- "start_point",
- PROP_FLOAT,
- PROP_XYZ); /* can change each frame when using adaptive domain */
- RNA_def_property_float_sdna(prop, NULL, "p0");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "p0", "Start point");
-
- prop = RNA_def_property(srna,
- "domain_resolution",
- PROP_INT,
- PROP_XYZ); /* can change each frame when using adaptive domain */
- RNA_def_property_int_sdna(prop, NULL, "res");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "res", "Smoke Grid Resolution");
-
- prop = RNA_def_property(srna, "burning_rate", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.01, 4.0);
- RNA_def_property_ui_range(prop, 0.01, 2.0, 1.0, 5);
- RNA_def_property_ui_text(
- prop, "Speed", "Speed of the burning reaction (use larger values for smaller flame)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "flame_smoke", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 8.0);
- RNA_def_property_ui_range(prop, 0.0, 4.0, 1.0, 5);
- RNA_def_property_ui_text(prop, "Smoke", "Amount of smoke created by burning fuel");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "flame_vorticity", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_range(prop, 0.0, 2.0);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 5);
- RNA_def_property_ui_text(prop, "Vorticity", "Additional vorticity for the flames");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "flame_ignition", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.5, 5.0);
- RNA_def_property_ui_range(prop, 0.5, 2.5, 1.0, 5);
- RNA_def_property_ui_text(prop, "Ignition", "Minimum temperature of flames");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "flame_max_temp", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 1.0, 10.0);
- RNA_def_property_ui_range(prop, 1.0, 5.0, 1.0, 5);
- RNA_def_property_ui_text(prop, "Maximum", "Maximum temperature of flames");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "flame_smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke emitted from burning fuel");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "use_adaptive_domain", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_ADAPTIVE_DOMAIN);
- RNA_def_property_ui_text(
- prop, "Adaptive Domain", "Adapt simulation resolution and size to fluid");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "additional_res", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "adapt_res");
- RNA_def_property_range(prop, 0, 512);
- RNA_def_property_ui_range(prop, 0, 512, 2, -1);
- RNA_def_property_ui_text(prop, "Additional", "Maximum number of additional cells");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "adapt_margin", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "adapt_margin");
- RNA_def_property_range(prop, 2, 24);
- RNA_def_property_ui_range(prop, 2, 24, 2, -1);
- RNA_def_property_ui_text(
- prop, "Margin", "Margin added around fluid to minimize boundary interference");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "adapt_threshold", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.01, 0.5);
- RNA_def_property_ui_range(prop, 0.01, 0.5, 1.0, 5);
- RNA_def_property_ui_text(
- prop, "Threshold", "Maximum amount of fluid cell can contain before it is considered empty");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- prop = RNA_def_property(srna, "cache_file_format", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "cache_file_format");
- RNA_def_property_enum_items(prop, cache_file_type_items);
- RNA_def_property_enum_funcs(prop, NULL, "rna_Smoke_cachetype_set", NULL);
- RNA_def_property_ui_text(prop, "File Format", "Select the file format to be used for caching");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
-
- /* display settings */
-
- prop = RNA_def_property(srna, "slice_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "slice_method");
- RNA_def_property_enum_items(prop, smoke_view_items);
- RNA_def_property_ui_text(prop, "View Method", "How to slice the volume for viewport rendering");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "axis_slice_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "axis_slice_method");
- RNA_def_property_enum_items(prop, axis_slice_method_items);
- RNA_def_property_ui_text(prop, "Method", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "slice_axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "slice_axis");
- RNA_def_property_enum_items(prop, axis_slice_position_items);
- RNA_def_property_ui_text(prop, "Axis", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "slice_per_voxel", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "slice_per_voxel");
- RNA_def_property_range(prop, 0.0, 100.0);
- RNA_def_property_ui_range(prop, 0.0, 5.0, 0.1, 1);
- RNA_def_property_ui_text(
- prop, "Slice Per Voxel", "How many slices per voxel should be generated");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "slice_depth", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "slice_depth");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
- RNA_def_property_ui_text(prop, "Position", "Position of the slice");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "display_thickness", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "display_thickness");
- RNA_def_property_range(prop, 0.001, 1000.0);
- RNA_def_property_ui_range(prop, 0.1, 100.0, 0.1, 3);
- RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
-
- prop = RNA_def_property(srna, "display_interpolation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "interp_method");
- RNA_def_property_enum_items(prop, interp_method_item);
- RNA_def_property_ui_text(
- prop, "Interpolation", "Interpolation method to use for smoke/fire volumes in solid mode");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "show_velocity", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "draw_velocity", 0);
- RNA_def_property_ui_text(
- prop, "Display Velocity", "Toggle visualization of the velocity field as needles");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "vector_display_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "vector_draw_type");
- RNA_def_property_enum_items(prop, vector_draw_items);
- RNA_def_property_ui_text(prop, "Display Type", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "vector_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "vector_scale");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
- RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- /* --------- Color mapping. --------- */
-
- prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Smoke_use_color_ramp_set");
- RNA_def_property_ui_text(
- prop,
- "Use Color Ramp",
- "Render a simulation field while mapping its voxels values to the colors of a ramp");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- static const EnumPropertyItem coba_field_items[] = {
- {FLUID_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"},
- {FLUID_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"},
- {FLUID_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"},
- {FLUID_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"},
- {FLUID_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"},
- {FLUID_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"},
- {FLUID_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"},
- {FLUID_FIELD_VELOCITY_X, "VELOCITY_X", 0, "X Velocity", "X component of the velocity field"},
- {FLUID_FIELD_VELOCITY_Y, "VELOCITY_Y", 0, "Y Velocity", "Y component of the velocity field"},
- {FLUID_FIELD_VELOCITY_Z, "VELOCITY_Z", 0, "Z Velocity", "Z component of the velocity field"},
- {0, NULL, 0, NULL, NULL},
- };
-
- prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "coba_field");
- RNA_def_property_enum_items(prop, coba_field_items);
- RNA_def_property_ui_text(prop, "Field", "Simulation field to color map");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "coba");
- RNA_def_property_struct_type(prop, "ColorRamp");
- RNA_def_property_ui_text(prop, "Color Ramp", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "clipping", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "clipping");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
- RNA_def_property_ui_text(
- prop,
- "Clipping",
- "Value under which voxels are considered empty space to optimize caching and rendering");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
-}
-
-static void rna_def_smoke_flow_settings(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem smoke_flow_types[] = {
- {MOD_SMOKE_FLOW_TYPE_OUTFLOW, "OUTFLOW", 0, "Outflow", "Delete smoke from simulation"},
- {MOD_SMOKE_FLOW_TYPE_SMOKE, "SMOKE", 0, "Smoke", "Add smoke"},
- {MOD_SMOKE_FLOW_TYPE_SMOKEFIRE, "BOTH", 0, "Fire + Smoke", "Add fire and smoke"},
- {MOD_SMOKE_FLOW_TYPE_FIRE, "FIRE", 0, "Fire", "Add fire"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_flow_sources[] = {
- {MOD_SMOKE_FLOW_SOURCE_PARTICLES,
- "PARTICLES",
- ICON_PARTICLES,
- "Particle System",
- "Emit smoke from particles"},
- {MOD_SMOKE_FLOW_SOURCE_MESH,
- "MESH",
- ICON_META_CUBE,
- "Mesh",
- "Emit smoke from mesh surface or volume"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem smoke_flow_texture_types[] = {
- {MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO,
- "AUTO",
- 0,
- "Generated",
- "Generated coordinates centered to flow object"},
- {MOD_SMOKE_FLOW_TEXTURE_MAP_UV, "UV", 0, "UV", "Use UV layer for texture coordinates"},
- {0, NULL, 0, NULL, NULL},
- };
-
- srna = RNA_def_struct(brna, "SmokeFlowSettings", NULL);
- RNA_def_struct_ui_text(srna, "Flow Settings", "Smoke flow settings");
- RNA_def_struct_sdna(srna, "SmokeFlowSettings");
- RNA_def_struct_path_func(srna, "rna_SmokeFlowSettings_path");
-
- prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "density");
- RNA_def_property_range(prop, 0.0, 1);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 4);
- RNA_def_property_ui_text(prop, "Density", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "color");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "fuel_amount", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 10);
- RNA_def_property_ui_range(prop, 0.0, 5.0, 1.0, 4);
- RNA_def_property_ui_text(prop, "Flame Rate", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "temperature", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "temp");
- RNA_def_property_range(prop, -10, 10);
- RNA_def_property_ui_range(prop, -10, 10, 1, 1);
- RNA_def_property_ui_text(prop, "Temp. Diff.", "Temperature difference to ambient temperature");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "psys");
- RNA_def_property_struct_type(prop, "ParticleSystem");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Particle Systems", "Particle systems emitted from the object");
- RNA_def_property_update(prop, 0, "rna_Smoke_reset_dependency");
-
- prop = RNA_def_property(srna, "smoke_flow_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, smoke_flow_types);
- RNA_def_property_ui_text(prop, "Flow Type", "Change how flow affects the simulation");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "smoke_flow_source", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "source");
- RNA_def_property_enum_items(prop, smoke_flow_sources);
- RNA_def_property_ui_text(prop, "Source", "Change how smoke is emitted");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "use_absolute", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_ABSOLUTE);
- RNA_def_property_ui_text(
- prop, "Absolute Density", "Only allow given density value in emitter area");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "use_initial_velocity", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_INITVELOCITY);
- RNA_def_property_ui_text(
- prop, "Initial Velocity", "Smoke has some initial velocity when it is emitted");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "vel_multi");
- RNA_def_property_range(prop, -100.0, 100.0);
- RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Source", "Multiplier of source velocity passed to smoke");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "velocity_normal", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "vel_normal");
- RNA_def_property_range(prop, -100.0, 100.0);
- RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Normal", "Amount of normal directional velocity");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "velocity_random", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "vel_random");
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_range(prop, 0.0, 2.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Random", "Amount of random velocity");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "volume_density", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Volume", "Factor for smoke emitted from inside the mesh volume");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Surface", "Maximum distance from mesh surface to emit smoke");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "particle_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.1, 20.0);
- RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Size", "Particle size in simulation cells");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "use_particle_size", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_USE_PART_SIZE);
- RNA_def_property_ui_text(
- prop, "Set Size", "Set particle size in simulation cells or use nearest cell");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "subframes", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 0, 50);
- RNA_def_property_ui_range(prop, 0, 10, 1, -1);
- RNA_def_property_ui_text(prop,
- "Subframes",
- "Number of additional samples to take between frames to improve "
- "quality of fast moving flows");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "density_vertex_group", PROP_STRING, PROP_NONE);
- RNA_def_property_string_funcs(prop,
- "rna_SmokeFlow_density_vgroup_get",
- "rna_SmokeFlow_density_vgroup_length",
- "rna_SmokeFlow_density_vgroup_set");
- RNA_def_property_ui_text(
- prop, "Vertex Group", "Name of vertex group which determines surface emission rate");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "use_texture", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_TEXTUREEMIT);
- RNA_def_property_ui_text(prop, "Use Texture", "Use a texture to control emission strength");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "texture_map_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "texture_type");
- RNA_def_property_enum_items(prop, smoke_flow_texture_types);
- RNA_def_property_ui_text(prop, "Mapping", "Texture mapping type");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "uvlayer_name");
- RNA_def_property_ui_text(prop, "UV Map", "UV map name");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SmokeFlow_uvlayer_set");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "noise_texture", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Texture", "Texture that controls emission strength");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "texture_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.01, 10.0);
- RNA_def_property_ui_range(prop, 0.1, 5.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Size", "Size of texture mapping");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-
- prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 200.0);
- RNA_def_property_ui_range(prop, 0.0, 100.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Offset", "Z-offset of texture mapping");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-}
-
-static void rna_def_smoke_coll_settings(BlenderRNA *brna)
-{
- static const EnumPropertyItem smoke_coll_type_items[] = {
- {SM_COLL_STATIC, "COLLSTATIC", 0, "Static", "Non moving obstacle"},
- {SM_COLL_RIGID, "COLLRIGID", 0, "Rigid", "Rigid obstacle"},
- {SM_COLL_ANIMATED, "COLLANIMATED", 0, "Animated", "Animated obstacle"},
- {0, NULL, 0, NULL, NULL},
- };
-
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "SmokeCollSettings", NULL);
- RNA_def_struct_ui_text(srna, "Collision Settings", "Smoke collision settings");
- RNA_def_struct_sdna(srna, "SmokeCollSettings");
- RNA_def_struct_path_func(srna, "rna_SmokeCollSettings_path");
-
- prop = RNA_def_property(srna, "collision_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, smoke_coll_type_items);
- RNA_def_property_ui_text(prop, "Collision type", "Collision type");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
-}
-
-void RNA_def_smoke(BlenderRNA *brna)
-{
- rna_def_smoke_domain_settings(brna);
- rna_def_smoke_flow_settings(brna);
- rna_def_smoke_coll_settings(brna);
-}
-
-#endif
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 5116fefde94..4260ce84b75 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -29,7 +29,6 @@ set(INC
../makesdna
../makesrna
../render/extern/include
- ../../../intern/elbeem/extern
../../../intern/eigen
../../../intern/guardedalloc
)
@@ -55,12 +54,11 @@ set(SRC
intern/MOD_dynamicpaint.c
intern/MOD_edgesplit.c
intern/MOD_explode.c
- intern/MOD_fluidsim.c
- intern/MOD_fluidsim_util.c
intern/MOD_hook.c
intern/MOD_laplaciandeform.c
intern/MOD_laplaciansmooth.c
intern/MOD_lattice.c
+ intern/MOD_manta.c
intern/MOD_mask.c
intern/MOD_meshcache.c
intern/MOD_meshcache_mdd.c
@@ -81,7 +79,6 @@ set(SRC
intern/MOD_shrinkwrap.c
intern/MOD_simpledeform.c
intern/MOD_skin.c
- intern/MOD_smoke.c
intern/MOD_smooth.c
intern/MOD_softbody.c
intern/MOD_solidify.c
@@ -102,7 +99,6 @@ set(SRC
intern/MOD_wireframe.c
MOD_modifiertypes.h
- intern/MOD_fluidsim_util.h
intern/MOD_meshcache_util.h
intern/MOD_util.h
intern/MOD_weightvg_util.h
@@ -133,10 +129,6 @@ if(WITH_MOD_REMESH)
add_definitions(-DWITH_MOD_REMESH)
endif()
-if(WITH_MOD_FLUID)
- add_definitions(-DWITH_MOD_FLUID)
-endif()
-
if(WITH_MOD_OCEANSIM)
add_definitions(-DWITH_OCEANSIM)
endif()
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 96622bf7763..da42eb467ee 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -56,7 +56,7 @@ extern ModifierTypeInfo modifierType_Mask;
extern ModifierTypeInfo modifierType_SimpleDeform;
extern ModifierTypeInfo modifierType_Multires;
extern ModifierTypeInfo modifierType_Surface;
-extern ModifierTypeInfo modifierType_Smoke;
+extern ModifierTypeInfo modifierType_Manta;
extern ModifierTypeInfo modifierType_ShapeKey;
extern ModifierTypeInfo modifierType_Solidify;
extern ModifierTypeInfo modifierType_Screw;
diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c
deleted file mode 100644
index 620b21f3e0c..00000000000
--- a/source/blender/modifiers/intern/MOD_fluidsim.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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) 2005 by the Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup modifiers
- */
-
-#include "BLI_utildefines.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_object_fluidsim_types.h"
-#include "DNA_object_types.h"
-
-#include "BKE_layer.h"
-#include "BKE_modifier.h"
-
-#include "DEG_depsgraph_build.h"
-
-#include "MOD_fluidsim_util.h"
-#include "MOD_modifiertypes.h"
-
-#include "MEM_guardedalloc.h"
-
-/* Fluidsim */
-static void initData(ModifierData *md)
-{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
-
- fluidsim_init(fluidmd);
-}
-static void freeData(ModifierData *md)
-{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
-
- fluidsim_free(fluidmd);
-}
-
-static void copyData(const ModifierData *md, ModifierData *target, const int UNUSED(flag))
-{
- const FluidsimModifierData *fluidmd = (const FluidsimModifierData *)md;
- FluidsimModifierData *tfluidmd = (FluidsimModifierData *)target;
-
- /* Free any FSS that was allocated in initData() */
- if (tfluidmd->fss) {
- MEM_SAFE_FREE(tfluidmd->fss->meshVelocities);
- MEM_freeN(tfluidmd->fss);
- }
-
- if (fluidmd->fss == NULL) {
- tfluidmd->fss = NULL;
- return;
- }
-
- tfluidmd->fss = MEM_dupallocN(fluidmd->fss);
- if (tfluidmd->fss->meshVelocities != NULL) {
- tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities);
- }
-}
-
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
-{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
- Mesh *result = NULL;
-
- /* check for alloc failing */
- if (!fluidmd->fss) {
- initData(md);
-
- if (!fluidmd->fss) {
- return mesh;
- }
- }
-
- result = fluidsimModifier_do(fluidmd, ctx, mesh);
-
- return result ? result : mesh;
-}
-
-static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
- if (fluidmd && fluidmd->fss) {
- if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
- FOREACH_SCENE_OBJECT_BEGIN (ctx->scene, ob1) {
- if (ob1 != ctx->object) {
- FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(
- ob1, eModifierType_Fluidsim);
-
- /* Only put dependencies from NON-DOMAIN fluids in here. */
- if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) {
- DEG_add_object_relation(ctx->node, ob1, DEG_OB_COMP_TRANSFORM, "Fluidsim Object");
- }
- }
- }
- FOREACH_SCENE_OBJECT_END;
- }
- }
-}
-
-static bool dependsOnTime(ModifierData *UNUSED(md))
-{
- return true;
-}
-
-ModifierTypeInfo modifierType_Fluidsim = {
- /* name */ "Fluidsim",
- /* structName */ "FluidsimModifierData",
- /* structSize */ sizeof(FluidsimModifierData),
- /* type */ eModifierTypeType_Nonconstructive,
-
- /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_RequiresOriginalData |
- eModifierTypeFlag_Single,
-
- /* copyData */ copyData,
-
- /* deformVerts */ NULL,
- /* deformMatrices */ NULL,
- /* deformVertsEM */ NULL,
- /* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
-
- /* initData */ initData,
- /* requiredDataMask */ NULL,
- /* freeData */ freeData,
- /* isDisabled */ NULL,
- /* updateDepsgraph */ updateDepsgraph,
- /* dependsOnTime */ dependsOnTime,
- /* dependsOnNormals */ NULL,
- /* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
- /* foreachTexLink */ NULL,
- /* freeRuntimeData */ NULL,
-};
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
deleted file mode 100644
index 3083d89d555..00000000000
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * 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) 2005 by the Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup modifiers
- */
-
-#include <stddef.h>
-#include <zlib.h>
-
-#include "BLI_utildefines.h"
-
-#ifdef WITH_MOD_FLUID
-# include "BLI_blenlib.h"
-# include "BLI_math.h"
-#endif
-
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_fluidsim_types.h"
-
-#include "BKE_fluidsim.h" /* ensure definitions here match */
-#include "BKE_mesh.h"
-#ifdef WITH_MOD_FLUID
-# include "BKE_global.h"
-# include "BKE_library.h"
-#endif
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
-
-#include "MOD_fluidsim_util.h"
-#include "MOD_modifiertypes.h"
-
-#include "MEM_guardedalloc.h"
-
-// headers for fluidsim bobj meshes
-#include "LBM_fluidsim.h"
-
-void fluidsim_init(FluidsimModifierData *fluidmd)
-{
-#ifdef WITH_MOD_FLUID
- if (fluidmd) {
- FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings");
-
- fluidmd->fss = fss;
-
- if (!fss) {
- return;
- }
-
- fss->fmd = fluidmd;
- fss->type = OB_FLUIDSIM_ENABLE;
- fss->threads = 0;
- fss->show_advancedoptions = 0;
-
- fss->resolutionxyz = 65;
- fss->previewresxyz = 45;
- fss->realsize = 0.5;
- fss->guiDisplayMode = OB_FSDOM_PREVIEW;
- fss->renderDisplayMode = OB_FSDOM_FINAL;
-
- fss->viscosityValue = 1.0;
- fss->viscosityExponent = 6;
-
- fss->grav[0] = 0.0;
- fss->grav[1] = 0.0;
- fss->grav[2] = -9.81;
-
- fss->animStart = 0.0;
- fss->animEnd = 4.0;
- fss->animRate = 1.0;
- fss->gstar = 0.005; // used as normgstar
- fss->maxRefine = -1;
- /* maxRefine is set according to resolutionxyz during bake */
-
- /* fluid/inflow settings
- * fss->iniVel --> automatically set to 0 */
-
- modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), OB_FLUIDSIM_SURF_DIR_DEFAULT);
-
- /* first init of bounding box */
- /* no bounding box needed */
-
- /* todo - reuse default init from elbeem! */
- fss->typeFlags = OB_FSBND_PARTSLIP | OB_FSSG_NOOBS;
- fss->domainNovecgen = 0;
- fss->volumeInitType = 1; /* volume */
- fss->partSlipValue = 0.2;
-
- fss->generateTracers = 0;
- fss->generateParticles = 0.0;
- fss->surfaceSmoothing = 1.0;
- fss->surfaceSubdivs = 0.0;
- fss->particleInfSize = 0.0;
- fss->particleInfAlpha = 0.0;
-
- /* init fluid control settings */
- fss->attractforceStrength = 0.2;
- fss->attractforceRadius = 0.75;
- fss->velocityforceStrength = 0.2;
- fss->velocityforceRadius = 0.75;
- fss->cpsTimeStart = fss->animStart;
- fss->cpsTimeEnd = fss->animEnd;
- fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width
-
- /*
- * BAD TODO: this is done in buttons_object.c in the moment
- * Mesh *mesh = ob->data;
- * // calculate bounding box
- * fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
- */
-
- fss->meshVelocities = NULL;
-
- fss->lastgoodframe = -1;
-
- fss->flag |= OB_FLUIDSIM_ACTIVE;
- }
-#else
- (void)fluidmd; /* unused */
-#endif
- return;
-}
-
-void fluidsim_free(FluidsimModifierData *fluidmd)
-{
- if (fluidmd && fluidmd->fss) {
- if (fluidmd->fss->meshVelocities) {
- MEM_freeN(fluidmd->fss->meshVelocities);
- }
- MEM_SAFE_FREE(fluidmd->fss);
- }
-
- return;
-}
-
-#ifdef WITH_MOD_FLUID
-/* read .bobj.gz file into a fluidsimMesh struct */
-static Mesh *fluidsim_read_obj(const char *filename, const MPoly *mp_example)
-{
- int wri = 0, i;
- int gotBytes;
- gzFile gzf;
- int numverts = 0, numfaces = 0;
- Mesh *mesh = NULL;
- MPoly *mp;
- MLoop *ml;
- MVert *mv;
- short *normals, *no_s;
- float no[3];
-
- const short mp_mat_nr = mp_example->mat_nr;
- const char mp_flag = mp_example->flag;
-
- /* ------------------------------------------------
- * get numverts + numfaces first
- * ------------------------------------------------ */
- gzf = BLI_gzopen(filename, "rb");
- if (!gzf) {
- return NULL;
- }
-
- /* read numverts */
- gotBytes = gzread(gzf, &wri, sizeof(wri));
- numverts = wri;
-
- /* skip verts */
- gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;
-
- /* read number of normals */
- if (gotBytes) {
- gotBytes = gzread(gzf, &wri, sizeof(wri));
- }
-
- /* skip normals */
- gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;
-
- /* get no. of triangles */
- if (gotBytes) {
- gotBytes = gzread(gzf, &wri, sizeof(wri));
- }
- numfaces = wri;
-
- gzclose(gzf);
- /* ------------------------------------------------ */
-
- if (!numfaces || !numverts || !gotBytes) {
- return NULL;
- }
-
- gzf = BLI_gzopen(filename, "rb");
- if (!gzf) {
- return NULL;
- }
-
- mesh = BKE_mesh_new_nomain(numverts, 0, 0, numfaces * 3, numfaces);
-
- if (!mesh) {
- gzclose(gzf);
- return NULL;
- }
-
- /* read numverts */
- gotBytes = gzread(gzf, &wri, sizeof(wri));
-
- /* read vertex position from file */
- mv = mesh->mvert;
-
- for (i = 0; i < numverts; i++, mv++) {
- gotBytes = gzread(gzf, mv->co, sizeof(float) * 3);
- }
-
- /* should be the same as numverts */
- gotBytes = gzread(gzf, &wri, sizeof(wri));
- if (wri != numverts) {
- if (mesh) {
- BKE_id_free(NULL, mesh);
- }
- gzclose(gzf);
- return NULL;
- }
-
- normals = MEM_calloc_arrayN(numverts, 3 * sizeof(short), "fluid_tmp_normals");
- if (!normals) {
- if (mesh) {
- BKE_id_free(NULL, mesh);
- }
- gzclose(gzf);
- return NULL;
- }
-
- /* read normals from file (but don't save them yet) */
- for (i = numverts, no_s = normals; i > 0; i--, no_s += 3) {
- gotBytes = gzread(gzf, no, sizeof(float) * 3);
- normal_float_to_short_v3(no_s, no);
- }
-
- /* read no. of triangles */
- gotBytes = gzread(gzf, &wri, sizeof(wri));
-
- if (wri != numfaces) {
- printf("Fluidsim: error in reading data from file.\n");
- if (mesh) {
- BKE_id_free(NULL, mesh);
- }
- gzclose(gzf);
- MEM_freeN(normals);
- return NULL;
- }
-
- /* read triangles from file */
- mp = mesh->mpoly;
- ml = mesh->mloop;
- for (i = 0; i < numfaces; i++, mp++, ml += 3) {
- int face[3];
-
- gotBytes = gzread(gzf, face, sizeof(int) * 3);
-
- /* initialize from existing face */
- mp->mat_nr = mp_mat_nr;
- mp->flag = mp_flag;
-
- mp->loopstart = i * 3;
- mp->totloop = 3;
-
- ml[0].v = face[0];
- ml[1].v = face[1];
- ml[2].v = face[2];
- }
-
- gzclose(gzf);
-
- BKE_mesh_calc_edges(mesh, false, false);
- BKE_mesh_apply_vert_normals(mesh, (short(*)[3])normals);
- MEM_freeN(normals);
-
- // CDDM_calc_normals(result);
- return mesh;
-}
-
-void fluid_get_bb(MVert *mvert,
- int totvert,
- float obmat[4][4],
- /*RET*/ float start[3],
- /*RET*/ float size[3])
-{
- float bbsx = 0.0, bbsy = 0.0, bbsz = 0.0;
- float bbex = 1.0, bbey = 1.0, bbez = 1.0;
- int i;
- float vec[3];
-
- if (totvert == 0) {
- zero_v3(start);
- zero_v3(size);
- return;
- }
-
- copy_v3_v3(vec, mvert[0].co);
- mul_m4_v3(obmat, vec);
- bbsx = vec[0];
- bbsy = vec[1];
- bbsz = vec[2];
- bbex = vec[0];
- bbey = vec[1];
- bbez = vec[2];
-
- for (i = 1; i < totvert; i++) {
- copy_v3_v3(vec, mvert[i].co);
- mul_m4_v3(obmat, vec);
-
- if (vec[0] < bbsx) {
- bbsx = vec[0];
- }
- if (vec[1] < bbsy) {
- bbsy = vec[1];
- }
- if (vec[2] < bbsz) {
- bbsz = vec[2];
- }
- if (vec[0] > bbex) {
- bbex = vec[0];
- }
- if (vec[1] > bbey) {
- bbey = vec[1];
- }
- if (vec[2] > bbez) {
- bbez = vec[2];
- }
- }
-
- /* return values... */
- if (start) {
- start[0] = bbsx;
- start[1] = bbsy;
- start[2] = bbsz;
- }
- if (size) {
- size[0] = bbex - bbsx;
- size[1] = bbey - bbsy;
- size[2] = bbez - bbsz;
- }
-}
-
-//-------------------------------------------------------------------------------
-// old interface
-//-------------------------------------------------------------------------------
-
-void fluid_estimate_memory(Object *ob, FluidsimSettings *fss, char *value)
-{
- Mesh *mesh;
-
- value[0] = '\0';
-
- if (ob->type == OB_MESH) {
- /* use mesh bounding box and object scaling */
- mesh = ob->data;
-
- fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
- elbeemEstimateMemreq(
- fss->resolutionxyz, fss->bbSize[0], fss->bbSize[1], fss->bbSize[2], fss->maxRefine, value);
- }
-}
-
-/* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
-static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, Mesh *mesh, char *filename)
-{
- int wri, i, j;
- float wrf;
- gzFile gzf;
- FluidsimSettings *fss = fluidmd->fss;
- int len = strlen(filename);
- int totvert = mesh->totvert;
- FluidVertexVelocity *velarray = NULL;
-
- /* mesh and vverts have to be valid from loading... */
-
- if (fss->meshVelocities) {
- MEM_freeN(fss->meshVelocities);
- }
-
- if (len < 7) {
- return;
- }
-
- if (fss->domainNovecgen > 0) {
- return;
- }
-
- fss->meshVelocities = MEM_calloc_arrayN(
- mesh->totvert, sizeof(FluidVertexVelocity), "Fluidsim_velocities");
- fss->totvert = totvert;
-
- velarray = fss->meshVelocities;
-
- /* .bobj.gz, correct filename
- * 87654321 */
- filename[len - 6] = 'v';
- filename[len - 5] = 'e';
- filename[len - 4] = 'l';
-
- gzf = BLI_gzopen(filename, "rb");
- if (!gzf) {
- MEM_freeN(fss->meshVelocities);
- fss->meshVelocities = NULL;
- return;
- }
-
- gzread(gzf, &wri, sizeof(wri));
- if (wri != totvert) {
- MEM_freeN(fss->meshVelocities);
- fss->meshVelocities = NULL;
- return;
- }
-
- for (i = 0; i < totvert; i++) {
- for (j = 0; j < 3; j++) {
- gzread(gzf, &wrf, sizeof(wrf));
- velarray[i].vel[j] = wrf;
- }
- }
-
- gzclose(gzf);
-}
-
-static Mesh *fluidsim_read_cache(
- Object *ob, Mesh *orgmesh, FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
-{
- int curFrame = framenr /* - 1 */ /*scene->r.sfra*/; /* start with 0 at start frame */
- /* why start with 0 as start frame?? Animations + time are frozen for frame 0 anyway.
- * (See physics_fluid.c for that. - DG) */
- /* If we start with frame 0, we need to remap all animation channels, too,
- * because they will all be 1 frame late if using frame-1! - DG */
-
- char targetFile[FILE_MAX];
- FluidsimSettings *fss = fluidmd->fss;
- Mesh *newmesh = NULL;
- MPoly *mpoly;
- MPoly mp_example = {0};
-
- const int displaymode = useRenderParams ? fss->renderDisplayMode : fss->guiDisplayMode;
-
- switch (displaymode) {
- case OB_FSDOM_GEOM:
- /* just display original object */
- return NULL;
- case OB_FSDOM_PREVIEW:
- /* use preview mesh */
- BLI_join_dirfile(
- targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
- break;
- case OB_FSDOM_FINAL:
- /* use final mesh */
- BLI_join_dirfile(
- targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
- break;
- default:
- BLI_assert(!"Wrong fluidsim display type");
- return NULL;
- }
-
- /* offset baked frame */
- curFrame += fss->frameOffset;
-
- BLI_path_abs(targetFile, modifier_path_relbase_from_global(ob));
- BLI_path_frame(targetFile, curFrame, 0); // fixed #frame-no
-
- /* assign material + flags to new mesh.
- * if there's no faces in original mesh, keep materials and flags unchanged */
- mpoly = orgmesh->mpoly;
- if (mpoly) {
- mp_example = *mpoly;
- }
- /* else leave NULL'd */
-
- newmesh = fluidsim_read_obj(targetFile, &mp_example);
-
- if (!newmesh) {
- /* switch, abort background rendering when fluidsim mesh is missing */
- const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
-
- if (G.background == 1) {
- if (BLI_getenv(strEnvName2)) {
- int elevel = atoi(BLI_getenv(strEnvName2));
- if (elevel > 0) {
- printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",
- strEnvName2,
- targetFile);
- exit(1);
- }
- }
- }
-
- /* display org. object upon failure which is in new mesh */
- return NULL;
- }
-
- /* load vertex velocities, if they exist...
- * TODO? use generate flag as loading flag as well?
- * warning, needs original .bobj.gz mesh loading filename */
- if (displaymode == OB_FSDOM_FINAL) {
- fluidsim_read_vel_cache(fluidmd, newmesh, targetFile);
- }
- else {
- if (fss->meshVelocities) {
- MEM_freeN(fss->meshVelocities);
- }
-
- fss->meshVelocities = NULL;
- }
-
- return newmesh;
-}
-#endif // WITH_MOD_FLUID
-
-Mesh *fluidsimModifier_do(FluidsimModifierData *fluidmd,
- const ModifierEvalContext *ctx,
- Mesh *mesh)
-{
-#ifdef WITH_MOD_FLUID
- Object *ob = ctx->object;
- Depsgraph *depsgraph = ctx->depsgraph;
- const bool useRenderParams = (ctx->flag & MOD_APPLY_RENDER) != 0;
- // const bool isFinalCalc = (ctx->flag & MOD_APPLY_USECACHE) != 0;
- Mesh *result = NULL;
- int framenr;
- FluidsimSettings *fss = NULL;
-
- framenr = (int)DEG_get_ctime(depsgraph);
-
- /* only handle fluidsim domains */
- if (fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN)) {
- return mesh;
- }
-
- /* sanity check */
- if (!fluidmd || !fluidmd->fss) {
- return mesh;
- }
-
- fss = fluidmd->fss;
-
- /* timescale not supported yet
- * clmd->sim_parms->timescale = timescale; */
-
- /* support reversing of baked fluid frames here */
- if ((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0)) {
- framenr = fss->lastgoodframe - framenr + 1;
- CLAMP(framenr, 1, fss->lastgoodframe);
- }
-
- /* try to read from cache */
- /* if the frame is there, fine, otherwise don't do anything */
- if ((result = fluidsim_read_cache(ob, mesh, fluidmd, framenr, useRenderParams))) {
- return result;
- }
-
- return mesh;
-#else
- /* unused */
- UNUSED_VARS(fluidmd, ctx, mesh);
- return NULL;
-#endif
-}
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_manta.c
index 34275d91ee6..b561ac6fc44 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_manta.c
@@ -30,7 +30,7 @@
#include "DNA_collection_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
+#include "DNA_manta_types.h"
#include "DNA_object_force_types.h"
#include "DNA_mesh_types.h"
@@ -38,7 +38,7 @@
#include "BKE_layer.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
-#include "BKE_smoke.h"
+#include "BKE_manta.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -49,45 +49,45 @@
static void initData(ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ MantaModifierData *mmd = (MantaModifierData *)md;
- smd->domain = NULL;
- smd->flow = NULL;
- smd->coll = NULL;
- smd->type = 0;
- smd->time = -1;
+ mmd->domain = NULL;
+ mmd->flow = NULL;
+ mmd->effec = NULL;
+ mmd->type = 0;
+ mmd->time = -1;
}
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
- const SmokeModifierData *smd = (const SmokeModifierData *)md;
- SmokeModifierData *tsmd = (SmokeModifierData *)target;
+ const MantaModifierData *mmd = (const MantaModifierData *)md;
+ MantaModifierData *tmmd = (MantaModifierData *)target;
- smokeModifier_free(tsmd);
- smokeModifier_copy(smd, tsmd, flag);
+ mantaModifier_free(tmmd);
+ mantaModifier_copy(mmd, tmmd, flag);
}
static void freeData(ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ MantaModifierData *mmd = (MantaModifierData *)md;
- smokeModifier_free(smd);
+ mantaModifier_free(mmd);
}
static void requiredDataMask(Object *UNUSED(ob),
ModifierData *md,
CustomData_MeshMasks *r_cddata_masks)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ MantaModifierData *mmd = (MantaModifierData *)md;
- if (smd && (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
- if (smd->flow->source == MOD_SMOKE_FLOW_SOURCE_MESH) {
+ if (mmd && (mmd->type & MOD_MANTA_TYPE_FLOW) && mmd->flow) {
+ if (mmd->flow->source == FLUID_FLOW_SOURCE_MESH) {
/* vertex groups */
- if (smd->flow->vgroup_density) {
+ if (mmd->flow->vgroup_density) {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
}
/* uv layer */
- if (smd->flow->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_UV) {
+ if (mmd->flow->texture_type == FLUID_FLOW_TEXTURE_MAP_UV) {
r_cddata_masks->fmask |= CD_MASK_MTFACE;
}
}
@@ -96,14 +96,17 @@ static void requiredDataMask(Object *UNUSED(ob),
static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ Mesh *result = NULL;
if (ctx->flag & MOD_APPLY_ORCO) {
return me;
}
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
- return smokeModifier_do(smd, ctx->depsgraph, scene, ctx->object, me);
+
+ result = mantaModifier_do(mmd, ctx->depsgraph, scene, ctx->object, me);
+ return result ? result : me;
}
static bool dependsOnTime(ModifierData *UNUSED(md))
@@ -113,65 +116,76 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
static bool is_flow_cb(Object *UNUSED(ob), ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
- return (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow;
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ return (mmd->type & MOD_MANTA_TYPE_FLOW) && mmd->flow;
}
static bool is_coll_cb(Object *UNUSED(ob), ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
- return (smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll;
+ MantaModifierData *mmd = (MantaModifierData *)md;
+ return (mmd->type & MOD_MANTA_TYPE_EFFEC) && mmd->effec;
}
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ MantaModifierData *mmd = (MantaModifierData *)md;
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
+ if (mmd && (mmd->type & MOD_MANTA_TYPE_DOMAIN) && mmd->domain) {
DEG_add_collision_relations(ctx->node,
ctx->object,
- smd->domain->fluid_group,
- eModifierType_Smoke,
+ mmd->domain->fluid_group,
+ eModifierType_Manta,
is_flow_cb,
- "Smoke Flow");
+ "Manta Flow");
DEG_add_collision_relations(ctx->node,
ctx->object,
- smd->domain->coll_group,
- eModifierType_Smoke,
+ mmd->domain->coll_group,
+ eModifierType_Manta,
is_coll_cb,
- "Smoke Coll");
+ "Manta Coll");
DEG_add_forcefield_relations(ctx->node,
ctx->object,
- smd->domain->effector_weights,
+ mmd->domain->effector_weights,
true,
PFIELD_SMOKEFLOW,
- "Smoke Force Field");
+ "Manta Force Field");
+
+ if (mmd->domain->guiding_parent != NULL) {
+ DEG_add_object_relation(
+ ctx->node, mmd->domain->guiding_parent, DEG_OB_COMP_TRANSFORM, "Fluid Guiding Object");
+ DEG_add_object_relation(
+ ctx->node, mmd->domain->guiding_parent, DEG_OB_COMP_GEOMETRY, "Fluid Guiding Object");
+ }
}
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
- SmokeModifierData *smd = (SmokeModifierData *)md;
+ MantaModifierData *mmd = (MantaModifierData *)md;
- if (smd->type == MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
- walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_CB_NOP);
- walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_CB_NOP);
- walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_CB_NOP);
+ if (mmd->type == MOD_MANTA_TYPE_DOMAIN && mmd->domain) {
+ walk(userData, ob, (ID **)&mmd->domain->coll_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&mmd->domain->fluid_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&mmd->domain->eff_group, IDWALK_CB_NOP);
+
+ if (mmd->domain->guiding_parent) {
+ walk(userData, ob, (ID **)&mmd->domain->guiding_parent, IDWALK_CB_NOP);
+ }
- if (smd->domain->effector_weights) {
- walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_CB_NOP);
+ if (mmd->domain->effector_weights) {
+ walk(userData, ob, (ID **)&mmd->domain->effector_weights->group, IDWALK_CB_NOP);
}
}
- if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) {
- walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_CB_USER);
+ if (mmd->type == MOD_MANTA_TYPE_FLOW && mmd->flow) {
+ walk(userData, ob, (ID **)&mmd->flow->noise_texture, IDWALK_CB_USER);
}
}
-ModifierTypeInfo modifierType_Smoke = {
- /* name */ "Smoke",
- /* structName */ "SmokeModifierData",
- /* structSize */ sizeof(SmokeModifierData),
+ModifierTypeInfo modifierType_Manta = {
+ /* name */ "Manta",
+ /* structName */ "MantaModifierData",
+ /* structSize */ sizeof(MantaModifierData),
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_UsesPointCache |
eModifierTypeFlag_Single,
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 998a2b1cd65..03f5f881d08 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -279,12 +279,11 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(ParticleInstance);
INIT_TYPE(Explode);
INIT_TYPE(Shrinkwrap);
- INIT_TYPE(Fluidsim);
INIT_TYPE(Mask);
INIT_TYPE(SimpleDeform);
INIT_TYPE(Multires);
INIT_TYPE(Surface);
- INIT_TYPE(Smoke);
+ INIT_TYPE(Manta);
INIT_TYPE(ShapeKey);
INIT_TYPE(Solidify);
INIT_TYPE(Screw);
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index fc945562c98..edb76226c8e 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -33,6 +33,7 @@ set(INC
../../windowmanager
../../../../intern/clog
../../../../intern/guardedalloc
+ ../../../../intern/mantaflow/extern
../../../../intern/opencolorio
)
@@ -253,10 +254,6 @@ if(WITH_LIBMV)
add_definitions(-DWITH_LIBMV)
endif()
-if(WITH_MOD_FLUID)
- add_definitions(-DWITH_MOD_FLUID)
-endif()
-
if(WITH_MOD_OCEANSIM)
add_definitions(-DWITH_OCEANSIM)
endif()
@@ -265,8 +262,8 @@ if(WITH_MOD_REMESH)
add_definitions(-DWITH_MOD_REMESH)
endif()
-if(WITH_MOD_SMOKE)
- add_definitions(-DWITH_SMOKE)
+if(WITH_MOD_MANTA)
+ add_definitions(-DWITH_MANTA)
endif()
if(WITH_OPENCOLLADA)
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index a841e974e85..b8b1e72f527 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -50,15 +50,14 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"sdl_dynload", NULL},
{(char *)"jack", NULL},
{(char *)"libmv", NULL},
- {(char *)"mod_fluid", NULL},
{(char *)"mod_oceansim", NULL},
{(char *)"mod_remesh", NULL},
- {(char *)"mod_smoke", NULL},
{(char *)"collada", NULL},
{(char *)"opencolorio", NULL},
{(char *)"openmp", NULL},
{(char *)"openvdb", NULL},
{(char *)"alembic", NULL},
+ {(char *)"manta", NULL},
{NULL},
};
@@ -214,12 +213,6 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
-#ifdef WITH_MOD_FLUID
- SetObjIncref(Py_True);
-#else
- SetObjIncref(Py_False);
-#endif
-
#ifdef WITH_OCEANSIM
SetObjIncref(Py_True);
#else
@@ -232,12 +225,6 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
-#ifdef WITH_SMOKE
- SetObjIncref(Py_True);
-#else
- SetObjIncref(Py_False);
-#endif
-
#ifdef WITH_COLLADA
SetObjIncref(Py_True);
#else
@@ -268,6 +255,12 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_MANTA
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#undef SetObjIncref
return builtopts_info;
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 71bc01d6b98..b345130afe5 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -197,8 +197,15 @@ void BPY_context_set(bContext *C)
BPy_SetContext(C);
}
+#ifdef WITH_MANTA
+/* defined in manta module */
+extern PyObject *Manta_initPython(void);
+#endif
+
+#ifdef WITH_AUDASPACE
/* defined in AUD_C-API.cpp */
extern PyObject *AUD_initPython(void);
+#endif
#ifdef WITH_CYCLES
/* defined in cycles module */
@@ -225,6 +232,9 @@ static struct _inittab bpy_internal_modules[] = {
{"bmesh.utils", BPyInit_bmesh_utils},
{"bmesh.utils", BPyInit_bmesh_geometry},
#endif
+#ifdef WITH_MANTA
+ {"manta", Manta_initPython},
+#endif
#ifdef WITH_AUDASPACE
{"aud", AUD_initPython},
#endif
@@ -293,6 +303,10 @@ void BPY_python_start(int argc, const char **argv)
/* Initialize thread support (also acquires lock) */
PyEval_InitThreads();
+
+ /* (sebbas): Required to prevent assertion error */
+ /* see: https://stackoverflow.com/questions/27844676/assertionerror-3-x-only-when-calling-py-finalize-with-threads */
+ Py_DECREF(PyImport_ImportModule("threading"));
#else
(void)argc;
(void)argv;
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index e265197646c..d97a7d258bd 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -36,7 +36,7 @@ set(INC
../../../intern/atomic
../../../intern/guardedalloc
../../../intern/mikktspace
- ../../../intern/smoke/extern
+ ../../../intern/mantaflow/extern
)
set(INC_SYS
@@ -86,8 +86,8 @@ if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)
endif()
-if(WITH_MOD_SMOKE)
- add_definitions(-DWITH_SMOKE)
+if(WITH_MOD_MANTA)
+ add_definitions(-DWITH_MANTA)
endif()
if(WITH_FREESTYLE)
diff --git a/source/blender/shader_fx/CMakeLists.txt b/source/blender/shader_fx/CMakeLists.txt
index 57c7345076e..6d918763996 100644
--- a/source/blender/shader_fx/CMakeLists.txt
+++ b/source/blender/shader_fx/CMakeLists.txt
@@ -30,7 +30,6 @@ set(INC
../makesdna
../makesrna
../render/extern/include
- ../../../intern/elbeem/extern
../../../intern/eigen
../../../intern/guardedalloc
)
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 04e3f7e88dc..99413679285 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -676,6 +676,7 @@ enum {
WM_JOB_TYPE_SEQ_BUILD_PREVIEW,
WM_JOB_TYPE_POINTCACHE,
WM_JOB_TYPE_DPAINT_BAKE,
+ WM_JOB_TYPE_OBJECT_SIM_MANTA,
WM_JOB_TYPE_ALEMBIC,
WM_JOB_TYPE_SHADER_COMPILATION,
WM_JOB_TYPE_STUDIOLIGHT,
diff --git a/source/tools b/source/tools
-Subproject aa9cc18913aca559e932d5b7894e3c222ccffae
+Subproject 6cf5f61a957798d3fa0678aa92a2afd99023b03