1
1

Compare commits

...

981 Commits

Author SHA1 Message Date
ed32db06c1 Merge branch 'master' into fluid-mantaflow 2019-12-16 15:05:04 +01:00
451400f6e6 Mantaflow: Fixed more issues raised in part 6 of the review (D3855)
Mostly renaming from manta to fluid
2019-12-16 15:02:32 +01:00
6ed9eab010 Mantaflow: Post merge fixes 2019-12-15 22:41:56 +01:00
75eb9b93b3 Merge branch 'master' into fluid-mantaflow 2019-12-15 22:36:01 +01:00
d2dfaff2b6 Mantaflow: Cleaned up warnings 2019-12-15 22:26:00 +01:00
09aa3439b8 Mantaflow: Fix even more names, ie fluid instead of smoke 2019-12-15 21:57:18 +01:00
484a2803e6 Mantaflow: Fix more names, ie fluid instead of smoke 2019-12-15 21:45:50 +01:00
6f17b4cc5e Mantaflow: Fix wrong include in new overlay extras 2019-12-15 21:22:08 +01:00
2cc63752fd Mantaflow: Clean up waveletNoiseTile.bin 2019-12-12 22:50:17 +01:00
50256da50a Merge branch 'master' into fluid-mantaflow 2019-12-12 22:46:00 +01:00
6ca148dad0 Mantaflow: Minor sanity checks 2019-12-12 22:34:52 +01:00
57d25f4f9b Mantaflow: Updated manta source files 2019-12-12 22:33:00 +01:00
c83447cdf4 Mantaflow: Mantaflow is now not an experimental feature 2019-12-12 17:53:44 +01:00
36d309cff7 Mantaflow: Renaming from manta to fluid 2019-12-12 14:12:11 +01:00
10bc043c99 Mantaflow: Fix for guiding res pointer 2019-12-12 02:46:47 +01:00
a3e2b60f93 Mantaflow: Mantaflow is now an experimental feature 2019-12-12 02:46:05 +01:00
b75c38ee83 Mantaflow: Fixed more issues raised in part 11 of the review (D3861) 2019-12-11 17:41:38 +01:00
d9328f69b8 Mantaflow: Fixed more issues raised in part 2 of the review (D3851) 2019-12-11 17:33:46 +01:00
6b62eb17a0 Mantaflow: Clang format previous commit 2019-12-11 17:29:47 +01:00
3d4e5a89eb Mantaflow: Fixed more issues raised in part 8 of the review (D3857) 2019-12-11 17:25:31 +01:00
df747de1fc Mantaflow: Clang format previous commit 2019-12-11 16:03:13 +01:00
5d009982b1 Mantaflow: Fixed issues raised in part 9 of the review (D3858) 2019-12-11 16:00:46 +01:00
c98a82b7d5 Mantaflow: Fixed issues raised in part 11 of the review (D3861) 2019-12-11 12:36:06 +01:00
a3328a8699 Mantaflow: Fixed issues raised in part 10 of the review (D3860) 2019-12-11 11:24:13 +01:00
c54fd66c0a Mantaflow: Fixed more issues raised in part 8 of the review (D3857) 2019-12-11 10:24:48 +01:00
63b0377e96 Mantaflow: Fixed issues raised in part 8 of the review (D3857) 2019-12-11 10:07:14 +01:00
2fcf705a17 Mantaflow: Fixed issues raised in part 7 of the review (D3856) 2019-12-10 22:53:14 +01:00
881b90b922 Mantaflow: Fixed issues raised in part 6 of the review (D3855) 2019-12-10 22:02:13 +01:00
f4db26f01b Mantaflow: Fixed issues raised in part 3 of the review (D3852) 2019-12-10 21:44:36 +01:00
82d75a46ce Mantaflow: Fixed issues raised in part 2 of the review (D3851) 2019-12-10 18:25:17 +01:00
fc557cdd13 Mantaflow: Fixed issues raised in part 1 of the review (D3850) 2019-12-10 15:35:30 +01:00
e96877c8b7 Mantaflow: Flame vorticity fix 2019-12-01 22:29:18 +01:00
6b7b619f06 Mantaflow: Cleaned up extern C in implementation file
No need to duplicate it, it is already declared in header file
2019-11-27 11:39:33 +01:00
c179a13a4b Merge branch 'master' into fluid-mantaflow 2019-11-27 11:17:58 +01:00
0ca44974c9 Mantaflow: Fix for bake not being triggered when executed for the first time 2019-11-26 23:21:36 +01:00
95e9c164a9 Mantaflow: Cleanup in smoke script 2019-11-26 22:02:02 +01:00
c7c92ca63b Mantaflow: Improved fluid inflow setup 2019-11-26 21:50:47 +01:00
5628318fb3 Mantaflow: Added Bake all functionality
The new option for cache type final includes the bake all operator
2019-11-26 21:50:09 +01:00
bd36ad9171 Mantaflow: Cleanup and sanity checks in fluid scripts 2019-11-26 21:49:07 +01:00
37ae8d65fa Mantaflow: Cleaned up pointer exchange 2019-11-26 21:41:07 +01:00
730c829b25 Mantaflow: Cleaned up smoke noise code 2019-11-25 21:36:06 +01:00
aaa0cecb2c Mantaflow: Added flame vorticity functionality 2019-11-25 21:22:32 +01:00
6feca2c932 Mantaflow: Added cache reset functionality
Particularly important for cache replay mode
2019-11-25 21:10:38 +01:00
355107ce5e Mantaflow: Updated Manta pointer exchange setup 2019-11-25 20:45:13 +01:00
b0b92717bb Mantaflow: Fix solid mode drawing issue for liquid domains 2019-11-23 00:17:18 +01:00
0109c52ea7 Mantaflow: Small adjustments to surface-distance parameter
Better default values
2019-11-22 13:02:38 +01:00
20933a1d44 Mantaflow: Updated build setup
Moved Manta source files to extern/ and adapted the updater script
2019-11-21 23:00:22 +01:00
b0f221bda1 Fix T71583: Liquid domains with missing origin offset 2019-11-21 15:33:56 +01:00
baceb91552 Mantaflow: Removed cache reset setup for now 2019-11-21 10:33:22 +01:00
c73aaf6af2 Merge branch 'master' into fluid-mantaflow 2019-11-20 18:49:01 +01:00
a8a41cfdf2 Mantaflow: Cleanup with clang-format 2019-11-20 18:47:02 +01:00
2e863df3a9 Merge branch 'master' into fluid-mantaflow 2019-11-20 14:41:16 +01:00
e1aa388135 Mantaflow: Big update for liquid simulations
Support for second order obstacles, additional parameters to control liquid behavior (e.g. flip ratio, max/min timesteps)
2019-11-20 14:39:22 +01:00
13124fa84e Mantaflow: Added min/max timestep parameters
These parameters will allow the user to better control how long bake jobs may/should take.
2019-11-20 13:05:53 +01:00
fcb49d8029 Mantaflow: Fix for memory deallocation
Mesh was being freed slightly too early. Might have been the cause of very random crashes.
2019-11-20 13:00:06 +01:00
0ea952df43 Mantaflow: Sanity check required when reading older files 2019-11-20 12:54:31 +01:00
98d7f35087 Mantaflow: Fix for Eevee attempting to draw volumes into liquid domains 2019-11-20 12:45:42 +01:00
3e8cec8d2b Mantaflow: Updated manta source updater script 2019-11-20 12:42:27 +01:00
5c03ccfc06 Mantaflow: Updated manta pp files 2019-11-20 12:41:25 +01:00
9b098e340b Mantaflow: Reset all cache pause frames fields when data bake is freed
Data Free was only resetting its own pause frame even though all bakes get deleted during this operation.
2019-11-08 12:47:08 +01:00
1cd70c4f09 Merge branch 'master' into fluid-mantaflow 2019-11-08 12:24:25 +01:00
ccbf9ea490 Mantaflow: Optimization for parallel tasks
Default value in minimum iter per thread was preventing multithreading to kick in
2019-11-01 16:49:26 +01:00
998c8d18f2 Mantaflow: Added first version of new cache system
Refactored caching code to make it compatible with new replay option
2019-10-19 23:25:50 +02:00
c43553391a Mantaflow: Updated manta script calls
Refactoring and now using the new boundaryWidth optimization in fillHoles
2019-10-09 19:02:35 +02:00
a4a825e0fc Mantaflow: Updated manta pp files 2019-10-09 18:53:27 +02:00
db822888ef Mantaflow: Renamed variables to match new struct names
Variable names were referring to SmokeFlowSettings and SmokeCollisionSettings which have been renamed to Manta...
2019-10-08 16:36:56 +02:00
28c66e118e Fix broken manta update script 2019-10-06 23:09:55 +02:00
5419b7ab92 Updated manta update script
Use clang-format now after copying preprocessed files
2019-10-06 22:13:41 +02:00
4f338388d9 Applied clang-format to manta preprocessed source files
Just for better readability, files remain read-only, i.e. editing in manta repo only
2019-10-06 22:12:14 +02:00
a937bb8b0d Mantaflow: Fix crash when freeing bake with unknown cache directory 2019-09-27 17:38:42 +02:00
114783000d Fix T70175: Mantaflow not using subframes for particle emitters in Gas sim
Fixes issue with particle emitter not considering subframes
2019-09-27 11:45:52 +02:00
0d31127d6c Mantaflow: Fixes issue with missing materials 2019-09-26 15:06:57 +02:00
26afd3e99d Merge branch 'master' into fluid-mantaflow 2019-09-26 13:00:15 +02:00
2a789871e2 Merge branch 'master' into fluid-mantaflow 2019-09-25 15:02:47 +02:00
f1c3777fb9 Mantaflow: Fix for voxel indicator cube in domain object
Voxel indicator cube was not considering rotations of domain object
2019-09-25 11:21:39 +02:00
b333870203 Mantaflow: Fix for multiple modifiers issue
Some old smoke names were not renamed correctly
2019-09-20 15:36:07 +02:00
26635d7b6d Mantaflow: Fix for versioning issue
Fixes crash with old fluid (Elbeem) modifier
2019-09-02 20:48:52 +02:00
3377b77491 Mantaflow: Fix for noise density issue
Emission values for noise need to be upscaled with upres factor
2019-09-02 20:47:19 +02:00
552149d8f5 Mantaflow: Fix warning in rna_manta.c 2019-08-28 01:26:35 +02:00
d62f6de0a4 Mantaflow: Remove particle type additions from previous commit
Generated warning from bpy_rna.c should be safe to ignore for now
2019-08-26 01:34:21 +02:00
cd9a54c012 Merge branch 'master' into fluid-mantaflow 2019-08-26 00:50:08 +02:00
052f0c68a6 Mantaflow: Small fixes for a clean console 2019-08-26 00:09:06 +02:00
8beba05ecc Merge branch 'master' into fluid-mantaflow 2019-08-18 22:53:13 +02:00
a97d7a829f Mantaflow: Addressed all issues from the review / diff 2019-08-18 21:53:07 +02:00
02a94d6a4c Merge branch 'master' into fluid-mantaflow 2019-07-23 18:09:17 +02:00
eefef6179d Mantaflow: Updated Mantaflow sources files 2019-07-23 18:01:09 +02:00
e08ae99652 Merge branch 'master' into fluid-mantaflow 2019-07-18 22:20:20 +02:00
a39a724187 Mantaflow: Code cleanup in UI 2019-07-18 15:13:30 +02:00
aa6d630144 Mantaflow: Update for adaptive domain
Fixes issues with smoke moving not uniformly when domain size changes.
2019-07-18 15:12:55 +02:00
9a964c3f34 Mantaflow: More manta / smoke renaming and added some sanity checks for the adaptive domain 2019-06-23 17:51:05 +02:00
c2b72102bd Mantaflow: Removed old liquid code completely
rip
2019-06-19 17:05:39 +02:00
aa1e9f2e53 Mantaflow: Removed old smoke code completely
rip
2019-06-18 16:36:24 +02:00
41a0e7a5de Mantaflow: Applied Nils big rename patches
Replaces occurences of smoke with manta
2019-06-18 16:20:24 +02:00
603894cc4d Mantaflow: Fix caching bug from master merge review 2019-05-27 11:29:45 +02:00
0442170995 Mantaflow: Cleanup Mantaflow source files
No need to have numpy bindings in Blender right now
2019-05-27 11:27:46 +02:00
232ec3132d Mantaflow: Moved smoke dissolve function from Blender C code to internal Mantaflow code 2019-05-27 11:26:41 +02:00
7842721f4c Fix T65043: Make sure that final mesh geometry gets initialized 2019-05-23 22:04:40 +02:00
f82717a061 Mantaflow: Small fix related to mesh domain object and post merge cleanup 2019-05-22 00:25:27 +02:00
c2fe19cf88 Merge branch 'master' into fluid-mantaflow 2019-05-21 22:26:45 +02:00
52501be2c2 Mantaflow: Post merge fixes 2019-05-19 22:01:35 +02:00
71b7e996d4 Merge branch 'master' into fluid-mantaflow 2019-05-19 21:07:09 +02:00
ebb639def2 Mantaflow: Small UI fix
effector_weights function had deprecated arguments
2019-05-19 21:05:20 +02:00
bfb2f4db1a Mantaflow: Implemented adaptive domain for manta smoke
This functionality exists in the vanilla build already but had to be disabled in the manta build. Now it is back.
2019-05-19 21:04:04 +02:00
66698b9f37 Mantaflow: Updated UI for domain border behaviour
Options for domain borders are now in a separate panel
2019-05-19 19:34:40 +02:00
d06aedc245 Mantaflow: Fix for smoke emission from particles 2019-05-10 19:59:32 +02:00
09a3217c96 Mantaflow: Updated manta pp files and added update script 2019-05-10 11:56:56 +02:00
b9ca115d50 Merge branch 'master' into fluid-mantaflow 2019-05-04 15:55:59 +02:00
773647d319 Merge 'master' into 'fluid-mantaflow'
Conflicts:
	release/scripts/startup/bl_ui/properties_physics_common.py
	release/scripts/startup/bl_ui/properties_physics_smoke.py
	source/blender/blenkernel/CMakeLists.txt
	source/blender/blenkernel/intern/particle_system.c
	source/blender/blenkernel/intern/pointcache.c
	source/blender/blenkernel/intern/smoke.c
	source/blender/editors/physics/CMakeLists.txt
	source/blender/makesdna/DNA_smoke_types.h
	source/blender/modifiers/intern/MOD_smoke.c
2019-05-04 15:55:17 +02:00
1ed8eaa348 Merge 'master' into 'fluid-mantaflow' 2019-05-04 12:36:02 +02:00
432f9da43f Merge 'master' into 'fluid-mantaflow'
Conflicts:
	build_files/cmake/macros.cmake
	intern/smoke/CMakeLists.txt
	source/blender/blenkernel/CMakeLists.txt
	source/blender/blenkernel/intern/smoke.c
	source/blender/draw/engines/eevee/eevee_volumes.c
2019-05-04 12:35:31 +02:00
723cc85423 Mantaflow: Fixes small issue with levelset
Minor change in levelset generation and added sanity check for flowsflags
2019-04-06 18:33:12 +02:00
ac540f0692 Merge branch 'smokeTypes' into smokeC 2019-04-06 18:25:33 +02:00
3c00523eaa Merge branch 'rnaSmoke' into smokeTypes 2019-04-06 18:25:12 +02:00
2d438ae53e Merge branch 'particleSystem' into rnaSmoke 2019-04-06 18:24:49 +02:00
95b9766c17 Merge branch 'bakeConfig' into particleSystem 2019-04-06 18:24:34 +02:00
a7cf4cccf0 Merge branch 'sourceUpdate' into bakeConfig 2019-04-06 18:24:18 +02:00
697b8f1bb8 Merge branch 'internUpdate' into sourceUpdate 2019-04-06 18:23:42 +02:00
7104d1311f Merge branch 'buildConfig' into internUpdate 2019-04-06 18:23:29 +02:00
90f3d5d851 Merge branch 'pythonScripts' into buildConfig 2019-04-06 18:21:38 +02:00
809443ee6f Merge branch 'mantaWrapper' into pythonScripts 2019-04-06 18:20:19 +02:00
6cf9f1e525 Mantaflow: Cleanup debug output and some refactoring
No need to have huge debug output enabled
2019-04-06 18:14:53 +02:00
c1af4f849f Merge branch 'fluid-mantaflow' into smokeC 2019-04-06 17:08:04 +02:00
0756286ee1 Mantaflow: Updated smoke.c to let mantaflow side handle inflow application
Write inflow into separate inflow grids instead of writing directly into simulation grids
2019-04-06 00:00:16 +02:00
1960703a3b Merge branch 'smokeTypes' into smokeC 2019-04-05 23:54:30 +02:00
0be2660313 Mantaflow: Updates to variable names in smoke domain settings
Unused padding variables now use underscore in variable name
2019-04-05 23:54:06 +02:00
e001c3d534 Merge branch 'rnaSmoke' into smokeTypes 2019-04-05 23:48:07 +02:00
a261b850f1 Mantaflow: Minor update in smoke rna
Added const to return type to silence some warnings
2019-04-05 23:47:42 +02:00
a2abfcbfc1 Merge branch 'particleSystem' into rnaSmoke 2019-04-05 23:44:36 +02:00
4331add63b Mantaflow: Updated particle system to use newer flags and functions
Manta code in particle system needs to use updated flags as well
2019-04-05 23:42:12 +02:00
30a29660df Merge branch 'bakeConfig' into particleSystem 2019-04-05 23:37:30 +02:00
a71f1dec8f Mantaflow: Updated manta bake job setup
Bake jobs now lock the UI completely
2019-04-05 23:34:42 +02:00
319ce72c3a Merge branch 'sourceUpdate' into bakeConfig 2019-04-05 23:23:28 +02:00
9d40d0ad2e Mantaflow: Smaller update for draw engine code
Mainly adjusted some flags to work with manta
2019-04-05 23:22:53 +02:00
305bedc9d1 Merge branch 'internUpdate' into sourceUpdate 2019-04-05 23:18:32 +02:00
f9a7a90557 Merge branch 'buildConfig' into internUpdate 2019-04-05 23:17:05 +02:00
9159d9bebc Merge branch 'pythonScripts' into buildConfig 2019-04-05 23:04:56 +02:00
f75704033c Mantaflow: Updated fluid UI to handle locked UI during bake
Since bake locks the UI it needs to show a hint on how to pause / cancel the bake job
2019-04-05 23:04:09 +02:00
7ad431ff0a Merge branch 'mantaWrapper' into pythonScripts 2019-04-05 23:01:34 +02:00
c3ba70bbae Mantaflow: Updated fluid wrapper and script files
Includes setup in which inflow is applied on mantaflow side
2019-04-05 22:59:43 +02:00
9eeaf30357 Merge branch 'mantaFiles' into mantaWrapper 2019-04-05 21:45:46 +02:00
dc70424faa Mantaflow: Updated manta preprocessed files
New pp files with updated init plugin
2019-04-05 21:38:12 +02:00
f701c6344d Merge branch 'smokeTypes' into smokeC 2019-03-26 21:05:16 +01:00
f33519945c Merge branch 'rnaSmoke' into smokeTypes 2019-03-26 20:44:00 +01:00
a38c14aecb Merge branch 'particleSystem' into rnaSmoke 2019-03-26 20:04:36 +01:00
27b26f6b1c Merge branch 'bakeConfig' into particleSystem 2019-03-26 19:19:22 +01:00
287b26f910 Merge branch 'sourceUpdate' into bakeConfig 2019-03-26 18:56:23 +01:00
e4cd623fef Merge branch 'internUpdate' into sourceUpdate 2019-03-26 17:47:15 +01:00
a8a9f6aae1 Merge branch 'buildConfig' into internUpdate 2019-03-26 15:46:58 +01:00
e9ee13d4d6 Merge branch 'pythonScripts' into buildConfig 2019-03-26 15:29:28 +01:00
2457cfdfb6 Merge branch 'mantaWrapper' into pythonScripts 2019-03-26 15:22:26 +01:00
e9413e9ec6 Merge branch 'mantaFiles' into mantaWrapper 2019-03-26 13:23:37 +01:00
a1ef8a2cea Merge branch 'master' into mantaFiles 2019-03-26 12:56:46 +01:00
0f3da2016d Mantaflow: Update for new outflow flag
Trigger outflow object allocation when active outflow objects present in scene
2018-11-08 22:33:01 +01:00
8ad5665ee6 Mantaflow: Updated entire smoke.c code
Big customizations to make old smoke.c work with smoke and liquids
2018-11-08 22:33:01 +01:00
06fd308103 Mantaflow: Updated types for outflow
Added new flag for active outflow
2018-11-08 22:32:52 +01:00
85e757257e Mantaflow: Updated fluid modifier settings
Updated fields for domain, flow and effector settings
2018-11-08 22:32:52 +01:00
1c6da92b1a Mantaflow: Updated rna smoke code
Necessary updates for new fluid parameters
2018-11-08 22:32:41 +01:00
350df53d29 Mantaflow: Updated particle system
Bug fix for display amount field and refactoring in general
2018-11-08 22:32:25 +01:00
2933b9c895 Mantaflow: Customization for particle system
Added functionality to read mantaflow particle systems (FLIP + secondary)
2018-11-08 22:32:25 +01:00
4ddf0b6812 Mantaflow: Added bake configuration
Handles entire baking setup
2018-11-08 22:32:13 +01:00
f3fa0fb9b1 Mantaflow: Updates in /blender/source
A collection of smaller changes in the C files
2018-11-08 22:31:54 +01:00
ed417d796b Mantaflow: Update other /intern packages
Disabled old smoke code and added new speed vector code to cycles
2018-11-08 22:31:42 +01:00
3e11933329 Mantaflow: Adapted build config
CMake configuration update and macros for mantaflow
2018-11-08 22:31:30 +01:00
60e5963baf Mantaflow: Updated particle and fluid modifier UI
Made path field accessible after bake and removed obsolete UI text in particle settings
2018-11-08 22:31:18 +01:00
8da87f1eb0 Mantaflow: Customized UI for Manta fluids
Single UI for smoke and liquid
2018-11-08 22:31:18 +01:00
8a498582b3 Mantaflow: Refactoring for smoke outflow
Now setting outflow every frame, allowing walls to be keyframed
2018-11-08 22:28:16 +01:00
a1a1d4300e Mantaflow: Improved allocation of fluid outflow objects
Similarly to flow and obstacle objects, the outflow grid now only gets allocated when outflow objects are actually present. Commit also includes improved vector (mesh, particles) cleanup (fixes issue with particles being visible although domain is empty in simulation).
2018-11-06 15:24:04 +01:00
2b3ada655a Mantaflow: Added fluid wrapper files
Wrapper files manage communication between /source/blender C code and Mantaflow Cpp/Python code (preprocessed files)
2018-11-06 15:17:42 +01:00
cc802e66d7 Mantaflow: Updated Manta pp files
includes critical fix for outflow at domain borders and fixes crash when using secondary particles with open domain borders
2018-11-06 14:22:12 +01:00
792eb57e62 Mantaflow: Added preprocessed Mantaflow source files
Preprocessed files for both OpenMP and TBB
2018-10-28 14:47:51 +01:00
c29ce9bafa fix for particle UI and mesh name update 2018-08-27 16:15:30 +02:00
61e194757b improved cache directory handling 2018-08-24 00:25:27 +02:00
7b648f2b4c secondary particle naming update 2018-08-24 00:24:01 +02:00
a7db0defc8 updated some default values 2018-08-14 13:39:03 +02:00
50e8022ffb cleanups and fix missing rename in alembic exporter 2018-08-13 16:04:23 +02:00
ac8ed6555a removed obsolete imports in fluid ui 2018-08-11 23:48:07 +02:00
627740da7a fixed issue with addons submodule commit pointer 2018-08-11 23:20:14 +02:00
6271f052b8 Merge branch 'master' into fluid-mantaflow 2018-08-11 22:47:24 +02:00
af010fe4b9 another UI cleanup 2018-08-11 22:47:17 +02:00
1dc196391b Merge branch 'fluid-mantaflow' of https://git.blender.org/blender into fluid-mantaflow 2018-08-11 22:43:20 +02:00
59015857e8 Merge commit '1f33075ef043f0281c69a261c53eda0ce8334cbe' into fluid-mantaflow 2018-08-11 22:25:51 +02:00
461e2cfc40 post merge fixes and cleanups 2018-08-11 17:19:41 +02:00
74b435c32c Merge branch 'master' into fluid-mantaflow 2018-08-11 15:10:33 +02:00
ac5d656a27 janitorial services for 2.8
cleanups, cleanups, cleanups
2018-08-11 15:01:37 +02:00
b1ee77d2d6 fix for odd python assertion error
error was appearing when closing blender
2018-08-04 13:54:06 +02:00
57113144a5 manta script export refactor and lots of cleanups 2018-08-03 23:24:06 +02:00
1095680c28 Merge branch 'master' into fluid-mantaflow 2018-08-03 15:08:39 +02:00
0dd35a7e85 minor cleanups 2018-08-03 11:01:22 +02:00
4aa6d74ae4 minor cleanup and fix memory leak (resulted from active fields commit) 2018-08-03 00:07:28 +02:00
e9dfc5c167 improved cache resume functionality
it is now possible to resume an already completed bake
2018-08-02 17:44:22 +02:00
7b0ffd69e0 fix for active fields (cache read)
new cache does not save active fields, e.g. fire. so for now, just
reload them during cache read step
2018-08-02 13:27:54 +02:00
1667a76172 fix in python cleanup function
new motion blur vertvel vector was not being deleted. clearing all dicts before deletion now.
2018-08-02 01:46:55 +02:00
150b57c7f9 fix for particle system crash 2018-08-01 17:44:16 +02:00
801bbb7427 fixes for motion blur support
- added missing velocity interpolation. vertvel vector now pulls data
from interpolated vel grid (needed especially when using different
solver sizes)
- added missing cleanup calls on the python end (i.e. delete new python
motion blur objects too)
2018-08-01 00:12:42 +02:00
55e94f7008 Merge branch 'master' into fluid-mantaflow 2018-07-30 17:24:37 +02:00
80c53eb3cf small fixes for manta script export 2018-07-30 16:15:37 +02:00
5ccc748f41 added initial support for motion blur (cycles) 2018-07-29 18:23:30 +02:00
32b1ea9771 updated fluid guiding mode
mode now set by guiding object (and not by domain object). i.e. guide mode setting now only affects cells from guiding object
2018-07-29 18:01:20 +02:00
0df08c66c1 fix for smoke guiding and some cleanup 2018-07-13 10:27:41 +02:00
dd075f267c added guiding object velocity factor (UI option) 2018-07-11 16:49:20 +02:00
070d9da1e8 improvements to keyframe parameters 2018-07-11 00:24:04 +02:00
ca7431c483 more sanity checks for fluid guiding 2018-07-10 23:18:56 +02:00
fc31bd2950 fluid guiding overhaul
- fluid guiding now has a separate cache. velocities from guiding
objects can be baked into this cache
- alternatively, another another (baked) fluid domain can be set as the
parent. its velocities will then used for the guiding effect (e.g. use
smoke sim to guide liquid sim)
- minor other updates: refactored manta-script exporter, fixed liquid
leak (fractions completely disabled now), naming cleanups, fix for
smoke resume bake (was missing velocity reload)
2018-07-07 15:56:39 +02:00
ebaa0f0055 Merge branch 'master' into fluid-mantaflow 2018-06-12 13:50:58 +02:00
1be28f9ba8 UI and workflow optimizations
leave UI enabled when bake is paused, reset scene frame before scene update
2018-05-15 15:13:18 +02:00
ed35ac426e fix for inflow with subframes/adaptive time steps 2018-05-14 15:22:18 +02:00
86b1274665 refactored liquid script setup 2018-05-14 15:17:21 +02:00
a5158499fe small cleanup and refactor 2018-05-10 21:34:35 +02:00
2b541854b5 fix for windows path issue
escape slashes in python calls
2018-05-10 20:16:49 +02:00
cfc9ad3ebd added sanity check before bake free call 2018-05-10 16:45:54 +02:00
1ddcbac9a0 added some sanity checks to prevent illegal cache access 2018-05-08 02:06:43 +02:00
fc6981e979 improvement for cache pause/resume functionality
bake now resumes correctly even if current scene is changed in between
2018-05-08 01:34:20 +02:00
b5fa065165 enabled raw mesh pointer normalization 2018-05-07 19:00:31 +02:00
d1858148e6 added pause/resume bake functionality
works for all bake types (data, noise, mesh, particles)
2018-05-07 17:29:58 +02:00
879b71e179 minor secondary particle fixes
fixes immediate bake crash and missing tracers
2018-05-07 17:27:11 +02:00
7d1c73f5ba legacy code cleanup
mostly from manta script export (which needs to be refactored later) and from pointcache (which needs to go altogether)
2018-05-07 12:20:58 +02:00
adbca18ea8 improved data save/load setup and added cancel bake operator 2018-05-07 11:27:12 +02:00
b724ceba4c small openvdb fix
happened because of previous merge commit
2018-05-06 00:00:27 +02:00
ee590724ac disable mesh and fluid noise toggle during bake 2018-05-05 23:55:55 +02:00
1d9bb5d7b0 Merge branch 'master' into fluid-mantaflow 2018-05-05 23:14:14 +02:00
3960e05c37 bigger cleanup and added direct manta mesh pointer access 2018-05-05 21:23:41 +02:00
aef00c38c3 small UI update 2018-05-04 17:26:04 +02:00
d1f5551bde preparations for liquid real time updates during bake 2018-05-02 16:43:39 +02:00
8a4864be2f make FLIP particle system toggle available even after bake 2018-05-02 12:24:03 +02:00
04e9b3ff01 fix for particle file extension 2018-05-02 11:22:26 +02:00
3718200a22 added support for obj mesh caching 2018-05-02 00:47:45 +02:00
32e89737d7 more mesh improvements
added more smoothening settings and a preview/final mesh switch
2018-05-01 23:41:22 +02:00
41109f4f0f improved cache formats
now supporting openvdb and others - manta handles file IO
2018-05-01 19:33:06 +02:00
e42f589a92 use improved particle levelset function 2018-04-30 16:48:26 +02:00
987745e440 updated manta pp files 2018-04-30 16:47:28 +02:00
9378430cfa big refactor for data, mesh, particles separation
replaced high res options with factor, particles and mesh now have separate solver, placed bake buttons in corresponding tabs in UI, fixed high res mesh
2018-04-30 14:56:32 +02:00
b122c5ad06 fix smoke / manta rename in quick effects 2018-04-02 16:05:20 +02:00
77e3cacc79 fix smoke / manta rename in UI 2018-04-02 15:41:01 +02:00
39c8edad54 replaced WITH_SMOKE macro with WITH_MANTA in entire project
for a mantaflow build, one now only has to enable the WITH_MANTA macro
2018-04-02 15:21:29 +02:00
91233bda02 clean up and fixed some warnings
fixes broken linux build
2018-04-02 14:52:01 +02:00
a260fd1542 minor stability improvements for new adaptive inflow setup 2018-04-01 23:25:32 +02:00
86c49311a4 updated adaptive time stepping
moved adaptive stepping loop out of manta simulation (python) and into big step (update flows + update obstacles + manta simulation) (blender c)
2018-03-31 17:54:45 +02:00
384ec9dfc8 just cleanup and minor bug fixes 2018-03-26 21:14:30 +02:00
7d4c961dde get wavelet noise params at every frame (animatable) 2018-03-25 14:22:26 +02:00
2a6a579b06 support for animated properties in new decoupled baking setup 2018-03-25 13:52:09 +02:00
d141e55237 big cleanup in FLUID.cpp
removed global python params vector. now using local vectors.
2018-03-24 22:45:13 +01:00
449306bbaf fix for multiple domains and different flow objects in scene 2018-03-24 17:48:39 +01:00
646f9e3f15 more updates for decoupled baking - initial support for smoke 2018-03-24 14:48:22 +01:00
87b5b49879 cleanup and made multiprocessing only available for unix
before adding multiprocessing for windows see if it is worth the effort
2018-03-21 16:22:26 +01:00
d7161fc3f1 more changes for decoupled fluid cache
liquid support finished, smoke and stability todo
2018-03-19 13:48:23 +01:00
293a67cacf fix warning for cache read function 2018-03-13 16:32:31 +01:00
ac0d74cb6d cleanup in pointcache.c 2018-03-13 16:17:16 +01:00
2c4b5e6207 added first version of decoupled cache - breaks compatibility, blender not fully working right now 2018-03-13 13:57:44 +01:00
908dbedff3 fix legacy wturbulence
windows will not compile with issue - only warning on linux
2018-03-03 15:35:16 +01:00
218c012925 post merge compiling fixes 2018-02-24 00:25:03 +01:00
edd75f7e17 Merge branch 'master' into fluid-mantaflow 2018-02-23 23:39:20 +01:00
8c71781683 cleanup before master merge 2018-02-23 23:26:52 +01:00
8b46cf45f7 refactored python object desctruction setup
no need to specify individual variables anymore - deletion now based on id
2017-12-15 16:27:45 +01:00
4de0c06708 updated manta pp files 2017-12-15 16:23:11 +01:00
359f29f373 small fix in cache for pointcache and openvdb 2017-12-08 14:57:14 +01:00
8fa642db3d reactivated smoke adaptive domain settings 2017-12-06 22:21:56 +01:00
b88e77517f some cleanup and simplifications 2017-12-05 18:19:36 +01:00
f2b5dd6ecd cleanup alphaV viscosity 2017-12-03 12:24:39 +01:00
b37472c4e7 added missing preset scripts to git repo 2017-12-02 16:56:06 +01:00
e6ddb4bb1c fix for liquid surface distance and some UI updates 2017-12-02 16:54:43 +01:00
56f7df0b94 moved smoke advection to the end of simulation step
otherwise moving obstacles are in trouble, ie always one step behind
2017-12-02 16:53:58 +01:00
bc6ab0f077 updated viscosity settings
reusing viscosity UI from elbeem fluid
2017-12-02 16:13:20 +01:00
07c02b0462 cleanup debug output and also added some sanity type conversions 2017-12-02 12:52:32 +01:00
8ea0a8cbc6 fix for particle caching and also added more sanity checks in particle getters 2017-12-01 16:35:12 +01:00
da5e513c42 cleanup in smoke script 2017-11-30 23:25:04 +01:00
22e5ed2053 Merge branch 'master' into fluid-mantaflow 2017-11-29 17:11:59 +01:00
02b271947e added settings for fluid diffusion (i.e. viscosity and surface tension) 2017-11-29 16:28:37 +01:00
6976df8346 added support for updated manta fire burn function 2017-11-29 16:26:18 +01:00
b6cc2d4dcf updated manta pp files 2017-11-29 16:25:26 +01:00
d1abec2026 use particle size from particle settings UI for manta particles 2017-11-29 15:27:42 +01:00
3ed9864aa4 changed particle lifetime from int to float 2017-11-29 15:01:34 +01:00
a769db448c activated viscosity and surface tension settings for liquids 2017-11-28 12:49:22 +01:00
4d56dc8de7 refactored setup for liquid on first frame again 2017-11-28 12:46:51 +01:00
af86b91cac small fix for inflow levelset
clear after initial frame to avoid sampling snd parts twice
2017-11-27 11:09:45 +01:00
acee60cc58 updated manta pp files 2017-11-27 11:01:03 +01:00
69afb0b6f6 updated caching (now using frame 1 for liquids as well) and also added new snd particle parameters 2017-11-26 17:22:19 +01:00
9f1b5cce63 cleanup: removed unused secondary particle type vector 2017-11-25 11:24:20 +01:00
c131e0059c fix for levelset generation
bad array init prevented outer levelset region from being set correctly
2017-11-19 18:51:29 +01:00
6a454f10ff removed deleteInObstacle option
need to see if this fixes the liquid mass instability issue
2017-11-19 18:50:11 +01:00
b668b186d7 fix for alembic particle exporter
added missing type checks for manta particle systems
2017-11-13 20:52:56 +01:00
e70c28e484 fix for alembic mesh exporter
liquids and smoke can both be of domain type. checking for smoke domain needed to be more specific, i.e. now checking domain type as well.
2017-11-13 19:45:34 +01:00
ef8a137d8a fix for particle and mesh scaling 2017-11-11 13:07:44 +01:00
91ef5780c9 re-enabled bubble rise factor and some small snd particles fixes 2017-11-11 13:07:44 +01:00
09d2c464dd obvel velocity fix, disabling surface tension and viscosity for now, set do not delete flip in obstacle 2017-11-08 14:31:27 +01:00
bd269c8caf updates for new manta pp files, also added first setup for viscosity and surface tension 2017-11-01 19:55:38 +01:00
255485d2b9 added missing ray normalization in levelset generation call 2017-11-01 12:38:39 +01:00
dbc97a5cff updated manta pp files 2017-11-01 12:37:31 +01:00
b920cc6bb3 openvdb changes for manta support
customization for obstacle grid to match mantaflow flags grid
2017-10-24 21:42:41 +02:00
f149896761 changes for quick smoke cycles node setup and minor bug fixes
with quick smoke, the cycles setup for fire was unreachable (why?) -> removed the if-clause. also fixed minor bugs (UI Quick Liquid, copy settings for effector object)
2017-10-24 19:46:25 +02:00
fcc131d237 Merge branch 'master' into fluid-mantaflow 2017-10-14 12:54:36 +02:00
90413d600e fix for particle count in UI
was missing count reset
2017-10-09 00:00:00 +02:00
90ec9b4026 disabling fractions and enabling moving obstacles again
fractions do not support moving obstacles right now. also, fractions combined with obstacles results in particle leak (likely because of inaccuracies at fluid/obs border when repeatedly subtracting from phi grid - sdf not preserved)
2017-10-06 13:21:38 +02:00
c1fb55b44b big fluid particles update
- refactored original snd particle functions on mantaflow side
- bug fixes for particle reading (fixes disappearing issue when using
various ptypes at once)
- added support (esp. in caching) for future particle life vector (on
mantaflow it's side already in use. todo: copy values to blender
particle systems)
- memory optimization: only allocate particle fields when they're
actually enabled in UI
- fixed standalone script export (snd particle system, pdata fields)
2017-10-03 14:08:58 +02:00
949316d0a7 fluid particles UI update 2017-09-27 14:55:17 +02:00
8e38037be2 cleanup for adaptive time stepping
especially the timestep was too big and resulted in adaptive steps when adaptive stepping was actually disabled.
2017-09-27 14:39:06 +02:00
519a9e04a4 general cleanup 2017-09-22 14:37:39 +02:00
5d0370e8c5 fix for initial velocities
added sanity check that clears any left over velocities
2017-09-21 01:57:31 +02:00
373d96e3db fix for liquid velocity bug
now explicitly setting initial velocity in inflow region. this solves the problem where liquid inflow becomes unstable over time. it also allows you to use liquid plane objects with initial velocity (similar to smoke). for proper liquid initial velocities a volume initialization is needed though (todo).
2017-09-19 14:23:26 +02:00
4e7edefe08 Merge branch 'master' into fluid-mantaflow 2017-09-19 01:11:31 +02:00
e9624e1f7b Merge commit '68596950550d' into fluid-mantaflow 2017-09-04 22:15:05 +02:00
3097c05262 various smaller fixes / cleanup for obstacles and guiding 2017-09-04 01:11:19 +02:00
fca7d66a3f improved initial velocity setup for smoke and liquids
initial velocity grids now only allocated if actually enabled in UI. rudimentary support for liquid initial velocity when using plane inflow objects, proper liquid initial velocities (set invels in full volume) still todo though.
2017-09-03 02:23:38 +02:00
613cc715fa flow source UI updates 2017-09-02 22:59:33 +02:00
e47fdf4b05 improved fluid obstacle / guide surface distance value
preserves levelset inside flow objects
2017-09-02 22:55:48 +02:00
544d8fe9b5 cleanup in manta script exporter 2017-09-02 15:40:16 +02:00
afc9c2ddcb added surface thickness option for effector objects (i.e. obstacle or guide objects) 2017-08-31 17:07:41 +02:00
00c5ddd9d7 obstacle grid optimization
now only allocating obstacle grids when there actually is an obstacle object present
2017-08-28 13:05:13 +02:00
397c4208a5 added support for liquid guiding
guiding liquid simulations is currently considered experimental though
2017-08-27 01:39:09 +02:00
e486b84b33 cleanup for smoke preconditioner (multi-grid)
better way to set preconditioner flag in dynamic scenes (scenes with moving obstacle)
2017-08-26 22:35:39 +02:00
79ea5f6324 added guiding parameters to UI
alpha and beta parameters are used to control lag and size of fluid guiding
2017-08-25 12:32:45 +02:00
11ea224ac5 updated manta pp files
various tweaks that are not in the official mantaflow branch - need to merge them there later
2017-08-23 18:18:58 +02:00
d39b661722 various fluid guiding improvements
the domain settings for fluid guiding are gone now. guiding objects handle settings individually, guiding functions kick in automatically if there is a guiding object present.
2017-08-21 11:47:33 +02:00
b3ed9257aa fix for levelset generation
fixes problem with multiple collision / guiding objects. levelset was overwritten incorrectly.
2017-08-18 17:52:46 +02:00
75482e3169 added options for fluid guiding
Collision settings are now effector settings. In there an object can be of type collision or guiding.
2017-08-17 19:57:15 +02:00
0baa089467 name cleanup for levelset grids 2017-08-12 17:33:29 +02:00
39eb8fa1a6 new method for levelset generation from mesh
now considering planes as well
2017-08-09 17:35:38 +02:00
1a914c0c06 added missing openmp files for guiding 2017-08-05 07:43:56 +02:00
d18ae102f3 added minimal guiding UI controls
minimal controls = toggle guiding and set tornado velocity strength
2017-08-04 23:08:06 +02:00
1b80047d1c first working fluid guiding setup in smoke script 2017-08-02 00:43:15 +02:00
1f314b9ea5 adapted spiral velocity getter from mantaflow
now possible to get 3D instead of just 2D target vel grid (useful for tornado effect)
2017-08-01 20:16:57 +02:00
0c4e3fd968 eventually convert bubble snd parts to floats 2017-07-28 21:33:05 +02:00
9019d66b6a added control fields for float and tracer particle amount
float / tracer particle amount now determined by probability
2017-07-24 17:36:28 +02:00
cb9fb1c9fc committing unfinished liquid inflow velocity code
everything commented out, needs some more consideration
2017-07-28 22:11:58 +02:00
3bdfb5f982 made textual descriptions of new min max particle fields a bit clearer 2017-07-23 19:23:22 +02:00
e6a43693f4 added UI fields to control FLIP particle amount
also cleaned up the UI a bit
2017-07-23 14:52:41 +02:00
adf1db3969 added missing manta omp files
correspond to previous manta files update
2017-07-21 20:46:32 +02:00
25170baeab updated manta pp files
fix for outflow flag at outermost cell: now overriding with obstacle is possible, PFLOAT name change in mantaflow
2017-07-21 16:16:37 +02:00
a1a0e9efef initial tracer particle support 2017-07-20 22:56:31 +02:00
f22f84ea32 fix for particle float type define
PFLOAT name collided with PFLOAT from windows header
2017-07-20 22:48:24 +02:00
d724a45092 added bubble control to UI
control how much gravity affects bubbles, i.e. control how fast they rise
2017-07-19 00:41:37 +02:00
697df3a368 Merge branch 'master' into fluid-mantaflow 2017-07-18 18:50:16 +02:00
d9ba9993d8 added setup for bubble particles
blender internal particle setup (not manta side), i.e. UI, particle system creation / deletion, particle IO.
2017-07-18 10:27:51 +02:00
44f49e765b updated manta pp files
added drop and float particle support. also improved drop particle generation.
2017-07-17 21:58:26 +02:00
766572cd0a outflow cleanup in liquid script
now using initDomain() to set outflow cells
2017-07-14 20:45:41 +02:00
6ed2fe0229 added settings for snd particle type vector
this extra vector stores snd particle types: drop, float, bubble, tracer
2017-07-12 22:09:21 +02:00
354b496972 added float and tracer particle flags 2017-07-11 23:38:27 +02:00
feda06e184 updated manta pp files 2017-07-11 23:14:23 +02:00
3ee4f50995 update for smoke domain boundaries
using phiout levelset for smoke outflow
2017-07-11 19:09:34 +02:00
8379725171 fix for liquid domain boundaries
cells next to domain walls are used for fractions. if outflow is enabled these should get set to outflow cells and not fluid cells (were set to fluid and liquid didnt leave domain)
2017-07-11 18:21:28 +02:00
166c3db1e7 added support for smoke initial velocity 2017-07-07 20:03:15 +02:00
0f25e77920 more flexible particle threshold velocity 2017-07-06 22:37:52 +02:00
97ee6ac8b9 improved particle setup sanity checks and fixed object drawtype setup (when parts enabled switch to wireframe, otherwise solid) 2017-07-06 11:14:00 +02:00
47056f2b3a refactoring in rna particle setup
made particle system creation / deletion more modular. this will be helpful when adding floats and tracer particles.
2017-07-05 19:13:37 +02:00
d12bb24d38 Merge branch 'master' into fluid-mantaflow 2017-07-03 19:53:25 +02:00
6b3c3ad5b0 UI fix: disable snd parts threshold field when cache is baked 2017-07-03 19:44:20 +02:00
e3d1f6b984 cleanup in particle UI
particle UI for automatically generated systems was offering too many settings. now (similarly to elbeem) only restricted access
2017-07-02 19:16:03 +02:00
93d31ac344 improved pointcache and now also supporting FLIP visualization again 2017-07-02 19:13:59 +02:00
72311c6357 more improvements for particle caching with pointcache 2017-07-01 13:59:38 +02:00
a9992eaaab first support for ptcache files for liquids 2017-06-30 23:17:45 +02:00
03742faf43 added guards in pointcache read/write functions
if we want to use ptcache format for liquids, first make sure not to access smoke fields.
2017-06-29 14:42:33 +02:00
273cf1f65c cleanup in FLUID class 2017-06-27 20:23:09 +02:00
29553c0684 replaced particle dim getter with domain dim getter 2017-06-26 23:46:11 +02:00
9b7d06b255 added particle UI tab 2017-06-26 21:20:50 +02:00
67df724a1f added particle data pointer getter to mantaflow files 2017-06-25 17:37:04 +02:00
1bdf2152e1 added first version of secondary particle function to mantaflow files
liquid script now also has additional particle system (for all secondary particles)
2017-06-24 19:55:49 +02:00
60600dd36e updated manta obstacle velocity
some more improvements to obstacle velocities in mantaflow. now manta only accepts mac grids. any resampling from vec3 to mac needs to be done before calling wall function.
2017-06-24 18:52:41 +02:00
672caef66f big cleanup for manta directives
very early in the project these directives where set to preserve the functionality of the original smoke code. keeping up this dual compatibility would be an overkill for this branch.
2017-06-24 16:22:58 +02:00
3c516cac3c disabling liquid obstacle velocities for now
need fractions support for obvels first
2017-06-22 22:45:18 +02:00
9cde58c214 Fix T51837: Added num particles sanity check when reading particle files. Also fixed num particles field for pVel files 2017-06-21 23:17:34 +02:00
c0c3ebf115 small name fix for maxvel variable
name did not match variable name that gets deleted
2017-06-20 00:39:51 +02:00
b203980733 refactored obstacle velocities 2017-06-19 19:27:44 +02:00
231f75aab2 applied some fixes that automatic analyze tool suggested 2017-06-17 23:56:48 +02:00
443d567234 added particle velocity scaling 2017-06-16 11:13:00 +02:00
b20f9b3ff5 automated some UI selections
now smoke domains set volume cache automatically, liquid domains set surface cache automatically
2017-06-15 13:50:31 +02:00
a8ac44e74f setting solver res here is obsolete
no need to set this explicitly. solver only threw expection when loading blend files created with vanilla blender. versioning support will handle this in the future.
2017-06-14 21:28:41 +02:00
e3850739a0 added support for particle velocities
now saving and loading particle velocities from uni files
2017-06-14 21:12:51 +02:00
ae8f0385c5 implemented new caching approach
caching is now divided into two parts: surface and volume caching. the reasooning behind this is that for some setups (e.g. liquid + particles) there needs to be a way to cache both the mesh (surface caching) and particles (volumetric caching). Also, smoke scenes might use meshes in the future (e.g. vortex sheets)
2017-06-14 15:59:57 +02:00
dfb1d7f1bd refactored new option for particles and mesh 2017-06-13 14:56:54 +02:00
8a79adcaf7 implemented viewport display switcher for liquids
previously the viewport switcher only worked for smoke. only drawback is now that toggling the viewport switcher resets the cache(probably because of recalculating liquid mesh). baked caches however stay. issue remains a todo.
2017-06-13 14:47:31 +02:00
a3efe48987 added cfl field to UI
adjustable cfl number lets users better control timesteps
2017-06-12 23:13:59 +02:00
16c8f46a31 added particle instance variable initialization and cleaned up a bit 2017-06-12 22:38:23 +02:00
f686625d8b added new cache option that supports mesh and FLIP particle export 2017-06-12 17:48:25 +02:00
74ff9c1036 fix for particle system sanity check
sanity was a little to late. needs to be before any file reading (getter) operation
2017-06-11 14:37:19 +02:00
a281ef6a98 automatically set domain mesh draw type for particles and mesh mode
for particles it is more convenient to have a wire frame, for meshes the solid mode is better
2017-06-11 13:58:47 +02:00
8b7a20de97 added narrow band field to UI
being able to control the particle band width is useful when working with the FLIP particle cache. with a higher band width you can fill up the entire fluid volume with particles
2017-06-11 01:45:14 +02:00
6f67dc1080 fix for required shift when domains moves
when domain moves away from position it was originally simulated it, a shift needs to be added to the particle coords. the was opposite to what is needed.
2017-06-10 10:57:54 +02:00
0ca08748b8 set manta particle radius in particle system as well 2017-06-10 10:55:08 +02:00
8f2ffc1b1c fix for preconditioner and closed domains
closed domains require zero pressure fixing enabled for the preconditioner to work
2017-06-10 00:51:12 +02:00
aab52d938f fixed domain border collision key mapping
textual descriptions of borders did not match blender views
2017-06-09 22:40:19 +02:00
c410bb71f2 filter out dead particles
mantaflow stores dead particles for internal purposes. in blender we just skip them, they dont need to be shown in the UI
2017-06-09 21:16:24 +02:00
bdd845c42d improved manta particle step function
function now scales, translates particle data properly
2017-06-09 00:40:14 +02:00
e9e41421a6 added function in smoke rna to register FLIP particle system
when flip particle file format is toggled, a new particle gets registered. toggling meshes releases the particle system
2017-06-08 23:38:11 +02:00
35c99918f4 added api to read fluid domain dimension from particle file 2017-06-07 02:40:18 +02:00
152e58dff1 renamed debug level flag
flag was conflicting in debug mode
2017-06-06 15:19:45 +02:00
0a4750a658 replaced border collisions menu in UI with boolean flags
Setting domain borders should not be determined by a few textual descriptions. Rather, users should be able to set any combination of borders.
2017-06-05 16:33:47 +02:00
a45e818dc8 adjusted boundary width for set obstacle velocities
boundary width was one cell too big. in some cases with moving obstacles, particles would just stay next to wall.
2017-06-05 16:23:28 +02:00
1c1e99363d improvements to the pointcache
fixed a problem where caching would not resume after restarting the simulation. also, cache file names are now a bit nicer
2017-06-04 22:05:43 +02:00
50e351e6e0 added debug flag to control console output
console output had gotten to a point where it slowed down the simulation
2017-06-03 02:51:01 +02:00
5468cf836e added function to handle particle reading inside particle system c code 2017-06-02 22:37:20 +02:00
9cb43962a7 added c/c++ api functions and extended caching to account for particles 2017-06-02 22:36:18 +02:00
8810490a2c added particle file reader function
reading from .uni files. this function is an adapted version of the load() function for particles in Mantaflow
2017-06-01 23:30:54 +02:00
3a41fc953a cleaned up some weird spaces 2017-05-31 22:47:12 +02:00
e066521fa3 fix missing classes in python scripts
post merge cleanup
2017-05-30 00:36:19 +02:00
96cf0cc946 Merge branch 'master' into fluid-mantaflow 2017-05-29 23:02:34 +02:00
fd09c48c3d removed optional border velocities for obstacles
having just the velocities inside the obstacle seems sufficient for now (visually)
2017-05-27 22:41:13 +02:00
c0a7082fb9 improved setObstacleVelocity() function
now checking if obvel present before interpolating. also added some sanity checks
2017-05-24 22:31:57 +02:00
51c05767d2 set obstacle velocity after every setWallBcs()
if not set, the essential obstacle velocities will get overwritten with 0
2017-05-12 20:00:45 +02:00
fb7b154acc improved liquid inflow / generating phi grid
phiObs has to be subtracted from phi and not just from phiIn. otherwise when joining phi and phiIn, some obstacle areas in phi are not set to positive value, stay negative and hence show up as liquid
2017-05-03 19:24:16 +02:00
de9c1e02fc small fix for phi grid reset 2017-04-20 16:09:56 +02:00
cc3dbb5196 disabling fractions in liquid for now
can be enabled again once setObstacleVelocity() supports them
2017-04-18 00:45:04 +02:00
a4b48c95d9 interpolating phi later in step
interpolation needs to come later to avoid weird mesh resizing in first frames (occurred between frame 1 and 2)
2017-04-14 00:36:29 +02:00
1797850eee use larger surface distance value so that obvels cover larger area. manta can then better extrpolate those obvels 2017-04-13 19:11:42 +02:00
de7a71915b small fix for frame number: manta starts on frame 0, not on 1 2017-04-11 13:50:23 +02:00
d519e28f58 save and load obstacle velocities (for standalone mode) 2017-04-05 13:43:10 +02:00
45369cb1f0 added cleanup routine in destructor for multigrid 2017-04-03 01:03:33 +02:00
c8df09ab0d updated manta pp files 2017-04-02 21:18:28 +02:00
1e3f3565c3 removed dummy fractions grid from smoke script 2017-03-27 21:51:43 +02:00
5c1c489e5d updated manta pp files and adapted obstacle velocity setter in smoke/liquid script
important: boundaryWidth for liquids is 2 instead of default 1
2017-03-26 20:40:17 +02:00
a8901bc63e added adaptive time stepping option to ui 2017-03-26 20:38:26 +02:00
a7b5871ccf added support for liquid moving obstacles
using same obvel setter as in smoke script. fractions left out for now
2017-03-26 15:26:12 +02:00
4a813b78b0 removed high res clean up functions for liquid
in theory with correct obvels no need to clear phi inside obs. if still needed, then maybe do this later in blender c code
2017-03-26 15:24:00 +02:00
effbf4a4cb added guard for smoke/liquid sampling/distance functions
in smoke domains no need to get mesh distances, in liquid domains no need to calculate smoke influence factor
2017-03-25 13:04:51 +02:00
8561336e2a removed flow type guard and instead made FLUID destructor less restrictive
required if multiple domains in viewport. domains do not know what flow objects they have inside
2017-03-24 15:55:57 +01:00
ddeb4c5f58 fix for wrong framenr argument in step function 2017-03-24 15:51:20 +01:00
cb8424e14d improved raycasting for mesh distances again
also includes name and formatting cleanup
2017-03-23 12:01:52 +01:00
cbf3e40121 improved levelset calculation function
now using better estimates for min distance and also 14 instead of just 6 raydirs for raycasts (added 8 quadrant diagonals)
2017-03-22 14:27:42 +01:00
59b56db129 removed unused phi reset from obstacle update function 2017-03-21 15:08:04 +01:00
09465fef32 added ids to all grids, vars, funcs, etc in manta scripts
having unique python variables allows having multiple domains in the viewport at once
2017-03-20 20:13:09 +02:00
76c9289a03 split up fluid solver and helper variable setup 2017-03-19 02:04:10 +02:00
3b60dd8c46 fixed and cleaned up inflow grid
inflow grid is necessary when running manta script in mantaflow standalone mode
2017-03-18 19:10:37 +02:00
d3c6768daa added id member variable and cleaned up manta init function 2017-03-17 13:25:41 +02:00
a279388006 added preprocessing for destructor and init script strings 2017-03-17 01:17:26 +02:00
bb37d1d33b cleanup in manta C api
no need to pass smoke modifier data as argument anymore
2017-03-16 22:31:57 +02:00
2c46cadd18 cleanup in pointcache 2017-03-16 17:04:26 +02:00
8d52f85699 cleanup in blender python 2017-03-16 00:28:11 +02:00
ae4d6ea4a6 cleanup spectrum
spectrum files not need anymore - moved in master too
2017-03-15 23:55:27 +02:00
137c0355ab major automatization update for domain setup
depending on the domain type the appropriate settings for cache type, draw type and border collisions type are now set automatically
2017-03-15 23:45:34 +02:00
5cd5f9ec06 fix for combining emission maps
the function that combines the emission maps was not considering the mesh distance maps. hence, when using subframes for liquids, the values were not set and the emitter object had an incorrect shape.
2017-03-14 14:26:35 +01:00
821a6e75bc manual sanity clean up for preconditioner
necessary when changing grid size. internal grid has to be freed and reallocated to match new grid size
2017-03-14 01:13:04 +01:00
77ba932ec1 small fix for extrapolation function
distance argument was not int - was problematic with uneven divisions size
2017-03-13 23:04:10 +02:00
0d53e3fbd0 optimizations for liquid caching
liquid simulations now running without first saving to file
2017-03-12 23:13:37 +01:00
af8722d0d0 added tbb support for mantaflow
if openmp is not present or disabled we now use tbb manta pp files as a fallback to provide at least some acceleration
2017-03-11 15:50:01 +01:00
b57e38e9ab Merge branch 'master' into fluid-mantaflow 2017-03-10 23:04:26 +01:00
02bb2aa8c5 added multigrid preconditioner setup
dynamic and static obstacles are recognized and preconditioner is set accordingly
2017-03-03 17:33:26 +02:00
0199f41bc0 updated mantaflow pp files
new mantaflow files require cxx11 option because of new multigrid solver
2017-03-02 13:10:45 +02:00
74e07a644a extrapolate obvels outside of obstacle and set them afterwards with option for borderWidth 2017-02-28 02:34:14 +02:00
1ad5aef63a setting obstacle velocities
for now we're doing this before advection. TODO: check if maybe doing this after pressure solve as in original code
2017-02-28 02:33:29 +02:00
b612a7f7a8 obvels need scaling before manta can use them 2017-02-27 19:20:11 +02:00
86e3e95de6 reordered cleanup before and after smoke step 2017-02-26 15:44:23 +02:00
b1f72a09c1 small fix for manta function registration 2017-02-24 00:12:39 +02:00
59ccfbee87 new manta functions to handle moving obstacles
added function to set obstacle velocities at fl/obs border, cleanup for averageVel function (more general name and vec3 argument instead of mac)
2017-02-23 12:56:48 +02:00
71979c248f manta script cleanup 2017-02-21 01:04:23 +02:00
7711b72c83 updated manta vec3 extrapolation
now using inside mode as well - similar to extrapolateLsSimple()
2017-02-20 11:39:34 +02:00
fce0b2daad updated mesh distance function
now using raycast in inverted direction as well. if this is not done, there are cases with wrong phi grid (swapped inside and outside)
2017-02-19 10:31:42 +02:00
dadebe55c8 argument cleanup: no need to have cell_size in update mesh function
smoke_pos_to_cell() handles cell_size division
2017-02-17 14:33:56 +02:00
ce1ae77991 cleaned up headers 2016-12-29 12:13:35 +02:00
5bcd39da48 removed high res getter for flags grid 2016-12-04 18:12:39 +02:00
cf964047e1 moved forces to pre step function and now resetting inflow obstacle with 0.0 (instead of 0.5) 2016-12-02 23:07:41 +01:00
3656c02c92 improved inflow, outflow and implemented initial support for moving objects
- outflow objects may move now
- inflow routine in mantaflow script now inside adaptive time stepping
- flag grid is generated from phiobs. no more "hacks" that write bit
masks by hand

TODO:
- object velocities need to be set at borders
2016-12-01 13:19:53 +01:00
f4a69f192f no need to use two cells for border of smoke domain 2016-11-16 17:52:15 +02:00
5749df3f85 moved clean up and copy functions to pre/post step 2016-11-15 12:01:31 +02:00
037662d04b added pre and post step functions 2016-11-15 12:01:31 +02:00
ca73e57b2f removed obsolete high res grid access function 2016-11-12 02:33:15 +02:00
d28cb620dd added numObstacle grid in manta script and access functions 2016-11-12 02:31:04 +02:00
b7d857f22e added missing grids to liquid/smoke grid import/export and also cleaned up scripts a bit 2016-11-12 00:18:38 +02:00
e5ebf2e4fe new mantaflow functions which should replace some of the calls from smoke.c 2016-11-11 13:54:19 +02:00
f84a0752fa formatting and comment clean up 2016-11-11 13:10:11 +02:00
4221aa7119 refactored manta script export functions 2016-11-10 00:41:09 +02:00
8c39247db1 added obstacle access functions and cleaned up a bit 2016-11-09 22:09:47 +02:00
757cb5223d changed obstacle type to int to match manta flag grid type 2016-11-09 22:06:12 +02:00
5b3bf7acd9 updated liquid inflow function 2016-11-07 00:56:25 +01:00
37f0c4f572 cleaned up a bit in scripts and now using new readParticle() function instead of temp file hack 2016-11-04 19:38:45 +02:00
f7fb1cb2d8 updated manta pp files and simplified python api 2016-11-03 22:04:14 +02:00
2ef7da9d06 disabling velocity reset for now. reason: not only obstacle cell velocities are reset but also border cells 2016-11-02 00:41:02 +01:00
88537b758e reverting to old IO functions. changes from D2317 produce posixpath, mantaflow save() and load() require string though 2016-10-29 22:30:23 +02:00
47ac6aa864 Mantaflow: Fix typo in smoke_export_low script. 2016-10-29 13:26:29 -06:00
657259fbaa Mantaflow: Use Path objects instead of os.path.join()
File paths are passed into these functions, so convert passed path to pathlib.Path object to avoid internal/external conflicts. This should be easier to maintain and visually cleaner.

Reviewers: sebbas

Reviewed By: sebbas

Differential Revision: https://developer.blender.org/D2317
2016-10-26 20:37:57 +02:00
7eefa08cf8 Merge branch 'master' into fluid-mantaflow 2016-10-25 21:11:59 +02:00
0ccc7262f3 boundary width as variable and small clean up in liquid high-res step 2016-10-24 12:09:10 +02:00
2c05b7f8be clean up in cmake setup 2016-10-23 21:28:08 +02:00
831332dfbb small clean up 2016-10-23 16:14:14 +02:00
b1fdf48235 refactored manta liquid script 2016-10-23 16:14:14 +02:00
15aa698211 no need to rename main() from mantaflow - simply remove file from cmake and no main() method clash will occur 2016-10-23 16:14:14 +02:00
a04378301e forgot to revert my own version number changes for macos in CMakeLists - fixed that 2016-10-23 16:14:14 +02:00
395568ddae change path's to literal strings, to prevent escape issues with windows paths. 2016-10-20 13:00:55 -06:00
5db51d2119 updated manta files with linker fixes 2016-10-20 17:44:01 +02:00
338e0006a1 better inflow map generation 2016-10-17 21:02:35 +02:00
8ef9cff3a1 adapted draw routine to handle liquid domains better 2016-10-12 10:41:44 +02:00
92d1ebc7d2 fix for CMakeLists 2016-10-10 22:39:12 +02:00
9c7d8fea1b Merge branch 'master' into fluid-mantaflow 2016-10-09 00:53:18 +02:00
cd963e3824 small clean up (removed deprecated variable) 2016-10-08 22:52:54 +02:00
d4acb55f1d correct path parsing for smoke script 2016-10-07 00:49:12 +02:00
8fd32cdebf fixed temp directory for highres liquids (correct temp directory) 2016-10-06 23:01:55 +02:00
129b642521 better path parsing for python io calls 2016-10-05 09:12:34 +02:00
2ae461bfb1 small clean up. removed 'phi reset' which caused the mesh flickering 2016-10-04 14:52:10 +02:00
ca19521848 mesh normals were read in incorrectly. now using reverse order 2016-09-24 15:14:54 +02:00
4bc5700fc1 updated cmake lists to account for windows systems 2016-09-23 22:57:12 +02:00
0ba55c3c39 hooked up blender kernel code to work with obstacle adaptions in liquid script 2016-09-20 00:45:25 +02:00
5d44015a46 adapted manta liquid script to support obstacles 2016-09-19 19:32:19 +02:00
0c2997fee9 cleanup for quick liquid script 2016-09-18 20:54:29 +02:00
7f10f639be boundary width != 0 needed for liquid obstacles 2016-09-18 16:23:11 +02:00
a5a472485c refactored liquid inflow function 2016-09-18 13:41:40 +02:00
510f4fd416 removed access to manta grids from blender kernel code (bad sideeffects with new obstacle script code) 2016-09-16 00:43:19 +02:00
8c0776f18b fix for highres smoke flag and some cleanup 2016-09-15 09:29:32 +02:00
4054724bf8 fix for script smoke export 2016-09-14 14:51:05 +02:00
e43b821664 added liquid obstacle grids and access functions 2016-09-13 02:32:14 +02:00
05664b2b4c clean up and maintenance in script files 2016-09-12 20:11:45 +02:00
db18178f97 refactored manta script export and also added script export functionality for liquids 2016-09-11 19:24:18 +02:00
05405f759c removed unnecessary flag updates from liquid script 2016-09-10 17:50:21 +02:00
97152cf76b ui cleanup in fluid quality and general fluid tab 2016-09-09 11:19:38 +02:00
473f12e00b enabled liquid high resolution mode in ui 2016-09-08 01:26:31 +02:00
b8e4bb0769 pointcache adaptions for liquid high resolution files 2016-09-07 21:39:46 +02:00
64afd4263c improved high resolution step for liquids - using phiparts in high res mode as well now 2016-09-06 14:12:57 +02:00
a3e364757d added liquid high res api functions 2016-09-05 20:29:11 +02:00
d2ed5517c2 made particle radius factor field accessible 2016-08-29 22:17:57 +02:00
e283052af4 small fix for obstacle flag 2016-08-26 23:39:20 +02:00
cbf0a28f87 adapted value ranges for some fields and removed vorticity guard in smoke script 2016-08-23 00:31:37 +02:00
47a1640795 fix ui tab class. tab from elbeem was using this class before. 2016-08-22 19:01:17 +02:00
93a1054ece sanity check: make sure that domain type and flow types are valid combinations 2016-08-22 00:16:17 +02:00
b77f9388a4 removed chrono calls in mantaflow file. they caused some trouble with the blender build and are not needed anyways. 2016-08-21 01:04:57 +02:00
c635588cdc fix for viewport switcher: don't hide it when cache is baked 2016-08-20 00:22:38 +02:00
2c6348bf35 added support for external forces for liquids 2016-08-19 21:27:46 +02:00
11398e6cf6 refactored inflow flag 2016-08-19 14:08:16 +02:00
34cb963bf3 added gravity field and clean up UI a bit 2016-08-19 14:06:50 +02:00
90bad37c82 fixed obstacles for liquids (=blender source - manta liquid script needs some more customizations) 2016-08-19 14:01:34 +02:00
67bbd8b3db cleaned up a bit in mantaflow scripts 2016-08-18 23:12:31 +02:00
8c7ddbcfe6 added some sanity checks for ui and outflow fields 2016-08-17 19:26:32 +02:00
8067321206 added particle number (discretization) field to ui 2016-08-17 19:21:24 +02:00
4a2909c147 cleanup in manta liquid and smoke scripts 2016-08-17 19:15:45 +02:00
af8fb98bb4 removed 'stand-in' grid from liquid script (transparency functions only handling smoke domains) 2016-08-17 00:15:54 +02:00
449bea5438 fix in pointcache: make sure file is saved before trying to write liquid cache 2016-08-16 13:15:17 +02:00
26020784ad cleanup for filenames and classes: SMOKE -> FLUID 2016-08-16 13:12:58 +02:00
89436dd519 now using scene gravity in all mantaflow scripts (smoke and liquid) 2016-08-15 22:59:31 +02:00
ea7ed9dd10 refactored mantaflow scripts 2016-08-15 22:54:04 +02:00
96334c0719 fix for openvdb caching 2016-08-13 23:55:12 +02:00
c1756a55a8 removed smoke flames tab (was re-added after merge with master) 2016-08-12 16:21:58 +02:00
6fd71252b7 another cleanup for viewport switch. removed old 'show high resolution' check-box. 2016-08-12 16:06:09 +02:00
ca6966c39d updated manta pp files 2016-08-12 15:33:59 +02:00
63e97093d6 Merge branch 'master' into fluid-mantaflow 2016-08-12 14:17:04 +02:00
0a633dc170 disable high resolution liquid for now. high res loop in manta script needs some more work. 2016-08-12 12:45:17 +02:00
1c57b84127 preparations for liquid high resolution 2016-08-12 12:35:02 +02:00
9bd37ebc30 fix for viewport geometry mode 2016-08-11 17:12:47 +02:00
855f164761 removed preview resolution field. will not be needed 2016-08-11 15:45:56 +02:00
7083b22422 hooked up viewport viewing mode switch 2016-08-11 15:22:04 +02:00
866876a1d8 fix for manta liquid inflow and some general code cleanup in liquid script 2016-08-10 23:36:11 +02:00
e64269b8fc UI changes: renamed modifier label and some preparations for liquid high res mode 2016-08-10 22:10:45 +02:00
362f5e892b fix for outflow: only delete content from cells inside mesh 2016-08-09 15:24:02 +02:00
2ea7dab100 border collisions now work for smoke AND liquids 2016-08-09 15:23:51 +02:00
55694aa88e added 'Quick Liquid' script (similar to exisiting 'Quick Smoke' and 'Quick Fluid') 2016-08-09 00:10:59 +02:00
c23ce4a79d fixed viewport bug: objects inside smoke or liquid domain are now visible 2016-08-08 21:21:47 +02:00
c2bdfb18e0 better default values for vorticity and particle randomness 2016-08-08 21:20:39 +02:00
1187d35e7b added default values for render and viewport mode 2016-08-08 15:52:28 +02:00
5e00f7b9c0 implemented flow behavior geometry mode. works with liquids and also with smoke. 2016-08-07 23:58:21 +02:00
5ffcd36578 clean up for variable names 2016-08-07 20:34:54 +02:00
2e6abd0186 liquid settings: removed narrow band option (no need to toggle / turn off) and fixed particle randomness setting 2016-08-07 14:18:21 +02:00
648ee14cb9 reorganized fluid ui: introduced fluid quality tab and merged fluid behavior settings into one tab 2016-08-06 22:19:56 +02:00
9734506289 hiding fft noise type from gui: currently not supported in mantaflow 2016-08-04 17:41:24 +02:00
fc074465b7 fix for cache file format: wrong format not producing crash anymore 2016-08-04 16:13:29 +02:00
24d394efa8 added new border collision option: horizontally open (useful for liquids) 2016-08-03 12:57:36 +02:00
49fc90a4be bug fix: phiinit grid was not initialized to null 2016-08-03 10:49:10 +02:00
aa51619731 using inflow flag to control when to apply inflow 2016-08-03 02:10:05 +02:00
19148237c7 customized outflow function to account for liquids 2016-08-02 23:54:01 +02:00
940df74902 now using new behavior outflow flags instead of outflow type flags 2016-08-01 11:30:49 +02:00
12ad5310db more outflow ui customizations 2016-07-31 20:42:35 +02:00
d9cad3c0e7 made flag grid also accessible through manta api. needed for liquid outflow. 2016-07-30 22:50:19 +02:00
35c666b468 made flag grid also accessible through manta api. needed for liquid outflow. 2016-07-29 23:16:32 +02:00
a139f273b3 removed outflow flow type 2016-07-27 01:08:41 +02:00
5b98fce170 removed old liquid files (not needed anymore) 2016-07-26 14:19:10 +02:00
b30ce82e3e renamed some tabs to match other 'fluid' tabs 2016-07-25 20:12:45 +02:00
f9eee6d858 final touches for fluid source settings panel 2016-07-24 12:56:31 +02:00
394ede20b6 reorganized flow source settings in UI 2016-07-24 10:11:47 +02:00
4b6d9f0a8d reorganized ui for flow behaviour field 2016-07-23 12:04:58 +02:00
bcf01ecadf hooked up pointcache to new liquid grid io. caching now works even if bake was interrupted. 2016-07-21 02:28:33 +02:00
d23f1a5947 added c api functions for liquid grid io 2016-07-20 09:34:54 +02:00
03eac283a5 added functions to save / load liquid grids and particle systems 2016-07-19 00:19:37 +02:00
87bd42ebc9 added io section to liquid script. grid io needed for caching. 2016-07-18 01:05:14 +02:00
506cf7051f distinguishing between phi and phi_init grid 2016-07-17 17:51:56 +02:00
128a60137d added normalization for liquid inflow (needed for mantaflow) 2016-07-16 13:20:15 +02:00
0aa086586a made viewport switcher functional. now switching between geometry and render/preview works. 2016-07-16 12:58:11 +02:00
bdce2b847d clean up: bad formatting in pointcache fixed 2016-07-15 15:19:26 +02:00
1a05cf6547 cleaned up /removed some old TODOs 2016-07-15 14:50:44 +02:00
25b7d8a8ad renamed viewport mode switcher variables 2016-07-15 12:39:21 +02:00
4ffac9faf1 possible fix for running manta python calls under windows 2016-07-14 23:52:49 +02:00
8eac981888 no need to add old smoke code as lib 2016-07-13 23:51:24 +02:00
ce69ec37cf more UI changes: clean up layout for smoke, fire and liquids 2016-07-08 19:47:13 +02:00
07d241fbe2 UI customizations: distinguish between flow type and flow behavior 2016-07-06 17:23:51 +02:00
ba0825d407 mesh faces for liquids now enabled 2016-07-05 19:36:12 +02:00
cf3c18948b liquid mesh scaling improvements 2016-07-04 00:09:30 +02:00
697566e5c9 sanity check in liquid mesh create function. prevents crashes 2016-07-03 21:18:50 +02:00
ed954841bf some cleanup for liquid inflow 2016-07-03 13:11:41 +02:00
77bb36bffb mesh scaling according to scale factor. not perfect solution though 2016-07-02 18:02:13 +02:00
25922e9b17 removed mesh scaling. better do this in smoke.c and keep cpp wrapper independent from mesh size 2016-07-01 15:59:38 +02:00
93872456e6 fixed return type for vertex getter 2016-07-01 15:22:19 +02:00
ce4d31cf3d cleanup function names 2016-06-30 00:09:15 +02:00
9a78eea081 final cleanup for liquid inflow 2016-06-29 01:23:20 +02:00
9773ffa92f added new liquid inflow function. this version uses 6 raycasts and not only considers distance to flow mesh surface from within mesh but also from outside. 2016-06-28 19:21:49 +02:00
17d51b6d09 cleanup liquid inflow functions 2016-06-25 15:34:04 +02:00
8661d1bd60 cleanup in manta export. obj file export is not needed anymore 2016-06-23 22:12:54 +02:00
e507cb0ba0 removed shift for vertices - only needed in mantaflow 2016-06-21 14:51:22 +02:00
80f4b470a5 cleanup: removed old manta obj approach - we're using phi grid for liquid inflow 2016-06-20 01:05:43 +02:00
d450e098ac cleanup old mesh load function in header 2016-06-19 20:11:15 +02:00
88306313ed fixed memory leak (liquid mesh was copied but not freed) 2016-06-18 19:32:31 +02:00
40eecf3740 temporary fix for viewport tranparency (additional density grid in liquid sim) 2016-06-18 17:33:41 +02:00
032d417da0 fix for gzopen: added missing cast (void* -> gzfile) 2016-06-18 17:31:49 +02:00
da8789bf66 small gzfile fix: declare file variable before using it and use const file name 2016-06-18 16:04:35 +02:00
d127b44036 clean up in elbeem fluid code: removed some early tests (not needed since manta liquids are in smoke modifier) 2016-06-18 13:04:38 +02:00
3b521e7012 new function that builds a derived mesh from the fluid objects mesh data (fluid object gets mesh data by reading bobj.gz) 2016-06-17 11:04:19 +02:00
6dd1cf2a3e hooked up pointcache so that it triggers the new mesh read function 2016-06-16 01:12:04 +02:00
d67e7284b9 added mesh (.bobj.gz files) read functionality to fluid class 2016-06-15 16:36:21 +02:00
6a288555eb implemented getters for mesh fields and also added them to the c api 2016-06-15 01:07:56 +02:00
c933f959af added fields for meshes to fluid object 2016-06-14 22:45:12 +02:00
9516230a8a making maxres a public field 2016-06-13 14:13:01 +02:00
0972761bf0 new liquid inflow approach based on multiple raycasts 2016-06-12 02:32:42 +02:00
6c177d3d30 fixed missing sign from previous commit 2016-06-11 18:21:24 +02:00
0992e7f686 reverting to old liquid inflow - previous approach results in inaacurate meshes (interpolation issue) 2016-06-11 18:01:22 +02:00
e8863f0be1 trying out new liquid inflow values 2016-06-11 00:53:13 +02:00
5a83406340 custom file names for liquid cache now supported 2016-06-10 14:17:01 +02:00
7abab97769 started integration of liquids in pointcache 2016-06-09 19:28:49 +02:00
4cb76badec added high res liquid inflow grid (the one manta uses to create the mesh) 2016-06-09 00:05:25 +02:00
465250ad34 need to disable some smoke functions again 2016-06-08 22:59:15 +02:00
80f4488cf6 script cleanup (added some debug messages and remained phi grid) 2016-06-08 22:55:40 +02:00
a3c04bdd56 added phi high res grid. will be used later in liquid upres mode 2016-06-08 22:53:24 +02:00
a09387ee55 splitting up domain initialization. otherwise crashing 2016-06-08 22:49:04 +02:00
f0c17c7599 added high res liquid phi grid getter 2016-06-08 22:28:15 +02:00
664d6ad6c6 first customizations for liquid caching - extending the smoke cache 2016-06-08 16:22:40 +02:00
2c991e2ff2 re-enabled the remaining smoke functions. smoke sim now back to normal state 2016-06-08 16:19:33 +02:00
836db6c990 fixed domain switching - now using flags correctly 2016-06-07 00:45:26 +02:00
05c03b6526 cleaned up scripts and init functions which use them 2016-06-06 18:13:31 +02:00
2bd08d59d6 just some ui changes for the liquid domain switcher 2016-06-05 00:20:53 +02:00
d3c57bc244 added some liquid domain flags. mantaflow needs to know what domain to setup 2016-06-04 22:04:09 +02:00
6fe495f564 added liquid ensure function 2016-06-04 14:28:01 +02:00
c435b25a8e cleaned up liquid init and made it public 2016-06-04 11:10:49 +02:00
fef67913f2 use smaller randomness factor for now 2016-06-03 20:05:41 +02:00
a29e47ad23 re-enabled smoke ensure functions 2016-06-02 23:02:44 +02:00
1cbac79a1e added liquid flags / adapted settings to handle smoke 2016-06-02 22:16:33 +02:00
f13e9ccc61 better liquid inflow function 2016-06-01 19:20:21 +02:00
492e457afa memory cleanup for liquid inflow 2016-05-30 01:03:47 +02:00
b7d4d4a440 manta mesh smoothing not very performant. removing for now 2016-05-29 16:18:05 +02:00
a13cf9d56a better use floats for inflow liquid inflow map 2016-05-29 00:34:23 +02:00
be151d5ebd mantaflow mesh smoothing functions 2016-05-28 17:55:29 +02:00
7872e2fc3b added liquid inflow map 2016-05-27 16:20:51 +02:00
240ed366ce disabling smoke and fire grid 'ensures' for now - conflict with liquids 2016-05-27 10:39:03 +02:00
787735d8da reading from phitemp now 2016-05-27 00:32:54 +02:00
4500bd8195 added phitemp grid to mantaflow script (for blender to use for liquid mesh map) 2016-05-26 22:05:12 +02:00
7a8fd7068e major clean up
- removed deprecated scons setup
- reverted to original code in intern/smoke (new structures are all in
intern/mantaflow)
- minor CMake clean ups
2016-05-25 11:26:56 +02:00
c65d58a384 Merge branch 'master' into fluid-mantaflow 2016-05-24 23:10:59 +02:00
21d382fdfe disabling ptcache and some other smoke specific functionality to get liquids running in smoke core 2016-05-23 23:24:32 +02:00
e506b450e0 liquid grid pointer exchange functions (lets blender write the inflow to the mantaflow grid) 2016-05-21 02:17:50 +02:00
d352bc36b2 using smoke flags to guard certain calls (important when liquid is added) 2016-05-21 00:52:14 +02:00
909715d336 added flags to distinguish smoke and liquid setup 2016-05-20 18:41:49 +02:00
ba01efb841 liquid init function in header 2016-05-19 21:35:14 +02:00
cadcaac2dc small cleanup for smoke init function as well 2016-05-19 21:33:35 +02:00
68ccc63c1b added liquid init function (putting together manta script and firing off first python call) 2016-05-19 21:30:23 +02:00
45c146f4d6 don't forget to sample particles on first frame 2016-05-18 21:11:07 +02:00
bc11878b4c liquid script cleanup (removed old mesh .obj loading approach) 2016-05-17 16:03:10 +02:00
cb3f5f9b72 added liquid destruction script snippets 2016-05-17 15:54:56 +02:00
e32d03d7bd start frame for manta step was always one frame ahead 2016-05-15 02:20:04 +02:00
e8938ee9dc idea for mantaflow liquids api entry point 2016-05-14 11:08:18 +02:00
50b60c4edb fixed broken CMake for mantaflow directory 2016-05-13 01:32:11 +02:00
4a6f96a6d3 moved some script snippets to separate shared file (now there is only one solver string, one adaptive time stepping string, etc) 2016-05-12 13:01:39 +02:00
976ddc6636 new manta script file to hold shared snippets for smoke and liquids (e.g. imports, solver object) 2016-05-11 12:45:01 +02:00
026fdb3eaa some variables from previous commit were not renamed. fixed that. 2016-05-09 00:22:19 +02:00
b885c421a5 smoke api now matching new SMOKE names 2016-05-09 00:17:40 +02:00
a726479802 smoke object is now known as SMOKE (was MANTA). otherwise it might get confusing with new LIQUID object 2016-05-08 20:00:56 +02:00
c5051412a1 first implementation of liquid API (similar to smoke) 2016-05-07 16:35:03 +02:00
ba914f6c59 fixed include paths 2016-05-06 14:57:05 +02:00
d74149c6fd formatting (indentation) smoke script to match liquid and mantaflow scripts in general 2016-05-06 14:55:29 +02:00
756eedd2ab added new liquid script functions (mostly nb flip) 2016-05-05 10:33:23 +02:00
5e2a1bfe3d cleaned up manta api and script 2016-05-02 11:21:54 +02:00
39f65a97d2 adapted obstacle flags for mantaflow 2016-04-25 16:23:10 +02:00
520075c9de transferred object velocities to mantaflow 2016-04-25 16:22:14 +02:00
a59e9cd9f6 removed some deprecated functions 2016-04-23 13:48:01 +02:00
db47130a9c simplified grid pointer access functions 2016-04-23 13:45:38 +02:00
a9ca030f61 Merge branch 'master' into fluid-mantaflow 2016-04-06 13:15:12 +01:00
2533ccd609 removed deprecated cmake setup 2016-04-05 23:34:31 +01:00
bd34f1827a removed old manta_pp files from internal python dir - manta_pp files are in intern/mantaflow 2016-04-04 18:01:30 +01:00
ca58fa9a14 minor formatting cleanup 2016-04-03 23:52:49 +01:00
32de14f6c9 better use smaller uvweight reset time (strange smoke movement when set too high) 2016-04-02 12:55:14 +01:00
e248452b6c reverting to original fluid solver destructor. additional guards not needed. 2016-04-01 22:12:02 +02:00
f5c3f4acc2 making sure that all python objects are garbage collected 2016-04-01 22:10:52 +02:00
d2ef009a65 first customizations for using mantafow flags grid (replaces obstacle grid / array in blender) 2016-03-31 22:13:28 +01:00
b464579ad1 important: initialize uv helper grids as well 2016-03-30 20:06:51 +02:00
88ac9387cb added caching for mantaflow texture grids 2016-03-29 16:48:09 +01:00
a267258554 better and safer to delete solver python variables (and thus trigger object deletion) at the end 2016-03-28 13:29:54 +01:00
3f22573395 added current frame number to manta step. useful for standalone mantaflow script usage and for correct caching (uvweight) 2016-03-28 09:15:21 +01:00
88cb1a9c8f run uv setup strings only when using high res 2016-03-27 22:56:18 +01:00
d6356b71e3 switched back to old uv setup using low res solver 2016-03-27 10:01:32 +01:00
81ea46dee6 generalized mantaflow grid helper functions 2016-03-26 16:13:20 +01:00
8e5f736da7 implemented external forces 2016-03-25 18:32:39 +01:00
bce4ca54c5 crash fixes when loading a new script and some better default parameters 2016-03-24 14:59:59 +01:00
ee4c49462a added guards in fluid solver destructor 2016-03-24 01:35:29 +01:00
e4d27ed7b0 fixed pyobject reference count and changed mantaflow deallocation callback -> solver objects now deleted as well 2016-03-23 20:05:18 +01:00
5e24184124 now using separate flags for heat, fire, colors and highres 2016-03-23 06:10:39 +01:00
00bc0e6804 clean up strings for solver and gc 2016-03-22 21:22:04 +01:00
57af2486ff adapted setup for energy grid (now using high res) 2016-03-22 16:30:41 +01:00
6c1846e64f cleaned up include statements 2016-03-21 18:53:37 +01:00
329f128f23 now deleting python grid references properly 2016-03-20 23:26:43 +01:00
937c63766f moved uv setup and calculations from step low to step high. not needed in step low 2016-03-19 20:57:13 +01:00
fec5e07c4f fixed broken destructor from previous commit 2016-03-18 23:06:15 +01:00
8869dc6f72 fixed formatting issue in MANTA 2016-03-18 14:31:50 +01:00
f2206deadd fixing script export and small cleanups 2016-03-18 09:06:56 +01:00
6a2e523639 fixed include for manta python api header 2016-03-17 18:51:32 +01:00
837a78a451 updated manta pp files 2016-03-17 10:58:56 +01:00
1af573bb48 configured CMake and includes to use new manta api 2016-03-17 09:32:01 +01:00
81b646de8b renamed old smoke api functions in header because of name conflicts 2016-03-17 01:11:35 +01:00
f5200ea512 added macros to kernel code to use new manta smoke api 2016-03-16 21:54:46 +01:00
471d26025e removing old mantaflow code from kernel smoke.c for now. needs refactoring, maybe add later again 2016-03-16 12:39:08 +01:00
279bebead6 clean up in rna smoke 2016-03-16 09:14:40 +01:00
722f7f95be totally refactored, cleaned up manta object and its API 2016-03-15 20:09:47 +01:00
c27a16bdd1 setting up smokedomainsettings for new manta object 2016-03-15 11:23:30 +01:00
e763f021c8 setting up CMakeLists in mantaflow directory 2016-03-15 09:18:25 +01:00
ac5fdf2e16 prepared some paths in CMakeLists for new mantaflow directory 2016-03-14 12:10:57 +01:00
dde516be37 added color code snippet, fixed buoyancy sign, cleaned up standalone mode 2016-03-14 07:57:01 +01:00
e87694001f moved old liquid code to separate file 2016-03-14 07:53:41 +01:00
3b032529f8 refactored wavelet turbulence noise 2016-03-13 18:50:13 +01:00
3137f8f768 refactored deletion snippets for python 2016-03-13 18:44:45 +01:00
99f9cd040a extracted manta python api function to new files 2016-03-13 14:19:32 +01:00
4cc72652c4 changed new manta smoke api a bit 2016-03-12 12:51:11 +01:00
63a4dc5447 cleanup in CMakeLists 2016-03-11 10:33:24 +01:00
ea21f7cb99 removed old unused operator types 2016-03-10 09:01:49 +01:00
461d1ed860 added helper classes that were used in intern/smoke too 2016-03-09 16:14:20 +01:00
6d719f0727 small cleanup in ui - removing solver res for now 2016-03-08 14:42:15 +01:00
1340530c8c created separate mantaflow directory for api files 2016-03-07 22:57:48 +01:00
d69cc7ad06 updated manta pp files and new buoyancy function 2016-03-06 23:50:06 +01:00
1c8b45a596 small script cleanup, removed uvs variable 2016-03-03 22:48:30 +01:00
692c60eeb8 set wavelet noise value ranges, now using inverse posScale factor and fixed octaves issue when upres == 1 2016-02-26 18:48:46 +01:00
ec5a5ddc4f using mantaMsg() for debug messages 2016-02-26 16:13:46 +01:00
d40deb173c updated mantaflow pp files 2016-02-26 16:03:27 +01:00
db733cb2c0 even more cleanup 2016-02-26 12:59:04 +01:00
2deb386318 more noise and ui cleanup 2016-02-26 11:15:02 +01:00
f1fbad849f clean up wavelet noise 2016-02-26 09:21:53 +01:00
e8ba159405 some cleanup 2016-02-26 09:17:11 +01:00
33dba2c866 small while loop changes 2016-02-19 11:46:34 +01:00
986093dfb7 now using adaptTimestep(), new step setup and correct dt 2016-02-14 23:16:48 +01:00
d9e7005a52 manta step updates - reordered some functions 2016-02-04 20:55:13 +01:00
d58f9896cc epsilon fix 2016-02-02 16:30:31 +01:00
ab9c7d289e boundary width fix 2016-02-01 12:52:03 +01:00
61ce9584cc removed readme 2016-01-28 09:47:50 +01:00
00aeafc110 updated boundary and open bound settings 2016-01-22 15:20:14 +01:00
76f42e3ffe updated mantaflow pp files 2016-01-22 15:18:51 +01:00
81ac552eeb added del guards and removed noise grids (were not used anyway) 2016-01-18 18:10:42 +01:00
c1be8670b2 reverting to old mantaflow initialization 2016-01-17 23:05:31 +01:00
dbf8380953 updated ui wavelet noise and readme issue section 2016-01-16 22:04:33 +01:00
f0a54fa5e9 readme updates - known issues section 2016-01-14 14:46:39 +01:00
0f91dd6ce3 ui updates 2016-01-14 14:46:09 +01:00
e8c34986ed better noise integration - especially wavelet noise 2016-01-14 13:55:11 +01:00
328855b18d bound / border condition fixes 2016-01-13 00:34:32 +01:00
2be683a9f9 more readme updates (troubleshooting section) 2016-01-12 23:36:03 +01:00
846d196c4e script generation and readme updates 2016-01-12 23:10:19 +01:00
a167cb75ce wavelet fixes and refactored smoke.h 2016-01-09 21:37:23 +01:00
4be4b58816 more manta api refactoring 2016-01-09 03:01:08 +01:00
965ac27fb7 refactoring manta api and started to comment out old code -> removing it later 2016-01-08 02:12:57 +01:00
43fcc9207a some manta api refactoring 2016-01-07 21:01:19 +01:00
59ed95e447 cannot have heat, flame, fuel, react grids here 2016-01-07 03:37:29 +01:00
b1debbea46 fixing cache 2016-01-07 02:27:25 +01:00
7227b9ae10 removed #if #end directives from fluid destructor 2016-01-03 02:53:21 +01:00
8af5aa365d flag fix 2016-01-03 01:10:25 +01:00
5c70edab88 cleanup and naming changes 2016-01-03 01:07:48 +01:00
b9d1c5cb77 high res fixes 2016-01-02 17:36:47 +01:00
16a7dc70ee readme updates 2015-12-24 00:58:34 +01:00
cd35a608b3 Merge remote-tracking branch 'github/soc-2014-fluid' into soc-2014-fluid 2015-12-23 23:53:11 +01:00
caa23de7fb cleanup from previous noise test 2015-12-23 23:52:48 +01:00
ba0ef25670 added readme 2015-12-22 03:40:15 +01:00
db9caab5b1 Merge branch 'master' into soc-2014-fluid
Conflicts:
	CMakeLists.txt
	extern/CMakeLists.txt
	extern/SConscript
2015-12-21 15:21:11 +01:00
c15ac2fdda script improvements - noise settings 2015-12-21 01:06:02 +01:00
d77b678265 buoyancy improvements 2015-12-16 00:15:49 +01:00
6ec6e81563 fixed issue with bound conditions 2015-10-24 13:06:40 +02:00
3430e0aab9 minor cleanups 2015-10-12 20:38:51 +02:00
d0c9ebf9cb fuel inflow and manta script cleanup 2015-10-11 23:44:51 +02:00
9a6f22462d fixed manta density inflow grid and removed unneeded manta pp gui files 2015-10-09 18:27:27 +02:00
c411456263 refactored manta script creation 2015-10-09 12:48:24 +02:00
2e56d6a07b Merge branch 'master' into soc-2014-fluid 2015-10-06 01:01:14 +02:00
6af37db96f script changes 2015-10-06 00:53:27 +02:00
fe64157063 improving manta export script 2015-10-06 00:51:00 +02:00
d02bb60d3c updated manta pp files and adapted smoke.h 2015-10-01 11:02:40 +02:00
04eaf6bd58 removed manta-full 2015-09-30 22:01:24 +02:00
556ff7c85d fixed scons setup and removed old pp non openmp mantaflow files 2015-09-22 18:59:33 +02:00
895dc7db15 new pymain.cpp also for openmp setup 2015-09-19 22:11:58 +02:00
6cfc4110cd refactoring fluid_3d constructor setup 2015-09-19 20:28:09 +02:00
9ac37c4e0e added caching for simulation with manta solver 2015-09-19 16:58:03 +02:00
f6d5c3465a fixed setup when with_manta flag is disabled 2015-09-18 23:48:49 +02:00
191f3fc1c2 added non-openmp mantaflow pp files 2015-09-17 18:01:30 +02:00
c08a25d7e7 updated mantaflow files and some further tweaks to get it working in blender 2015-09-17 15:39:39 +02:00
9cbe88808c remove comments for cleaner console 2015-09-16 15:05:16 +02:00
807cd2e33e cleaner export paths in manta script 2015-09-10 01:38:59 +02:00
803e5a9ade read blender values in processBurn and cleaned up fire plugin 2015-09-09 14:32:10 +02:00
04d826c296 finished high resolution fire 2015-09-08 13:04:01 +02:00
497c40b29c refactored updatePointers functions 2015-09-08 01:02:59 +02:00
cd76de8410 work on high resolution fire 2015-09-08 00:39:02 +02:00
3804e91127 initialize color grids before burning - needed! 2015-09-07 01:32:42 +02:00
9dcc33794c minor tweaks 2015-09-07 00:38:39 +02:00
e9afe07ae1 Merge remote-tracking branch 'github/soc-2014-fluid' into soc-2014-fluid
merge with github version
2015-09-06 20:16:21 +02:00
d31e7960ea plugin changes 2015-09-06 19:57:24 +02:00
71d5c16487 updated fire plugin 2015-09-05 22:24:58 +02:00
18aa00cc5e more fire integration 2015-09-05 18:35:38 +02:00
a35c4b1df3 first draft for fire setup with manta 2015-09-05 15:19:15 +02:00
cd712d50b7 just removed some typos 2015-09-03 23:21:42 +02:00
1dbcacbd26 cleaning up repository 2015-08-15 15:42:41 +02:00
82c2daa248 Merge branch 'master' into soc-2014-fluid
Conflicts:
	CMakeLists.txt
	extern/CMakeLists.txt
	extern/SConscript
	intern/ghost/intern/GHOST_WindowCocoa.mm
	source/creator/CMakeLists.txt
2015-08-15 13:34:27 +02:00
Roman Pogribnyi
3d397d22d7 Smoke: UI controls for manta buoyancy used 2015-05-17 21:22:08 +02:00
Roman Pogribnyi
16ace5e6f7 Smoke: manta export paths corrected 2015-05-17 20:46:04 +02:00
Roman Pogribnyi
03c7acf3a0 Smoke: Updated mantaflow sources 2015-04-13 22:17:59 +02:00
Roman Pogribnyi
79f7f4d562 after-merge errors fixed 2015-03-15 23:05:11 +01:00
Roman Pogribnyi
5c64aa2554 Merge branch 'master' into soc-2014-fluid 2015-03-15 19:57:06 +01:00
Roman Pogribnyi
2a1a6bc572 2D lowres smoke 2015-03-09 22:55:34 +01:00
Roman Pogribnyi
bf64cd1fd8 Forces passed to Mantaflow correctly, vortex working 2015-03-05 00:19:24 +01:00
Roman Pogribnyi
1799615629 Manta 2D smoke indexing fixed 2015-02-01 23:58:36 +01:00
Roman Pogribnyi
2d0f34ef76 Manta 2D Smoke display correct 2015-02-01 23:52:19 +01:00
Roman Pogribnyi
d607c2a598 manta scene file location, work on 2D smoke 2015-01-27 23:24:16 +01:00
Roman Pogribnyi
d72968e91d fields saved properly for export, unused code removed 2014-12-04 23:14:53 +01:00
Roman Pogribnyi
666cc76e42 completing flags passing, removing comments from scenarios 2014-11-17 10:53:10 +01:00
Roman Pogribnyi
a380ca2a63 passing obstacle flags to manta correctly 2014-11-15 15:05:23 +01:00
Roman Pogribnyi
1377d74cb5 high res smoke colors fixed 2014-11-14 14:41:43 +01:00
Roman Pogribnyi
43d7cbdea8 Boundary conditions + new feature 2014-11-11 23:42:18 +01:00
Roman Pogribnyi
26dca6df78 Buoyancy in Manta using heat from Blender 2014-11-09 15:39:17 +01:00
Roman Pogribnyi
6b11773770 error checks for Manta_API functions 2014-11-09 14:41:12 +01:00
Roman Pogribnyi
15ba8ec5af shrinking Fluid_3d class 2014-11-09 14:38:01 +01:00
Roman Pogribnyi
b63074492d low- and highres colored smoke 2014-11-06 00:31:09 +01:00
Roman Pogribnyi
b1acc10d8b not initializing density fields 2014-11-05 21:26:12 +01:00
Roman Pogribnyi
cbda5b801b SMOKE: mantaflow in Fluid_3d object, running wavelets 2014-11-05 20:53:08 +01:00
Roman Pogribnyi
2e6fbe23b8 SMOKE: wavelets included in setups 2014-11-04 17:45:03 +01:00
Roman Pogribnyi
645c283477 wturbulence for mantaflow 2014-11-02 14:21:17 +01:00
Roman Pogribnyi
f45d319d60 division between high-res and low-res manta operations 2014-11-02 14:20:54 +01:00
Roman Pogribnyi
4256c72ae3 working with manta compiler flag 2014-10-30 16:36:06 +01:00
Roman Pogribnyi
d410d6622a lowres density pointers corrected 2014-10-30 11:48:07 +01:00
Roman Pogribnyi
c181d0b9be lowres: computing forces only once 2014-10-27 13:38:45 +01:00
Roman Pogribnyi
c92be53d24 Not using disk setup file anymore 2014-10-27 09:56:29 +01:00
Roman Pogribnyi
cd5898aecb low-res: only manta solver, with manta flag simulation 2014-10-27 09:16:32 +01:00
Roman Pogribnyi
8d40c8de5a Defining Interfaces for Manta_API 2014-10-26 21:59:40 +01:00
Roman Pogribnyi
b4ef7ed987 GetGridPOinter form mantaflow working 2014-10-26 21:51:41 +01:00
Roman Pogribnyi
4ffc4fb0bc UI syntax 2014-10-26 21:50:31 +01:00
Roman Pogribnyi
e62f96480a unused manta UI disabled 2014-10-25 14:54:54 +02:00
Roman Pogribnyi
71493088c1 deleting manta solvers and fields correctly 2014-10-25 14:10:15 +02:00
Roman Pogribnyi
5d3ae295d8 compiler flags for osx and linux 2014-10-25 12:26:59 +02:00
Roman Pogribnyi
2696d2bb8b mantaflow stable on osx 2014-10-24 17:45:28 +02:00
Roman Pogribnyi
9b54025191 Manta python module imported correctly 2014-10-24 12:33:19 +02:00
ee54a4eaee Fix compile 2014-10-23 18:41:11 +02:00
0d41f63eb2 Revert changes.
Still one linking error left.
2014-10-23 18:04:28 +02:00
f43088623c Revert name changes to be conform with mana_full 2014-10-23 17:17:01 +02:00
33c5699a41 Fix compile error on Linux 2014-10-23 16:55:49 +02:00
f2c5ff385d Fix merge error
Streamline Python function name
2014-10-23 16:46:28 +02:00
9c113a870a Fix merge error (still some left)
Fix some path issues
2014-10-23 16:36:01 +02:00
2cc063318c Fix CMake (missing path for zlib) 2014-10-23 15:36:05 +02:00
8662cddce1 Fix (one) compile error on MSVC 2013
Fix merge error
2014-10-23 15:24:24 +02:00
9ff1ebed52 Merge remote-tracking branch 'origin/master' into soc-2014-fluid
Conflicts:
	.gitignore
	intern/cycles/CMakeLists.txt
	source/blender/blenkernel/intern/smoke.c
	source/blender/python/intern/bpy_interface.c
	source/creator/CMakeLists.txt
2014-10-23 15:12:28 +02:00
Roman Pogribnyi
a2ed11c6ee readGridFromMemory correct dimensionality 2014-10-23 11:59:50 +02:00
Roman Pogribnyi
77fcd6c400 unnecessary calls to Mantaflow removed 2014-10-22 20:47:41 +02:00
Roman Pogribnyi
9cc9c7ec16 high-res: inflow data passed in-memory, forces working 2014-10-21 23:09:04 +02:00
Roman Pogribnyi
2b3b73fbb0 low-res: passing obstacles in-memory 2014-10-18 15:52:46 +02:00
Roman Pogribnyi
e6a37c3f24 low res: errors in grid construction fixed, methods for passing obstacles to Mantaflow added 2014-10-18 15:15:45 +02:00
Roman Pogribnyi
8b9abeb8e0 methods for adding texture values to grids, working for Real type 2014-10-17 17:37:53 +02:00
Roman Pogribnyi
86aeeb16f8 in-memory passing of force fields 2014-10-16 22:05:00 +02:00
Roman Pogribnyi
453a284e97 generating grid name from type 2014-10-16 21:42:37 +02:00
Roman Pogribnyi
2fcda12a14 passing void pointers for different types of grids 2014-10-16 21:33:35 +02:00
Roman Pogribnyi
b3413a07b4 passing inflow adaptive grids without disk files 2014-10-15 19:51:35 +02:00
Roman Pogribnyi
193461e3da Manta_API as singletone 2014-10-11 20:21:40 +02:00
Roman Pogribnyi
065e1a196c debug output, smoke BC 2014-10-11 19:39:03 +02:00
Roman Pogribnyi
c7c360c573 loading influence fields form file 2014-10-11 19:38:08 +02:00
Roman Pogribnyi
239260d45b returning to non-static methods 2014-10-11 19:35:53 +02:00
Roman Pogribnyi
1ad9eebd51 more vars from sds, flow density added to manta 2014-09-27 14:48:56 +02:00
Roman Pogribnyi
db26bdd36f writing correct density emitter to file 2014-09-27 13:53:41 +02:00
Roman Pogribnyi
b79bcc8121 replacing step function 2014-09-27 09:38:38 +02:00
Roman Pogribnyi
f91b07d655 loading flow data on first sim frame 2014-09-22 14:46:14 +02:00
Roman Pogribnyi
8e32d79158 scenario changed according to simpleplume 2014-09-22 13:35:42 +02:00
Roman Pogribnyi
8f14ff3905 per-step sim without writing to disk, reducing number of arguments to manta 2014-09-21 16:37:49 +02:00
Roman Pogribnyi
309e1bcc2d low-res smoke scenario running, unused files removed 2014-09-21 14:51:48 +02:00
Roman Pogribnyi
065676a6f8 updated mantaflow version 2014-09-21 14:43:44 +02:00
Roman Pogribnyi
00157066bf reverting to old smoke style, simpleplume scenario for debug 2014-09-21 14:43:00 +02:00
Roman Pogribnyi
527920ecf6 using bake buton, reading more settings 2014-09-20 16:48:46 +02:00
Roman Pogribnyi
199b6cdc1e timestep config corrected 2014-08-31 23:03:26 +02:00
Roman Pogribnyi
0fce063fd0 Display and render of highres smoke fixed 2014-08-25 15:28:12 +02:00
Roman Pogribnyi
9c7f7c6573 more parameters for smoke scenario, writing out emitter fields 2014-08-25 14:43:17 +02:00
Roman Pogribnyi
b3cc023c08 smoke scenarion working 2014-08-19 11:03:29 +02:00
Roman Pogribnyi
86989150b5 started scenarios implemetation; added file for smoke; back to setup file generation 2014-08-18 20:48:33 +02:00
Roman Pogribnyi
c9a3db6c42 reverting to Bake button 2014-08-18 16:49:01 +02:00
Roman Pogribnyi
ca26093a2c functions for scenarios parsing added 2014-08-18 16:01:37 +02:00
Roman Pogribnyi
01ec151a07 commented parts and debug msgs removed in rest of files 2014-08-18 15:22:59 +02:00
Roman Pogribnyi
0e200e9d31 manta.cpp commented parts removed 2014-08-18 15:08:39 +02:00
Roman Pogribnyi
dca46055ee releasing python after sim step 2014-08-18 14:53:03 +02:00
Roman Pogribnyi
2b9c2bc1d4 debug messages added 2014-08-18 11:52:26 +02:00
Roman Pogribnyi
5f39d58e6d setup script passed directly; file still created fir debug 2014-08-18 09:25:54 +02:00
Roman Pogribnyi
a651697d78 frame counting for simulation correct 2014-08-17 22:26:26 +02:00
Roman Pogribnyi
c9571f9a3e Run sim from timeline, without Bake button 2014-08-17 15:55:00 +02:00
Roman Pogribnyi
775b93767f RNA update operations corrected 2014-08-16 12:03:17 +02:00
Roman Pogribnyi
f105ea7b5e timestep decreased 2014-08-15 22:25:22 +02:00
Roman Pogribnyi
269dbda090 old density read-style 2014-08-15 22:18:52 +02:00
Roman Pogribnyi
0607338884 repositioned domain handling; quick smoke working 2014-08-15 21:48:15 +02:00
Roman Pogribnyi
3bd5139761 faster SDF, displaying smoke 2014-08-15 20:17:23 +02:00
Roman Pogribnyi
dca8568fff added comments 2014-08-14 23:14:49 +02:00
Roman Pogribnyi
4b7cc3923e removed commented parts 2014-08-14 23:11:12 +02:00
Roman Pogribnyi
dcdb8a658c inflow without noise; passing rotated geometry to amantaflow correct 2014-08-14 23:04:56 +02:00
Roman Pogribnyi
6642bd6ab4 wavelets source positioning correct 2014-08-13 22:12:02 +02:00
Roman Pogribnyi
dc529debbd resizeable domain added. Working for non-rotated objects 2014-08-13 20:57:12 +02:00
Roman Pogribnyi
9575a37b20 loading and displaying wavelets smoke 2014-08-13 16:06:04 +02:00
Roman Pogribnyi
00c9e3b4cf rotating domain to get manta axes 2014-08-12 22:43:39 +02:00
Roman Pogribnyi
2f96dbd3fc invoking BKE_cache_write when read from cached files successful; handling wavelet 2014-08-12 22:42:23 +02:00
Roman Pogribnyi
201555edca updating highres fluid_3d; writing smoke cache to BKE_pointcache 2014-08-12 00:55:35 +02:00
Roman Pogribnyi
74136a6d06 re-runs with wavelets work 2014-08-11 22:16:15 +02:00
Roman Pogribnyi
8537dccb30 runtime error in abscent FLUID_3D obj seems corrected 2014-08-11 21:48:16 +02:00
Roman Pogribnyi
e5b7630809 more density in emitter, unused function declaration removed 2014-08-10 18:05:10 +02:00
Roman Pogribnyi
edc3b4b687 force fields direction correct 2014-08-09 13:00:48 +02:00
Roman Pogribnyi
818d6ae380 more fluid_3d pointers handling 2014-08-08 23:46:11 +02:00
Roman Pogribnyi
868980d7f2 FLUID3D pointers handling 2014-08-08 22:25:33 +02:00
Roman Pogribnyi
ba0d7cb56d Buoyancy factor corrected 2014-08-08 17:55:36 +02:00
Roman Pogribnyi
0e173445c7 manta running speed increased. Buoyancy factor added 2014-08-08 17:55:14 +02:00
Roman Pogribnyi
861bfc9441 correct number of sim frames 2014-08-08 16:51:22 +02:00
Roman Pogribnyi
e3adec65f7 Error with force_grid_size fixed. Direction still incorrect 2014-08-08 14:16:10 +02:00
Roman Pogribnyi
ec9c908018 forces included in manta simulation on per-basis step 2014-08-08 00:14:35 +02:00
Roman Pogribnyi
306ef174cb updating force_fields on per-step basis 2014-08-07 23:50:58 +02:00
Roman Pogribnyi
5a54c9c6b7 updating force field on smoke_process 2014-08-07 20:34:21 +02:00
Roman Pogribnyi
ff20f36680 exporting wind force 2014-08-07 20:12:38 +02:00
Roman Pogribnyi
9156dcac7d addForceField method in mantaflow added 2014-08-07 19:58:15 +02:00
Roman Pogribnyi
fa4dec8e52 Linux running error fixed. Replay sim error fixed 2014-08-05 19:34:15 +02:00
Roman Pogribnyi
1f22e9d68c passing correctly rotated geometry to manta 2014-08-05 19:20:29 +02:00
Roman Pogribnyi
6a22addd61 returning to densityInflowMesh 2014-08-05 14:11:06 +02:00
Roman Pogribnyi
5c6ee2794d extracting force_fields 2014-08-04 12:08:37 +02:00
Roman Pogribnyi
4de2c21a40 closing file correctly 2014-08-03 17:45:54 +02:00
Roman Pogribnyi
73186af86e renaming of processed density field files 2014-08-02 13:04:30 +02:00
Roman Pogribnyi
2e06c6dbe7 progress textfield started, stopButton correct 2014-08-02 13:03:29 +02:00
Roman Pogribnyi
e7dbab06f4 unused file deleted 2014-08-01 19:36:27 +02:00
Roman Pogribnyi
0f8dabc1d7 imorting mantaflow correctly in Unix 2014-08-01 19:33:39 +02:00
Roman Pogribnyi
c6ca55e32e stop sim button 2014-07-31 23:13:21 +02:00
Roman Pogribnyi
79d6c89eaf frame_num field added, manta_sim in separate thread 2014-07-31 19:54:09 +02:00
Roman Pogribnyi
ce20c8d876 step, stop sim manta operations added 2014-07-31 19:52:50 +02:00
Roman Pogribnyi
473255d2f7 method for frame_step in separate thread added 2014-07-31 13:13:35 +02:00
Roman Pogribnyi
c8138097f7 per-step simulation added 2014-07-31 00:12:24 +02:00
Roman Pogribnyi
411ee40384 single-threaded re-runs work ok 2014-07-30 18:24:02 +02:00
Roman Pogribnyi
3122ee62d1 back to single-threaded method to debug manta re-run errors 2014-07-30 17:29:24 +02:00
Roman Pogribnyi
5f19242c58 new flags for manta module 2014-07-28 21:16:58 +02:00
Roman Pogribnyi
ada6ead6cc manta readfile to separate function 2014-07-28 12:09:00 +02:00
Roman Pogribnyi
e3aecd084e using user-defined frame bounds 2014-07-25 20:35:00 +02:00
Roman Pogribnyi
3643bf3be0 added start-end frame fields in UI 2014-07-25 19:40:31 +02:00
Roman Pogribnyi
06f05294cb function bodies moved to cpp file, some sim settings tweaked 2014-07-25 16:53:24 +02:00
Roman Pogribnyi
762a4b57a8 manta tun is separate thread 2014-07-24 14:54:32 +02:00
Roman Pogribnyi
15a2f381b0 class registration improved 2014-07-23 20:06:56 +02:00
Roman Pogribnyi
5e92c2770a debug output removed 2014-07-23 20:01:30 +02:00
Roman Pogribnyi
0f64929d79 added debug messages 2014-07-22 16:44:57 +02:00
Roman Pogribnyi
bab35daf74 unused files removed 2014-07-22 15:20:02 +02:00
Roman Pogribnyi
5bd23adb62 division on manta_pp and manta_full to switch between full module and pp files 2014-07-22 15:18:47 +02:00
Roman Pogribnyi
7752cfb1d8 cleaned cmakelists file 2014-07-21 16:48:52 +02:00
Roman Pogribnyi
fe44c97b37 unused plugin files removed 2014-07-21 16:47:34 +02:00
Roman Pogribnyi
8f9b4a3566 removing source duplicates 2014-07-17 15:36:20 +02:00
Roman Pogribnyi
ea0e959843 compiling & linking; unused paths deleted; compile flags for manta removed 2014-07-17 15:12:52 +02:00
Roman Pogribnyi
91921bb051 depends added, unused list commands removed 2014-07-17 13:51:43 +02:00
Roman Pogribnyi
c6e418c690 non-existing files generated and preprocessed 2014-07-17 13:20:29 +02:00
Roman Pogribnyi
1c2f537505 paths for repositioned manta_pp folder correct 2014-07-17 10:00:36 +02:00
Roman Pogribnyi
df1c4bb710 removing repository info 2014-07-17 10:00:36 +02:00
Roman Pogribnyi
eb64dca859 fixed prep-not-found issue,files compiling 2014-07-17 10:00:35 +02:00
2fd69c5185 Fix generating temporary files with prep binary, also comment out include of hgnfo header for now.
- I just uncommented failing code
- dunno whats up with hginfo, guess thats from external source versioncontrol of manta (?)
- pls disable openmp, due this branch was not merged lately and misses omp cmake fixes
I checked all is compiling fine now
2014-07-16 01:47:10 +02:00
Roman Pogribnyi
8a990a8318 correct prep binary location, debug messages instead of prep step 2014-07-15 16:24:32 +02:00
Roman Pogribnyi
25ef55b304 library creation for Win systems 2014-07-14 13:00:42 +02:00
Roman Pogribnyi
a70e4394ac removed pp files, preproessing during compiling step 2014-07-14 12:57:43 +02:00
Roman Pogribnyi
2071f5901a setting for debugging the linking issue 2014-07-12 16:00:50 +02:00
Roman Pogribnyi
41a28c2106 Compiling intermediate files for linking c++ code from bpy_interface.c 2014-07-10 23:02:13 +02:00
Roman Pogribnyi
8c3aedcec5 Big commit. Manta included in Blender Python. NOT ALL modules imported 2014-07-08 21:31:15 +02:00
Roman Pogribnyi
f80924027f importing manta module to interpreter 2014-07-02 20:13:12 +02:00
Roman Pogribnyi
37613a8cba *FAULTY* code, big commit: manta files, Cmake and Scons integration. Started work on full-cycle fluids 2014-07-02 11:50:03 +02:00
Roman Pogribnyi
f47b7784cf settings for SDF tweaked 2014-06-25 13:05:40 +02:00
Roman Pogribnyi
aa59cb6615 Running Manta in separate thread 2014-06-21 10:26:36 +02:00
Roman Pogribnyi
559ae8567c vorticity, SDF grids added 2014-06-21 10:25:13 +02:00
Roman Pogribnyi
efa2f69473 method for transforming meshes back from [-1,1] coords; sdf fields for obstacles and inflow meshes added 2014-06-19 15:05:05 +02:00
Roman Pogribnyi
7548135aec Manta vars initialization, support for inflow objs in setup file, *.obj export for bounding box[ -1,1] 2014-06-16 23:11:58 +02:00
Roman Pogribnyi
91c5025ce8 repositioning handled 2014-06-14 01:37:53 +02:00
Roman Pogribnyi
c781f59974 resizing meshes accordingly, tweaks in SDF method call 2014-06-14 00:40:05 +02:00
Roman Pogribnyi
7ae6959df9 Better handling of obj files when writing there 2014-06-13 22:07:20 +02:00
Roman Pogribnyi
7e0aa75de9 Setup file handles collision objs correctly 2014-06-13 22:05:29 +02:00
Roman Pogribnyi
b5b81bea79 correct file naming 2014-06-13 19:45:57 +02:00
Roman Pogribnyi
42567648a7 exporting Collision and flow objects as .obj files 2014-06-13 19:45:20 +02:00
Roman Pogribnyi
c249d3dad1 Noise settings UI 2014-06-10 23:52:45 +02:00
Roman Pogribnyi
c0ecba8002 UI for UVS count 2014-06-10 22:59:58 +02:00
Roman Pogribnyi
b37b145a95 indentation method added, minor fixes 2014-06-10 22:19:37 +02:00
Roman Pogribnyi
6a1ffeefd8 indents added; correct order of wavelets restored 2014-06-08 13:16:35 +02:00
Roman Pogribnyi
98d62932e5 setup file is correct 2014-06-07 17:59:10 +02:00
Roman Pogribnyi
8fddd571a1 flags, mock sources and obstacles. handling of octaves 2014-06-07 16:55:59 +02:00
Roman Pogribnyi
f6a5020d09 wavelet vars added 2014-06-07 16:38:52 +02:00
Roman Pogribnyi
0d979ce138 noise accounts for indentation 2014-06-07 16:16:30 +02:00
Roman Pogribnyi
44b4cf699d noise field name var 2014-06-06 23:42:23 +02:00
Roman Pogribnyi
9ed7be50aa Separate Solver creation function; 2D solver option implemented: UI + functionality 2014-06-06 23:39:00 +02:00
Roman Pogribnyi
1eae4069f7 Pressure function separated; Bundary Conditions set correctly 2014-06-05 18:47:37 +02:00
Roman Pogribnyi
a36bb2ae85 unused comments removed 2014-06-03 23:18:03 +02:00
Roman Pogribnyi
7177c3f129 separate function for semiLagrange advecttion. Using stringstream for script generation 2014-06-03 23:16:30 +02:00
Roman Pogribnyi
33e9a9e0ce Separate function for noise generation. Pressure syntax correct 2014-06-02 15:41:19 +02:00
Roman Pogribnyi
bcb5c61dc3 support for Domain Border Collisions added 2014-05-31 17:29:35 +02:00
Roman Pogribnyi
ac78fde848 operator to generate setup file added 2014-05-30 14:03:33 +02:00
Roman Pogribnyi
a009fb637b function to generate setup file added 2014-05-30 13:58:45 +02:00
Roman Pogribnyi
e7e5ef2c04 use_manta property added to smoke DNA 2014-05-30 13:45:43 +02:00
Roman Pogribnyi
2cf121ca35 Mantaflow UI added: tab and file generation button 2014-05-30 13:40:24 +02:00
Roman Pogribnyi
9ae7bd0cdb added manta.h to smoke cmake config 2014-05-30 13:17:32 +02:00
Roman Pogribnyi
60f32a6389 CMakeLists warnings restored 2014-05-30 13:15:25 +02:00
Roman Pogribnyi
e726908fb4 comments style fixed 2014-05-25 22:21:03 +02:00
Roman Pogribnyi
66f21314f9 added Manta.h for mantaflow integrtion; reading smoke simulation files 2014-05-25 00:44:12 +02:00
337 changed files with 83330 additions and 55698 deletions

View File

@@ -242,8 +242,7 @@ 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_FLUID "Enable Mantaflow Fluid Simulation Framework" ON)
option(WITH_MOD_REMESH "Enable Remesh Modifier" ON)
option(WITH_MOD_OCEANSIM "Enable Ocean Modifier" ON)

View File

@@ -30,9 +30,8 @@ set(WITH_INPUT_NDOF ON CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL 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_FLUID 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)

View File

@@ -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_FLUID 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)

View File

@@ -31,9 +31,8 @@ set(WITH_INPUT_NDOF ON CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL 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_FLUID 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)

View File

@@ -411,6 +411,10 @@ if(NOT WITH_TBB OR NOT TBB_FOUND)
message(STATUS "TBB not found, disabling OpenVDB")
set(WITH_OPENVDB OFF)
endif()
if(WITH_MOD_FLUID)
message(STATUS "TBB not found, disabling Fluid modifier")
set(WITH_MOD_FLUID OFF)
endif()
endif()
# CMake FindOpenMP doesn't know about AppleClang before 3.12, so provide custom flags.

View File

@@ -567,6 +567,10 @@ else()
message(STATUS "TBB disabled, also disabling OpenVDB")
set(WITH_OPENVDB OFF)
endif()
if(WITH_MOD_FLUID)
message(STATUS "TBB disabled, disabling Fluid modifier")
set(WITH_MOD_FLUID OFF)
endif()
endif()
# used in many places so include globally, like OpenGL

View File

@@ -18,10 +18,6 @@
* \ingroup intern
*/
/** \defgroup elbeem elbeem
* \ingroup intern
*/
/** \defgroup iksolver iksolver
* \ingroup intern
*/

View File

@@ -105,3 +105,7 @@ if(WITH_QUADRIFLOW)
set(QUADRIFLOW_CMAKE_CFG ${CMAKE_CURRENT_SOURCE_DIR}/quadriflow/blender_config.cmake)
add_subdirectory(quadriflow)
endif()
if(WITH_MOD_FLUID)
add_subdirectory(mantaflow)
endif()

203
extern/mantaflow/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,203 @@
# ***** 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")
add_definitions(-DWITH_FLUID=1)
set(MANTA_DEP
dependencies
)
set(MANTA_HLP
helper
)
set(MANTA_PP
preprocessed
)
if(WITH_TBB)
add_definitions(-DTBB=1)
endif()
if(WITH_OPENVDB)
add_definitions(-DOPENVDB=1)
endif()
set(INC
${MANTA_PP}
${MANTA_PP}/fileio
${MANTA_PP}/python
${MANTA_PP}/plugin
${MANTA_HLP}/pwrapper
${MANTA_HLP}/util
${MANTA_DEP}/cnpy
)
set(INC_SYS
${PYTHON_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
)
if(WITH_TBB)
list(APPEND INC_SYS
${TBB_INCLUDE_DIRS}
)
endif()
if(WITH_OPENVDB)
list(APPEND INC_SYS
${BOOST_INCLUDE_DIR}
${OPENEXR_INCLUDE_DIRS}
${OPENVDB_INCLUDE_DIRS}
)
endif()
set(SRC
${MANTA_DEP}/cnpy/cnpy.cpp
${MANTA_DEP}/cnpy/cnpy.h
${MANTA_PP}/commonkernels.h
${MANTA_PP}/commonkernels.h.reg.cpp
${MANTA_PP}/conjugategrad.cpp
${MANTA_PP}/conjugategrad.h
${MANTA_PP}/conjugategrad.h.reg.cpp
${MANTA_PP}/edgecollapse.cpp
${MANTA_PP}/edgecollapse.h
${MANTA_PP}/edgecollapse.h.reg.cpp
${MANTA_PP}/fastmarch.cpp
${MANTA_PP}/fastmarch.h
${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.cpp
${MANTA_PP}/fluidsolver.cpp
${MANTA_PP}/fluidsolver.h
${MANTA_PP}/fluidsolver.h.reg.cpp
${MANTA_PP}/general.cpp
${MANTA_PP}/general.h
${MANTA_PP}/general.h.reg.cpp
${MANTA_PP}/gitinfo.h
${MANTA_PP}/grid.cpp
${MANTA_PP}/grid.h
${MANTA_PP}/grid.h.reg.cpp
${MANTA_PP}/grid4d.cpp
${MANTA_PP}/grid4d.h
${MANTA_PP}/grid4d.h.reg.cpp
${MANTA_PP}/kernel.cpp
${MANTA_PP}/kernel.h
${MANTA_PP}/kernel.h.reg.cpp
${MANTA_PP}/levelset.cpp
${MANTA_PP}/levelset.h
${MANTA_PP}/levelset.h.reg.cpp
${MANTA_PP}/mesh.cpp
${MANTA_PP}/mesh.h
${MANTA_PP}/mesh.h.reg.cpp
${MANTA_PP}/movingobs.cpp
${MANTA_PP}/movingobs.h
${MANTA_PP}/movingobs.h.reg.cpp
${MANTA_PP}/multigrid.cpp
${MANTA_PP}/multigrid.h
${MANTA_PP}/multigrid.h.reg.cpp
${MANTA_PP}/noisefield.cpp
${MANTA_PP}/noisefield.h
${MANTA_PP}/noisefield.h.reg.cpp
${MANTA_PP}/particle.cpp
${MANTA_PP}/particle.h
${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.cpp
${MANTA_PP}/registration.cpp
${MANTA_PP}/shapes.cpp
${MANTA_PP}/shapes.h
${MANTA_PP}/shapes.h.reg.cpp
${MANTA_PP}/test.cpp
${MANTA_PP}/timing.cpp
${MANTA_PP}/timing.h
${MANTA_PP}/timing.h.reg.cpp
${MANTA_PP}/turbulencepart.cpp
${MANTA_PP}/turbulencepart.h
${MANTA_PP}/turbulencepart.h.reg.cpp
${MANTA_PP}/vortexpart.cpp
${MANTA_PP}/vortexpart.h
${MANTA_PP}/vortexpart.h.reg.cpp
${MANTA_PP}/vortexsheet.cpp
${MANTA_PP}/vortexsheet.h
${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(extern_mantaflow "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

222
extern/mantaflow/LICENSE vendored Normal file
View File

@@ -0,0 +1,222 @@
Copyright 2018, the mantaflow team. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-------------------------------------------------------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
-------------------------------------------------------------------------
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
------------------------------------------------------------------------------
APPENDIX: HOW TO APPLY THE APACHE LICENSE TO YOUR WORK
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "[]" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification
within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

11
extern/mantaflow/README.md vendored Normal file
View File

@@ -0,0 +1,11 @@
# Mantaflow #
Mantaflow is an open-source framework targeted at fluid simulation research in Computer Graphics.
Its parallelized C++ solver core, python scene definition interface and plugin system allow for quickly prototyping and testing new algorithms.
In addition, it provides a toolbox of examples for deep learning experiments with fluids. E.g., it contains examples
how to build convolutional neural network setups in conjunction with the [tensorflow framework](https://www.tensorflow.org).
For more information on how to install, run and code with Mantaflow, please head over to our home page at
[http://mantaflow.com](http://mantaflow.com)

102
extern/mantaflow/UPDATE.sh vendored Normal file
View File

@@ -0,0 +1,102 @@
#!/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
# Try to check out Mantaflow repository before building?
CLEAN_REPOSITORY=0
# Choose which multithreading platform to use for Mantaflow preprocessing
USE_OMP=0
USE_TBB=1
if [[ "$USE_OMP" -eq "1" && "$USE_TBB" -eq "1" ]]; then
echo "Cannot build Mantaflow for OpenMP and TBB at the same time"
exit 1
elif [[ "$USE_OMP" -eq "0" && "$USE_TBB" -eq "0" ]]; then
echo "WARNING: Building Mantaflow without multithreading"
else
if [[ "$USE_OMP" -eq "1" ]]; then
echo "Building Mantaflow with OpenMP multithreading"
elif [[ "$USE_TBB" -eq "1" ]]; then
echo "Building Mantaflow with TBB multithreading"
fi
fi
# ==================== 2) BUILD MANTAFLOW ================================================
# For OpenMP, we need non-default compiler to build Mantaflow on OSX
if [[ "$USE_OMP" -eq "1" && "$OSTYPE" == "darwin"* ]]; then
export CC=/usr/local/opt/llvm/bin/clang
export CXX=/usr/local/opt/llvm/bin/clang++
export LDFLAGS=-L/usr/local/opt/llvm/lib
fi
cd $MANTA_INSTALLATION
# Check-out manta repo from git?
if [[ "$CLEAN_REPOSITORY" -eq "1" ]]; then
if cd mantaflowgit/; then git pull; else git clone git@bitbucket.org:thunil/mantaflowgit.git; cd mantaflowgit; fi
git checkout develop
fi
MANTA_BUILD_PATH=$MANTA_INSTALLATION/mantaflowgit/build_blender/
mkdir -p $MANTA_BUILD_PATH
cd $MANTA_BUILD_PATH
cmake .. -DGUI=OFF -DOPENMP=$USE_OMP -DTBB=$USE_TBB -DBLENDER=ON -DPREPDEBUG=ON && make -j8
# ==================== 3) COPY MANTAFLOW FILES TO BLENDER ROOT ===========================
mkdir -p $BLENDER_INSTALLATION/blender/tmp/dependencies/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/dependencies/cnpy "$_"
mkdir -p $BLENDER_INSTALLATION/blender/tmp/helper/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/source/util "$_"
mkdir -p $BLENDER_INSTALLATION/blender/tmp/helper/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/source/pwrapper "$_"
mkdir -p $BLENDER_INSTALLATION/blender/tmp/preprocessed/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/build_blender/pp/source/. "$_"
# Remove some files that are not need in Blender
rm $BLENDER_INSTALLATION/blender/tmp/dependencies/cnpy/example1.cpp
rm $BLENDER_INSTALLATION/blender/tmp/helper/pwrapper/pymain.cpp
rm $BLENDER_INSTALLATION/blender/tmp/preprocessed/*.reg
rm $BLENDER_INSTALLATION/blender/tmp/preprocessed/python/*.reg
rm $BLENDER_INSTALLATION/blender/tmp/preprocessed/fileio/*.reg
# ==================== 4) CLANG-FORMAT ===================================================
cd $BLENDER_INSTALLATION/blender/tmp/
echo "Applying clang format to Mantaflow source files"
find . -iname *.h -o -iname *.cpp | xargs clang-format --verbose -i -style=file
find . -iname *.h -o -iname *.cpp | xargs dos2unix --verbose
# ==================== 5) MOVE MANTAFLOW FILES TO EXTERN/ ================================
BLENDER_MANTA_EXTERN=$BLENDER_INSTALLATION/blender/extern/mantaflow/
BLENDER_TMP=$BLENDER_INSTALLATION/blender/tmp
BLENDER_TMP_DEP=$BLENDER_TMP/dependencies
BLENDER_TMP_HLP=$BLENDER_TMP/helper
BLENDER_TMP_PP=$BLENDER_TMP/preprocessed
# Move files from tmp dir to extern/
cp -Rf $BLENDER_TMP_DEP $BLENDER_MANTA_EXTERN
cp -Rf $BLENDER_TMP_HLP $BLENDER_MANTA_EXTERN
cp -Rf $BLENDER_TMP_PP $BLENDER_MANTA_EXTERN
# Copy the Mantaflow license and readme files as well
cp -Rf $MANTA_INSTALLATION/mantaflowgit/LICENSE $BLENDER_MANTA_EXTERN
cp -Rf $MANTA_INSTALLATION/mantaflowgit/README.md $BLENDER_MANTA_EXTERN
# Cleanup left over dir
rm -r $BLENDER_TMP
echo "Successfully copied new Mantaflow files to" $BLENDER_INSTALLATION/blender/extern/mantaflow/
# ==================== 6) 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.

View File

@@ -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.

View File

@@ -0,0 +1,385 @@
// 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;
}

View File

@@ -0,0 +1,310 @@
// 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;
}
} // namespace cnpy
#endif

View File

@@ -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

View File

@@ -0,0 +1,132 @@
/******************************************************************************
*
* 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);
int numDims = PyArray_NDIM(pParent);
long *pDims = (long *)PyArray_DIMS(pParent);
pData = PyArray_DATA(pParent);
TotalSize = PyArray_SIZE(pParent);
Dims = std::vector<long>(&pDims[0], &pDims[numDims]);
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;
// }
} // namespace Manta

View File

@@ -0,0 +1,86 @@
/******************************************************************************
*
* 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;
std::vector<long> Dims;
private:
void *pParentPyArray;
};
// template<> PyArrayContainer* fromPyPtr<PyArrayContainer>(PyObject* obj, std::vector<void*>*
// tmp);
template<> PyArrayContainer fromPy<PyArrayContainer>(PyObject *obj);
} // namespace Manta
# endif
#endif

View File

@@ -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
*
* 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 Manta

View File

@@ -0,0 +1,126 @@
/******************************************************************************
*
* 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 Manta
# endif
#endif

View File

@@ -0,0 +1,568 @@
/******************************************************************************
*
* 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 Manta

View File

@@ -0,0 +1,251 @@
/******************************************************************************
*
* 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 Manta
# if NUMPY == 1
# include "numpyWrap.h"
# endif
# endif
#endif

View File

@@ -0,0 +1,414 @@
/******************************************************************************
*
* 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 Manta

View File

@@ -0,0 +1,48 @@
/******************************************************************************
*
* 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

View File

@@ -0,0 +1,784 @@
/******************************************************************************
*
* 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 Pb

View File

@@ -0,0 +1,106 @@
/******************************************************************************
*
* 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;
} // namespace Manta
// **************************************************
// 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 Manta
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);
} // namespace Pb
#endif

View File

@@ -0,0 +1,79 @@
/******************************************************************************
*
* 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 Manta
#endif

324
extern/mantaflow/helper/util/interpol.h vendored Normal file
View File

@@ -0,0 +1,324 @@
/******************************************************************************
*
* 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 Manta
#endif

View File

@@ -0,0 +1,204 @@
/******************************************************************************
*
* 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 Manta
#endif

View File

@@ -0,0 +1,394 @@
/******************************************************************************
*
* 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 Manta
#endif /* MATRIXBASE_H */

308
extern/mantaflow/helper/util/mcubes.h vendored Normal file
View File

@@ -0,0 +1,308 @@
/******************************************************************************
*
* 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

View File

@@ -0,0 +1,103 @@
/******************************************************************************
*
* 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 Manta
#endif

View File

@@ -0,0 +1,429 @@
/******************************************************************************
*
* 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 Manta
#endif

1112
extern/mantaflow/helper/util/rcmatrix.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,312 @@
/******************************************************************************
*
* 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;
}
}; // namespace 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);
}
}; // namespace Manta

View File

@@ -0,0 +1,205 @@
/******************************************************************************
*
* 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
}; // namespace Manta
#endif

214
extern/mantaflow/helper/util/solvana.h vendored Normal file
View File

@@ -0,0 +1,214 @@
/******************************************************************************
*
* 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

View File

@@ -0,0 +1,50 @@
/******************************************************************************
*
* 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);
}
} // namespace Manta

515
extern/mantaflow/helper/util/vector4d.h vendored Normal file
View File

@@ -0,0 +1,515 @@
/******************************************************************************
*
* 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 Manta
#endif

View File

@@ -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
*
* Basic vector class
*
******************************************************************************/
#include "vectorbase.h"
using namespace std;
namespace Manta {
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());
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);
}
} // namespace Manta

View File

@@ -0,0 +1,679 @@
/******************************************************************************
*
* 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 Manta
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep link).
#include "commonkernels.h"
namespace Manta {
extern "C" {
void PbRegister_file_2()
{
}
}
} // namespace Manta

View File

@@ -0,0 +1,719 @@
// 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);
}
}
}; // namespace Manta

View File

@@ -0,0 +1,479 @@
// 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 Manta
#endif

View File

@@ -0,0 +1,13 @@
// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep link).
#include "conjugategrad.h"
namespace Manta {
extern "C" {
void PbRegister_file_3()
{
}
}
} // namespace Manta

View File

@@ -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
*
* 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 Manta

View File

@@ -0,0 +1,51 @@
// 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);
} // namespace Manta
#endif

View File

@@ -0,0 +1,13 @@
// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep link).
#include "edgecollapse.h"
namespace Manta {
extern "C" {
void PbRegister_file_19()
{
}
}
} // namespace Manta

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,241 @@
// 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 Manta
#endif

View File

@@ -0,0 +1,13 @@
// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep link).
#include "fastmarch.h"
namespace Manta {
extern "C" {
void PbRegister_file_5()
{
}
}
} // namespace Manta

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,490 @@
// 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 Manta

View File

@@ -0,0 +1,342 @@
// 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 Manta

View File

@@ -0,0 +1,81 @@
// 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 Manta
#endif

View File

@@ -0,0 +1,13 @@
// 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()
{
}
}
} // namespace Manta

View File

@@ -0,0 +1,397 @@
// 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);
}
}
} // namespace Manta

View File

@@ -0,0 +1,395 @@
// 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() const
{
return mDt;
}
inline Real getDx() const
{
return 1.0 / mGridSize.max();
}
inline Real getTime() const
{
return mTimeTotal;
}
//! 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;
}
//! Per frame duration. 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;
}
protected:
Vec3i mGridSize;
const int mDim;
bool mLockDt;
//! 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
;
} // namespace Manta
#endif

View File

@@ -0,0 +1,70 @@
// 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);
}
}
} // namespace Manta

View File

@@ -0,0 +1,167 @@
// 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 Manta

247
extern/mantaflow/preprocessed/general.h vendored Normal file
View File

@@ -0,0 +1,247 @@
// 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_FLUID, make sure we have "BLENDER"
#ifndef BLENDER
# ifdef WITH_FLUID
# 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 Manta
#endif

View File

@@ -0,0 +1,13 @@
// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep link).
#include "general.h"
namespace Manta {
extern "C" {
void PbRegister_file_1()
{
}
}
} // namespace Manta

View File

@@ -0,0 +1,3 @@
#define MANTA_GIT_VERSION "commit 761849c592daaea320f9026768b5a0750528009c"

2939
extern/mantaflow/preprocessed/grid.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

2260
extern/mantaflow/preprocessed/grid.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,246 @@
// 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_37);
static const Pb::Register _R_28("FlagGrid", "initDomain", FlagGrid::_W_38);
static const Pb::Register _R_29("FlagGrid", "updateFromLevelset", FlagGrid::_W_39);
static const Pb::Register _R_30("FlagGrid", "fillGrid", FlagGrid::_W_40);
static const Pb::Register _R_31("FlagGrid", "countCells", FlagGrid::_W_41);
#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>", "permuteAxes", Grid<int>::_W_24);
static const Pb::Register _R_49("Grid<int>", "permuteAxesCopyToGrid", Grid<int>::_W_25);
static const Pb::Register _R_50("Grid<int>", "getMaxAbs", Grid<int>::_W_26);
static const Pb::Register _R_51("Grid<int>", "getMax", Grid<int>::_W_27);
static const Pb::Register _R_52("Grid<int>", "getMin", Grid<int>::_W_28);
static const Pb::Register _R_53("Grid<int>", "getL1", Grid<int>::_W_29);
static const Pb::Register _R_54("Grid<int>", "getL2", Grid<int>::_W_30);
static const Pb::Register _R_55("Grid<int>", "setBound", Grid<int>::_W_31);
static const Pb::Register _R_56("Grid<int>", "setBoundNeumann", Grid<int>::_W_32);
static const Pb::Register _R_57("Grid<int>", "getDataPointer", Grid<int>::_W_33);
static const Pb::Register _R_58("Grid<int>", "printGrid", Grid<int>::_W_34);
static const Pb::Register _R_59("Grid<Real>", "Grid<Real>", "GridBase");
template<> const char *Namify<Grid<Real>>::S = "Grid<Real>";
static const Pb::Register _R_60("Grid<Real>", "Grid", Grid<Real>::_W_9);
static const Pb::Register _R_61("Grid<Real>", "save", Grid<Real>::_W_10);
static const Pb::Register _R_62("Grid<Real>", "load", Grid<Real>::_W_11);
static const Pb::Register _R_63("Grid<Real>", "clear", Grid<Real>::_W_12);
static const Pb::Register _R_64("Grid<Real>", "copyFrom", Grid<Real>::_W_13);
static const Pb::Register _R_65("Grid<Real>", "getGridType", Grid<Real>::_W_14);
static const Pb::Register _R_66("Grid<Real>", "add", Grid<Real>::_W_15);
static const Pb::Register _R_67("Grid<Real>", "sub", Grid<Real>::_W_16);
static const Pb::Register _R_68("Grid<Real>", "setConst", Grid<Real>::_W_17);
static const Pb::Register _R_69("Grid<Real>", "addConst", Grid<Real>::_W_18);
static const Pb::Register _R_70("Grid<Real>", "addScaled", Grid<Real>::_W_19);
static const Pb::Register _R_71("Grid<Real>", "mult", Grid<Real>::_W_20);
static const Pb::Register _R_72("Grid<Real>", "multConst", Grid<Real>::_W_21);
static const Pb::Register _R_73("Grid<Real>", "clamp", Grid<Real>::_W_22);
static const Pb::Register _R_74("Grid<Real>", "stomp", Grid<Real>::_W_23);
static const Pb::Register _R_75("Grid<Real>", "permuteAxes", Grid<Real>::_W_24);
static const Pb::Register _R_76("Grid<Real>", "permuteAxesCopyToGrid", Grid<Real>::_W_25);
static const Pb::Register _R_77("Grid<Real>", "getMaxAbs", Grid<Real>::_W_26);
static const Pb::Register _R_78("Grid<Real>", "getMax", Grid<Real>::_W_27);
static const Pb::Register _R_79("Grid<Real>", "getMin", Grid<Real>::_W_28);
static const Pb::Register _R_80("Grid<Real>", "getL1", Grid<Real>::_W_29);
static const Pb::Register _R_81("Grid<Real>", "getL2", Grid<Real>::_W_30);
static const Pb::Register _R_82("Grid<Real>", "setBound", Grid<Real>::_W_31);
static const Pb::Register _R_83("Grid<Real>", "setBoundNeumann", Grid<Real>::_W_32);
static const Pb::Register _R_84("Grid<Real>", "getDataPointer", Grid<Real>::_W_33);
static const Pb::Register _R_85("Grid<Real>", "printGrid", Grid<Real>::_W_34);
static const Pb::Register _R_86("Grid<Vec3>", "Grid<Vec3>", "GridBase");
template<> const char *Namify<Grid<Vec3>>::S = "Grid<Vec3>";
static const Pb::Register _R_87("Grid<Vec3>", "Grid", Grid<Vec3>::_W_9);
static const Pb::Register _R_88("Grid<Vec3>", "save", Grid<Vec3>::_W_10);
static const Pb::Register _R_89("Grid<Vec3>", "load", Grid<Vec3>::_W_11);
static const Pb::Register _R_90("Grid<Vec3>", "clear", Grid<Vec3>::_W_12);
static const Pb::Register _R_91("Grid<Vec3>", "copyFrom", Grid<Vec3>::_W_13);
static const Pb::Register _R_92("Grid<Vec3>", "getGridType", Grid<Vec3>::_W_14);
static const Pb::Register _R_93("Grid<Vec3>", "add", Grid<Vec3>::_W_15);
static const Pb::Register _R_94("Grid<Vec3>", "sub", Grid<Vec3>::_W_16);
static const Pb::Register _R_95("Grid<Vec3>", "setConst", Grid<Vec3>::_W_17);
static const Pb::Register _R_96("Grid<Vec3>", "addConst", Grid<Vec3>::_W_18);
static const Pb::Register _R_97("Grid<Vec3>", "addScaled", Grid<Vec3>::_W_19);
static const Pb::Register _R_98("Grid<Vec3>", "mult", Grid<Vec3>::_W_20);
static const Pb::Register _R_99("Grid<Vec3>", "multConst", Grid<Vec3>::_W_21);
static const Pb::Register _R_100("Grid<Vec3>", "clamp", Grid<Vec3>::_W_22);
static const Pb::Register _R_101("Grid<Vec3>", "stomp", Grid<Vec3>::_W_23);
static const Pb::Register _R_102("Grid<Vec3>", "permuteAxes", Grid<Vec3>::_W_24);
static const Pb::Register _R_103("Grid<Vec3>", "permuteAxesCopyToGrid", Grid<Vec3>::_W_25);
static const Pb::Register _R_104("Grid<Vec3>", "getMaxAbs", Grid<Vec3>::_W_26);
static const Pb::Register _R_105("Grid<Vec3>", "getMax", Grid<Vec3>::_W_27);
static const Pb::Register _R_106("Grid<Vec3>", "getMin", Grid<Vec3>::_W_28);
static const Pb::Register _R_107("Grid<Vec3>", "getL1", Grid<Vec3>::_W_29);
static const Pb::Register _R_108("Grid<Vec3>", "getL2", Grid<Vec3>::_W_30);
static const Pb::Register _R_109("Grid<Vec3>", "setBound", Grid<Vec3>::_W_31);
static const Pb::Register _R_110("Grid<Vec3>", "setBoundNeumann", Grid<Vec3>::_W_32);
static const Pb::Register _R_111("Grid<Vec3>", "getDataPointer", Grid<Vec3>::_W_33);
static const Pb::Register _R_112("Grid<Vec3>", "printGrid", Grid<Vec3>::_W_34);
#endif
#ifdef _C_GridBase
static const Pb::Register _R_113("GridBase", "GridBase", "PbClass");
template<> const char *Namify<GridBase>::S = "GridBase";
static const Pb::Register _R_114("GridBase", "GridBase", GridBase::_W_0);
static const Pb::Register _R_115("GridBase", "getSizeX", GridBase::_W_1);
static const Pb::Register _R_116("GridBase", "getSizeY", GridBase::_W_2);
static const Pb::Register _R_117("GridBase", "getSizeZ", GridBase::_W_3);
static const Pb::Register _R_118("GridBase", "getSize", GridBase::_W_4);
static const Pb::Register _R_119("GridBase", "is3D", GridBase::_W_5);
static const Pb::Register _R_120("GridBase", "is4D", GridBase::_W_6);
static const Pb::Register _R_121("GridBase", "getSizeT", GridBase::_W_7);
static const Pb::Register _R_122("GridBase", "getStrideT", GridBase::_W_8);
#endif
#ifdef _C_MACGrid
static const Pb::Register _R_123("MACGrid", "MACGrid", "Grid<Vec3>");
template<> const char *Namify<MACGrid>::S = "MACGrid";
static const Pb::Register _R_124("MACGrid", "MACGrid", MACGrid::_W_35);
static const Pb::Register _R_125("MACGrid", "setBoundMAC", MACGrid::_W_36);
#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);
KEEP_UNUSED(_R_120);
KEEP_UNUSED(_R_121);
KEEP_UNUSED(_R_122);
KEEP_UNUSED(_R_123);
KEEP_UNUSED(_R_124);
KEEP_UNUSED(_R_125);
}
}
} // namespace Manta

1798
extern/mantaflow/preprocessed/grid4d.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

1558
extern/mantaflow/preprocessed/grid4d.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}
}
} // namespace Manta

View File

@@ -0,0 +1,61 @@
// 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 Manta

99
extern/mantaflow/preprocessed/kernel.h vendored Normal file
View File

@@ -0,0 +1,99 @@
// 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 Manta
// all kernels will automatically be added to the "Kernels" group in doxygen
#endif

View File

@@ -0,0 +1,13 @@
// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep link).
#include "kernel.h"
namespace Manta {
extern "C" {
void PbRegister_file_15()
{
}
}
} // namespace Manta

View File

@@ -0,0 +1,876 @@
// 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, const FlagGrid *flags, int subtractType)
: KernelBase(&a, 0), a(a), b(b), flags(flags), subtractType(subtractType)
{
runMessage();
run();
}
inline void op(IndexInt idx,
Grid<Real> &a,
const Grid<Real> &b,
const FlagGrid *flags,
int subtractType) const
{
if (flags && ((*flags)(idx)&subtractType) == 0)
return;
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;
inline const FlagGrid *getArg2()
{
return flags;
}
typedef FlagGrid type2;
inline int &getArg3()
{
return subtractType;
}
typedef int type3;
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, flags, subtractType);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
Grid<Real> &a;
const Grid<Real> &b;
const FlagGrid *flags;
int subtractType;
};
void LevelsetGrid::subtract(const LevelsetGrid &o, const FlagGrid *flags, const int subtractType)
{
KnSubtract(*this, o, flags, subtractType);
}
//! 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 maxDepth, int boundaryWidth)
{
Real curVal, i1, i2, j1, j2, k1, k2;
Vec3i c, cTmp;
std::stack<Vec3i> undoPos;
std::stack<Real> undoVal;
std::stack<Vec3i> todoPos;
FOR_IJK_BND(*this, boundaryWidth)
{
curVal = 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 (curVal < 0.)
continue;
if (curVal > 0. && i1 > 0. && i2 > 0. && j1 > 0. && j2 > 0. && k1 > 0. && k2 > 0.)
continue;
/* Cell at c is positive (outside) and has at least one negative (inside) neighbour cell */
c = Vec3i(i, j, k);
/* Current cell is outside and has inside neighbour(s) */
undoPos.push(c);
undoVal.push(curVal);
todoPos.push(c);
/* Enforce negative cell - if search depth gets exceeded this will be reverted to the original
* value */
mData[index(c.x, c.y, c.z)] = -0.5;
while (!todoPos.empty()) {
todoPos.pop();
/* Add neighbouring positive (inside) cells to stacks and set negavtive cell value */
if (c.x > 0 && mData[index(c.x - 1, c.y, c.z)] > 0.) {
cTmp = Vec3i(c.x - 1, c.y, c.z);
undoPos.push(cTmp);
undoVal.push(mData[index(cTmp)]);
todoPos.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);
undoPos.push(cTmp);
undoVal.push(mData[index(cTmp)]);
todoPos.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);
undoPos.push(cTmp);
undoVal.push(mData[index(cTmp)]);
todoPos.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);
undoPos.push(cTmp);
undoVal.push(mData[index(cTmp)]);
todoPos.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);
undoPos.push(cTmp);
undoVal.push(mData[index(cTmp)]);
todoPos.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);
undoPos.push(cTmp);
undoVal.push(mData[index(cTmp)]);
todoPos.push(cTmp);
mData[index(cTmp)] = -0.5;
}
/* Restore original value in cells if undo needed ie once cell undo count exceeds given limit
*/
if (undoPos.size() > maxDepth) {
/* Clear todo stack */
while (!todoPos.empty()) {
todoPos.pop();
}
/* Clear undo stack and revert value */
while (!undoPos.empty()) {
c = undoPos.top();
curVal = undoVal.top();
undoPos.pop();
undoVal.pop();
mData[index(c.x, c.y, c.z)] = curVal;
}
break;
}
/* Ensure that undo stack is cleared at the end if no more items in todo stack left */
if (todoPos.empty()) {
while (!undoPos.empty()) {
undoPos.pop();
}
while (!undoVal.empty()) {
undoVal.pop();
}
}
/* Pop value for next while iteration */
else {
c = todoPos.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 Manta

245
extern/mantaflow/preprocessed/levelset.h vendored Normal file
View File

@@ -0,0 +1,245 @@
// 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, const FlagGrid *flags = NULL, const int subtractType = 0);
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);
const FlagGrid *flags = _args.getPtrOpt<FlagGrid>("flags", 1, NULL, &_lock);
const int subtractType = _args.getOpt<int>("subtractType", 2, 0, &_lock);
pbo->_args.copy(_args);
_retval = getPyNone();
pbo->subtract(o, flags, subtractType);
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 maxDepth = 10, int boundaryWidth = 1);
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 maxDepth = _args.getOpt<int>("maxDepth", 0, 10, &_lock);
int boundaryWidth = _args.getOpt<int>("boundaryWidth", 1, 1, &_lock);
pbo->_args.copy(_args);
_retval = getPyNone();
pbo->fillHoles(maxDepth, boundaryWidth);
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 Manta
#endif

View File

@@ -0,0 +1,32 @@
// 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);
}
}
} // namespace Manta

2733
extern/mantaflow/preprocessed/mesh.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

1690
extern/mantaflow/preprocessed/mesh.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,239 @@
// 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);
}
}
} // namespace Manta

View File

@@ -0,0 +1,112 @@
// 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 Manta

View File

@@ -0,0 +1,164 @@
// 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 Manta
#endif

View File

@@ -0,0 +1,26 @@
// 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);
}
}
} // namespace Manta

File diff suppressed because it is too large Load Diff

View File

@@ -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.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 Manta
#endif

View File

@@ -0,0 +1,13 @@
// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep link).
#include "multigrid.h"
namespace Manta {
extern "C" {
void PbRegister_file_4()
{
}
}
} // namespace Manta

View File

@@ -0,0 +1,325 @@
// 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;
}
}
} // namespace Manta

View File

@@ -0,0 +1,635 @@
// 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 Manta
#endif

View File

@@ -0,0 +1,60 @@
// 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);
}
}
} // namespace Manta

1620
extern/mantaflow/preprocessed/particle.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

2582
extern/mantaflow/preprocessed/particle.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,437 @@
// 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);
}
}
} // namespace Manta

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,496 @@
// 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 Manta

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,435 @@
// 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 Manta

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,802 @@
// 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,
const MACGrid *obvel = 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,
MACGrid *obvel = 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,
obvel,
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);
MACGrid *obvel = _args.getPtrOpt<MACGrid>("obvel", 15, 0, &_lock);
Real gfClamp = _args.getOpt<Real>("gfClamp", 16, 1e-04, &_lock);
Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 17, 1.5, &_lock);
Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 18, 1e-3, &_lock);
int preconditioner = _args.getOpt<int>("preconditioner", 19, 1, &_lock);
bool zeroPressureFixing = _args.getOpt<bool>("zeroPressureFixing", 20, false, &_lock);
const Grid<Real> *curv = _args.getPtrOpt<Grid<Real>>("curv", 21, NULL, &_lock);
const Real surfTens = _args.getOpt<Real>("surfTens", 22, 0., &_lock);
_retval = getPyNone();
PD_fluid_guiding(vel,
velT,
pressure,
flags,
weight,
blurRadius,
theta,
tau,
sigma,
epsRel,
epsAbs,
maxIters,
phi,
perCellCorr,
fractions,
obvel,
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);
}
}
} // namespace Manta

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,578 @@
// 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 Manta

View File

@@ -0,0 +1,780 @@
// 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 Manta

Some files were not shown because too many files have changed in this diff Show More