diff options
author | Daniel Genrich <daniel.genrich@gmx.net> | 2012-05-20 21:25:45 +0400 |
---|---|---|
committer | Daniel Genrich <daniel.genrich@gmx.net> | 2012-05-20 21:25:45 +0400 |
commit | 37ed2e4f46d43c6011ee756c3e6b0062816bdac6 (patch) | |
tree | 95f33620156353abc94fc22fc4355d8cde9435fb | |
parent | f3ed42fd4b58d329641b4e76bcc617df83782b00 (diff) |
- Use Smoke code from trunk again:
Unforeseen problems: The new code uses hidden arrays, file based functions. Nils himself describes the code as following in one of his new papers "Unuseable for rising smoke". What a bummer.
- New approach: Backport features as moving obstacles, preconditioned conjugate gradient solver, etc.
- This commit also contains the following code:
Better pressure and divergence calculation, idea taken from NVIDIA (graphic gems #3)
65 files changed, 8114 insertions, 15889 deletions
diff --git a/intern/smoke/CMakeLists.txt b/intern/smoke/CMakeLists.txt index 8cac5f2daa3..9524f7b2935 100644 --- a/intern/smoke/CMakeLists.txt +++ b/intern/smoke/CMakeLists.txt @@ -24,9 +24,9 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - intern/util - intern/source + intern ../memutil + ../../extern/bullet2/src ) set(INC_SYS @@ -35,44 +35,68 @@ set(INC_SYS ) set(SRC + intern/EIGENVALUE_HELPER.cpp + intern/FLUID_3D.cpp + intern/FLUID_3D_SOLVERS.cpp + intern/FLUID_3D_STATIC.cpp + intern/LU_HELPER.cpp + intern/SPHERE.cpp + intern/WTURBULENCE.cpp intern/smoke_API.cpp - - intern/source/advectionplugins.cpp - intern/source/animplugins.cpp - intern/source/conjugategrad.cpp - intern/source/fileio.cpp - intern/source/fluidsolver.cpp - intern/source/glutgui.cpp - intern/source/guihelpers.cpp - intern/source/initplugins.cpp - intern/source/smoke.cpp - intern/source/poissonsolvers.cpp - intern/source/smokeplugins.cpp - intern/source/solverinit.cpp - intern/source/solverparams.cpp - intern/source/stdplugins.cpp - intern/source/vortexpart.cpp - intern/source/vortexplugins.cpp - - intern/util/globals.cpp - intern/util/paramset.cpp + + extern/smoke_API.h + intern/EIGENVALUE_HELPER.h + intern/FFT_NOISE.h + intern/FLUID_3D.h + intern/IMAGE.h + intern/INTERPOLATE.h + intern/LU_HELPER.h + intern/MERSENNETWISTER.h + intern/OBSTACLE.h + intern/SPHERE.h + intern/VEC3.h + intern/WAVELET_NOISE.h + intern/WTURBULENCE.h + intern/tnt/jama_eig.h + intern/tnt/jama_lu.h + intern/tnt/tnt.h + intern/tnt/tnt_array1d.h + intern/tnt/tnt_array1d_utils.h + intern/tnt/tnt_array2d.h + intern/tnt/tnt_array2d_utils.h + intern/tnt/tnt_array3d.h + intern/tnt/tnt_array3d_utils.h + intern/tnt/tnt_cmat.h + intern/tnt/tnt_fortran_array1d.h + intern/tnt/tnt_fortran_array1d_utils.h + intern/tnt/tnt_fortran_array2d.h + intern/tnt/tnt_fortran_array2d_utils.h + intern/tnt/tnt_fortran_array3d.h + intern/tnt/tnt_fortran_array3d_utils.h + intern/tnt/tnt_i_refvec.h + intern/tnt/tnt_math_utils.h + intern/tnt/tnt_sparse_matrix_csr.h + intern/tnt/tnt_stopwatch.h + intern/tnt/tnt_subscript.h + intern/tnt/tnt_vec.h + intern/tnt/tnt_version.h ) # quiet -Wundef add_definitions(-DDDF_DEBUG=0) if(WITH_OPENMP) - add_definitions(-DDDF_OPENMP=1) + add_definitions(-DPARALLEL=1) else() - add_definitions(-DDDF_OPENMP=0) + add_definitions(-DPARALLEL=0) endif() -#if(WITH_FFTW3) -# add_definitions(-DWITH_FFTW3) -# list(APPEND INC -# ${FFTW3_INCLUDE_DIRS} -# ) -#endif() +if(WITH_FFTW3) + add_definitions(-DWITH_FFTW3) + list(APPEND INC + ${FFTW3_INCLUDE_DIRS} + ) +endif() blender_add_lib(bf_intern_smoke "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/smoke/SConscript b/intern/smoke/SConscript index 3ede5a97640..0511257d319 100644 --- a/intern/smoke/SConscript +++ b/intern/smoke/SConscript @@ -2,20 +2,21 @@ Import ('env') sources = env.Glob('intern/*.cpp') -sources += env.Glob('intern/util/*.cpp') -sources += env.Glob('intern/source/*.cpp') incs = '' -defs = ' DDF_GLUTGUI=0 ' +defs = '' if env['WITH_BF_OPENMP']: if env['OURPLATFORM'] == 'linuxcross': incs += ' ' + env['BF_OPENMP_INC'] - defs += ' DDF_OPENMP=1' + defs += ' PARALLEL=1' incs += ' ' + env['BF_PNG_INC'] + ' ' + env['BF_ZLIB_INC'] -incs += ' intern intern/util intern/source ' +incs += ' intern ../../extern/bullet2/src ../memutil ../guardealloc ' +if env['WITH_BF_FFTW3']: + defs += ' WITH_FFTW3' + incs += env['BF_FFTW3_INC'] env.BlenderLib ('bf_intern_smoke', sources, Split(incs), Split(defs), libtype=['intern'], priority=[40] ) diff --git a/intern/smoke/extern/smoke_API.h b/intern/smoke/extern/smoke_API.h index d9273db97ed..d5a43c19929 100644 --- a/intern/smoke/extern/smoke_API.h +++ b/intern/smoke/extern/smoke_API.h @@ -53,6 +53,8 @@ float *smoke_get_velocity_x(struct FLUID_3D *fluid); float *smoke_get_velocity_y(struct FLUID_3D *fluid); float *smoke_get_velocity_z(struct FLUID_3D *fluid); +float *smoke_get_pressure(struct FLUID_3D *fluid); + /* Moving obstacle velocity provided by blender */ void smoke_get_ob_velocity(struct FLUID_3D *fluid, float **x, float **y, float **z); @@ -61,7 +63,6 @@ float *smoke_get_force_y(struct FLUID_3D *fluid); float *smoke_get_force_z(struct FLUID_3D *fluid); unsigned char *smoke_get_obstacle(struct FLUID_3D *fluid); -unsigned char *smoke_get_obstacle_anim(struct FLUID_3D *fluid); size_t smoke_get_index(int x, int max_x, int y, int max_y, int z); size_t smoke_get_index2d(int x, int max_x, int y); diff --git a/intern/smoke/intern/COPYING b/intern/smoke/intern/COPYING deleted file mode 100644 index d511905c164..00000000000 --- a/intern/smoke/intern/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/intern/smoke/intern/EIGENVALUE_HELPER.cpp b/intern/smoke/intern/EIGENVALUE_HELPER.cpp new file mode 100644 index 00000000000..4910a2b42a7 --- /dev/null +++ b/intern/smoke/intern/EIGENVALUE_HELPER.cpp @@ -0,0 +1,888 @@ +/** \file smoke/intern/EIGENVALUE_HELPER.cpp + * \ingroup smoke + */ + +#include "EIGENVALUE_HELPER.h" + + +void Eigentred2(sEigenvalue& eval) { + + // This is derived from the Algol procedures tred2 by + // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for + // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutine in EISPACK. + + int n=eval.n; + + for (int j = 0; j < n; j++) { + eval.d[j] = eval.V[n-1][j]; + } + + // Householder reduction to tridiagonal form. + + for (int i = n-1; i > 0; i--) { + + // Scale to avoid under/overflow. + + float scale = 0.0; + float h = 0.0; + for (int k = 0; k < i; k++) { + scale = scale + fabs(eval.d[k]); + } + if (scale == 0.0) { + eval.e[i] = eval.d[i-1]; + for (int j = 0; j < i; j++) { + eval.d[j] = eval.V[i-1][j]; + eval.V[i][j] = 0.0; + eval.V[j][i] = 0.0; + } + } else { + + // Generate Householder vector. + + for (int k = 0; k < i; k++) { + eval.d[k] /= scale; + h += eval.d[k] * eval.d[k]; + } + float f = eval.d[i-1]; + float g = sqrt(h); + if (f > 0) { + g = -g; + } + eval.e[i] = scale * g; + h = h - f * g; + eval.d[i-1] = f - g; + for (int j = 0; j < i; j++) { + eval.e[j] = 0.0; + } + + // Apply similarity transformation to remaining columns. + + for (int j = 0; j < i; j++) { + f = eval.d[j]; + eval.V[j][i] = f; + g = eval.e[j] + eval.V[j][j] * f; + for (int k = j+1; k <= i-1; k++) { + g += eval.V[k][j] * eval.d[k]; + eval.e[k] += eval.V[k][j] * f; + } + eval.e[j] = g; + } + f = 0.0; + for (int j = 0; j < i; j++) { + eval.e[j] /= h; + f += eval.e[j] * eval.d[j]; + } + float hh = f / (h + h); + for (int j = 0; j < i; j++) { + eval.e[j] -= hh * eval.d[j]; + } + for (int j = 0; j < i; j++) { + f = eval.d[j]; + g = eval.e[j]; + for (int k = j; k <= i-1; k++) { + eval.V[k][j] -= (f * eval.e[k] + g * eval.d[k]); + } + eval.d[j] = eval.V[i-1][j]; + eval.V[i][j] = 0.0; + } + } + eval.d[i] = h; + } + + // Accumulate transformations. + + for (int i = 0; i < n-1; i++) { + eval.V[n-1][i] = eval.V[i][i]; + eval.V[i][i] = 1.0; + float h = eval.d[i+1]; + if (h != 0.0) { + for (int k = 0; k <= i; k++) { + eval.d[k] = eval.V[k][i+1] / h; + } + for (int j = 0; j <= i; j++) { + float g = 0.0; + for (int k = 0; k <= i; k++) { + g += eval.V[k][i+1] * eval.V[k][j]; + } + for (int k = 0; k <= i; k++) { + eval.V[k][j] -= g * eval.d[k]; + } + } + } + for (int k = 0; k <= i; k++) { + eval.V[k][i+1] = 0.0; + } + } + for (int j = 0; j < n; j++) { + eval.d[j] = eval.V[n-1][j]; + eval.V[n-1][j] = 0.0; + } + eval.V[n-1][n-1] = 1.0; + eval.e[0] = 0.0; +} + +void Eigencdiv(sEigenvalue& eval, float xr, float xi, float yr, float yi) { + float r,d; + if (fabs(yr) > fabs(yi)) { + r = yi/yr; + d = yr + r*yi; + eval.cdivr = (xr + r*xi)/d; + eval.cdivi = (xi - r*xr)/d; + } else { + r = yr/yi; + d = yi + r*yr; + eval.cdivr = (r*xr + xi)/d; + eval.cdivi = (r*xi - xr)/d; + } + } + +void Eigentql2 (sEigenvalue& eval) { + + // This is derived from the Algol procedures tql2, by + // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for + // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutine in EISPACK. + + int n=eval.n; + + for (int i = 1; i < n; i++) { + eval.e[i-1] = eval.e[i]; + } + eval.e[n-1] = 0.0; + + float f = 0.0; + float tst1 = 0.0; + float eps = pow(2.0,-52.0); + for (int l = 0; l < n; l++) { + + // Find small subdiagonal element + + tst1 = max(tst1,fabs(eval.d[l]) + fabs(eval.e[l])); + int m = l; + + // Original while-loop from Java code + while (m < n) { + if (fabs(eval.e[m]) <= eps*tst1) { + break; + } + m++; + } + + + // If m == l, d[l] is an eigenvalue, + // otherwise, iterate. + + if (m > l) { + int iter = 0; + do { + iter = iter + 1; // (Could check iteration count here.) + + // Compute implicit shift + + float g = eval.d[l]; + float p = (eval.d[l+1] - g) / (2.0 * eval.e[l]); + float r = hypot(p,1.0); + if (p < 0) { + r = -r; + } + eval.d[l] = eval.e[l] / (p + r); + eval.d[l+1] = eval.e[l] * (p + r); + float dl1 = eval.d[l+1]; + float h = g - eval.d[l]; + for (int i = l+2; i < n; i++) { + eval.d[i] -= h; + } + f = f + h; + + // Implicit QL transformation. + + p = eval.d[m]; + float c = 1.0; + float c2 = c; + float c3 = c; + float el1 = eval.e[l+1]; + float s = 0.0; + float s2 = 0.0; + for (int i = m-1; i >= l; i--) { + c3 = c2; + c2 = c; + s2 = s; + g = c * eval.e[i]; + h = c * p; + r = hypot(p,eval.e[i]); + eval.e[i+1] = s * r; + s = eval.e[i] / r; + c = p / r; + p = c * eval.d[i] - s * g; + eval.d[i+1] = h + s * (c * g + s * eval.d[i]); + + // Accumulate transformation. + + for (int k = 0; k < n; k++) { + h = eval.V[k][i+1]; + eval.V[k][i+1] = s * eval.V[k][i] + c * h; + eval.V[k][i] = c * eval.V[k][i] - s * h; + } + } + p = -s * s2 * c3 * el1 * eval.e[l] / dl1; + eval.e[l] = s * p; + eval.d[l] = c * p; + + // Check for convergence. + + } while (fabs(eval.e[l]) > eps*tst1); + } + eval.d[l] = eval.d[l] + f; + eval.e[l] = 0.0; + } + + // Sort eigenvalues and corresponding vectors. + + for (int i = 0; i < n-1; i++) { + int k = i; + float p = eval.d[i]; + for (int j = i+1; j < n; j++) { + if (eval.d[j] < p) { + k = j; + p = eval.d[j]; + } + } + if (k != i) { + eval.d[k] = eval.d[i]; + eval.d[i] = p; + for (int j = 0; j < n; j++) { + p = eval.V[j][i]; + eval.V[j][i] = eval.V[j][k]; + eval.V[j][k] = p; + } + } + } +} + +void Eigenorthes (sEigenvalue& eval) { + + // This is derived from the Algol procedures orthes and ortran, + // by Martin and Wilkinson, Handbook for Auto. Comp., + // Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutines in EISPACK. + + int n=eval.n; + + int low = 0; + int high = n-1; + + for (int m = low+1; m <= high-1; m++) { + + // Scale column. + + float scale = 0.0; + for (int i = m; i <= high; i++) { + scale = scale + fabs(eval.H[i][m-1]); + } + if (scale != 0.0) { + + // Compute Householder transformation. + + float h = 0.0; + for (int i = high; i >= m; i--) { + eval.ort[i] = eval.H[i][m-1]/scale; + h += eval.ort[i] * eval.ort[i]; + } + float g = sqrt(h); + if (eval.ort[m] > 0) { + g = -g; + } + h = h - eval.ort[m] * g; + eval.ort[m] = eval.ort[m] - g; + + // Apply Householder similarity transformation + // H = (I-u*u'/h)*H*(I-u*u')/h) + + for (int j = m; j < n; j++) { + float f = 0.0; + for (int i = high; i >= m; i--) { + f += eval.ort[i]*eval.H[i][j]; + } + f = f/h; + for (int i = m; i <= high; i++) { + eval.H[i][j] -= f*eval.ort[i]; + } + } + + for (int i = 0; i <= high; i++) { + float f = 0.0; + for (int j = high; j >= m; j--) { + f += eval.ort[j]*eval.H[i][j]; + } + f = f/h; + for (int j = m; j <= high; j++) { + eval.H[i][j] -= f*eval.ort[j]; + } + } + eval.ort[m] = scale*eval.ort[m]; + eval.H[m][m-1] = scale*g; + } + } + + // Accumulate transformations (Algol's ortran). + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + eval.V[i][j] = (i == j ? 1.0 : 0.0); + } + } + + for (int m = high-1; m >= low+1; m--) { + if (eval.H[m][m-1] != 0.0) { + for (int i = m+1; i <= high; i++) { + eval.ort[i] = eval.H[i][m-1]; + } + for (int j = m; j <= high; j++) { + float g = 0.0; + for (int i = m; i <= high; i++) { + g += eval.ort[i] * eval.V[i][j]; + } + // Double division avoids possible underflow + g = (g / eval.ort[m]) / eval.H[m][m-1]; + for (int i = m; i <= high; i++) { + eval.V[i][j] += g * eval.ort[i]; + } + } + } + } + } + +void Eigenhqr2 (sEigenvalue& eval) { + + // This is derived from the Algol procedure hqr2, + // by Martin and Wilkinson, Handbook for Auto. Comp., + // Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutine in EISPACK. + + // Initialize + + int nn = eval.n; + int n = nn-1; + int low = 0; + int high = nn-1; + float eps = pow(2.0,-52.0); + float exshift = 0.0; + float p=0,q=0,r=0,s=0,z=0,t,w,x,y; + + // Store roots isolated by balanc and compute matrix norm + + float norm = 0.0; + for (int i = 0; i < nn; i++) { + if ((i < low) || (i > high)) { + eval.d[i] = eval.H[i][i]; + eval.e[i] = 0.0; + } + for (int j = max(i-1,0); j < nn; j++) { + norm = norm + fabs(eval.H[i][j]); + } + } + + // Outer loop over eigenvalue index + + int iter = 0; + int totIter = 0; + while (n >= low) { + + // NT limit no. of iterations + totIter++; + if(totIter>100) { + //if(totIter>15) std::cout<<"!!!!iter ABORT !!!!!!! "<<totIter<<"\n"; + // NT hack/fix, return large eigenvalues + for (int i = 0; i < nn; i++) { + eval.d[i] = 10000.; + eval.e[i] = 10000.; + } + return; + } + + // Look for single small sub-diagonal element + + int l = n; + while (l > low) { + s = fabs(eval.H[l-1][l-1]) + fabs(eval.H[l][l]); + if (s == 0.0) { + s = norm; + } + if (fabs(eval.H[l][l-1]) < eps * s) { + break; + } + l--; + } + + // Check for convergence + // One root found + + if (l == n) { + eval.H[n][n] = eval.H[n][n] + exshift; + eval.d[n] = eval.H[n][n]; + eval.e[n] = 0.0; + n--; + iter = 0; + + // Two roots found + + } else if (l == n-1) { + w = eval.H[n][n-1] * eval.H[n-1][n]; + p = (eval.H[n-1][n-1] - eval.H[n][n]) / 2.0; + q = p * p + w; + z = sqrt(fabs(q)); + eval.H[n][n] = eval.H[n][n] + exshift; + eval.H[n-1][n-1] = eval.H[n-1][n-1] + exshift; + x = eval.H[n][n]; + + // float pair + + if (q >= 0) { + if (p >= 0) { + z = p + z; + } else { + z = p - z; + } + eval.d[n-1] = x + z; + eval.d[n] = eval.d[n-1]; + if (z != 0.0) { + eval.d[n] = x - w / z; + } + eval.e[n-1] = 0.0; + eval.e[n] = 0.0; + x = eval.H[n][n-1]; + s = fabs(x) + fabs(z); + p = x / s; + q = z / s; + r = sqrt(p * p+q * q); + p = p / r; + q = q / r; + + // Row modification + + for (int j = n-1; j < nn; j++) { + z = eval.H[n-1][j]; + eval.H[n-1][j] = q * z + p * eval.H[n][j]; + eval.H[n][j] = q * eval.H[n][j] - p * z; + } + + // Column modification + + for (int i = 0; i <= n; i++) { + z = eval.H[i][n-1]; + eval.H[i][n-1] = q * z + p * eval.H[i][n]; + eval.H[i][n] = q * eval.H[i][n] - p * z; + } + + // Accumulate transformations + + for (int i = low; i <= high; i++) { + z = eval.V[i][n-1]; + eval.V[i][n-1] = q * z + p * eval.V[i][n]; + eval.V[i][n] = q * eval.V[i][n] - p * z; + } + + // Complex pair + + } else { + eval.d[n-1] = x + p; + eval.d[n] = x + p; + eval.e[n-1] = z; + eval.e[n] = -z; + } + n = n - 2; + iter = 0; + + // No convergence yet + + } else { + + // Form shift + + x = eval.H[n][n]; + y = 0.0; + w = 0.0; + if (l < n) { + y = eval.H[n-1][n-1]; + w = eval.H[n][n-1] * eval.H[n-1][n]; + } + + // Wilkinson's original ad hoc shift + + if (iter == 10) { + exshift += x; + for (int i = low; i <= n; i++) { + eval.H[i][i] -= x; + } + s = fabs(eval.H[n][n-1]) + fabs(eval.H[n-1][n-2]); + x = y = 0.75 * s; + w = -0.4375 * s * s; + } + + // MATLAB's new ad hoc shift + + if (iter == 30) { + s = (y - x) / 2.0; + s = s * s + w; + if (s > 0) { + s = sqrt(s); + if (y < x) { + s = -s; + } + s = x - w / ((y - x) / 2.0 + s); + for (int i = low; i <= n; i++) { + eval.H[i][i] -= s; + } + exshift += s; + x = y = w = 0.964; + } + } + + iter = iter + 1; // (Could check iteration count here.) + + // Look for two consecutive small sub-diagonal elements + + int m = n-2; + while (m >= l) { + z = eval.H[m][m]; + r = x - z; + s = y - z; + p = (r * s - w) / eval.H[m+1][m] + eval.H[m][m+1]; + q = eval.H[m+1][m+1] - z - r - s; + r = eval.H[m+2][m+1]; + s = fabs(p) + fabs(q) + fabs(r); + p = p / s; + q = q / s; + r = r / s; + if (m == l) { + break; + } + if (fabs(eval.H[m][m-1]) * (fabs(q) + fabs(r)) < + eps * (fabs(p) * (fabs(eval.H[m-1][m-1]) + fabs(z) + + fabs(eval.H[m+1][m+1])))) { + break; + } + m--; + } + + for (int i = m+2; i <= n; i++) { + eval.H[i][i-2] = 0.0; + if (i > m+2) { + eval.H[i][i-3] = 0.0; + } + } + + // Double QR step involving rows l:n and columns m:n + + for (int k = m; k <= n-1; k++) { + int notlast = (k != n-1); + if (k != m) { + p = eval.H[k][k-1]; + q = eval.H[k+1][k-1]; + r = (notlast ? eval.H[k+2][k-1] : 0.0); + x = fabs(p) + fabs(q) + fabs(r); + if (x != 0.0) { + p = p / x; + q = q / x; + r = r / x; + } + } + if (x == 0.0) { + break; + } + s = sqrt(p * p + q * q + r * r); + if (p < 0) { + s = -s; + } + if (s != 0) { + if (k != m) { + eval.H[k][k-1] = -s * x; + } else if (l != m) { + eval.H[k][k-1] = -eval.H[k][k-1]; + } + p = p + s; + x = p / s; + y = q / s; + z = r / s; + q = q / p; + r = r / p; + + // Row modification + + for (int j = k; j < nn; j++) { + p = eval.H[k][j] + q * eval.H[k+1][j]; + if (notlast) { + p = p + r * eval.H[k+2][j]; + eval.H[k+2][j] = eval.H[k+2][j] - p * z; + } + eval.H[k][j] = eval.H[k][j] - p * x; + eval.H[k+1][j] = eval.H[k+1][j] - p * y; + } + + // Column modification + + for (int i = 0; i <= min(n,k+3); i++) { + p = x * eval.H[i][k] + y * eval.H[i][k+1]; + if (notlast) { + p = p + z * eval.H[i][k+2]; + eval.H[i][k+2] = eval.H[i][k+2] - p * r; + } + eval.H[i][k] = eval.H[i][k] - p; + eval.H[i][k+1] = eval.H[i][k+1] - p * q; + } + + // Accumulate transformations + + for (int i = low; i <= high; i++) { + p = x * eval.V[i][k] + y * eval.V[i][k+1]; + if (notlast) { + p = p + z * eval.V[i][k+2]; + eval.V[i][k+2] = eval.V[i][k+2] - p * r; + } + eval.V[i][k] = eval.V[i][k] - p; + eval.V[i][k+1] = eval.V[i][k+1] - p * q; + } + } // (s != 0) + } // k loop + } // check convergence + } // while (n >= low) + //if(totIter>15) std::cout<<"!!!!iter "<<totIter<<"\n"; + + // Backsubstitute to find vectors of upper triangular form + + if (norm == 0.0) { + return; + } + + for (n = nn-1; n >= 0; n--) { + p = eval.d[n]; + q = eval.e[n]; + + // float vector + + if (q == 0) { + int l = n; + eval.H[n][n] = 1.0; + for (int i = n-1; i >= 0; i--) { + w = eval.H[i][i] - p; + r = 0.0; + for (int j = l; j <= n; j++) { + r = r + eval.H[i][j] * eval.H[j][n]; + } + if (eval.e[i] < 0.0) { + z = w; + s = r; + } else { + l = i; + if (eval.e[i] == 0.0) { + if (w != 0.0) { + eval.H[i][n] = -r / w; + } else { + eval.H[i][n] = -r / (eps * norm); + } + + // Solve real equations + + } else { + x = eval.H[i][i+1]; + y = eval.H[i+1][i]; + q = (eval.d[i] - p) * (eval.d[i] - p) + eval.e[i] * eval.e[i]; + t = (x * s - z * r) / q; + eval.H[i][n] = t; + if (fabs(x) > fabs(z)) { + eval.H[i+1][n] = (-r - w * t) / x; + } else { + eval.H[i+1][n] = (-s - y * t) / z; + } + } + + // Overflow control + + t = fabs(eval.H[i][n]); + if ((eps * t) * t > 1) { + for (int j = i; j <= n; j++) { + eval.H[j][n] = eval.H[j][n] / t; + } + } + } + } + + // Complex vector + + } else if (q < 0) { + int l = n-1; + + // Last vector component imaginary so matrix is triangular + + if (fabs(eval.H[n][n-1]) > fabs(eval.H[n-1][n])) { + eval.H[n-1][n-1] = q / eval.H[n][n-1]; + eval.H[n-1][n] = -(eval.H[n][n] - p) / eval.H[n][n-1]; + } else { + Eigencdiv(eval, 0.0,-eval.H[n-1][n],eval.H[n-1][n-1]-p,q); + eval.H[n-1][n-1] = eval.cdivr; + eval.H[n-1][n] = eval.cdivi; + } + eval.H[n][n-1] = 0.0; + eval.H[n][n] = 1.0; + for (int i = n-2; i >= 0; i--) { + float ra,sa,vr,vi; + ra = 0.0; + sa = 0.0; + for (int j = l; j <= n; j++) { + ra = ra + eval.H[i][j] * eval.H[j][n-1]; + sa = sa + eval.H[i][j] * eval.H[j][n]; + } + w = eval.H[i][i] - p; + + if (eval.e[i] < 0.0) { + z = w; + r = ra; + s = sa; + } else { + l = i; + if (eval.e[i] == 0) { + Eigencdiv(eval,-ra,-sa,w,q); + eval.H[i][n-1] = eval.cdivr; + eval.H[i][n] = eval.cdivi; + } else { + + // Solve complex equations + + x = eval.H[i][i+1]; + y = eval.H[i+1][i]; + vr = (eval.d[i] - p) * (eval.d[i] - p) + eval.e[i] * eval.e[i] - q * q; + vi = (eval.d[i] - p) * 2.0 * q; + if ((vr == 0.0) && (vi == 0.0)) { + vr = eps * norm * (fabs(w) + fabs(q) + + fabs(x) + fabs(y) + fabs(z)); + } + Eigencdiv(eval, x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi); + eval.H[i][n-1] = eval.cdivr; + eval.H[i][n] = eval.cdivi; + if (fabs(x) > (fabs(z) + fabs(q))) { + eval.H[i+1][n-1] = (-ra - w * eval.H[i][n-1] + q * eval.H[i][n]) / x; + eval.H[i+1][n] = (-sa - w * eval.H[i][n] - q * eval.H[i][n-1]) / x; + } else { + Eigencdiv(eval, -r-y*eval.H[i][n-1],-s-y*eval.H[i][n],z,q); + eval.H[i+1][n-1] = eval.cdivr; + eval.H[i+1][n] = eval.cdivi; + } + } + + // Overflow control + + t = max(fabs(eval.H[i][n-1]),fabs(eval.H[i][n])); + if ((eps * t) * t > 1) { + for (int j = i; j <= n; j++) { + eval.H[j][n-1] = eval.H[j][n-1] / t; + eval.H[j][n] = eval.H[j][n] / t; + } + } + } + } + } + } + + // Vectors of isolated roots + + for (int i = 0; i < nn; i++) { + if (i < low || i > high) { + for (int j = i; j < nn; j++) { + eval.V[i][j] = eval.H[i][j]; + } + } + } + + // Back transformation to get eigenvectors of original matrix + + for (int j = nn-1; j >= low; j--) { + for (int i = low; i <= high; i++) { + z = 0.0; + for (int k = low; k <= min(j,high); k++) { + z = z + eval.V[i][k] * eval.H[k][j]; + } + eval.V[i][j] = z; + } + } +} + + + +int computeEigenvalues3x3( + float dout[3], + float a[3][3]) +{ + /*TNT::Array2D<float> A = TNT::Array2D<float>(3,3, &a[0][0]); + TNT::Array1D<float> eig = TNT::Array1D<float>(3); + TNT::Array1D<float> eigImag = TNT::Array1D<float>(3); + JAMA::Eigenvalue<float> jeig = JAMA::Eigenvalue<float>(A);*/ + + sEigenvalue jeig; + + // Compute the values + { + jeig.n = 3; + int n=3; + //V = Array2D<float>(n,n); + //d = Array1D<float>(n); + //e = Array1D<float>(n); + for (int y=0; y<3; y++) + { + jeig.d[y]=0.0f; + jeig.e[y]=0.0f; + for (int t=0; t<3; t++) jeig.V[y][t]=0.0f; + } + + jeig.issymmetric = 1; + for (int j = 0; (j < 3) && jeig.issymmetric; j++) { + for (int i = 0; (i < 3) && jeig.issymmetric; i++) { + jeig.issymmetric = (a[i][j] == a[j][i]); + } + } + + if (jeig.issymmetric) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + jeig.V[i][j] = a[i][j]; + } + } + + // Tridiagonalize. + Eigentred2(jeig); + + // Diagonalize. + Eigentql2(jeig); + + } else { + //H = TNT::Array2D<float>(n,n); + for (int y=0; y<3; y++) + { + jeig.ort[y]=0.0f; + for (int t=0; t<3; t++) jeig.H[y][t]=0.0f; + } + //ort = TNT::Array1D<float>(n); + + for (int j = 0; j < n; j++) { + for (int i = 0; i < n; i++) { + jeig.H[i][j] = a[i][j]; + } + } + + // Reduce to Hessenberg form. + Eigenorthes(jeig); + + // Reduce Hessenberg to real Schur form. + Eigenhqr2(jeig); + } + } + + //jeig.getfloatEigenvalues(eig); + + // complex ones + //jeig.getImagEigenvalues(eigImag); + dout[0] = sqrt(jeig.d[0]*jeig.d[0] + jeig.e[0]*jeig.e[0]); + dout[1] = sqrt(jeig.d[1]*jeig.d[1] + jeig.e[1]*jeig.e[1]); + dout[2] = sqrt(jeig.d[2]*jeig.d[2] + jeig.e[2]*jeig.e[2]); + return 0; +} diff --git a/intern/smoke/intern/EIGENVALUE_HELPER.h b/intern/smoke/intern/EIGENVALUE_HELPER.h new file mode 100644 index 00000000000..a3f983c3209 --- /dev/null +++ b/intern/smoke/intern/EIGENVALUE_HELPER.h @@ -0,0 +1,77 @@ +/** \file smoke/intern/EIGENVALUE_HELPER.h + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +////////////////////////////////////////////////////////////////////// +// Modified to not require TNT matrix library anymore. It was very slow +// when being run in parallel. Required TNT JAMA::Eigenvalue libraries were +// converted into independent functions. +// - MiikaH +// +////////////////////////////////////////////////////////////////////// +// Helper function, compute eigenvalues of 3x3 matrix +////////////////////////////////////////////////////////////////////// + +#ifndef EIGENVAL_HELPER_H +#define EIGENVAL_HELPER_H + +//#include "tnt/jama_eig.h" + +#include <algorithm> +#include <cmath> + +using namespace std; + +////////////////////////////////////////////////////////////////////// +// eigenvalues of 3x3 non-symmetric matrix +////////////////////////////////////////////////////////////////////// + + +struct sEigenvalue +{ + int n; + int issymmetric; + float d[3]; /* real part */ + float e[3]; /* img part */ + float V[3][3]; /* Eigenvectors */ + + float H[3][3]; + + + float ort[3]; + + float cdivr; + float cdivi; +}; + +void Eigentred2(sEigenvalue& eval); + +void Eigencdiv(sEigenvalue& eval, float xr, float xi, float yr, float yi); + +void Eigentql2 (sEigenvalue& eval); + +void Eigenorthes (sEigenvalue& eval); + +void Eigenhqr2 (sEigenvalue& eval); + +int computeEigenvalues3x3(float dout[3], float a[3][3]); + + +#endif diff --git a/intern/smoke/intern/FFT_NOISE.h b/intern/smoke/intern/FFT_NOISE.h new file mode 100644 index 00000000000..a087b4e1391 --- /dev/null +++ b/intern/smoke/intern/FFT_NOISE.h @@ -0,0 +1,181 @@ +/** \file smoke/intern/FFT_NOISE.h + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +///////////////////////////////////////////////////////////////////////// +// + +#ifndef FFT_NOISE_H_ +#define FFT_NOISE_H_ + +#ifdef WITH_FFTW3 +#include <iostream> +#include <fftw3.h> +#include <MERSENNETWISTER.h> + +#include "WAVELET_NOISE.h" + +#ifndef M_PI +#define M_PI 3.14159265 +#endif + +///////////////////////////////////////////////////////////////////////// +// shift spectrum to the format that FFTW expects +///////////////////////////////////////////////////////////////////////// +static void shift3D(float*& field, int xRes, int yRes, int zRes) +{ + int xHalf = xRes / 2; + int yHalf = yRes / 2; + int zHalf = zRes / 2; + // int slabSize = xRes * yRes; + for (int z = 0; z < zHalf; z++) + for (int y = 0; y < yHalf; y++) + for (int x = 0; x < xHalf; x++) + { + int index = x + y * xRes + z * xRes * yRes; + float temp; + int xSwap = xHalf; + int ySwap = yHalf * xRes; + int zSwap = zHalf * xRes * yRes; + + // [0,0,0] to [1,1,1] + temp = field[index]; + field[index] = field[index + xSwap + ySwap + zSwap]; + field[index + xSwap + ySwap + zSwap] = temp; + + // [1,0,0] to [0,1,1] + temp = field[index + xSwap]; + field[index + xSwap] = field[index + ySwap + zSwap]; + field[index + ySwap + zSwap] = temp; + + // [0,1,0] to [1,0,1] + temp = field[index + ySwap]; + field[index + ySwap] = field[index + xSwap + zSwap]; + field[index + xSwap + zSwap] = temp; + + // [0,0,1] to [1,1,0] + temp = field[index + zSwap]; + field[index + zSwap] = field[index + xSwap + ySwap]; + field[index + xSwap + ySwap] = temp; + } +} + +static void generatTile_FFT(float* const noiseTileData, std::string filename) +{ + if (loadTile(noiseTileData, filename)) return; + + int res = NOISE_TILE_SIZE; + int xRes = res; + int yRes = res; + int zRes = res; + int totalCells = xRes * yRes * zRes; + + // create and shift the filter + float* filter = new float[totalCells]; + for (int z = 0; z < zRes; z++) + for (int y = 0; y < yRes; y++) + for (int x = 0; x < xRes; x++) + { + int index = x + y * xRes + z * xRes * yRes; + float diff[] = {abs(x - xRes/2), + abs(y - yRes/2), + abs(z - zRes/2)}; + float radius = sqrtf(diff[0] * diff[0] + + diff[1] * diff[1] + + diff[2] * diff[2]) / (xRes / 2); + radius *= M_PI; + float H = cos((M_PI / 2.0f) * log(4.0f * radius / M_PI) / log(2.0f)); + H = H * H; + float filtered = H; + + // clamp everything outside the wanted band + if (radius >= M_PI / 2.0f) + filtered = 0.0f; + + // make sure to capture all low frequencies + if (radius <= M_PI / 4.0f) + filtered = 1.0f; + + filter[index] = filtered; + } + shift3D(filter, xRes, yRes, zRes); + + // create the noise + float* noise = new float[totalCells]; + int index = 0; + MTRand twister; + for (int z = 0; z < zRes; z++) + for (int y = 0; y < yRes; y++) + for (int x = 0; x < xRes; x++, index++) + noise[index] = twister.randNorm(); + + // create padded field + fftw_complex* forward = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * totalCells); + + // init padded field + index = 0; + for (int z = 0; z < zRes; z++) + for (int y = 0; y < yRes; y++) + for (int x = 0; x < xRes; x++, index++) + { + forward[index][0] = noise[index]; + forward[index][1] = 0.0f; + } + + // forward FFT + fftw_complex* backward = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * totalCells); + fftw_plan forwardPlan = fftw_plan_dft_3d(xRes, yRes, zRes, forward, backward, FFTW_FORWARD, FFTW_ESTIMATE); + fftw_execute(forwardPlan); + fftw_destroy_plan(forwardPlan); + + // apply filter + index = 0; + for (int z = 0; z < zRes; z++) + for (int y = 0; y < yRes; y++) + for (int x = 0; x < xRes; x++, index++) + { + backward[index][0] *= filter[index]; + backward[index][1] *= filter[index]; + } + + // backward FFT + fftw_plan backwardPlan = fftw_plan_dft_3d(xRes, yRes, zRes, backward, forward, FFTW_BACKWARD, FFTW_ESTIMATE); + fftw_execute(backwardPlan); + fftw_destroy_plan(backwardPlan); + + // subtract out the low frequency components + index = 0; + for (int z = 0; z < zRes; z++) + for (int y = 0; y < yRes; y++) + for (int x = 0; x < xRes; x++, index++) + noise[index] -= forward[index][0] / totalCells; + + // save out the noise tile + saveTile(noise, filename); + + fftw_free(forward); + fftw_free(backward); + delete[] filter; + delete[] noise; +} + +#endif + +#endif /* FFT_NOISE_H_ */ diff --git a/intern/smoke/intern/FLUID_3D.cpp b/intern/smoke/intern/FLUID_3D.cpp new file mode 100644 index 00000000000..525774358e6 --- /dev/null +++ b/intern/smoke/intern/FLUID_3D.cpp @@ -0,0 +1,1458 @@ +/** \file smoke/intern/FLUID_3D.cpp + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +// FLUID_3D.cpp: implementation of the FLUID_3D class. +// +////////////////////////////////////////////////////////////////////// +// Heavy parallel optimization done. Many of the old functions now +// take begin and end parameters and process only specified part of the data. +// Some functions were divided into multiple ones. +// - MiikaH +////////////////////////////////////////////////////////////////////// + +#include "FLUID_3D.h" +#include "IMAGE.h" +#include <INTERPOLATE.h> +#include "SPHERE.h" +#include <zlib.h> + +#include "float.h" + +#if PARALLEL==1 +#include <omp.h> +#endif // PARALLEL + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) : + _xRes(res[0]), _yRes(res[1]), _zRes(res[2]), _res(0.0f) +{ + // set simulation consts + _dt = dtdef; // just in case. set in step from a RNA factor + + // start point of array + _p0[0] = p0[0]; + _p0[1] = p0[1]; + _p0[2] = p0[2]; + + _iterations = 100; + _tempAmb = 0; + _heatDiffusion = 1e-3; + _totalTime = 0.0f; + _totalSteps = 0; + _res = Vec3Int(_xRes,_yRes,_zRes); + _maxRes = MAX3(_xRes, _yRes, _zRes); + + // initialize wavelet turbulence + /* + if(amplify) + _wTurbulence = new WTURBULENCE(_res[0],_res[1],_res[2], amplify, noisetype); + else + _wTurbulence = NULL; + */ + + // scale the constants according to the refinement of the grid + _dx = 1.0f / (float)_maxRes; + _constantScaling = 64.0f / _maxRes; + _constantScaling = (_constantScaling < 1.0f) ? 1.0f : _constantScaling; + _vorticityEps = 2.0f / _constantScaling; // Just in case set a default value + + // allocate arrays + _totalCells = _xRes * _yRes * _zRes; + _slabSize = _xRes * _yRes; + _xVelocity = new float[_totalCells]; + _yVelocity = new float[_totalCells]; + _zVelocity = new float[_totalCells]; + _xVelocityOb = new float[_totalCells]; + _yVelocityOb = new float[_totalCells]; + _zVelocityOb = new float[_totalCells]; + _xVelocityOld = new float[_totalCells]; + _yVelocityOld = new float[_totalCells]; + _zVelocityOld = new float[_totalCells]; + _xForce = new float[_totalCells]; + _yForce = new float[_totalCells]; + _zForce = new float[_totalCells]; + _density = new float[_totalCells]; + _densityOld = new float[_totalCells]; + _heat = new float[_totalCells]; + _heatOld = new float[_totalCells]; + _obstacles = new unsigned char[_totalCells]; // set 0 at end of step + + // For debugging purposes + _pressure = new float[_totalCells]; + + // For threaded version: + _xVelocityTemp = new float[_totalCells]; + _yVelocityTemp = new float[_totalCells]; + _zVelocityTemp = new float[_totalCells]; + _densityTemp = new float[_totalCells]; + _heatTemp = new float[_totalCells]; + + // DG TODO: check if alloc went fine + + for (int x = 0; x < _totalCells; x++) + { + _density[x] = 0.0f; + _densityOld[x] = 0.0f; + _heat[x] = 0.0f; + _heatOld[x] = 0.0f; + _xVelocity[x] = 0.0f; + _yVelocity[x] = 0.0f; + _zVelocity[x] = 0.0f; + _xVelocityOb[x] = 0.0f; + _yVelocityOb[x] = 0.0f; + _zVelocityOb[x] = 0.0f; + _xVelocityOld[x] = 0.0f; + _yVelocityOld[x] = 0.0f; + _zVelocityOld[x] = 0.0f; + _xForce[x] = 0.0f; + _yForce[x] = 0.0f; + _zForce[x] = 0.0f; + _obstacles[x] = false; + _pressure[x] = 0.0f; + } + + // boundary conditions of the fluid domain + // set default values -> vertically non-colliding + _domainBcFront = true; + _domainBcTop = false; + _domainBcLeft = true; + _domainBcBack = _domainBcFront; + _domainBcBottom = _domainBcTop; + _domainBcRight = _domainBcLeft; + + _colloPrev = 1; // default value + + setBorderObstacles(); // walls + +} + +void FLUID_3D::setBorderObstacles() +{ + + // set side obstacles + unsigned int index; + for (int y = 0; y < _yRes; y++) + for (int x = 0; x < _xRes; x++) + { + // bottom slab + index = x + y * _xRes; + if(_domainBcBottom==1) _obstacles[index] = 1; + + // top slab + index += _totalCells - _slabSize; + if(_domainBcTop==1) _obstacles[index] = 1; + } + + for (int z = 0; z < _zRes; z++) + for (int x = 0; x < _xRes; x++) + { + // front slab + index = x + z * _slabSize; + if(_domainBcFront==1) _obstacles[index] = 1; + + // back slab + index += _slabSize - _xRes; + if(_domainBcBack==1) _obstacles[index] = 1; + } + + for (int z = 0; z < _zRes; z++) + for (int y = 0; y < _yRes; y++) + { + // left slab + index = y * _xRes + z * _slabSize; + if(_domainBcLeft==1) _obstacles[index] = 1; + + // right slab + index += _xRes - 1; + if(_domainBcRight==1) _obstacles[index] = 1; + } +} + +FLUID_3D::~FLUID_3D() +{ + if (_xVelocity) delete[] _xVelocity; + if (_yVelocity) delete[] _yVelocity; + if (_zVelocity) delete[] _zVelocity; + if (_xVelocityOb) delete[] _xVelocityOb; + if (_yVelocityOb) delete[] _yVelocityOb; + if (_zVelocityOb) delete[] _zVelocityOb; + if (_xVelocityOld) delete[] _xVelocityOld; + if (_yVelocityOld) delete[] _yVelocityOld; + if (_zVelocityOld) delete[] _zVelocityOld; + if (_xForce) delete[] _xForce; + if (_yForce) delete[] _yForce; + if (_zForce) delete[] _zForce; + if (_density) delete[] _density; + if (_densityOld) delete[] _densityOld; + if (_heat) delete[] _heat; + if (_heatOld) delete[] _heatOld; + if (_obstacles) delete[] _obstacles; + // if (_wTurbulence) delete _wTurbulence; + + // for debugging purposes + if(_pressure) + delete[] _pressure; + + if (_xVelocityTemp) delete[] _xVelocityTemp; + if (_yVelocityTemp) delete[] _yVelocityTemp; + if (_zVelocityTemp) delete[] _zVelocityTemp; + if (_densityTemp) delete[] _densityTemp; + if (_heatTemp) delete[] _heatTemp; + + // printf("deleted fluid\n"); +} + +// init direct access functions from blender +void FLUID_3D::initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *borderCollision) +{ + _alpha = alpha; + _beta = beta; + _dtFactor = dt_factor; + _vorticityRNA = vorticity; + _borderColli = borderCollision; +} + +////////////////////////////////////////////////////////////////////// +// step simulation once +////////////////////////////////////////////////////////////////////// +void FLUID_3D::step(float dt) +{ +#if 0 + // If border rules have been changed + if (_colloPrev != *_borderColli) { + printf("Border collisions changed\n"); + + // DG TODO: Need to check that no animated obstacle flags are overwritten + setBorderCollisions(); + } +#endif + + // DG: TODO for the moment redo border for every timestep since it's been deleted every time by moving obstacles + setBorderCollisions(); + + + // set delta time by dt_factor + _dt = (*_dtFactor) * dt; + // set vorticity from RNA value + _vorticityEps = (*_vorticityRNA)/_constantScaling; + + +#if PARALLEL==1 + int threadval = 1; + threadval = omp_get_max_threads(); + + int stepParts = 1; + float partSize = _zRes; + + stepParts = threadval*2; // Dividing parallelized sections into numOfThreads * 2 sections + partSize = (float)_zRes/stepParts; // Size of one part; + + if (partSize < 4) {stepParts = threadval; // If the slice gets too low (might actually slow things down, change it to larger + partSize = (float)_zRes/stepParts;} + if (partSize < 4) {stepParts = (int)(ceil((float)_zRes/4.0f)); // If it's still too low (only possible on future systems with +24 cores), change it to 4 + partSize = (float)_zRes/stepParts;} +#else + int zBegin=0; + int zEnd=_zRes; +#endif + + +#if PARALLEL==1 + #pragma omp parallel + { + #pragma omp for schedule(static,1) + for (int i=0; i<stepParts; i++) + { + int zBegin = (int)((float)i*partSize + 0.5f); + int zEnd = (int)((float)(i+1)*partSize + 0.5f); +#endif + + wipeBoundariesSL(zBegin, zEnd); + addVorticity(zBegin, zEnd); + addBuoyancy(_heat, _density, zBegin, zEnd); + addForce(zBegin, zEnd); + +#if PARALLEL==1 + } // end of parallel + #pragma omp barrier + + #pragma omp single + { +#endif + /* + * addForce() changed Temp values to preserve thread safety + * (previous functions in per thread loop still needed + * original velocity data) + * + * So swap temp values to velocity + */ + SWAP_POINTERS(_xVelocity, _xVelocityTemp); + SWAP_POINTERS(_yVelocity, _yVelocityTemp); + SWAP_POINTERS(_zVelocity, _zVelocityTemp); +#if PARALLEL==1 + } // end of single + + #pragma omp barrier + + #pragma omp for + for (int i=0; i<2; i++) + { + if (i==0) + { +#endif + project(); +#if PARALLEL==1 + } + else + { +#endif + diffuseHeat(); +#if PARALLEL==1 + } + } + + #pragma omp barrier + + #pragma omp single + { +#endif + /* + * For thread safety use "Old" to read + * "current" values but still allow changing values. + */ + SWAP_POINTERS(_xVelocity, _xVelocityOld); + SWAP_POINTERS(_yVelocity, _yVelocityOld); + SWAP_POINTERS(_zVelocity, _zVelocityOld); + SWAP_POINTERS(_density, _densityOld); + SWAP_POINTERS(_heat, _heatOld); + + advectMacCormackBegin(0, _zRes); + +#if PARALLEL==1 + } // end of single + + #pragma omp barrier + + + #pragma omp for schedule(static,1) + for (int i=0; i<stepParts; i++) + { + + int zBegin = (int)((float)i*partSize + 0.5f); + int zEnd = (int)((float)(i+1)*partSize + 0.5f); +#endif + + advectMacCormackEnd1(zBegin, zEnd); + +#if PARALLEL==1 + } // end of parallel + + #pragma omp barrier + + #pragma omp for schedule(static,1) + for (int i=0; i<stepParts; i++) + { + + int zBegin = (int)((float)i*partSize + 0.5f); + int zEnd = (int)((float)(i+1)*partSize + 0.5f); +#endif + + advectMacCormackEnd2(zBegin, zEnd); + + artificialDampingSL(zBegin, zEnd); + + // Using forces as temp arrays + +#if PARALLEL==1 + } + } + + + + for (int i=1; i<stepParts; i++) + { + int zPos=(int)((float)i*partSize + 0.5f); + + artificialDampingExactSL(zPos); + + } +#endif + + /* + * swap final velocity back to Velocity array + * from temp xForce storage + */ + SWAP_POINTERS(_xVelocity, _xForce); + SWAP_POINTERS(_yVelocity, _yForce); + SWAP_POINTERS(_zVelocity, _zForce); + + + + + _totalTime += _dt; + _totalSteps++; + + for (int i = 0; i < _totalCells; i++) + { + _xForce[i] = _yForce[i] = _zForce[i] = 0.0f; + } + +} + + +// Set border collision model from RNA setting + +void FLUID_3D::setBorderCollisions() { + + + _colloPrev = *_borderColli; // saving the current value + + // boundary conditions of the fluid domain + if (_colloPrev == 0) + { + // No collisions + _domainBcFront = false; + _domainBcTop = false; + _domainBcLeft = false; + } + else if (_colloPrev == 2) + { + // Collide with all sides + _domainBcFront = true; + _domainBcTop = true; + _domainBcLeft = true; + } + else + { + // Default values: Collide with "walls", but not top and bottom + _domainBcFront = true; + _domainBcTop = false; + _domainBcLeft = true; + } + + _domainBcBack = _domainBcFront; + _domainBcBottom = _domainBcTop; + _domainBcRight = _domainBcLeft; + + + + // set side obstacles + int index; + for (int y = 0; y < _yRes; y++) + for (int x = 0; x < _xRes; x++) + { + // front slab + index = x + y * _xRes; + if(_domainBcBottom==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + + // back slab + index += _totalCells - _slabSize; + if(_domainBcTop==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + } + + for (int z = 0; z < _zRes; z++) + for (int x = 0; x < _xRes; x++) + { + // bottom slab + index = x + z * _slabSize; + if(_domainBcFront==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + + // top slab + index += _slabSize - _xRes; + if(_domainBcBack==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + } + + for (int z = 0; z < _zRes; z++) + for (int y = 0; y < _yRes; y++) + { + // left slab + index = y * _xRes + z * _slabSize; + if(_domainBcLeft==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + + // right slab + index += _xRes - 1; + if(_domainBcRight==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + } +} + +////////////////////////////////////////////////////////////////////// +// helper function to dampen co-located grid artifacts of given arrays in intervals +// (only needed for velocity, strength (w) depends on testcase... +////////////////////////////////////////////////////////////////////// + + +void FLUID_3D::artificialDampingSL(int zBegin, int zEnd) { + const float w = 0.9; + + memmove(_xForce+(_slabSize*zBegin), _xVelocityTemp+(_slabSize*zBegin), sizeof(float)*_slabSize*(zEnd-zBegin)); + memmove(_yForce+(_slabSize*zBegin), _yVelocityTemp+(_slabSize*zBegin), sizeof(float)*_slabSize*(zEnd-zBegin)); + memmove(_zForce+(_slabSize*zBegin), _zVelocityTemp+(_slabSize*zBegin), sizeof(float)*_slabSize*(zEnd-zBegin)); + + + if(_totalSteps % 4 == 1) { + for (int z = zBegin+1; z < zEnd-1; z++) + for (int y = 1; y < _res[1]-1; y++) + for (int x = 1+(y+z)%2; x < _res[0]-1; x+=2) { + const int index = x + y*_res[0] + z * _slabSize; + _xForce[index] = (1-w)*_xVelocityTemp[index] + 1./6. * w*( + _xVelocityTemp[index+1] + _xVelocityTemp[index-1] + + _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] + + _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] ); + + _yForce[index] = (1-w)*_yVelocityTemp[index] + 1./6. * w*( + _yVelocityTemp[index+1] + _yVelocityTemp[index-1] + + _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] + + _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] ); + + _zForce[index] = (1-w)*_zVelocityTemp[index] + 1./6. * w*( + _zVelocityTemp[index+1] + _zVelocityTemp[index-1] + + _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] + + _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] ); + } + } + + if(_totalSteps % 4 == 3) { + for (int z = zBegin+1; z < zEnd-1; z++) + for (int y = 1; y < _res[1]-1; y++) + for (int x = 1+(y+z+1)%2; x < _res[0]-1; x+=2) { + const int index = x + y*_res[0] + z * _slabSize; + _xForce[index] = (1-w)*_xVelocityTemp[index] + 1./6. * w*( + _xVelocityTemp[index+1] + _xVelocityTemp[index-1] + + _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] + + _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] ); + + _yForce[index] = (1-w)*_yVelocityTemp[index] + 1./6. * w*( + _yVelocityTemp[index+1] + _yVelocityTemp[index-1] + + _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] + + _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] ); + + _zForce[index] = (1-w)*_zVelocityTemp[index] + 1./6. * w*( + _zVelocityTemp[index+1] + _zVelocityTemp[index-1] + + _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] + + _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] ); + } + + } +} + + + +void FLUID_3D::artificialDampingExactSL(int pos) { + const float w = 0.9; + int index, x,y,z; + + + size_t posslab; + + for (z=pos-1; z<=pos; z++) + { + posslab=z * _slabSize; + + if(_totalSteps % 4 == 1) { + for (y = 1; y < _res[1]-1; y++) + for (x = 1+(y+z)%2; x < _res[0]-1; x+=2) { + index = x + y*_res[0] + posslab; + /* + * Uses xForce as temporary storage to allow other threads to read + * old values from xVelocityTemp + */ + _xForce[index] = (1-w)*_xVelocityTemp[index] + 1./6. * w*( + _xVelocityTemp[index+1] + _xVelocityTemp[index-1] + + _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] + + _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] ); + + _yForce[index] = (1-w)*_yVelocityTemp[index] + 1./6. * w*( + _yVelocityTemp[index+1] + _yVelocityTemp[index-1] + + _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] + + _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] ); + + _zForce[index] = (1-w)*_zVelocityTemp[index] + 1./6. * w*( + _zVelocityTemp[index+1] + _zVelocityTemp[index-1] + + _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] + + _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] ); + + } + } + + if(_totalSteps % 4 == 3) { + for (y = 1; y < _res[1]-1; y++) + for (x = 1+(y+z+1)%2; x < _res[0]-1; x+=2) { + index = x + y*_res[0] + posslab; + + /* + * Uses xForce as temporary storage to allow other threads to read + * old values from xVelocityTemp + */ + _xForce[index] = (1-w)*_xVelocityTemp[index] + 1./6. * w*( + _xVelocityTemp[index+1] + _xVelocityTemp[index-1] + + _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] + + _xVelocityTemp[index+_slabSize] + _xVelocityTemp[index-_slabSize] ); + + _yForce[index] = (1-w)*_yVelocityTemp[index] + 1./6. * w*( + _yVelocityTemp[index+1] + _yVelocityTemp[index-1] + + _yVelocityTemp[index+_res[0]] + _yVelocityTemp[index-_res[0]] + + _yVelocityTemp[index+_slabSize] + _yVelocityTemp[index-_slabSize] ); + + _zForce[index] = (1-w)*_zVelocityTemp[index] + 1./6. * w*( + _zVelocityTemp[index+1] + _zVelocityTemp[index-1] + + _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] + + _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] ); + + } + + } + } +} + +////////////////////////////////////////////////////////////////////// +// copy out the boundary in all directions +////////////////////////////////////////////////////////////////////// +void FLUID_3D::copyBorderAll(float* field, int zBegin, int zEnd) +{ + int index, x, y, z; + int zSize = zEnd-zBegin; + int _blockTotalCells=_slabSize * zSize; + + if (zBegin==0) + for (int y = 0; y < _yRes; y++) + for (int x = 0; x < _xRes; x++) + { + // front slab + index = x + y * _xRes; + field[index] = field[index + _slabSize]; + } + + if (zEnd==_zRes) + for (y = 0; y < _yRes; y++) + for (x = 0; x < _xRes; x++) + { + + // back slab + index = x + y * _xRes + _blockTotalCells - _slabSize; + field[index] = field[index - _slabSize]; + } + + for (z = 0; z < zSize; z++) + for (x = 0; x < _xRes; x++) + { + // bottom slab + index = x + z * _slabSize; + field[index] = field[index + _xRes]; + + // top slab + index += _slabSize - _xRes; + field[index] = field[index - _xRes]; + } + + for (z = 0; z < zSize; z++) + for (y = 0; y < _yRes; y++) + { + // left slab + index = y * _xRes + z * _slabSize; + field[index] = field[index + 1]; + + // right slab + index += _xRes - 1; + field[index] = field[index - 1]; + } +} + +////////////////////////////////////////////////////////////////////// +// wipe boundaries of velocity and density +////////////////////////////////////////////////////////////////////// +void FLUID_3D::wipeBoundaries(int zBegin, int zEnd) +{ + setZeroBorder(_xVelocity, _res, zBegin, zEnd); + setZeroBorder(_yVelocity, _res, zBegin, zEnd); + setZeroBorder(_zVelocity, _res, zBegin, zEnd); + setZeroBorder(_density, _res, zBegin, zEnd); +} + +void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd) +{ + + ///////////////////////////////////// + // setZeroBorder to all: + ///////////////////////////////////// + + ///////////////////////////////////// + // setZeroX + ///////////////////////////////////// + + const int slabSize = _xRes * _yRes; + int index, x,y,z; + + for (z = zBegin; z < zEnd; z++) + for (y = 0; y < _yRes; y++) + { + // left slab + index = y * _xRes + z * slabSize; + _xVelocity[index] = 0.0f; + _yVelocity[index] = 0.0f; + _zVelocity[index] = 0.0f; + _density[index] = 0.0f; + + // right slab + index += _xRes - 1; + _xVelocity[index] = 0.0f; + _yVelocity[index] = 0.0f; + _zVelocity[index] = 0.0f; + _density[index] = 0.0f; + } + + ///////////////////////////////////// + // setZeroY + ///////////////////////////////////// + + for (z = zBegin; z < zEnd; z++) + for (x = 0; x < _xRes; x++) + { + // bottom slab + index = x + z * slabSize; + _xVelocity[index] = 0.0f; + _yVelocity[index] = 0.0f; + _zVelocity[index] = 0.0f; + _density[index] = 0.0f; + + // top slab + index += slabSize - _xRes; + _xVelocity[index] = 0.0f; + _yVelocity[index] = 0.0f; + _zVelocity[index] = 0.0f; + _density[index] = 0.0f; + + } + + ///////////////////////////////////// + // setZeroZ + ///////////////////////////////////// + + + const int totalCells = _xRes * _yRes * _zRes; + + index = 0; + if (zBegin == 0) + for (y = 0; y < _yRes; y++) + for (x = 0; x < _xRes; x++, index++) + { + // front slab + _xVelocity[index] = 0.0f; + _yVelocity[index] = 0.0f; + _zVelocity[index] = 0.0f; + _density[index] = 0.0f; + } + + if (zEnd == _zRes) + { + index=0; + int indexx=0; + const int cellsslab = totalCells - slabSize; + + for (y = 0; y < _yRes; y++) + for (x = 0; x < _xRes; x++, index++) + { + + // back slab + indexx = index + cellsslab; + _xVelocity[indexx] = 0.0f; + _yVelocity[indexx] = 0.0f; + _zVelocity[indexx] = 0.0f; + _density[indexx] = 0.0f; + } + } + +} +////////////////////////////////////////////////////////////////////// +// add forces to velocity field +////////////////////////////////////////////////////////////////////// +void FLUID_3D::addForce(int zBegin, int zEnd) +{ + int begin=zBegin * _slabSize; + int end=begin + (zEnd - zBegin) * _slabSize; + + for (int i = begin; i < end; i++) + { + _xVelocityTemp[i] = _xVelocity[i] + _dt * _xForce[i]; + _yVelocityTemp[i] = _yVelocity[i] + _dt * _yForce[i]; + _zVelocityTemp[i] = _zVelocity[i] + _dt * _zForce[i]; + } +} +////////////////////////////////////////////////////////////////////// +// project into divergence free field +////////////////////////////////////////////////////////////////////// +void FLUID_3D::project() +{ + int x, y, z; + size_t index; + + // float *_pressure = new float[_totalCells]; + float *_divergence = new float[_totalCells]; + + memset(_pressure, 0, sizeof(float)*_totalCells); + memset(_divergence, 0, sizeof(float)*_totalCells); + + // set VELOCITY and PRESSURE inside of obstacles cells to zero + setObstacleBoundaries(_pressure, 0, _zRes); + + // copy out the boundaries + if(_domainBcLeft == 0) setNeumannX(_xVelocity, _res, 0, _zRes); + else setZeroX(_xVelocity, _res, 0, _zRes); + + if(_domainBcFront == 0) setNeumannY(_yVelocity, _res, 0, _zRes); + else setZeroY(_yVelocity, _res, 0, _zRes); + + if(_domainBcTop == 0) setNeumannZ(_zVelocity, _res, 0, _zRes); + else setZeroZ(_zVelocity, _res, 0, _zRes); + + // calculate divergence + index = _slabSize + _xRes + 1; + for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes) + for (y = 1; y < _yRes - 1; y++, index += 2) + for (x = 1; x < _xRes - 1; x++, index++) + { + + if(_obstacles[index]) + { + _divergence[index] = 0.0f; + continue; + } + + float xright = _xVelocity[index + 1]; + float xleft = _xVelocity[index - 1]; + float yup = _yVelocity[index + _xRes]; + float ydown = _yVelocity[index - _xRes]; + float ztop = _zVelocity[index + _slabSize]; + float zbottom = _zVelocity[index - _slabSize]; + + if(_obstacles[index+1]) xright = - _xVelocity[index]; // DG: += + if(_obstacles[index-1]) xleft = - _xVelocity[index]; + if(_obstacles[index+_xRes]) yup = - _yVelocity[index]; + if(_obstacles[index-_xRes]) ydown = - _yVelocity[index]; + if(_obstacles[index+_slabSize]) ztop = - _zVelocity[index]; + if(_obstacles[index-_slabSize]) zbottom = - _zVelocity[index]; + + if(_obstacles[index+1]) xright += _xVelocityOb[index + 1]; + if(_obstacles[index-1]) xleft += _xVelocityOb[index - 1]; + if(_obstacles[index+_xRes]) yup += _yVelocityOb[index + _xRes]; + if(_obstacles[index-_xRes]) ydown += _yVelocityOb[index - _xRes]; + if(_obstacles[index+_slabSize]) ztop += _zVelocityOb[index + _slabSize]; + if(_obstacles[index-_slabSize]) zbottom += _zVelocityOb[index - _slabSize]; + + _divergence[index] = -_dx * 0.5f * ( + xright - xleft + + yup - ydown + + ztop - zbottom ); + + // Pressure is zero anyway since now a local array is used + _pressure[index] = 0.0f; + } + + // copyBorderAll(_pressure, 0, _zRes); + + // solve Poisson equation + solvePressurePre(_pressure, _divergence, _obstacles); + + // DG TODO: Alternative for solvePressurePre, does not work correctly + // solvePressureJacobian(_pressure, _divergence, _obstacles); + + { + float maxvalue = 0; + for(unsigned int i = 0; i < _xRes * _yRes * _zRes; i++) + { + if(_pressure[i] > maxvalue) + maxvalue = _pressure[i]; + + /* HACK: Animated collision object sometimes result in a non converging solvePressurePre() */ + if(_pressure[i] > _dx * _dt) + _pressure[i] = _dx * _dt; + else if(_pressure[i] < -_dx * _dt) + _pressure[i] = -_dx * _dt; + + // if(_obstacle[i] && _pressure[i] != 0.0) + // printf("BAD PRESSURE i\n"); + + // if(_pressure[i]>1) + // printf("index: %d\n", i); + } + // printf("Max pressure: %f, dx: %f\n", maxvalue, _dx); + } + + // DG TODO: check this function, for now this is done in the next function + // setObstaclePressure(_pressure, 0, _zRes); + + // project out solution + float invDx = 1.0f / _dx; + index = _slabSize + _xRes + 1; + for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes) + for (y = 1; y < _yRes - 1; y++, index += 2) + for (x = 1; x < _xRes - 1; x++, index++) + { + float vMask[3] = {1.0f, 1.0f, 1.0f}, vObst[3] = {0, 0, 0}; + float vR = 0.0f, vL = 0.0f, vT = 0.0f, vB = 0.0f, vD = 0.0f, vU = 0.0f; + + float pC = _pressure[index]; // center + float pR = _pressure[index + 1]; // right + float pL = _pressure[index - 1]; // left + float pT = _pressure[index + _slabSize]; // top + float pB = _pressure[index - _slabSize]; // bottom + float pU = _pressure[index + _xRes]; // Up + float pD = _pressure[index - _xRes]; // Down + + if(!_obstacles[index]) + { + // DG TODO: What if obstacle is left + right and one is moving? + if(_obstacles[index+1]) { pR = pC; vObst[0] = _xVelocityOb[index + 1]; vMask[0] = 0; } + if(_obstacles[index-1]) { pL = pC; vObst[0] = _xVelocityOb[index - 1]; vMask[0] = 0; } + if(_obstacles[index+_xRes]) { pU = pC; vObst[1] = _yVelocityOb[index + _xRes]; vMask[1] = 0; } + if(_obstacles[index-_xRes]) { pD = pC; vObst[1] = _yVelocityOb[index - _xRes]; vMask[1] = 0; } + if(_obstacles[index+_slabSize]) { pT = pC; vObst[2] = _zVelocityOb[index + _slabSize]; vMask[2] = 0; } + if(_obstacles[index-_slabSize]) { pB = pC; vObst[2] = _zVelocityOb[index - _slabSize]; vMask[2] = 0; } + + _xVelocity[index] -= 0.5f * (pR - pL) * invDx; + _yVelocity[index] -= 0.5f * (pU - pD) * invDx; + _zVelocity[index] -= 0.5f * (pT - pB) * invDx; + + _xVelocity[index] = (vMask[0] * _xVelocity[index]) + vObst[0]; + _yVelocity[index] = (vMask[1] * _yVelocity[index]) + vObst[1]; + _zVelocity[index] = (vMask[2] * _zVelocity[index]) + vObst[2]; + } + else + { + _xVelocity[index] = _xVelocityOb[index]; + _yVelocity[index] = _yVelocityOb[index]; + _zVelocity[index] = _zVelocityOb[index]; + } + } + + // setObstacleVelocity(0, _zRes); + + // if (_pressure) delete[] _pressure; + if (_divergence) delete[] _divergence; +} + +////////////////////////////////////////////////////////////////////// +// calculate the obstacle velocity at boundary +////////////////////////////////////////////////////////////////////// +void FLUID_3D::setObstacleVelocity(int zBegin, int zEnd) +{ + + // completely TODO <-- who wrote this and what is here TODO? DG + + const size_t index_ = _slabSize + _xRes + 1; + + //int vIndex=_slabSize + _xRes + 1; + + int bb=0; + int bt=0; + + if (zBegin == 0) {bb = 1;} + if (zEnd == _zRes) {bt = 1;} + + // tag remaining obstacle blocks + for (int z = zBegin + bb; z < zEnd - bt; z++) + { + size_t index = index_ +(z-1)*_slabSize; + + for (int y = 1; y < _yRes - 1; y++, index += 2) + { + for (int x = 1; x < _xRes - 1; x++, index++) + { + if (!_obstacles[index]) + { + // if(_obstacles[index+1]) xright = - _xVelocityOb[index]; + if((_obstacles[index - 1] & 8) && abs(_xVelocityOb[index - 1]) > FLT_EPSILON ) + { + // printf("velocity x!\n"); + _xVelocity[index] = _xVelocityOb[index - 1]; + _xVelocity[index - 1] = _xVelocityOb[index - 1]; + } + // if(_obstacles[index+_xRes]) yup = - _yVelocityOb[index]; + if((_obstacles[index - _xRes] & 8) && abs(_yVelocityOb[index - _xRes]) > FLT_EPSILON) + { + // printf("velocity y!\n"); + _yVelocity[index] = _yVelocityOb[index - _xRes]; + _yVelocity[index - _xRes] = _yVelocityOb[index - _xRes]; + } + // if(_obstacles[index+_slabSize]) ztop = - _zVelocityOb[index]; + if((_obstacles[index - _slabSize] & 8) && abs(_zVelocityOb[index - _slabSize]) > FLT_EPSILON) + { + // printf("velocity z!\n"); + _zVelocity[index] = _zVelocityOb[index - _slabSize]; + _zVelocity[index - _slabSize] = _zVelocityOb[index - _slabSize]; + } + } + else + { + _density[index] = 0; + } + //vIndex++; + } // x loop + //vIndex += 2; + } // y loop + //vIndex += 2 * _xRes; + } // z loop +} + +////////////////////////////////////////////////////////////////////// +// diffuse heat +////////////////////////////////////////////////////////////////////// +void FLUID_3D::diffuseHeat() +{ + SWAP_POINTERS(_heat, _heatOld); + + copyBorderAll(_heatOld, 0, _zRes); + solveHeat(_heat, _heatOld, _obstacles); + + // zero out inside obstacles + for (int x = 0; x < _totalCells; x++) + if (_obstacles[x]) + _heat[x] = 0.0f; + +} + +////////////////////////////////////////////////////////////////////// +// stamp an obstacle in the _obstacles field +////////////////////////////////////////////////////////////////////// +void FLUID_3D::addObstacle(OBSTACLE* obstacle) +{ + int index = 0; + for (int z = 0; z < _zRes; z++) + for (int y = 0; y < _yRes; y++) + for (int x = 0; x < _xRes; x++, index++) + if (obstacle->inside(x * _dx, y * _dx, z * _dx)) { + _obstacles[index] = true; + } +} + +////////////////////////////////////////////////////////////////////// +// calculate the obstacle directional types +////////////////////////////////////////////////////////////////////// +void FLUID_3D::setObstaclePressure(float *_pressure, int zBegin, int zEnd) +{ + + // completely TODO <-- who wrote this and what is here TODO? DG + + const size_t index_ = _slabSize + _xRes + 1; + + //int vIndex=_slabSize + _xRes + 1; + + int bb=0; + int bt=0; + + if (zBegin == 0) {bb = 1;} + if (zEnd == _zRes) {bt = 1;} + + // tag remaining obstacle blocks + for (int z = zBegin + bb; z < zEnd - bt; z++) + { + size_t index = index_ +(z-1)*_slabSize; + + for (int y = 1; y < _yRes - 1; y++, index += 2) + { + for (int x = 1; x < _xRes - 1; x++, index++) + { + // could do cascade of ifs, but they are a pain + if (_obstacles[index] /* && !(_obstacles[index] & 8) DG TODO TEST THIS CONDITION */) + { + const int top = _obstacles[index + _slabSize]; + const int bottom= _obstacles[index - _slabSize]; + const int up = _obstacles[index + _xRes]; + const int down = _obstacles[index - _xRes]; + const int left = _obstacles[index - 1]; + const int right = _obstacles[index + 1]; + + // unused + // const bool fullz = (top && bottom); + // const bool fully = (up && down); + //const bool fullx = (left && right); + + /* + _xVelocity[index] = + _yVelocity[index] = + _zVelocity[index] = 0.0f; + */ + _pressure[index] = 0.0f; + + // average pressure neighbors + float pcnt = 0.; + if (left && !right) { + _pressure[index] += _pressure[index + 1]; + pcnt += 1.; + } + if (!left && right) { + _pressure[index] += _pressure[index - 1]; + pcnt += 1.; + } + if (up && !down) { + _pressure[index] += _pressure[index - _xRes]; + pcnt += 1.; + } + if (!up && down) { + _pressure[index] += _pressure[index + _xRes]; + pcnt += 1.; + } + if (top && !bottom) { + _pressure[index] += _pressure[index - _slabSize]; + pcnt += 1.; + } + if (!top && bottom) { + _pressure[index] += _pressure[index + _slabSize]; + pcnt += 1.; + } + + if(pcnt > 0.000001f) + _pressure[index] /= pcnt; + + // TODO? set correct velocity bc's + // velocities are only set to zero right now + // this means it's not a full no-slip boundary condition + // but a "half-slip" - still looks ok right now + } + //vIndex++; + } // x loop + //vIndex += 2; + } // y loop + //vIndex += 2 * _xRes; + } // z loop +} + +void FLUID_3D::setObstacleBoundaries(float *_pressure, int zBegin, int zEnd) +{ + // cull degenerate obstacles , move to addObstacle? + + // r = b - Ax + const size_t index_ = _slabSize + _xRes + 1; + + int bb=0; + int bt=0; + + if (zBegin == 0) {bb = 1;} + if (zEnd == _zRes) {bt = 1;} + + for (int z = zBegin + bb; z < zEnd - bt; z++) + { + size_t index = index_ +(z-1)*_slabSize; + + for (int y = 1; y < _yRes - 1; y++, index += 2) + { + for (int x = 1; x < _xRes - 1; x++, index++) + { + if (_obstacles[index] != EMPTY) + { + const int top = _obstacles[index + _slabSize]; + const int bottom= _obstacles[index - _slabSize]; + const int up = _obstacles[index + _xRes]; + const int down = _obstacles[index - _xRes]; + const int left = _obstacles[index - 1]; + const int right = _obstacles[index + 1]; + + int counter = 0; + if (up) counter++; + if (down) counter++; + if (left) counter++; + if (right) counter++; + if (top) counter++; + if (bottom) counter++; + + // DG TODO: Do not shrink obstacles for now + // if (counter < 3) + // _obstacles[index] = EMPTY; + } + if (_obstacles[index]) + { + _xVelocity[index] = + _yVelocity[index] = + _zVelocity[index] = 0.0f; + _pressure[index] = 0.0f; + } + //vIndex++; + } // x-loop + //vIndex += 2; + } // y-loop + //vIndex += 2* _xRes; + } // z-loop +} + +////////////////////////////////////////////////////////////////////// +// add buoyancy forces +////////////////////////////////////////////////////////////////////// +void FLUID_3D::addBuoyancy(float *heat, float *density, int zBegin, int zEnd) +{ + int index = zBegin*_slabSize; + + for (int z = zBegin; z < zEnd; z++) + for (int y = 0; y < _yRes; y++) + for (int x = 0; x < _xRes; x++, index++) + { + _zForce[index] += *_alpha * density[index] + (*_beta * (heat[index] - _tempAmb)); // DG: was _yForce, changed for Blender + } +} + +////////////////////////////////////////////////////////////////////// +// add vorticity to the force field +////////////////////////////////////////////////////////////////////// +void FLUID_3D::addVorticity(int zBegin, int zEnd) +{ + //int x,y,z,index; + if(_vorticityEps<=0.) return; + + int _blockSize=zEnd-zBegin; + int _blockTotalCells = _slabSize * (_blockSize+2); + + float *_xVorticity, *_yVorticity, *_zVorticity, *_vorticity; + + int bb=0; + int bt=0; + int bb1=-1; + int bt1=-1; + + if (zBegin == 0) {bb1 = 1; bb = 1; _blockTotalCells-=_blockSize;} + if (zEnd == _zRes) {bt1 = 1;bt = 1; _blockTotalCells-=_blockSize;} + + _xVorticity = new float[_blockTotalCells]; + _yVorticity = new float[_blockTotalCells]; + _zVorticity = new float[_blockTotalCells]; + _vorticity = new float[_blockTotalCells]; + + memset(_xVorticity, 0, sizeof(float)*_blockTotalCells); + memset(_yVorticity, 0, sizeof(float)*_blockTotalCells); + memset(_zVorticity, 0, sizeof(float)*_blockTotalCells); + memset(_vorticity, 0, sizeof(float)*_blockTotalCells); + + //const size_t indexsetupV=_slabSize; + const size_t index_ = _slabSize + _xRes + 1; + + // calculate vorticity + float gridSize = 0.5f / _dx; + //index = _slabSize + _xRes + 1; + + + size_t vIndex=_xRes + 1; + + for (int z = zBegin + bb1; z < (zEnd - bt1); z++) + { + size_t index = index_ +(z-1)*_slabSize; + vIndex = index-(zBegin-1+bb)*_slabSize; + + for (int y = 1; y < _yRes - 1; y++, index += 2) + { + for (int x = 1; x < _xRes - 1; x++, index++) + { + + int up = _obstacles[index + _xRes] ? index : index + _xRes; + int down = _obstacles[index - _xRes] ? index : index - _xRes; + float dy = (up == index || down == index) ? 1.0f / _dx : gridSize; + int out = _obstacles[index + _slabSize] ? index : index + _slabSize; + int in = _obstacles[index - _slabSize] ? index : index - _slabSize; + float dz = (out == index || in == index) ? 1.0f / _dx : gridSize; + int right = _obstacles[index + 1] ? index : index + 1; + int left = _obstacles[index - 1] ? index : index - 1; + float dx = (right == index || left == index) ? 1.0f / _dx : gridSize; + + _xVorticity[vIndex] = (_zVelocity[up] - _zVelocity[down]) * dy + (-_yVelocity[out] + _yVelocity[in]) * dz; + _yVorticity[vIndex] = (_xVelocity[out] - _xVelocity[in]) * dz + (-_zVelocity[right] + _zVelocity[left]) * dx; + _zVorticity[vIndex] = (_yVelocity[right] - _yVelocity[left]) * dx + (-_xVelocity[up] + _xVelocity[down])* dy; + + _vorticity[vIndex] = sqrtf(_xVorticity[vIndex] * _xVorticity[vIndex] + + _yVorticity[vIndex] * _yVorticity[vIndex] + + _zVorticity[vIndex] * _zVorticity[vIndex]); + + vIndex++; + } + vIndex+=2; + } + //vIndex+=2*_xRes; + } + + // calculate normalized vorticity vectors + float eps = _vorticityEps; + + //index = _slabSize + _xRes + 1; + vIndex=_slabSize + _xRes + 1; + + for (int z = zBegin + bb; z < (zEnd - bt); z++) + { + size_t index = index_ +(z-1)*_slabSize; + vIndex = index-(zBegin-1+bb)*_slabSize; + + for (int y = 1; y < _yRes - 1; y++, index += 2) + { + for (int x = 1; x < _xRes - 1; x++, index++) + { + // + + if (!_obstacles[index]) + { + float N[3]; + + int up = _obstacles[index + _xRes] ? vIndex : vIndex + _xRes; + int down = _obstacles[index - _xRes] ? vIndex : vIndex - _xRes; + float dy = (up == vIndex || down == vIndex) ? 1.0f / _dx : gridSize; + int out = _obstacles[index + _slabSize] ? vIndex : vIndex + _slabSize; + int in = _obstacles[index - _slabSize] ? vIndex : vIndex - _slabSize; + float dz = (out == vIndex || in == vIndex) ? 1.0f / _dx : gridSize; + int right = _obstacles[index + 1] ? vIndex : vIndex + 1; + int left = _obstacles[index - 1] ? vIndex : vIndex - 1; + float dx = (right == vIndex || left == vIndex) ? 1.0f / _dx : gridSize; + N[0] = (_vorticity[right] - _vorticity[left]) * dx; + N[1] = (_vorticity[up] - _vorticity[down]) * dy; + N[2] = (_vorticity[out] - _vorticity[in]) * dz; + + float magnitude = sqrtf(N[0] * N[0] + N[1] * N[1] + N[2] * N[2]); + if (magnitude > 0.0f) + { + magnitude = 1.0f / magnitude; + N[0] *= magnitude; + N[1] *= magnitude; + N[2] *= magnitude; + + _xForce[index] += (N[1] * _zVorticity[vIndex] - N[2] * _yVorticity[vIndex]) * _dx * eps; + _yForce[index] -= (N[0] * _zVorticity[vIndex] - N[2] * _xVorticity[vIndex]) * _dx * eps; + _zForce[index] += (N[0] * _yVorticity[vIndex] - N[1] * _xVorticity[vIndex]) * _dx * eps; + } + } // if + vIndex++; + } // x loop + vIndex+=2; + } // y loop + //vIndex+=2*_xRes; + } // z loop + + if (_xVorticity) delete[] _xVorticity; + if (_yVorticity) delete[] _yVorticity; + if (_zVorticity) delete[] _zVorticity; + if (_vorticity) delete[] _vorticity; +} + + +void FLUID_3D::advectMacCormackBegin(int zBegin, int zEnd) +{ + Vec3Int res = Vec3Int(_xRes,_yRes,_zRes); + + if(_domainBcLeft == 0) copyBorderX(_xVelocityOld, res, zBegin, zEnd); + else setZeroX(_xVelocityOld, res, zBegin, zEnd); + + if(_domainBcFront == 0) copyBorderY(_yVelocityOld, res, zBegin, zEnd); + else setZeroY(_yVelocityOld, res, zBegin, zEnd); + + if(_domainBcTop == 0) copyBorderZ(_zVelocityOld, res, zBegin, zEnd); + else setZeroZ(_zVelocityOld, res, zBegin, zEnd); +} + +////////////////////////////////////////////////////////////////////// +// Advect using the MacCormack method from the Selle paper +////////////////////////////////////////////////////////////////////// +void FLUID_3D::advectMacCormackEnd1(int zBegin, int zEnd) +{ + Vec3Int res = Vec3Int(_xRes,_yRes,_zRes); + + const float dt0 = _dt / _dx; + + int begin=zBegin * _slabSize; + int end=begin + (zEnd - zBegin) * _slabSize; + for (int x = begin; x < end; x++) + _xForce[x] = 0.0; + + // advectFieldMacCormack1(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res) + + advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _densityTemp, res, zBegin, zEnd); + advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heatTemp, res, zBegin, zEnd); + advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocity, res, zBegin, zEnd); + advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocity, res, zBegin, zEnd); + advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocity, res, zBegin, zEnd); + + // Have to wait untill all the threads are done -> so continuing in step 3 +} + +////////////////////////////////////////////////////////////////////// +// Advect using the MacCormack method from the Selle paper +////////////////////////////////////////////////////////////////////// +void FLUID_3D::advectMacCormackEnd2(int zBegin, int zEnd) +{ + const float dt0 = _dt / _dx; + Vec3Int res = Vec3Int(_xRes,_yRes,_zRes); + + // use force array as temp arrays + float* t1 = _xForce; + + // advectFieldMacCormack2(dt, xVelocity, yVelocity, zVelocity, oldField, newField, tempfield, temp, res, obstacles) + + advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _density, _densityTemp, t1, res, _obstacles, zBegin, zEnd); + advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heat, _heatTemp, t1, res, _obstacles, zBegin, zEnd); + advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocityTemp, _xVelocity, t1, res, _obstacles, zBegin, zEnd); + advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocityTemp, _yVelocity, t1, res, _obstacles, zBegin, zEnd); + advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocityTemp, _zVelocity, t1, res, _obstacles, zBegin, zEnd); + + if(_domainBcLeft == 0) copyBorderX(_xVelocityTemp, res, zBegin, zEnd); + else setZeroX(_xVelocityTemp, res, zBegin, zEnd); + + if(_domainBcFront == 0) copyBorderY(_yVelocityTemp, res, zBegin, zEnd); + else setZeroY(_yVelocityTemp, res, zBegin, zEnd); + + if(_domainBcTop == 0) copyBorderZ(_zVelocityTemp, res, zBegin, zEnd); + else setZeroZ(_zVelocityTemp, res, zBegin, zEnd); + + setZeroBorder(_density, res, zBegin, zEnd); + setZeroBorder(_heat, res, zBegin, zEnd); +#if 0 + { + const size_t index_ = _slabSize + _xRes + 1; + int bb=0; + int bt=0; + + if (zBegin == 0) {bb = 1;} + if (zEnd == _zRes) {bt = 1;} + + for (int z = zBegin + bb; z < zEnd - bt; z++) + { + size_t index = index_ +(z-1)*_slabSize; + + for (int y = 1; y < _yRes - 1; y++, index += 2) + { + for (int x = 1; x < _xRes - 1; x++, index++) + { + // clean custom velocities from moving obstacles again + if (_obstacles[index]) + { + _xVelocity[index] = + _yVelocity[index] = + _zVelocity[index] = 0.0f; + } + } + } + } + } +#endif + + /*int begin=zBegin * _slabSize; + int end=begin + (zEnd - zBegin) * _slabSize; + for (int x = begin; x < end; x++) + _xForce[x] = _yForce[x] = 0.0f;*/ +} diff --git a/intern/smoke/intern/FLUID_3D.h b/intern/smoke/intern/FLUID_3D.h new file mode 100644 index 00000000000..0e7863df6c6 --- /dev/null +++ b/intern/smoke/intern/FLUID_3D.h @@ -0,0 +1,231 @@ +/** \file smoke/intern/FLUID_3D.h + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +// FLUID_3D.h: interface for the FLUID_3D class. +// +////////////////////////////////////////////////////////////////////// +// Heavy parallel optimization done. Many of the old functions now +// take begin and end parameters and process only specified part of the data. +// Some functions were divided into multiple ones. +// - MiikaH +////////////////////////////////////////////////////////////////////// + +#ifndef FLUID_3D_H +#define FLUID_3D_H + +#include <cstdlib> +#include <cmath> +#include <cstring> +#include <iostream> +#include "OBSTACLE.h" +// #include "WTURBULENCE.h" +#include "VEC3.h" + +using namespace std; +using namespace BasicVector; +class WTURBULENCE; + +class FLUID_3D +{ + public: + FLUID_3D(int *res, /* int amplify, */ float *p0, float dtdef); + FLUID_3D() {}; + virtual ~FLUID_3D(); + + void initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli); + + // create & allocate vector noise advection + void initVectorNoise(int amplify); + + void addSmokeColumn(); + static void addSmokeTestCase(float* field, Vec3Int res); + + void step(float dt); + void addObstacle(OBSTACLE* obstacle); + + const float* xVelocity() { return _xVelocity; }; + const float* yVelocity() { return _yVelocity; }; + const float* zVelocity() { return _zVelocity; }; + + int xRes() const { return _xRes; }; + int yRes() const { return _yRes; }; + int zRes() const { return _zRes; }; + + public: + // dimensions + int _xRes, _yRes, _zRes, _maxRes; + Vec3Int _res; + size_t _totalCells; + int _slabSize; + float _dx; + float _p0[3]; + float _p1[3]; + float _totalTime; + int _totalSteps; + int _totalImgDumps; + int _totalVelDumps; + + void artificialDampingSL(int zBegin, int zEnd); + void artificialDampingExactSL(int pos); + + void setBorderObstacles(); + + // fields + float* _density; + float* _densityOld; + float* _heat; + float* _heatOld; + float* _xVelocity; + float* _yVelocity; + float* _zVelocity; + float* _xVelocityOb; + float* _yVelocityOb; + float* _zVelocityOb; + float* _xVelocityOld; + float* _yVelocityOld; + float* _zVelocityOld; + float* _xForce; + float* _yForce; + float* _zForce; + unsigned char* _obstacles; /* only used (usefull) for static obstacles like domain boundaries */ + unsigned char* _obstaclesAnim; + + // for debug purposes + float *_pressure; + + // Required for proper threading: + float* _xVelocityTemp; + float* _yVelocityTemp; + float* _zVelocityTemp; + float* _heatTemp; + float* _densityTemp; + + // CG fields + int _iterations; + + // simulation constants + float _dt; + float *_dtFactor; + float _vorticityEps; + float _heatDiffusion; + float *_vorticityRNA; // RNA-pointer. + float *_alpha; // for the buoyancy density term <-- as pointer to get blender RNA in here + float *_beta; // was _buoyancy <-- as pointer to get blender RNA in here + float _tempAmb; /* ambient temperature */ + float _constantScaling; + + bool _domainBcFront; // z + bool _domainBcTop; // y + bool _domainBcLeft; // x + bool _domainBcBack; // DOMAIN_BC_FRONT + bool _domainBcBottom; // DOMAIN_BC_TOP + bool _domainBcRight; // DOMAIN_BC_LEFT + int *_borderColli; // border collision rules <-- as pointer to get blender RNA in here + int _colloPrev; // To track whether value has been changed (to not + // have to recalibrate borders if nothing has changed + void setBorderCollisions(); + + void setObstacleVelocity(int zBegin, int zEnd); + + // WTURBULENCE object, if active + // WTURBULENCE* _wTurbulence; + + // boundary setting functions + void copyBorderAll(float* field, int zBegin, int zEnd); + + // timestepping functions + void wipeBoundaries(int zBegin, int zEnd); + void wipeBoundariesSL(int zBegin, int zEnd); + void addForce(int zBegin, int zEnd); + void addVorticity(int zBegin, int zEnd); + void addBuoyancy(float *heat, float *density, int zBegin, int zEnd); + + // solver stuff + void project(); + void diffuseHeat(); + void solvePressure(float* field, float* b, unsigned char* skip); + + void solvePressurePre(float* field, float* b, unsigned char* skip); + void solvePressureJacobian(float* p, float* d, unsigned char* ob); + + void solveHeat(float* field, float* b, unsigned char* skip); + + + // handle obstacle boundaries + void setObstacleBoundaries(float *_pressure, int zBegin, int zEnd); + void setObstaclePressure(float *_pressure, int zBegin, int zEnd); + + public: + // advection, accessed e.g. by WTURBULENCE class + //void advectMacCormack(); + void advectMacCormackBegin(int zBegin, int zEnd); + void advectMacCormackEnd1(int zBegin, int zEnd); + void advectMacCormackEnd2(int zBegin, int zEnd); + + // boundary setting functions + static void copyBorderX(float* field, Vec3Int res, int zBegin, int zEnd); + static void copyBorderY(float* field, Vec3Int res, int zBegin, int zEnd); + static void copyBorderZ(float* field, Vec3Int res, int zBegin, int zEnd); + static void setNeumannX(float* field, Vec3Int res, int zBegin, int zEnd); + static void setNeumannY(float* field, Vec3Int res, int zBegin, int zEnd); + static void setNeumannZ(float* field, Vec3Int res, int zBegin, int zEnd); + static void setZeroX(float* field, Vec3Int res, int zBegin, int zEnd); + static void setZeroY(float* field, Vec3Int res, int zBegin, int zEnd); + static void setZeroZ(float* field, Vec3Int res, int zBegin, int zEnd); + static void setZeroBorder(float* field, Vec3Int res, int zBegin, int zEnd) { + setZeroX(field, res, zBegin, zEnd); + setZeroY(field, res, zBegin, zEnd); + setZeroZ(field, res, zBegin, zEnd); + }; + + + + // static advection functions, also used by WTURBULENCE + static void advectFieldSemiLagrange(const float dt, const float* velx, const float* vely, const float* velz, + float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd); + static void advectFieldMacCormack1(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity, + float* oldField, float* tempResult, Vec3Int res, int zBegin, int zEnd); + static void advectFieldMacCormack2(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity, + float* oldField, float* newField, float* tempResult, float* temp1,Vec3Int res, const unsigned char* obstacles, int zBegin, int zEnd); + + + // temp ones for testing + /*static void advectFieldMacCormack(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity, + float* oldField, float* newField, float* temp1, float* temp2, Vec3Int res, const unsigned char* obstacles);*/ + /*static void advectFieldSemiLagrange2(const float dt, const float* velx, const float* vely, const float* velz, + float* oldField, float* newField, Vec3Int res);*/ + + // maccormack helper functions + static void clampExtrema(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity, + float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd); + static void clampOutsideRays(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity, + float* oldField, float* newField, Vec3Int res, const unsigned char* obstacles, const float *oldAdvection, int zBegin, int zEnd); + + + + // output helper functions + // static void writeImageSliceXY(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.); + // static void writeImageSliceYZ(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.); + // static void writeImageSliceXZ(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.); + // static void writeProjectedIntern(const float *field, Vec3Int res, int dir1, int dir2, string prefix, int picCnt, float scale=1.); +}; + +#endif diff --git a/intern/smoke/intern/FLUID_3D_SOLVERS.cpp b/intern/smoke/intern/FLUID_3D_SOLVERS.cpp new file mode 100644 index 00000000000..eaadccf566e --- /dev/null +++ b/intern/smoke/intern/FLUID_3D_SOLVERS.cpp @@ -0,0 +1,389 @@ +/** \file smoke/intern/FLUID_3D_SOLVERS.cpp + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +// FLUID_3D.cpp: implementation of the FLUID_3D class. +// +////////////////////////////////////////////////////////////////////// +// Both solvers optimized by merging loops and precalculating +// stuff used in iteration loop. +// - MiikaH +////////////////////////////////////////////////////////////////////// + +#include "FLUID_3D.h" +#include <cstring> +#define SOLVER_ACCURACY 1e-06 + +////////////////////////////////////////////////////////////////////// +// solve the heat equation with CG +////////////////////////////////////////////////////////////////////// +void FLUID_3D::solveHeat(float* field, float* b, unsigned char* skip) +{ + int x, y, z; + const int twoxr = 2 * _xRes; + size_t index; + const float heatConst = _dt * _heatDiffusion / (_dx * _dx); + float *_q, *_residual, *_direction, *_Acenter; + + // i = 0 + int i = 0; + + _residual = new float[_totalCells]; // set 0 + _direction = new float[_totalCells]; // set 0 + _q = new float[_totalCells]; // set 0 + _Acenter = new float[_totalCells]; // set 0 + + memset(_residual, 0, sizeof(float)*_totalCells); + memset(_q, 0, sizeof(float)*_totalCells); + memset(_direction, 0, sizeof(float)*_totalCells); + memset(_Acenter, 0, sizeof(float)*_totalCells); + + float deltaNew = 0.0f; + + // r = b - Ax + index = _slabSize + _xRes + 1; + for (z = 1; z < _zRes - 1; z++, index += twoxr) + for (y = 1; y < _yRes - 1; y++, index += 2) + for (x = 1; x < _xRes - 1; x++, index++) + { + // if the cell is a variable + _Acenter[index] = 1.0f; + if (!skip[index]) + { + // set the matrix to the Poisson stencil in order + if (!skip[index + 1]) _Acenter[index] += heatConst; + if (!skip[index - 1]) _Acenter[index] += heatConst; + if (!skip[index + _xRes]) _Acenter[index] += heatConst; + if (!skip[index - _xRes]) _Acenter[index] += heatConst; + if (!skip[index + _slabSize]) _Acenter[index] += heatConst; + if (!skip[index - _slabSize]) _Acenter[index] += heatConst; + + _residual[index] = b[index] - (_Acenter[index] * field[index] + + field[index - 1] * (skip[index - 1] ? 0.0 : -heatConst) + + field[index + 1] * (skip[index + 1] ? 0.0 : -heatConst) + + field[index - _xRes] * (skip[index - _xRes] ? 0.0 : -heatConst) + + field[index + _xRes] * (skip[index + _xRes] ? 0.0 : -heatConst) + + field[index - _slabSize] * (skip[index - _slabSize] ? 0.0 : -heatConst) + + field[index + _slabSize] * (skip[index + _slabSize] ? 0.0 : -heatConst)); + } + else + { + _residual[index] = 0.0f; + } + + _direction[index] = _residual[index]; + deltaNew += _residual[index] * _residual[index]; + } + + + // While deltaNew > (eps^2) * delta0 + const float eps = SOLVER_ACCURACY; + float maxR = 2.0f * eps; + while ((i < _iterations) && (maxR > eps)) + { + // q = Ad + float alpha = 0.0f; + + index = _slabSize + _xRes + 1; + for (z = 1; z < _zRes - 1; z++, index += twoxr) + for (y = 1; y < _yRes - 1; y++, index += 2) + for (x = 1; x < _xRes - 1; x++, index++) + { + // if the cell is a variable + if (!skip[index]) + { + + _q[index] = (_Acenter[index] * _direction[index] + + _direction[index - 1] * (skip[index - 1] ? 0.0 : -heatConst) + + _direction[index + 1] * (skip[index + 1] ? 0.0 : -heatConst) + + _direction[index - _xRes] * (skip[index - _xRes] ? 0.0 : -heatConst) + + _direction[index + _xRes] * (skip[index + _xRes] ? 0.0 : -heatConst) + + _direction[index - _slabSize] * (skip[index - _slabSize] ? 0.0 : -heatConst) + + _direction[index + _slabSize] * (skip[index + _slabSize] ? 0.0 : -heatConst)); + } + else + { + _q[index] = 0.0f; + } + alpha += _direction[index] * _q[index]; + } + + if (fabs(alpha) > 0.0f) + alpha = deltaNew / alpha; + + float deltaOld = deltaNew; + deltaNew = 0.0f; + + maxR = 0.0f; + + index = _slabSize + _xRes + 1; + for (z = 1; z < _zRes - 1; z++, index += twoxr) + for (y = 1; y < _yRes - 1; y++, index += 2) + for (x = 1; x < _xRes - 1; x++, index++) + { + field[index] += alpha * _direction[index]; + + _residual[index] -= alpha * _q[index]; + maxR = (_residual[index] > maxR) ? _residual[index] : maxR; + + deltaNew += _residual[index] * _residual[index]; + } + + float beta = deltaNew / deltaOld; + + index = _slabSize + _xRes + 1; + for (z = 1; z < _zRes - 1; z++, index += twoxr) + for (y = 1; y < _yRes - 1; y++, index += 2) + for (x = 1; x < _xRes - 1; x++, index++) + _direction[index] = _residual[index] + beta * _direction[index]; + + + i++; + } + // cout << i << " iterations converged to " << maxR << endl; + + if (_residual) delete[] _residual; + if (_direction) delete[] _direction; + if (_q) delete[] _q; + if (_Acenter) delete[] _Acenter; +} + + +void FLUID_3D::solvePressurePre(float* field, float* b, unsigned char* skip) +{ + int x, y, z; + size_t index; + float *_q, *_Precond, *_h, *_residual, *_direction; + + // i = 0 + int i = 0; + + _residual = new float[_totalCells]; // set 0 + _direction = new float[_totalCells]; // set 0 + _q = new float[_totalCells]; // set 0 + _h = new float[_totalCells]; // set 0 + _Precond = new float[_totalCells]; // set 0 + + memset(_residual, 0, sizeof(float)*_xRes*_yRes*_zRes); + memset(_q, 0, sizeof(float)*_xRes*_yRes*_zRes); + memset(_direction, 0, sizeof(float)*_xRes*_yRes*_zRes); + memset(_h, 0, sizeof(float)*_xRes*_yRes*_zRes); + memset(_Precond, 0, sizeof(float)*_xRes*_yRes*_zRes); + + float deltaNew = 0.0f; + + // r = b - Ax + index = _slabSize + _xRes + 1; + for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes) + for (y = 1; y < _yRes - 1; y++, index += 2) + for (x = 1; x < _xRes - 1; x++, index++) + { + // if the cell is a variable + float Acenter = 0.0f; + if (!skip[index]) + { + // set the matrix to the Poisson stencil in order + if (!skip[index + 1]) Acenter += 1.; + if (!skip[index - 1]) Acenter += 1.; + if (!skip[index + _xRes]) Acenter += 1.; + if (!skip[index - _xRes]) Acenter += 1.; + if (!skip[index + _slabSize]) Acenter += 1.; + if (!skip[index - _slabSize]) Acenter += 1.; + + _residual[index] = b[index] - (Acenter * field[index] + + field[index - 1] * (skip[index - 1] ? 0.0 : -1.0f)+ + field[index + 1] * (skip[index + 1] ? 0.0 : -1.0f)+ + field[index - _xRes] * (skip[index - _xRes] ? 0.0 : -1.0f)+ + field[index + _xRes] * (skip[index + _xRes] ? 0.0 : -1.0f)+ + field[index - _slabSize] * (skip[index - _slabSize] ? 0.0 : -1.0f)+ + field[index + _slabSize] * (skip[index + _slabSize] ? 0.0 : -1.0f) ); + } + else + { + _residual[index] = 0.0f; + } + + // P^-1 + if(Acenter < 1.0) + _Precond[index] = 0.0; + else + _Precond[index] = 1.0 / Acenter; + + // p = P^-1 * r + _direction[index] = _residual[index] * _Precond[index]; + + deltaNew += _residual[index] * _direction[index]; + } + + + // While deltaNew > (eps^2) * delta0 + const float eps = SOLVER_ACCURACY; + //while ((i < _iterations) && (deltaNew > eps*delta0)) + float maxR = 2.0f * eps; + // while (i < _iterations) + while ((i < _iterations) && (maxR > 0.001*eps)) + { + + float alpha = 0.0f; + + index = _slabSize + _xRes + 1; + for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes) + for (y = 1; y < _yRes - 1; y++, index += 2) + for (x = 1; x < _xRes - 1; x++, index++) + { + // if the cell is a variable + float Acenter = 0.0f; + if (!skip[index]) + { + // set the matrix to the Poisson stencil in order + if (!skip[index + 1]) Acenter += 1.; + if (!skip[index - 1]) Acenter += 1.; + if (!skip[index + _xRes]) Acenter += 1.; + if (!skip[index - _xRes]) Acenter += 1.; + if (!skip[index + _slabSize]) Acenter += 1.; + if (!skip[index - _slabSize]) Acenter += 1.; + + _q[index] = Acenter * _direction[index] + + _direction[index - 1] * (skip[index - 1] ? 0.0 : -1.0f) + + _direction[index + 1] * (skip[index + 1] ? 0.0 : -1.0f) + + _direction[index - _xRes] * (skip[index - _xRes] ? 0.0 : -1.0f) + + _direction[index + _xRes] * (skip[index + _xRes] ? 0.0 : -1.0f)+ + _direction[index - _slabSize] * (skip[index - _slabSize] ? 0.0 : -1.0f) + + _direction[index + _slabSize] * (skip[index + _slabSize] ? 0.0 : -1.0f); + } + else + { + _q[index] = 0.0f; + } + + alpha += _direction[index] * _q[index]; + } + + + if (fabs(alpha) > 0.0f) + alpha = deltaNew / alpha; + + float deltaOld = deltaNew; + deltaNew = 0.0f; + + maxR = 0.0; + + float tmp; + + // x = x + alpha * d + index = _slabSize + _xRes + 1; + for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes) + for (y = 1; y < _yRes - 1; y++, index += 2) + for (x = 1; x < _xRes - 1; x++, index++) + { + field[index] += alpha * _direction[index]; + + _residual[index] -= alpha * _q[index]; + + _h[index] = _Precond[index] * _residual[index]; + + tmp = _residual[index] * _h[index]; + deltaNew += tmp; + maxR = (tmp > maxR) ? tmp : maxR; + + } + + + // beta = deltaNew / deltaOld + float beta = deltaNew / deltaOld; + + // d = h + beta * d + index = _slabSize + _xRes + 1; + for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes) + for (y = 1; y < _yRes - 1; y++, index += 2) + for (x = 1; x < _xRes - 1; x++, index++) + _direction[index] = _h[index] + beta * _direction[index]; + + // i = i + 1 + i++; + } + // cout << i << " iterations converged to " << sqrt(maxR) << endl; + + if (_h) delete[] _h; + if (_Precond) delete[] _Precond; + if (_residual) delete[] _residual; + if (_direction) delete[] _direction; + if (_q) delete[] _q; +} +#if 0 +void FLUID_3D::solvePressureJacobian(float* p, float* d, unsigned char* ob) +{ + float *_tmp = new float[_totalCells]; + unsigned int x, y, z; + + float maxdp = 0.0f; + + do + { + maxdp = 0.0f; + + size_t index = _slabSize + _xRes + 1; + for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes) + for (y = 1; y < _yRes - 1; y++, index += 2) + for (x = 1; x < _xRes - 1; x++, index++) + { + float dC = d[index]; + float pC = p[index]; // center + + float pR = p[index + 1]; // right + float pL = p[index - 1]; // left + float pT = p[index + _slabSize]; // top + float pB = p[index - _slabSize]; // bottom + float pU = p[index + _xRes]; // Up + float pD = p[index - _xRes]; // Down + + if(ob[index + 1]) pR = pC; + if(ob[index - 1]) pL = pC; + if(ob[index + _slabSize]) pT = pC; + if(ob[index - _slabSize]) pB = pC; + if(ob[index + _xRes]) pU = pC; + if(ob[index - _xRes]) pD = pC; + + _tmp[index] = (pR + pL + pT + pB + pU + pD + dC) / 6.0f; + + if(ob[index]) + _tmp[index] = 0; + } + + for(unsigned int i = 0; i < _totalCells; i++) + { + float dp = _tmp[i] - p[i]; + + if(dp < 0) + dp *= -1.0f; + + if(dp > maxdp) + maxdp = dp; + + p[i] = _tmp[i]; + } + printf("maxdp: %f\n", maxdp); + } while(maxdp > SOLVER_ACCURACY); + + printf("\n"); + + if (_tmp) delete[] _tmp; +} +#endif diff --git a/intern/smoke/intern/FLUID_3D_STATIC.cpp b/intern/smoke/intern/FLUID_3D_STATIC.cpp new file mode 100644 index 00000000000..85b3657dc92 --- /dev/null +++ b/intern/smoke/intern/FLUID_3D_STATIC.cpp @@ -0,0 +1,685 @@ +/** \file smoke/intern/FLUID_3D_STATIC.cpp + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +// FLUID_3D.cpp: implementation of the static functions of the FLUID_3D class. +// +////////////////////////////////////////////////////////////////////// +// Heavy parallel optimization done. Many of the old functions now +// take begin and end parameters and process only specified part of the data. +// Some functions were divided into multiple ones. +// - MiikaH +////////////////////////////////////////////////////////////////////// + +#include <zlib.h> +#include "FLUID_3D.h" +#include "IMAGE.h" +#include "WTURBULENCE.h" +#include "INTERPOLATE.h" + +////////////////////////////////////////////////////////////////////// +// add a test cube of density to the center +////////////////////////////////////////////////////////////////////// +/* +void FLUID_3D::addSmokeColumn() { + addSmokeTestCase(_density, _res, 1.0); + // addSmokeTestCase(_zVelocity, _res, 1.0); + addSmokeTestCase(_heat, _res, 1.0); + if (_wTurbulence) { + addSmokeTestCase(_wTurbulence->getDensityBig(), _wTurbulence->getResBig(), 1.0); + } +} +*/ + +////////////////////////////////////////////////////////////////////// +// generic static version, so that it can be applied to the +// WTURBULENCE grid as well +////////////////////////////////////////////////////////////////////// + +void FLUID_3D::addSmokeTestCase(float* field, Vec3Int res) +{ + const int slabSize = res[0]*res[1]; int maxRes = (int)MAX3V(res); + float dx = 1.0f / (float)maxRes; + + float xTotal = dx * res[0]; + float yTotal = dx * res[1]; + + float heighMin = 0.05; + float heighMax = 0.10; + + for (int y = 0; y < res[2]; y++) + for (int z = (int)(heighMin*res[2]); z <= (int)(heighMax * res[2]); z++) + for (int x = 0; x < res[0]; x++) { + float xLength = x * dx - xTotal * 0.4f; + float yLength = y * dx - yTotal * 0.5f; + float radius = sqrtf(xLength * xLength + yLength * yLength); + + if (radius < 0.075f * xTotal) { + int index = x + y * res[0] + z * slabSize; + field[index] = 1.0f; + } + } +} + + +////////////////////////////////////////////////////////////////////// +// set x direction to Neumann boundary conditions +////////////////////////////////////////////////////////////////////// +void FLUID_3D::setNeumannX(float* field, Vec3Int res, int zBegin, int zEnd) +{ + const int slabSize = res[0] * res[1]; + int index; + for (int z = zBegin; z < zEnd; z++) + for (int y = 0; y < res[1]; y++) + { + // left slab + index = y * res[0] + z * slabSize; + field[index] = field[index + 2]; + + // right slab + index += res[0] - 1; + field[index] = field[index - 2]; + } + + // fix, force top slab to only allow outwards flux + for (int y = 0; y < res[1]; y++) + for (int z = zBegin; z < zEnd; z++) + { + // top slab + index = y * res[0] + z * slabSize; + index += res[0] - 1; + if(field[index]<0.) field[index] = 0.; + index -= 1; + if(field[index]<0.) field[index] = 0.; + } + } + +////////////////////////////////////////////////////////////////////// +// set y direction to Neumann boundary conditions +////////////////////////////////////////////////////////////////////// +void FLUID_3D::setNeumannY(float* field, Vec3Int res, int zBegin, int zEnd) +{ + const int slabSize = res[0] * res[1]; + int index; + for (int z = zBegin; z < zEnd; z++) + for (int x = 0; x < res[0]; x++) + { + // bottom slab + index = x + z * slabSize; + field[index] = field[index + 2 * res[0]]; + + // top slab + index += slabSize - res[0]; + field[index] = field[index - 2 * res[0]]; + } + + // fix, force top slab to only allow outwards flux + for (int z = zBegin; z < zEnd; z++) + for (int x = 0; x < res[0]; x++) + { + // top slab + index = x + z * slabSize; + index += slabSize - res[0]; + if(field[index]<0.) field[index] = 0.; + index -= res[0]; + if(field[index]<0.) field[index] = 0.; + } + +} + +////////////////////////////////////////////////////////////////////// +// set z direction to Neumann boundary conditions +////////////////////////////////////////////////////////////////////// +void FLUID_3D::setNeumannZ(float* field, Vec3Int res, int zBegin, int zEnd) +{ + const int slabSize = res[0] * res[1]; + const int totalCells = res[0] * res[1] * res[2]; + const int cellsslab = totalCells - slabSize; + int index; + + index = 0; + if (zBegin == 0) + for (int y = 0; y < res[1]; y++) + for (int x = 0; x < res[0]; x++, index++) + { + // front slab + field[index] = field[index + 2 * slabSize]; + } + + if (zEnd == res[2]) + { + index = 0; + int indexx = 0; + + for (int y = 0; y < res[1]; y++) + for (int x = 0; x < res[0]; x++, index++) + { + + // back slab + indexx = index + cellsslab; + field[indexx] = field[indexx - 2 * slabSize]; + } + + + // fix, force top slab to only allow outwards flux + for (int y = 0; y < res[1]; y++) + for (int x = 0; x < res[0]; x++) + { + // top slab + index = x + y * res[0]; + index += cellsslab; + if(field[index]<0.) field[index] = 0.; + index -= slabSize; + if(field[index]<0.) field[index] = 0.; + } + + } // zEnd == res[2] + +} + +////////////////////////////////////////////////////////////////////// +// set x direction to zero +////////////////////////////////////////////////////////////////////// +void FLUID_3D::setZeroX(float* field, Vec3Int res, int zBegin, int zEnd) +{ + const int slabSize = res[0] * res[1]; + int index; + for (int z = zBegin; z < zEnd; z++) + for (int y = 0; y < res[1]; y++) + { + // left slab + index = y * res[0] + z * slabSize; + field[index] = 0.0f; + + // right slab + index += res[0] - 1; + field[index] = 0.0f; + } +} + +////////////////////////////////////////////////////////////////////// +// set y direction to zero +////////////////////////////////////////////////////////////////////// +void FLUID_3D::setZeroY(float* field, Vec3Int res, int zBegin, int zEnd) +{ + const int slabSize = res[0] * res[1]; + int index; + for (int z = zBegin; z < zEnd; z++) + for (int x = 0; x < res[0]; x++) + { + // bottom slab + index = x + z * slabSize; + field[index] = 0.0f; + + // top slab + index += slabSize - res[0]; + field[index] = 0.0f; + } +} + +////////////////////////////////////////////////////////////////////// +// set z direction to zero +////////////////////////////////////////////////////////////////////// +void FLUID_3D::setZeroZ(float* field, Vec3Int res, int zBegin, int zEnd) +{ + const int slabSize = res[0] * res[1]; + const int totalCells = res[0] * res[1] * res[2]; + + int index = 0; + if ((zBegin == 0)) + for (int y = 0; y < res[1]; y++) + for (int x = 0; x < res[0]; x++, index++) + { + // front slab + field[index] = 0.0f; + } + + if (zEnd == res[2]) + { + index=0; + int indexx=0; + const int cellsslab = totalCells - slabSize; + + for (int y = 0; y < res[1]; y++) + for (int x = 0; x < res[0]; x++, index++) + { + + // back slab + indexx = index + cellsslab; + field[indexx] = 0.0f; + } + } + } +////////////////////////////////////////////////////////////////////// +// copy grid boundary +////////////////////////////////////////////////////////////////////// +void FLUID_3D::copyBorderX(float* field, Vec3Int res, int zBegin, int zEnd) +{ + const int slabSize = res[0] * res[1]; + int index; + for (int z = zBegin; z < zEnd; z++) + for (int y = 0; y < res[1]; y++) + { + // left slab + index = y * res[0] + z * slabSize; + field[index] = field[index + 1]; + + // right slab + index += res[0] - 1; + field[index] = field[index - 1]; + } +} +void FLUID_3D::copyBorderY(float* field, Vec3Int res, int zBegin, int zEnd) +{ + const int slabSize = res[0] * res[1]; + //const int totalCells = res[0] * res[1] * res[2]; + int index; + for (int z = zBegin; z < zEnd; z++) + for (int x = 0; x < res[0]; x++) + { + // bottom slab + index = x + z * slabSize; + field[index] = field[index + res[0]]; + // top slab + index += slabSize - res[0]; + field[index] = field[index - res[0]]; + } +} +void FLUID_3D::copyBorderZ(float* field, Vec3Int res, int zBegin, int zEnd) +{ + const int slabSize = res[0] * res[1]; + const int totalCells = res[0] * res[1] * res[2]; + int index=0; + + if ((zBegin == 0)) + for (int y = 0; y < res[1]; y++) + for (int x = 0; x < res[0]; x++, index++) + { + field[index] = field[index + slabSize]; + } + + if ((zEnd == res[2])) + { + + index=0; + int indexx=0; + const int cellsslab = totalCells - slabSize; + + for (int y = 0; y < res[1]; y++) + for (int x = 0; x < res[0]; x++, index++) + { + // back slab + indexx = index + cellsslab; + field[indexx] = field[indexx - slabSize]; + } + } +} + +///////////////////////////////////////////////////////////////////// +// advect field with the semi lagrangian method +////////////////////////////////////////////////////////////////////// +void FLUID_3D::advectFieldSemiLagrange(const float dt, const float* velx, const float* vely, const float* velz, + float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd) +{ + const int xres = res[0]; + const int yres = res[1]; + const int zres = res[2]; + const int slabSize = res[0] * res[1]; + + + for (int z = zBegin; z < zEnd; z++) + for (int y = 0; y < yres; y++) + for (int x = 0; x < xres; x++) + { + const int index = x + y * xres + z * xres*yres; + + // backtrace + float xTrace = x - dt * velx[index]; + float yTrace = y - dt * vely[index]; + float zTrace = z - dt * velz[index]; + + // clamp backtrace to grid boundaries + if (xTrace < 0.5) xTrace = 0.5; + if (xTrace > xres - 1.5) xTrace = xres - 1.5; + if (yTrace < 0.5) yTrace = 0.5; + if (yTrace > yres - 1.5) yTrace = yres - 1.5; + if (zTrace < 0.5) zTrace = 0.5; + if (zTrace > zres - 1.5) zTrace = zres - 1.5; + + // locate neighbors to interpolate + const int x0 = (int)xTrace; + const int x1 = x0 + 1; + const int y0 = (int)yTrace; + const int y1 = y0 + 1; + const int z0 = (int)zTrace; + const int z1 = z0 + 1; + + // get interpolation weights + const float s1 = xTrace - x0; + const float s0 = 1.0f - s1; + const float t1 = yTrace - y0; + const float t0 = 1.0f - t1; + const float u1 = zTrace - z0; + const float u0 = 1.0f - u1; + + const int i000 = x0 + y0 * xres + z0 * slabSize; + const int i010 = x0 + y1 * xres + z0 * slabSize; + const int i100 = x1 + y0 * xres + z0 * slabSize; + const int i110 = x1 + y1 * xres + z0 * slabSize; + const int i001 = x0 + y0 * xres + z1 * slabSize; + const int i011 = x0 + y1 * xres + z1 * slabSize; + const int i101 = x1 + y0 * xres + z1 * slabSize; + const int i111 = x1 + y1 * xres + z1 * slabSize; + + // interpolate + // (indices could be computed once) + newField[index] = u0 * (s0 * (t0 * oldField[i000] + + t1 * oldField[i010]) + + s1 * (t0 * oldField[i100] + + t1 * oldField[i110])) + + u1 * (s0 * (t0 * oldField[i001] + + t1 * oldField[i011]) + + s1 * (t0 * oldField[i101] + + t1 * oldField[i111])); + } +} + + +///////////////////////////////////////////////////////////////////// +// advect field with the maccormack method +// +// comments are the pseudocode from selle's paper +////////////////////////////////////////////////////////////////////// +void FLUID_3D::advectFieldMacCormack1(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity, + float* oldField, float* tempResult, Vec3Int res, int zBegin, int zEnd) +{ + /*const int sx= res[0]; + const int sy= res[1]; + const int sz= res[2]; + + for (int x = 0; x < sx * sy * sz; x++) + phiHatN[x] = phiHatN1[x] = oldField[x];*/ // not needed as all the values are written first + + float*& phiN = oldField; + float*& phiN1 = tempResult; + + + + // phiHatN1 = A(phiN) + advectFieldSemiLagrange( dt, xVelocity, yVelocity, zVelocity, phiN, phiN1, res, zBegin, zEnd); // uses wide data from old field and velocities (both are whole) +} + + + +void FLUID_3D::advectFieldMacCormack2(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity, + float* oldField, float* newField, float* tempResult, float* temp1, Vec3Int res, const unsigned char* obstacles, int zBegin, int zEnd) +{ + float* phiHatN = tempResult; + float* t1 = temp1; + const int sx= res[0]; + const int sy= res[1]; + + float*& phiN = oldField; + float*& phiN1 = newField; + + + + // phiHatN = A^R(phiHatN1) + advectFieldSemiLagrange( -1.0*dt, xVelocity, yVelocity, zVelocity, phiHatN, t1, res, zBegin, zEnd); // uses wide data from old field and velocities (both are whole) + + // phiN1 = phiHatN1 + (phiN - phiHatN) / 2 + const int border = 0; + for (int z = zBegin+border; z < zEnd-border; z++) + for (int y = border; y < sy-border; y++) + for (int x = border; x < sx-border; x++) { + int index = x + y * sx + z * sx*sy; + phiN1[index] = phiHatN[index] + (phiN[index] - t1[index]) * 0.50f; + //phiN1[index] = phiHatN1[index]; // debug, correction off + } + copyBorderX(phiN1, res, zBegin, zEnd); + copyBorderY(phiN1, res, zBegin, zEnd); + copyBorderZ(phiN1, res, zBegin, zEnd); + + // clamp any newly created extrema + clampExtrema(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res, zBegin, zEnd); // uses wide data from old field and velocities (both are whole) + + // if the error estimate was bad, revert to first order + clampOutsideRays(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res, obstacles, phiHatN, zBegin, zEnd); // phiHatN is only used at cells within thread range, so its ok + +} + + +////////////////////////////////////////////////////////////////////// +// Clamp the extrema generated by the BFECC error correction +////////////////////////////////////////////////////////////////////// +void FLUID_3D::clampExtrema(const float dt, const float* velx, const float* vely, const float* velz, + float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd) +{ + const int xres= res[0]; + const int yres= res[1]; + const int zres= res[2]; + const int slabSize = res[0] * res[1]; + + int bb=0; + int bt=0; + + if (zBegin == 0) {bb = 1;} + if (zEnd == res[2]) {bt = 1;} + + + for (int z = zBegin+bb; z < zEnd-bt; z++) + for (int y = 1; y < yres-1; y++) + for (int x = 1; x < xres-1; x++) + { + const int index = x + y * xres+ z * xres*yres; + // backtrace + float xTrace = x - dt * velx[index]; + float yTrace = y - dt * vely[index]; + float zTrace = z - dt * velz[index]; + + // clamp backtrace to grid boundaries + if (xTrace < 0.5) xTrace = 0.5; + if (xTrace > xres - 1.5) xTrace = xres - 1.5; + if (yTrace < 0.5) yTrace = 0.5; + if (yTrace > yres - 1.5) yTrace = yres - 1.5; + if (zTrace < 0.5) zTrace = 0.5; + if (zTrace > zres - 1.5) zTrace = zres - 1.5; + + // locate neighbors to interpolate + const int x0 = (int)xTrace; + const int x1 = x0 + 1; + const int y0 = (int)yTrace; + const int y1 = y0 + 1; + const int z0 = (int)zTrace; + const int z1 = z0 + 1; + + const int i000 = x0 + y0 * xres + z0 * slabSize; + const int i010 = x0 + y1 * xres + z0 * slabSize; + const int i100 = x1 + y0 * xres + z0 * slabSize; + const int i110 = x1 + y1 * xres + z0 * slabSize; + const int i001 = x0 + y0 * xres + z1 * slabSize; + const int i011 = x0 + y1 * xres + z1 * slabSize; + const int i101 = x1 + y0 * xres + z1 * slabSize; + const int i111 = x1 + y1 * xres + z1 * slabSize; + + float minField = oldField[i000]; + float maxField = oldField[i000]; + + minField = (oldField[i010] < minField) ? oldField[i010] : minField; + maxField = (oldField[i010] > maxField) ? oldField[i010] : maxField; + + minField = (oldField[i100] < minField) ? oldField[i100] : minField; + maxField = (oldField[i100] > maxField) ? oldField[i100] : maxField; + + minField = (oldField[i110] < minField) ? oldField[i110] : minField; + maxField = (oldField[i110] > maxField) ? oldField[i110] : maxField; + + minField = (oldField[i001] < minField) ? oldField[i001] : minField; + maxField = (oldField[i001] > maxField) ? oldField[i001] : maxField; + + minField = (oldField[i011] < minField) ? oldField[i011] : minField; + maxField = (oldField[i011] > maxField) ? oldField[i011] : maxField; + + minField = (oldField[i101] < minField) ? oldField[i101] : minField; + maxField = (oldField[i101] > maxField) ? oldField[i101] : maxField; + + minField = (oldField[i111] < minField) ? oldField[i111] : minField; + maxField = (oldField[i111] > maxField) ? oldField[i111] : maxField; + + newField[index] = (newField[index] > maxField) ? maxField : newField[index]; + newField[index] = (newField[index] < minField) ? minField : newField[index]; + } +} + +////////////////////////////////////////////////////////////////////// +// Reverts any backtraces that go into boundaries back to first +// order -- in this case the error correction term was totally +// incorrect +////////////////////////////////////////////////////////////////////// +void FLUID_3D::clampOutsideRays(const float dt, const float* velx, const float* vely, const float* velz, + float* oldField, float* newField, Vec3Int res, const unsigned char* obstacles, const float *oldAdvection, int zBegin, int zEnd) +{ + const int sx= res[0]; + const int sy= res[1]; + const int sz= res[2]; + const int slabSize = res[0] * res[1]; + + int bb=0; + int bt=0; + + if (zBegin == 0) {bb = 1;} + if (zEnd == res[2]) {bt = 1;} + + for (int z = zBegin+bb; z < zEnd-bt; z++) + for (int y = 1; y < sy-1; y++) + for (int x = 1; x < sx-1; x++) + { + const int index = x + y * sx+ z * slabSize; + // backtrace + float xBackward = x + dt * velx[index]; + float yBackward = y + dt * vely[index]; + float zBackward = z + dt * velz[index]; + float xTrace = x - dt * velx[index]; + float yTrace = y - dt * vely[index]; + float zTrace = z - dt * velz[index]; + + // see if it goes outside the boundaries + bool hasObstacle = + (zTrace < 1.0f) || (zTrace > sz - 2.0f) || + (yTrace < 1.0f) || (yTrace > sy - 2.0f) || + (xTrace < 1.0f) || (xTrace > sx - 2.0f) || + (zBackward < 1.0f) || (zBackward > sz - 2.0f) || + (yBackward < 1.0f) || (yBackward > sy - 2.0f) || + (xBackward < 1.0f) || (xBackward > sx - 2.0f); + // reuse old advection instead of doing another one... + if(hasObstacle) { newField[index] = oldAdvection[index]; continue; } + + // clamp to prevent an out of bounds access when looking into + // the _obstacles array + zTrace = (zTrace < 0.5f) ? 0.5f : zTrace; + zTrace = (zTrace > sz - 1.5f) ? sz - 1.5f : zTrace; + yTrace = (yTrace < 0.5f) ? 0.5f : yTrace; + yTrace = (yTrace > sy - 1.5f) ? sy - 1.5f : yTrace; + xTrace = (xTrace < 0.5f) ? 0.5f : xTrace; + xTrace = (xTrace > sx - 1.5f) ? sx - 1.5f : xTrace; + + // locate neighbors to interpolate, + // do backward first since we will use the forward indices if a + // reversion is actually necessary + zBackward = (zBackward < 0.5f) ? 0.5f : zBackward; + zBackward = (zBackward > sz - 1.5f) ? sz - 1.5f : zBackward; + yBackward = (yBackward < 0.5f) ? 0.5f : yBackward; + yBackward = (yBackward > sy - 1.5f) ? sy - 1.5f : yBackward; + xBackward = (xBackward < 0.5f) ? 0.5f : xBackward; + xBackward = (xBackward > sx - 1.5f) ? sx - 1.5f : xBackward; + + int x0 = (int)xBackward; + int x1 = x0 + 1; + int y0 = (int)yBackward; + int y1 = y0 + 1; + int z0 = (int)zBackward; + int z1 = z0 + 1; + if(obstacles && !hasObstacle) { + hasObstacle = hasObstacle || + obstacles[x0 + y0 * sx + z0*slabSize] || + obstacles[x0 + y1 * sx + z0*slabSize] || + obstacles[x1 + y0 * sx + z0*slabSize] || + obstacles[x1 + y1 * sx + z0*slabSize] || + obstacles[x0 + y0 * sx + z1*slabSize] || + obstacles[x0 + y1 * sx + z1*slabSize] || + obstacles[x1 + y0 * sx + z1*slabSize] || + obstacles[x1 + y1 * sx + z1*slabSize] ; + } + // reuse old advection instead of doing another one... + if(hasObstacle) { newField[index] = oldAdvection[index]; continue; } + + x0 = (int)xTrace; + x1 = x0 + 1; + y0 = (int)yTrace; + y1 = y0 + 1; + z0 = (int)zTrace; + z1 = z0 + 1; + if(obstacles && !hasObstacle) { + hasObstacle = hasObstacle || + obstacles[x0 + y0 * sx + z0*slabSize] || + obstacles[x0 + y1 * sx + z0*slabSize] || + obstacles[x1 + y0 * sx + z0*slabSize] || + obstacles[x1 + y1 * sx + z0*slabSize] || + obstacles[x0 + y0 * sx + z1*slabSize] || + obstacles[x0 + y1 * sx + z1*slabSize] || + obstacles[x1 + y0 * sx + z1*slabSize] || + obstacles[x1 + y1 * sx + z1*slabSize] ; + } // obstacle array + // reuse old advection instead of doing another one... + if(hasObstacle) { newField[index] = oldAdvection[index]; continue; } + + // see if either the forward or backward ray went into + // a boundary + if (hasObstacle) { + // get interpolation weights + float s1 = xTrace - x0; + float s0 = 1.0f - s1; + float t1 = yTrace - y0; + float t0 = 1.0f - t1; + float u1 = zTrace - z0; + float u0 = 1.0f - u1; + + const int i000 = x0 + y0 * sx + z0 * slabSize; + const int i010 = x0 + y1 * sx + z0 * slabSize; + const int i100 = x1 + y0 * sx + z0 * slabSize; + const int i110 = x1 + y1 * sx + z0 * slabSize; + const int i001 = x0 + y0 * sx + z1 * slabSize; + const int i011 = x0 + y1 * sx + z1 * slabSize; + const int i101 = x1 + y0 * sx + z1 * slabSize; + const int i111 = x1 + y1 * sx + z1 * slabSize; + + // interpolate, (indices could be computed once) + newField[index] = u0 * (s0 * ( + t0 * oldField[i000] + + t1 * oldField[i010]) + + s1 * (t0 * oldField[i100] + + t1 * oldField[i110])) + + u1 * (s0 * (t0 * oldField[i001] + + t1 * oldField[i011]) + + s1 * (t0 * oldField[i101] + + t1 * oldField[i111])); + } + } // xyz +} diff --git a/intern/smoke/intern/IMAGE.h b/intern/smoke/intern/IMAGE.h new file mode 100644 index 00000000000..a606fcddf72 --- /dev/null +++ b/intern/smoke/intern/IMAGE.h @@ -0,0 +1,289 @@ +/** \file smoke/intern/IMAGE.h + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +////////////////////////////////////////////////////////////////////// +// +#ifndef IMAGE_H +#define IMAGE_H + +#include <stdlib.h> +#include <string> +#include <fstream> +#include <sstream> +#include <zlib.h> + +////////////////////////////////////////////////////////////////////// +// NT helper functions +////////////////////////////////////////////////////////////////////// +template < class T > inline T ABS( T a ) { + return (0 < a) ? a : -a ; +} + +template < class T > inline void SWAP_POINTERS( T &a, T &b ) { + T temp = a; + a = b; + b = temp; +} + +template < class T > inline void CLAMP( T &a, T b=0., T c=1.) { + if(a<b) { a=b; return; } + if(a>c) { a=c; return; } +} + +template < class T > inline T MIN( T a, T b) { + return (a < b) ? a : b; +} + +template < class T > inline T MAX( T a, T b) { + return (a > b) ? a : b; +} + +template < class T > inline T MAX3( T a, T b, T c) { + T max = (a > b) ? a : b; + max = (max > c) ? max : c; + return max; +} + +template < class T > inline float MAX3V( T vec) { + float max = (vec[0] > vec[1]) ? vec[0] : vec[1]; + max = (max > vec[2]) ? max : vec[2]; + return max; +} + +template < class T > inline float MIN3V( T vec) { + float min = (vec[0] < vec[1]) ? vec[0] : vec[1]; + min = (min < vec[2]) ? min : vec[2]; + return min; +} + +////////////////////////////////////////////////////////////////////// +// PNG, POV-Ray, and PBRT output functions +////////////////////////////////////////////////////////////////////// +#ifndef NOPNG +#ifdef WIN32 +#include "png.h" +#else +#include <png.h> +#endif +#endif // NOPNG + +/* + NOTE when someone decided to uncomment the following code, please remember to put it between #ifndef NOPNG #endif +*/ +namespace IMAGE { + /* + static int writePng(const char *fileName, unsigned char **rowsp, int w, int h) + { + // defaults + const int colortype = PNG_COLOR_TYPE_RGBA; + const int bitdepth = 8; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_bytep *rows = rowsp; + + FILE *fp = NULL; + std::string doing = "open for writing"; + if (!(fp = fopen(fileName, "wb"))) goto fail; + + if(!png_ptr) { + doing = "create png write struct"; + if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail; + } + if(!info_ptr) { + doing = "create png info struct"; + if (!(info_ptr = png_create_info_struct(png_ptr))) goto fail; + } + + if (setjmp(png_jmpbuf(png_ptr))) goto fail; + doing = "init IO"; + png_init_io(png_ptr, fp); + doing = "write header"; + png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + doing = "write info"; + png_write_info(png_ptr, info_ptr); + doing = "write image"; + png_write_image(png_ptr, rows); + doing = "write end"; + png_write_end(png_ptr, NULL); + doing = "write destroy structs"; + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose( fp ); + return 0; + + fail: + std::cerr << "writePng: could not "<<doing<<" !\n"; + if(fp) fclose( fp ); + if(png_ptr || info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr); + return -1; + } + */ + + ///////////////////////////////////////////////////////////////////////////////// + // write a numbered PNG file out, padded with zeros up to three zeros + ///////////////////////////////////////////////////////////////////////////////// + /* + static void dumpNumberedPNG(int counter, std::string prefix, float* field, int xRes, int yRes) + { + char buffer[256]; + sprintf(buffer,"%04i", counter); + std::string number = std::string(buffer); + + unsigned char pngbuf[xRes*yRes*4]; + unsigned char *rows[yRes]; + float *pfield = field; + for (int j=0; j<yRes; j++) { + for (int i=0; i<xRes; i++) { + float val = *pfield; + if(val>1.) val=1.; + if(val<0.) val=0.; + pngbuf[(j*xRes+i)*4+0] = (unsigned char)(val*255.); + pngbuf[(j*xRes+i)*4+1] = (unsigned char)(val*255.); + pngbuf[(j*xRes+i)*4+2] = (unsigned char)(val*255.); + pfield++; + pngbuf[(j*xRes+i)*4+3] = 255; + } + rows[j] = &pngbuf[(yRes-j-1)*xRes*4]; + } + std::string filenamePNG = prefix + number + std::string(".png"); + writePng(filenamePNG.c_str(), rows, xRes, yRes, false); + printf("Writing %s\n", filenamePNG.c_str()); + + } +*/ + ///////////////////////////////////////////////////////////////////////////////// + // export pbrt volumegrid geometry object + ///////////////////////////////////////////////////////////////////////////////// + /* + static void dumpPBRT(int counter, std::string prefix, float* fieldOrg, int xRes, int yRes, int zRes) + { + char buffer[256]; + sprintf(buffer,"%04i", counter); + std::string number = std::string(buffer); + + std::string filenamePbrt = prefix + number + std::string(".pbrt.gz"); + printf("Writing PBRT %s\n", filenamePbrt.c_str()); + + float *field = new float[xRes*yRes*zRes]; + // normalize values + float maxDensVal = ABS(fieldOrg[0]); + float targetNorm = 0.5; + for (int i = 0; i < xRes * yRes * zRes; i++) { + if(ABS(fieldOrg[i])>maxDensVal) maxDensVal = ABS(fieldOrg[i]); + field[i] = 0.; + } + if(maxDensVal>0.) { + for (int i = 0; i < xRes * yRes * zRes; i++) { + field[i] = ABS(fieldOrg[i]) / maxDensVal * targetNorm; + } + } + + std::fstream fout; + fout.open(filenamePbrt.c_str(), std::ios::out); + + int maxRes = (xRes > yRes) ? xRes : yRes; + maxRes = (maxRes > zRes) ? maxRes : zRes; + + const float xSize = 1.0 / (float)maxRes * (float)xRes; + const float ySize = 1.0 / (float)maxRes * (float)yRes; + const float zSize = 1.0 / (float)maxRes * (float)zRes; + + gzFile file; + file = gzopen(filenamePbrt.c_str(), "wb1"); + if (file == NULL) { + std::cerr << " Couldn't write file " << filenamePbrt << "!!!" << std::endl; + return; + } + + // dimensions + gzprintf(file, "Volume \"volumegrid\" \n"); + gzprintf(file, " \"integer nx\" %i\n", xRes); + gzprintf(file, " \"integer ny\" %i\n", yRes); + gzprintf(file, " \"integer nz\" %i\n", zRes); + gzprintf(file, " \"point p0\" [ 0.0 0.0 0.0 ] \"point p1\" [%f %f %f ] \n", xSize, ySize, zSize); + gzprintf(file, " \"float density\" [ \n"); + for (int i = 0; i < xRes * yRes * zRes; i++) + gzprintf(file, "%f ", field[i]); + gzprintf(file, "] \n \n"); + + gzclose(file); + delete[] field; + } + */ + + ///////////////////////////////////////////////////////////////////////////////// + // 3D df3 export + ///////////////////////////////////////////////////////////////////////////////// +/* + static void dumpDF3(int counter, std::string prefix, float* fieldOrg, int xRes, int yRes, int zRes) + { + char buffer[256]; + + // do deferred copying to final directory, better for network directories + sprintf(buffer,"%04i", counter); + std::string number = std::string(buffer); + std::string filenameDf3 = prefix + number + std::string(".df3.gz"); + printf("Writing DF3 %s\n", filenameDf3.c_str()); + + gzFile file; + file = gzopen(filenameDf3.c_str(), "wb1"); + if (file == NULL) { + std::cerr << " Couldn't write file " << filenameDf3 << "!!!" << std::endl; + return; + } + + // dimensions + const int byteSize = 2; + const unsigned short int onx=xRes,ony=yRes,onz=zRes; + unsigned short int nx,ny,nz; + nx = onx >> 8; + ny = ony >> 8; + nz = onz >> 8; + nx += (onx << 8); + ny += (ony << 8); + nz += (onz << 8); + gzwrite(file, (void*)&nx, sizeof(short)); + gzwrite(file, (void*)&ny, sizeof(short)); + gzwrite(file, (void*)&nz, sizeof(short)); + const int nitems = onx*ony*onz; + const float mul = (float)( (1<<(8*byteSize))-1); + + unsigned short int *buf = new unsigned short int[nitems]; + for (int k = 0; k < onz; k++) + for (int j = 0; j < ony; j++) + for (int i = 0; i < onx; i++) { + float val = fieldOrg[k*(onx*ony)+j*onx+i] ; + CLAMP(val); + buf[k*(onx*ony)+j*onx+i] = (short int)(val*mul); + } + gzwrite(file, (void*)buf, sizeof(unsigned short int)* nitems); + + gzclose(file); + delete[] buf; + } + */ + +}; + + +#endif + diff --git a/intern/smoke/intern/INTERPOLATE.h b/intern/smoke/intern/INTERPOLATE.h new file mode 100644 index 00000000000..b76c8df0b59 --- /dev/null +++ b/intern/smoke/intern/INTERPOLATE.h @@ -0,0 +1,230 @@ +/** \file smoke/intern/INTERPOLATE.h + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +////////////////////////////////////////////////////////////////////// +#ifndef INTERPOLATE_H +#define INTERPOLATE_H + +#include <iostream> +#include <VEC3.h> + +namespace INTERPOLATE { + +////////////////////////////////////////////////////////////////////// +// linear interpolators +////////////////////////////////////////////////////////////////////// +static inline float lerp(float t, float a, float b) { + return ( a + t * (b - a) ); +} + +static inline float lerp(float* field, float x, float y, int res) { + // clamp backtrace to grid boundaries + if (x < 0.5f) x = 0.5f; + if (x > res - 1.5f) x = res - 1.5f; + if (y < 0.5f) y = 0.5f; + if (y > res - 1.5f) y = res - 1.5f; + + const int x0 = (int)x; + const int y0 = (int)y; + x -= x0; + y -= y0; + float d00, d10, d01, d11; + + // lerp the velocities + d00 = field[x0 + y0 * res]; + d10 = field[(x0 + 1) + y0 * res]; + d01 = field[x0 + (y0 + 1) * res]; + d11 = field[(x0 + 1) + (y0 + 1) * res]; + return lerp(y, lerp(x, d00, d10), + lerp(x, d01, d11)); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// 3d linear interpolation +////////////////////////////////////////////////////////////////////////////////////////// +static inline float lerp3d(float* field, float x, float y, float z, int xres, int yres, int zres) { + // clamp pos to grid boundaries + if (x < 0.5) x = 0.5; + if (x > xres - 1.5) x = xres - 1.5; + if (y < 0.5) y = 0.5; + if (y > yres - 1.5) y = yres - 1.5; + if (z < 0.5) z = 0.5; + if (z > zres - 1.5) z = zres - 1.5; + + // locate neighbors to interpolate + const int x0 = (int)x; + const int x1 = x0 + 1; + const int y0 = (int)y; + const int y1 = y0 + 1; + const int z0 = (int)z; + const int z1 = z0 + 1; + + // get interpolation weights + const float s1 = x - (float)x0; + const float s0 = 1.0f - s1; + const float t1 = y - (float)y0; + const float t0 = 1.0f - t1; + const float u1 = z - (float)z0; + const float u0 = 1.0f - u1; + + const int slabSize = xres*yres; + const int i000 = x0 + y0 * xres + z0 * slabSize; + const int i010 = x0 + y1 * xres + z0 * slabSize; + const int i100 = x1 + y0 * xres + z0 * slabSize; + const int i110 = x1 + y1 * xres + z0 * slabSize; + const int i001 = x0 + y0 * xres + z1 * slabSize; + const int i011 = x0 + y1 * xres + z1 * slabSize; + const int i101 = x1 + y0 * xres + z1 * slabSize; + const int i111 = x1 + y1 * xres + z1 * slabSize; + + // interpolate (indices could be computed once) + return ( u0 * (s0 * (t0 * field[i000] + + t1 * field[i010]) + + s1 * (t0 * field[i100] + + t1 * field[i110])) + + u1 * (s0 * (t0 * field[i001] + + t1 * field[i011]) + + s1 * (t0 * field[i101] + + t1 * field[i111])) ); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// convert field entries of type T to floats, then interpolate +////////////////////////////////////////////////////////////////////////////////////////// +template <class T> +static inline float lerp3dToFloat(T* field1, + float x, float y, float z, int xres, int yres, int zres) { + // clamp pos to grid boundaries + if (x < 0.5) x = 0.5; + if (x > xres - 1.5) x = xres - 1.5; + if (y < 0.5) y = 0.5; + if (y > yres - 1.5) y = yres - 1.5; + if (z < 0.5) z = 0.5; + if (z > zres - 1.5) z = zres - 1.5; + + // locate neighbors to interpolate + const int x0 = (int)x; + const int x1 = x0 + 1; + const int y0 = (int)y; + const int y1 = y0 + 1; + const int z0 = (int)z; + const int z1 = z0 + 1; + + // get interpolation weights + const float s1 = x - (float)x0; + const float s0 = 1.0f - s1; + const float t1 = y - (float)y0; + const float t0 = 1.0f - t1; + const float u1 = z - (float)z0; + const float u0 = 1.0f - u1; + + const int slabSize = xres*yres; + const int i000 = x0 + y0 * xres + z0 * slabSize; + const int i010 = x0 + y1 * xres + z0 * slabSize; + const int i100 = x1 + y0 * xres + z0 * slabSize; + const int i110 = x1 + y1 * xres + z0 * slabSize; + const int i001 = x0 + y0 * xres + z1 * slabSize; + const int i011 = x0 + y1 * xres + z1 * slabSize; + const int i101 = x1 + y0 * xres + z1 * slabSize; + const int i111 = x1 + y1 * xres + z1 * slabSize; + + // interpolate (indices could be computed once) + return (float)( + ( u0 * (s0 * (t0 * (float)field1[i000] + + t1 * (float)field1[i010]) + + s1 * (t0 * (float)field1[i100] + + t1 * (float)field1[i110])) + + u1 * (s0 * (t0 * (float)field1[i001] + + t1 * (float)field1[i011]) + + s1 * (t0 * (float)field1[i101] + + t1 * (float)field1[i111])) ) ); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// interpolate a vector from 3 fields +////////////////////////////////////////////////////////////////////////////////////////// +static inline Vec3 lerp3dVec(float* field1, float* field2, float* field3, + float x, float y, float z, int xres, int yres, int zres) { + // clamp pos to grid boundaries + if (x < 0.5) x = 0.5; + if (x > xres - 1.5) x = xres - 1.5; + if (y < 0.5) y = 0.5; + if (y > yres - 1.5) y = yres - 1.5; + if (z < 0.5) z = 0.5; + if (z > zres - 1.5) z = zres - 1.5; + + // locate neighbors to interpolate + const int x0 = (int)x; + const int x1 = x0 + 1; + const int y0 = (int)y; + const int y1 = y0 + 1; + const int z0 = (int)z; + const int z1 = z0 + 1; + + // get interpolation weights + const float s1 = x - (float)x0; + const float s0 = 1.0f - s1; + const float t1 = y - (float)y0; + const float t0 = 1.0f - t1; + const float u1 = z - (float)z0; + const float u0 = 1.0f - u1; + + const int slabSize = xres*yres; + const int i000 = x0 + y0 * xres + z0 * slabSize; + const int i010 = x0 + y1 * xres + z0 * slabSize; + const int i100 = x1 + y0 * xres + z0 * slabSize; + const int i110 = x1 + y1 * xres + z0 * slabSize; + const int i001 = x0 + y0 * xres + z1 * slabSize; + const int i011 = x0 + y1 * xres + z1 * slabSize; + const int i101 = x1 + y0 * xres + z1 * slabSize; + const int i111 = x1 + y1 * xres + z1 * slabSize; + + // interpolate (indices could be computed once) + return Vec3( + ( u0 * (s0 * (t0 * field1[i000] + + t1 * field1[i010]) + + s1 * (t0 * field1[i100] + + t1 * field1[i110])) + + u1 * (s0 * (t0 * field1[i001] + + t1 * field1[i011]) + + s1 * (t0 * field1[i101] + + t1 * field1[i111])) ) , + ( u0 * (s0 * (t0 * field2[i000] + + t1 * field2[i010]) + + s1 * (t0 * field2[i100] + + t1 * field2[i110])) + + u1 * (s0 * (t0 * field2[i001] + + t1 * field2[i011]) + + s1 * (t0 * field2[i101] + + t1 * field2[i111])) ) , + ( u0 * (s0 * (t0 * field3[i000] + + t1 * field3[i010]) + + s1 * (t0 * field3[i100] + + t1 * field3[i110])) + + u1 * (s0 * (t0 * field3[i001] + + t1 * field3[i011]) + + s1 * (t0 * field3[i101] + + t1 * field3[i111])) ) + ); +} + +}; +#endif diff --git a/intern/smoke/intern/LICENSE.txt b/intern/smoke/intern/LICENSE.txt new file mode 100644 index 00000000000..94a9ed024d3 --- /dev/null +++ b/intern/smoke/intern/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/intern/smoke/intern/LU_HELPER.cpp b/intern/smoke/intern/LU_HELPER.cpp new file mode 100644 index 00000000000..40060371071 --- /dev/null +++ b/intern/smoke/intern/LU_HELPER.cpp @@ -0,0 +1,139 @@ +/** \file smoke/intern/LU_HELPER.cpp + * \ingroup smoke + */ + +#include "LU_HELPER.h" + +int isNonsingular (sLU LU_) { + for (int j = 0; j < 3; j++) { + if (LU_.values[j][j] == 0) + return 0; + } + return 1; +} + +sLU computeLU( float a[3][3]) +{ + sLU result; + int m=3; + int n=3; + + //float LU_[3][3]; + for (int i = 0; i < m; i++) { + result.piv[i] = i; + for (int j = 0; j < n; j++) result.values[i][j]=a[i][j]; + } + + result.pivsign = 1; + //Real *LUrowi = 0;; + //Array1D<Real> LUcolj(m); + //float *LUrowi = 0; + float LUcolj[3]; + + // Outer loop. + + for (int j = 0; j < n; j++) { + + // Make a copy of the j-th column to localize references. + + for (int i = 0; i < m; i++) { + LUcolj[i] = result.values[i][j]; + } + + // Apply previous transformations. + + for (int i = 0; i < m; i++) { + //float LUrowi[3]; + //LUrowi = result.values[i]; + + // Most of the time is spent in the following dot product. + + int kmax = min(i,j); + double s = 0.0; + for (int k = 0; k < kmax; k++) { + s += result.values[i][k]*LUcolj[k]; + } + + result.values[i][j] = LUcolj[i] -= s; + } + + // Find pivot and exchange if necessary. + + int p = j; + for (int i = j+1; i < m; i++) { + if (abs(LUcolj[i]) > abs(LUcolj[p])) { + p = i; + } + } + if (p != j) { + int k=0; + for (k = 0; k < n; k++) { + double t = result.values[p][k]; + result.values[p][k] = result.values[j][k]; + result.values[j][k] = t; + } + k = result.piv[p]; + result.piv[p] = result.piv[j]; + result.piv[j] = k; + result.pivsign = -result.pivsign; + } + + // Compute multipliers. + + if ((j < m) && (result.values[j][j] != 0.0)) { + for (int i = j+1; i < m; i++) { + result.values[i][j] /= result.values[j][j]; + } + } + } + + return result; +} + +void solveLU3x3(sLU& A, float x[3], float b[3]) +{ + //TNT::Array1D<float> jamaB = TNT::Array1D<float>(3, &b[0]); + //TNT::Array1D<float> jamaX = A.solve(jamaB); + + + // Solve A, B + + { + if (!isNonsingular(A)) { + x[0]=0.0f; + x[1]=0.0f; + x[2]=0.0f; + return; + } + + + //Array1D<Real> Ax = permute_copy(b, piv); + float Ax[3]; + + // permute copy: b , A.piv + { + for (int i = 0; i < 3; i++) + Ax[i] = b[A.piv[i]]; + } + + // Solve L*Y = B(piv) + for (int k = 0; k < 3; k++) { + for (int i = k+1; i < 3; i++) { + Ax[i] -= Ax[k]*A.values[i][k]; + } + } + + // Solve U*X = Y; + for (int k = 2; k >= 0; k--) { + Ax[k] /= A.values[k][k]; + for (int i = 0; i < k; i++) + Ax[i] -= Ax[k]*A.values[i][k]; + } + + + x[0] = Ax[0]; + x[1] = Ax[1]; + x[2] = Ax[2]; + return; + } +} diff --git a/intern/smoke/intern/LU_HELPER.h b/intern/smoke/intern/LU_HELPER.h new file mode 100644 index 00000000000..b82b8f5030e --- /dev/null +++ b/intern/smoke/intern/LU_HELPER.h @@ -0,0 +1,54 @@ +/** \file smoke/intern/LU_HELPER.h + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +////////////////////////////////////////////////////////////////////// +// Modified to not require TNT matrix library anymore. It was very slow +// when being run in parallel. Required TNT JAMA:LU libraries were +// converted into independent functions. +// - MiikaH +////////////////////////////////////////////////////////////////////// + +#ifndef LU_HELPER_H +#define LU_HELPER_H + +#include <cmath> +#include <algorithm> + +using namespace std; + +////////////////////////////////////////////////////////////////////// +// Helper function, compute eigenvalues of 3x3 matrix +////////////////////////////////////////////////////////////////////// + +struct sLU +{ + float values[3][3]; + int pivsign; + int piv[3]; +}; + + +int isNonsingular (sLU LU_); +sLU computeLU( float a[3][3]); +void solveLU3x3(sLU& A, float x[3], float b[3]); + + +#endif diff --git a/intern/smoke/intern/MERSENNETWISTER.h b/intern/smoke/intern/MERSENNETWISTER.h new file mode 100644 index 00000000000..116568c2834 --- /dev/null +++ b/intern/smoke/intern/MERSENNETWISTER.h @@ -0,0 +1,432 @@ +/** \file smoke/intern/MERSENNETWISTER.h + * \ingroup smoke + */ +// MersenneTwister.h +// Mersenne Twister random number generator -- a C++ class MTRand +// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus +// Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com + +// The Mersenne Twister is an algorithm for generating random numbers. It +// was designed with consideration of the flaws in various other generators. +// The period, 2^19937-1, and the order of equidistribution, 623 dimensions, +// are far greater. The generator is also fast; it avoids multiplication and +// division, and it benefits from caches and pipelines. For more information +// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html + +// Reference +// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally +// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on +// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30. + +// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, +// Copyright (C) 2000 - 2003, Richard J. Wagner +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The names of its contributors may not be used to endorse or promote +// products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The original code included the following notice: +// +// When you use this, send an email to: matumoto@math.keio.ac.jp +// with an appropriate reference to your work. +// +// It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu +// when you write. + +#ifndef MERSENNETWISTER_H +#define MERSENNETWISTER_H + +// Not thread safe (unless auto-initialization is avoided and each thread has +// its own MTRand object) + +#include <iostream> +#include <limits.h> +#include <stdio.h> +#include <time.h> +#include <math.h> + +class MTRand { +// Data +public: + typedef unsigned long uint32; // unsigned integer type, at least 32 bits + + enum { N = 624 }; // length of state vector + enum { SAVE = N + 1 }; // length of array for save() + +protected: + enum { M = 397 }; // period parameter + + uint32 state[N]; // internal state + uint32 *pNext; // next value to get from state + int left; // number of values left before reload needed + + +//Methods +public: + MTRand( const uint32& oneSeed ); // initialize with a simple uint32 + MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or an array + MTRand(); // auto-initialize with /dev/urandom or time() and clock() + + // Do NOT use for CRYPTOGRAPHY without securely hashing several returned + // values together, otherwise the generator state can be learned after + // reading 624 consecutive values. + + // Access to 32-bit random numbers + double rand(); // real number in [0,1] + double rand( const double& n ); // real number in [0,n] + double randExc(); // real number in [0,1) + double randExc( const double& n ); // real number in [0,n) + double randDblExc(); // real number in (0,1) + double randDblExc( const double& n ); // real number in (0,n) + uint32 randInt(); // integer in [0,2^32-1] + uint32 randInt( const uint32& n ); // integer in [0,n] for n < 2^32 + double operator()() { return rand(); } // same as rand() + + // Access to 53-bit random numbers (capacity of IEEE double precision) + double rand53(); // real number in [0,1) + + // Access to nonuniform random number distributions + double randNorm( const double& mean = 0.0, const double& variance = 1.0 ); + + // Re-seeding functions with same behavior as initializers + void seed( const uint32 oneSeed ); + void seed( uint32 *const bigSeed, const uint32 seedLength = N ); + void seed(); + + // Saving and loading generator state + void save( uint32* saveArray ) const; // to array of size SAVE + void load( uint32 *const loadArray ); // from such array + friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand ); + friend std::istream& operator>>( std::istream& is, MTRand& mtrand ); + +protected: + void initialize( const uint32 oneSeed ); + void reload(); + uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; } + uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; } + uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; } + uint32 mixBits( const uint32& u, const uint32& v ) const + { return hiBit(u) | loBits(v); } + uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const + { return m ^ (mixBits(s0,s1)>>1) ^ ((~loBit(s1) + 1) & 0x9908b0dfUL); } + static uint32 hash( time_t t, clock_t c ); +}; + + +inline MTRand::MTRand( const uint32& oneSeed ) + { seed(oneSeed); } + +inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength ) + { seed(bigSeed,seedLength); } + +inline MTRand::MTRand() + { seed(); } + +inline double MTRand::rand() + { return double(randInt()) * (1.0/4294967295.0); } + +inline double MTRand::rand( const double& n ) + { return rand() * n; } + +inline double MTRand::randExc() + { return double(randInt()) * (1.0/4294967296.0); } + +inline double MTRand::randExc( const double& n ) + { return randExc() * n; } + +inline double MTRand::randDblExc() + { return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); } + +inline double MTRand::randDblExc( const double& n ) + { return randDblExc() * n; } + +inline double MTRand::rand53() +{ + uint32 a = randInt() >> 5, b = randInt() >> 6; + return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0); // by Isaku Wada +} + +inline double MTRand::randNorm( const double& mean, const double& variance ) +{ + // Return a real number from a normal (Gaussian) distribution with given + // mean and variance by Box-Muller method + double r = sqrt( -2.0 * log( 1.0-randDblExc()) ) * variance; + double phi = 2.0 * 3.14159265358979323846264338328 * randExc(); + return mean + r * cos(phi); +} + +inline MTRand::uint32 MTRand::randInt() +{ + // Pull a 32-bit integer from the generator state + // Every other access function simply transforms the numbers extracted here + + if( left == 0 ) reload(); + --left; + + register 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); + register int i = 1; + register uint32 j = 0; + register int k = ( N > seedLength ? N : seedLength ); + for( ; k; --k ) + { + state[i] = + state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL ); + state[i] += ( bigSeed[j] & 0xffffffffUL ) + j; + state[i] &= 0xffffffffUL; + ++i; ++j; + if( i >= N ) { state[0] = state[N-1]; i = 1; } + if( j >= seedLength ) j = 0; + } + for( k = N - 1; k; --k ) + { + state[i] = + state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL ); + state[i] -= i; + state[i] &= 0xffffffffUL; + ++i; + if( i >= N ) { state[0] = state[N-1]; i = 1; } + } + state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array + reload(); +} + + +inline void MTRand::seed() +{ + // seed deterministically to produce reproducible runs + seed(123456); + + /* + // Seed the generator with an array from /dev/urandom if available + // Otherwise use a hash of time() and clock() values + + // First try getting an array from /dev/urandom + FILE* urandom = fopen( "/dev/urandom", "rb" ); + if( urandom ) + { + uint32 bigSeed[N]; + register uint32 *s = bigSeed; + register int i = N; + register bool success = true; + while( success && i-- ) + success = fread( s++, sizeof(uint32), 1, urandom ); + fclose(urandom); + if( success ) { seed( bigSeed, N ); return; } + } + + // Was not successful, so use time() and clock() instead + seed( hash( time(NULL), clock() ) ); + */ +} + + +inline void MTRand::initialize( const uint32 seed ) +{ + // Initialize generator state with seed + // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier. + // In previous versions, most significant bits (MSBs) of the seed affect + // only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto. + register uint32 *s = state; + register uint32 *r = state; + register int i = 1; + *s++ = seed & 0xffffffffUL; + for( ; i < N; ++i ) + { + *s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL; + r++; + } +} + + +inline void MTRand::reload() +{ + // Generate N new values in state + // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com) + register uint32 *p = state; + register int i; + for( i = N - M; i--; ++p ) + *p = twist( p[M], p[0], p[1] ); + for( i = M; --i; ++p ) + *p = twist( p[M-N], p[0], p[1] ); + *p = twist( p[M-N], p[0], state[0] ); + + left = N, pNext = state; +} + + +inline MTRand::uint32 MTRand::hash( time_t t, clock_t c ) +{ + // Get a uint32 from t and c + // Better than uint32(x) in case x is floating point in [0,1] + // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk) + + static uint32 differ = 0; // guarantee time-based seeds will change + + uint32 h1 = 0; + unsigned char *p = (unsigned char *) &t; + for( size_t i = 0; i < sizeof(t); ++i ) + { + h1 *= UCHAR_MAX + 2U; + h1 += p[i]; + } + uint32 h2 = 0; + p = (unsigned char *) &c; + for( size_t j = 0; j < sizeof(c); ++j ) + { + h2 *= UCHAR_MAX + 2U; + h2 += p[j]; + } + return ( h1 + differ++ ) ^ h2; +} + + +inline void MTRand::save( uint32* saveArray ) const +{ + register uint32 *sa = saveArray; + register const uint32 *s = state; + register int i = N; + for( ; i--; *sa++ = *s++ ) {} + *sa = left; +} + + +inline void MTRand::load( uint32 *const loadArray ) +{ + register uint32 *s = state; + register uint32 *la = loadArray; + register int i = N; + for( ; i--; *s++ = *la++ ) {} + left = *la; + pNext = &state[N-left]; +} + + +inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand ) +{ + register const MTRand::uint32 *s = mtrand.state; + register int i = mtrand.N; + for( ; i--; os << *s++ << "\t" ) {} + return os << mtrand.left; +} + + +inline std::istream& operator>>( std::istream& is, MTRand& mtrand ) +{ + register MTRand::uint32 *s = mtrand.state; + register int i = mtrand.N; + for( ; i--; is >> *s++ ) {} + is >> mtrand.left; + mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left]; + return is; +} + +#endif // MERSENNETWISTER_H + +// Change log: +// +// v0.1 - First release on 15 May 2000 +// - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus +// - Translated from C to C++ +// - Made completely ANSI compliant +// - Designed convenient interface for initialization, seeding, and +// obtaining numbers in default or user-defined ranges +// - Added automatic seeding from /dev/urandom or time() and clock() +// - Provided functions for saving and loading generator state +// +// v0.2 - Fixed bug which reloaded generator one step too late +// +// v0.3 - Switched to clearer, faster reload() code from Matthew Bellew +// +// v0.4 - Removed trailing newline in saved generator format to be consistent +// with output format of built-in types +// +// v0.5 - Improved portability by replacing static const int's with enum's and +// clarifying return values in seed(); suggested by Eric Heimburg +// - Removed MAXINT constant; use 0xffffffffUL instead +// +// v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits +// - Changed integer [0,n] generator to give better uniformity +// +// v0.7 - Fixed operator precedence ambiguity in reload() +// - Added access for real numbers in (0,1) and (0,n) +// +// v0.8 - Included time.h header to properly support time_t and clock_t +// +// v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto +// - Allowed for seeding with arrays of any length +// - Added access for real numbers in [0,1) with 53-bit resolution +// - Added access for real numbers from normal (Gaussian) distributions +// - Increased overall speed by optimizing twist() +// - Doubled speed of integer [0,n] generation +// - Fixed out-of-range number generation on 64-bit machines +// - Improved portability by substituting literal constants for long enum's +// - Changed license from GNU LGPL to BSD + diff --git a/intern/smoke/intern/Makefile b/intern/smoke/intern/Makefile deleted file mode 100644 index 86093b0a66f..00000000000 --- a/intern/smoke/intern/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -# Minimal LBM demonstration program by Nils Thuerey -# See http://www.ntoken.com and http://www.matthiasmueller.info/realtimephysics/ for further info -# The code is released under the GPL, see LICENSE.txt for details - -EXE=synthturb -SOURCES = $(wildcard source/*.cpp util/*.cpp) -HEADERS = $(wildcard source/*.h util/*.h) -OBJCMD = $(patsubst %.cpp,build_cmd/%.o,$(SOURCES)) -OBJGUI = $(patsubst %.cpp,build_gui/%.o,$(SOURCES)) - -CXX=g++ -CFLAGS = -c -O3 -Isource -Iutil -DDDF_OPENMP=0 -LDFLAGS = -lz - -# comment out the following two lines for disabling OPENMP -LDFLAGS = -lz -fopenmp -lgomp -CFLAGS = -c -fopenmp -O3 -Isource -Iutil -DDDF_OPENMP=1 -# uncomment this line for macs -#LDFLAGS = -lz -framework OpenGL -framework GLUT -lgomp - -DEFGUI = -DDDF_GLUTGUI=1 -DEFCMD = -DDDF_GLUTGUI=0 - -default: all - -all: cmd gui - -cmd: $(OBJCMD) - $(CXX) $(LDFLAGS) -o turbCmd $(OBJCMD) - -gui: $(OBJGUI) - $(CXX) $(LDFLAGS) -lglut -o turbGui $(OBJGUI) - -build_cmd/%.o : %.cpp $(HEADERS) - $(CXX) $(CFLAGS) $(DEFCMD) -o $@ $< - -build_gui/%.o : %.cpp $(HEADERS) - $(CXX) $(CFLAGS) $(DEFGUI) -o $@ $< - -clean: - rm -f *.o build_gui/source/*.o build_gui/util/*.o build_cmd/source/*.o build_gui/util/*.o turbCmd turbGui - diff --git a/intern/smoke/intern/Makefile.FFT b/intern/smoke/intern/Makefile.FFT new file mode 100644 index 00000000000..e45af1df29b --- /dev/null +++ b/intern/smoke/intern/Makefile.FFT @@ -0,0 +1,22 @@ +# common stuff
+LDFLAGS_COMMON = -lfftw3 #-lglut -lglu32 -lopengl32 -lz -lpng
+CFLAGS_COMMON = -c -Wall -I./ #-I/cygdrive/c/lib/glvu/include -D_WIN32
+
+CC = g++
+CFLAGS = ${CFLAGS_COMMON} -O3 -Wno-unused
+LDFLAGS = ${LDFLAGS_COMMON}
+EXECUTABLE = noiseFFT
+
+SOURCES = noiseFFT.cpp
+OBJECTS = $(SOURCES:.cpp=.o)
+
+all: $(SOURCES) $(EXECUTABLE)
+
+$(EXECUTABLE): $(OBJECTS)
+ $(CC) $(OBJECTS) $(LDFLAGS) -o $@
+
+.cpp.o:
+ $(CC) $(CFLAGS) $< -o $@
+
+clean:
+ rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
diff --git a/intern/smoke/intern/Makefile.cygwin b/intern/smoke/intern/Makefile.cygwin new file mode 100644 index 00000000000..c93753a67fe --- /dev/null +++ b/intern/smoke/intern/Makefile.cygwin @@ -0,0 +1,23 @@ +CC = g++
+LDFLAGS = -lz -lpng
+CFLAGS = -O3 -Wno-unused -c -Wall -I./ -D_WIN32
+EXECUTABLE = FLUID_3D
+
+SOURCES = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp
+OBJECTS = $(SOURCES:.cpp=.o)
+
+all: $(SOURCES) $(EXECUTABLE)
+
+$(EXECUTABLE): $(OBJECTS)
+ $(CC) $(OBJECTS) $(LDFLAGS) -o $@
+
+.cpp.o:
+ $(CC) $(CFLAGS) $< -o $@
+
+SPHERE.o: SPHERE.h
+FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp
+FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp
+main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp
+
+clean:
+ rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
diff --git a/intern/smoke/intern/Makefile.linux b/intern/smoke/intern/Makefile.linux new file mode 100644 index 00000000000..8e71af465dd --- /dev/null +++ b/intern/smoke/intern/Makefile.linux @@ -0,0 +1,23 @@ +CC = g++
+LDFLAGS = -lz -lpng -fopenmp -lgomp
+CFLAGS = -c -Wall -I./ -fopenmp -DPARALLEL=1 -O3 -Wno-unused
+EXECUTABLE = FLUID_3D
+
+SOURCES = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp
+OBJECTS = $(SOURCES:.cpp=.o)
+
+all: $(SOURCES) $(EXECUTABLE)
+
+$(EXECUTABLE): $(OBJECTS)
+ $(CC) $(OBJECTS) $(LDFLAGS) -o $@
+
+.cpp.o:
+ $(CC) $(CFLAGS) $< -o $@
+
+SPHERE.o: SPHERE.h
+FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp
+FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp
+main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp
+
+clean:
+ rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
diff --git a/intern/smoke/intern/Makefile.mac b/intern/smoke/intern/Makefile.mac new file mode 100644 index 00000000000..227aaa10a16 --- /dev/null +++ b/intern/smoke/intern/Makefile.mac @@ -0,0 +1,35 @@ +CC = g++
+
+# uncomment the other two OPENMP_... lines, if your gcc supports OpenMP
+#OPENMP_FLAGS = -fopenmp -DPARALLEL=1 -I/opt/gcc-4.3/usr/local/include
+#OPENMPLD_FLAGS = -fopenmp -lgomp -I/opt/gcc-4.3/usr/local/lib
+OPENMP_FLAGS =
+OPENMPLD_FLAGS =
+
+# assumes MacPorts libpng installation
+PNG_INCLUDE = -I/opt/local/include
+PNG_LIBS = -I/opt/local/lib
+
+LDFLAGS = $(PNG_LIBS)-lz -lpng $(OPENMPLD_FLAGS)
+CFLAGS = -c -Wall -I./ $(PNG_INCLUDE) $(OPENMP_FLAGS) -O3 -Wno-unused
+EXECUTABLE = FLUID_3D
+
+SOURCES = main.cpp FLUID_3D.cpp FLUID_3D_SOLVERS.cpp FLUID_3D_STATIC.cpp SPHERE.cpp WTURBULENCE.cpp
+OBJECTS = $(SOURCES:.cpp=.o)
+
+all: $(SOURCES) $(EXECUTABLE)
+
+$(EXECUTABLE): $(OBJECTS)
+ $(CC) $(OBJECTS) $(LDFLAGS) -o $@
+
+.cpp.o:
+ $(CC) $(CFLAGS) $< -o $@
+
+SPHERE.o: SPHERE.h
+FLUID_3D.o: FLUID_3D.h FLUID_3D.cpp
+FLUID_3D_SOLVERS.o: FLUID_3D.h FLUID_3D_SOLVERS.cpp
+main.o: FLUID_3D.h FLUID_3D.cpp FLUID_3D_SOLVERS.cpp
+
+clean:
+ rm -f *.o $(EXECUTABLE_LOADER) $(EXECUTABLE)
+
diff --git a/intern/smoke/intern/OBSTACLE.h b/intern/smoke/intern/OBSTACLE.h new file mode 100644 index 00000000000..da8ec6be024 --- /dev/null +++ b/intern/smoke/intern/OBSTACLE.h @@ -0,0 +1,46 @@ +/** \file smoke/intern/OBSTACLE.h + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +// OBSTACLE.h: interface for the OBSTACLE class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef OBSTACLE_H +#define OBSTACLE_H + +enum OBSTACLE_FLAGS { + EMPTY = 0, + /* 1 is used to flag an object cell */ + MARCHED = 2, + RETIRED = 4, + ANIMATED = 8, +}; + +class OBSTACLE +{ +public: + OBSTACLE() {}; + virtual ~OBSTACLE() {}; + + virtual bool inside(float x, float y, float z) = 0; +}; + +#endif diff --git a/intern/smoke/intern/README.txt b/intern/smoke/intern/README.txt deleted file mode 100644 index fc71f662ac4..00000000000 --- a/intern/smoke/intern/README.txt +++ /dev/null @@ -1,90 +0,0 @@ -DDF Fluid solver with Turbulence extensions ---------------------------------------------- - -Sample implementation for the paper - "Synthetic turbulence using Artificial Boundary layers" - T.Pfaff, N.Thuerey, A.Selle, M.Gross - ACM SIGGRAPH Asia 2009 - - - License ------------- - -The code is provided under the General Public License (GPL v2). -Please see the included file COPYRIGHT for more information. - - - Installing ------------- - -You will need the GLUT and ZLIB libraries in order to build the project. -If they aren't installed in the normal include, lib paths, you'll need to -manually add their install path to the makefile. -For rendering, you also need to have the (open source) PBRT raytracer -installed (see www.pbrt.org for details). - -By default, the code uses OpenMP for some operations. If your compiler -doesn't handle OpenMP, disable it as indicated in the Makefile. - - - Running ------------- - -The makefiles will build two executables, the command line tool turbCmd -and the GUI interface turbGui. -They include two hard-coded scenes, a static one, similar to the fuel tank -scene in the paper, and a dynamic one, similar to the car scene in the -paper. Both executables take the following command line arguments: - -turbCmd/turbGui [mode] - where mode is - scene : generate scene files. has to be run first. - pre-static : precompute static scene - pre-dynamic : precompute dynamic scene - run-static : run static scene - run-dynamic : run dynamic scene - - - GUI -------------- - -The GUI can be used to visualize vortex particles, scalar and velocity grids. -It shows a 2D slice of the 3D volume grid. -Additional Information (which slice is displayed, display ranges etc. -are shown on the console) - -Basic Navigation: -- Press p to start/stop the simulation, l performs a single step -- Move camera position with WASD, zoom in using Q/E. -- Hold left mouse button to rotate camera, right mouse button to translate -- Select displayed slide with +/- -- Select x/y/z slice with * -- Press ESC to exit - -Grid display: -- Vector grids (velocity etc.) are hidden by default. Press V to enable display. -- Shift+V toggles component-wise display and centered vector display of vector grids. -- Use [ ] keys to adjust the viewing range(scaling) of scalar grids, { } keys - for vector grids. -- Use X to select the next scalar grid, Z to select the next vector grid. -- The simulations include different "solvers", e.g. to handle the normal and the - upscaled grids. Use ~ to switch between solvers. - -Additional options: -- By default, all vortex particles are displayed. The Shift+G key toggles the display - of vortex particles in the current slice only. - - - Rendering --------------- - -The program saves gzipped pbrt or df3 (povray) smoke density files, which can be used to -render the smoke volumes. An example script for rendering using PBRT is included -("render.sh" shell script). You need to edit the PBRT path in the script. -Use "./render.sh sta" or "./render.sh dyn" to render the static/dynamic scene. - -Note that using PBRT rendering of volume data is fairly slow, thus the render -process will take a while. Also, the rendering of animated meshes is not easily possible, -therefore the car mesh is omitted in the dynamic scene. - - diff --git a/intern/smoke/intern/SPHERE.cpp b/intern/smoke/intern/SPHERE.cpp new file mode 100644 index 00000000000..dc59c69d0bd --- /dev/null +++ b/intern/smoke/intern/SPHERE.cpp @@ -0,0 +1,53 @@ +/** \file smoke/intern/SPHERE.cpp + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +// SPHERE.cpp: implementation of the SPHERE class. +// +////////////////////////////////////////////////////////////////////// + +#include "SPHERE.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +SPHERE::SPHERE(float x, float y, float z, float radius) : + _radius(radius) +{ + _center[0] = x; + _center[1] = y; + _center[2] = z; +} + +SPHERE::~SPHERE() +{ + +} + +bool SPHERE::inside(float x, float y, float z) +{ + float translate[] = {x - _center[0], y - _center[1], z - _center[2]}; + float magnitude = translate[0] * translate[0] + + translate[1] * translate[1] + + translate[2] * translate[2]; + + return (magnitude < _radius * _radius) ? true : false; +} diff --git a/intern/smoke/intern/SPHERE.h b/intern/smoke/intern/SPHERE.h new file mode 100644 index 00000000000..d5a232e0242 --- /dev/null +++ b/intern/smoke/intern/SPHERE.h @@ -0,0 +1,44 @@ +/** \file smoke/intern/SPHERE.h + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +// SPHERE.h: interface for the SPHERE class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef SPHERE_H +#define SPHERE_H + +#include "OBSTACLE.h" + +class SPHERE : public OBSTACLE +{ +public: + SPHERE(float x, float y, float z, float radius); + virtual ~SPHERE(); + + bool inside(float x, float y, float z); + +private: + float _center[3]; + float _radius; +}; + +#endif diff --git a/intern/smoke/intern/util/vectorbase.h b/intern/smoke/intern/VEC3.h index 2adfeebc5f7..63ce68566a9 100644 --- a/intern/smoke/intern/util/vectorbase.h +++ b/intern/smoke/intern/VEC3.h @@ -1,36 +1,19 @@ +/** \file smoke/intern/VEC3.h + * \ingroup smoke + */ /****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Vector class - * + * Copyright 2007 Nils Thuerey + * Basic vector class *****************************************************************************/ +#ifndef BASICVECTOR_H +#define BASICVECTOR_H - -#ifndef DDF_BASICVEC_H -#define DDF_BASICVEC_H - -// get rid of windos min/max defines -#ifdef WIN32 -#define NOMINMAX -#endif - -#include <stdio.h> #include <math.h> #include <stdlib.h> +#include <stdio.h> #include <iostream> #include <sstream> -// if min/max are still around... -#ifdef WIN32 -#undef min -#undef max -#endif - // use which fp-precision? 1=float, 2=double #ifndef FLOATINGPOINT_PRECISION #if DDF_DEBUG==1 @@ -40,12 +23,23 @@ #endif // DDF_DEBUG==1 #endif -// dimension of solver&problem -#ifndef DDF_DIM -#define DDF_DIM 3 +// VECTOR_EPSILON is the minimal vector length +// In order to be able to discriminate floating point values near zero, and +// to be sure not to fail a comparison because of roundoff errors, use this +// value as a threshold. + +#if FLOATINGPOINT_PRECISION==1 +typedef float Real; +#define FP_REAL_MAX __FLT_MAX__ +#define VECTOR_EPSILON (1e-5f) +#else +typedef double Real; +#define FP_REAL_MAX __DBL_MAX__ +#define VECTOR_EPSILON (1e-10) #endif -// windos, hardcoded limits for now... + +// hardcoded limits for now... // for e.g. MSVC compiler... // some of these defines can be needed // for linux systems as well (e.g. FLT_MAX) @@ -64,102 +58,100 @@ # endif // DBL_MAX #endif // __DBL_MAX__ +#ifndef FLT_MAX +#define FLT_MAX __FLT_MAX__ +#endif + +#ifndef DBL_MAX +#define DBL_MAX __DBL_MAX__ +#endif + #ifndef M_PI # define M_PI 3.1415926536 # define M_E 2.7182818284 #endif -namespace DDF { + +namespace BasicVector { // basic inlined vector class template<class Scalar> -class ntlVector3Dim +class Vector3Dim { public: // Constructor - inline ntlVector3Dim(); + inline Vector3Dim(); // Copy-Constructor - inline ntlVector3Dim(const ntlVector3Dim<Scalar> &v ); - inline ntlVector3Dim(const float *); - inline ntlVector3Dim(const double *); + inline Vector3Dim(const Vector3Dim<Scalar> &v ); + inline Vector3Dim(const float *); + inline Vector3Dim(const double *); // construct a vector from one Scalar - inline ntlVector3Dim(Scalar); + inline Vector3Dim(Scalar); // construct a vector from three Scalars - inline ntlVector3Dim(Scalar, Scalar, Scalar); + inline Vector3Dim(Scalar, Scalar, Scalar); // get address of array for OpenGL Scalar *getAddress() { return value; } // Assignment operator - inline const ntlVector3Dim<Scalar>& operator= (const ntlVector3Dim<Scalar>& v); + inline const Vector3Dim<Scalar>& operator= (const Vector3Dim<Scalar>& v); // Assignment operator - inline const ntlVector3Dim<Scalar>& operator= (Scalar s); + inline const Vector3Dim<Scalar>& operator= (Scalar s); // Assign and add operator - inline const ntlVector3Dim<Scalar>& operator+= (const ntlVector3Dim<Scalar>& v); + inline const Vector3Dim<Scalar>& operator+= (const Vector3Dim<Scalar>& v); // Assign and add operator - inline const ntlVector3Dim<Scalar>& operator+= (Scalar s); + inline const Vector3Dim<Scalar>& operator+= (Scalar s); // Assign and sub operator - inline const ntlVector3Dim<Scalar>& operator-= (const ntlVector3Dim<Scalar>& v); + inline const Vector3Dim<Scalar>& operator-= (const Vector3Dim<Scalar>& v); // Assign and sub operator - inline const ntlVector3Dim<Scalar>& operator-= (Scalar s); + inline const Vector3Dim<Scalar>& operator-= (Scalar s); // Assign and mult operator - inline const ntlVector3Dim<Scalar>& operator*= (const ntlVector3Dim<Scalar>& v); + inline const Vector3Dim<Scalar>& operator*= (const Vector3Dim<Scalar>& v); // Assign and mult operator - inline const ntlVector3Dim<Scalar>& operator*= (Scalar s); + inline const Vector3Dim<Scalar>& operator*= (Scalar s); // Assign and div operator - inline const ntlVector3Dim<Scalar>& operator/= (const ntlVector3Dim<Scalar>& v); + inline const Vector3Dim<Scalar>& operator/= (const Vector3Dim<Scalar>& v); // Assign and div operator - inline const ntlVector3Dim<Scalar>& operator/= (Scalar s); + inline const Vector3Dim<Scalar>& operator/= (Scalar s); // unary operator - inline ntlVector3Dim<Scalar> operator- () const; + inline Vector3Dim<Scalar> operator- () const; // binary operator add - inline ntlVector3Dim<Scalar> operator+ (const ntlVector3Dim<Scalar>&) const; + inline Vector3Dim<Scalar> operator+ (const Vector3Dim<Scalar>&) const; // binary operator add - inline ntlVector3Dim<Scalar> operator+ (Scalar) const; + inline Vector3Dim<Scalar> operator+ (Scalar) const; // binary operator sub - inline ntlVector3Dim<Scalar> operator- (const ntlVector3Dim<Scalar>&) const; + inline Vector3Dim<Scalar> operator- (const Vector3Dim<Scalar>&) const; // binary operator sub - inline ntlVector3Dim<Scalar> operator- (Scalar) const; + inline Vector3Dim<Scalar> operator- (Scalar) const; // binary operator mult - inline ntlVector3Dim<Scalar> operator* (const ntlVector3Dim<Scalar>&) const; + inline Vector3Dim<Scalar> operator* (const Vector3Dim<Scalar>&) const; // binary operator mult - inline ntlVector3Dim<Scalar> operator* (Scalar) const; + inline Vector3Dim<Scalar> operator* (Scalar) const; // binary operator div - inline ntlVector3Dim<Scalar> operator/ (const ntlVector3Dim<Scalar>&) const; + inline Vector3Dim<Scalar> operator/ (const Vector3Dim<Scalar>&) const; // binary operator div - inline ntlVector3Dim<Scalar> operator/ (Scalar) const; + inline Vector3Dim<Scalar> operator/ (Scalar) const; // Projection normal to a vector - inline ntlVector3Dim<Scalar> getOrthogonalntlVector3Dim() const; + inline Vector3Dim<Scalar> getOrthogonalntlVector3Dim() const; // Project into a plane - inline const ntlVector3Dim<Scalar>& projectNormalTo(const ntlVector3Dim<Scalar> &v); + inline const Vector3Dim<Scalar>& projectNormalTo(const Vector3Dim<Scalar> &v); - inline Scalar min() const { return (x<y) ? ( (x<z) ? x:z ) : ( (y<z) ? y:z); } - inline Scalar max() const { return (x>y) ? ( (x>z) ? x:z ) : ( (y>z) ? y:z); } - // minimize - inline const ntlVector3Dim<Scalar> &minimize(const ntlVector3Dim<Scalar> &); + inline const Vector3Dim<Scalar> &minimize(const Vector3Dim<Scalar> &); // maximize - inline const ntlVector3Dim<Scalar> &maximize(const ntlVector3Dim<Scalar> &); + inline const Vector3Dim<Scalar> &maximize(const Vector3Dim<Scalar> &); // access operator inline Scalar& operator[](unsigned int i); // access operator inline const Scalar& operator[](unsigned int i) const; - // return absolutes of all components - inline ntlVector3Dim<Scalar> getAbsolutes() const { return - ntlVector3Dim<Scalar>(fabs(value[0]), fabs(value[1]), fabs(value[2]) ); - }; - - // debug output vector to a string - std::string toString(); - //! actual values union { struct { @@ -176,33 +168,6 @@ public: Scalar Z; }; }; - - // expe compatibility functions - void makeFloor(const ntlVector3Dim<Scalar>& cmp); - void makeCeil(const ntlVector3Dim<Scalar>& cmp); - Scalar squaredDistanceTo(const ntlVector3Dim<Scalar>& vec) const; - - // Returns true if the vector's s components are all greater that the ones of the vector it is compared against. - inline bool operator < ( const ntlVector3Dim<Scalar>& vec ) const; - // Returns true if the vector's s components are all greater or equal that the ones of the vector it is compared against. - inline bool operator <= ( const ntlVector3Dim<Scalar>& vec ) const; - // Returns true if the vector's s components are all smaller that the ones of the vector it is compared against. - inline bool operator > ( const ntlVector3Dim<Scalar>& vec ) const; - // Returns true if the vector's s components are all smaller or equal that the ones of the vector it is compared against. - inline bool operator >= ( const ntlVector3Dim<Scalar>& vec ) const; - - // Return the maximal component value. - inline Scalar maxComponent(void) const; - // Return the minimal component value. - inline Scalar minComponent(void) const; - // Return the index of the maximal coordinate value. - inline int maxComponentId(void) const; - // Return the index of the minimal coordinate value. - inline int minComponentId(void) const; - - // zero element - static const ntlVector3Dim<Scalar> ZERO; - protected: }; @@ -210,24 +175,6 @@ protected: -// VECTOR_EPSILON is the minimal vector length -// In order to be able to discriminate floating point values near zero, and -// to be sure not to fail a comparison because of roundoff errors, use this -// value as a threshold. - -#if FLOATINGPOINT_PRECISION==1 -typedef float Real; -#define FP_REAL_MAX __FLT_MAX__ -#define VECTOR_EPSILON (1e-5f) -#else -typedef double Real; -#define FP_REAL_MAX __DBL_MAX__ -#define VECTOR_EPSILON (1e-10) -#endif -// as variable in globals.cpp -extern const Real gVecEpsilon; - - //------------------------------------------------------------------------------ // VECTOR inline FUNCTIONS @@ -239,7 +186,7 @@ extern const Real gVecEpsilon; Constructor. */ template<class Scalar> -inline ntlVector3Dim<Scalar>::ntlVector3Dim( void ) +inline Vector3Dim<Scalar>::Vector3Dim( void ) { value[0] = value[1] = value[2] = 0; } @@ -250,25 +197,25 @@ inline ntlVector3Dim<Scalar>::ntlVector3Dim( void ) Copy-Constructor. */ template<class Scalar> -inline ntlVector3Dim<Scalar>::ntlVector3Dim( const ntlVector3Dim<Scalar> &v ) +inline Vector3Dim<Scalar>::Vector3Dim( const Vector3Dim<Scalar> &v ) { - value[0] = v.value[0]; - value[1] = v.value[1]; - value[2] = v.value[2]; + value[0] = v.value[0]; + value[1] = v.value[1]; + value[2] = v.value[2]; } - template<class Scalar> -inline ntlVector3Dim<Scalar>::ntlVector3Dim( const float *fvalue) +template<class Scalar> +inline Vector3Dim<Scalar>::Vector3Dim( const float *fvalue) { - value[0] = (Scalar)fvalue[0]; - value[1] = (Scalar)fvalue[1]; - value[2] = (Scalar)fvalue[2]; + value[0] = (Scalar)fvalue[0]; + value[1] = (Scalar)fvalue[1]; + value[2] = (Scalar)fvalue[2]; } - template<class Scalar> -inline ntlVector3Dim<Scalar>::ntlVector3Dim( const double *fvalue) +template<class Scalar> +inline Vector3Dim<Scalar>::Vector3Dim( const double *fvalue) { - value[0] = (Scalar)fvalue[0]; - value[1] = (Scalar)fvalue[1]; - value[2] = (Scalar)fvalue[2]; + value[0] = (Scalar)fvalue[0]; + value[1] = (Scalar)fvalue[1]; + value[2] = (Scalar)fvalue[2]; } @@ -280,7 +227,7 @@ inline ntlVector3Dim<Scalar>::ntlVector3Dim( const double *fvalue) \return The new vector */ template<class Scalar> -inline ntlVector3Dim<Scalar>::ntlVector3Dim(Scalar s ) +inline Vector3Dim<Scalar>::Vector3Dim(Scalar s ) { value[0]= s; value[1]= s; @@ -296,7 +243,7 @@ inline ntlVector3Dim<Scalar>::ntlVector3Dim(Scalar s ) \return The new vector */ template<class Scalar> -inline ntlVector3Dim<Scalar>::ntlVector3Dim(Scalar s1, Scalar s2, Scalar s3) +inline Vector3Dim<Scalar>::Vector3Dim(Scalar s1, Scalar s2, Scalar s3) { value[0]= s1; value[1]= s2; @@ -304,29 +251,15 @@ inline ntlVector3Dim<Scalar>::ntlVector3Dim(Scalar s1, Scalar s2, Scalar s3) } -/************************************************************************* - Compute the vector product of two 3D vectors - \param v Second vector to compute the product with - \return A new vector with the product values - */ -/*template<class Scalar> -inline ntlVector3Dim<Scalar> -ntlVector3Dim<Scalar>::operator^( const ntlVector3Dim<Scalar> &v ) const -{ - return ntlVector3Dim<Scalar>(value[1]*v.value[2] - value[2]*v.value[1], - value[2]*v.value[0] - value[0]*v.value[2], - value[0]*v.value[1] - value[1]*v.value[0]); -}*/ - /************************************************************************* - Copy a ntlVector3Dim componentwise. + Copy a Vector3Dim componentwise. \param v vector with values to be copied \return Reference to self */ template<class Scalar> -inline const ntlVector3Dim<Scalar>& -ntlVector3Dim<Scalar>::operator=( const ntlVector3Dim<Scalar> &v ) +inline const Vector3Dim<Scalar>& +Vector3Dim<Scalar>::operator=( const Vector3Dim<Scalar> &v ) { value[0] = v.value[0]; value[1] = v.value[1]; @@ -341,8 +274,8 @@ ntlVector3Dim<Scalar>::operator=( const ntlVector3Dim<Scalar> &v ) \return Reference to self */ template<class Scalar> -inline const ntlVector3Dim<Scalar>& -ntlVector3Dim<Scalar>::operator=(Scalar s) +inline const Vector3Dim<Scalar>& +Vector3Dim<Scalar>::operator=(Scalar s) { value[0] = s; value[1] = s; @@ -352,13 +285,13 @@ ntlVector3Dim<Scalar>::operator=(Scalar s) /************************************************************************* - Add another ntlVector3Dim componentwise. + Add another Vector3Dim componentwise. \param v vector with values to be added \return Reference to self */ template<class Scalar> -inline const ntlVector3Dim<Scalar>& -ntlVector3Dim<Scalar>::operator+=( const ntlVector3Dim<Scalar> &v ) +inline const Vector3Dim<Scalar>& +Vector3Dim<Scalar>::operator+=( const Vector3Dim<Scalar> &v ) { value[0] += v.value[0]; value[1] += v.value[1]; @@ -373,8 +306,8 @@ ntlVector3Dim<Scalar>::operator+=( const ntlVector3Dim<Scalar> &v ) \return Reference to self */ template<class Scalar> -inline const ntlVector3Dim<Scalar>& -ntlVector3Dim<Scalar>::operator+=(Scalar s) +inline const Vector3Dim<Scalar>& +Vector3Dim<Scalar>::operator+=(Scalar s) { value[0] += s; value[1] += s; @@ -389,8 +322,8 @@ ntlVector3Dim<Scalar>::operator+=(Scalar s) \return Reference to self */ template<class Scalar> -inline const ntlVector3Dim<Scalar>& -ntlVector3Dim<Scalar>::operator-=( const ntlVector3Dim<Scalar> &v ) +inline const Vector3Dim<Scalar>& +Vector3Dim<Scalar>::operator-=( const Vector3Dim<Scalar> &v ) { value[0] -= v.value[0]; value[1] -= v.value[1]; @@ -405,8 +338,8 @@ ntlVector3Dim<Scalar>::operator-=( const ntlVector3Dim<Scalar> &v ) \return Reference to self */ template<class Scalar> -inline const ntlVector3Dim<Scalar>& -ntlVector3Dim<Scalar>::operator-=(Scalar s) +inline const Vector3Dim<Scalar>& +Vector3Dim<Scalar>::operator-=(Scalar s) { value[0]-= s; value[1]-= s; @@ -421,8 +354,8 @@ ntlVector3Dim<Scalar>::operator-=(Scalar s) \return Reference to self */ template<class Scalar> -inline const ntlVector3Dim<Scalar>& -ntlVector3Dim<Scalar>::operator*=( const ntlVector3Dim<Scalar> &v ) +inline const Vector3Dim<Scalar>& +Vector3Dim<Scalar>::operator*=( const Vector3Dim<Scalar> &v ) { value[0] *= v.value[0]; value[1] *= v.value[1]; @@ -437,8 +370,8 @@ ntlVector3Dim<Scalar>::operator*=( const ntlVector3Dim<Scalar> &v ) \return Reference to self */ template<class Scalar> -inline const ntlVector3Dim<Scalar>& -ntlVector3Dim<Scalar>::operator*=(Scalar s) +inline const Vector3Dim<Scalar>& +Vector3Dim<Scalar>::operator*=(Scalar s) { value[0] *= s; value[1] *= s; @@ -448,13 +381,13 @@ ntlVector3Dim<Scalar>::operator*=(Scalar s) /************************************************************************* - Divide by another ntlVector3Dim componentwise. + Divide by another Vector3Dim componentwise. \param v vector of values to divide by \return Reference to self */ template<class Scalar> -inline const ntlVector3Dim<Scalar>& -ntlVector3Dim<Scalar>::operator/=( const ntlVector3Dim<Scalar> &v ) +inline const Vector3Dim<Scalar>& +Vector3Dim<Scalar>::operator/=( const Vector3Dim<Scalar> &v ) { value[0] /= v.value[0]; value[1] /= v.value[1]; @@ -469,8 +402,8 @@ ntlVector3Dim<Scalar>::operator/=( const ntlVector3Dim<Scalar> &v ) \return Reference to self */ template<class Scalar> -inline const ntlVector3Dim<Scalar>& -ntlVector3Dim<Scalar>::operator/=(Scalar s) +inline const Vector3Dim<Scalar>& +Vector3Dim<Scalar>::operator/=(Scalar s) { value[0] /= s; value[1] /= s; @@ -489,10 +422,10 @@ ntlVector3Dim<Scalar>::operator/=(Scalar s) \return The new (negative) vector */ template<class Scalar> -inline ntlVector3Dim<Scalar> -ntlVector3Dim<Scalar>::operator-() const +inline Vector3Dim<Scalar> +Vector3Dim<Scalar>::operator-() const { - return ntlVector3Dim<Scalar>(-value[0], -value[1], -value[2]); + return Vector3Dim<Scalar>(-value[0], -value[1], -value[2]); } @@ -508,10 +441,10 @@ ntlVector3Dim<Scalar>::operator-() const \return The sum vector */ template<class Scalar> -inline ntlVector3Dim<Scalar> -ntlVector3Dim<Scalar>::operator+( const ntlVector3Dim<Scalar> &v ) const +inline Vector3Dim<Scalar> +Vector3Dim<Scalar>::operator+( const Vector3Dim<Scalar> &v ) const { - return ntlVector3Dim<Scalar>(value[0]+v.value[0], + return Vector3Dim<Scalar>(value[0]+v.value[0], value[1]+v.value[1], value[2]+v.value[2]); } @@ -523,10 +456,10 @@ ntlVector3Dim<Scalar>::operator+( const ntlVector3Dim<Scalar> &v ) const \return The sum vector */ template<class Scalar> -inline ntlVector3Dim<Scalar> -ntlVector3Dim<Scalar>::operator+(Scalar s) const +inline Vector3Dim<Scalar> +Vector3Dim<Scalar>::operator+(Scalar s) const { - return ntlVector3Dim<Scalar>(value[0]+s, + return Vector3Dim<Scalar>(value[0]+s, value[1]+s, value[2]+s); } @@ -538,10 +471,10 @@ ntlVector3Dim<Scalar>::operator+(Scalar s) const \return The difference vector */ template<class Scalar> -inline ntlVector3Dim<Scalar> -ntlVector3Dim<Scalar>::operator-( const ntlVector3Dim<Scalar> &v ) const +inline Vector3Dim<Scalar> +Vector3Dim<Scalar>::operator-( const Vector3Dim<Scalar> &v ) const { - return ntlVector3Dim<Scalar>(value[0]-v.value[0], + return Vector3Dim<Scalar>(value[0]-v.value[0], value[1]-v.value[1], value[2]-v.value[2]); } @@ -553,10 +486,10 @@ ntlVector3Dim<Scalar>::operator-( const ntlVector3Dim<Scalar> &v ) const \return The difference vector */ template<class Scalar> -inline ntlVector3Dim<Scalar> -ntlVector3Dim<Scalar>::operator-(Scalar s ) const +inline Vector3Dim<Scalar> +Vector3Dim<Scalar>::operator-(Scalar s ) const { - return ntlVector3Dim<Scalar>(value[0]-s, + return Vector3Dim<Scalar>(value[0]-s, value[1]-s, value[2]-s); } @@ -569,48 +502,38 @@ ntlVector3Dim<Scalar>::operator-(Scalar s ) const \return The product vector */ template<class Scalar> -inline ntlVector3Dim<Scalar> -ntlVector3Dim<Scalar>::operator*( const ntlVector3Dim<Scalar>& v) const +inline Vector3Dim<Scalar> +Vector3Dim<Scalar>::operator*( const Vector3Dim<Scalar>& v) const { - return ntlVector3Dim<Scalar>(value[0]*v.value[0], + return Vector3Dim<Scalar>(value[0]*v.value[0], value[1]*v.value[1], value[2]*v.value[2]); } /************************************************************************* - Build a ntlVector3Dim with a Scalar value multiplied to each component. + Build a Vector3Dim with a Scalar value multiplied to each component. \param s The Scalar value to multiply with \return The product vector */ template<class Scalar> -inline ntlVector3Dim<Scalar> -ntlVector3Dim<Scalar>::operator*(Scalar s) const +inline Vector3Dim<Scalar> +Vector3Dim<Scalar>::operator*(Scalar s) const { - return ntlVector3Dim<Scalar>(value[0]*s, value[1]*s, value[2]*s); + return Vector3Dim<Scalar>(value[0]*s, value[1]*s, value[2]*s); } -// allow multiplications of the form: v2 = 3 * v1 -template<class Scalar> -inline ntlVector3Dim<Scalar> -operator*(Scalar s, ntlVector3Dim<Scalar> v) -{ - return ntlVector3Dim<Scalar>(v.value[0]*s, v.value[1]*s, v.value[2]*s); -} - - - /************************************************************************* Build a vector divided componentwise by another vector. \param v The second vector to divide by \return The ratio vector */ template<class Scalar> -inline ntlVector3Dim<Scalar> -ntlVector3Dim<Scalar>::operator/(const ntlVector3Dim<Scalar>& v) const +inline Vector3Dim<Scalar> +Vector3Dim<Scalar>::operator/(const Vector3Dim<Scalar>& v) const { - return ntlVector3Dim<Scalar>(value[0]/v.value[0], + return Vector3Dim<Scalar>(value[0]/v.value[0], value[1]/v.value[1], value[2]/v.value[2]); } @@ -623,10 +546,10 @@ ntlVector3Dim<Scalar>::operator/(const ntlVector3Dim<Scalar>& v) const \return The ratio vector */ template<class Scalar> -inline ntlVector3Dim<Scalar> -ntlVector3Dim<Scalar>::operator/(Scalar s) const +inline Vector3Dim<Scalar> +Vector3Dim<Scalar>::operator/(Scalar s) const { - return ntlVector3Dim<Scalar>(value[0]/s, + return Vector3Dim<Scalar>(value[0]/s, value[1]/s, value[2]/s); } @@ -642,7 +565,7 @@ ntlVector3Dim<Scalar>::operator/(Scalar s) const */ template<class Scalar> inline Scalar& -ntlVector3Dim<Scalar>::operator[]( unsigned int i ) +Vector3Dim<Scalar>::operator[]( unsigned int i ) { return value[i]; } @@ -655,7 +578,7 @@ ntlVector3Dim<Scalar>::operator[]( unsigned int i ) */ template<class Scalar> inline const Scalar& -ntlVector3Dim<Scalar>::operator[]( unsigned int i ) const +Vector3Dim<Scalar>::operator[]( unsigned int i ) const { return value[i]; } @@ -674,7 +597,7 @@ ntlVector3Dim<Scalar>::operator[]( unsigned int i ) const \return The value of the scalar product */ template<class Scalar> -inline Scalar dot(const ntlVector3Dim<Scalar> &t, const ntlVector3Dim<Scalar> &v ) +inline Scalar dot(const Vector3Dim<Scalar> &t, const Vector3Dim<Scalar> &v ) { //return t.value[0]*v.value[0] + t.value[1]*v.value[1] + t.value[2]*v.value[2]; return ((t[0]*v[0]) + (t[1]*v[1]) + (t[2]*v[2])); @@ -685,9 +608,9 @@ inline Scalar dot(const ntlVector3Dim<Scalar> &t, const ntlVector3Dim<Scalar> &v Calculate the cross product of this and another vector */ template<class Scalar> -inline ntlVector3Dim<Scalar> cross(const ntlVector3Dim<Scalar> &t, const ntlVector3Dim<Scalar> &v) +inline Vector3Dim<Scalar> cross(const Vector3Dim<Scalar> &t, const Vector3Dim<Scalar> &v) { - ntlVector3Dim<Scalar> cp( + Vector3Dim<Scalar> cp( ((t[1]*v[2]) - (t[2]*v[1])), ((t[2]*v[0]) - (t[0]*v[2])), ((t[0]*v[1]) - (t[1]*v[0])) ); @@ -703,22 +626,22 @@ inline ntlVector3Dim<Scalar> cross(const ntlVector3Dim<Scalar> &t, const ntlVect \return The orthonormal vector */ template<class Scalar> -ntlVector3Dim<Scalar> -ntlVector3Dim<Scalar>::getOrthogonalntlVector3Dim() const +Vector3Dim<Scalar> +Vector3Dim<Scalar>::getOrthogonalntlVector3Dim() const { - // Determine the component with max. absolute value - int maxIndex= (fabs(value[0]) > fabs(value[1])) ? 0 : 1; - maxIndex= (fabs(value[maxIndex]) > fabs(value[2])) ? maxIndex : 2; - - /************************************************************************* - Choose another axis than the one with max. component and project - orthogonal to self - */ - ntlVector3Dim<Scalar> vec(0.0); - vec[(maxIndex+1)%3]= 1; - vec.normalize(); - vec.projectNormalTo(this->getNormalized()); - return vec; + // Determine the component with max. absolute value + int max= (fabs(value[0]) > fabs(value[1])) ? 0 : 1; + max= (fabs(value[max]) > fabs(value[2])) ? max : 2; + + /************************************************************************* + Choose another axis than the one with max. component and project + orthogonal to self + */ + Vector3Dim<Scalar> vec(0.0); + vec[(max+1)%3]= 1; + vec.normalize(); + vec.projectNormalTo(this->getNormalized()); + return vec; } @@ -729,14 +652,14 @@ ntlVector3Dim<Scalar>::getOrthogonalntlVector3Dim() const \return The projected vector */ template<class Scalar> -inline const ntlVector3Dim<Scalar>& -ntlVector3Dim<Scalar>::projectNormalTo(const ntlVector3Dim<Scalar> &v) +inline const Vector3Dim<Scalar>& +Vector3Dim<Scalar>::projectNormalTo(const Vector3Dim<Scalar> &v) { - Scalar sprod = dot(*this,v); - value[0]= value[0] - v.value[0] * sprod; - value[1]= value[1] - v.value[1] * sprod; - value[2]= value[2] - v.value[2] * sprod; - return *this; + Scalar sprod = dot(*this,v); + value[0]= value[0] - v.value[0] * sprod; + value[1]= value[1] - v.value[1] * sprod; + value[2]= value[2] - v.value[2] * sprod; + return *this; } @@ -754,8 +677,8 @@ ntlVector3Dim<Scalar>::projectNormalTo(const ntlVector3Dim<Scalar> &v) \return Reference to the modified self */ template<class Scalar> -inline const ntlVector3Dim<Scalar> & -ntlVector3Dim<Scalar>::minimize(const ntlVector3Dim<Scalar> &pnt) +inline const Vector3Dim<Scalar> & +Vector3Dim<Scalar>::minimize(const Vector3Dim<Scalar> &pnt) { for (unsigned int i = 0; i < 3; i++) value[i] = MIN(value[i],pnt[i]); @@ -771,8 +694,8 @@ ntlVector3Dim<Scalar>::minimize(const ntlVector3Dim<Scalar> &pnt) \return Reference to the modified self */ template<class Scalar> -inline const ntlVector3Dim<Scalar> & -ntlVector3Dim<Scalar>::maximize(const ntlVector3Dim<Scalar> &pnt) +inline const Vector3Dim<Scalar> & +Vector3Dim<Scalar>::maximize(const Vector3Dim<Scalar> &pnt) { for (unsigned int i = 0; i < 3; i++) value[i] = MAX(value[i],pnt[i]); @@ -788,7 +711,7 @@ ntlVector3Dim<Scalar>::maximize(const ntlVector3Dim<Scalar> &pnt) // HELPER FUNCTIONS, independent of implementation /************************************************************************/ -#define VECTOR_TYPE ntlVector3Dim<Scalar> +#define VECTOR_TYPE Vector3Dim<Scalar> /************************************************************************* @@ -803,7 +726,7 @@ inline Scalar norm( const VECTOR_TYPE &v) } // for e.g. min max operator -inline Real normHelper(const ntlVector3Dim<Real> &v) { +inline Real normHelper(const Vector3Dim<Real> &v) { return norm(v); } inline Real normHelper(const Real &v) { @@ -816,10 +739,11 @@ inline Real normHelper(const int &v) { /************************************************************************* Same as getNorm but doesnt sqrt - */ + */ template<class Scalar> -inline Scalar normNoSqrt( const VECTOR_TYPE &v) { - return v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; +inline Scalar normNoSqrt( const VECTOR_TYPE &v) +{ + return v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; } @@ -830,67 +754,41 @@ inline Scalar normNoSqrt( const VECTOR_TYPE &v) { template<class Scalar> inline VECTOR_TYPE getNormalized( const VECTOR_TYPE &v) { - Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; - if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) - return v; /* normalized "enough"... */ - else if (l > VECTOR_EPSILON*VECTOR_EPSILON) - { - Scalar fac = 1./sqrt(l); - return VECTOR_TYPE(v[0]*fac, v[1]*fac, v[2]*fac); - } - else - return VECTOR_TYPE((Scalar)0); + Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) + return v; /* normalized "enough"... */ + else if (l > VECTOR_EPSILON*VECTOR_EPSILON) + { + Scalar fac = 1./sqrt(l); + return VECTOR_TYPE(v[0]*fac, v[1]*fac, v[2]*fac); + } + else + return VECTOR_TYPE((Scalar)0); } /************************************************************************* Compute the norm of the vector and normalize it. \return The value of the norm - */ - template<class Scalar> + */ +template<class Scalar> inline Scalar normalize( VECTOR_TYPE &v) { - Scalar norm; - Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; - if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) { - norm = 1.; + Scalar norm; + Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) { + norm = 1.; } else if (l > VECTOR_EPSILON*VECTOR_EPSILON) { - norm = sqrt(l); - Scalar fac = 1./norm; - v[0] *= fac; - v[1] *= fac; - v[2] *= fac; + norm = sqrt(l); + Scalar fac = 1./norm; + v[0] *= fac; + v[1] *= fac; + v[2] *= fac; } else { - v[0]= v[1]= v[2]= 0; - norm = 0.; - } - return (Scalar)norm; -} - -/************************************************************************* - Stable vector to angle conversion - \return unique Angles in the of phi=[0,2PI], th=[0,PI] - */ - template<class Scalar> -inline void vecToAngle(const VECTOR_TYPE &v, Scalar& phi, Scalar& 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; + v[0]= v[1]= v[2]= 0; + norm = 0.; + } + return (Scalar)norm; } @@ -1030,7 +928,10 @@ inline void hsvToRgb( VECTOR_TYPE &V ) //! global string for formatting vector output in utilities.cpp -extern const char *globVecFormatStr; +//extern const char *globVecFormatStr; +#if 0 +static const char *globVecFormatStr = "[%6.4f,%6.4f,%6.4f]"; +#endif /************************************************************************* Outputs the object in human readable form using the format @@ -1038,178 +939,51 @@ extern const char *globVecFormatStr; */ template<class Scalar> std::ostream& -operator<<( std::ostream& os, const DDF::ntlVector3Dim<Scalar>& i ) +operator<<( std::ostream& os, const BasicVector::Vector3Dim<Scalar>& i ) { +#if 0 char buf[256]; - snprintf(buf,256,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]); +#if _WIN32 + sprintf(buf,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]); +#else + snprintf(buf,256,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]); +#endif os << std::string(buf); - //os << '[' << i[0] << ", " << i[1] << ", " << i[2] << ']'; - return os; +#endif + return os; } - /************************************************************************* Reads the contents of the object from a stream using the same format as the output operator. */ template<class Scalar> std::istream& -operator>>( std::istream& is, DDF::ntlVector3Dim<Scalar>& i ) +operator>>( std::istream& is, BasicVector::Vector3Dim<Scalar>& i ) { - char c; - char dummy[3]; - is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c; - return is; -} - -// helper function for output -template<class Scalar> std::string ntlVector3Dim<Scalar>::toString() { - char buf[256]; - snprintf(buf,256,globVecFormatStr, (double)(*this)[0],(double)(*this)[1],(double)(*this)[2]); - return std::string(buf); + char c; + char dummy[3]; + is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c; + return is; } -// helper function for output -template<class Vec> bool intVecIsEqual(Vec a, Vec b) { - return a[0]==b[0] && a[1]==b[1] && a[2]==b[2]; -} /**************************************************************************/ // typedefs! /**************************************************************************/ -// a 3D vector with double precision -typedef ntlVector3Dim<double> nVec3d; - -// a 3D vector with single precision -typedef ntlVector3Dim<float> nVec3f; - -// a 3D integer vector -typedef ntlVector3Dim<int> nVec3i; - -/* convert int,float and double vectors */ -template<class T> inline nVec3i vec2I(T v) { return nVec3i((int)v[0],(int)v[1],(int)v[2]); } -template<class T> inline nVec3i vec2I(T v0, T v1, T v2) { return nVec3i((int)v0,(int)v1,(int)v2); } -template<class T> inline nVec3d vec2D(T v) { return nVec3d(v[0],v[1],v[2]); } -template<class T> inline nVec3i vec2D(T v0, T v1, T v2) { return nVec3d((double)v0,(double)v1,(double)v2); } -template<class T> inline nVec3f vec2F(T v) { return nVec3f(v[0],v[1],v[2]); } -template<class T> inline nVec3i vec2F(T v0, T v1, T v2) { return nVec3f((float)v0,(float)v1,(float)v2); } -template<class T> inline nVec3i vecround(T v) { return nVec3i((int)round(v[0]),(int)round(v[1]),(int)round(v[2])); } - - - -/************************************************************************/ -// default vector typing - - -// a 3D vector for graphics output, typically float? -typedef ntlVector3Dim<Real> Vec3; - -/* convert to Real vec */ -template<class T> inline Vec3 vec2R(T v) { return Vec3(v[0],v[1],v[2]); } - - /* get minimal vector length value that can be discriminated. */ inline Real getVecEpsilon() { return (Real)VECTOR_EPSILON; } -// expe compatibility functions - -//template<class Scalar> -//inline XXX ntlVector3Dim<Scalar>:: - -//-------------------------------------------------------------------------------- -template<class Scalar> -inline Scalar ntlVector3Dim<Scalar>::squaredDistanceTo(const ntlVector3Dim<Scalar>& vec) const -{ - Scalar dx,dy,dz; - dx = x-vec.x; - dy = y-vec.y; - dz = z-vec.z; - return dx*dx + dy*dy + dz*dz; -} -//-------------------------------------------------------------------------------- -template<class Scalar> -inline void ntlVector3Dim<Scalar>::makeFloor(const ntlVector3Dim<Scalar>& cmp) -{ - if( cmp.x < x ) x = cmp.x; - if( cmp.y < y ) y = cmp.y; - if( cmp.z < z ) z = cmp.z; -} -//-------------------------------------------------------------------------------- -template<class Scalar> -inline void ntlVector3Dim<Scalar>::makeCeil(const ntlVector3Dim<Scalar>& cmp) -{ - if( cmp.x > x ) x = cmp.x; - if( cmp.y > y ) y = cmp.y; - if( cmp.z > z ) z = cmp.z; -} +// a 3D integer vector +typedef Vector3Dim<int> Vec3Int; -//-------------------------------------------------------------------------------- -template<class Scalar> -inline bool ntlVector3Dim<Scalar>::operator < ( const ntlVector3Dim<Scalar>& vec ) const -{ - if( x < vec.x && y < vec.y && z < vec.z ) - return true; - return false; -} -//-------------------------------------------------------------------------------- -template<class Scalar> -inline bool ntlVector3Dim<Scalar>::operator <= ( const ntlVector3Dim<Scalar>& vec ) const -{ - if( x <= vec.x && y <= vec.y && z <= vec.z ) - return true; - return false; -} -//-------------------------------------------------------------------------------- -template<class Scalar> -inline bool ntlVector3Dim<Scalar>::operator > ( const ntlVector3Dim<Scalar>& vec ) const -{ - if( x > vec.x && y > vec.y && z > vec.z ) - return true; - return false; -} -//-------------------------------------------------------------------------------- -template<class Scalar> -inline bool ntlVector3Dim<Scalar>::operator >= ( const ntlVector3Dim<Scalar>& vec ) const -{ - if( x >= vec.x && y >= vec.y && z >= vec.z ) - return true; - return false; -} +// a 3D vector +typedef Vector3Dim<Real> Vec3; -//-------------------------------------------------------------------------------- -template<class Scalar> -inline Scalar ntlVector3Dim<Scalar>::maxComponent(void) const -{ - return VMAX(*this); -} -//-------------------------------------------------------------------------------- -template<class Scalar> -inline Scalar ntlVector3Dim<Scalar>::minComponent(void) const -{ - return VMIN(*this); -} -//-------------------------------------------------------------------------------- -template<class Scalar> -inline int ntlVector3Dim<Scalar>::maxComponentId(void) const -{ - if (x<y) - return (y<z ? 2 : 1); - else - return (x<z ? 2 : 0); -} -//-------------------------------------------------------------------------------- -template<class Scalar> -inline int ntlVector3Dim<Scalar>::minComponentId(void) const -{ - if (x<y) - return (x<z ? 0 : 2); - else - return (y<Z ? 1 : 2); -} -}; // namespace DDF +}; // namespace -#endif /* DDF_BASICVEC_H */ +#endif /* BASICVECTOR_H */ diff --git a/intern/smoke/intern/WAVELET_NOISE.h b/intern/smoke/intern/WAVELET_NOISE.h new file mode 100644 index 00000000000..66dfb95d143 --- /dev/null +++ b/intern/smoke/intern/WAVELET_NOISE.h @@ -0,0 +1,517 @@ +/** \file smoke/intern/WAVELET_NOISE.h + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +////////////////////////////////////////////////////////////////////////////////////////// +// Wavelet noise functions +// +// This code is based on the C code provided in the appendices of: +// +// @article{1073264, +// author = {Robert L. Cook and Tony DeRose}, +// title = {Wavelet noise}, +// journal = {ACM Trans. Graph.}, +// volume = {24}, +// number = {3}, +// year = {2005}, +// issn = {0730-0301}, +// pages = {803--811}, +// doi = {http://doi.acm.org/10.1145/1073204.1073264}, +// publisher = {ACM}, +// address = {New York, NY, USA}, +// } +// +////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef WAVELET_NOISE_H +#define WAVELET_NOISE_H + +#include <MERSENNETWISTER.h> + +#ifdef WIN32 +#include <float.h> +#define isnan _isnan +#endif + +// Tile file header, update revision upon any change done to the noise generator +static const char tilefile_headerstring[] = "Noise Tile File rev. "; +static const char tilefile_revision[] = "001"; + +#define NOISE_TILE_SIZE 128 +static const int noiseTileSize = NOISE_TILE_SIZE; + +// warning - noiseTileSize has to be 128^3! +#define modFast128(x) ((x) & 127) +#define modFast64(x) ((x) & 63) +#define DOWNCOEFFS 0.000334f,-0.001528f, 0.000410f, 0.003545f,-0.000938f,-0.008233f, 0.002172f, 0.019120f, \ + -0.005040f,-0.044412f, 0.011655f, 0.103311f,-0.025936f,-0.243780f, 0.033979f, 0.655340f, \ + 0.655340f, 0.033979f,-0.243780f,-0.025936f, 0.103311f, 0.011655f,-0.044412f,-0.005040f, \ + 0.019120f, 0.002172f,-0.008233f,-0.000938f, 0.003546f, 0.000410f,-0.001528f, 0.000334f + +////////////////////////////////////////////////////////////////////////////////////////// +// Wavelet downsampling -- periodic boundary conditions +////////////////////////////////////////////////////////////////////////////////////////// +static void downsampleX(float *from, float *to, int n){ + // if these values are not local incorrect results are generated + float downCoeffs[32] = { DOWNCOEFFS }; + const float *a = &downCoeffs[16]; + for (int i = 0; i < n / 2; i++) { + to[i] = 0; + for (int k = 2 * i - 16; k < 2 * i + 16; k++) + to[i] += a[k - 2 * i] * from[modFast128(k)]; + } +} +static void downsampleY(float *from, float *to, int n){ + // if these values are not local incorrect results are generated + float downCoeffs[32] = { DOWNCOEFFS }; + const float *a = &downCoeffs[16]; + for (int i = 0; i < n / 2; i++) { + to[i * n] = 0; + for (int k = 2 * i - 16; k < 2 * i + 16; k++) + to[i * n] += a[k - 2 * i] * from[modFast128(k) * n]; + } +} +static void downsampleZ(float *from, float *to, int n){ + // if these values are not local incorrect results are generated + float downCoeffs[32] = { DOWNCOEFFS }; + const float *a = &downCoeffs[16]; + for (int i = 0; i < n / 2; i++) { + to[i * n * n] = 0; + for (int k = 2 * i - 16; k < 2 * i + 16; k++) + to[i * n * n] += a[k - 2 * i] * from[modFast128(k) * n * n]; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Wavelet downsampling -- Neumann boundary conditions +////////////////////////////////////////////////////////////////////////////////////////// +static void downsampleNeumann(const float *from, float *to, int n, int stride) +{ + // if these values are not local incorrect results are generated + float downCoeffs[32] = { DOWNCOEFFS }; + const float *const aCoCenter= &downCoeffs[16]; + for (int i = 0; i < n / 2; i++) { + to[i * stride] = 0; + for (int k = 2 * i - 16; k < 2 * i + 16; k++) { + // handle boundary + float fromval; + if (k < 0) { + fromval = from[0]; + } else if(k > n - 1) { + fromval = from[(n - 1) * stride]; + } else { + fromval = from[k * stride]; + } + to[i * stride] += aCoCenter[k - 2 * i] * fromval; + } + } +} +static void downsampleXNeumann(float* to, const float* from, int sx,int sy, int sz) { + for (int iy = 0; iy < sy; iy++) + for (int iz = 0; iz < sz; iz++) { + const int i = iy * sx + iz*sx*sy; + downsampleNeumann(&from[i], &to[i], sx, 1); + } +} +static void downsampleYNeumann(float* to, const float* from, int sx,int sy, int sz) { + for (int ix = 0; ix < sx; ix++) + for (int iz = 0; iz < sz; iz++) { + const int i = ix + iz*sx*sy; + downsampleNeumann(&from[i], &to[i], sy, sx); + } +} +static void downsampleZNeumann(float* to, const float* from, int sx,int sy, int sz) { + for (int ix = 0; ix < sx; ix++) + for (int iy = 0; iy < sy; iy++) { + const int i = ix + iy*sx; + downsampleNeumann(&from[i], &to[i], sz, sx*sy); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Wavelet upsampling - periodic boundary conditions +////////////////////////////////////////////////////////////////////////////////////////// +static float _upCoeffs[4] = {0.25f, 0.75f, 0.75f, 0.25f}; +static void upsampleX(float *from, float *to, int n) { + const float *p = &_upCoeffs[2]; + + for (int i = 0; i < n; i++) { + to[i] = 0; + for (int k = i / 2; k <= i / 2 + 1; k++) + to[i] += p[i - 2 * k] * from[modFast64(k)]; + } +} +static void upsampleY(float *from, float *to, int n) { + const float *p = &_upCoeffs[2]; + + for (int i = 0; i < n; i++) { + to[i * n] = 0; + for (int k = i / 2; k <= i / 2 + 1; k++) + to[i * n] += p[i - 2 * k] * from[modFast64(k) * n]; + } +} +static void upsampleZ(float *from, float *to, int n) { + const float *p = &_upCoeffs[2]; + + for (int i = 0; i < n; i++) { + to[i * n * n] = 0; + for (int k = i / 2; k <= i / 2 + 1; k++) + to[i * n * n] += p[i - 2 * k] * from[modFast64(k) * n * n]; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Wavelet upsampling - Neumann boundary conditions +////////////////////////////////////////////////////////////////////////////////////////// +static void upsampleNeumann(const float *from, float *to, int n, int stride) { + static const float *const pCoCenter = &_upCoeffs[2]; + for (int i = 0; i < n; i++) { + to[i * stride] = 0; + for (int k = i / 2; k <= i / 2 + 1; k++) { + float fromval; + if(k>n/2) { + fromval = from[(n/2) * stride]; + } else { + fromval = from[k * stride]; + } + to[i * stride] += pCoCenter[i - 2 * k] * fromval; + } + } +} +static void upsampleXNeumann(float* to, const float* from, int sx, int sy, int sz) { + for (int iy = 0; iy < sy; iy++) + for (int iz = 0; iz < sz; iz++) { + const int i = iy * sx + iz*sx*sy; + upsampleNeumann(&from[i], &to[i], sx, 1); + } +} +static void upsampleYNeumann(float* to, const float* from, int sx, int sy, int sz) { + for (int ix = 0; ix < sx; ix++) + for (int iz = 0; iz < sz; iz++) { + const int i = ix + iz*sx*sy; + upsampleNeumann(&from[i], &to[i], sy, sx); + } +} +static void upsampleZNeumann(float* to, const float* from, int sx, int sy, int sz) { + for (int ix = 0; ix < sx; ix++) + for (int iy = 0; iy < sy; iy++) { + const int i = ix + iy*sx; + upsampleNeumann(&from[i], &to[i], sz, sx*sy); + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// load in an existing noise tile +////////////////////////////////////////////////////////////////////////////////////////// +static bool loadTile(float* const noiseTileData, std::string filename) +{ + FILE* file; + char headerbuffer[64]; + size_t headerlen; + size_t bread; + int endiantest = 1; + char endianness; + + file = fopen(filename.c_str(), "rb"); + + if (file == NULL) { + printf("loadTile: No noise tile '%s' found.\n", filename.c_str()); + return false; + } + + //Check header + headerlen = strlen(tilefile_headerstring) + strlen(tilefile_revision) + 2; + bread = fread((void*)headerbuffer, 1, headerlen, file); + if (*((unsigned char*)&endiantest) == 1) + endianness = 'L'; + else + endianness = 'B'; + if ((bread != headerlen) + || (strncmp(headerbuffer, tilefile_headerstring, strlen(tilefile_headerstring))) + || (strncmp(headerbuffer+ strlen(tilefile_headerstring), tilefile_revision, strlen(tilefile_revision))) + || (headerbuffer[headerlen-2] != endianness) + || (headerbuffer[headerlen-1] != (char)((char)sizeof(long)+'0'))) + { + printf("loadTile : Noise tile '%s' was generated on an incompatible platform.\n",filename.c_str()); + fclose(file); + return false; + } + + // dimensions + size_t gridSize = noiseTileSize * noiseTileSize * noiseTileSize; + + // noiseTileData memory is managed by caller + bread = fread((void*)noiseTileData, sizeof(float), gridSize, file); + fclose(file); + printf("Noise tile file '%s' loaded.\n", filename.c_str()); + + if (bread != gridSize) { + printf("loadTile: Noise tile '%s' is wrong size %d.\n", filename.c_str(), (int)bread); + return false; + } + + // check for invalid nan tile data that could be generated. bug is now + // fixed, but invalid files may still hang around + if (isnan(noiseTileData[0])) { + printf("loadTile: Noise tile '%s' contains nan values.\n", filename.c_str()); + return false; + } + + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// write out an existing noise tile +////////////////////////////////////////////////////////////////////////////////////////// +static void saveTile(float* const noiseTileData, std::string filename) +{ + FILE* file; + file = fopen(filename.c_str(), "wb"); + int endiantest=1; + char longsize; + + if (file == NULL) { + printf("saveTile: Noise tile '%s' could not be saved.\n", filename.c_str()); + return; + } + + //Write file header + fwrite(tilefile_headerstring, strlen(tilefile_headerstring), 1, file); + fwrite(tilefile_revision, strlen(tilefile_revision), 1, file); + //Endianness + if (*((unsigned char*)&endiantest) == 1) + fwrite("L", 1, 1, file); //Little endian + else + fwrite("B",1,1,file); //Big endian + //32/64bit + longsize = (char)sizeof(long)+'0'; + fwrite(&longsize, 1, 1, file); + + + fwrite((void*)noiseTileData, sizeof(float), noiseTileSize * noiseTileSize * noiseTileSize, file); + fclose(file); + + printf("saveTile: Noise tile file '%s' saved.\n", filename.c_str()); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// create a new noise tile if necessary +////////////////////////////////////////////////////////////////////////////////////////// +static void generateTile_WAVELET(float* const noiseTileData, std::string filename) { + // if a tile already exists, just use that + if (loadTile(noiseTileData, filename)) return; + + const int n = noiseTileSize; + const int n3 = n*n*n; + std::cout <<"Generating new 3d noise tile size="<<n<<"^3 \n"; + MTRand twister; + + float *temp13 = new float[n3]; + float *temp23 = new float[n3]; + float *noise3 = new float[n3]; + + // initialize + for (int i = 0; i < n3; i++) { + temp13[i] = temp23[i] = noise3[i] = 0.; + } + + // Step 1. Fill the tile with random numbers in the range -1 to 1. + for (int i = 0; i < n3; i++) + noise3[i] = twister.randNorm(); + + // Steps 2 and 3. Downsample and upsample the tile + for (int iy = 0; iy < n; iy++) + for (int iz = 0; iz < n; iz++) { + const int i = iy * n + iz*n*n; + downsampleX(&noise3[i], &temp13[i], n); + upsampleX (&temp13[i], &temp23[i], n); + } + for (int ix = 0; ix < n; ix++) + for (int iz = 0; iz < n; iz++) { + const int i = ix + iz*n*n; + downsampleY(&temp23[i], &temp13[i], n); + upsampleY (&temp13[i], &temp23[i], n); + } + for (int ix = 0; ix < n; ix++) + for (int iy = 0; iy < n; iy++) { + const int i = ix + iy*n; + downsampleZ(&temp23[i], &temp13[i], n); + upsampleZ (&temp13[i], &temp23[i], n); + } + + // Step 4. Subtract out the coarse-scale contribution + for (int i = 0; i < n3; i++) + noise3[i] -= temp23[i]; + + // Avoid even/odd variance difference by adding odd-offset version of noise to itself. + int offset = n / 2; + if (offset % 2 == 0) offset++; + + int icnt=0; + for (int ix = 0; ix < n; ix++) + for (int iy = 0; iy < n; iy++) + for (int iz = 0; iz < n; iz++) { + temp13[icnt] = noise3[modFast128(ix+offset) + modFast128(iy+offset)*n + modFast128(iz+offset)*n*n]; + icnt++; + } + + for (int i = 0; i < n3; i++) + noise3[i] += temp13[i]; + + for (int i = 0; i < n3; i++) + noiseTileData[i] = noise3[i]; + + saveTile(noise3, filename); + delete[] temp13; + delete[] temp23; + delete[] noise3; + std::cout <<"Generating new 3d noise done\n"; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// x derivative of noise +////////////////////////////////////////////////////////////////////////////////////////// +static inline float WNoiseDx(Vec3 p, float* data) { + int c[3], mid[3], n = noiseTileSize; + float w[3][3], t, result = 0; + + mid[0] = (int)ceil(p[0] - 0.5); + t = mid[0] - (p[0] - 0.5); + w[0][0] = -t; + w[0][2] = (1.f - t); + w[0][1] = 2.0f * t - 1.0f; + + mid[1] = (int)ceil(p[1] - 0.5); + t = mid[1] - (p[1] - 0.5); + w[1][0] = t * t / 2; + w[1][2] = (1 - t) * (1 - t) / 2; + w[1][1] = 1 - w[1][0] - w[1][2]; + + mid[2] = (int)ceil(p[2] - 0.5); + t = mid[2] - (p[2] - 0.5); + w[2][0] = t * t / 2; + w[2][2] = (1 - t) * (1 - t)/2; + w[2][1] = 1 - w[2][0] - w[2][2]; + + // to optimize, explicitly unroll this loop + for (int z = -1; z <=1; z++) + for (int y = -1; y <=1; y++) + for (int x = -1; x <=1; x++) + { + float weight = 1.0f; + c[0] = modFast128(mid[0] + x); + weight *= w[0][x+1]; + c[1] = modFast128(mid[1] + y); + weight *= w[1][y+1]; + c[2] = modFast128(mid[2] + z); + weight *= w[2][z+1]; + result += weight * data[c[2]*n*n+c[1]*n+c[0]]; + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// y derivative of noise +////////////////////////////////////////////////////////////////////////////////////////// +static inline float WNoiseDy(Vec3 p, float* data) { + int c[3], mid[3], n=noiseTileSize; + float w[3][3], t, result =0; + + mid[0] = (int)ceil(p[0] - 0.5); + t = mid[0]-(p[0] - 0.5); + w[0][0] = t * t / 2; + w[0][2] = (1 - t) * (1 - t) / 2; + w[0][1] = 1 - w[0][0] - w[0][2]; + + mid[1] = (int)ceil(p[1] - 0.5); + t = mid[1]-(p[1] - 0.5); + w[1][0] = -t; + w[1][2] = (1.f - t); + w[1][1] = 2.0f * t - 1.0f; + + mid[2] = (int)ceil(p[2] - 0.5); + t = mid[2] - (p[2] - 0.5); + w[2][0] = t * t / 2; + w[2][2] = (1 - t) * (1 - t)/2; + w[2][1] = 1 - w[2][0] - w[2][2]; + + // to optimize, explicitly unroll this loop + for (int z = -1; z <=1; z++) + for (int y = -1; y <=1; y++) + for (int x = -1; x <=1; x++) + { + float weight = 1.0f; + c[0] = modFast128(mid[0] + x); + weight *= w[0][x+1]; + c[1] = modFast128(mid[1] + y); + weight *= w[1][y+1]; + c[2] = modFast128(mid[2] + z); + weight *= w[2][z+1]; + result += weight * data[c[2]*n*n+c[1]*n+c[0]]; + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// z derivative of noise +////////////////////////////////////////////////////////////////////////////////////////// +static inline float WNoiseDz(Vec3 p, float* data) { + int c[3], mid[3], n=noiseTileSize; + float w[3][3], t, result =0; + + mid[0] = (int)ceil(p[0] - 0.5); + t = mid[0]-(p[0] - 0.5); + w[0][0] = t * t / 2; + w[0][2] = (1 - t) * (1 - t) / 2; + w[0][1] = 1 - w[0][0] - w[0][2]; + + mid[1] = (int)ceil(p[1] - 0.5); + t = mid[1]-(p[1] - 0.5); + w[1][0] = t * t / 2; + w[1][2] = (1 - t) * (1 - t) / 2; + w[1][1] = 1 - w[1][0] - w[1][2]; + + mid[2] = (int)ceil(p[2] - 0.5); + t = mid[2] - (p[2] - 0.5); + w[2][0] = -t; + w[2][2] = (1.f - t); + w[2][1] = 2.0f * t - 1.0f; + + // to optimize, explicitly unroll this loop + for (int z = -1; z <=1; z++) + for (int y = -1; y <=1; y++) + for (int x = -1; x <=1; x++) + { + float weight = 1.0f; + c[0] = modFast128(mid[0] + x); + weight *= w[0][x+1]; + c[1] = modFast128(mid[1] + y); + weight *= w[1][y+1]; + c[2] = modFast128(mid[2] + z); + weight *= w[2][z+1]; + result += weight * data[c[2]*n*n+c[1]*n+c[0]]; + } + return result; +} + +#endif + diff --git a/intern/smoke/intern/WTURBULENCE.cpp b/intern/smoke/intern/WTURBULENCE.cpp new file mode 100644 index 00000000000..83bec466c9f --- /dev/null +++ b/intern/smoke/intern/WTURBULENCE.cpp @@ -0,0 +1,1071 @@ +/** \file smoke/intern/WTURBULENCE.cpp + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +// WTURBULENCE handling +/////////////////////////////////////////////////////////////////////////////////// +// Parallelized turbulence even further. TNT matrix library functions +// rewritten to improve performance. +// - MiikaH +////////////////////////////////////////////////////////////////////// + +#include "WTURBULENCE.h" +#include "INTERPOLATE.h" +#include "IMAGE.h" +#include <MERSENNETWISTER.h> +#include "WAVELET_NOISE.h" +#include "FFT_NOISE.h" +#include "EIGENVALUE_HELPER.h" +#include "LU_HELPER.h" +#include "SPHERE.h" +#include <zlib.h> +#include <math.h> + +// needed to access static advection functions +#include "FLUID_3D.h" + +#if PARALLEL==1 +#include <omp.h> +#endif // PARALLEL + +// 2^ {-5/6} +static const float persistence = 0.56123f; + +////////////////////////////////////////////////////////////////////// +// constructor +////////////////////////////////////////////////////////////////////// +WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype) +{ + // if noise magnitude is below this threshold, its contribution + // is negilgible, so stop evaluating new octaves + _cullingThreshold = 1e-3; + + // factor by which to increase the simulation resolution + _amplify = amplify; + + // manually adjust the overall amount of turbulence + // DG - RNA-fied _strength = 2.; + + // add the corresponding octaves of noise + _octaves = (int)(log((float)_amplify) / log(2.0f) + 0.5); // XXX DEBUG/ TODO: int casting correct? - dg + + // noise resolution + _xResBig = _amplify * xResSm; + _yResBig = _amplify * yResSm; + _zResBig = _amplify * zResSm; + _resBig = Vec3Int(_xResBig, _yResBig, _zResBig); + _invResBig = Vec3(1./(float)_resBig[0], 1./(float)_resBig[1], 1./(float)_resBig[2]); + _slabSizeBig = _xResBig*_yResBig; + _totalCellsBig = _slabSizeBig * _zResBig; + + // original / small resolution + _xResSm = xResSm; + _yResSm = yResSm; + _zResSm = zResSm; + _resSm = Vec3Int(xResSm, yResSm, zResSm); + _invResSm = Vec3(1./(float)_resSm[0], 1./(float)_resSm[1], 1./(float)_resSm[2] ); + _slabSizeSm = _xResSm*_yResSm; + _totalCellsSm = _slabSizeSm * _zResSm; + + // allocate high resolution density field + _totalStepsBig = 0; + _densityBig = new float[_totalCellsBig]; + _densityBigOld = new float[_totalCellsBig]; + + for(int i = 0; i < _totalCellsBig; i++) { + _densityBig[i] = + _densityBigOld[i] = 0.; + } + + // allocate & init texture coordinates + _tcU = new float[_totalCellsSm]; + _tcV = new float[_totalCellsSm]; + _tcW = new float[_totalCellsSm]; + _tcTemp = new float[_totalCellsSm]; + + // map all + const float dx = 1./(float)(_resSm[0]); + const float dy = 1./(float)(_resSm[1]); + const float dz = 1./(float)(_resSm[2]); + int index = 0; + for (int z = 0; z < _zResSm; z++) + for (int y = 0; y < _yResSm; y++) + for (int x = 0; x < _xResSm; x++, index++) + { + _tcU[index] = x*dx; + _tcV[index] = y*dy; + _tcW[index] = z*dz; + _tcTemp[index] = 0.; + } + + // noise tiles + _noiseTile = new float[noiseTileSize * noiseTileSize * noiseTileSize]; + /* + std::string noiseTileFilename = std::string("noise.wavelets"); + generateTile_WAVELET(_noiseTile, noiseTileFilename); + */ + setNoise(noisetype); + /* + std::string noiseTileFilename = std::string("noise.fft"); + generatTile_FFT(_noiseTile, noiseTileFilename); + */ +} + +////////////////////////////////////////////////////////////////////// +// destructor +////////////////////////////////////////////////////////////////////// +WTURBULENCE::~WTURBULENCE() { + delete[] _densityBig; + delete[] _densityBigOld; + + delete[] _tcU; + delete[] _tcV; + delete[] _tcW; + delete[] _tcTemp; + + delete[] _noiseTile; +} + +////////////////////////////////////////////////////////////////////// +// Change noise type +// +// type (1<<0) = wavelet / 2 +// type (1<<1) = FFT / 4 +// type (1<<2) = curl / 8 +////////////////////////////////////////////////////////////////////// +void WTURBULENCE::setNoise(int type) +{ + if(type == (1<<1)) // FFT + { + // needs fft + #ifdef WITH_FFTW3 + std::string noiseTileFilename = std::string("noise.fft"); + generatTile_FFT(_noiseTile, noiseTileFilename); + #endif + } + else if(type == (1<<2)) // curl + { + // TODO: not supported yet + } + else // standard - wavelet + { + std::string noiseTileFilename = std::string("noise.wavelets"); + generateTile_WAVELET(_noiseTile, noiseTileFilename); + } +} + +// init direct access functions from blender +void WTURBULENCE::initBlenderRNA(float *strength) +{ + _strength = strength; +} + +////////////////////////////////////////////////////////////////////// +// Get the smallest valid x derivative +// +// Takes the one-sided finite difference in both directions and +// selects the smaller of the two +////////////////////////////////////////////////////////////////////// +static float minDx(int x, int y, int z, float* input, Vec3Int res) +{ + const int index = x + y * res[0] + z * res[0] * res[1]; + const int maxx = res[0]-2; + + // get grid values + float center = input[index]; + float left = (x <= 1) ? FLT_MAX : input[index - 1]; + float right = (x >= maxx) ? FLT_MAX : input[index + 1]; + + const float dx = res[0]; + + // get all the derivative estimates + float dLeft = (x <= 1) ? FLT_MAX : (center - left) * dx; + float dRight = (x >= maxx) ? FLT_MAX : (right - center) * dx; + float dCenter = (x <= 1 || x >= maxx) ? FLT_MAX : (right - left) * dx * 0.5f; + + // if it's on a boundary, only one estimate is valid + if (x <= 1) return dRight; + if (x >= maxx) return dLeft; + + // if it's not on a boundary, get the smallest one + float finalD; + finalD = (fabs(dCenter) < fabs(dRight)) ? dCenter : dRight; + finalD = (fabs(finalD) < fabs(dLeft)) ? finalD : dLeft; + + return finalD; +} + +////////////////////////////////////////////////////////////////////// +// get the smallest valid y derivative +// +// Takes the one-sided finite difference in both directions and +// selects the smaller of the two +////////////////////////////////////////////////////////////////////// +static float minDy(int x, int y, int z, float* input, Vec3Int res) +{ + const int index = x + y * res[0] + z * res[0] * res[1]; + const int maxy = res[1]-2; + + // get grid values + float center = input[index]; + float down = (y <= 1) ? FLT_MAX : input[index - res[0]]; + float up = (y >= maxy) ? FLT_MAX : input[index + res[0]]; + + const float dx = res[1]; // only for square domains + + // get all the derivative estimates + float dDown = (y <= 1) ? FLT_MAX : (center - down) * dx; + float dUp = (y >= maxy) ? FLT_MAX : (up - center) * dx; + float dCenter = (y <= 1 || y >= maxy) ? FLT_MAX : (up - down) * dx * 0.5f; + + // if it's on a boundary, only one estimate is valid + if (y <= 1) return dUp; + if (y >= maxy) return dDown; + + // if it's not on a boundary, get the smallest one + float finalD = (fabs(dCenter) < fabs(dUp)) ? dCenter : dUp; + finalD = (fabs(finalD) < fabs(dDown)) ? finalD : dDown; + + return finalD; +} + +////////////////////////////////////////////////////////////////////// +// get the smallest valid z derivative +// +// Takes the one-sided finite difference in both directions and +// selects the smaller of the two +////////////////////////////////////////////////////////////////////// +static float minDz(int x, int y, int z, float* input, Vec3Int res) +{ + const int slab = res[0]*res[1]; + const int index = x + y * res[0] + z * slab; + const int maxz = res[2]-2; + + // get grid values + float center = input[index]; + float front = (z <= 1) ? FLT_MAX : input[index - slab]; + float back = (z >= maxz) ? FLT_MAX : input[index + slab]; + + const float dx = res[2]; // only for square domains + + // get all the derivative estimates + float dfront = (z <= 1) ? FLT_MAX : (center - front) * dx; + float dback = (z >= maxz) ? FLT_MAX : (back - center) * dx; + float dCenter = (z <= 1 || z >= maxz) ? FLT_MAX : (back - front) * dx * 0.5f; + + // if it's on a boundary, only one estimate is valid + if (z <= 1) return dback; + if (z >= maxz) return dfront; + + // if it's not on a boundary, get the smallest one + float finalD = (fabs(dCenter) < fabs(dback)) ? dCenter : dback; + finalD = (fabs(finalD) < fabs(dfront)) ? finalD : dfront; + + return finalD; +} + +////////////////////////////////////////////////////////////////////// +// handle texture coordinates (advection, reset, eigenvalues), +// Beware -- uses big density maccormack as temporary arrays +////////////////////////////////////////////////////////////////////// +void WTURBULENCE::advectTextureCoordinates (float dtOrg, float* xvel, float* yvel, float* zvel, float *tempBig1, float *tempBig2) { + + // advection + SWAP_POINTERS(_tcTemp, _tcU); + FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]); + FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]); + FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]); + FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel, + _tcTemp, tempBig1, _resSm, 0 , _resSm[2]); + FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel, + _tcTemp, _tcU, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]); + + SWAP_POINTERS(_tcTemp, _tcV); + FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]); + FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]); + FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]); + FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel, + _tcTemp, tempBig1, _resSm, 0 , _resSm[2]); + FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel, + _tcTemp, _tcV, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]); + + SWAP_POINTERS(_tcTemp, _tcW); + FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]); + FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]); + FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]); + FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel, + _tcTemp, tempBig1, _resSm, 0 , _resSm[2]); + FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel, + _tcTemp, _tcW, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]); +} + +////////////////////////////////////////////////////////////////////// +// Compute the eigenvalues of the advected texture +////////////////////////////////////////////////////////////////////// +void WTURBULENCE::computeEigenvalues(float *_eigMin, float *_eigMax) { + // stats + float maxeig = -1.; + float mineig = 10.; + + // texture coordinate eigenvalues + for (int z = 1; z < _zResSm-1; z++) { + for (int y = 1; y < _yResSm-1; y++) + for (int x = 1; x < _xResSm-1; x++) + { + const int index = x+ y *_resSm[0] + z*_slabSizeSm; + + // compute jacobian + float jacobian[3][3] = { + { minDx(x, y, z, _tcU, _resSm), minDx(x, y, z, _tcV, _resSm), minDx(x, y, z, _tcW, _resSm) } , + { minDy(x, y, z, _tcU, _resSm), minDy(x, y, z, _tcV, _resSm), minDy(x, y, z, _tcW, _resSm) } , + { minDz(x, y, z, _tcU, _resSm), minDz(x, y, z, _tcV, _resSm), minDz(x, y, z, _tcW, _resSm) } + }; + + // ONLY compute the eigenvalues after checking that the matrix + // is nonsingular + sLU LU = computeLU(jacobian); + + if (isNonsingular(LU)) + { + // get the analytic eigenvalues, quite slow right now... + Vec3 eigenvalues = Vec3(1.); + computeEigenvalues3x3( &eigenvalues[0], jacobian); + _eigMax[index] = MAX3V(eigenvalues); + _eigMin[index] = MIN3V(eigenvalues); + maxeig = MAX(_eigMax[index],maxeig); + mineig = MIN(_eigMin[index],mineig); + } + else + { + _eigMax[index] = 10.0f; + _eigMin[index] = 0.1; + } + } + } +} + +////////////////////////////////////////////////////////////////////// +// advect & reset texture coordinates based on eigenvalues +////////////////////////////////////////////////////////////////////// +void WTURBULENCE::resetTextureCoordinates(float *_eigMin, float *_eigMax) +{ + // allowed deformation of the textures + const float limit = 2.f; + const float limitInv = 1./limit; + + // standard reset + int resets = 0; + const float dx = 1./(float)(_resSm[0]); + const float dy = 1./(float)(_resSm[1]); + const float dz = 1./(float)(_resSm[2]); + + for (int z = 1; z < _zResSm-1; z++) + for (int y = 1; y < _yResSm-1; y++) + for (int x = 1; x < _xResSm-1; x++) + { + const int index = x+ y *_resSm[0] + z*_slabSizeSm; + if (_eigMax[index] > limit || _eigMin[index] < limitInv) + { + _tcU[index] = (float)x * dx; + _tcV[index] = (float)y * dy; + _tcW[index] = (float)z * dz; + resets++; + } + } +} + +////////////////////////////////////////////////////////////////////// +// Compute the highest frequency component of the wavelet +// decomposition +////////////////////////////////////////////////////////////////////// +void WTURBULENCE::decomposeEnergy(float *_energy, float *_highFreqEnergy) +{ + // do the decomposition -- the goal here is to have + // the energy with the high frequency component stomped out + // stored in _tcTemp when it is done. _highFreqEnergy is only used + // as an additional temp array + + // downsample input + downsampleXNeumann(_highFreqEnergy, _energy, _xResSm, _yResSm, _zResSm); + downsampleYNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm); + downsampleZNeumann(_highFreqEnergy, _tcTemp, _xResSm, _yResSm, _zResSm); + + // upsample input + upsampleZNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm); + upsampleYNeumann(_highFreqEnergy, _tcTemp, _xResSm, _yResSm, _zResSm); + upsampleXNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm); + + // subtract the down and upsampled field from the original field -- + // what should be left over is solely the high frequency component + int index = 0; + for (int z = 0; z < _zResSm; z++) + for (int y = 0; y < _yResSm; y++) { + for (int x = 0; x < _xResSm; x++, index++) { + // brute force reset of boundaries + if(z >= _zResSm - 1 || x >= _xResSm - 1 || y >= _yResSm - 1 || z <= 0 || y <= 0 || x <= 0) + _highFreqEnergy[index] = 0.; + else + _highFreqEnergy[index] = _energy[index] - _tcTemp[index]; + } + } +} + +////////////////////////////////////////////////////////////////////// +// compute velocity from energies and march into obstacles +// for wavelet decomposition +////////////////////////////////////////////////////////////////////// +void WTURBULENCE::computeEnergy(float *_energy, float* xvel, float* yvel, float* zvel, unsigned char *origObstacles) +{ + unsigned char *obstacles = new unsigned char[_totalCellsSm]; + memcpy(obstacles, origObstacles, sizeof(unsigned char) * _totalCellsSm); + + // compute everywhere + for (int x = 0; x < _totalCellsSm; x++) + _energy[x] = 0.5f * (xvel[x] * xvel[x] + yvel[x] * yvel[x] + zvel[x] * zvel[x]); + + FLUID_3D::copyBorderX(_energy, _resSm, 0 , _resSm[2]); + FLUID_3D::copyBorderY(_energy, _resSm, 0 , _resSm[2]); + FLUID_3D::copyBorderZ(_energy, _resSm, 0 , _resSm[2]); + + // pseudo-march the values into the obstacles + // the wavelet upsampler only uses a 3x3 support neighborhood, so + // propagating the values in by 4 should be sufficient + int index; + + // iterate + for (int iter = 0; iter < 4; iter++) + { + index = _slabSizeSm + _xResSm + 1; + for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm) + for (int y = 1; y < _yResSm - 1; y++, index += 2) + for (int x = 1; x < _xResSm - 1; x++, index++) + if (obstacles[index] && obstacles[index] != RETIRED) + { + float sum = 0.0f; + int valid = 0; + + if (!obstacles[index + 1] || obstacles[index + 1] == RETIRED) + { + sum += _energy[index + 1]; + valid++; + } + if (!obstacles[index - 1] || obstacles[index - 1] == RETIRED) + { + sum += _energy[index - 1]; + valid++; + } + if (!obstacles[index + _xResSm] || obstacles[index + _xResSm] == RETIRED) + { + sum += _energy[index + _xResSm]; + valid++; + } + if (!obstacles[index - _xResSm] || obstacles[index - _xResSm] == RETIRED) + { + sum += _energy[index - _xResSm]; + valid++; + } + if (!obstacles[index + _slabSizeSm] || obstacles[index + _slabSizeSm] == RETIRED) + { + sum += _energy[index + _slabSizeSm]; + valid++; + } + if (!obstacles[index - _slabSizeSm] || obstacles[index - _slabSizeSm] == RETIRED) + { + sum += _energy[index - _slabSizeSm]; + valid++; + } + if (valid > 0) + { + _energy[index] = sum / (float)valid; + obstacles[index] = MARCHED; + } + } + index = _slabSizeSm + _xResSm + 1; + for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm) + for (int y = 1; y < _yResSm - 1; y++, index += 2) + for (int x = 1; x < _xResSm - 1; x++, index++) + if (obstacles[index] == MARCHED) + obstacles[index] = RETIRED; + } + index = _slabSizeSm + _xResSm + 1; + for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm) + for (int y = 1; y < _yResSm - 1; y++, index += 2) + for (int x = 1; x < _xResSm - 1; x++, index++) + if (obstacles[index]) + obstacles[index] = 1; // DG TODO ? animated obstacle flag? + + free(obstacles); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Evaluate derivatives +////////////////////////////////////////////////////////////////////////////////////////// +Vec3 WTURBULENCE::WVelocity(Vec3 orgPos) +{ + // arbitrarily offset evaluation points + const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2.0,0,0); + const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2.0,0); + const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2.0); + + const float f1y = WNoiseDy(p1, _noiseTile); + const float f1z = WNoiseDz(p1, _noiseTile); + + const float f2x = WNoiseDx(p2, _noiseTile); + const float f2z = WNoiseDz(p2, _noiseTile); + + const float f3x = WNoiseDx(p3, _noiseTile); + const float f3y = WNoiseDy(p3, _noiseTile); + + Vec3 ret = Vec3( + f3y - f2z, + f1z - f3x, + f2x - f1y ); + return ret; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Evaluate derivatives with Jacobian +////////////////////////////////////////////////////////////////////////////////////////// +Vec3 WTURBULENCE::WVelocityWithJacobian(Vec3 orgPos, float* xUnwarped, float* yUnwarped, float* zUnwarped) +{ + // arbitrarily offset evaluation points + const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2.0,0,0); + const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2.0,0); + const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2.0); + + Vec3 final; + final[0] = WNoiseDx(p1, _noiseTile); + final[1] = WNoiseDy(p1, _noiseTile); + final[2] = WNoiseDz(p1, _noiseTile); + // UNUSED const float f1x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2]; + const float f1y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2]; + const float f1z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2]; + + final[0] = WNoiseDx(p2, _noiseTile); + final[1] = WNoiseDy(p2, _noiseTile); + final[2] = WNoiseDz(p2, _noiseTile); + const float f2x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2]; + // UNUSED const float f2y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2]; + const float f2z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2]; + + final[0] = WNoiseDx(p3, _noiseTile); + final[1] = WNoiseDy(p3, _noiseTile); + final[2] = WNoiseDz(p3, _noiseTile); + const float f3x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2]; + const float f3y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2]; + // UNUSED const float f3z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2]; + + Vec3 ret = Vec3( + f3y - f2z, + f1z - f3x, + f2x - f1y ); + return ret; +} + + +////////////////////////////////////////////////////////////////////// +// perform an actual noise advection step +////////////////////////////////////////////////////////////////////// +/*void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles) +{ + // enlarge timestep to match grid + const float dt = dtOrg * _amplify; + const float invAmp = 1.0f / _amplify; + float *tempBig1 = new float[_totalCellsBig]; + float *tempBig2 = new float[_totalCellsBig]; + float *bigUx = new float[_totalCellsBig]; + float *bigUy = new float[_totalCellsBig]; + float *bigUz = new float[_totalCellsBig]; + float *_energy = new float[_totalCellsSm]; + float *highFreqEnergy = new float[_totalCellsSm]; + float *eigMin = new float[_totalCellsSm]; + float *eigMax = new float[_totalCellsSm]; + + memset(tempBig1, 0, sizeof(float)*_totalCellsBig); + memset(tempBig2, 0, sizeof(float)*_totalCellsBig); + memset(highFreqEnergy, 0, sizeof(float)*_totalCellsSm); + memset(eigMin, 0, sizeof(float)*_totalCellsSm); + memset(eigMax, 0, sizeof(float)*_totalCellsSm); + + // prepare textures + advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempBig1, tempBig2); + + // compute eigenvalues of the texture coordinates + computeEigenvalues(eigMin, eigMax); + + // do wavelet decomposition of energy + computeEnergy(_energy, xvel, yvel, zvel, obstacles); + decomposeEnergy(_energy, highFreqEnergy); + + // zero out coefficients inside of the obstacle + for (int x = 0; x < _totalCellsSm; x++) + if (obstacles[x]) _energy[x] = 0.f; + + float maxVelocity = 0.; + for (int z = 1; z < _zResBig - 1; z++) + for (int y = 1; y < _yResBig - 1; y++) + for (int x = 1; x < _xResBig - 1; x++) + { + // get unit position for both fine and coarse grid + const Vec3 pos = Vec3(x,y,z); + const Vec3 posSm = pos * invAmp; + + // get grid index for both fine and coarse grid + const int index = x + y *_xResBig + z *_slabSizeBig; + const int indexSmall = (int)posSm[0] + (int)posSm[1] * _xResSm + (int)posSm[2] * _slabSizeSm; + + // get a linearly interpolated velocity and texcoords + // from the coarse grid + Vec3 vel = INTERPOLATE::lerp3dVec( xvel,yvel,zvel, + posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm); + Vec3 uvw = INTERPOLATE::lerp3dVec( _tcU,_tcV,_tcW, + posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm); + + // multiply the texture coordinate by _resSm so that turbulence + // synthesis begins at the first octave that the coarse grid + // cannot capture + Vec3 texCoord = Vec3(uvw[0] * _resSm[0], + uvw[1] * _resSm[1], + uvw[2] * _resSm[2]); + + // retrieve wavelet energy at highest frequency + float energy = INTERPOLATE::lerp3d( + highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm); + + // base amplitude for octave 0 + float coefficient = sqrtf(2.0f * fabs(energy)); + const float amplitude = *_strength * fabs(0.5 * coefficient) * persistence; + + // add noise to velocity, but only if the turbulence is + // sufficiently undeformed, and the energy is large enough + // to make a difference + const bool addNoise = eigMax[indexSmall] < 2. && + eigMin[indexSmall] > 0.5; + if (addNoise && amplitude > _cullingThreshold) { + // base amplitude for octave 0 + float amplitudeScaled = amplitude; + + for (int octave = 0; octave < _octaves; octave++) + { + // multiply the vector noise times the maximum allowed + // noise amplitude at this octave, and add it to the total + vel += WVelocity(texCoord) * amplitudeScaled; + + // scale coefficient for next octave + amplitudeScaled *= persistence; + texCoord *= 2.0f; + } + } + + // Store velocity + turbulence in big grid for maccormack step + // + // If you wanted to save memory, you would instead perform a + // semi-Lagrangian backtrace for the current grid cell here. Then + // you could just throw the velocity away. + bigUx[index] = vel[0]; + bigUy[index] = vel[1]; + bigUz[index] = vel[2]; + + // compute the velocity magnitude for substepping later + const float velMag = bigUx[index] * bigUx[index] + + bigUy[index] * bigUy[index] + + bigUz[index] * bigUz[index]; + if (velMag > maxVelocity) maxVelocity = velMag; + + // zero out velocity inside obstacles + float obsCheck = INTERPOLATE::lerp3dToFloat( + obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm); + if (obsCheck > 0.95) + bigUx[index] = bigUy[index] = bigUz[index] = 0.; + } + + // prepare density for an advection + SWAP_POINTERS(_densityBig, _densityBigOld); + + // based on the maximum velocity present, see if we need to substep, + // but cap the maximum number of substeps to 5 + const int maxSubSteps = 5; + maxVelocity = sqrt(maxVelocity) * dt; + int totalSubsteps = (int)(maxVelocity / (float)maxSubSteps); + totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; + totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps; + const float dtSubdiv = dt / (float)totalSubsteps; + + // set boundaries of big velocity grid + FLUID_3D::setZeroX(bigUx, _resBig, 0, _resBig[2]); + FLUID_3D::setZeroY(bigUy, _resBig, 0, _resBig[2]); + FLUID_3D::setZeroZ(bigUz, _resBig, 0, _resBig[2]); + + // do the MacCormack advection, with substepping if necessary + for(int substep = 0; substep < totalSubsteps; substep++) + { + FLUID_3D::advectFieldMacCormack(dtSubdiv, bigUx, bigUy, bigUz, + _densityBigOld, _densityBig, tempBig1, tempBig2, _resBig, NULL); + + if (substep < totalSubsteps - 1) + SWAP_POINTERS(_densityBig, _densityBigOld); + } // substep + + // wipe the density borders + FLUID_3D::setZeroBorder(_densityBig, _resBig, 0, _resBig[2]); + + // reset texture coordinates now in preparation for next timestep + // Shouldn't do this before generating the noise because then the + // eigenvalues stored do not reflect the underlying texture coordinates + resetTextureCoordinates(eigMin, eigMax); + + delete[] tempBig1; + delete[] tempBig2; + delete[] bigUx; + delete[] bigUy; + delete[] bigUz; + delete[] _energy; + delete[] highFreqEnergy; + + delete[] eigMin; + delete[] eigMax; + + + _totalStepsBig++; +}*/ + +//struct + +////////////////////////////////////////////////////////////////////// +// perform the full turbulence algorithm, including OpenMP +// if available +////////////////////////////////////////////////////////////////////// +void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles) +{ + // enlarge timestep to match grid + const float dt = dtOrg * _amplify; + const float invAmp = 1.0f / _amplify; + float *tempBig1 = (float *)calloc(_totalCellsBig, sizeof(float)); + float *tempBig2 = (float *)calloc(_totalCellsBig, sizeof(float)); + float *bigUx = (float *)calloc(_totalCellsBig, sizeof(float)); + float *bigUy = (float *)calloc(_totalCellsBig, sizeof(float)); + float *bigUz = (float *)calloc(_totalCellsBig, sizeof(float)); + float *_energy = (float *)calloc(_totalCellsSm, sizeof(float)); + float *highFreqEnergy = (float *)calloc(_totalCellsSm, sizeof(float)); + float *eigMin = (float *)calloc(_totalCellsSm, sizeof(float)); + float *eigMax = (float *)calloc(_totalCellsSm, sizeof(float)); + + memset(_tcTemp, 0, sizeof(float)*_totalCellsSm); + + + // prepare textures + advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempBig1, tempBig2); + + // do wavelet decomposition of energy + computeEnergy(_energy, xvel, yvel, zvel, obstacles); + + for (int x = 0; x < _totalCellsSm; x++) + if (obstacles[x]) _energy[x] = 0.f; + + decomposeEnergy(_energy, highFreqEnergy); + + // zero out coefficients inside of the obstacle + for (int x = 0; x < _totalCellsSm; x++) + if (obstacles[x]) highFreqEnergy[x] = 0.f; + + Vec3Int ressm(_xResSm, _yResSm, _zResSm); + FLUID_3D::setNeumannX(highFreqEnergy, ressm, 0 , ressm[2]); + FLUID_3D::setNeumannY(highFreqEnergy, ressm, 0 , ressm[2]); + FLUID_3D::setNeumannZ(highFreqEnergy, ressm, 0 , ressm[2]); + + + int threadval = 1; +#if PARALLEL==1 + threadval = omp_get_max_threads(); +#endif + + + // parallel region setup + // Uses omp_get_max_trheads to get number of required cells. + float* maxVelMagThreads = new float[threadval]; + + for (int i=0; i<threadval; i++) maxVelMagThreads[i] = -1.0f; + +#if PARALLEL==1 + +#pragma omp parallel +#endif + { float maxVelMag1 = 0.; +#if PARALLEL==1 + const int id = omp_get_thread_num(); /*, num = omp_get_num_threads(); */ +#endif + + // vector noise main loop +#if PARALLEL==1 +#pragma omp for schedule(static,1) +#endif + for (int zSmall = 0; zSmall < _zResSm; zSmall++) + { + for (int ySmall = 0; ySmall < _yResSm; ySmall++) + for (int xSmall = 0; xSmall < _xResSm; xSmall++) + { + const int indexSmall = xSmall + ySmall * _xResSm + zSmall * _slabSizeSm; + + // compute jacobian + float jacobian[3][3] = { + { minDx(xSmall, ySmall, zSmall, _tcU, _resSm), minDx(xSmall, ySmall, zSmall, _tcV, _resSm), minDx(xSmall, ySmall, zSmall, _tcW, _resSm) } , + { minDy(xSmall, ySmall, zSmall, _tcU, _resSm), minDy(xSmall, ySmall, zSmall, _tcV, _resSm), minDy(xSmall, ySmall, zSmall, _tcW, _resSm) } , + { minDz(xSmall, ySmall, zSmall, _tcU, _resSm), minDz(xSmall, ySmall, zSmall, _tcV, _resSm), minDz(xSmall, ySmall, zSmall, _tcW, _resSm) } + }; + + // get LU factorization of texture jacobian and apply + // it to unit vectors + sLU LU = computeLU(jacobian); + float xUnwarped[3], yUnwarped[3], zUnwarped[3]; + float xWarped[3], yWarped[3], zWarped[3]; + bool nonSingular = isNonsingular(LU); + + xUnwarped[0] = 1.0f; xUnwarped[1] = 0.0f; xUnwarped[2] = 0.0f; + yUnwarped[0] = 0.0f; yUnwarped[1] = 1.0f; yUnwarped[2] = 0.0f; + zUnwarped[0] = 0.0f; zUnwarped[1] = 0.0f; zUnwarped[2] = 1.0f; + + xWarped[0] = 1.0f; xWarped[1] = 0.0f; xWarped[2] = 0.0f; + yWarped[0] = 0.0f; yWarped[1] = 1.0f; yWarped[2] = 0.0f; + zWarped[0] = 0.0f; zWarped[1] = 0.0f; zWarped[2] = 1.0f; + +#if 0 + // UNUSED + float eigMax = 10.0f; + float eigMin = 0.1f; +#endif + if (nonSingular) + { + solveLU3x3(LU, xUnwarped, xWarped); + solveLU3x3(LU, yUnwarped, yWarped); + solveLU3x3(LU, zUnwarped, zWarped); + + // compute the eigenvalues while we have the Jacobian available + Vec3 eigenvalues = Vec3(1.); + computeEigenvalues3x3( &eigenvalues[0], jacobian); + eigMax[indexSmall] = MAX3V(eigenvalues); + eigMin[indexSmall] = MIN3V(eigenvalues); + } + + // make sure to skip one on the beginning and end + int xStart = (xSmall == 0) ? 1 : 0; + int xEnd = (xSmall == _xResSm - 1) ? _amplify - 1 : _amplify; + int yStart = (ySmall == 0) ? 1 : 0; + int yEnd = (ySmall == _yResSm - 1) ? _amplify - 1 : _amplify; + int zStart = (zSmall == 0) ? 1 : 0; + int zEnd = (zSmall == _zResSm - 1) ? _amplify - 1 : _amplify; + + for (int zBig = zStart; zBig < zEnd; zBig++) + for (int yBig = yStart; yBig < yEnd; yBig++) + for (int xBig = xStart; xBig < xEnd; xBig++) + { + const int x = xSmall * _amplify + xBig; + const int y = ySmall * _amplify + yBig; + const int z = zSmall * _amplify + zBig; + + // get unit position for both fine and coarse grid + const Vec3 pos = Vec3(x,y,z); + const Vec3 posSm = pos * invAmp; + + // get grid index for both fine and coarse grid + const int index = x + y *_xResBig + z *_slabSizeBig; + + // get a linearly interpolated velocity and texcoords + // from the coarse grid + Vec3 vel = INTERPOLATE::lerp3dVec( xvel,yvel,zvel, + posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm); + Vec3 uvw = INTERPOLATE::lerp3dVec( _tcU,_tcV,_tcW, + posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm); + + // multiply the texture coordinate by _resSm so that turbulence + // synthesis begins at the first octave that the coarse grid + // cannot capture + Vec3 texCoord = Vec3(uvw[0] * _resSm[0], + uvw[1] * _resSm[1], + uvw[2] * _resSm[2]); + + // retrieve wavelet energy at highest frequency + float energy = INTERPOLATE::lerp3d( + highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm); + + // base amplitude for octave 0 + float coefficient = sqrtf(2.0f * fabs(energy)); + const float amplitude = *_strength * fabs(0.5 * coefficient) * persistence; + + // add noise to velocity, but only if the turbulence is + // sufficiently undeformed, and the energy is large enough + // to make a difference + const bool addNoise = eigMax[indexSmall] < 2. && + eigMin[indexSmall] > 0.5; + if (addNoise && amplitude > _cullingThreshold) { + // base amplitude for octave 0 + float amplitudeScaled = amplitude; + + for (int octave = 0; octave < _octaves; octave++) + { + // multiply the vector noise times the maximum allowed + // noise amplitude at this octave, and add it to the total + vel += WVelocityWithJacobian(texCoord, &xUnwarped[0], &yUnwarped[0], &zUnwarped[0]) * amplitudeScaled; + + // scale coefficient for next octave + amplitudeScaled *= persistence; + texCoord *= 2.0f; + } + } + + // Store velocity + turbulence in big grid for maccormack step + // + // If you wanted to save memory, you would instead perform a + // semi-Lagrangian backtrace for the current grid cell here. Then + // you could just throw the velocity away. + bigUx[index] = vel[0]; + bigUy[index] = vel[1]; + bigUz[index] = vel[2]; + + // compute the velocity magnitude for substepping later + const float velMag = bigUx[index] * bigUx[index] + + bigUy[index] * bigUy[index] + + bigUz[index] * bigUz[index]; + if (velMag > maxVelMag1) maxVelMag1 = velMag; + + // zero out velocity inside obstacles + float obsCheck = INTERPOLATE::lerp3dToFloat( + obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm); + if (obsCheck > 0.95) + bigUx[index] = bigUy[index] = bigUz[index] = 0.; + } // xyz*/ + +#if PARALLEL==1 + maxVelMagThreads[id] = maxVelMag1; +#else + maxVelMagThreads[0] = maxVelMag1; +#endif + } + } + } // omp + + // compute maximum over threads + float maxVelMag = maxVelMagThreads[0]; +#if PARALLEL==1 + for (int i = 1; i < threadval; i++) + if (maxVelMag < maxVelMagThreads[i]) + maxVelMag = maxVelMagThreads[i]; +#endif + delete [] maxVelMagThreads; + + + // prepare density for an advection + SWAP_POINTERS(_densityBig, _densityBigOld); + + // based on the maximum velocity present, see if we need to substep, + // but cap the maximum number of substeps to 5 + const int maxSubSteps = 25; + const int maxVel = 5; + maxVelMag = sqrt(maxVelMag) * dt; + int totalSubsteps = (int)(maxVelMag / (float)maxVel); + totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; + // printf("totalSubsteps: %d\n", totalSubsteps); + totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps; + const float dtSubdiv = dt / (float)totalSubsteps; + + // set boundaries of big velocity grid + FLUID_3D::setZeroX(bigUx, _resBig, 0 , _resBig[2]); + FLUID_3D::setZeroY(bigUy, _resBig, 0 , _resBig[2]); + FLUID_3D::setZeroZ(bigUz, _resBig, 0 , _resBig[2]); + +#if PARALLEL==1 + int stepParts = threadval*2; // Dividing parallelized sections into numOfThreads * 2 sections + float partSize = (float)_zResBig/stepParts; // Size of one part; + + if (partSize < 4) {stepParts = threadval; // If the slice gets too low (might actually slow things down, change it to larger + partSize = (float)_zResBig/stepParts;} + if (partSize < 4) {stepParts = (int)(ceil((float)_zResBig/4.0f)); // If it's still too low (only possible on future systems with +24 cores), change it to 4 + partSize = (float)_zResBig/stepParts;} +#else + int zBegin=0; + int zEnd=_resBig[2]; +#endif + + // do the MacCormack advection, with substepping if necessary + for(int substep = 0; substep < totalSubsteps; substep++) + { + +#if PARALLEL==1 + #pragma omp parallel + { + + #pragma omp for schedule(static,1) + for (int i=0; i<stepParts; i++) + { + int zBegin = (int)((float)i*partSize + 0.5f); + int zEnd = (int)((float)(i+1)*partSize + 0.5f); +#endif + FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz, + _densityBigOld, tempBig1, _resBig, zBegin, zEnd); +#if PARALLEL==1 + } + + #pragma omp barrier + + #pragma omp for schedule(static,1) + for (int i=0; i<stepParts; i++) + { + int zBegin = (int)((float)i*partSize + 0.5f); + int zEnd = (int)((float)(i+1)*partSize + 0.5f); +#endif + FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz, + _densityBigOld, _densityBig, tempBig1, tempBig2, _resBig, NULL, zBegin, zEnd); +#if PARALLEL==1 + } + } +#endif + + if (substep < totalSubsteps - 1) + SWAP_POINTERS(_densityBig, _densityBigOld); + } // substep + + free(tempBig1); + free(tempBig2); + free(bigUx); + free(bigUy); + free(bigUz); + free(_energy); + free(highFreqEnergy); + + // wipe the density borders + FLUID_3D::setZeroBorder(_densityBig, _resBig, 0 , _resBig[2]); + + // reset texture coordinates now in preparation for next timestep + // Shouldn't do this before generating the noise because then the + // eigenvalues stored do not reflect the underlying texture coordinates + resetTextureCoordinates(eigMin, eigMax); + + free(eigMin); + free(eigMax); + + // output files + // string prefix = string("./amplified.preview/density_bigxy_"); + // FLUID_3D::writeImageSliceXY(_densityBig, _resBig, _resBig[2]/2, prefix, _totalStepsBig, 1.0f); + //string df3prefix = string("./df3/density_big_"); + //IMAGE::dumpDF3(_totalStepsBig, df3prefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]); + // string pbrtPrefix = string("./pbrt/density_big_"); + // IMAGE::dumpPBRT(_totalStepsBig, pbrtPrefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]); + + _totalStepsBig++; +} diff --git a/intern/smoke/intern/WTURBULENCE.h b/intern/smoke/intern/WTURBULENCE.h new file mode 100644 index 00000000000..f31ca100fdf --- /dev/null +++ b/intern/smoke/intern/WTURBULENCE.h @@ -0,0 +1,133 @@ +/** \file smoke/intern/WTURBULENCE.h + * \ingroup smoke + */ +////////////////////////////////////////////////////////////////////// +// This file is part of Wavelet Turbulence. +// +// Wavelet Turbulence is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Wavelet Turbulence is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright 2008 Theodore Kim and Nils Thuerey +// +// WTURBULENCE handling +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef WTURBULENCE_H +#define WTURBULENCE_H + +#include "VEC3.h" +using namespace BasicVector; +class SIMPLE_PARSER; + +/////////////////////////////////////////////////////////////////////////////// +/// Main WTURBULENCE class, stores large density array etc. +/////////////////////////////////////////////////////////////////////////////// +class WTURBULENCE +{ + public: + // both config files can be NULL, altCfg might override values from noiseCfg + WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype); + + /// destructor + virtual ~WTURBULENCE(); + + void setNoise(int type); + void initBlenderRNA(float *strength); + + // step more readable version -- no rotation correction + void stepTurbulenceReadable(float dt, float* xvel, float* yvel, float* zvel, unsigned char *obstacles); + + // step more complete version -- include rotation correction + // and use OpenMP if available + void stepTurbulenceFull(float dt, float* xvel, float* yvel, float* zvel, unsigned char *obstacles); + + // texcoord functions + void advectTextureCoordinates(float dtOrg, float* xvel, float* yvel, float* zvel, float *tempBig1, float *tempBig2); + void resetTextureCoordinates(float *_eigMin, float *_eigMax); + + void computeEnergy(float *energy, float* xvel, float* yvel, float* zvel, unsigned char *obstacles); + + // evaluate wavelet noise function + Vec3 WVelocity(Vec3 p); + Vec3 WVelocityWithJacobian(Vec3 p, float* xUnwarped, float* yUnwarped, float* zUnwarped); + + // access functions + inline float* getDensityBig() { return _densityBig; } + inline float* getArrayTcU() { return _tcU; } + inline float* getArrayTcV() { return _tcV; } + inline float* getArrayTcW() { return _tcW; } + + inline Vec3Int getResSm() { return _resSm; } // small resolution + inline Vec3Int getResBig() { return _resBig; } + inline int getOctaves() { return _octaves; } + + // is accessed on through rna gui + float *_strength; + + // protected: + // enlargement factor from original velocity field / simulation + // _Big = _amplify * _Sm + int _amplify; + int _octaves; + + // noise settings + float _cullingThreshold; + // float _noiseStrength; + // float _noiseSizeScale; + // bool _uvwAdvection; + // bool _uvwReset; + // float _noiseTimeanimSpeed; + // int _dumpInterval; + // nt _noiseControlType; + // debug, scale density for projections output images + // float _outputScale; + + // noise resolution + int _xResBig; + int _yResBig; + int _zResBig; + Vec3Int _resBig; + Vec3 _invResBig; + int _totalCellsBig; + int _slabSizeBig; + // original / small resolution + int _xResSm; + int _yResSm; + int _zResSm; + Vec3Int _resSm; + Vec3 _invResSm; + int _totalCellsSm; + int _slabSizeSm; + + float* _densityBig; + float* _densityBigOld; + + // texture coordinates for noise + float* _tcU; + float* _tcV; + float* _tcW; + float* _tcTemp; + + // noise data + float* _noiseTile; + //float* _noiseTileExt; + + // step counter + int _totalStepsBig; + + void computeEigenvalues(float *_eigMin, float *_eigMax); + void decomposeEnergy(float *energy, float *_highFreqEnergy); +}; + +#endif // WTURBULENCE_H + diff --git a/intern/smoke/intern/smoke_API.cpp b/intern/smoke/intern/smoke_API.cpp index 0d2e6a81094..01753a25d2d 100644 --- a/intern/smoke/intern/smoke_API.cpp +++ b/intern/smoke/intern/smoke_API.cpp @@ -28,37 +28,36 @@ * \ingroup smoke */ + +#include "FLUID_3D.h" +#include "WTURBULENCE.h" + #include <stdio.h> #include <stdlib.h> #include <math.h> -#include "smoke.h" - -// #define FLUID_3D void -#define WTURBULENCE void - -using namespace DDF; - // y in smoke is z in blender extern "C" FLUID_3D *smoke_init(int *res, float *p0, float dtdef) { - printf("-------------------- SMOKE CREATE --------------------------\n"); - FLUID_3D *fluid = new FLUID_3D(res); - printf("-------------------- SMOKE INIT --------------------------\n"); - if(!fluid->_init) - fluid->init(); + // smoke lib uses y as top-bottom/vertical axis where blender uses z + FLUID_3D *fluid = new FLUID_3D(res, p0, dtdef); + + // printf("xres: %d, yres: %d, zres: %d\n", res[0], res[1], res[2]); + return fluid; } extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype) { - return NULL; + // initialize wavelet turbulence + if(amplify) + return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype); + else + return NULL; } extern "C" void smoke_free(FLUID_3D *fluid) { - printf("-------------------- SMOKE DEL ---------------------------\n"); - fluid->del(); delete fluid; fluid = NULL; } @@ -72,7 +71,7 @@ extern "C" void smoke_turbulence_free(WTURBULENCE *wt) extern "C" size_t smoke_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */) { // // const int index = x + y * smd->res[0] + z * smd->res[0]*smd->res[1]; - return x + y * max_x + z * max_x*max_y; // (z*mSizeY+y)*mSizeX+x + return x + y * max_x + z * max_x*max_y; } extern "C" size_t smoke_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */) @@ -82,33 +81,103 @@ extern "C" size_t smoke_get_index2d(int x, int max_x, int y /*, int max_y, int z extern "C" void smoke_step(FLUID_3D *fluid, float dtSubdiv) { - printf("-------------------- SMOKE STEP --------------------------\n"); - fluid->step(); + fluid->step(dtSubdiv); } extern "C" void smoke_turbulence_step(WTURBULENCE *wt, FLUID_3D *fluid) { - + wt->stepTurbulenceFull(fluid->_dt/fluid->_dx, fluid->_xVelocity, fluid->_yVelocity, fluid->_zVelocity, fluid->_obstacles); } extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli) { - + fluid->initBlenderRNA(alpha, beta, dt_factor, vorticity, border_colli); } extern "C" void smoke_dissolve(FLUID_3D *fluid, int speed, int log) { - + float *density = fluid->_density; + //float *densityOld = fluid->_densityOld; + float *heat = fluid->_heat; + + if(log) + { + /* max density/speed = dydx */ + float dydx = 1.0 / (float)speed; + size_t size= fluid->_xRes * fluid->_yRes * fluid->_zRes; + + for(size_t i = 0; i < size; i++) + { + density[i] *= (1.0 - dydx); + + if(density[i] < 0.0f) + density[i] = 0.0f; + + heat[i] *= (1.0 - dydx); + + /*if(heat[i] < 0.0f) + heat[i] = 0.0f;*/ + } + } + else // linear falloff + { + /* max density/speed = dydx */ + float dydx = 1.0 / (float)speed; + size_t size= fluid->_xRes * fluid->_yRes * fluid->_zRes; + + for(size_t i = 0; i < size; i++) + { + density[i] -= dydx; + + if(density[i] < 0.0f) + density[i] = 0.0f; + + if(abs(heat[i]) < dydx) heat[i] = 0.0f; + else if (heat[i]>0.0f) heat[i] -= dydx; + else if (heat[i]<0.0f) heat[i] += dydx; + + } + } } extern "C" void smoke_dissolve_wavelet(WTURBULENCE *wt, int speed, int log) { - + float *density = wt->getDensityBig(); + Vec3Int r = wt->getResBig(); + + if(log) + { + /* max density/speed = dydx */ + float dydx = 1.0 / (float)speed; + size_t size= r[0] * r[1] * r[2]; + + for(size_t i = 0; i < size; i++) + { + density[i] *= (1.0 - dydx); + + if(density[i] < 0.0f) + density[i] = 0.0f; + } + } + else // linear falloff + { + /* max density/speed = dydx */ + float dydx = 1.0 / (float)speed; + size_t size= r[0] * r[1] * r[2]; + + for(size_t i = 0; i < size; i++) + { + density[i] -= dydx; + + if(density[i] < 0.0f) + density[i] = 0.0f; + } + } } extern "C" void smoke_initWaveletBlenderRNA(WTURBULENCE *wt, float *strength) { - + wt->initBlenderRNA(strength); } template < class T > inline T ABS( T a ) @@ -118,83 +187,113 @@ template < class T > inline T ABS( T a ) extern "C" void smoke_export(FLUID_3D *fluid, float *dt, float *dx, float **dens, float **densold, float **heat, float **heatold, float **vx, float **vy, float **vz, float **vxold, float **vyold, float **vzold, unsigned char **obstacles) { - + *dens = fluid->_density; + *densold = fluid->_densityOld; + *heat = fluid->_heat; + *heatold = fluid->_heatOld; + *vx = fluid->_xVelocity; + *vy = fluid->_yVelocity; + *vz = fluid->_zVelocity; + *vxold = fluid->_xVelocityOld; + *vyold = fluid->_yVelocityOld; + *vzold = fluid->_zVelocityOld; + *obstacles = fluid->_obstacles; + dt = &(fluid->_dt); + dx = &(fluid->_dx); + } extern "C" void smoke_turbulence_export(WTURBULENCE *wt, float **dens, float **densold, float **tcu, float **tcv, float **tcw) { - + if(!wt) + return; + + *dens = wt->_densityBig; + *densold = wt->_densityBigOld; + *tcu = wt->_tcU; + *tcv = wt->_tcV; + *tcw = wt->_tcW; +} + +extern "C" float *smoke_get_pressure(FLUID_3D *fluid) +{ + return fluid->_pressure; } extern "C" float *smoke_get_density(FLUID_3D *fluid) { - if(fluid->_density) - return fluid->_density->data(); - else - return NULL; + return fluid->_density; } extern "C" float *smoke_get_heat(FLUID_3D *fluid) { - return NULL; + return fluid->_heat; } extern "C" float *smoke_get_velocity_x(FLUID_3D *fluid) { - return NULL; + return fluid->_xVelocity; } extern "C" float *smoke_get_velocity_y(FLUID_3D *fluid) { - return NULL; + return fluid->_yVelocity; } extern "C" float *smoke_get_velocity_z(FLUID_3D *fluid) { - return NULL; + return fluid->_zVelocity; } extern "C" float *smoke_get_force_x(FLUID_3D *fluid) { - return NULL; + return fluid->_xForce; } extern "C" float *smoke_get_force_y(FLUID_3D *fluid) { - return NULL; + return fluid->_yForce; } extern "C" float *smoke_get_force_z(FLUID_3D *fluid) { - return NULL; + return fluid->_zForce; } extern "C" float *smoke_turbulence_get_density(WTURBULENCE *wt) { - return NULL; + return wt ? wt->getDensityBig() : NULL; } extern "C" void smoke_turbulence_get_res(WTURBULENCE *wt, int *res) { - + if(wt) + { + Vec3Int r = wt->getResBig(); + res[0] = r[0]; + res[1] = r[1]; + res[2] = r[2]; + } } extern "C" unsigned char *smoke_get_obstacle(FLUID_3D *fluid) { - return NULL; + return fluid->_obstacles; } extern "C" void smoke_get_ob_velocity(FLUID_3D *fluid, float **x, float **y, float **z) { - + *x = fluid->_xVelocityOb; + *y = fluid->_yVelocityOb; + *z = fluid->_zVelocityOb; } extern "C" unsigned char *smoke_get_obstacle_anim(FLUID_3D *fluid) { - return NULL; + return fluid->_obstaclesAnim; } extern "C" void smoke_turbulence_set_noise(WTURBULENCE *wt, int type) { - + wt->setNoise(type); } diff --git a/intern/smoke/intern/source/advectionplugins.cpp b/intern/smoke/intern/source/advectionplugins.cpp deleted file mode 100644 index 5ad292352f1..00000000000 --- a/intern/smoke/intern/source/advectionplugins.cpp +++ /dev/null @@ -1,915 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Advection plugins: - * semi lagrange, mac cormack - * - *****************************************************************************/ - -#include "fluidsolver.h" -#include "solverplugin.h" -#include "paramset.h" - -// safety boundary for semi lagrange advection step -#define SLADVBOUND 2 - -namespace DDF { - -//***************************************************************************** -// velocity access helpers - -class getVelCentered { - private: - getVelCentered() {}; - ~getVelCentered() {}; - public: - static inline Vec3 getVelocity(GridAccessor<Vec3,1> &gaVel, int i,int j, int k) { - Vec3 v = Vec3( - 0.5*( gaVel(i ,j ,k)[0] + gaVel(i+1,j ,k )[0] ), - 0.5*( gaVel(i ,j ,k)[1] + gaVel(i ,j+1,k )[1] ), - 0.5*( gaVel(i ,j ,k)[2] + gaVel(i ,j ,k+1)[2] ) ); - if(DDF_DIMENSION==2) { v[2] = 0.; } - return v; - } -}; // getVelCentered - -class getVelX { - private: - getVelX() {}; - ~getVelX() {}; - public: - static inline Vec3 getVelocity(GridAccessor<Vec3,1> &gaVel, int i,int j, int k) { - const Real u = gaVel(i,j,k)[0]; - const Real v = 0.25*( - gaVel(i ,j ,k)[1] + gaVel(i-1,j ,k)[1] + - gaVel(i ,j+1,k)[1] + gaVel(i-1,j+1,k)[1] ); -# if DDF_DIMENSION==3 - const Real w = 0.25*( - gaVel(i ,j,k )[2] + gaVel(i-1,j,k )[2] + - gaVel(i ,j,k+1)[2] + gaVel(i-1,j,k+1)[2] ); -# else - const Real w = 0.; -# endif - return Vec3(u,v,w); - } -}; // getVelX - -class getVelY { - private: - getVelY() {}; - ~getVelY() {}; - public: - static inline Vec3 getVelocity(GridAccessor<Vec3,1> &gaVel, int i,int j, int k) { - const Real u = 0.25*( - gaVel(i ,j ,k)[0] + gaVel(i ,j-1,k)[0] + - gaVel(i+1,j ,k)[0] + gaVel(i+1,j-1,k)[0] ); - const Real v = gaVel(i,j,k)[1]; -# if DDF_DIMENSION==3 - const Real w = 0.25*( - gaVel(i,j ,k )[2] + gaVel(i,j-1,k )[2] + - gaVel(i,j ,k+1)[2] + gaVel(i,j-1,k+1)[2] ); -# else - const Real w = 0.; -# endif - return Vec3(u,v,w); - } -}; // getVelY - -class getVelZ { - private: - getVelZ() {}; - ~getVelZ() {}; - public: - static inline Vec3 getVelocity(GridAccessor<Vec3,1> &gaVel, int i,int j, int k) { - const Real u = 0.25*( - gaVel(i ,j,k )[0] + gaVel(i ,j,k-1)[0] + - gaVel(i+1,j,k )[0] + gaVel(i+1,j,k-1)[0] ); - const Real v = 0.25*( - gaVel(i,j ,k )[1] + gaVel(i,j ,k-1)[1] + - gaVel(i,j+1,k )[1] + gaVel(i,j+1,k-1)[1] ); - const Real w = gaVel(i,j,k)[2]; - return Vec3(u,v,w); - } -}; // getVelZ - - -//***************************************************************************** -// semi lagrange advection -class fsSlAdvection : public GridOpBaseFlagbord<SLADVBOUND> { - public: - fsSlAdvection(FlagGrid *flags, Grid<Vec3> *vel, Grid<Vec3> *dstvel, Vec3 &minv, Vec3 &maxv, Real dt) : - GridOpBaseFlagbord<SLADVBOUND>(), mpVel(vel), mpDstVel(dstvel), mDt(dt) { - mpFlags = flags; - mMinVel = Vec3( vec2R(mpFlags->getSize()) * 100. ); - mMaxVel = Vec3(0.); - applyOperatorToGrids(this); - minv = mMinVel; - maxv = mMaxVel; - }; - ~fsSlAdvection() { }; - void resetVariables() { }; - void buildCallList() { - gaVel.gridAccInit(mpVel, AM_READ, gaCalls); - gaDstVel.gridAccInit(mpDstVel, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - -# define PINIT_INTERPOL \ - Real srcpi = (Real)i-(u*mDt); \ - Real srcpj = (Real)j-(v*mDt); \ - Real srcpk = (Real)k-(w*mDt); \ - int srci = (int)srcpi; \ - int srcj = (int)srcpj; \ - int srck = (int)srcpk; \ - CLAMP_TO_GRID(srci,srcj,srck,mpVel); \ - const float s1 = srcpi-(float)srci, s0 = 1.-s1; \ - const float t1 = srcpj-(float)srcj, t0 = 1.-t1; \ - const float f1 = srcpk-(float)srck, f0 = 1.-f1; \ - /* end init */ - - inline Real getSladvVel(const int a, const int b, const int c, const int index, const int src_i, const int src_j, const int src_k) { - const int flag = getFlagAcc()(a,b,c); - if (fgIsFluid(flag) ) return gaVel(a,b,c)[index]; - if (fgIsObstacle(flag) ) return 0.; - // default, return own source vel - return gaVel(src_i,src_j,src_k)[index]; - } - inline Real interpolateSladvVel(const int i, const int j, const int k, const int index, - const Real f0, const Real f1, const Real s0, const Real s1, const Real t0, const Real t1) { - - int si = i, sip1 = i+1; - int sj = j, sjp1 = j+1; - int sk = k, skp1 = k+1; - - if(DDF_DIMENSION==3) { - return ( f0*( - s0*(t0*getSladvVel(si ,sj,sk , index, si,sj,sk) + t1*getSladvVel(si ,sjp1,sk , index, si,sj,sk) ) + - s1*(t0*getSladvVel(sip1,sj,sk , index, si,sj,sk) + t1*getSladvVel(sip1,sjp1,sk , index, si,sj,sk) ) ) - + f1 * ( - s0*(t0*getSladvVel(si ,sj,skp1, index, si,sj,sk) + t1*getSladvVel(si ,sjp1,skp1, index, si,sj,sk) ) + - s1*(t0*getSladvVel(sip1,sj,skp1, index, si,sj,sk) + t1*getSladvVel(sip1,sjp1,skp1, index, si,sj,sk) ) ) - ) ; - } else { - // NOTE! srck not used for 2d! - return ( f0*( - s0*(t0*getSladvVel(si ,sj,sk, index, si,sj,sk) + t1*getSladvVel(si ,sjp1,sk, index, si,sj,sk) ) + - s1*(t0*getSladvVel(sip1,sj,sk, index, si,sj,sk) + t1*getSladvVel(sip1,sjp1,sk, index, si,sj,sk) ) ) ); - } // 2d - } - - inline void operator() (int i, int j, int k) { - // always init...? - if (fgIsObstacle(getFlagAcc()(i,j,k)) ) { - gaDstVel.write(i,j,k)=Vec3(0.); - return; - } - if (!fgIsFluid(getFlagAcc()(i,j,k)) ) { - gaDstVel.write(i,j,k) = gaVel(i,j,k); // copy, not necessary? - return; - } - - const bool debugAdv = false; - - if (1) { // advect x - const Real u = gaVel(i,j,k)[0]; - const Real v = 0.25*( - gaVel(i ,j ,k)[1] + gaVel(i-1,j ,k)[1] + - gaVel(i ,j+1,k)[1] + gaVel(i-1,j+1,k)[1] ); -# if DDF_DIMENSION==3 - const Real w = 0.25*( - gaVel(i ,j,k )[2] + gaVel(i-1,j,k )[2] + - gaVel(i ,j,k+1)[2] + gaVel(i-1,j,k+1)[2] ); -# else - const Real w = 0.; -# endif - PINIT_INTERPOL; - gaDstVel.write(i,j,k)[0] = interpolateSladvVel(srci,srcj,srck,0,f0,f1,s0,s1,t0,t1); - if (debugAdv) debMsg("sgAdvectX","vel="<<PRINT_VEC(u,v,w)<<" mDt="<<mDt<<" weights="<<s0<<","<<s1<<","<<t0<<","<<t1<<","<<f0<<","<<f1 <<" src"<<PRINT_VEC(srci,srcj,srck)<<" srcp"<<PRINT_VEC(srcpi,srcpj,srcpk)<<" ijk"<<PRINT_VEC(i,j,k) ); - if (debugAdv) debMsg("sgAdvectX","vals: "<<gaVel(srci ,srcj,srck)[0] <<", "<<gaVel(srci ,srcj+1,srck)[0] <<", "<<gaVel(srci+1,srcj,srck)[0] <<", "<<gaVel(srci+1,srcj+1,srck)[0] ); - if (debugAdv && DDF_DIMENSION==3) debMsg("sgAdvectX","vals: "<<gaVel(srci ,srcj,srck+1)[0] <<", "<<gaVel(srci ,srcj+1,srck+1)[0] <<", "<<gaVel(srci+1,srcj,srck+1)[0] <<", "<<gaVel(srci+1,srcj+1,srck+1)[0] ); - } - - if (1) { // advect y - const Real u = 0.25*( - gaVel(i ,j ,k)[0] + gaVel(i ,j-1,k)[0] + - gaVel(i+1,j ,k)[0] + gaVel(i+1,j-1,k)[0] ); - const Real v = gaVel(i,j,k)[1]; -# if DDF_DIMENSION==3 - const Real w = 0.25*( - gaVel(i,j ,k )[2] + gaVel(i,j-1,k )[2] + - gaVel(i,j ,k+1)[2] + gaVel(i,j-1,k+1)[2] ); -# else - const Real w = 0.; -# endif - PINIT_INTERPOL; - gaDstVel.write(i,j,k)[1] = interpolateSladvVel(srci,srcj,srck,1,f0,f1,s0,s1,t0,t1); - if (debugAdv) debMsg("sgAdvectY","vel="<<PRINT_VEC(u,v,w)<<" mDt="<<mDt<<" weights="<<s0<<","<<s1<<","<<t0<<","<<t1<<","<<f0<<","<<f1 <<" src"<<PRINT_VEC(srci,srcj,srck) ); - if (debugAdv) debMsg("sgAdvectY","vals: "<<gaVel(srci ,srcj,srck)[1] <<", "<<gaVel(srci ,srcj+1,srck)[1] <<", "<<gaVel(srci+1,srcj,srck)[1] <<", "<<gaVel(srci+1,srcj+1,srck)[1] ); - } - - if (gDim==3){ // advect z - const Real u = 0.25*( - gaVel(i ,j,k )[0] + gaVel(i ,j,k-1)[0] + - gaVel(i+1,j,k )[0] + gaVel(i+1,j,k-1)[0] ); - const Real v = 0.25*( - gaVel(i,j ,k )[1] + gaVel(i,j ,k-1)[1] + - gaVel(i,j+1,k )[1] + gaVel(i,j+1,k-1)[1] ); - const Real w = gaVel(i,j,k)[2]; - PINIT_INTERPOL; - gaDstVel.write(i,j,k)[2] = interpolateSladvVel(srci,srcj,srck,2,f0,f1,s0,s1,t0,t1); - if (debugAdv) debMsg("sgAdvectZ","vel="<<PRINT_VEC(u,v,w)<<" mDt="<<mDt<<" weights="<<s0<<","<<s1<<","<<t0<<","<<t1<<","<<f0<<","<<f1 <<" src"<<PRINT_VEC(srci,srcj,srck) ); - if (debugAdv) debMsg("sgAdvectZ","vals: "<<gaVel(srci ,srcj,srck)[2] <<", "<<gaVel(srci ,srcj+1,srck)[2] <<", "<<gaVel(srci+1,srcj,srck)[2] <<", "<<gaVel(srci+1,srcj+1,srck)[2] ); - } - if (DDF_DEBUG) { - Vec3 v = gaDstVel(i,j,k); - if (normNoSqrt(v)>normNoSqrt(mMaxVel)) mMaxVel=v; - if (normNoSqrt(v)<normNoSqrt(mMinVel)) mMinVel=v; - } - }; - void reduce(fsSlAdvection &op) { - // update min/max - if (normNoSqrt(op.mMaxVel)>normNoSqrt(mMaxVel)) mMaxVel=op.mMaxVel; - if (normNoSqrt(op.mMinVel)<normNoSqrt(mMinVel)) mMinVel=op.mMinVel; - }; - protected: - Grid<Vec3> *mpVel; - Grid<Vec3> *mpDstVel; - Real mDt; - GridAccessor<Vec3,SLADVBOUND> gaVel; - GridAccessor<Vec3,0> gaDstVel; - Vec3 mMinVel, mMaxVel; -}; // fsSlAdvection */ - -#undef PINIT_INTERPOL - -template < class VEL > -class fsSlAdvectionReal : public GridOpBaseFlagbord<SLADVBOUND> { - public: - fsSlAdvectionReal(FlagGrid *flags, Grid<Vec3> *vel, Grid<Real> *srcreal, - Grid<Real> *dstreal, Real dt, bool advectLs=false) : - GridOpBaseFlagbord<SLADVBOUND>(), mpVel(vel), mpSrcReal(srcreal), - mpDstReal(dstreal), mDt(dt), mAdvectLs(advectLs) - { - mpFlags = flags; - //debMsg("fsSlAdvectionReal","Grid "<<srcreal->getName()<<", dt="<<mDt ); // DEBUGold - applyOperatorToGrids(this); - }; - ~fsSlAdvectionReal() { }; - void resetVariables() { }; - void buildCallList() { - gaVel.gridAccInit(mpVel, AM_READ, gaCalls); - gaSrcReal.gridAccInit(mpSrcReal, AM_READ, gaCalls); - gaDstReal.gridAccInit(mpDstReal, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - // apply changes for vec sladv later on... - inline Real getSladvReal( - const int a, const int b, const int c, - const int index, const int src_i, const int src_j, const int src_k) { - // default, return value - return gaSrcReal(a,b,c); - } - inline Real interpolateSladvReal(const int i, const int j, const int k, const int index, - const Real f0, const Real f1, const Real s0, const Real s1, const Real t0, const Real t1) { - - int si = i, sip1 = si+1; - int sj = j, sjp1 = sj+1; - int sk = k, skp1 = sk+1; - - if(DDF_DIMENSION==3) { - return ( f0*( - s0*(t0*getSladvReal(si ,sj,sk , index, si,sj,sk) + t1*getSladvReal(si ,sjp1,sk , index, si,sj,sk) ) + - s1*(t0*getSladvReal(sip1,sj,sk , index, si,sj,sk) + t1*getSladvReal(sip1,sjp1,sk , index, si,sj,sk) ) ) - + f1 * ( - s0*(t0*getSladvReal(si ,sj,skp1, index, si,j,k) + t1*getSladvReal(si ,sjp1,skp1, index, si,sj,sk) ) + - s1*(t0*getSladvReal(sip1,sj,skp1, index, si,j,k) + t1*getSladvReal(sip1,sjp1,skp1, index, si,sj,sk) ) ) - ) ; - } else { - // NOTE! srck not used for 2d! - return ( f0*( - s0*(t0*getSladvReal(si ,sj,sk, index, si,j,k) + t1*getSladvReal(si ,sjp1,sk, index, si,sj,sk) ) + - s1*(t0*getSladvReal(sip1,sj,sk, index, si,j,k) + t1*getSladvReal(sip1,sjp1,sk, index, si,sj,sk) ) ) ); - } // 2d - } - - inline void operator() (int i, int j, int k) { - // always init...? - if (fgIsObstacle(getFlagAcc()(i,j,k)) ) { - gaDstReal.write(i,j,k)=(0.); - return; - } - if ((!mAdvectLs) && (!fgIsFluid(getFlagAcc()(i,j,k))) ) { - gaDstReal.write(i,j,k) = gaSrcReal(i,j,k); // copy, not necessary? - return; - } - const bool debugAdv = false; - const Vec3 vel = VEL::getVelocity(gaVel, i,j,k); - - Real srcpi = (Real)i-(vel[0]*mDt); - Real srcpj = (Real)j-(vel[1]*mDt); - Real srcpk = (Real)k-(vel[2]*mDt); - int srci = (int)srcpi; - int srcj = (int)srcpj; - int srck = (int)srcpk; - CLAMP_TO_GRID(srci,srcj,srck,mpVel); - const float s1 = srcpi-(float)srci, s0 = 1.-s1; - const float t1 = srcpj-(float)srcj, t0 = 1.-t1; - const float f1 = srcpk-(float)srck, f0 = 1.-f1; - - gaDstReal.write(i,j,k) = interpolateSladvReal(srci,srcj,srck,0,f0,f1,s0,s1,t0,t1); - }; - void reduce(fsSlAdvectionReal &op) { - // ... - }; - protected: - Grid<Vec3> *mpVel; - Grid<Real> *mpSrcReal; - Grid<Real> *mpDstReal; - Real mDt; - GridAccessor<Vec3,1> gaVel; - GridAccessor<Real,SLADVBOUND> gaSrcReal; - GridAccessor<Real,0> gaDstReal; - // levelset special, also advect non-fluid cells - bool mAdvectLs; - -}; // fsSlAdvectionReal */ - -// interface for advection -class spSemiLagrangeAdvVec3 : public SolverPlugin { - public: - spSemiLagrangeAdvVec3() : SolverPlugin(), mNameFlags("flags"),mNameCurrVel("vel-curr"),mNameOldVel("vec-temp"),mNameVel("vel-curr"), - mTemp1("temp1"),mTemp2("temp2"),mMAC(true) { - }; - ~spSemiLagrangeAdvVec3() { }; - - // init plugin, return failure - virtual bool parseParams(const ParamSet& params) { - debMsg("spSemiLagrangeAdvVec3","parse"); - mNameFlags = params.FindOneString("flags",mNameFlags); - mNameVel = params.FindOneString("vel",mNameVel); - mTemp1 = params.FindOneString("temp1",mTemp1); - mTemp2 = params.FindOneString("temp2",mTemp1); - mNameCurrVel = params.FindOneString("vel-src",mNameCurrVel); - mNameOldVel = params.FindOneString("vel-dst",mNameOldVel); - mMAC = params.FindOneInt("mac",1) != 0; - return true; - }; - virtual bool initPlugin() { - debMsg("spSemiLagrangeAdvVec3","init"); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spSemiLagrangeAdvVec3","step "<<dt); - Vec3 mMinv,mMaxv; - FlagGrid* flags = mpPlParams->getGridInt(mNameFlags); - Grid<Vec3>* Currvel = mpPlParams->getGridVec3(mNameCurrVel); - Grid<Vec3>* Oldvel = mpPlParams->getGridVec3(mNameOldVel); - Grid<Real>* tmp1 = mpPlParams->getGridReal(mTemp1); - Grid<Real>* tmp2 = mpPlParams->getGridReal(mTemp2); - Grid<Vec3>* vel = mpPlParams->getGridVec3(mNameVel); - - if (mMAC) - fsSlAdvection(flags, Currvel, Oldvel, mMinv,mMaxv, dt); - else - { - // X - goCopyVec3ToScalar<Real,0>(tmp1,Currvel); - fsSlAdvectionReal<getVelCentered>(flags, vel, tmp1, tmp2, dt, false); - goCopyScalarToVec3<Real,0>(Oldvel,tmp2); - // Y - goCopyVec3ToScalar<Real,1>(tmp1,Currvel); - fsSlAdvectionReal<getVelCentered>(flags, vel, tmp1, tmp2, dt, false); - goCopyScalarToVec3<Real,1>(Oldvel,tmp2); - // Z - goCopyVec3ToScalar<Real,2>(tmp1,Currvel); - fsSlAdvectionReal<getVelCentered>(flags, vel, tmp1, tmp2, dt, false); - goCopyScalarToVec3<Real,2>(Oldvel,tmp2); - } - swapGrids(mpPlParams, mNameCurrVel, mNameOldVel); - return true; - }; - - protected: - // grid access - std::string mNameFlags, mNameCurrVel, mNameOldVel, mNameVel, mTemp1, mTemp2; - bool mMAC; -}; - -// interface for real advection -class spSemiLagrangeAdvReal : public SolverPlugin { - public: - spSemiLagrangeAdvReal() : - SolverPlugin(), mNameFlags("flags"), - mNameVel("vel-curr"), mNameCurrReal("-unnamed1-"), - mNameOldReal("real-temp") , - mAdvectLs(false) { }; - ~spSemiLagrangeAdvReal() { }; - - // init plugin, return failure - virtual bool parseParams(const ParamSet& params) { - debMsg("spSemiLagrangeAdvReal","parse"); - mNameFlags = params.FindOneString("flags",mNameFlags); - mNameVel = params.FindOneString("vel",mNameVel); - mNameCurrReal = params.FindOneString("real-src",mNameCurrReal); - mNameOldReal = params.FindOneString("real-dst",mNameOldReal); - mAdvectLs = params.FindOneInt("advect-ls",mAdvectLs); - return true; - }; - virtual bool initPlugin() { - debMsg("spSemiLagrangeAdvReal","init"); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spSemiLagrangeAdvReal","step "<<dt); - FlagGrid* flags = mpPlParams->getGridInt(mNameFlags); - Grid<Vec3>* vel = mpPlParams->getGridVec3(mNameVel); - Grid<Real>* CurrReal = mpPlParams->getGridReal(mNameCurrReal); - Grid<Real>* newReal = mpPlParams->getGridReal(mNameOldReal); - - fsSlAdvectionReal<getVelCentered>(flags, vel, CurrReal, newReal, dt, mAdvectLs); - swapGrids(mpPlParams, mNameCurrReal, mNameOldReal); - return true; - }; - - protected: - // grid access - std::string mNameFlags, mNameVel, mNameCurrReal, mNameOldReal; - bool mAdvectLs; -}; - -// mac cormack adevection - correct using the back and forth sl steps -template < class VEL > -class fsMacCormackCorrect : public GridOpBaseFlagbord<1> { - public: - fsMacCormackCorrect(FlagGrid *flags, Grid<Real> *dst, Grid<Real> *old, Grid<Real> *temp1, - Grid<Real> *temp2, Real strength, bool advLs) : - GridOpBaseFlagbord<1>(), mpDst(dst), mpOld(old), mpTemp1(temp1), mpTemp2(temp2) - , mStrength(strength), mAdvectLs(advLs) - { - mpFlags = flags; - applyOperatorToGrids(this); - }; - - ~fsMacCormackCorrect() { }; - - void resetVariables() { }; - - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - gaOld.gridAccInit(mpOld, AM_READ, gaCalls); - gaTemp1.gridAccInit(mpTemp1, AM_READ, gaCalls); - gaTemp2.gridAccInit(mpTemp2, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - if (!fgIsFluid(getFlagAcc()(i,j,k)) ) { - if(mAdvectLs) gaDst.write(i,j,k) = gaTemp1(i,j,k); // levelset -> copy value - else gaDst.write(i,j,k) = 0.; // default, reset - return; - } - gaDst.write(i,j,k) = gaTemp1(i,j,k) + - (gaOld(i,j,k) - - gaTemp2(i,j,k)) * 0.5; - - // interpolate between SL and MC - if(mStrength<1.) { - gaDst.write(i,j,k) = (1.-mStrength)*gaTemp1(i,j,k) + mStrength*gaDst(i,j,k); - } - }; - - void reduce(fsMacCormackCorrect &op) { }; - - protected: - Grid<Real> *mpDst, *mpOld, *mpTemp1, *mpTemp2; - GridAccessor<Real,0> gaDst; - GridAccessor<Real,1> gaOld, gaTemp1, gaTemp2; - Real mStrength; - bool mAdvectLs; -}; - -// mac cormack adevection - clamp sl advection -template < class VEL > -class fsMacCormackClamp : public GridOpBaseFlagbord<SLADVBOUND> { - public: - fsMacCormackClamp(FlagGrid *flags, Grid<Vec3> *vel, Grid<Real> *srcreal, - Grid<Real> *dstreal, Real dt) : - GridOpBaseFlagbord<SLADVBOUND>(), mpVel(vel), mpSrcReal(srcreal), - mpDstReal(dstreal), mDt(dt) { - - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsMacCormackClamp() { }; - void resetVariables() { }; - void buildCallList() { - gaVel.gridAccInit(mpVel, AM_READ, gaCalls); - gaSrcReal.gridAccInit(mpSrcReal, AM_READ, gaCalls); - gaDstReal.gridAccInit(mpDstReal, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - //! hack to fix negative rounding, this depends on always rounding down... define P2IOFF 200 - - // apply changes for vec sladv later on... - inline Real getSladvReal( - const int a, const int b, const int c, - const int src_i, const int src_j, const int src_k) { - // default, return value - return gaSrcReal(a,b,c); - } - inline Real clampValue(const int i, const int j, const int k, - Real val) { - int si = i, sip1 = i+1; - int sj = j, sjp1 = j+1; - int sk = k, skp1 = k+1; - - const Real v000 = getSladvReal(si ,sj ,sk , si,sj,sk); - const Real v010 = getSladvReal(si ,sjp1,sk , si,sj,sk); - const Real v100 = getSladvReal(sip1,sj ,sk , si,sj,sk); - const Real v110 = getSladvReal(sip1,sjp1,sk , si,sj,sk); - - // compute minima/maxima - Real max = v000, min=v000; - if(v010>max) max = v010; - if(v100>max) max = v100; - if(v110>max) max = v110; - - if(v010<min) min = v010; - if(v100<min) min = v100; - if(v110<min) min = v110; - - if(DDF_DIMENSION==3) { - const Real v001 = getSladvReal(si ,sj ,skp1, si,j,k); - const Real v011 = getSladvReal(si ,sjp1,skp1, si,sj,sk); - const Real v101 = getSladvReal(sip1,sj ,skp1, si,j,k); - const Real v111 = getSladvReal(sip1,sjp1,skp1, si,sj,sk); - - if(v001>max) max = v001; - if(v011>max) max = v011; - if(v101>max) max = v101; - if(v111>max) max = v111; - if(v001<min) min = v001; - if(v011<min) min = v011; - if(v101<min) min = v101; - if(v111<min) min = v111; - } - if(val<min) return min; - if(val>max) return max; - return val; - } - - // same as semi-lagrange advection, only clamp instead of interpolation - inline void operator() (int i, int j, int k) { - // always init...? - if (fgIsObstacle(getFlagAcc()(i,j,k)) ) { - return; - } - if (!fgIsFluid(getFlagAcc()(i,j,k)) ) { - return; - } - const Vec3 vel = VEL::getVelocity(gaVel, i,j,k); - - Real srcpi = (Real)i-(vel[0]*mDt); - Real srcpj = (Real)j-(vel[1]*mDt); - Real srcpk = (Real)k-(vel[2]*mDt); - - int srci = (int)srcpi; - int srcj = (int)srcpj; - int srck = (int)srcpk; - CLAMP_TO_GRID(srci,srcj,srck,mpVel); - - gaDstReal.write(i,j,k) = clampValue(srci,srcj,srck, gaDstReal(i,j,k) ); - }; - void reduce(fsMacCormackClamp &op) { - // ... - }; - protected: - Grid<Vec3> *mpVel; - Grid<Real> *mpSrcReal; - Grid<Real> *mpDstReal; - Real mDt; - GridAccessor<Vec3,1> gaVel; - GridAccessor<Real,SLADVBOUND> gaSrcReal; - GridAccessor<Real,0> gaDstReal; -}; // fsMacCormackClamp */ - - -// mac cormack adevection - clamp boundaries -template < class VEL > -class fsMacCormackBoundaryClamp : public GridOpBaseFlagbord<SLADVBOUND> { - public: - fsMacCormackBoundaryClamp(FlagGrid *flags, Grid<Vec3> *vel, - Grid<Real> *dstreal, Grid<Real> *srcorg, Real dt) : - GridOpBaseFlagbord<SLADVBOUND>(), - mpVel(vel), - mpSrcOrg(srcorg), - mpDstReal(dstreal), - mDt(dt) - { - mpFlags = flags; - applyOperatorToGrids(this); - }; - - ~fsMacCormackBoundaryClamp() { }; - - void resetVariables() { }; - - void buildCallList() { - gaVel.gridAccInit(mpVel, AM_READ, gaCalls); - gaDstReal.gridAccInit(mpDstReal, AM_WRITE, gaCalls); - gaSrcOrg.gridAccInit(mpSrcOrg, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - // same as semi-lagrange advection, only clamp instead of interpolation - inline void operator() (int i, int j, int k) { - // always init...? - if (fgIsObstacle(getFlagAcc()(i,j,k)) ) { - return; - } - if (!fgIsFluid(getFlagAcc()(i,j,k)) ) { - // NT fix, preserve surrounding values from original grid everywhere in empty space - gaDstReal.write(i,j,k) = gaSrcOrg(i,j,k); // fix , SURROUND_RESET - return; - } - const Vec3 vel = VEL::getVelocity(gaVel, i,j,k); - bool doReset = false; - - // forward lookup - Real srcpiForw = (Real)i-(vel[0]*mDt); - Real srcpjForw = (Real)j-(vel[1]*mDt); - Real srcpkForw = (Real)k-(vel[2]*mDt); - // backward lookup - Real srcpiBack = (Real)i+(vel[0]*mDt); - Real srcpjBack = (Real)j+(vel[1]*mDt); - Real srcpkBack = (Real)k+(vel[2]*mDt); - - int srciForw = (int)srcpiForw; - int srcjForw = (int)srcpjForw; - int srckForw = (int)srcpkForw; - if( CLAMP_TO_GRID_BOOL(srciForw,srcjForw,srckForw,mpVel) ) doReset = true; - - int srciBack = (int)srcpiBack; - int srcjBack = (int)srcpjBack; - int srckBack = (int)srcpkBack; - if(!doReset) { - if( CLAMP_TO_GRID_BOOL(srciBack,srcjBack,srckBack,mpVel) ) doReset = true; - } // not yet reset - - if(!doReset) { - if ( fgIsObstacle(getFlagAcc()(srciForw,srcjForw,srckForw)) || - fgIsObstacle(getFlagAcc()(srciBack,srcjBack,srckBack)) - ) { - doReset = true; - } - } // not yet reset - - if(doReset) { - gaDstReal.write(i,j,k) = gaSrcOrg(i,j,k); - } - }; - void reduce(fsMacCormackBoundaryClamp &op) { - // ... - }; - protected: - Grid<Vec3> *mpVel; - Grid<Real> *mpSrcOrg; - Grid<Real> *mpDstReal; - Real mDt; - GridAccessor<Vec3,1> gaVel; - GridAccessor<Real,0> gaDstReal; - GridAccessor<Real,0> gaSrcOrg; -}; // fsMacCormackBoundaryClamp */ - - -// interface for MacCormack advection of a scalar field -class spMacCormackReal : public SolverPlugin { - public: - spMacCormackReal() : - SolverPlugin(), mNameFlags("flags"), - mNameVel("vel-curr"), - mNameCurrReal("-unnamed1-"), mNameOldReal("real-temp") , - mNameTemp1("temp1"), mNameTemp2("temp2") , - mStrength(0.5), mAdvectLs(false) - { }; - ~spMacCormackReal() { }; - - // init plugin, return failure - virtual bool parseParams(const ParamSet& params) { - debMsg("spMacCormackReal","parse"); - mNameFlags = params.FindOneString("flags",mNameFlags); - mNameVel = params.FindOneString("vel",mNameVel); - mNameCurrReal = params.FindOneString("real-src",mNameCurrReal); - mNameOldReal = params.FindOneString("real-dst",mNameOldReal); - mNameTemp1 = params.FindOneString("temp1",mNameTemp1); - mNameTemp2 = params.FindOneString("temp2",mNameTemp2); - mAdvectLs = params.FindOneInt("advect-ls",mAdvectLs); - mStrength = params.FindOneFloat("strength",mStrength); - return true; - }; - virtual bool initPlugin() { - debMsg("spMacCormackReal","init"); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spMacCormackReal","step "<<dt); - - FlagGrid* flags = mpPlParams->getGridInt(mNameFlags); - Grid<Vec3>* vel = mpPlParams->getGridVec3(mNameVel); - Grid<Real>* CurrReal = mpPlParams->getGridReal(mNameCurrReal); - Grid<Real>* newReal = mpPlParams->getGridReal(mNameOldReal); - Grid<Real>* temp1 = mpPlParams->getGridReal(mNameTemp1); - Grid<Real>* temp2 = mpPlParams->getGridReal(mNameTemp2); - - // normal forward step - fsSlAdvectionReal<getVelCentered>(flags, vel, CurrReal, temp1, dt, mAdvectLs); - - // backwards step - fsSlAdvectionReal<getVelCentered>(flags, vel, temp1, temp2, -1. * dt, mAdvectLs); - - // compute correction - fsMacCormackCorrect<getVelCentered>(flags, newReal, CurrReal, temp1, temp2, mStrength, mAdvectLs); - - // clamp values - fsMacCormackClamp<getVelCentered>(flags, vel, CurrReal, newReal, dt); - //fsMacCormackBoundaryClamp(flags, vel, CurrReal, temp1, dt); - fsMacCormackBoundaryClamp<getVelCentered>(flags, vel, newReal, temp1, dt); - - swapGrids(mpPlParams, mNameCurrReal, mNameOldReal); - return true; - }; - - protected: - // grid access - std::string mNameFlags, mNameVel, mNameCurrReal, mNameOldReal, mNameTemp1, mNameTemp2; - Real mStrength; - bool mAdvectLs; -}; - -// interface for maccormack advection of the velocities -class spMacCormackVec3 : public SolverPlugin { - public: - spMacCormackVec3() : - SolverPlugin(), mNameFlags("flags"), - mNameVel("vel-curr"), - mNameCurrVec3("vel-curr"), mNameOldVec3("vec-temp") , - mNameTemp1("temp1"), mNameTemp2("temp2"), mMAC(true) - { }; - ~spMacCormackVec3() { }; - - // init plugin, return failure - virtual bool parseParams(const ParamSet& params) { - debMsg("spMacCormackVec3","parse"); - mNameFlags = params.FindOneString("flags",mNameFlags); - mNameCurrVec3 = params.FindOneString("vel-src",mNameCurrVec3); - mNameOldVec3 = params.FindOneString("vel-dst",mNameOldVec3); - mMAC = params.FindOneInt("mac",1) != 0; - - // reuse currvec3, if given - mNameVel = params.FindOneString("vel",mNameCurrVec3); - - mNameTemp1 = params.FindOneString("temp1",mNameTemp1); - mNameTemp2 = params.FindOneString("temp2",mNameTemp2); - return true; - }; - virtual bool initPlugin() { - debMsg("spMacCormackVec3","init"); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spMacCormackVec3","step "<<dt); - const Real mStrength = 0.5; - - FlagGrid* flags = mpPlParams->getGridInt(mNameFlags); - Grid<Vec3>* advVel = mpPlParams->getGridVec3(mNameVel); - Grid<Vec3>* currVec3 = mpPlParams->getGridVec3(mNameCurrVec3); - Grid<Vec3>* oldVec3 = mpPlParams->getGridVec3(mNameOldVec3); - Grid<Real>* temp1 = mpPlParams->getGridReal(mNameTemp1); - Grid<Real>* temp2 = mpPlParams->getGridReal(mNameTemp2); - - Grid<Real>* realTmp = mpPlParams->getGridReal("residual"); - Grid<Real>* realNew = mpPlParams->getGridReal("tmp"); - - // normal forward step - bool advectLs = false; - //fsSlAdvectionReal<getVelCentered>(flags, currVec3, realTmp, temp1, dt, advectLs); - - if (mMAC) - { - // X - goCopyVec3ToScalar<Real,0>(realTmp,currVec3); - // normal forward step - fsSlAdvectionReal<getVelX>(flags, advVel, realTmp, temp1, dt, advectLs); - // backwards step - fsSlAdvectionReal<getVelX>(flags, advVel, temp1, temp2, -1. * dt, advectLs); - // compute correction - fsMacCormackCorrect<getVelX>(flags, realNew, realTmp, temp1, temp2, mStrength, advectLs); - // clamp values - fsMacCormackClamp<getVelX>(flags, advVel, realTmp, realNew, dt); - fsMacCormackBoundaryClamp<getVelX>(flags, advVel, realNew, temp1, dt); - goCopyScalarToVec3<Real,0>(oldVec3,realNew); - - // Y - goCopyVec3ToScalar<Real,1>(realTmp,currVec3); - // normal forward step - fsSlAdvectionReal<getVelY>(flags, advVel, realTmp, temp1, dt, advectLs); - // backwards step - fsSlAdvectionReal<getVelY>(flags, advVel, temp1, temp2, -1. * dt, advectLs); - // compute correction - fsMacCormackCorrect<getVelY>(flags, realNew, realTmp, temp1, temp2, mStrength, advectLs); - // clamp values - fsMacCormackClamp<getVelY>(flags, advVel, realTmp, realNew, dt); - fsMacCormackBoundaryClamp<getVelY>(flags, advVel, realNew, temp1, dt); - goCopyScalarToVec3<Real,1>(oldVec3,realNew); - - // Z - goCopyVec3ToScalar<Real,2>(realTmp,currVec3); - // normal forward step - fsSlAdvectionReal<getVelZ>(flags, advVel, realTmp, temp1, dt, advectLs); - // backwards step - fsSlAdvectionReal<getVelZ>(flags, advVel, temp1, temp2, -1. * dt, advectLs); - // compute correction - fsMacCormackCorrect<getVelZ>(flags, realNew, realTmp, temp1, temp2, mStrength, advectLs); - // clamp values - fsMacCormackClamp<getVelZ>(flags, advVel, realTmp, realNew, dt); - fsMacCormackBoundaryClamp<getVelZ>(flags, advVel, realNew, temp1, dt); - goCopyScalarToVec3<Real,2>(oldVec3,realNew); - } - else - { - for (int i=0;i<3;i++) - { - if (i==0) goCopyVec3ToScalar<Real,0>(realTmp,currVec3); - if (i==1) goCopyVec3ToScalar<Real,1>(realTmp,currVec3); - if (i==2) goCopyVec3ToScalar<Real,2>(realTmp,currVec3); - // normal forward step - fsSlAdvectionReal<getVelCentered>(flags, advVel, realTmp, temp1, dt, advectLs); - // backwards step - fsSlAdvectionReal<getVelCentered>(flags, advVel, temp1, temp2, -1. * dt, advectLs); - // compute correction - fsMacCormackCorrect<getVelCentered>(flags, realNew, realTmp, temp1, temp2, mStrength, advectLs); - // clamp values - fsMacCormackClamp<getVelCentered>(flags, advVel, realTmp, realNew, dt); - fsMacCormackBoundaryClamp<getVelCentered>(flags, advVel, realNew, temp1, dt); - if (i==0) goCopyScalarToVec3<Real,0>(oldVec3,realNew); - if (i==1) goCopyScalarToVec3<Real,1>(oldVec3,realNew); - if (i==2) goCopyScalarToVec3<Real,2>(oldVec3,realNew); - } - } - swapGrids(mpPlParams, mNameCurrVec3, mNameOldVec3); - return true; - }; - - protected: - // grid access - std::string mNameFlags, mNameVel, mNameCurrVec3, mNameOldVec3, mNameTemp1, mNameTemp2; - bool mMAC; - //bool mAdvectLs; -}; - -//***************************************************************************** -// external accessor helper function - -void doSemiLagrangeReal(FlagGrid* flags, Grid<Vec3>* vel, Grid<Real>* src, Grid<Real>* dst, Real dt) -{ - fsSlAdvectionReal<getVelCentered>(flags, vel, src, dst, dt, false); -} - -//***************************************************************************** - -// create one of the standard hard coded plugins -SolverPlugin* MakeAdvectionPlugin(std::string name) { - - if(name.compare("semi-lagr-advect-vec3")==0) { - return new spSemiLagrangeAdvVec3; - } else if(name.compare( "semi-lagr-advect-real")==0) { - return new spSemiLagrangeAdvReal; - - } else if(name.compare( string("maccormack-advect-real") )==0) { - return new spMacCormackReal; - } else if(name.compare( string("maccormack-advect-vec3") )==0) { - return new spMacCormackVec3; - } - - return NULL; -} - - -} // end namespace DDF - diff --git a/intern/smoke/intern/source/animplugins.cpp b/intern/smoke/intern/source/animplugins.cpp deleted file mode 100644 index ba7bb884f82..00000000000 --- a/intern/smoke/intern/source/animplugins.cpp +++ /dev/null @@ -1,642 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Plugins to animate boundaries and ABL fields. - * - *****************************************************************************/ - -#include <fstream> -#include "fluidsolver.h" -#include "solverplugin.h" -#include "paramset.h" -#include "quaternion.h" -#include <zlib.h> - -#include "matrixbase.h" - -using namespace std; - -// safety boundary for semi lagrange advection step -#define SLADVBOUND 2 - -namespace DDF { - -class ObjectTransformation { - public: - ObjectTransformation(Real v) : - center(v), pos(v), posVel(v), - rotMat(v), rotVel(v), - scale(v), scaleVel(v) {}; - - Vec3 center; - Vec3 pos, posVel; - Mat4 rotMat; - Vec3 rotVel; - Vec3 scale, scaleVel; -}; - -//***************************************************************************** -// Gridop : update moving obstacles -class opSetMovingObstacleBC : public GridOpBaseFlagbord<SLADVBOUND> { - public: - opSetMovingObstacleBC(FlagGrid *flags, Grid<Vec3> *vel, FlagGrid *obs, - ObjectTransformation trafo, Real dt, bool deleteOld, Grid<Real> *distsrc, Grid<Real> *distdst, const vector<Vec3>& if1, const vector<Vec3>& if2, bool doforces) : - GridOpBaseFlagbord<SLADVBOUND>(), - mpVel(vel), mTrafo(trafo), mDt(dt) , - mpObs(obs), mDeleteOld(deleteOld), mIF1(), mIF2(), mpDistSrc(distsrc), mpDistDst(distdst), mDoForces(doforces) - { - mpFlags = flags; - - // don't scale to infinity - if (normNoSqrt(mTrafo.scale) < 1e-16) mTrafo.scale = 1.; - - // transform positions to src coordinates - Vec3 srcSize = vec2R(mpFlags->getSize()); - Vec3 destSize = vec2R(mpObs->getSize()); - mCenterFlag = (mTrafo.center + mTrafo.pos) * srcSize; - mTrafo.pos *= srcSize; - mTrafo.center *= destSize; - mTrafo.scale = Vec3(destSize.max()/srcSize.max()) / mTrafo.scale; - mTrafo.posVel *= srcSize; - - for (unsigned i=0; i<if1.size(); i++) mIF1.push_back( if1[i] * destSize); - for (unsigned i=0; i<if2.size(); i++) mIF2.push_back( if2[i] * destSize); - - cout << "pos " << mTrafo.pos << " scale " << mTrafo.scale << " center " << mTrafo.center << endl; - debMsg("opSetMovingObstacleBC","pos="<<mTrafo.pos << " "); - - // assume an additional layer of obstacle cells, so BND=2 - applyOperatorWithBoundToGrid(this, mpFlags, 1); - }; - - - ~opSetMovingObstacleBC() { }; - void resetVariables() { }; - void reduce(opSetMovingObstacleBC &op) { }; - - void buildCallList() { - this->gaFlags.gridAccInit(mpFlags, AM_WRITE, gaCalls); - gaVel.gridAccInit(mpVel, AM_WRITE, gaCalls); - gaObs.gridAccInit(mpObs, AM_READ, gaCalls); - - if(mpDistSrc) gaDistSrc.gridAccInit(mpDistSrc, AM_READ, gaCalls); - if(mpDistDst) gaDistDst.gridAccInit(mpDistDst, AM_READWRITE, gaCalls); - //setFlags(mpFlags); - }; - - // point transformation - inline void trafoPoint(Vec3 &pos, Mat4 &mat) { - pos -= mCenterFlag; - pos = (mat * pos) * mTrafo.scale; - pos += mTrafo.center; // to dest coordinates - } - - inline void operator() (int i, int j, int k) { - int srcFlag = FEMPTY; - Vec3 currVel = mTrafo.posVel; - Vec3 pos (i,j,k); - nVec3i src (1,1,1); - - // with rotation, use trafo matrix - if (mDoForces) - { - Vec3 r = (pos-mCenterFlag); - currVel += cross( mTrafo.rotVel, r ); - } - trafoPoint( pos, mTrafo.rotMat); - src = vecround( pos); - - // check validity of lookup - bool isvalid = mpObs->checkIndexValidWithBounds(src.x,src.y,src.z, 1); - if(isvalid) - srcFlag = gaObs( src.x,src.y,src.z ); - - // write new flag grid - if (mDeleteOld && fgIsObstacle( getFlagAcc()(i,j,k) ) ) - this->gaFlags.write(i,j,k) = FEMPTY; - - if (!isvalid) return; - - if (fgIsObstacle(srcFlag) ) { - gaFlags.write(i,j,k) = FOBSTACLE; - if (mDoForces) gaVel.write(i,j,k) = currVel; // velocity boundary condition - } - else if (mpDistSrc != NULL) { - // join distance fields, if the exist - Real ndst = gaDistDst(i,j,k), nsrc = gaDistSrc(src.x,src.y,src.z); - if (nsrc > 0 && (ndst == 0 || nsrc < ndst)) - gaDistDst.write(i,j,k) = nsrc; - } - - // initialize density source (moving smoke-box) - for (unsigned n=0; n<mIF1.size(); n++) - { - if (src.x >= mIF1[n].x && src.y >= mIF1[n].y && src.z >= mIF1[n].z && - src.x <= mIF2[n].x && src.y <= mIF2[n].y && src.z <= mIF2[n].z) - this->gaFlags.write(i,j,k) = gaFlags(i,j,k) | FDENSITYSOURCE; - } - - // done... - }; - protected: - Grid<Vec3> *mpVel; - GridAccessor<Vec3,1> gaVel; - - ObjectTransformation mTrafo; - - Real mDt; - FlagGrid *mpObs; - GridAccessor<int,0> gaObs; - Vec3 mCenterFlag; - bool mDeleteOld; - - Mat4 mMatRot,mMatRotNext; - - vector<Vec3> mIF1, mIF2; - Grid<Real> *mpDistSrc, *mpDistDst; - GridAccessor<Real,1> gaPhiDebug; - GridAccessor<Real,0> gaDistSrc, gaDistDst; - bool mDoForces; -}; - -//***************************************************************************** -// Plugin for moving obstacles with linear speed -class spSetMovingObstacleBC : public SolverPlugin { - public: - spSetMovingObstacleBC() : - SolverPlugin(), mNameFlags("flags"), - mNameVel("vel-curr"), mObstacle(""),mTrafo(0.) - { }; - ~spSetMovingObstacleBC() { }; - - // init plugin, return failure - virtual bool parseParams(const ParamSet& params) { - mNameFlags = params.FindOneString("flags",mNameFlags); // flag grid - mNameFlagsSrc = params.FindOneString("flags-src",""); // static background flag grid - mNameVel = params.FindOneString("vel","vel-curr"); // velocity grid - mObstacle = params.FindOneString("obstacle",mObstacle); // flag grid of the moving object - - mTrafo.posVel = params.FindOneVector("obs-vel",mTrafo.posVel); // linear velocity - mTrafo.pos = params.FindOneVector("obs-pos",mTrafo.pos); // initial position - - // center of rotation/scale - mTrafo.center = params.FindOneVector("obs-center",mTrafo.center); // rotation pivot - mRotAxis = params.FindOneVector("obs-rot-axis",Vec3(0.)); // rotation axis - mRotAngle = params.FindOneFloat("obs-rot-angle",0.); // initial rotation angle (degrees) - mRotVel = params.FindOneFloat("obs-rot-vel",0.); // rotation velocity (degrees/timestep) - mTrafo.scaleVel = params.FindOneVector("obs-scale-vel",mTrafo.scaleVel); // scale velocity - mTrafo.scale = params.FindOneVector("obs-scale",mTrafo.scale); // initial scaling - mRotAngle *= M_PI/180.; - mRotVel *= M_PI/180.; - normalize(mRotAxis); - mTrafo.rotVel = mRotAxis * mRotVel; - return true; - }; - virtual bool initPlugin() { - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spSetMovingObstacleBC","step "<<dt); - const Real mStrength = 0.5; - - // get grids - FlagGrid* flags = mpPlParams->getGridInt(mNameFlags); - FlagGrid* flagsrc = mNameFlagsSrc.empty() ? NULL : mpPlParams->getGridInt(mNameFlagsSrc); - Grid<Vec3>* vel = mpPlParams->getGridVec3(mNameVel); - FlagGrid* obs = mpPlParams->getGridInt(mObstacle); - Grid<Real>* phiCurr = NULL; // mpPlParams->getGridReal("phi-curr"); - - // copy background grid - if (flagsrc) goCopyGrid<int>(flags,flagsrc); - - // set flags & velocities inside cells - Quat q(mRotAxis,mRotAngle); - mTrafo.rotMat = q.getRotMat(); - opSetMovingObstacleBC(flags, vel, obs, mTrafo, dt, flagsrc==NULL, NULL, NULL, vector<Vec3>(),vector<Vec3>(),true); - - // initialize obstacle boundaries with velocities - FOR_IJK_GRID(flags) { - if (!fgIsObstacle( flags->getGlobal(i,j,k) ) ) { - if (i>0 && fgIsObstacle( flags->getGlobal(i-1,j,k) ) ) { - vel->getGlobal(i,j,k)[0] = vel->getGlobal(i-1,j,k)[0]; - } - if (j>0 && fgIsObstacle( flags->getGlobal(i,j-1,k) ) ) { - vel->getGlobal(i,j,k)[1] = vel->getGlobal(i,j-1,k)[1]; - } - if(gDim==3 && (k>0 && fgIsObstacle( flags->getGlobal(i,j,k-1) ) )) { - vel->getGlobal(i,j,k)[2] = vel->getGlobal(i,j,k-1)[2]; - } - } - else { - // reset level set inside of the obstacle? - if (phiCurr) { - if(phiCurr->getGlobal(i,j,k)<0.) phiCurr->getGlobal(i,j,k) = 0.5; - } - } - } - - // update pos, rot, scale - mTrafo.pos += mTrafo.posVel * dt; - mRotAngle += mRotVel * dt; - mTrafo.scale += mTrafo.scaleVel * dt; - - return true; - }; - - protected: - std::string mNameFlags, mNameVel, mObstacle, mNameFlagsSrc; - ObjectTransformation mTrafo; - Vec3 mRotAxis; - Real mRotAngle, mRotVel; -}; - -//***************************************************************************** -// A set of precalculated boundary layers -class VortexDBSet { - public: - // load from file - VortexDBSet(gzFile& gzf, int numPhi, int numTheta, const Vec3& sizeFlags) - { - Real gd; - if (gzread(gzf,&numPoints,sizeof(int)) != sizeof(int)) { errFatal("spAnimate::initPlugin","gzread failed", SIMWORLD_INITERROR); } - if (gzread(gzf,&gd,sizeof(Real)) != sizeof(Real)) { errFatal("spAnimate::initPlugin","gzread failed", SIMWORLD_INITERROR); } - if (gzread(gzf,&mSize[0],sizeof(Vec3)) != sizeof(Vec3)) { errFatal("spAnimate::initPlugin","gzread failed", SIMWORLD_INITERROR); } - if (gzread(gzf,&mVScale[0],sizeof(Vec3)) != sizeof(Vec3)) { errFatal("spAnimate::initPlugin","gzread failed", SIMWORLD_INITERROR); } - if (gzread(gzf,&mVOffs[0],sizeof(Vec3)) != sizeof(Vec3)) { errFatal("spAnimate::initPlugin","gzread failed", SIMWORLD_INITERROR); } - mPos.resize(numPoints); - mNoDir.resize(numPoints); - for (int i=0;i<numPoints;i++) - if (gzread(gzf,&mPos[i][0],sizeof(Vec3)) != sizeof(Vec3)) { errFatal("spAnimate::initPlugin","gzread failed", SIMWORLD_INITERROR); } - for (int i=0;i<numPoints;i++) - if (gzread(gzf,&mNoDir[i][0],sizeof(Vec3)) != sizeof(Vec3)) { errFatal("spAnimate::initPlugin","gzread failed", SIMWORLD_INITERROR); } - mLookup.resize(numTheta); - for (int i=0;i<numTheta;i++) - { - mLookup[i] = vector<int>(numPhi); - if (gzread(gzf,&mLookup[i][0],numPhi*sizeof(int)) != (int)(numPhi*sizeof(int))) { errFatal("spAnimate::initPlugin","gzread failed", SIMWORLD_INITERROR); } - } - gd /= sizeFlags.max(); - mIGriddiv2 = 1./ ( gd*gd); - mIScale = sizeFlags / (mVScale * mSize); - //cout << "load set : N " << mSize << " vscale " << mVScale<< " offs " << mVOffs << endl << numPoints << " items" << endl; - } - - // bilinear interpolation of the nearest datapoints in the set - void bilinearChooseSets(const vector<Real>& mPhi, const vector<Real>& mTheta, const vector<Vec3>& mSetDir, Real& a11, Real& a12, Real& a21, Real& a22, int& idx11, int& idx12, int& idx21, int& idx22, const Vec3& vel, Real& mult) const - { - Vec3 dir = vel; - mult = normalize(dir); cout << " norm dir " << mult; - if (mult < 1e-10){ - mult=0; return; - } - mult /= mNorm; cout << " set norm " << mNorm << " total " << mult << endl; - Real phi, theta; - vecToAngle(dir, phi, theta); - - // find linear coefficients - int idxp1=0, idxp2=mPhi.size()-1; - for (unsigned i=0;i<mPhi.size();i++) - { - if (mPhi[i] <= phi && mPhi[i] > mPhi[idxp1]) idxp1=i; - if (mPhi[i] >= phi && mPhi[i] < mPhi[idxp2]) idxp2=i; - } - Real ap = (idxp1 == idxp2) ? 0 : (phi - mPhi[idxp1]) / (mPhi[idxp2] - mPhi[idxp1]); - - int idxt1=0, idxt2=mTheta.size()-1; - for (unsigned i=0;i<mTheta.size();i++) - { - if (mTheta[i] <= theta && mTheta[i] > mTheta[idxt1]) idxt1=i; - if (mTheta[i] >= theta && mTheta[i] < mTheta[idxt2]) idxt2=i; - } - Real at = (idxt1 == idxt2) ? 0 : (theta - mTheta[idxt1]) / (mTheta[idxt2] - mTheta[idxt1]); - - idx11 = mLookup[idxt1][idxp1]; a11 = (1.-at)*(1.-ap); - idx12 = mLookup[idxt1][idxp2]; a12 = (1.-at)*(ap); - idx21 = mLookup[idxt2][idxp1]; a21 = (at)*(1.-ap); - idx22 = mLookup[idxt2][idxp2]; a22 = (at)*(ap); - - //printf("phi %g theta %g : chose phi= %g(%g)%g ,theta= %g(%g)%g\n",phi*180./M_PI,theta*180./M_PI,mPhi[idxp1]*180./M_PI,ap,mPhi[idxp2]*180./M_PI,mTheta[idxt1]*180./M_PI,at,mTheta[idxt2]*180./M_PI ); - //cout << vel << " to " << mSetDir[idx11]*mult << " " << mSetDir[idx12]*mult << " " << mSetDir[idx21]*mult << " " << mSetDir[idx22]*mult << endl; - //cout << idx11 << "," << idx12 << "," << idx21 << "," << idx22 << "," <<endl; - //cout << "final : " << mult*(a11*mSetDir[idx11]+a12*mSetDir[idx12]+a21*mSetDir[idx21]+a22*mSetDir[idx22]) << " to orig " << vel <<endl; - - } - - // map confined vorticity to simulation grid - void mapdown(FlagGrid *flags, Grid<Vec3>* dst, const Mat4& rot, const Vec3& pos, const Vec3& nvec, const vector<vector<Vec3> >& mSetVort, const vector<Real>& mPhi, const vector<Real>& mTheta, const vector<Vec3>& mSetDir, const Vec3& cnt, const Vec3& sc) - { - Real mult, a11, a12, a21, a22; - int idx11, idx12, idx22, idx21; - bilinearChooseSets(mPhi,mTheta,mSetDir, a11,a12,a21,a22,idx11,idx12,idx21,idx22,nvec,mult); - if (mult == 0) return; - - Vec3 srcSize = vec2R(flags->getSize()); - Vec3 centerSrc = (cnt + pos) * srcSize; - Vec3 centerDst = cnt * mSize; - Vec3 iscale = Vec3(srcSize.max()/mSize.max()) * sc; - cout << "mult " << mult << " gridd " << iscale << " total " << mult*mIGriddiv2 <<endl; - //mult /= mIGriddiv2; - Real pt,pp; - vecToAngle(nvec,pp,pt); - for (unsigned n=0;n<mPos.size();n++) - { - Vec3 p = (mPos[n] - centerDst) * iscale; - p = rot * p; - p += centerSrc; - // transfer vorticity sources - nVec3i npos = vecround(p); - - if (!flags->checkIndexValid(npos.x,npos.y,npos.z)) continue; - //printf("point %d : set %g %g %g grid %g %g %g\n",n,mPos[n].x,mPos[n].y,mPos[n].z,p.x,p.y,p.z); - - if (fgIsFluid(flags->getGlobal(npos.x,npos.y,npos.z))) - { - Vec3 vsi = a11*mSetVort[idx11][n]; - vsi += a12*mSetVort[idx12][n]; - vsi += a21*mSetVort[idx21][n]; - vsi += a22*mSetVort[idx22][n]; - Vec3 vs = rot * vsi; - (*dst)(npos.x,npos.y,npos.z) += -vs * mult; - //cout << dst->getName() << ":" << npos << " <<= " <<-vs*mult << " : " << (*dst)(npos.x,npos.y,npos.z) << endl; - } - } - } - - vector<vector<int> > mLookup; - vector<Vec3> mPos, mNoDir; - Vec3 mVScale, mVOffs, mSize, mIScale; - Real mIGriddiv2, mNorm; - int numPoints; -}; - -//***************************************************************************** -// Interface for precalculated DB -class VortexDB -{ - public: - // load from file - VortexDB(const string& file, const Vec3& sizeFlags) - { - // load database - int numSets, numPhi, numTheta; - gzFile gzf = gzopen(file.c_str(),"rb"); - if (gzf == NULL) { errFatal("spAnimate::initPlugin","can't open vortex source database",SIMWORLD_INITERROR);exit(1); } - if (gzread(gzf,&numSets,sizeof(int)) != sizeof(int)) { errFatal("spAnimate::initPlugin","gzread numSets failed",SIMWORLD_INITERROR); } - if (gzread(gzf,&numTheta,sizeof(int)) != sizeof(int)) { errFatal("spAnimate::initPlugin","gzread numTheta failed",SIMWORLD_INITERROR); } - if (gzread(gzf,&numPhi,sizeof(int)) != sizeof(int)) { errFatal("spAnimate::initPlugin","gzread numPhi failed",SIMWORLD_INITERROR); } - mTheta.resize(numTheta); - mPhi.resize(numPhi); - if (gzread(gzf,&mTheta[0],numTheta*sizeof(Real)) != (int)(numTheta*sizeof(Real))) { errFatal("spAnimate::initPlugin","gzread theta failed",SIMWORLD_INITERROR); } - if (gzread(gzf,&mPhi[0],numPhi*sizeof(Real)) != (int)(numPhi*sizeof(Real))) { errFatal("spAnimate::initPlugin","gzread phi failed",SIMWORLD_INITERROR); } - mTrans = new VortexDBSet(gzf, numPhi, numTheta, sizeFlags); - mRot = new VortexDBSet(gzf, numPhi, numTheta, sizeFlags); - - mSetDir.resize(numSets); - mSetVort.resize(numSets); - for (int i=0;i<numSets;i++) - { - VortexDBSet *cset = ((i & 1) == 0) ? mTrans : mRot; - if (gzread(gzf,&mSetDir[i][0],sizeof(Vec3)) != sizeof(Vec3)) { errFatal("spAnimate::initPlugin","gzread u0 failed",SIMWORLD_INITERROR); } - - mSetVort[i] = vector<Vec3>(cset->numPoints); - for (int j=0;j<cset->numPoints;j++) - if (gzread(gzf,&mSetVort[i][j][0],sizeof(Vec3)) != sizeof(Vec3)) { errFatal("spAnimate::initPlugin","gzread data failed",SIMWORLD_INITERROR); } - } - mTrans->mNorm = norm(mSetDir[0]); - mRot->mNorm = norm(mSetDir[1]); - - gzclose(gzf); - debMsg("VortexDB::VortexDB()", "VDB loaded, " << numSets << " sets"); - } - ~VortexDB() - { - delete mRot; - delete mTrans; - } - - // map confined vorticity to simulation grid - void project(FlagGrid *flags, Grid<Vec3>* dst, const ObjectTransformation& trafo, const Vec3& uvel) - { - Mat4 matRotBack = trafo.rotMat; - matRotBack.transpose(); - Vec3 uv = trafo.rotMat * uvel; - Vec3 urot = matRotBack * trafo.rotVel; - cout << "linear " << uv << " (unrot " << uvel << ") rot " << urot << " (unrot " << trafo.rotVel << ")" <<endl; - - mTrans->mapdown(flags, dst, matRotBack, trafo.pos, uv, mSetVort, mPhi, mTheta, mSetDir, trafo.center, trafo.scale); - mRot->mapdown(flags, dst, matRotBack, trafo.pos, urot, mSetVort, mPhi, mTheta, mSetDir, trafo.center, trafo.scale); - } - - private: - vector<Real> mPhi, mTheta; - vector<vector<Vec3> > mSetVort; - vector<Vec3> mSetDir; - VortexDBSet *mRot, *mTrans; -}; - -// Helper class for loading animation data -class AnimFrame -{ - public: - AnimFrame(ifstream& ifs) - { - Real rx,ry,rz; Mat4 mat; - ifs >> time >> pos.x >> pos.y >> pos.z >> rx >> ry >> rz; ifs.ignore(1000,'\n'); - rot = Quat(rx*M_PI/180.,ry*M_PI/180.,rz*M_PI/180.); - } - - Vec3 pos, pvel, rvel; - Quat rot; - Real time; -}; - -//***************************************************************************** -// load and playback animation -class spAnimate : public SolverPlugin { - public: - spAnimate() : - SolverPlugin(),mFrames(),mTime(0.),mVDB(NULL), mIflow1(), mIflow2() - { }; - ~spAnimate() { - if (mVDB!=NULL) delete mVDB; - }; - - // init plugin, return failure - virtual bool parseParams(const ParamSet& params) { - mNameSrc = params.FindOneString("flags-src","unnamed"); // static background flags - mNameDst = params.FindOneString("flags-dst","flags"); // flag grid - mDistSrc = params.FindOneString("ndist-src",""); // static background distance field - mDistDst = params.FindOneString("ndist-dst",""); // distance field - mVortSrc = params.FindOneString("vort-src",""); // static background ABL source - mVortDst = params.FindOneString("vort-dst",""); // ABL source field - mVortFile = params.FindOneString("vort-file",""); // vortex DB filename - mDoForces = params.FindOneInt("do-forces",1)!=0; // enforce velocities on the moving object boundary - mNameVel = params.FindOneString("vel","vel-curr"); // velocity field - mFile = params.FindOneString("file","no-filename"); // animation control file - mAnimParams = params.FindOneString("params","unnamed"); // params where animated object is stored - return true; - }; - virtual bool initPlugin() { - - // load animation stream from text file - ifstream ifs (mFile.c_str()); - if (!ifs) { - errMsg("spAnimate::initPlugin","can't load animation file !"); return false; - } - int numFrames, numInflows; - Vec3 lastPos(0.), lastAxis(0.); - Real delta, lastTime(0.); - ifs >> numFrames; ifs.ignore(1000,'\n'); - ifs >> delta; ifs.ignore(1000,'\n'); - ifs >> mScale; ifs.ignore(1000,'\n'); - ifs >> mRotCenter.x >> mRotCenter.y >> mRotCenter.z; ifs.ignore(1000,'\n'); - // obtain frame data - for (int n=0;n<numFrames;n++) - { - // load frame, calculate speed by finite differences - AnimFrame frame(ifs); - frame.time *= delta; - frame.pvel = (frame.pos - lastPos) / (frame.time - lastTime); - - Vec3 axis = frame.rot.getAxis(); - frame.rvel = (axis - lastAxis) / (frame.time - lastTime); - mFrames.push_back(frame); - lastPos = frame.pos; - lastAxis = axis; - lastTime = frame.time; - } - mFrames[0].pvel = mFrames[1].pvel; - mFrames[0].rvel = mFrames[1].rvel; - - // load inflow box information - ifs >> numInflows; ifs.ignore(1000,'\n'); - for (int n=0;n<numInflows;n++) - { - Vec3 b1,b2; - ifs >> b1.x >> b1.y >> b1.z >> b2.x >> b2.y >> b2.z; ifs.ignore(1000,'\n'); - mIflow1.push_back(b1); - mIflow2.push_back(b2); - } - // load vortex database - if (!mVortFile.empty()) - mVDB = new VortexDB(mVortFile,vec2R(mpPlParams->getFluidSolver()->getGridFlags()->getSize())); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spAnimate","step "<<dt); - - // linear interpolatation of the animation frames - Real multiplier = mpPlParams->getMultiplier(); - if (multiplier < 1) multiplier = 1; - dt /= multiplier; - mTime += dt; - vector<AnimFrame>::const_iterator f1=mFrames.begin(), f2=mFrames.end()-1, it=mFrames.begin(); - for (;it != mFrames.end();++it) - { - if (it->time <= mTime && it->time > f1->time) f1 = it; - if (it->time >= mTime && it->time < f2->time) f2 = it; - } - Real a2 = (f1->time == f2->time) ? 0 : (mTime - f1->time) / (f2->time - f1->time), a1=1.-a2; - - // setup transformation matrix - Vec3 finalPos = f1->pos * a1 + f2->pos * a2; - Quat finalQ = Quat::slerp(f1->rot, f2->rot, a2); - - ObjectTransformation trafo(0.); - Vec3 ax = finalQ.getAxis() * 180./M_PI; - //printf("QUAT %g %g %g %g\nAXIS %g %g %g\n",finalQ.x,finalQ.y,finalQ.z,finalQ.w,ax.x,ax.y,ax.z); - trafo.rotMat = finalQ.getRotMat(); - trafo.pos = finalPos; - trafo.posVel = f2->pvel; - trafo.rotVel = f2->rvel; - trafo.scale = mScale; - trafo.center = mRotCenter; - cout << "pvel : " << trafo.posVel << endl; - - // log data for output in pbrt files - /*Vec3 rpos = (finalPos * mDomainSize) + mDomain0; - ostringstream str; - Real angle = normalize(ax); - if (angle < 1e-8) ax = Vec3(0.,1.,0.); - str << rpos.x << " " << rpos.y << " " << rpos.z << " " << ax.x << " " << ax.y << " " << ax.z << " " << -angle; - mpPlParams->getFluidSolver()->setDebugBuffer(str.str());*/ - - // get grids - FlagGrid* src = mpPlParams->getGridInt(mNameSrc); - FlagGrid* dst = mpPlParams->getGridInt(mNameDst); - FlagGrid* obs = ddfWorldFindSolver(mAnimParams)->getGridFlags(); - Grid<Real>* distsrc = mDistSrc.empty() ? NULL : mpPlParams->getGridReal(mDistSrc); - Grid<Real>* distdst = mDistDst.empty() ? NULL : mpPlParams->getGridReal(mDistDst); - Grid<Real>* distobs = mDistSrc.empty() ? NULL : ddfWorldFindSolver(mAnimParams)->getParams()->getGridReal(mDistSrc); - Grid<Vec3>* vortsrc = mVortSrc.empty() ? NULL : mpPlParams->getGridVec3(mVortSrc); - Grid<Vec3>* vortdst = mVortDst.empty() ? NULL : mpPlParams->getGridVec3(mVortDst); - Grid<Vec3>* vel = mpPlParams->getGridVec3(mNameVel); - - cout << "time " << mTime << " pos " << trafo.pos << endl; - //cout << "lookup bounds: " << trafo.pos * vec2R(obs->getSize()) << " to " << mScale * vec2R(obs->getSize()) + trafo.pos * vec2R(obs->getSize()) << endl; - - // copy static fields - goCopyGrid<int>(dst,src); - if (distsrc != NULL) goCopyGrid<Real>(distdst,distsrc); - if (vortsrc != NULL) goCopyGrid<Vec3>(vortdst,vortsrc); - - // set flags & velocities inside cells - opSetMovingObstacleBC(dst, vel, obs, trafo, dt, false, distobs, distdst, mIflow1, mIflow2, mDoForces); - - // query vortex DB - Vec3 uvel = -trafo.posVel * vec2R(dst->getSize()) ;//+ mpPlParams->mU0 ; - if (mVDB != NULL) - mVDB->project(dst, vortdst, trafo,uvel); - - // initialize obstacle boundaries with velocities - if (mDoForces) { - FOR_IJK_GRID_BND(dst,1) { - if (!fgIsObstacle( dst->getGlobal(i,j,k) ) ) { - if (fgIsObstacle( dst->getGlobal(i-1,j,k) ) && !fgIsObstacle( src->getGlobal(i-1,j,k) ) ) { - vel->getGlobal(i,j,k)[0] = vel->getGlobal(i-1,j,k)[0]; - } - if (fgIsObstacle( dst->getGlobal(i,j-1,k) ) && !fgIsObstacle( src->getGlobal(i,j-1,k) )) { - vel->getGlobal(i,j,k)[1] = vel->getGlobal(i,j-1,k)[1]; - } - if(gDim==3 && (fgIsObstacle( dst->getGlobal(i,j,k-1) ) && !fgIsObstacle( src->getGlobal(i,j,k-1) ) )) { - vel->getGlobal(i,j,k)[2] = vel->getGlobal(i,j,k-1)[2]; - } - } - } } - - return true; - }; - - protected: - // grid access - std::string mNameSrc, mNameDst, mNameVel, mAnimParams, mFile, mDistSrc, mDistDst, mVortSrc, mVortDst, mVortFile; - vector<AnimFrame> mFrames; - Real mTime, mScale; - Vec3 mRotCenter; - VortexDB* mVDB; - vector<Vec3> mIflow1, mIflow2; - bool mDoForces; -}; - -//***************************************************************************** -// create plugins -SolverPlugin* MakeAnimPlugin(std::string name) { - if(name.compare( "set-moving-obs-bcs" )==0) { - return new spSetMovingObstacleBC; - } else if(name.compare( "animate" )==0) { - return new spAnimate; - } - - return NULL; -} - -} diff --git a/intern/smoke/intern/source/conjugategrad.cpp b/intern/smoke/intern/source/conjugategrad.cpp deleted file mode 100644 index 042469e093f..00000000000 --- a/intern/smoke/intern/source/conjugategrad.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Conjugate Gradient solver classes, used in Pressure solve - * - *****************************************************************************/ - -#include "globals.h" -#include "vectorbase.h" -#include "grid.h" -#include "operators.h" -#include "conjugategrad.h" - -// oreconditioning methods: -// 1 = incomplete cholesky ala wavelet turbulence (needs 4 additional grids) -// 2 = modified IC ala Bridson (1 add. grid) - -namespace DDF { - -void InitPreconditionIncompCholesky(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 - - if(!A0 || !Ai || !Aj || !Ak) { - errFatal("InitPreconditioner","method=1 but grids PCA0,j,k not set!", SIMWORLD_GRIDERROR); - return; - } - FOR_IJK_GRID(A0) { - A0->getGlobal(i,j,k) = orgA0->getGlobal(i,j,k); - Ai->getGlobal(i,j,k) = orgAi->getGlobal(i,j,k); - Aj->getGlobal(i,j,k) = orgAj->getGlobal(i,j,k); - Ak->getGlobal(i,j,k) = orgAk->getGlobal(i,j,k); - } - - if(0) FOR_IJK_GRID(flags) { // DEBUG - if(0) debMsg("DEB_INCOMP_CHOL mat","at "<<PRINT_IJK<<" "<< - A0->getGlobal(i,j,k)<<" "<< Ai->getGlobal(i,j,k)<<" "<< Aj->getGlobal(i,j,k)<<" "<< Ak->getGlobal(i,j,k)<<" " ); - printf("ORGMAT debug at %d,%d,%d = %f, %f, %f, %f \n", i,j,k, - A0->getGlobal(i,j,k), Ai->getGlobal(i,j,k), Aj->getGlobal(i,j,k), Ak->getGlobal(i,j,k) ); - } // DEBUG - - FOR_IJK_GRID(flags) { - if (fgIsFluid(flags->getGlobal(i,j,k)) ) { - A0->getGlobal(i,j,k) = sqrt(A0->getGlobal(i,j,k)); - - // 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->getGlobal(i,j,k); - Ai->getGlobal(i,j,k) *= invDiagonal; - Aj->getGlobal(i,j,k) *= invDiagonal; - Ak->getGlobal(i,j,k) *= 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->getGlobal(i+1,j,k) -= Ai->getGlobal(i,j,k) * Ai->getGlobal(i,j,k); - A0->getGlobal(i,j+1,k) -= Aj->getGlobal(i,j,k) * Aj->getGlobal(i,j,k); - A0->getGlobal(i,j,k+1) -= Ak->getGlobal(i,j,k) * Ak->getGlobal(i,j,k); - } - } - - // invert A0 for faster computation later - FOR_IJK_GRID(flags) { - if ( (fgIsFluid(flags->getGlobal(i,j,k)) ) && - (A0->getGlobal(i,j,k) > 0.) ) - { - // invert - A0->getGlobal(i,j,k) = 1. / A0->getGlobal(i,j,k); - } - } - - if(0) FOR_IJK_GRID(flags) { // DEBUG - if(0) debMsg("DEB_INCOMP_CHOL mat","at "<<PRINT_IJK<<" "<< - A0->getGlobal(i,j,k)<<" "<< Ai->getGlobal(i,j,k)<<" "<< Aj->getGlobal(i,j,k)<<" "<< Ak->getGlobal(i,j,k)<<" " ); - printf("debug at %d,%d,%d = %f, %f, %f, %f \n", i,j,k, - A0->getGlobal(i,j,k), Ai->getGlobal(i,j,k), Aj->getGlobal(i,j,k), Ak->getGlobal(i,j,k) ); - } // DEBUG - //exit(1); -}; - - - -void InitPreconditionModifiedIncompCholesky2(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 - // simplify access to grids... - Grid<Real> &Aprecond = *_A0; - Grid<Real> &A0 = *_orgA0; - Grid<Real> &Ai = *_orgAi; - Grid<Real> &Aj = *_orgAj; - Grid<Real> &Ak = *_orgAk; - - if(!_A0) { - errFatal("InitPreconditioner","method=2 but grids PCA0 not set!", SIMWORLD_GRIDERROR); - return; - } - - GridOpTouchMemory<Real>(NULL, _A0, 0.); - - const Real tau = 0.97; - const Real sigma = 0.25; - FOR_IJK_GRID(flags) { - if (fgIsFluid(flags->getGlobal(i,j,k)) ) { - // 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 ); - //debMsg("Aprecond","at "<<PRINT_IJK<<" "<<Aprecond(i,j,k) ); - // */ - } - } -}; - - - -void InitPrecondition(int method, 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) -{ - - //debMsg("InitPrecondition","Method="<<method); - - switch(method) { - case 1: - InitPreconditionIncompCholesky(Flags, A0,Ai,Aj,Ak , orgA0,orgAi,orgAj,orgAk ); - break; - case 2: - InitPreconditionModifiedIncompCholesky2(Flags, A0,Ai,Aj,Ak , orgA0,orgAi,orgAj,orgAk ); - break; - //default: - // nothing to do ... goInitPreconditionID(mpSearch, mpResidual, mpFlags ); - }; - -}; - - - - - -void ApplyPreconditionIncompCholesky(Grid<Real> *dst, Grid<Real> *Var1, 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) { - // debug out - if(0) { FOR_IJK_GRID(dst) { - printf("apply1 at %d,%d,%d = %f, %f \n", i,j,k, dst->getGlobal(i,j,k)*1000., Var1->getGlobal(i,j,k)*1000. ); - } } // DEBUG out - - FOR_IJK_GRID(dst) { - if (fgIsFluid(flags->getGlobal(i,j,k)) ) { - // forward substitution - dst->getGlobal(i,j,k) = ( Var1->getGlobal(i,j,k) - - ( dst->getGlobal(i-1, j, k) * Ai->getGlobal(i-1, j,k) ) - - ( dst->getGlobal(i, j-1, k) * Aj->getGlobal(i, j-1,k) ) - - ( dst->getGlobal(i, j, k-1) * Ak->getGlobal(i,j, k-1) ) ) - * A0->getGlobal(i,j,k) ; // */ - } - } - - FOR_IJKREV_GRID(dst) { - if (fgIsFluid(flags->getGlobal(i,j,k)) ) { - // backw. substitution - dst->getGlobal(i,j,k) = ( dst->getGlobal(i,j,k) - - ( dst->getGlobal(i+1,j,k) * Ai->getGlobal(i+0,j,k) ) - - ( dst->getGlobal(i,j+1,k) * Aj->getGlobal(i,j+0,k) ) - - ( dst->getGlobal(i,j,k+1) * Ak->getGlobal(i,j,k+0) ) ) - * A0->getGlobal(i,j,k) ;// */ - } - } - - // debug out - if(0) { FOR_IJK_GRID(dst) { - printf("apply2 at %d,%d,%d = %f, %f \n", i,j,k, dst->getGlobal(i,j,k)*1000., Var1->getGlobal(i,j,k)*1000. ); - } } // DEBUG out -}; - - -void ApplyPreconditionModifiedIncompCholesky2(Grid<Real> *dst, Grid<Real> *Var1, FlagGrid *flags, - Grid<Real> *Aprecond, Grid<Real> *Aunused1, Grid<Real> *Aunused2, Grid<Real> *Aunused3, - Grid<Real> *orgA0, Grid<Real> *orgAi, Grid<Real> *orgAj, Grid<Real> *orgAk) { - - FOR_IJK_GRID(dst) { - if (fgIsFluid(flags->getGlobal(i,j,k)) ) { - const Real precond = Aprecond->getGlobal(i,j,k); - // forward substitution - dst->getGlobal(i,j,k) = ( Var1->getGlobal(i,j,k) - - ( dst->getGlobal(i-1, j, k) * orgAi->getGlobal(i-1, j,k) *precond ) - - ( dst->getGlobal(i, j-1, k) * orgAj->getGlobal(i, j-1,k) *precond ) - - ( dst->getGlobal(i, j, k-1) * orgAk->getGlobal(i,j, k-1) *precond ) ) - * precond ; // */ - } - } - - FOR_IJKREV_GRID(dst) { - if (fgIsFluid(flags->getGlobal(i,j,k)) ) { - const Real precond = Aprecond->getGlobal(i,j,k); - // backw. substitution - dst->getGlobal(i,j,k) = ( dst->getGlobal(i,j,k) - - ( dst->getGlobal(i+1,j,k) * orgAi->getGlobal(i+0,j,k) *precond ) - - ( dst->getGlobal(i,j+1,k) * orgAj->getGlobal(i,j+0,k) *precond ) - - ( dst->getGlobal(i,j,k+1) * orgAk->getGlobal(i,j,k+0) *precond ) ) - * precond ;// */ - } - } -}; - - -void ApplyPrecondition(int method, Grid<Real> *Dst, Grid<Real> *Var1, 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) { - - // debMsg("ApplyPrecondition","Method="<<method); - switch(method) { - case 1: - ApplyPreconditionIncompCholesky(Dst, Var1, Flags, A0,Ai,Aj,Ak , orgA0,orgAi,orgAj,orgAk ); - break; - case 2: - ApplyPreconditionModifiedIncompCholesky2(Dst, Var1, Flags, A0,Ai,Aj,Ak , orgA0,orgAi,orgAj,orgAk ); - break; - default: - // id, means PC "off" - goPreconditionID(Dst, Var1, Flags); - } -} - -}; // DDF diff --git a/intern/smoke/intern/source/conjugategrad.h b/intern/smoke/intern/source/conjugategrad.h deleted file mode 100644 index 7591e1709c8..00000000000 --- a/intern/smoke/intern/source/conjugategrad.h +++ /dev/null @@ -1,505 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Conjugate Gradient solver classes, used in Pressure solve - * - *****************************************************************************/ - -#ifndef DDF_CONJUGATEGRADIENT_H -#define DDF_CONJUGATEGRADIENT_H - -#include "vectorbase.h" -#include "grid.h" -#include "operators.h" - - -namespace DDF { - -static const bool CG_DEBUG = false; - -// helper functions from conjugategrad.cpp -void InitPrecondition(int method, 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); -void ApplyPrecondition(int method, Grid<Real> *Dst, Grid<Real> *Var1, 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); - - -// hard coded laplacian operator without stored matix -class goApplyLacplace : public GridOpBase{ - public: - goApplyLacplace(Grid<Real> *Dst, Grid<Real> *Src, FlagGrid *Flags) : GridOpBase() { - mpDst = Dst; mpSrc = Src; - mpFlags = Flags; - applyOperatorToGrids(this); - }; - ~goApplyLacplace() { }; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - gaSrc.gridAccInit(mpSrc, AM_READ, gaCalls); - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - if(!fgIsFluid(getFlagAcc()(i,j,k)) ) { - gaDst.write(i,j,k) = gaSrc(i,j,k); - return; - } - - gaDst.write(i,j,k) = LAPLACEFAC * gaSrc(i,j,k) - - gaSrc(i-1,j,k) - gaSrc(i+1,j,k) - - gaSrc(i,j-1,k) - gaSrc(i,j+1,k) -#if DDF_DIMENSION==3 - - gaSrc(i,j,k-1) - gaSrc(i,j,k+1) -#endif // DDF_DIMENSION==3 - ; - } - void getRidOfWarning() { }; - void reduce(goApplyLacplace &op) { getRidOfWarning(); } - protected: - Grid<Real> *mpDst, *mpSrc; - GridAccessor<Real,0> gaDst; - GridAccessor<Real,1> gaSrc; -}; // goApplyLacplace - - - -//***************************************************************************** - -// compute residual (init) and add to sigma -class goInitSigma : public GridOpBase{ - public: - goInitSigma(Grid<Real> *Dst, Grid<Real> *Var1, Grid<Real> *Var2, FlagGrid *Flags, Real &set_sigma) : - GridOpBase() { - mpDst = Dst; // residual - mpVar1 = Var1; // rhs - mpVar2 = Var2; // temp - mpFlags = Flags; - applyOperatorToGrids( this ); - set_sigma = mSigma; - } - ~goInitSigma() {}; - virtual void resetVariables() { - mSigma = 0.; - } - void buildCallList() { - gaResid.gridAccInit( mpDst, AM_WRITE, gaCalls); - gaRhs.gridAccInit( mpVar1, AM_READ, gaCalls); - gaTemp.gridAccInit( mpVar2, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - const Real res = gaRhs(i,j,k) - gaTemp(i,j,k); - gaResid.write(i,j,k) = res; - - // only compute residual in fluid region - if(!fgIsFluid(getFlagAcc()(i,j,k)) ) return; - mSigma += res*res; - } - void reduce(goInitSigma &op) { - //debMsg("goInitSigma","reduce mSigma"<<mSigma<<" += "<<op.mSigma); - mSigma += op.mSigma; - } - protected: - Real mSigma; - Grid<Real> *mpDst, *mpVar1, *mpVar2; - GridAccessor<Real,0> gaResid, gaRhs, gaTemp; -}; // goInitSigma */ - - -class goUpdateSolution : public GridOpBase{ - public: - goUpdateSolution(Grid<Real> *Dst, Grid<Real> *Var1, FlagGrid *Flags, Real factor) : GridOpBase() { - mpDst = Dst; // pressure or residual - mpSrc = Var1; // update vector - mpFlags = Flags; - mFactor = factor; - applyOperatorToGrids( this ); - } - ~goUpdateSolution() {}; - void buildCallList() { - gaDst.gridAccInit( mpDst, AM_WRITE, gaCalls); - gaSrc.gridAccInit( mpSrc, AM_READ, gaCalls); - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - gaDst.write(i,j,k) += mFactor*gaSrc(i,j,k); - } - void reduce(goUpdateSolution &op) { }; - protected: - Real mFactor; - Grid<Real> *mpDst; - Grid<Real> *mpSrc; - GridAccessor<Real,0> gaDst; - GridAccessor<Real,0> gaSrc; -}; // goUpdateSolution */ - -class goUpdateSearchVec : public GridOpBase{ - public: - goUpdateSearchVec(Grid<Real> *Dst, Grid<Real> *Var1, FlagGrid *Flags, Real factor) : GridOpBase() { - mpDst = Dst; // pressure or residual - mpSrc = Var1; // update vector - mpFlags = Flags; - mFactor = factor; - applyOperatorToGrids( this ); - } - ~goUpdateSearchVec() {}; - void buildCallList() { - gaDst.gridAccInit( mpDst, AM_WRITE, gaCalls); - gaSrc.gridAccInit( mpSrc, AM_READ, gaCalls); - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - gaDst.write(i,j,k) = gaSrc(i,j,k) + mFactor*gaDst(i,j,k); - } - void reduce(goUpdateSearchVec &op) { }; - protected: - Real mFactor; - Grid<Real> *mpDst, *mpSrc; - GridAccessor<Real,0> gaDst, gaSrc; -}; // goUpdateSearchVec */ - - - -// currently only copies from source to dest... -class goPreconditionID : public GridOpBase{ - public: - goPreconditionID(Grid<Real> *Dst, Grid<Real> *Var1, FlagGrid *Flags) : GridOpBase() { - mpDst = Dst; - mpVar1 = Var1; - mpFlags = Flags; - applyOperatorToGrids( this ); - } - ~goPreconditionID() {}; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - gaVar1.gridAccInit(mpVar1, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - gaDst.write(i,j,k) = gaVar1(i,j,k); - } - void reduce(goPreconditionID &op) { } - protected: - Grid<Real> *mpDst, *mpVar1; - GridAccessor<Real,0> gaDst, gaVar1; -}; // goPreconditionID */ - - - -//***************************************************************************** -// compute the laplacian of src with right hand side rhs into the tmp grid -// for reference to CG solver -class goJacobiSolver : public GridOpBase{ - public: - goJacobiSolver(Grid<Real> *Dst, Grid<Real> *Src, Grid<Real> *Rhs, FlagGrid *Flags) : GridOpBase() { - mpDst = Dst; - mpSrc = Src; - mpRhs = Rhs; - mpFlags = Flags; - applyOperatorToGrids(this); - }; - ~goJacobiSolver() {}; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - gaRhs.gridAccInit(mpRhs, AM_READ, gaCalls); - gaSrc.gridAccInit(mpSrc, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - //debMsg("OPL","at "<<PRINT_IJK<<" dst="<<gaDst.write(i,j,k)<<" rhs="<<gaRhs(i,j,k)<<", src: "<< gaSrc(i-1,j,k) <<" "<< gaSrc(i+1,j,k)<<" "<< gaSrc(i,j-1,k) <<" "<< gaSrc(i,j+1,k) ); - if(fgIsObstacle(getFlagAcc()(i,j,k)) ) return; - gaDst.write(i,j,k) = ( gaRhs(i,j,k) + - + gaSrc(i-1,j,k) + gaSrc(i+1,j,k) - + gaSrc(i,j-1,k) + gaSrc(i,j+1,k) -#if DDF_DIMENSION==3 - + gaSrc(i,j,k-1) + gaSrc(i,j,k+1) -#endif // DDF_DIMENSION==3 - ) * (1./LAPLACEFAC); - } - - void reduce(goJacobiSolver &op) { } - - protected: - Grid<Real> *mpDst, *mpRhs, *mpSrc; - GridAccessor<Real,0> gaDst; - GridAccessor<Real,0> gaRhs; - GridAccessor<Real,1> gaSrc; -}; // goJacobiSolver - - - -//***************************************************************************** -// compute max values in grid (no position) -template<class Value> -class goCompMaxSimple : public GridOpBase{ - public: - goCompMaxSimple(Grid<Value> *Var, FlagGrid *Flags) : GridOpBase() { - mpVar = Var; - mpFlags = Flags; - applyOperatorToGrids( this ); - }; - ~goCompMaxSimple() {}; - virtual void resetVariables() { - mMaxAbs = -1e10; - mMax = 0.; - } - void buildCallList() { - gaVar.gridAccInit(mpVar, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - const Value s = gaVar(i,j,k); - const Real sabs = normHelper(s); - - if(sabs>mMaxAbs) { - mMaxAbs = sabs; - mMax = s; - //mMaxPos = nVec3i(i,j,k); - } - } - - void reduce(goCompMaxSimple &op) { - if(op.mMaxAbs>mMaxAbs) { - mMaxAbs = op.mMaxAbs; - mMax = op.mMax; - //mMaxPos = op.mMaxPos; - } - } - - Value getMax() { return mMax; } - Real getMaxAbs() { return mMaxAbs; } - //Real getMaxPosValue() { return mMaxPos; } - string toString() { - std::ostringstream out; - out << " max="<<mMax<<" ("<<mMaxAbs<<") "; - return out.str(); - } - protected: - //int outcnt; - Real mMaxAbs; - Value mMax; - Grid<Value> *mpVar; - GridAccessor<Real,0> gaVar; -}; // goCompMaxSimple - -//***************************************************************************** - -// basic interface -class GridCgInterface { - public: - GridCgInterface() : mUseResNorm(true) {}; - virtual ~GridCgInterface() {}; - - // solving functions - virtual bool iterate() = 0; - virtual void solve(int maxIter) = 0; - - // precond - virtual void setPreconditioner(int method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) = 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; - - void setUseResNorm(bool set) { mUseResNorm = set; } - - protected: - - // use norm of residual, or max value for threshold? - bool mUseResNorm; -}; - -//! run single iteration of the cg solver -// the template argument determines the type of matrix multiplication, -// typically a goApplyMatrix object (above), 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, FlagGrid* flags, Grid<Real>* tmp, - Grid<Real> *A0=NULL, Grid<Real> *Ai=NULL, Grid<Real> *Aj=NULL, Grid<Real> *Ak=NULL, - // optional grids that may be used in the apply-matrix class during matrix myultiplication - // used eg for surface tension - Grid<Real> *_optionalReal = NULL, Grid<Vec3> *_optionalVec = NULL ) : - GridCgInterface(), - mInited(false), mIterations(0), - mpDst(dst), mpRhs(rhs), mpResidual(residual), - mpSearch(search), mpFlags(flags), mpTmp(tmp), - mpA0(A0), mpAi(Ai), mpAj(Aj), mpAk(Ak), - mPcMethod(0), mpPCA0(A0), mpPCAi(Ai), mpPCAj(Aj), mpPCAk(Ak), - mSigma(0.), - mAccuracy(gVecEpsilon), mResNorm(1e20) - { - if(0) debMsg("PB-CG-Norms","init p"<<sqrt( DDF::GridOpNormNosqrt(mpDst, mpFlags).getValue() ) << - " rhs"<<sqrt( DDF::GridOpNormNosqrt(mpRhs, mpFlags).getValue() ) << " search"<<sqrt( DDF::GridOpNormNosqrt(mpSearch, mpFlags).getValue() ) << - " res"<<sqrt( DDF::GridOpNormNosqrt(mpResidual, mpFlags).getValue() ) << " tmp"<<sqrt( DDF::GridOpNormNosqrt(mpTmp, mpFlags).getValue() )<< - " sigma="<<mSigma ); // debug - - GridOpTouchMemory<Real>(NULL, dst, 0.); - GridOpTouchMemory<Real>(NULL, residual, 0.); - GridOpTouchMemory<Real>(NULL, search, 0.); - GridOpTouchMemory<Real>(NULL, tmp, 0.); - optionalReal = _optionalReal; - optionalVec = _optionalVec; - } - - void doInit() { - mInited = true; - - InitPrecondition(mPcMethod, mpFlags, mpPCA0,mpPCAi,mpPCAj,mpPCAk , mpA0,mpAi,mpAj,mpAk); - - // old APPLYMAT(mpTmp, mpDst, mpA0,mpAi,mpAj,mpAk, mpFlags, optionalReal, optionalVec); - // old goInitSigma(mpResidual, mpRhs, mpTmp, mpFlags, mSigma); - // old ApplyPrecondition(mPcMethod, mpSearch, mpResidual, mpFlags, mpPCA0,mpPCAi,mpPCAj,mpPCAk ); - // old GridOpNormNosqrt(mpResidual, mpFlags, &mResNorm); - - goCopyGrid<Real>(mpResidual, mpRhs); // p=0, residual = b - - // tmp == apply preconditioner(residual) - ApplyPrecondition(mPcMethod, mpTmp, mpResidual, mpFlags, mpPCA0,mpPCAi,mpPCAj,mpPCAk, mpA0,mpAi,mpAj,mpAk ); - - goCopyGrid<Real>(mpSearch, mpTmp); // search = tmp - - Real dotProdValue = 0.; // sigma = dot(tmp, residual) - goDotProd(mpTmp, mpResidual, mpFlags, &dotProdValue); - mSigma = dotProdValue; - - if(CG_DEBUG) debMsg("PB-CG-Norms","init p"<<sqrt( DDF::GridOpNormNosqrt(mpDst, mpFlags).getValue() ) << - " rhs"<<sqrt( DDF::GridOpNormNosqrt(mpRhs, mpFlags).getValue() ) << " search"<<sqrt( DDF::GridOpNormNosqrt(mpSearch, mpFlags).getValue() ) << - " res"<<sqrt( DDF::GridOpNormNosqrt(mpResidual, mpFlags).getValue() ) << " tmp"<<sqrt( DDF::GridOpNormNosqrt(mpTmp, mpFlags).getValue() )<< - " sigma="<<mSigma ); // debug - } - ~GridCg() { - }; - - //! perform cg iteration - bool iterate() { - if(!mInited) doInit(); - - //debMsg("CG","Iterate "<<mIterations<<" "<<mResNorm<<"/"<<mAccuracy); - //if(mResNorm<mAccuracy) return false; - - mIterations++; - - // create matrix application operator passed as template argument, - // this could reinterpret the mpA pointers (not so clean right now) - // tmp = applyMat(search) - APPLYMAT(mpTmp, mpSearch, mpA0,mpAi,mpAj,mpAk, mpFlags, optionalReal, optionalVec); - - Real dotProdTS; // alpha = sigma/dot(tmp, search) - goDotProd(mpTmp, mpSearch, mpFlags, &dotProdTS); - Real alpha = 0.; - if(fabs(dotProdTS)>0.) alpha = mSigma / dotProdTS; - - goUpdateSolution(mpDst, mpSearch, mpFlags, alpha); // dst += search * alpha - goUpdateSolution(mpResidual, mpTmp , mpFlags, -alpha); // residual += tmp * -alpha - ApplyPrecondition(mPcMethod, mpTmp, mpResidual, mpFlags, mpPCA0,mpPCAi,mpPCAj,mpPCAk, mpA0,mpAi,mpAj,mpAk ); - - // compute norm of the residual? - if(this->mUseResNorm) { - GridOpNormNosqrt(mpResidual, mpFlags, &mResNorm); - } else { - // TODO test... - goCompMaxSimple<Real> resMax = goCompMaxSimple<Real>(mpResidual, mpFlags); - mResNorm = resMax.getMaxAbs(); - } - if(0 || mIterations % 10 == 9) debMsg("GridCg","Iteration i="<<mIterations<<", resNorm="<<mResNorm<<" accuracy="<<mAccuracy ); - - // abort here to safe some work... - if(mResNorm<mAccuracy) return false; - - Real sigmaNew; // sigma_new = dot(tmp, residual) - goDotProd(mpTmp, mpResidual, mpFlags, &sigmaNew); - // abort here? - - Real beta = sigmaNew / mSigma; - // search = tmp + beta * srch - goUpdateSearchVec(mpSearch, mpTmp, mpFlags, beta); - - if(CG_DEBUG) debMsg("PB-Cg","iter2 i="<<mIterations<<" sigma="<<mSigma<<" alpha="<<alpha<<" beta="<<beta<<" "); - mSigma = sigmaNew; - - if(CG_DEBUG) debMsg("PB-CG-Norms","p"<<sqrt( DDF::GridOpNormNosqrt(mpDst, mpFlags).getValue() ) <<" search"<<sqrt( DDF::GridOpNormNosqrt(mpSearch, mpFlags).getValue() ) - <<" res"<<sqrt( DDF::GridOpNormNosqrt(mpResidual, mpFlags).getValue() ) <<" tmp"<<sqrt( DDF::GridOpNormNosqrt(mpTmp, mpFlags).getValue() ) ); // debug - if(CG_DEBUG) debMsg("PB-CG-Norms","p"<<( DDF::GridOpNormNosqrt(mpDst, mpFlags).getValue() ) <<" search"<<( DDF::GridOpNormNosqrt(mpSearch, mpFlags).getValue() ) - <<" res"<<( DDF::GridOpNormNosqrt(mpResidual, mpFlags).getValue() ) <<" tmp"<<( DDF::GridOpNormNosqrt(mpTmp, mpFlags).getValue() ) ); // debug, no sqrt! - return true; - } - - void solve(int maxIter) { - for (int iter=0; iter<maxIter; iter++) { - if (!iterate()) iter=maxIter; - } - return; - } - - // init pointers, and copy values from "normal" matrix - void setPreconditioner(int method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) { - mPcMethod = method; - mpPCA0 = A0; - mpPCAi = Ai; - mpPCAj = Aj; - mpPCAk = Ak; - } - - // access - - 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>* mpDst; - Grid<Real>* mpRhs; - Grid<Real>* mpResidual; - Grid<Real>* mpSearch; - FlagGrid* mpFlags; - Grid<Real>* mpTmp; - - Grid<Real> *mpA0, *mpAi, *mpAj, *mpAk; - - // preconditioning method 0=off, 1=incomp cholesky - int mPcMethod; - // preconditioning grids - Grid<Real> *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk; - - // optional grids that may be used in the apply-matrix class during matrix myultiplication - // used eg for surface tension - Grid<Real> *optionalReal; - Grid<Vec3> *optionalVec; - - // sigma / residual - Real mSigma; - // accuracy of solver (max. residuum) - Real mAccuracy; - // norm of the residual - Real mResNorm; -}; // GridCg - - - -} // namespace DDF - -#endif // DDF_CONJUGATEGRADIENT_H - diff --git a/intern/smoke/intern/source/fileio.cpp b/intern/smoke/intern/source/fileio.cpp deleted file mode 100644 index abc6f4ae2cd..00000000000 --- a/intern/smoke/intern/source/fileio.cpp +++ /dev/null @@ -1,633 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Plugins for loading and saving grids - * - *****************************************************************************/ - -// lsdebug -#include "fluidsolver.h" -#include "solverplugin.h" -#include "paramset.h" -#include "vortexpart.h" -#include <fstream> -#include <zlib.h> - -// global debugging var - reuse frame nr for badtrioutput, used in spluginDumpMeshSurf -int g_meshSurfaceOutNr = 0; -using std::endl; - -namespace DDF { - -// Header for universal grid file -typedef struct { - char id[4]; - int dimX, dimY, dimZ; - int frames, elements, elementType, bytesPerElement, bytesPerFrame; -} UniversalHeader; - - -// print timing stats -class spluginPrintTimingStats : public SolverPlugin { - public: - spluginPrintTimingStats() : - SolverPlugin(), mSort(0) { }; - - ~spluginPrintTimingStats() { }; - - virtual bool parseParams(const ParamSet& params) { - mSort = params.FindOneInt("sort", mSort ); - return true; - }; - virtual bool initPlugin() { return true; }; - - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - - debMsg("spluginPrintTimingStats", mpPlParams->getFluidSolver()->getTimingStats(mSort) ); - - return true; - }; - - protected: - int mSort; -}; - - -/******************************************************************************/ -// helper functions for isosurface - - - -/******************************************************************************/ - -class spluginDumperBase : public SolverPlugin { - public: - spluginDumperBase() : SolverPlugin(), - mSimTime(-1.), mMaxFrames(-1), - mAnimOutCounter(0), mLastAniOutTime(0.), mStart(0.), mDumpAllFrames(false), mLastDumpTime(-10.), - mOutputOverrideName(""), mOutname("") - { }; - - ~spluginDumperBase() { }; - - bool parseParamsDumperBase(const ParamSet& params) { - mOutputOverrideName = params.FindOneString("override-name", mOutputOverrideName ); - mDumpAllFrames = params.FindOneInt("dump-all-frames", mDumpAllFrames ); - mStart = params.FindOneFloat("start-time", mStart ); - mMaxFrames = params.FindOneInt("max-frames", mMaxFrames ); - - // do we have a override name param? if yes use... - // otherwise take defaults from params - if(mOutputOverrideName.length()>0) - mOutname = mOutputOverrideName; - else - mOutname = this->mpPlParams->mAnimOutputFile; - - mLastAniOutTime = mStart; - return true; - } - - // check if current frame should be dumped (note, needs valid mSimTime!) - bool doDump() { - // dump each frame once - if(mDumpAllFrames) { - if(mLastDumpTime<mSimTime) { - mLastDumpTime = mSimTime; - return true; - } - return false; - } - - // dump according to timestep - return (mpPlParams->mTimestepAnim>0. && - (mSimTime-mLastAniOutTime > mpPlParams->mTimestepAnim) && - (!mpPlParams->getQuit()) ); - } - - void increaseDumpCounter() { - mAnimOutCounter++; - if (mMaxFrames>=0) { - // signal end - if (mAnimOutCounter>=mMaxFrames) mpPlParams->setQuit(true); - } - } - - protected: - Real mSimTime; - // max no of frames param - int mMaxFrames; - // no of output frames - int mAnimOutCounter; - // output time of last animation frame - Real mLastAniOutTime, mStart; - // dump each frame? - int mDumpAllFrames; - double mLastDumpTime; - - // override name from params? - std::string mOutputOverrideName, mOutname; -}; - - -template<class T> -class fsLoadData : public GridOpBase { - public: - fsLoadData(FlagGrid *flags, Grid<T> *dst, unsigned char *data, const UniversalHeader& head, bool setonlyFluid, int interpol) : - GridOpBase(), mpDst(dst),mpData(data), onlyFluid(setonlyFluid), mInterpolateWithBorder(interpol) { - mpFlags = flags; - mSizeRead = nVec3i(head.dimX, head.dimY, head.dimZ); - mSizeDst = mpFlags->getSize() -nVec3i(1,1,1); - mPageSize = head.bytesPerElement * head.dimX * head.dimY * head.dimZ; - mBytesPerElement = head.bytesPerElement; - applyOperatorToGridsSimple(this); - }; - ~fsLoadData() {} - - void resetVariables() { }; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - inline T getRaw (unsigned chunk); - - // load & safety check access of file data at i,j,k - inline T getFileData (int i, int j, int k) { - CLAMP(i, 0, mSizeRead[0]-1); - CLAMP(j, 0, mSizeRead[1]-1); - CLAMP(k, 0, mSizeRead[2]-1); - - if (gDim==2) k=0; - unsigned chunk = i + mSizeRead[0]*(j + mSizeRead[1]*k); - return getRaw(chunk); - } - - inline void operator() (int i, int j, int k) { - nVec3i src = nVec3i(i,j,k); - const nVec3i dst = nVec3i(i,j,k); - - if(mInterpolateWithBorder>-1) { - for(int l=0; l<gDim; l++) { - if(dst[l]<mInterpolateWithBorder) { - // keep - } else if(dst[l]>=mSizeDst[l]-mInterpolateWithBorder) { - // keep upper grid boundary as well - src[l] = mSizeRead[l]-1 + (dst[l]-mSizeDst[l]); - } else { - //src[l] = dst[l]* mSizeRead[l] / mSizeDst[l]; - const int b = mInterpolateWithBorder; - src[l] = ((dst[l]-b) * (mSizeRead[l]-2*b) / (mSizeDst[l]-2*b)) + b; - } - } - //std::cerr <<"Init debug" << "at dst="<<dst<<"|"<<mSizeDst<<" file src="<<src<<", filesize"<<mSizeRead <<"\n"; - } else { - // direct read (standard way of loading) - // nothing to do, load from (i,j,k) - } - - if (!onlyFluid || fgIsFluid(getFlagAcc()(i,j,k)) ) - gaDst.write(i,j,k) = getFileData(src[0],src[1],src[2]); - }; - void reduce(fsLoadData &op) { }; - - protected: - Grid<T> *mpDst; - GridAccessor<T,0> gaDst; - - unsigned char * mpData; - bool onlyFluid; - nVec3i mSizeRead; // size of grid in file - nVec3i mSizeDst; // size of destination grid - int mInterpolateWithBorder; - unsigned mPageSize, mBytesPerElement; -}; - -template<class T> -inline T fsLoadData<T>::getRaw(unsigned chunk) -{ - return *((T*) &mpData[ mBytesPerElement * chunk]); -} -template<> -inline Vec3 fsLoadData<Vec3>::getRaw(unsigned chunk) -{ - Vec3 a; - for (int e=0; e < 3; e++) - a[e] = *((Real*) &mpData[ mBytesPerElement * chunk + e * mPageSize]); - return a; -} - -// query dimensions of universal grid file -nVec3i getUniversalGridSize(const string& file) -{ - UniversalHeader head; - - gzFile gzf = gzopen(file.c_str(),"r"); - if (gzf == NULL) { - errFatal("spluginLoadUniversal","can't open field file " << file, SIMWORLD_INITERROR); - return nVec3i(0); - } - if (gzread(gzf, &head,sizeof(UniversalHeader)) != sizeof(UniversalHeader) || strncmp(head.id, "DDF1", 4)) { - errFatal("spluginLoadUniversal","wrong filetype in " << file,SIMWORLD_INITERROR); - return nVec3i(0); - } - gzclose(gzf); - - return nVec3i(head.dimX, head.dimY, head.dimZ); -} - -// dump any grid to universal file format -class spluginDumpUniversal : public spluginDumperBase { - public: - spluginDumpUniversal() : spluginDumperBase(), mFirstTime(true) { }; - ~spluginDumpUniversal() { }; - - virtual bool parseParams(const ParamSet& params) { - mGrid = params.FindOneString("grid", ""); - mMAC = params.FindOneInt("mac", !mGrid.compare("vel-curr")) != 0; // MAC grid is default for 'vel-curr' only - mFilePerFrame = params.FindOneInt("file-per-frame", 0) != 0; - mNoExt = params.FindOneInt("no-ext", 0) != 0; - bool singleDump = params.FindOneInt("single-dump", 0) != 0; - parseParamsDumperBase(params); - if (singleDump) { mNoExt = true; mFilePerFrame = true; mDumpAllFrames = true; } - return true; - }; - virtual bool initPlugin() { - mSimTime = 0.; - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real org_dt) { - Real dt = org_dt * mpPlParams->getDeltaX(); - debMsg("spluginDumpUniversal","dt="<<dt<<" grid:"<<mGrid<<"; simTime="<< - mSimTime<<", last="<<mLastAniOutTime<<", cnt="<<mAnimOutCounter<<" dump-all-frame="<<mDumpAllFrames ); - mSimTime += dt; - - while( this->doDump() ) - { - UniversalHeader head; - const nVec3i gridSize = mpPlParams->getGridInt("flags")->getSize(); - - // get Grid - Grid<int> *gI=NULL; - Grid<Real> *gR=NULL; - Grid<Vec3> *gV=NULL; - if (mpPlParams->haveGridInt(mGrid)) { - gI = mpPlParams->getGridInt(mGrid); - head.bytesPerElement = sizeof(int); - head.elementType = 0; - head.elements = 1; - } - else if (mpPlParams->haveGridReal(mGrid)) { - gR = mpPlParams->getGridReal(mGrid); - head.bytesPerElement = sizeof(Real); - head.elementType = 1; - head.elements = 1; - } - else if (mpPlParams->haveGridVec3(mGrid)) { - gV = mpPlParams->getGridVec3(mGrid); - head.bytesPerElement = sizeof(Real); - head.elementType = 2; - head.elements = 3; - } - else { - errMsg("spluginDumpUniversal","Grid '"<<mGrid<<"' not found or gridtype unsupported"); - return false; - } - - if (mFirstTime || mFilePerFrame) { - // Open a file - std::string filename = mOutname; - if (mFilePerFrame && !mNoExt) { - char nrStr[5]; // nr conversion - snprintf(nrStr, 5, "%04d", mAnimOutCounter ); - filename += nrStr; - } - mGzf = gzopen( (filename+".gz").c_str(), "wb1"); - if (!mGzf) { - errMsg("spluginDumpUniversal","Unable to open output '"<<filename<<"' "); - return false; - } - debMsg("spluginDumpUniversal","writing to file '" << filename << ".gz'" ); - - // Write header - strncpy(head.id,"DDF1",4); - head.dimX = gridSize.x; - head.dimY = gridSize.y; - head.dimZ = (gDim==2) ? 1:gridSize.z; - head.frames = mMaxFrames; - head.bytesPerFrame = head.dimX * head.dimY * head.dimZ * head.elements * head.bytesPerElement + sizeof(float); - - gzwrite(mGzf, &head, sizeof(UniversalHeader)); - } - - // write frame - const int z0 = mpPlParams->getFluidSolver()->get2dKstart(); - const int z1 = mpPlParams->getFluidSolver()->get2dKend(); - for (int e=0; e< head.elements; e++) - { - // write grid of current element - FOR_IJK(z0,z1, 0, head.dimY, 0, head.dimX) - { - if (head.elementType == 0) - gzwrite(mGzf, &(gI->getGlobal(i,j,k)), sizeof(int)); - else if (head.elementType == 1) - gzwrite(mGzf, &(gR->getGlobal(i,j,k)), sizeof(Real)); - else if (head.elementType == 2) { - Real data = gV->getGlobal(i,j,k)[e]; - if (mMAC) // get centered value on MAC grid - { - nVec3i pos(i,j,k); - pos[e] += 1; - if (pos[e] < gridSize[e]) { - data += gV->getGlobal(pos[0],pos[1],pos[2])[e]; - data *= 0.5; - } - } - gzwrite(mGzf, &data, sizeof(Real)); - } - } - } - // write timestamp - float tm = mSimTime; - gzwrite(mGzf, &tm, sizeof(float)); - - if (mFilePerFrame) - gzclose(mGzf); - - this->increaseDumpCounter(); - } - - return true; - }; - - virtual void finish() - { - if (!mFilePerFrame && !mFirstTime) { - gzclose(mGzf); - debMsg("spluginDumpUniversal","file archive closed."); - } - }; - - protected: - // grid names to swap - std::string mGrid; - bool mFirstTime, mFilePerFrame, mMAC, mNoExt; - gzFile mGzf; -}; - - -class spluginLoadUniversal : public SolverPlugin { - public: - spluginLoadUniversal() : SolverPlugin() { }; - ~spluginLoadUniversal() { }; - - virtual bool parseParams(const ParamSet& params) { - onlyFluid = params.FindOneInt("onlyfluid", 0 ) != 0; - mGrid = params.FindOneString("grid", ""); - mSolver = params.FindOneString("solver", "" ); - mFile = params.FindOneString("file", "" ); - mSrcGrid = params.FindOneString("srcgrid", ""); - - // interpolate, but keep #mInterpolBorder cells from each side unscaled - // -1 means off, 0 means scale everything - mInterpolBorder = params.FindOneInt("interpolate-with-border", 1); - - return true; - }; - virtual bool initPlugin() { return true; }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spluginLoadUniversal","file " + mFile); - SolverParams* param = mpPlParams; - if (!mSolver.empty()) param = ddfWorldFindSolver(mSolver)->getParams(); - Grid<int>* flags = param->getGridInt("flags"); - nVec3i gridSize = flags->getSize(); - if (gDim==2) gridSize[2] = 1; - - - /* DG: Only Int Grid supported for the moment */ - /* Used during solver creation "new SolverObject()" with existing flags grid */ - if(!mSrcGrid.empty()) - { - // delete old grid - delete param->mGridsInt[mGrid]; - // exchange grid pointer - param->mGridsInt[mGrid] = param->mGridsInt[mSrcGrid]; - - return true; - } - - // load file into byte array - UniversalHeader head; - gzFile gzf = gzopen(mFile.c_str(),"r"); - if (gzf == NULL) - errFatal("spluginLoadUniversal","can't open field file " << mFile, SIMWORLD_INITERROR); - - if (gzread(gzf, &head,sizeof(UniversalHeader)) != sizeof(UniversalHeader) || strncmp(head.id, "DDF1", 4)) - errFatal("spluginLoadUniversal","wrong filetype in " << mFile,SIMWORLD_INITERROR); - - if (gridSize[0] != head.dimX || gridSize[1] != head.dimY || gridSize[2] != head.dimZ) { - debMsg("spluginLoadUniversal","file's gridsize (" << head.dimX << "," << head.dimY << "," << head.dimZ << ") != gridsize (" << gridSize[0] << "," << gridSize[1] << "," << gridSize[2] << ")"); - if(mInterpolBorder<=-1) - errFatal("spluginLoadUniversal","Gridsizes don't match, and interpolation is turned off" , SIMWORLD_GRIDERROR); - } - - unsigned char* rawFrame = new unsigned char[head.bytesPerFrame]; - if (gzread(gzf, rawFrame, head.bytesPerFrame) != head.bytesPerFrame) - errFatal("spluginLoadUniversal","error loading frame data in " << mFile,SIMWORLD_INITERROR); - - gzclose(gzf); - - // distinguish data types, invoke grid loader - if(param->haveGridInt(mGrid)) { - Grid<int>* grid = param->getGridInt(mGrid); - if (head.elementType != 0 || head.elements != 1) - errFatal("spluginLoadUniversal","Trying to load non-integer data into integer grid" , SIMWORLD_GRIDERROR); - fsLoadData<int>(flags, grid, rawFrame, head, onlyFluid, mInterpolBorder); - } else if(param->haveGridReal(mGrid)) { - Grid<Real>* grid = param->getGridReal(mGrid); - if (head.elementType != 1 || head.elements != 1) - errFatal("spluginLoadUniversal","Trying to load non-real data into real grid" , SIMWORLD_GRIDERROR); - fsLoadData<Real>(flags, grid, rawFrame, head, onlyFluid, mInterpolBorder); - } else if(param->haveGridVec3(mGrid)) { - Grid<Vec3>* grid = param->getGridVec3(mGrid); - if (head.elementType != 2 || head.elements != 3) - errFatal("spluginLoadUniversal","Trying to load non-vec3 data into vec3 grid" , SIMWORLD_GRIDERROR); - fsLoadData<Vec3>(flags, grid, rawFrame, head, onlyFluid, mInterpolBorder); - } else { - errFatal("spluginLoadUniversal","Grid not found "<< mGrid , SIMWORLD_GRIDERROR); - } - return true; - }; - - protected: - std::string mGrid, mFile, mSolver, mSrcGrid; - bool onlyFluid; - int mInterpolBorder; -}; - -// dump density to disk as gzipped df3 -class spluginDumpDf3 : public spluginDumperBase { - public: - spluginDumpDf3() : spluginDumperBase(), - mGrid("-unnamed1-"), prefix("") { }; - ~spluginDumpDf3() { }; - - virtual bool parseParams(const ParamSet& params) { - //debMsg("spluginDumpDf3","parse"); - mGrid = params.FindOneString("gridname", mGrid ); - prefix = params.FindOneString("prefix", mGrid ); - mPbrt = params.FindOneInt("pbrt", 0 ) != 0; - parseParamsDumperBase(params); - return true; - }; - virtual bool initPlugin() { - mSimTime = 0.; - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real org_dt) { - Real dt = org_dt * mpPlParams->getDeltaX(); - debMsg("spluginDumpDf3","dt="<<dt<<" grid:"<<mGrid<<"; simTime="<< - mSimTime<<", last="<<mLastAniOutTime<<", cnt="<<mAnimOutCounter<<" " ); - - mSimTime += dt; - // crude approx if dt is larger than mTimestepAnim, - // might be better to reduce dt? - while ( this->doDump() ) { - myTime_t dumptstart = getTime(); - mLastAniOutTime += mpPlParams->mTimestepAnim; - FlagGrid* pFlags = mpPlParams->getGridInt( "flags" ); - nVec3i gridSize = pFlags->getSize(); - Grid<Real>* srcVal = mpPlParams->getGridReal(mGrid); - - int dimMax = VMAX(gridSize); - - const int twodKs = mpPlParams->getFluidSolver()->get2dKstart(); - const int twodKe = mpPlParams->getFluidSolver()->get2dKend(); - // TODO why are x,y swapped? - //nVec3i min(twodKs, 0, 0); - //nVec3i max(twodKe, gridSize[0], gridSize[1]); - //nVec3i res = max-min; - - std::ostringstream voutfilename; - char nrStr[5]; // nr conversion - snprintf(nrStr, 5, "%04d", mAnimOutCounter ); - - voutfilename << this->mOutname; - if(prefix.length()>0) voutfilename << "_" << prefix; - voutfilename << "_" << nrStr; - - std::cout << "FRAME DUMP " << voutfilename.str() << std::endl; - - debMsg("spluginDumpDf3","Writing '"<<voutfilename.str()<<"', resolution="<<gridSize<<" " ); - string filenameDf3 = voutfilename.str() + (mPbrt ? ".pbrt.gz" : ".df3.gz"); - - gzFile file; - file = gzopen(filenameDf3.c_str(), "wb1"); - if (file != NULL) { - // dimensions - const int byteSize = 2; - const unsigned short int onx=srcVal->getSizeX(),ony=srcVal->getSizeY(),onz=srcVal->getSizeZ(); - /*unsigned short int nx,ny,nz; - nx = onx >> 8; - ny = ony >> 8; - nz = onz >> 8; - nx += (onx << 8); - ny += (ony << 8); - nz += (onz << 8); - nx = onx; ny = ony; nz = onz; - gzwrite(file, (void*)&nx, sizeof(short)); - gzwrite(file, (void*)&ny, sizeof(short)); - gzwrite(file, (void*)&nz, sizeof(short)); - */ - // get rid of swizzling - nVec3i write_res = nVec3i(onx,ony,onz); - const int nitems = onx*ony*onz; - const float mul = (float)( (1<<(8*byteSize))-1); - - Real *buf = new Real[nitems]; - for (int k = 0; k < onz; k++) - for (int j = 0; j < ony; j++) - for (int i = 0; i < onx; i++) { - float val = srcVal->getGlobal(i,j,k); - CLAMP(val, 0.f,1.f); - buf[k*(onx*ony)+j*onx+i] = val; - } - if (mPbrt) { - // text pbrt output - std::ostringstream sbuf; - Vec3 prop(onx,ony,onz); - prop /= prop.max(); - sbuf << "Volume \"volumegrid\"" << endl; - sbuf << " \"integer nx\" " << onx << endl; - sbuf << " \"integer ny\" " << ony << endl; - sbuf << " \"integer nz\" " << onz << endl; - sbuf << " \"point p0\" [ 0 0 0 ]" << endl; - sbuf << " \"point p1\" [ " << prop.x << " " << prop.y << " " << prop.z << " ]" << endl; - sbuf << " \"float density\" [ " << endl; - for (int i=0;i<nitems;++i) - sbuf << buf[i] << " "; - sbuf << " ] " << endl; - string bs = sbuf.str(); - gzwrite(file, (void*)(bs.c_str()), bs.length()); - } else { - // binary DF3 output - gzwrite(file, &write_res[0] , 3*sizeof(int)); - unsigned short int *dbuf = new unsigned short int[nitems]; - for (int i=0;i<nitems;++i) - dbuf[i] = (unsigned short int)(buf[i]*mul); - gzwrite(file, (void*)dbuf, sizeof(unsigned short int)* nitems); - delete[] dbuf; - } - gzclose(file); - delete[] buf; - // df3 gz written - } else { - errMsg("spluginDumpDf3","Unable to write to "<<filenameDf3 ); - } - - this->increaseDumpCounter(); - - myTime_t dumptend = getTime(); - debMsg("spluginDumpDf3","took "<< getTimeString(dumptend-dumptstart)<<" for frame "<<mAnimOutCounter ); - } - - return true; - }; - - protected: - // grid names to swap - std::string mGrid, prefix; - bool mPbrt; -}; - - - -//***************************************************************************** - -SolverPlugin* MakeIoPlugin(std::string name) { - if (name.compare( string("dump-df3") )==0) { - return new spluginDumpDf3; - } else if (name.compare( string("dump-universal") )==0) { - return new spluginDumpUniversal; - } else if (name.compare( string("load-universal") )==0) { - return new spluginLoadUniversal; - } else if (name.compare( string("print-timing-stats") )==0) { - return new spluginPrintTimingStats; - } - return NULL; -} - -} // end namespace DDF - diff --git a/intern/smoke/intern/source/fluidsolver.cpp b/intern/smoke/intern/source/fluidsolver.cpp deleted file mode 100644 index 173ce0a3e35..00000000000 --- a/intern/smoke/intern/source/fluidsolver.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Class encapsuling the solver - * - *****************************************************************************/ - -// lsdebug -#include "globals.h" -#include "vectorbase.h" - -#include "solverparams.h" -#include "solverplugin.h" -#include "paramset.h" - -#include "vortexpart.h" -//#include "boundbox.h" -#include "randomstream.h" -#include <fstream> -#include <sstream> - -// define global solver list -map<string, DDF::FluidSolver*> gFluidSolvers; -DDF::FluidSolver *gpFsolver = NULL; - -namespace DDF { -// search for fluid solve with given name -FluidSolver* ddfWorldFindSolver(const std::string solverName) { - if(gFluidSolvers.find(solverName) != gFluidSolvers.end() ) { - return gFluidSolvers[solverName]; - } - - errMsg("ddfWorldFindSolver","Solver '"<<solverName<<"' not found!"); - std::cout<<helperPrintMap(gFluidSolvers,"ddfWorldFindSolver")<<"\n"; - return NULL; -} - -// ctor -FluidSolver::FluidSolver(const std::string& name) : - mpParams(NULL), - mDt(0.), mDim(0), mGravity(0.), - mpFlags(NULL), - mStepCounter(0), - mName(name), mSolverInited(false) -{ - mpVorticitySys = NULL; - // debug test inits - mGravity = Vec3( 0., 0., 0.); -}; - -// dtor -FluidSolver::~FluidSolver() { - // free plugins - for (int i=0; i< (int)mPlugins.size(); i++) - delete mPlugins[i]; - for (int i=0; i< (int)mInitPlugins.size(); i++) - delete mInitPlugins[i]; - for (int i=0; i< (int)mEndPlugins.size(); i++) - delete mEndPlugins[i]; - - mPlugins.clear(); - mEndPlugins.clear(); - mInitPlugins.clear(); - mPluginTimes.clear(); - delete mpParams; - if (mpVorticitySys != NULL) delete mpVorticitySys; - - //note, handle free'ing other pointers... -}; - -// ***************************************************************************** -//! init solver -bool FluidSolver::initFluid() { - if(!mpParams) { - errMsg("FluidSolver::initFluid","Fatal - no params given..."); - return false; - } - mpParams->setFluidSolver( this ); - - // restrict z-axis in 2D - if (gDim==2) { - nVec3i nn = mpParams->getGridSize(); - nn[2] = gPatchSize; - mpParams->setGridSize(nn); - } - - const nVec3i n = mpParams->getGridSize(); - // set time to zero - mpParams->addToSimTime( -mpParams->getSimTime() ); - mpFlags = mpParams->getGridInt("flags"); - - // init from unittests - const int nMax = mpParams->getDimMax(); - - mTwodKs = 0; - mTwodKe = n[2]; - if (gDim==2) { - mTwodKs = gPatchSize/2; - mTwodKe = mTwodKs+1; - } - const int ks = mTwodKs; - const int ke = mTwodKe; - - // setup boundaries - for (int k=ks; k< ke; k++) - for (int j=0; j< n[1]-0; j++) - for (int i=0; i< n[0]-0; i++) { - int set = FFLUID; - if( k<=0 || j<=0 || i<=0 || - (k>=n[2]-1) || (j>=n[1]-1) || (i>=n[0]-1)) { set = FOBSTACLE; } - mpFlags->getGlobal(i,j,k) = set; - } - mDim = n; - - if (mpParams->mHostVorticitySystem) - mpVorticitySys = new VorticitySystem(this); - - return true; -}; - -//! run init plugins once, similar to simulateFluid -void FluidSolver::runInitPlugins() { - mDt = mpParams->getTimestep(); - DDF::myTime_t tStart = DDF::getTime(); - - // run plugins - for (int i=0; i< (int)mInitPlugins.size(); i++) { - - // execute - DDF::myTime_t plStart = DDF::getTime(); - if (! mInitPlugins[i]->performStep(mDt) ) { - errFatal("FluidSolver::runInitPlugins","Plugin step "<<i<<" failed!", SIMWORLD_PLUGINERROR); - } - DDF::myTime_t plEnd = DDF::getTime(); - } - - // timing... - DDF::myTime_t tEnd = DDF::getTime(); - debMsg("FluidSolver::runInitPlugins",mpParams->mName<<" t="<<mpParams->getSimTime() <<", dt="<<mDt<<", took "<< DDF::getTimeString(tEnd-tStart)<<" "); -}; - -//! run end plugins once, similar to simulateFluid -void FluidSolver::finalize() { - mDt = mpParams->getTimestep(); - DDF::myTime_t tStart = DDF::getTime(); - - // finalize main loop plugins - for (int i=0; i< (int)mPlugins.size(); i++) - mPlugins[i]->finish(); - - // run end plugins - for (int i=0; i< (int)mEndPlugins.size(); i++) { - - // execute - DDF::myTime_t plStart = DDF::getTime(); - if (! mEndPlugins[i]->performStep(mDt) ) { - errFatal("FluidSolver::runEndPlugins","Plugin step "<<i<<" failed!", SIMWORLD_PLUGINERROR); - } - DDF::myTime_t plEnd = DDF::getTime(); - //mPluginTimes[i] += (double)(plEnd-plStart); - } - - // timing... - DDF::myTime_t tEnd = DDF::getTime(); - debMsg("FluidSolver::finalize",mpParams->mName<<" t="<<mpParams->getSimTime() <<", dt="<<mDt<<", took "<< DDF::getTimeString(tEnd-tStart)<<" "); -}; - -// setup plugin stack -void FluidSolver::addPlugins(vector<SolverPlugin*>& plugins) { - debMsg("addPlugins","adding "<<plugins.size() ); - mPluginTimes.clear(); - - // store plugin stack, and perform first init - for (int i=0; i< (int)plugins.size(); i++) { - mPlugins.push_back( plugins[i] ); - mPluginTimes.push_back( 0. ); - - if(! mPlugins[i]->initPlugin() ) { - errFatal("FluidSolver::addPlugins","Init "<<i<<" failed!", SIMWORLD_PLUGINERROR); - } - } -} - -// setup init plugin stack -void FluidSolver::addInitPlugins(vector<SolverPlugin*>& plugins) { - debMsg("addInitPlugins","adding "<<plugins.size() ); - mPluginTimes.clear(); - - // store plugin stack, and perform first init - for (int i=0; i< (int)plugins.size(); i++) { - mInitPlugins.push_back( plugins[i] ); - - if(! mInitPlugins[i]->initPlugin() ) { - errFatal("FluidSolver::addInitPlugins","Init "<<i<<" failed!", SIMWORLD_PLUGINERROR); - } - } -} - -// setup end plugin stack -void FluidSolver::addEndPlugins(vector<SolverPlugin*>& plugins) { - debMsg("addInitPlugins","adding "<<plugins.size() ); - - // store plugin stack, and perform first init - for (int i=0; i< (int)plugins.size(); i++) { - mEndPlugins.push_back( plugins[i] ); - - if(! mEndPlugins[i]->initPlugin() ) { - errFatal("FluidSolver::addEndPlugins","Init "<<i<<" failed!", SIMWORLD_PLUGINERROR); - } - } -} - - -//! advance by time t -bool FluidSolver::simulateFluid() { - mDt = mpParams->getTimestep(); - DDF::myTime_t tStart = DDF::getTime(); - - debMsg("\nsimulateFluid"," for '"<<this->getName()<<"' "); - if(!isSolverInited()) { - errFatal("simulateFluid","Not inited!? 'SolverEnd' statement missing...?", SIMWORLD_GENERICERROR); - } - - if (mPlugins.size() == 0) { - mpParams->setQuit(true); - return false; - } - - // run plugins - for (int i=0; i< (int)mPlugins.size(); i++) { - // plugin active? start&stop time - if(! mPlugins[i]->isCurrentlyActive( mpParams->getSimTime() ) ) { - continue; - } - - // execute - DDF::myTime_t plStart = DDF::getTime(); - if (! mPlugins[i]->performStep(mDt) ) { - errFatal("FluidSolver::simulateFluid","Plugin step "<<i<<" failed!", SIMWORLD_PLUGINERROR); - } - DDF::myTime_t plEnd = DDF::getTime(); - mPluginTimes[i] += (double)(plEnd-plStart); - } - - mpParams->addToSimTime( mDt * mpParams->getDeltaX() ); - mpParams->addToNoiseTime(mDt); - mStepCounter++; - - // timing... - DDF::myTime_t tEnd = DDF::getTime(); - //debMsg("SG-Fl","simtime="<<sgSimTime<<", Time = "<< DDF::getTimeString(tEnd-tStart) ); - debMsg("FluidSolver::simulateFluid",mpParams->mName<<" t="<<mpParams->getSimTime() <<", dt="<<mDt<<", took "<< DDF::getTimeString(tEnd-tStart)<<" #steps:"<<mStepCounter); - - return true; -}; - -// velocity interpolation helpers -# define PINIT_INTERPOL(offa,offb,offc) \ - Real srcpi = pos[0]+(offa); \ - Real srcpj = pos[1]+(offb); \ - Real srcpk = pos[2]+(offc); \ - int srci = (int)srcpi; \ - int srcj = (int)srcpj; \ - int srck = (int)srcpk; \ - CLAMP_TO_GRID(srci,srcj,srck,vels); \ - const float s1 = srcpi-(float)srci, s0 = 1.-s1; \ - const float t1 = srcpj-(float)srcj, t0 = 1.-t1; \ - const float f1 = srcpk-(float)srck, f0 = 1.-f1; - /* end init */ - -# define VELACC vels->getGlobal -# if DDF_DIMENSION==3 -# define PADV_INTERPOLATE(index) \ - vel[index] = f0*( \ - s0*(t0*VELACC(srci ,srcj,srck)[index] + t1*VELACC(srci ,srcj+1,srck)[index] ) + \ - s1*(t0*VELACC(srci+1,srcj,srck)[index] + t1*VELACC(srci+1,srcj+1,srck)[index] ) ) \ - + f1 * ( \ - s0*(t0*VELACC(srci ,srcj,srck+1)[index] + t1*VELACC(srci ,srcj+1,srck+1)[index] ) + \ - s1*(t0*VELACC(srci+1,srcj,srck+1)[index] + t1*VELACC(srci+1,srcj+1,srck+1)[index] ) ) ; - /* end interp */ -# else - // NOTE! srck not used for 2d! -# define PADV_INTERPOLATE(index) \ - vel[index] = f0*( \ - s0*(t0*VELACC(srci ,srcj,srck)[index] + t1*VELACC(srci ,srcj+1,srck)[index] ) + \ - s1*(t0*VELACC(srci+1,srcj,srck)[index] + t1*VELACC(srci+1,srcj+1,srck)[index] ) ) ; - /* end interp */ -# endif // DDF_DIMENSION==3 - -Vec3 FluidSolver::interpolateVelocity(Vec3 pos, Grid<Vec3>* vels, const Real dx) { - Vec3 vel; - pos /= dx; // mpParams->getDeltaX(); - if (gDim==2) pos[2] = gPatchSize/2; - - Real koff= -0.5; - if (gDim==2) koff=0.; - - { PINIT_INTERPOL(0., -0.5, koff); - PADV_INTERPOLATE(0); } - - { PINIT_INTERPOL(-0.5, 0., koff); - PADV_INTERPOLATE(1); } - -# if DDF_DIMENSION==3 - { PINIT_INTERPOL(-0.5, -0.5, 0.); - PADV_INTERPOLATE(2); } -# else - vel[2] = 0.; -# endif - - //debMsg("interpolateVelocity","At "<<pos<<" = "<<vel ); // DEBUG - return vel; -} // interpolateVelocity - - -Vec3 FluidSolver::interpolateVpVelocity(Vec3 pos, Grid<Vec3>* vels) { - Vec3 vel; - if (gDim==2) pos[2] = gPatchSize/2; - - { PINIT_INTERPOL(0.5, 0., 0.); - PADV_INTERPOLATE(0); } - - { PINIT_INTERPOL(0., 0.5, 0.); - PADV_INTERPOLATE(1); } - -# if DDF_DIMENSION==3 - { PINIT_INTERPOL(0., 0., 0.5); - PADV_INTERPOLATE(2); } -# else - vel[2] = 0.; -# endif - - return vel; -} - -#undef PIOFF -#undef PINIT_INTERPOL -#undef PADV_INTERPOLATE -#undef VELACC - -// set velocity, check flags -// similar to force add (but slower!) -void FluidSolver::setGlobVelNoobs(int i,int j, int k, Vec3 &set, Grid<Vec3>* velGrid) { - if ( fgIsObstacle(mpFlags->getGlobal(i,j,k)) ) return; - - // new test, only set empty ones - if (!fgIsEmpty(mpFlags->getGlobal(i,j,k)) ) return; - Vec3& velE = velGrid->getGlobal(i,j,k); - if (fgIsEmpty(mpFlags->getGlobal(i-1,j,k)) ) { - velE[0] = set[0]; - } - if (fgIsEmpty(mpFlags->getGlobal(i,j-1,k)) ) { - velE[1] = set[1]; - } - if (fgIsEmpty(mpFlags->getGlobal(i,j,k-1)) ) { - velE[2] = set[2]; - } - return; - - - //Vec3& vel = mpCurrVel->getGlobal(i,j,k); - Vec3& vel = velGrid->getGlobal(i,j,k); - if (!fgIsObstacle(mpFlags->getGlobal(i-1,j,k)) ) { - vel[0] = set[0]; - } - - if (!fgIsObstacle(mpFlags->getGlobal(i,j-1,k)) ) { - vel[1] = set[1]; - } - - if (!fgIsObstacle(mpFlags->getGlobal(i,j,k-1)) ) { - vel[2] = set[2]; - } -} - -// return timing statistics string -std::string FluidSolver::getTimingStats(int sort) { - std::ostringstream ret; - ret << "FluidSolver::getTimingStats, #steps="<< (mStepCounter+1) <<"\n"; - const double istep = 1 / (double)(mStepCounter+1.); - - double total = 0.; - double max = -1.; - for(int i=0; i<(int)mPluginTimes.size(); i++) { - total += mPluginTimes[i]*istep; - if(mPluginTimes[i]*istep > max) max = mPluginTimes[i]*istep; - } - - if(sort==0) { - for(int i=0; i<(int)mPluginTimes.size(); i++) { - ret << i <<", "<< mPlugins[i]->getName() << " = "<< getTimeString( (myTime_t)(mPluginTimes[i]*istep) ) - <<"; " << (mPluginTimes[i]*istep / total *100.) <<"%" // per cent - <<"\n"; - } - } else { - std::vector<bool> done; - int printed = 0; - done.resize( mPluginTimes.size() ); - for(int i=0; i<(int)mPluginTimes.size(); i++) { - done[i] = false; - } - // sort the slow way... - while(printed< (int)mPluginTimes.size()) { - double nextMax = -1.; - for(int i=0; i<(int)mPluginTimes.size(); i++) { - if(mPluginTimes[i]*istep==max) { - ret << i <<", "<< mPlugins[i]->getName() << " = "<< getTimeString( (myTime_t)(mPluginTimes[i]*istep) ) - <<"; " << (mPluginTimes[i]*istep / total *100.) <<"%" // per cent - <<"\n"; - done[i] = true; - } - if(!done[i] && mPluginTimes[i]*istep > nextMax) nextMax = mPluginTimes[i]*istep; - } - max = nextMax; - printed++; - } - } - ret <<"Total time = " << getTimeString( (myTime_t)total ) <<"\n"; - - return ret.str(); -} - -}// end namespace DDF diff --git a/intern/smoke/intern/source/fluidsolver.h b/intern/smoke/intern/source/fluidsolver.h deleted file mode 100644 index f3906aa8f48..00000000000 --- a/intern/smoke/intern/source/fluidsolver.h +++ /dev/null @@ -1,162 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Class encapsuling the solver - * - *****************************************************************************/ - -#ifndef DDF_FLUIDSOLVER_H -#define DDF_FLUIDSOLVER_H - -#include "globals.h" -#include "grid.h" -#include "solverparams.h" - -namespace DDF { -class GeomFile; -class SolverPlugin; -class VorticitySystem; - -extern FluidSolver* ddfWorldFindSolver(const std::string solverName); - -//! patch grid based cg solver -class FluidSolver { - public: - // constructor - FluidSolver(const std::string& name="fluidSolverUnnamed"); - ~FluidSolver(); - - //! setup plugin stack - void addPlugins(vector<SolverPlugin*>& plugins); - //! setup init plugin stack - void addInitPlugins(vector<SolverPlugin*>& plugins); - //! setup end plugin stack - void addEndPlugins(vector<SolverPlugin*>& plugins); - - //! init solver - bool initFluid(); - //! init level set - void initLevelSet(int eiksolver); - //! advance by time t - bool simulateFluid(); - bool advanceParticles(Real t, Grid<Vec3>* vels); - //! run init plugins - void runInitPlugins(); - - //! run final plugins - void finalize(); - - // access functions - inline Real getDt() const { return mDt; } - inline Real getSimTime() const { return mpParams->getSimTime(); } - inline nVec3i getDim() const { return mDim; } - inline VorticitySystem* getVorticitySys() { return mpVorticitySys; } - - inline Vec3 getGravity() const { return mGravity; } - inline void setGravity(Vec3 set) { mGravity=set; } - inline Real getCellSize() const { return mCellSize; } - - inline int getStepCounter() const { return mStepCounter; } - inline FlagGrid* getGridFlags() { return getParams()->getGridInt("flags"); } - inline Grid<Vec3>* getGridCurrVel() { return getParams()->getGridVec3("vel-curr"); } - inline Grid<Vec3>* getGridOtherVel() { return getParams()->getGridVec3("vel-old"); } - inline Grid<Real>* getGridPressure() { return getParams()->getGridReal("pressure"); } - - inline int get2dKstart() const { return mTwodKs; } - inline int get2dKend() const { return mTwodKe; } - - inline void setName(std::string set) { mName = set; } - inline std::string getName() { return mName; } - - void setParams(SolverParams *params) { mpParams = params; } - SolverParams* getParams() { return mpParams; } - - bool isSolverInited() { return mSolverInited; } - void setSolverInited(bool set) { mSolverInited=set; } - - int getNumInitSteps() { return mInitPlugins.size(); } - int getNumPluginSteps() { return mPlugins.size(); } - - // return timing statistics string - std::string getTimingStats(int sort); - - // helper info functions - int getFrameNum() { - return (int)(getSimTime() / (getParams()->getDt() * getParams()->getDeltaX())); } - int getAniFrameNum() { - return (int)(getSimTime() / (getParams()->mTimestepAnim ) ); } - - protected: - typedef struct { - std::string name; - vector<Real> data; - } DataVector; - - // parameter set - SolverParams* mpParams; - - // time step - Real mDt; - // dimensions - nVec3i mDim; - // size of a single cell - Real mCellSize; - // gravity force - Vec3 mGravity; - - // flag grid - FlagGrid* mpFlags; - - VorticitySystem* mpVorticitySys; - - // some global info vars from init - // 2d k region start & end - int mTwodKs, mTwodKe; - // for debugging steps - int mStepCounter; - - // actual steps to be performed - vector<SolverPlugin*> mPlugins; - // steps for init - vector<SolverPlugin*> mInitPlugins; - // final steps - vector<SolverPlugin*> mEndPlugins; - // profiling of steps - vector<double> mPluginTimes; - - // debug, store name from init - std::string mName; - bool mSolverInited; - - public: - - // interpolate velocity at a given position (note! velocity is face-centered, - // so "normal" grid->getInerpolated(..) isnt correct - static Vec3 interpolateVelocity(Vec3 pos, Grid<Vec3>* vels, const Real dx); - Vec3 interpolateVpVelocity(Vec3 pos, Grid<Vec3>* vels); - - // set velocity using global accesses, and - // respecting obstacle flags (only !fgIsObstacle cells are modified) - void setGlobVelNoobs(int i,int j, int k, Vec3 &set, Grid<Vec3>* vel); - - // get velocity component interpolated at grid center - inline Vec3 getCenteredVel(Grid<Vec3> *vel, int x, int y, int z) { - Vec3 v = vel->getGlobal(x,y,z); - v[0] += vel->getGlobal(x+1,y ,z )[0]; - v[1] += vel->getGlobal(x ,y+1,z )[1]; - v[2] += vel->getGlobal(x ,y ,z+1)[2]; - v *= 0.5; - return v; - }; - -}; // FluidSolver - - -} // namespace DDF - -#endif // DDF_FLUIDSOLVER_H diff --git a/intern/smoke/intern/source/glutgui.cpp b/intern/smoke/intern/source/glutgui.cpp deleted file mode 100644 index b766e22c6cf..00000000000 --- a/intern/smoke/intern/source/glutgui.cpp +++ /dev/null @@ -1,951 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * GUI - * - *****************************************************************************/ - -#include <list> - -#include "globals.h" -#include "vectorbase.h" -#include "solverparams.h" -#include "paramset.h" - -#include "fluidsolver.h" -#include "boundbox.h" -#include "vortexpart.h" - -#if DDF_GLUTGUI==1 -#if defined(__APPLE__) -// mac -#include <GLUT/glut.h> -#else -#include <GL/glut.h> -#endif -#endif // DDF_GLUTGUI==1 - -// solver object from main -DDF::FluidSolver *gpGlutFsolver = NULL; - -// velocity grid to display "string showvel" param -std::string gShowVelgridName = std::string("vel-curr"); -// name of real grid to show -std::string gShowRealgridName = std::string("pressure"); - -// scale display of velocities with "float vel-scale" parameter for glut gui -static float gScaleVelocityDisplay = 1.; // = g Vec3 Divider -// scale real values in grids for display, store one value per grid -std::map<std::string,float> gScaleRealDisplay; - -// draw velocities at center instead of faces? -static bool gDrawCenteredVels = false; -static bool gVelocityMAC = true; -static bool gFinalizationDone = false; -// draw lines for grid (only for dims <= 128) -static bool gDrawLines = true; - -// toggle flag bit string display for probing on/off -static bool gProbeShowFlags = false; - -// show real values in empty cells? -const bool gHideEmptyValues = true; - - -/******************************************************************************/ -namespace DDF { - - - -// set by parser externally, read here... -ParamSet gGlutGuiParams; - -#if DDF_GLUTGUI==1 - -#if DDF_DIMENSION==2 -Vec3 gViewTrafo(0., 0., -0.01); -#else -Vec3 gViewTrafo(0., 0., -0.5); -#endif -Vec3 gViewRot(0., 0., 0.); - -bool gDrawVortexParticles = true; -//bool gDrawPhiRef = false; -bool gDrawVel = false; - -// time stepping -bool gStep = false; -bool gPause = false; -// movement speeds -const float gMoveSpeed = 0.002; -const float gRotSpeed = 0.2; - -// region of interest -BboxVeci gGlutRoi; -int gRoiPlane = 2; -// minimal and maximal values for grid info in GUI -Real gRealgridMin = 0., gRealgridmMax = 0.; -Vec3 gVecgridMin = Vec3(0.), gVecgridMax = Vec3(0.); - -bool gGlobalVPart = true; - -// helper functions in guihelpers.cpp -void glutgSelectNextSolver(); -void glutgSelectNextFloatArray(); -void glutgSelectNextVec3Array(); -void glutgSelectNextFloatArrayO(); -void initFloatArrayDisplay(); - -void handle_display(); - -// mouse motion -static int g_mouseBut = -1; -static int g_specialKey = -1; -static int g_lastMouseX=-1, g_lastMouseY=-1; - -/******************************************************************************/ - -void initGlutRoi(Real planeFac) { - nVec3i grsize = gpGlutFsolver->getGridFlags()->getSize(); - - // roi checks are "inclusive" of boundaries, so reduce by one... - grsize += nVec3i(-1); - grsize[gRoiPlane] = (grsize[gRoiPlane] * planeFac); - - nVec3i grsizeMin(0); - grsizeMin[gRoiPlane] = grsize[gRoiPlane]; - gGlutRoi = BboxVeci( grsizeMin, grsize ); - -} - -inline void initGlutRoiRect(nVec3f &p0,nVec3f &p1,nVec3f &p2,nVec3f &p3, nVec3i off, Real mDX,nVec3f pOffset) { - switch( gRoiPlane ) { - case 2: - p0 = nVec3f((off[0]+0)*mDX, (off[1]+0)*mDX, (off[2]+0)*mDX)+pOffset; - p1 = nVec3f((off[0]+1)*mDX, (off[1]+0)*mDX, (off[2]+0)*mDX)+pOffset; - p2 = nVec3f((off[0]+1)*mDX, (off[1]+1)*mDX, (off[2]+0)*mDX)+pOffset; - p3 = nVec3f((off[0]+0)*mDX, (off[1]+1)*mDX, (off[2]+0)*mDX)+pOffset; - break; - case 1: - p0 = nVec3f((off[0]+0)*mDX, (off[1])*mDX, (off[2]+0)*mDX)+pOffset; - p1 = nVec3f((off[0]+1)*mDX, (off[1])*mDX, (off[2]+0)*mDX)+pOffset; - p2 = nVec3f((off[0]+1)*mDX, (off[1])*mDX, (off[2]+1)*mDX)+pOffset; - p3 = nVec3f((off[0]+0)*mDX, (off[1])*mDX, (off[2]+1)*mDX)+pOffset; - break; - case 0: - p0 = nVec3f((off[0])*mDX, (off[1]+0)*mDX, (off[2]+0)*mDX)+pOffset; - p1 = nVec3f((off[0])*mDX, (off[1]+1)*mDX, (off[2]+0)*mDX)+pOffset; - p2 = nVec3f((off[0])*mDX, (off[1]+1)*mDX, (off[2]+1)*mDX)+pOffset; - p3 = nVec3f((off[0])*mDX, (off[1]+0)*mDX, (off[2]+1)*mDX)+pOffset; - break; - } -} - -void drawVortexParticles(VorticitySystem::VList& parts) -{ - if (gpGlutFsolver->getVorticitySys()->getParticles().size() == 0) return; - - Real dx = gpGlutFsolver->getParams()->getDeltaX(); - int a = gGlutRoi.getStart()[gRoiPlane]; - int b = gGlutRoi.getEnd()[gRoiPlane]; - - for (VorticitySystem::VList::const_iterator it = parts.begin(); it != parts.end(); ++it) - { - if (((*it)->getFlags() & VortexParticle::FInertial) == 0) - glColor3f(1., 1., 0.); - else - glColor3f(0.,1.,1.); - - Vec3 pos = (*it)->getPos() +.5; - glPointSize((*it)->getRadius()*1.5); - - if (gDim == 2) - pos[2] = 0.0; - else { - //pos[2] -= 0.5; // z offset to account for centered phi value - if (!gGlobalVPart && (pos[2]<a-0.5 ||pos[2]>b+0.5)) - continue; - } - pos *= dx; - glBegin(GL_POINTS);glVertex3f(pos[0],pos[1],pos[2]);glEnd(); - } - -#if DEBUG_VORTEXPATH==1 - glEnable(GL_BLEND); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBegin(GL_LINES); - for (std::list<LineElement>::const_iterator it = gVortexPath.begin(); it != gVortexPath.end();++it) - { - Vec3 p1 = it->p0 + .5, p2 = it->p1 + .5; - if (gDim == 2) - p2[2] = p1[2] = 0.0; - else { - int a2 = gGlutRoi.getStart()[gRoiPlane]; - int b2 = gGlutRoi.getEnd()[gRoiPlane]; - if (!gGlobalVPart && (p1[2]<a2-0.5 ||p1[2]>b2+0.5 || p2[2]<a2-0.5 ||p2[2]>b2+0.5)) - continue; - } - const Real intensity = 0.7; - glColor4f(intensity*it->r,intensity*it->g,intensity*it->b,it->a); - glVertex3f(dx*p1[0],dx*p1[1],dx*p1[2]); - glVertex3f(dx*p2[0],dx*p2[1],dx*p2[2]); - } - glEnd(); - glDisable(GL_BLEND); -#endif - -} - -// draw grid obstacles and compute min/max pressure -class fsDrawGridLines : public GridOpBase { - public: - fsDrawGridLines(FlagGrid *flags, BboxVeci roi) : - GridOpBase() { - mpFlags = flags; - mRoi = roi; - mDX = 1. / (Real)(mpFlags->getMaxSize()); - pOffset = nVec3f(0., 0., -.00001); - glBegin(GL_LINES); - applyOperatorToGridsSimple(this); - glEnd(); - }; - ~fsDrawGridLines() { }; - void resetVariables() { }; - void reduce(fsDrawGridLines &op) { }; - - void buildCallList() { - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - nVec3i off = nVec3i(i,j,k); - if (!mRoi.contains(off)) return; // if (gDim==3 && off[2]!=mRoi) return; - if (gDim==2) off[2] = 0; - nVec3f p0,p1,p2,p3; initGlutRoiRect(p0,p1,p2,p3,off,mDX,pOffset); - glColor3f(0.2,0.2,0.2); - glVertex3fv(&p0[0]); glVertex3fv(&p1[0]); - glVertex3fv(&p1[0]); glVertex3fv(&p2[0]); - glVertex3fv(&p2[0]); glVertex3fv(&p3[0]); - glVertex3fv(&p3[0]); glVertex3fv(&p0[0]); - }; - protected: - nVec3f pOffset; // drawing offset - BboxVeci mRoi; // display a single slice in 3d - Real mDX; -}; // fsDrawGridLines */ - -// draw grid obstacles and compute min/max pressure -// which scalar field to show in fsDrawObstacles drawTypes: -// 0 = eg pressure (w min/max) -// 1 = levelset (if active) -// 2 = error function -class fsDrawObstacles : public GridOpBase { - public: - fsDrawObstacles(FlagGrid *flags, - Grid<Real> *srcGrid, Grid<Real> *err, - Real minp, Real maxp, BboxVeci roi, int drawtype) : - GridOpBase(), mpSrc(srcGrid),mpErr(err), mDrawType(0) { - - mpFlags = flags; - mRoi = roi; - mDX = 1. / (Real)(mpSrc->getMaxSize()); - mMinP = minp; - mMaxP = maxp; - mFirstPInit = false; - pOffset = nVec3f(0., 0., -.00001); - mDrawType = drawtype; - - //mProjMult = gGlutProject / gScaleRealDisplay * mDX; - mValScale = gScaleRealDisplay[gShowRealgridName]; - mProjMult = 0;//gGlutProject / mValScale * mDX; - - SolverParams* prms = gpGlutFsolver->getParams(); - - mHideEmpty = gHideEmptyValues; - if(mpSrc->getDisplayFlags() & 2) mHideEmpty = false; - - glBegin(GL_QUADS); - applyOperatorToGridsSimple(this); - glEnd(); - //minp = mMinP; maxp = mMaxP; - }; - ~fsDrawObstacles() { }; - void resetVariables() { }; - void reduce(fsDrawObstacles &op) { }; - - void buildCallList() { - gaSrc.gridAccInit(mpSrc, AM_READ, gaCalls); - if (mpErr) { - gaErr.gridAccInit(mpErr, AM_READ, gaCalls); - } - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - const int currFlag = getFlagAcc()(i,j,k); - nVec3i gridPos = nVec3i(i,j,k); - - if (!mRoi.contains(gridPos)) return; - if (gDim==2) gridPos[2] = 0; - nVec3f p0,p1,p2,p3; - initGlutRoiRect(p0,p1,p2,p3,gridPos,mDX,pOffset); - - if (mDrawType==0) { - if (mHideEmpty && fgIsObstacle(currFlag)) { - // obstacle - glColor3f(0.15,0.15,0.15); - } else if (1 && fgIsOutflow(currFlag)) { - glColor3f(0.3,0.0,0.0); - } else if (mHideEmpty && fgIsEmpty(currFlag)) { - // empty cells - glColor3f(0.,0.2,0.); // */ - } else { - Real ps = 0.; - - // override with projection - { - // default, show field value - const Real val = gaSrc(i,j,k); - ps = val / mValScale ; - } - - if (fgIsInflow(currFlag)) { - glColor3f(ps, ps, 0.3); - } else { - if (ps>0) - glColor3f(ps,0.,0.); - else - glColor3f(0.,0.,fabs(ps)); - } - } - } else if (mDrawType==1) { - // level set display - if (gDim==2) gridPos[2] = gPatchSize/2; - - Real v = gaSrc(i,j,k); - - const Real vScale = 1./5. * mValScale; - v *= vScale; - CLAMP(v, (Real)-1., (Real)1.); - - if (v>=0.) { - glColor3f(v,0.,0.5); - } else { - if (v<=-1000.) { - glColor3f(0., 0., 0.); // invalid values - } else { - glColor3f(0.5, 1.+v, 0.); - } - } - } else if (mDrawType == 2) { - /* a to b fades from blue to green, b to c from green to red */ - /*const Real a = 0.01; - const Real b = 1.0; - const Real c = 20.0;*/ - const Real a = 0.0001; - const Real b = 0.01; - const Real c = 1.0; - if (gDim==2) gridPos[2] = gPatchSize/2; - Real err = fabs(gaErr(i,j,k)); - - if (err > b) { - Real val = (err-b)/(c-b); - glColor3f(val,1.0f-val,0.0f); - } else if (err > a) { - Real val = (err-a)/(b-a); - glColor3f(0.0f,val,1-val); - } else - glColor3f(0.0f, 0.0f, 0.0f); - - } else { - return; - } - - glVertex3fv(&p0[0]); - glVertex3fv(&p1[0]); - glVertex3fv(&p2[0]); - glVertex3fv(&p3[0]); - }; - protected: - nVec3f pOffset; // drawing offset - BboxVeci mRoi; - Real mDX; - Real mMinP, mMaxP; - bool mFirstPInit; - Grid<Real> *mpSrc; - Grid<Real> *mpErr; - GridAccessor<Real,0> gaSrc; - GridAccessor<Real,0> gaErr; - - Grid<Real> *mpPhi; - Grid<Real> *mpPhiRef; - - //! what to display 0=grid, 1=levelset - int mDrawType; - int mHideEmpty; - // multiplier for projected displays, adapted to gridsize - Real mProjMult, mValScale; -}; // fsDrawObstacles */ - -// draw grid obstacles and compute min/max pressure -class fsDrawCellIndex : public GridOpBase { - public: - fsDrawCellIndex(FlagGrid *flags, BboxVeci roi) : - GridOpBase() - { - mpFlags = flags; - mDX = 1. / (Real)(flags->getMaxSize()); - pOffset = nVec3f(0., 0., -.00001); - mRoi = roi; - - glBegin(GL_QUADS); - applyOperatorToGridsSimple(this); - glEnd(); - }; - ~fsDrawCellIndex() { }; - void resetVariables() { }; - void reduce(fsDrawCellIndex &op) { }; - - void buildCallList() { - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - const int currFlag = getFlagAcc()(i,j,k); - nVec3i gridPos = /*getFlagAcc().getAccPatch()->mOffset + */nVec3i(i,j,k); - if (!mRoi.contains(gridPos)) return; - - if (gDim==2) gridPos[2] = 0; - nVec3f p0,p1,p2,p3; - initGlutRoiRect(p0,p1,p2,p3,gridPos,mDX,pOffset); - - if (gDim==2) gridPos[2] = gPatchSize/2; - - Vec3 col = Vec3( - gridPos[0]/(Real)mpFlags->getSizeX(), - gridPos[1]/(Real)mpFlags->getSizeY(), - gridPos[2]/(Real)mpFlags->getSizeZ() ); - glColor3f(col[0],col[1],col[2]); - //debMsg("at "," "<<PRINT_IJK<<" "<<col); // DEBUG - - glVertex3fv(&p0[0]); - glVertex3fv(&p1[0]); - glVertex3fv(&p2[0]); - glVertex3fv(&p3[0]); - }; - protected: - nVec3f pOffset; // drawing offset - BboxVeci mRoi; - Real mDX; -}; // fsDrawLevelset */ - - - -// draw centered grid vels -class fsDrawVels : public GridOpBase { - public: - fsDrawVels(FlagGrid *flags, Grid<Vec3> *vel, BboxVeci roi) : - GridOpBase(), mpVel(vel) { - mpFlags = flags; - mDX = 1. / (Real)(mpVel->getMaxSize()); - mRoi = roi; - - // switch off mac display for this grid, if flags|4 is set - //if( mpVel->getDisplayFlags() & 4) mMacValues = false; - - glBegin(GL_LINES); - applyOperatorToGridsSimple(this); - glEnd(); - }; - ~fsDrawVels() { }; - void resetVariables() { }; - void reduce(fsDrawVels &op) { }; - - void buildCallList() { - gaVel.gridAccInit(mpVel, AM_READ, gaCalls); - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - const int currFlag = getFlagAcc()(i,j,k); - const bool dxScale = true; - //if (!fgIsFluid(currFlag)) return; - //if (fgIsObstacle(currFlag)) return; - - nVec3i off = nVec3i(i,j,k); - if (!mRoi.contains(off)) return; - if (gDim==2) off[2] = 0; - - nVec3f p = nVec3f(off[0]*mDX, off[1]*mDX, off[2]*mDX); - - if (gDrawCenteredVels) { // centered - nVec3f vOrg = vec2F( gaVel(i,j,k) ); - nVec3f v = vOrg; - if(mpVel->checkIndexValid(i+1,j+1,k+1) && gVelocityMAC) { - v[0] += gaVel(i+1,j,k)[0]; - v[1] += gaVel(i,j+1,k)[1]; - v[2] += gaVel(i,j,k+1)[2]; - v *= 0.5; - } - if(dxScale) v *= mDX; - v *= gScaleVelocityDisplay; - - p[0] += mDX*0.5; - p[1] += mDX*0.5; - if (gDim==3) p[2] += mDX*0.5; // offset in z dir for display only - - glColor3f(0.,1.,0.); - glVertex3fv(&p[0]); - p += v; - glColor3f(1.,1.,1.); - glVertex3fv(&p[0]); - } else { // side - // dont use averaged vels! - nVec3f v = vec2F( gaVel(i,j,k) ); // * 0.33; - if(dxScale) v *= mDX; - v *= gScaleVelocityDisplay; - - p = nVec3f(off[0]*mDX, off[1]*mDX, off[2]*mDX); - p[0] += 0.5*mDX; - glColor3f(0.,0.,1.); - glVertex3fv(&p[0]); - p[1] += v[1]; - glColor3f(1.,1.,1.); - glVertex3fv(&p[0]); - - p = nVec3f(off[0]*mDX, off[1]*mDX, off[2]*mDX); - p[1] += 0.5*mDX; - glColor3f(1.,0.,0.); - glVertex3fv(&p[0]); - p[0] += v[0]; - glColor3f(1.,1.,1.); - glVertex3fv(&p[0]); - - if (gDim==3) { - p = nVec3f(off[0]*mDX, off[1]*mDX, off[2]*mDX); - p[2] += 0.5*mDX; - glColor3f(1.,0.,0.); - glVertex3fv(&p[0]); - p[2] += v[2]; - glColor3f(1.,1.,1.); - glVertex3fv(&p[0]); } // 3dim - } - }; - protected: - Real mDX; - BboxVeci mRoi; - Grid<Vec3> *mpVel; - GridAccessor<Vec3,1> gaVel; - //bool mMacValues; -}; // fsDrawVels */ - - -/******************************************************************************/ - -extern bool advanceAllSolvers(); // from main -extern void finalizeAllSolvers(); // from main -extern void deleteAllSolvers(); // from main - -void runSimulation () { - if (gPause) return; - if (gFinalizationDone) return; - - bool quit = advanceAllSolvers(); - if (quit) { - gPause=true; - - if (!gFinalizationDone) { - finalizeAllSolvers(); - gFinalizationDone = true; - } - - // immediatly quit for qutorun - if(getenv("DDF_GUIAUTORUN")) { - if(atoi(getenv("DDF_GUIAUTORUN"))>=1) { - exit(0); - } - } - } // quit - - // debug info per timestep - gRealgridMin = gRealgridmMax = 0.; - - // compute only once each time step - if (1) { - Grid<Real> *realGrid = NULL; - realGrid = gpGlutFsolver->getParams()->getGridReal(gShowRealgridName); // DEBrealGrid - goFindMinMax<Real> gomm = goFindMinMax<Real>( gpGlutFsolver->getGridFlags(), realGrid ); - gRealgridMin = gomm.mMinVal; - gRealgridmMax = gomm.mMaxVal; - debMsg("MINMAX-REAL","min="<<gRealgridMin<<" at "<<gomm.mMinPos<<" max="<<gRealgridmMax<<" at "<<gomm.mMaxPos); - - goFindMinMax<Vec3> gomv = goFindMinMax<Vec3>( gpGlutFsolver->getGridFlags(), - gpGlutFsolver->getParams()->getGridVec3(gShowVelgridName) ); - gVecgridMin = gomv.mMinVal; - gVecgridMax = gomv.mMaxVal; - debMsg("MINMAXV","min="<<gomv.mMinVal<<" at "<<gomv.mMinPos<<" max="<<gomv.mMaxVal<<" at "<<gomv.mMaxPos); - - } // end minmax debug info - - glutPostRedisplay(); - if (gStep) { - gPause = true; - gStep = false; - } - - // pause sim, if an error occurred - if(!isSimworldOk()) { - gPause = true; - } -} - -// debug output for patch solver -void drawPatchGrid() -{ - Grid<Real> *perr = NULL; - - int drawType = 0; - - Grid<Real> *realGrid = NULL; - realGrid = gpGlutFsolver->getParams()->getGridReal(gShowRealgridName); // DEBUG - - // hide everything else for some iso disp settings - bool drawGridInfo = true; - - if(drawGridInfo) { - fsDrawObstacles( - gpGlutFsolver->getGridFlags(), - realGrid, perr, - gRealgridMin,gRealgridmMax, gGlutRoi, drawType); - } - - glLineWidth(1.0); - if(gDrawLines && drawGridInfo) { - fsDrawGridLines( gpGlutFsolver->getGridFlags(), gGlutRoi ); - } - - if (gDrawVel && drawGridInfo) { - Grid<Vec3> *vels = gpGlutFsolver->getParams()->getGridVec3(gShowVelgridName); - fsDrawVels( gpGlutFsolver->getParams()->getGridInt("flags"), vels, gGlutRoi ); - } - - if (gDrawVortexParticles && drawGridInfo && gpGlutFsolver->getVorticitySys() != NULL) { - drawVortexParticles(gpGlutFsolver->getVorticitySys()->getParticles()); - } -} - - -/******************************************************************************/ -void handle_display (void) { - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - //gluLookAt(0.5, 0.5, 1.0, 0.5, 0.5, 0.0, 0.0, 1.0, 0.0); - // from to up - gluLookAt(0., 0., 0.5, 0., 0., -0.5, 0., 1., 0.); - glPushMatrix(); - - glTranslatef( gViewTrafo[0], gViewTrafo[1], gViewTrafo[2] ); - glRotatef(gViewRot[0], 1.,0.,0.); - glRotatef(gViewRot[1], 0.,1.,0.); - // center on .5 .5 .5 - glTranslatef( -0.5,-0.5,-0.5 ); - - drawPatchGrid(); - - glPopMatrix(); - glFlush(); - glutSwapBuffers(); -} - -void print_stats() { - std::ostringstream outstr; - int frame = gpGlutFsolver->getFrameNum(); - int aniframe = gpGlutFsolver->getAniFrameNum(); - outstr << "Solver: "<<gpGlutFsolver->getName()<<", t="<< gpGlutFsolver->getSimTime() << " [frame " << frame << ", ani " << aniframe << "]\n"; - - // real grid stats - //Real absmax=gRealgridmMax; - //if (fabs(gRealgridMin)>fabs(absmax)) absmax=gRealgridMin; - outstr << "Real-grid: "<<gShowRealgridName<< " [range " << gScaleRealDisplay[gShowRealgridName] ; - if(gRealgridMin != 0.) outstr << " min " << gRealgridMin << "," ; - outstr << " max " << gRealgridmMax << "]\n"; - int numP = (gpGlutFsolver->getVorticitySys()==NULL) ? 0 : gpGlutFsolver->getVorticitySys()->getParticles().size(); - if (numP > 0) outstr << numP << " vortex parts active\n"; - - // vec grid stats - if(gDrawVel) { - outstr<<"Vec3-grid: "<<gShowVelgridName<<""; - if(gDrawCenteredVels) outstr<<", centered "; - else outstr<<", faces "; - - outstr << " range=" << gScaleVelocityDisplay ; - if(norm( gVecgridMin ) > 0.) outstr << " min=" << gVecgridMin << ","; - outstr << " max=" << gVecgridMax ; - if (!gVelocityMAC) outstr << " noMAC" ; - outstr << "\n"; - } - - debMsg("GRID", outstr.str()); -} - -void handle_reshape (int w, int h) { - glViewport(0, 0, (GLsizei) w, (GLsizei) h); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 0.05, 20.0); - - glMatrixMode(GL_MODELVIEW); -} - -void handle_keyboard(unsigned char key, int x, int y) { - bool roiMsgs = false; - switch (key) { - case 'p': - // run simulation - gPause = !gPause; - break; - case 'l': - // single step - gPause = false; - gStep = true; - break; - - // roi z plane - case '-': - case '_': - gGlutRoi.getStart()[gRoiPlane]--; gGlutRoi.getEnd()[gRoiPlane]--; - if (roiMsgs) debMsg("key","- plane = " << gGlutRoi.getStart()[gRoiPlane]); - if (roiMsgs) debMsg("changeGlutRoi","- roi = "<<gGlutRoi.toString()<<" plane="<<gRoiPlane ); // debug - break; - case '+': - case '=': - gGlutRoi.getStart()[gRoiPlane]++; gGlutRoi.getEnd()[gRoiPlane]++; - if (roiMsgs) debMsg("key","+ plane = " << gGlutRoi.getStart()[gRoiPlane]); - if (roiMsgs) debMsg("changeGlutRoi","+ roi = "<<gGlutRoi.toString()<<" plane="<<gRoiPlane ); // debug - break; - case '*': - gRoiPlane++; gRoiPlane=gRoiPlane%3; - initGlutRoi( 0.5 ); - if (roiMsgs) debMsg("changeGlutRoi","* roi = "<<gGlutRoi.toString()<<" plane="<<gRoiPlane ); // debug - break; - case 'o': - gDrawVortexParticles = !gDrawVortexParticles; - break; - case 'v': - // toggle velocity display - gDrawVel = !gDrawVel; - gVelocityMAC = !(gpGlutFsolver->getParams()->getGridVec3(gShowVelgridName)->getDisplayFlags() & 4); - break; - case 'V': - // toggle centered velocity display - gDrawCenteredVels = !gDrawCenteredVels; - break; - case 'g': - //gGlutProject *=-1; - break; - case 'G': - gGlobalVPart =!gGlobalVPart; - break; - case '`': { - // remember grid selection factor - nVec3i grsize = gpGlutFsolver->getGridFlags()->getSize(); - Real planeFac = ( ((Real)gGlutRoi.getStart()[gRoiPlane]+1.0) / (Real)grsize[gRoiPlane]) ; - //grsize[gRoiPlane] = (grsize[gRoiPlane] * planeFac); - - // show next solver, cycle through all available - glutgSelectNextSolver(); - - // reset struct that have to be initialized anew for solver - initGlutRoi(planeFac); - debMsg("selectNextSolver","Roi factor="<<planeFac<<", plane = "<< gGlutRoi.getStart()[gRoiPlane] ); - print_stats(); - } break; - - case '[': - gScaleRealDisplay[gShowRealgridName] *= 2.; - print_stats(); - break; - case ']': - gScaleRealDisplay[gShowRealgridName] /= 2.; - print_stats(); - break; - case '{': - gScaleVelocityDisplay /= 2.; - print_stats(); - break; - case '}': - gScaleVelocityDisplay *= 2.; - print_stats(); - break; - - case 'z': - // show next float grid - glutgSelectNextFloatArray(); - initFloatArrayDisplay(); - print_stats(); - break; - case 'x': - // show next vec3 grid - glutgSelectNextVec3Array(); - gVelocityMAC = !(gpGlutFsolver->getParams()->getGridVec3(gShowVelgridName)->getDisplayFlags() & 4); - print_stats(); - break; - // cam movement - case 'a': gViewTrafo[0] += gMoveSpeed* 15; break; - case 'd': gViewTrafo[0] += gMoveSpeed*-15; break; - case 's': gViewTrafo[1] += gMoveSpeed* 15; break; - case 'w': gViewTrafo[1] += gMoveSpeed*-15; break; - case 'q': gViewTrafo[2] += gMoveSpeed* 15; break; - case 'e': gViewTrafo[2] += gMoveSpeed*-15; break; - - case 27: // ESC - // quit - //cleanSimulation(); - exit(0); - break; - } - - glutPostRedisplay(); -} - - -void handle_mousePress(int button, int state, int x, int y) { - g_specialKey = glutGetModifiers(); - // if both a mouse button, and the ALT key, are pressed then - if ( (state == GLUT_DOWN) ) { - - if (button == GLUT_LEFT_BUTTON) { - g_mouseBut = GLUT_LEFT_BUTTON; - } else if (button == GLUT_MIDDLE_BUTTON) { - g_mouseBut = GLUT_MIDDLE_BUTTON; - } else { - g_mouseBut = GLUT_RIGHT_BUTTON; - } - } else { - g_mouseBut = -1; - g_lastMouseX=g_lastMouseY=-1; - // gProbeGridString = std::string(""); // reset display - } -} -void handle_mouseMotion(int x,int y) { - - if (g_lastMouseX==-1 && g_lastMouseY==-1) { - g_lastMouseX = x; - g_lastMouseY = y; - return; - } - - if (g_mouseBut==GLUT_RIGHT_BUTTON) { - gViewTrafo[0] += (g_lastMouseX-x) * -gMoveSpeed; - gViewTrafo[1] += (g_lastMouseY-y) * gMoveSpeed; - glutPostRedisplay(); - } - if (g_mouseBut==GLUT_MIDDLE_BUTTON) { - gViewTrafo[2] += (g_lastMouseX-x) * -gMoveSpeed; - gViewTrafo[2] += (g_lastMouseY-y) * gMoveSpeed; - glutPostRedisplay(); - } - if (g_mouseBut==GLUT_LEFT_BUTTON) { - gViewRot[1] += (g_lastMouseX-x) * -gRotSpeed; - gViewRot[0] += (g_lastMouseY-y) * -gRotSpeed; - glutPostRedisplay(); - } - g_lastMouseX = x; - g_lastMouseY = y; - //debMsg("mouseMotion"," at "<<PRINT_VEC(x,y,0.)<<", last "<<PRINT_VEC(g_lastMouseX,g_lastMouseY,0.)<<" but="<<g_mouseBut); -} - - - -/******************************************************************************/ -// glut gui test -int showGlutGui(const char *argv_title) -{ - int argc=1; - char argvb[64]; strcpy(argvb,"ddfCmd"); - char* argv = argvb; - int sx = 800, sy = 800; - - debMsg("\nglutGui","Starting..."); - - // init parser parameters - string solverName = gGlutGuiParams.FindOneString("solvername","default"); - gScaleVelocityDisplay = gGlutGuiParams.FindOneFloat("vel-scale", gScaleVelocityDisplay ); - gpGlutFsolver = ddfWorldFindSolver(solverName); - if (!gpGlutFsolver) { return 1; } - - //if(gpGlutFsolver->getGridFlags()->getMaxSize() > 128) gDrawLines = false; - gDrawLines = gGlutGuiParams.FindOneInt("draw-lines", gDrawLines ) > 0; - - gShowRealgridName = gGlutGuiParams.FindOneString("showgrid",gShowRealgridName); - gShowVelgridName = gGlutGuiParams.FindOneString("showvel",gShowVelgridName); - - gGlutGuiParams.ReportUnused(); - - if(gShowRealgridName.length()<=0 || (!gpGlutFsolver->getParams()->haveGridReal(gShowRealgridName)) ) { - debMsg("glutGui","Invalid gShowRealgridName init '"<<gShowRealgridName<<"', re-init..."); - glutgSelectNextFloatArray(); - } - initFloatArrayDisplay(); - - // center view to grid - Grid<Real> *realGrid = gpGlutFsolver->getParams()->getGridReal(gShowRealgridName); - nVec3i size = realGrid->getSize(); - double dx = 1./(double)realGrid->getMaxSize(); - gViewTrafo[0] = 0.5 - 0.5* (double)size[0] *dx; - gViewTrafo[1] = 0.5 - 0.5* (double)size[1] *dx; - - // init GLUT - glutInit(&argc, &argv); - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); - glutInitWindowSize(sx, sy); - glutInitWindowPosition(10, 10); - - std::ostringstream title; - title << string(argv_title); - glutCreateWindow( title.str().c_str() ); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - // initialize OpenGL - glClearColor(0.0, 0.0, 0.0, 0.0); - glClearDepth(1.0); - //glShadeModel(GL_SMOOTH); - glDepthFunc(GL_LESS); - - // initialize Simulation drawing - initGlutRoi( 0.5 ); - - // setup callbacks - glutDisplayFunc(handle_display); - glutReshapeFunc(handle_reshape); - glutKeyboardFunc(handle_keyboard); - glutIdleFunc(runSimulation); - glutMouseFunc(handle_mousePress); - glutMotionFunc(handle_mouseMotion); - glutMainLoop(); - - return 0; -} - - -#else // DDF_GLUTGUI==1 -/******************************************************************************/ -int showGlutGui(const char* str) -{ - // dummy - return 0; -} -#endif // DDF_GLUTGUI==1 - -}; // namespace DDF - diff --git a/intern/smoke/intern/source/grid.h b/intern/smoke/intern/source/grid.h deleted file mode 100644 index 02637db2c3c..00000000000 --- a/intern/smoke/intern/source/grid.h +++ /dev/null @@ -1,723 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Basic grid class - * - *****************************************************************************/ - -#ifndef DDF_GRIDS_H -#define DDF_GRIDS_H - -//#include "patches.h" -#include "globals.h" -#include "vectorbase.h" -// operators.h is included below -namespace DDF { - -const int gPatchSize = 5; - -class GaCallContainer; -// grid debugging -const bool gStrictGridDebug = (DDF_DEBUG==1); - -// class prototypes -template<class Scalar> class Grid; -template<class Scalar, int BOUNDARY> class GridAccessor; -template<class Scalar> class GridOpTouchMemory; - - -// globals, allocated in globals.cpp -extern int gGridIdCounter; - -// neighbor vectors (helper) -static const int nbx[27] = { -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1 }; -static const int nby[27] = { -1,-1,-1, 0, 0, 0, 1, 1, 1, -1,-1,-1, 0, 0, 0, 1, 1, 1, -1,-1,-1, 0, 0, 0, 1, 1, 1 }; -static const int nbz[27] = { -1,-1,-1, -1,-1,-1, -1,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; - -// debug value -const bool gUseInvalidCheck = false; -static const Real gInvalidReal = 0.; // -1e14; - -// helper to shorten grid funtions -//#define RETURN_ZERO {mZero=0; return mZero;} -#define RETURN_ZERO {this->setDummyZero(); return mZero;} - -//***************************************************************************** -// base class with standard functionality (sizes etc.) -class GridBase { - public: - // cons/des - GridBase(const std::string& name = "-unnamed-") : - mGridId(-1), - mSizeX(0), mSizeY(0), mSizeZ(0), - mMinIndex(0), mMaxIndex(0), - mName(name), - mSanityCheckMode(2), - mGridFlags(0) - { - mGridId = gGridIdCounter++; - // ... - }; - virtual ~GridBase() { }; - - - // standard access funcs - nVec3i getMinIndex() { return mMinIndex; } - void setMinIndex(nVec3i set) { mMinIndex = set; } - nVec3i getMaxIndex() { return mMaxIndex; } - void setMaxIndex(nVec3i set) { mMaxIndex = set; } - //! grid size access - nVec3i getSize() { return nVec3i(mSizeX,mSizeY,mSizeZ); } - nVec3i getGridSize() { return nVec3i(mSizeX,mSizeY,mSizeZ); } // synt. sugar... - int getSizeX() { return mSizeX; } - int getSizeY() { return mSizeY; } - int getSizeZ() { return mSizeZ; } - size_t getNumElements() { return mSizeX * mSizeY * mSizeZ; } - void setSize(nVec3i set) { mSizeX = set[0]; mSizeY = set[1]; mSizeZ = set[2]; } - - // helper functions for 2d/3d distinctions of loop boundaries - int getMinZLoopValue() { if(gDim==3) { return 0; } else { return gPatchSize/2; } } - int getMaxZLoopValue() { if(gDim==3) { return mSizeZ; } else { return gPatchSize/2+1; } } - int getMinZLoopValue(int bnd) { if(gDim==3) { return 0+bnd; } else { return gPatchSize/2; } } - int getMaxZLoopValue(int bnd) { if(gDim==3) { return mSizeZ-bnd; } else { return gPatchSize/2+1; } } - - int getGridId() { return mGridId; } - int getUsePatches() { return false; } - - std::string getName() { return mName; } - void setName(std::string set) { mName = set; } - - int getSanityCheckMode() { return mSanityCheckMode; } - void setSanityCheckMode(int set) { mSanityCheckMode = set; } - - // or'd flags used for debugging in the gui: - // 1 = means hide from display cycle - // 2 = show also values in empty region (eg for level set grids) - // 4 = this is a velocity grid with centered instead of staggered values - int getDisplayFlags() { return mDisplayFlags; } - void setDisplayFlags(int set) { mDisplayFlags = set; } - - // DG TODO: add description here - int getGridFlags() { return mGridFlags; } - void setGridFlags(int set) { mGridFlags = set; } - - - int getMaxSize() { - int ms = mSizeX; - if (mSizeY>ms) ms = mSizeY; - if (mSizeZ>ms) ms = mSizeZ; - return ms; - } - - bool checkIndexValid(int x,int y, int z) const { - if (x < 0) return false; - if (y < 0) return false; - if (z < 0) return false; - if (x>=mSizeX) return false; - if (y>=mSizeY) return false; - if (z>=mSizeZ) return false; - return true; - } - - bool checkIndexValidWithBounds(int x,int y, int z, int bnd) const { - if (x < 0+bnd) return false; - if (y < 0+bnd) return false; - if (z < 0+bnd) return false; - if (x>=mSizeX-bnd) return false; - if (y>=mSizeY-bnd) return false; - if (z>=mSizeZ-bnd) return false; - return true; - } - - bool checkIndexInBounds(int x,int y, int z, nVec3i s, nVec3i e) { - if (x < s[0]) return false; - if (y < s[1]) return false; - if (z < s[2]) return false; - if (x>= e[0]) return false; - if (y>= e[1]) return false; - if (z>= e[2]) return false; - return true; - } - - protected: - - //! global id for grid (for debugging) - int mGridId; - - //! grid sizes - int mSizeX; - int mSizeY; - int mSizeZ; - //! grid extent min - nVec3i mMinIndex; - //! grid extent max - nVec3i mMaxIndex; - - // grid name for debugging etc. - std::string mName; - // debugging, sanity check modes: 0=off, 1=check for nan/inf, 2=also check for threshold (default) - int mSanityCheckMode; - // debug display flags for grids (or'd) - // 1 = for debug display in gui - skip this grid? - // 2 = show empty cells - int mDisplayFlags; - - // see mGridFlags defines below - int mGridFlags; -}; - -// mGridFlags -#define DDF_GRID_NO_FREE 1 - - -//***************************************************************************** -// container of a single grid -template<class Scalar> -class Grid : public GridBase { - public: - // cons/des - Grid(const std::string& name="-unnamed-"); - virtual ~Grid(); - - //! init memory & reset to zero - void initGridMem(int x,int y, int z); - void initGridMem(nVec3i size) { initGridMem(size[0], size[1], size[2]); }; - - //! change size, dont reset any data - void resizeGridMem(int set_x,int set_y, int set_z); - - // string output - std::string toString(bool format=true); - // print formatted in given region - std::string printWithRoi(int* roi); - - // inlined access functions - inline Scalar& operator() (int x,int y, int z) { - if (gStrictGridDebug && (!checkIndexValid(x,y,z) )) { - errFatal("Grid::operator()","Invalid access to "<<PRINT_VEC(x,y,z) << ", grid dim: " << PRINT_VEC(mSizeX,mSizeY,mSizeZ) , SIMWORLD_GRIDERROR); - RETURN_ZERO; - } - return mpData[ ((z*mSizeY+y)*mSizeX+x) ]; - } - - // direct global access to grid - inline Scalar& getGlobal(int x,int y, int z) { - if (gStrictGridDebug && (!checkIndexValid(x,y,z) )) { - errFatal("Grid::operator()","Invalid access to "<<PRINT_VEC(x,y,z) << ", grid dim: " << PRINT_VEC(mSizeX,mSizeY,mSizeZ) , SIMWORLD_GRIDERROR); - RETURN_ZERO; - } - return mpData[ ((z*mSizeY+y)*mSizeX+x) ]; - } - // convenience defines.... - inline Scalar& getGlobal(nVec3i p) { return getGlobal(p[0],p[1],p[2]); } - inline Scalar& get(int x,int y, int z) { return getGlobal(x,y,z); } - inline Scalar& get(nVec3i p) { return getGlobal(p[0],p[1],p[2]); } - - inline Scalar *data() { return mpData; } - - // direct access with given index - inline Scalar& operator[] (size_t index) { - if (gStrictGridDebug && (index<0 || index>=(mSizeX*mSizeY*mSizeZ)) ) { - errFatal("Grid::operator()","Invalid access to index "<< index << ", grid dim: " << PRINT_VEC(mSizeX,mSizeY,mSizeZ) , SIMWORLD_GRIDERROR); - RETURN_ZERO; - } - return mpData[ index ]; - } - - // direct global access to grid - inline void setGlobal(Scalar val, int x,int y, int z) { - if (gStrictGridDebug && (!checkIndexValid(x,y,z) )) { - errFatal("Grid::operator()","Invalid access to "<<PRINT_VEC(x,y,z) << ", grid dim: " << PRINT_VEC(mSizeX,mSizeY,mSizeZ) , SIMWORLD_GRIDERROR); - return; - } - mpData[ ((z*mSizeY+y)*mSizeX+x) ] = val; - } - - inline void clearGrid() - { - memset(mpData, 0, sizeof(Scalar)*mSizeX*mSizeY*mSizeZ); - } - - - inline Scalar getInterpolated(Real x, Real y, Real z); - inline Scalar getInterpolated(Vec3 p) { return getInterpolated(p[0],p[1],p[2]); } - - inline size_t getDataSize() { return mDataSize; } - - protected: - //! for safely returning zero from access funcs - static Scalar mZero; - - // implementations ins globals.cpp - void setDummyZero(); - - // actual grid data (when usepatches=off) - Scalar *mpData; - - // for resizing the grid - size_t mDataSize; -}; // Grid - -// static constant fields for returning off-grid values in debug mode (gStrictGridDebug enabled) -template<class Scalar> -Scalar Grid<Scalar>::mZero; // = Scalar(0.); - - - -//***************************************************************************** -//***************************************************************************** -//***************************************************************************** - -template<class Scalar> -Grid<Scalar>::Grid(const std::string& name) : GridBase(name) { - mpData = NULL; -} - -template<class Scalar> -Grid<Scalar>::~Grid() { - if (mpData) delete[] mpData; -} - -template<class Scalar> -void Grid<Scalar>::initGridMem(int set_x,int set_y, int set_z) { - if (mpData) delete[] mpData; - Scalar zero; - zero = 0; - if (0) debMsg("Grid::Grid","Requested size "<<PRINT_VEC(set_x,set_y,set_z) ); - - // special 2D init - if (gDim==2) { - set_z = gPatchSize; - // min. thickness of 2d slice should be 5 cells... - if (gPatchSize<5) { - errFatal("Grid::initGridMem","Invalid gPatchSize="<<gPatchSize<<" for 2d compile!",SIMWORLD_GRIDERROR); - } - } - - // only valid for non patch based grids / non dyn. sims - mSizeX = set_x; - mSizeY = set_y; - mSizeZ = set_z; - mMinIndex = nVec3i(0,0,0); - mMaxIndex = nVec3i(mSizeX,mSizeY,mSizeZ); - int numElems = mSizeX*mSizeY*mSizeZ; - // compute patchsizes = (n-1)/gp - nVec3i mS(mSizeX,mSizeY,mSizeZ); - nVec3i mPs = (mS+nVec3i(-1))/gPatchSize; - - std::string patchstring[2] = { "full grid", "patchwise" }; - - // not UsePatches - mpData = new Scalar[numElems]; - mDataSize = numElems; - - for (int i=0; i<numElems; i++) { - mpData[i] = zero; - } - - if (0) debMsg("Grid::Grid","Inited size"<<mS<<", "<<patchstring[0]<<", mp"<<mPs<<", id="<<mGridId); // GRIDMEMDEB - // inited... -} - -// resize data, keep old data if new size is smaller -// parts are similar to initGridMem -template<class Scalar> -void Grid<Scalar>::resizeGridMem(int set_x,int set_y, int set_z) { - const bool debugRealloc = false; - size_t numElems = set_x*set_y*set_z; - Scalar zero; - - if (debugRealloc) debMsg("Grid::resizeGridMem","Inited size="<<mDataSize<<", requested size="<<numElems<<" "<<PRINT_VEC(set_x,set_y,set_z) ); - - // sanity check, same as initGridMem - if (gDim==2) { - set_z = gPatchSize; - - if (gPatchSize<5) { - errFatal("Grid::initGridMem","Invalid gPatchSize="<<gPatchSize<<" for 2d compile!",SIMWORLD_GRIDERROR); - } - } - - mSizeX = set_x; - mSizeY = set_y; - mSizeZ = set_z; - mMinIndex = nVec3i(0,0,0); - mMaxIndex = nVec3i(mSizeX,mSizeY,mSizeZ); - - if(mDataSize>=numElems) { - // ok, keep old size - - if (debugRealloc) debMsg("Grid::resizeGridMem","Data block kept"); - return; - } - - // reallocate - delete [] mpData; - // add safety buffer for future enlargements - size_t allocSize = (numElems * 1.5); - mpData = new Scalar[allocSize]; - mDataSize = allocSize; - - for (int i=0; i<allocSize; i++) { - mpData[i] = zero; - } - - if (debugRealloc) debMsg("Grid::resizeGridMem","Data block re-allocated"); -} - -//***************************************************************************** -//***************************************************************************** -//***************************************************************************** - - -template<class Scalar> -std::string Grid<Scalar>::toString(bool format) -{ - std::ostringstream out; - - /*for (int j=mMinIndex[1]; j<mMaxIndex[1]; j++) { - for (int k=mMinIndex[2]; k<mMaxIndex[2]; k++) { - for (int i=mMinIndex[0]; i<mMaxIndex[0]; i++) { - // debug yzx order */ - - int ks = mMinIndex[2]; - int ke = mMaxIndex[2]; - if (gDim==2) { ks = gPatchSize/2; ke = ks+1; } - for (int k=ks; k<ke; k++) { - for (int j=mMinIndex[1]; j<mMaxIndex[1]; j++) { - for (int i=mMinIndex[0]; i<mMaxIndex[0]; i++) { - // normal zyx order */ - out << getGlobal(i,j,k); - out <<" "; - } - if (format) out << std::endl; - } - if (format) out << std::endl; - } - - return out.str(); -} -// print only in indicated region -template<class Scalar> -std::string Grid<Scalar>::printWithRoi(int *roi) -{ - std::ostringstream out; - int ks = mMinIndex[2]; - int ke = mMaxIndex[2]; - if (gDim==2) { ks = gPatchSize/2; ke = ks+1; } - - if(0) debMsg("printWithRoi",this->getName()<<" size "<<this->getSize() <<" roi: "<< - roi[0]<<"-"<< roi[1]<<", "<< - roi[2]<<"-"<< roi[3]<<", "<< - roi[4]<<"-"<< roi[5]<<" " ); - - for (int k=ks; k<ke; k++) { - if (roi[4]>=0 && roi[4]>k) continue; - if (roi[5]>=0 && roi[5]<k) continue; - for (int j=mMinIndex[1]; j<mMaxIndex[1]; j++) { - if (roi[2]>=0 && roi[2]>j) continue; - if (roi[3]>=0 && roi[3]<j) continue; - for (int i=mMinIndex[0]; i<mMaxIndex[0]; i++) { - if (roi[0]>=0 && roi[0]>i) continue; - if (roi[1]>=0 && roi[1]<i) continue; - // normal zyx order */ - out << getGlobal(i,j,k); - out <<" "; - } - out << std::endl; - } - out << std::endl; - } - return out.str(); -} - -template<class Scalar> -inline Scalar Grid<Scalar>::getInterpolated(Real x, Real y, Real z) -{ - int xi = (int)x; - int yi = (int)y; - int zi = (int)z; - Real s1 = x-(Real)xi, s0 = 1.-s1; - Real t1 = y-(Real)yi, t0 = 1.-t1; - Real f1 = z-(Real)zi, f0 = 1.-f1; - - // clamp to border - if (x < 0) { xi = 0; s0 = 1.0; s1 = 0.0; } - if (y < 0) { yi = 0; t0 = 1.0; t1 = 0.0; } - if (z < 0) { zi = 0; f0 = 1.0; f1 = 0.0; } - if (xi >= mSizeX-1) { xi = mSizeX-2; s0 = 0.0; s1 = 1.0; } - if (yi >= mSizeY-1) { yi = mSizeY-2; t0 = 0.0; t1 = 1.0; } - if (zi >= mSizeZ-1) { zi = mSizeZ-2; f0 = 0.0; f1 = 1.0; } - - Scalar ret; - -#define VAL getGlobal -#if DDF_DIMENSION==3 - ret = ( - (VAL(xi ,yi,zi)*t0 + VAL(xi ,yi+1,zi)*t1 )*s0 + - (VAL(xi+1,yi,zi)*t0 + VAL(xi+1,yi+1,zi)*t1 )*s1 )*f0 - + ( - (VAL(xi ,yi,zi+1)*t0 + VAL(xi ,yi+1,zi+1)*t1 )*s0 + - (VAL(xi+1,yi,zi+1)*t0 + VAL(xi+1,yi+1,zi+1)*t1 )*s1 )*f1 ; -#else - ret = (VAL(xi ,yi,zi)*t0 + VAL(xi ,yi+1,zi)*t1 )*s0 - + (VAL(xi+1,yi,zi)*t0 + VAL(xi+1,yi+1,zi)*t1 )*s1 ; -#endif // DDF_DIMENSION==3 -#undef VAL - - return ret; -} - - -//***************************************************************************** -//***************************************************************************** -//***************************************************************************** - - - -// type to precompute indices -typedef unsigned int GaccIndex; - - -// access modes -enum GaAccModes { - AM_NONE=0, - AM_READ=1, - AM_READWRITE=2, - AM_WRITE=3 }; - -// interface for simplified locking -// read/write access and regions are checked during debug -// compilation with DDF_DEBUG = 1 -class GridAccessorBase { - public: - // cons/des - GridAccessorBase(int accmode) { - mAccMode = accmode; - }; - virtual ~GridAccessorBase() { }; - - virtual void lockRegion(nVec3i s, nVec3i e, int passid) { - debMsg("GridAccessorBase","Invalid lockRegion called..."); - passid = 0; - } - virtual void unlockRegion(int passid) { - debMsg("GridAccessorBase","Invalid unlockRegion called..."); - passid = 0; - } - - protected: - //! mode, should be consistent! 0=none, 1=read, 2=read&write, 3=write only - int mAccMode; -}; - - -// grid accessor class, handles locking and accessing patches -template<class Scalar, int BOUNDARY> -class GridAccessor : public GridAccessorBase { - public: - // cons/des - GridAccessor() : GridAccessorBase(AM_NONE), - mSrc(NULL), mRegionStart(0), mRegionEnd(0) - { }; - - virtual ~GridAccessor() { }; - - // init access to grid, and add accessor to grid-acc call list (for looping) - void gridAccInit(Grid<Scalar> *grid, GaAccModes acc, GaCallContainer &gacalls); - //! write access - Scalar& write(int x,int y, int z); - //! init write access to region from src grid (no boundaries!) - virtual void lockRegion(nVec3i s, nVec3i e, int passid); - //! unlock - virtual void unlockRegion(int passid); - //! read access (constant!) - inline const Scalar& operator() (int x,int y, int z) const; - - inline Scalar getInterpolated(Real x, Real y, Real z) const; - - //! read access with precomputed index - inline const Scalar& operator() (GaccIndex index) const; - //! compute grid acc index - inline GaccIndex getGaccIndex(int x,int y, int z); - //! get access to the source grid (mostly for debug checks, e.g. index ranges) - inline Grid<Scalar>* getGaSourceGrid() { return mSrc; } - - protected: - - std::string toString() const; - - //! source grid for access - Grid<Scalar>* mSrc; - // locked region - nVec3i mRegionStart, mRegionEnd; -}; - - -class GaCallContainer { - public: - // ctor, dtor - GaCallContainer() : threadId(-1), calls() { }; - virtual ~GaCallContainer() { }; - - int threadId; - std::vector<DDF::GridAccessorBase*> calls; -}; - - - - - - -// init access to grid, and add accessor to grid-acc call list (for looping) -template<class Scalar, int BOUNDARY> -void -GridAccessor<Scalar,BOUNDARY>::gridAccInit(Grid<Scalar> *grid, GaAccModes acc, GaCallContainer &gacalls) -{ - if (!grid) { - errFatal("GridAccessor::gridAccInit","Invalid source null grid!",SIMWORLD_GRIDERROR); - return; - } - mSrc = grid; - mAccMode = acc; - - // debug, check for double entries - if (DDF_DEBUG==1) { - for (size_t i=0; i<gacalls.calls.size(); i++) { - if (gacalls.calls[i] == this) { - errFatal("GridAccessor::gridAccInit","Debug check - double gacall entry!",SIMWORLD_GRIDERROR); - return; - } - } - } // debug - - gacalls.calls.push_back(this); -}; - -//! write access -template<class Scalar, int BOUNDARY> -Scalar& -GridAccessor<Scalar,BOUNDARY>::write(int x,int y, int z) { - - if (gStrictGridDebug) { - if (!mSrc->checkIndexValid(x,y,z) ) { - errFatal("GridAccessor::write","Acess to "<<PRINT_VEC(x,y,z)<<", out of bounds for grid "<<mSrc->getGridId()<<"!", SIMWORLD_GRIDERROR); - } - - if (!mSrc->checkIndexInBounds(x,y,z, mRegionStart, mRegionEnd) ) { - errFatal("GridAccessor::write","Acess to "<<PRINT_VEC(x,y,z)<<", out of locked region "<< - mRegionStart<<" to "<<mRegionEnd<<" for grid "<<mSrc->getGridId()<<"!", SIMWORLD_GRIDERROR); - } - - if((mAccMode!=AM_WRITE) && (mAccMode!=AM_READWRITE)) { - errFatal("GridAccessor::write","Acess to "<<PRINT_VEC(x,y,z)<<", region of grid "<<mSrc->getGridId()<<" not locked for writing!", SIMWORLD_GRIDERROR); - } - } - - //return (*mSrc)(mOffset[0]+x, mOffset[1]+y, mOffset[2]+z); - return (*mSrc)(x, y, z); -} - -//! init write access to region from src grid (no boundaries!) -template<class Scalar, int BOUNDARY> -void GridAccessor<Scalar,BOUNDARY>::lockRegion(nVec3i s, nVec3i e, int passid) { - //debMsg("GridAccessor","lockRegion #"<<tpatch->mPatchId<<", acc Mode="<<mAcc Mode<<" srcId"<<mSrc->getGridId() ); - - mRegionStart = s; - mRegionEnd = e; -} - -//! unlock -template<class Scalar, int BOUNDARY> -void GridAccessor<Scalar,BOUNDARY>::unlockRegion(int passid) { - // nothing to do now... -} - -//! read access (constant!) -template<class Scalar, int BOUNDARY> -const Scalar& -GridAccessor<Scalar,BOUNDARY>:: operator() (int x,int y, int z) const { - return (*mSrc)(x, y, z); -} - - -//! read access with gacc index -template<class Scalar, int BOUNDARY> -const Scalar& -GridAccessor<Scalar,BOUNDARY>:: operator() (GaccIndex index) const { - return (*mSrc)(index); -} -template<class Scalar, int BOUNDARY> -Scalar GridAccessor<Scalar,BOUNDARY>::getInterpolated(Real x, Real y, Real z) const -{ - return mSrc->getInterpolated(x,y,z); -} - - //const Scalar& operator() (GaccIndex index) const; -//! compute grid acc index -template<class Scalar, int BOUNDARY> GaccIndex -GridAccessor<Scalar,BOUNDARY>::getGaccIndex(int x,int y, int z) { - return (( (z) *mSrc->getSizeY()+ (y) ) *mSrc->getSizeX()+ (x) ); -} - -template<class Scalar, int BOUNDARY> -std::string -GridAccessor<Scalar,BOUNDARY>::toString() const { - std::ostringstream out; - out <<"accessor: "<<sizeof(Scalar)<<" region="<<mRegionStart<<" to "<<mRegionEnd<<" "; - // grid info? - - return out.str(); -} - - - -//***************************************************************************** -//***************************************************************************** -//***************************************************************************** - -//typedef Grid<int> FlagGrid; -#define FlagGrid Grid<int> - -//! obstacle flag types -typedef enum FluidSolverFlagsT { - FNONE=0, - FFLUID=1, - FOBSTACLE=2, - FEMPTY=4, - FINFLOW=8, - FOUTFLOW=16, - FPARTICLESOURCE=512, - FDENSITYSOURCE=1024, - F_TO_FLUID=(1<<16), // bit flag for changing types - F_RESEED=(1<<17), // reseed particles here - FINVALID=-1 -} FluidSolverFlags; - -// analogous to IS_OBS, IS_FLUID -inline bool fgIsObstacle(int flag) { - return ((flag & FOBSTACLE)!=0); -} -inline bool fgIsFluid(int flag) { - return ((flag & FFLUID)!=0); -} -inline bool fgIsEmpty(int flag) { - return ((flag & FEMPTY)!=0); -} -inline bool fgIsInflow(int flag) { - return ((flag & FINFLOW)!=0); -} -inline bool fgIsOutflow(int flag) { - return ((flag & FOUTFLOW)!=0); -} - -}; // namespace DDF - -#include "operators.h" -#endif // DDF_GRIDS_H - diff --git a/intern/smoke/intern/source/guihelpers.cpp b/intern/smoke/intern/source/guihelpers.cpp deleted file mode 100644 index 058afb2deba..00000000000 --- a/intern/smoke/intern/source/guihelpers.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Helper function for the GUI - * - *****************************************************************************/ - -#include "globals.h" -#include "vectorbase.h" -#include "solverparams.h" -#include "paramset.h" - -#include "fluidsolver.h" - -extern std::string gPhiRefName; -extern std::string gShowVelgridName; -extern std::string gShowRealgridName; - -// solver object from main -extern DDF::FluidSolver *gpGlutFsolver; - -// from parser.cpp -extern std::map<std::string, DDF::FluidSolver*> gFluidSolvers; - -// values from gui -extern std::map<std::string,float> gScaleRealDisplay; - -namespace DDF { - -extern Real gRealgridMin, gRealgridmMax; -extern Vec3 gVecgridMin, gVecgridMax; - -#if DDF_GLUTGUI==1 - -/******************************************************************************/ -// switch solvers & grids - - -template<class Scalar> -void glutgSelectNextGrid(std::map<std::string, Grid<Scalar>*> &gridMap, std::string &gname) { - bool debSwitch = false; - SolverParams* prms = gpGlutFsolver->getParams(); - Grid<Scalar> *retgrid = NULL; - - // clean up list, might contain entries with NULL pointers... - if(1) { - typename std::map<std::string, Grid<Scalar>*>::iterator iter = gridMap.begin(); - for ( ; iter!= gridMap.end(); iter++) { - if(!(*iter).second) { - gridMap.erase(iter); - iter--; - continue; - } - if (debSwitch) debMsg("deb disp","'"<<(*iter).second->getName()<<"' "); - } - - // sanity check, swap messes up names? - iter = gridMap.begin(); - for ( ; iter!= gridMap.end(); iter++) { - string name = (*iter).second->getName(); - prms->getGridType(name, retgrid); - //debMsg("glutGui","Scalar-grid '"<<retgrid->getName()<<"', '"<<name<<"' selected for display"); - - if(retgrid->getName().length() != name.length() ) { - errFatal("glutgSelectNextGrid","Invalid grid names!? "<<retgrid->getName()<<" vs. "<<name, SIMWORLD_GENERICERROR ); - } - retgrid = NULL; - } - } - - typename std::map<std::string, Grid<Scalar>*>::iterator iter = gridMap.begin(); - if (!(gname.length()>0)) { - // select first - if (debSwitch) debMsg("glutgSelectNextGrid","Not inited, getting first"); - - while((*iter).second->getDisplayFlags() & 1) { - if (debSwitch) debMsg("glutgSelectNextGrid","1 Skipping "<<" "<<(*iter).second->getName() ); - iter++; - if (iter == gridMap.end()) { iter = gridMap.begin(); } - } - - } else { - // iterate through map - //typename std::map<std::string, Grid<Scalar>*>::iterator iter = gridMap.begin(); - int cnt=0; - for (; iter!= gridMap.end(); iter++) { - if (debSwitch) debMsg("glutgSelectNextGrid","Searching "<<(*iter).second->getName() ); - if(gname == (*iter).second->getName()) break; - cnt++; - } - if (iter==gridMap.end()) { - if (debSwitch) debMsg("glutgSelectNextGrid","Not found, getting first "<<cnt); - iter = gridMap.begin(); - } else { - if (debSwitch) debMsg("glutgSelectNextGrid","Found, getting next "<<cnt<<" "<<(*iter).second->getName() ); - iter++; - - if (iter==gridMap.end()) { - if (debSwitch) debMsg("glutgSelectNextGrid","Last, getting first "<<cnt ); - iter = gridMap.begin(); - } - } - - // skip hidden grids... (getDisplayFlags&1) - while((*iter).second->getDisplayFlags() & 1) { - if (debSwitch) debMsg("glutgSelectNextGrid","Skipping "<<" "<<(*iter).second->getName() ); - - iter++; - if (iter == gridMap.end()) { iter = gridMap.begin(); } - - if (debSwitch) debMsg("glutgSelectNextGrid","Now "<<" "<<(*iter).second->getName() ); - } - } - - gname = (*iter).second->getName(); - prms->getGridType(gname, retgrid); - - debMsg("glutGui","Scalar-grid '"<<retgrid->getName()<<"', '"<<gname<<"' selected for display"); -} - -void glutgSelectNextFloatArray() { - SolverParams* prms = gpGlutFsolver->getParams(); - glutgSelectNextGrid<Real>( prms->mGridsReal, gShowRealgridName ); -} - -// init display, called eg after glutgSelectNextFloatArray -void initFloatArrayDisplay() { - // new grid? set standard scale - if( gScaleRealDisplay[gShowRealgridName] <= 0. ) gScaleRealDisplay[gShowRealgridName] = 1.; - - // show min/max values for selected grid - if(1) { - Grid<Real> *realGrid = NULL; - realGrid = gpGlutFsolver->getParams()->getGridReal(gShowRealgridName); // DEBrealGrid - goFindMinMax<Real> gomm = goFindMinMax<Real>( gpGlutFsolver->getGridFlags(), realGrid ); - - gRealgridMin = gomm.mMinVal; - gRealgridmMax = gomm.mMaxVal; - debMsg("MINMAX-REAL","min="<<gRealgridMin<<" at "<<gomm.mMinPos<<" max="<<gRealgridmMax<<" at "<<gomm.mMaxPos); - } -} - -void glutgSelectNextVec3Array() { - SolverParams* prms = gpGlutFsolver->getParams(); - glutgSelectNextGrid<Vec3>( prms->mGridsVec3, gShowVelgridName ); -} - -void glutgSelectNextFloatArrayO() { - //if (gFluidSolvers.find(solverName) != gFluidSolvers.end() ) { gpGlutFsolver = gFluidSolvers[solverName]; } - bool debSwitch = false; - SolverParams* prms = gpGlutFsolver->getParams(); - Grid<Real> *grid = NULL; - - // clean up list, might contain entries with NULL pointers... - for ( std::map<std::string, Grid<Real>*>::iterator iter = prms->mGridsReal.begin(); iter!= prms->mGridsReal.end(); iter++) { - if(!(*iter).second) { - prms->mGridsReal.erase(iter); - iter--; - continue; - } - //if (debSwitch) debMsg("deb disp","'"<<(*iter).second->getName()<<"' "); - } - - if (!(gShowRealgridName.length()>0)) { - // select first - if (debSwitch) debMsg("glutgSelectNextFloatArray","Not inited, getting first"); - gShowRealgridName = (*prms->mGridsReal.begin()).second->getName(); - grid = prms->getGridReal(gShowRealgridName); - - } else { - // iterate through map - std::map<std::string, Grid<Real>*>::iterator iter = prms->mGridsReal.begin(); - int cnt=0; - for (; iter!= prms->mGridsReal.end(); iter++) { - if (debSwitch) debMsg("glutgSelectNextFloatArray","Searching "<<(*iter).second->getName() ); - if(gShowRealgridName == (*iter).second->getName()) break; - cnt++; - } - if (iter==prms->mGridsReal.end()) { - if (debSwitch) debMsg("glutgSelectNextFloatArray","Not found, getting first "<<cnt); - iter = prms->mGridsReal.begin(); - } else { - if (debSwitch) debMsg("glutgSelectNextFloatArray","Found, getting next "<<cnt<<" "<<(*iter).second->getName() ); - iter++; - - if (iter==prms->mGridsReal.end()) { - if (debSwitch) debMsg("glutgSelectNextFloatArray","Last, getting first "<<cnt ); - iter = prms->mGridsReal.begin(); - //return; - } - } - - gShowRealgridName = (*iter).second->getName(); - grid = prms->getGridReal(gShowRealgridName); - } - - debMsg("glutGui","Real-grid '"<<grid->getName()<<"' selected for display"); -} - -void glutgSelectNextSolver() { - //if (gFluidSolvers.find(solverName) != gFluidSolvers.end() ) { gpGlutFsolver = gFluidSolvers[solverName]; } - bool debSwitch = false; - - if (!gpGlutFsolver) { - if (debSwitch) debMsg("glutgSelectNextSolver","Not inited, getting first"); - gpGlutFsolver = (*gFluidSolvers.begin()).second; - return; - } else { - - std::map<std::string, DDF::FluidSolver*>::iterator iter = gFluidSolvers.begin(); - int cnt=0; - for (; iter!= gFluidSolvers.end(); iter++) { - //debMsg("---"," = "<<(long int)(gpGlutFsolver)<<" c "<<cnt<<","<< (long int)((*iter).second) ); - if (gpGlutFsolver == (*iter).second) break; - cnt++; - } - if (iter==gFluidSolvers.end()) { - if (debSwitch) debMsg("glutgSelectNextSolver","Not found, getting first "<<cnt); - gpGlutFsolver = (*gFluidSolvers.begin()).second; - } else { - iter++; - if (iter==gFluidSolvers.end()) { - if (debSwitch) debMsg("glutgSelectNextSolver","Last, getting first "<<cnt); - gpGlutFsolver = (*gFluidSolvers.begin()).second; - } else { - if (debSwitch) debMsg("glutgSelectNextSolver","Found, getting next "<<cnt); - gpGlutFsolver = (*iter).second; - } - } - } - debMsg("glutGui","Solver '"<<gpGlutFsolver->getName()<<"' selected for display"); - - SolverParams* prms = gpGlutFsolver->getParams(); - if(!prms->haveGridReal(gShowRealgridName)) { - glutgSelectNextFloatArray(); - } - if(!prms->haveGridVec3(gShowVelgridName)) { - glutgSelectNextVec3Array(); - } -} - - -#endif // DDF_GLUTGUI==1 -}; // namespace DDF - diff --git a/intern/smoke/intern/source/initplugins.cpp b/intern/smoke/intern/source/initplugins.cpp deleted file mode 100644 index a43bd152771..00000000000 --- a/intern/smoke/intern/source/initplugins.cpp +++ /dev/null @@ -1,499 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Plugins to setup fluid grids - * - *****************************************************************************/ - -// lsdebug -#include "fluidsolver.h" -#include "solverplugin.h" -#include "paramset.h" - - -namespace DDF { - -//***************************************************************************** -// simple, set constant value - -class sinitSetConstant : public SolverPlugin { - public: - sinitSetConstant() : SolverPlugin(), - mGrid("-unnamed-"), mVal(0.) { }; - ~sinitSetConstant() { }; - - virtual bool parseParams(const ParamSet& params) { - mGrid = params.FindOneString("gridname", mGrid ); - mVal = params.FindOneFloat("value", mVal ); - return true; - }; - virtual bool initPlugin() { return true; }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("sinitSetConstant","step "<<dt); - Grid<int>* flags = mpPlParams->getGridInt("flags"); - - // distinguish data types - if(mpPlParams->haveGridInt(mGrid) && 1) { - Grid<int>* grid = mpPlParams->getGridInt(mGrid); - fsSetConstant<int>(flags, grid, (int)mVal); - } else if(mpPlParams->haveGridReal(mGrid) && 1) { - Grid<Real>* grid = mpPlParams->getGridReal(mGrid); - fsSetConstant<Real>(flags, grid, (Real)mVal); - } else if(mpPlParams->haveGridVec3(mGrid) && 1) { - Grid<Vec3>* grid = mpPlParams->getGridVec3(mGrid); - fsSetConstant<Vec3>(flags, grid, Vec3(mVal)); - } else { - errFatal("sinitSetConstant::performStep","Grid not found "<<mGrid , SIMWORLD_GRIDERROR); - } - return true; - }; - - protected: - // grid names to swap - std::string mGrid; - // value - float mVal; -}; - -template<class T> -class fsSetConditional : public GridOpBase { - public: - fsSetConditional(FlagGrid *flags, Grid<T> *dst , T target, int flag) : - GridOpBase(), mpDst(dst), mTargetVal(target), mCFlag(flag) { - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsSetConditional() { }; - void resetVariables() { }; - void buildCallList() { - setFlags(mpFlags); - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - }; - // add forces and update empty cells free surface boundaries - inline void operator() (int i, int j, int k) { - if ((getFlagAcc()(i,j,k) & mCFlag)==mCFlag) - gaDst.write(i,j,k) = mTargetVal; - }; - void reduce(fsSetConditional &op) { }; - - protected: - Grid<T> *mpDst; - GridAccessor<T,0> gaDst; - T mTargetVal; - int mCFlag; -}; // fsSetConditional */ - -class spluginSetConditional : public SolverPlugin { - public: - spluginSetConditional() : SolverPlugin(), - mGrid("-unnamed-"), mFlag(4), mTargetVec(0.) { - debMsg("spluginSetConditional","cons"); - }; - ~spluginSetConditional() { - debMsg("spluginSetConditional","des"); - }; - - virtual bool parseParams(const ParamSet& params) { - debMsg("spluginSetConditional","parse"); - mGrid = params.FindOneString("gridname", mGrid); - mFlags = params.FindOneString("flaggrid", "flags"); - mTargetVec = params.FindOneVector("target-vec", mTargetVec ); - mTargetReal = params.FindOneFloat("target-real", 0. ); - mFlag = params.FindOneInt("flag", mFlag ); - return true; - }; - virtual bool initPlugin() { - debMsg("spluginSetConditional","init"); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spluginSetConditional"," dt="<<dt<<" dest:"<<mGrid ); - FlagGrid* flagg = mpPlParams->getGridInt(mFlags); - - if (mpPlParams->haveGridVec3(mGrid)) { - fsSetConditional<Vec3>(flagg, mpPlParams->getGridVec3(mGrid), mTargetVec, mFlag); - } else if (mpPlParams->haveGridReal(mGrid)) { - fsSetConditional<Real>(flagg, mpPlParams->getGridReal(mGrid), mTargetReal, mFlag); - } else { - errFatal("spluginSetConditional::performStep","Grid not found "<<mGrid , SIMWORLD_GRIDERROR); - } - return true; - }; - - protected: - std::string mGrid,mFlags; - int mFlag; - Vec3 mTargetVec; - Real mTargetReal; -}; - -//***************************************************************************** -// initializes the domain with empty cells and a single cell border (or -// more depending on mBorder param) of obstacles - -class goInitBoxDomain : public GridOpBase { - public: - goInitBoxDomain(Grid<int>* dst, int border, int setempty, int flagInside = FEMPTY, int flagOutside = FOBSTACLE, int flagFloor = 0) : - GridOpBase(), mpFlagMod(dst), mBorder(border), mDoSetEmpty(setempty), mFlagInside(flagInside), mFlagOutside(flagOutside), mFlagFloor(flagFloor) { - mpFlags = NULL; // unused - mS = mpFlagMod->getSize()-nVec3i(1,1,1); - applyOperatorToGridsWithoutFlags(this, mpFlagMod); - }; - - ~goInitBoxDomain() { }; - void resetVariables() { }; - void buildCallList() { - gaFlagMod.gridAccInit(mpFlagMod, AM_WRITE, gaCalls); - }; - - // add forces and update empty cells free surface boundaries - inline void operator() (int i, int j, int k) { - - - gaFlagMod.write(i,j,k); - if ((i<1+mBorder) || (i>=mS.x-mBorder) - || (j<1+mBorder) || (j>=mS.y-mBorder) -# if DDF_DIMENSION==3 - || (k<1+mBorder) || (k>=mS.z-mBorder) -# endif - ) { - gaFlagMod.write(i,j,k) = mFlagOutside; - } else { - if(mDoSetEmpty) gaFlagMod.write(i,j,k) = mFlagInside; - } - if (j==0 && mFlagFloor > 0) gaFlagMod.write(i,j,k) = mFlagFloor; - }; - void reduce(goInitBoxDomain &op) { }; - - protected: - Grid<int> *mpFlagMod; - GridAccessor<int,0> gaFlagMod; - nVec3i mS; - int mBorder, mDoSetEmpty, mFlagInside, mFlagOutside, mFlagFloor; -}; // goInitBoxDomain - -class sinitBoxDomain : public SolverPlugin { - public: - sinitBoxDomain() - : SolverPlugin(), mGrid("flags"), mBorder(0) , mDoSetEmpty(1) - { }; - ~sinitBoxDomain() { }; - - virtual bool parseParams(const ParamSet& params) { - mGrid = params.FindOneString("gridname", mGrid ); - mBorder = params.FindOneInt("border", mBorder ); - mDoSetEmpty = params.FindOneInt("set-empty", mDoSetEmpty ); - mFlag1 = params.FindOneInt("flag-inside", FEMPTY ); - mFlag2 = params.FindOneInt("flag-border", FOBSTACLE ); - mFloor = params.FindOneInt("flag-floor", 0); - return true; - }; - virtual bool initPlugin() { return true; }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("sinitBoxDomain","step "<<dt); - Grid<int>* grflags = mpPlParams->getGridInt(mGrid); - - goInitBoxDomain(grflags, mBorder,mDoSetEmpty,mFlag1,mFlag2,mFloor); - return true; - }; - - protected: - std::string mGrid; - int mBorder, mDoSetEmpty, mFlag1, mFlag2, mFloor; -}; - -//***************************************************************************** -// creates a fluid box spanned by lowCorner and highCorner (both specified -// in range [0,1]) - -class goSetBoxFluid : public GridOpBase { - public: - goSetBoxFluid(Grid<int> *dst, const Vec3& lowCorner, const Vec3& highCorner, int type, bool brd, - Grid<Vec3>* vel = NULL, Vec3 set = Vec3(0.), Grid<Real>* dist = NULL, Grid<Vec3>* norm = NULL ) : - GridOpBase(), mpFlagMod(dst), mType(type), mBorder(brd), - mpVel(vel), mVelSet(set), mpDist(dist), mpNorm(norm) { - mpFlags = NULL; - mILen = 1. / dst->getMaxSize(); - mLowCorner = Vec3(lowCorner.x * float(mpFlagMod->getSizeX()), lowCorner.y * float(mpFlagMod->getSizeY()), lowCorner.z * float(mpFlagMod->getSizeZ())); - mHighCorner = Vec3(highCorner.x * float(mpFlagMod->getSizeX()), highCorner.y * float(mpFlagMod->getSizeY()), highCorner.z * float(mpFlagMod->getSizeZ())); - for (int i=0;i<3;i++) - if(mLowCorner[i] > mHighCorner[i]) { - Real a=mLowCorner[i]; mLowCorner[i]=mHighCorner[i]; mHighCorner[i]=a; } - applyOperatorToGridsWithoutFlags(this, mpFlagMod); - }; - - ~goSetBoxFluid() { }; - void resetVariables() { }; - void buildCallList() { - gaFlagMod.gridAccInit(mpFlagMod, AM_WRITE, gaCalls); - if(mpVel) gaVel.gridAccInit(mpVel, AM_WRITE, gaCalls); - if(mpDist) gaDist.gridAccInit(mpDist, AM_READWRITE, gaCalls); - if(mpNorm) gaNorm.gridAccInit(mpNorm, AM_READWRITE, gaCalls); - }; - - // add forces and update empty cells free surface boundaries - inline void operator() (int i, int j, int k) { - if (mBorder && (i==0 || j==0 || k==0 || i==mpFlagMod->getSizeX()-1 || j==mpFlagMod->getSizeY()-1 || k==mpFlagMod->getSizeZ()-1)) - gaFlagMod.write(i,j,k) = FOBSTACLE; - if (gaFlagMod.write(i,j,k) == FOBSTACLE) - return; - if ((i>=mLowCorner.x) && (i<=mHighCorner.x) - && (j>=mLowCorner.y) && (j<=mHighCorner.y) -#if DDF_DIMENSION==3 - && (k>=mLowCorner.z) && (k<=mHighCorner.z) -#endif - ) - { - if(mpVel) { - Vec3 &v = gaVel.write(i,j,k); - if(gaFlagMod.write(i,j,k) == mType) { - //v += mVelSet; - //v *= 0.5; // warning, depends on init order... - // NT CJW test, dont overwrite!? - } else { - v = mVelSet; - } - } - - if(fgIsObstacle(mType)) - gaFlagMod.write(i,j,k) = mType; - else - gaFlagMod.write(i,j,k) |= mType; - } - // build distance field - if (mpDist && mpNorm) { - int numIn=0; - Vec3 pos(i,j,k), ref(0.); - for (int e=0;e<3;e++) { - if ((pos[e]>=mLowCorner[e]) && (pos[e]<=mHighCorner[e])) { - ref[e] = pos[e]; - numIn++; - } else if (pos[e]>mLowCorner[e]) - ref[e] = mHighCorner[e]; - else - ref[e] = mLowCorner[e]; - } - Vec3 nrm = pos-ref; - Real newDist = normalize(nrm)*mILen, oldDist = gaDist(i,j,k); - if (oldDist == 0 || newDist < oldDist) { - gaDist.write(i,j,k) = newDist; - gaNorm.write(i,j,k) = nrm; - } - } - - }; - void reduce(goSetBoxFluid &op) { }; - - protected: - Grid<int> *mpFlagMod; - GridAccessor<int,0> gaFlagMod; - Vec3 mLowCorner, mHighCorner; - int mType; - bool mBorder; - - // optional velocity - Grid<Vec3> *mpVel; - GridAccessor<Vec3,0> gaVel; - Vec3 mVelSet; - Real mILen; - Grid<Real> *mpDist; - Grid<Vec3> *mpNorm; - GridAccessor<Vec3,0> gaNorm; - GridAccessor<Real,0> gaDist; -}; // goSetBoxFluid - -//***************************************************************************** -// creates a fluid ball with given radius at given position (both specified -// in range [0,1]) -// optionally, also initializes velocity - -class goSetBallFluid : public GridOpBase { - public: - goSetBallFluid(Grid<int> *dst, const Vec3& center, const Vec3& scale, Real radius, int type, int cyl, - Grid<Vec3>* vel = NULL, Vec3 set = Vec3(0.), Grid<Real>* dist = NULL, Grid<Vec3>* norm = NULL ) : - GridOpBase(), mpFlagMod(dst), mpDist(dist), mpNorm(norm), mType(type), mCylinderAxis(cyl), - mpVel(vel), mVelSet(set) { - mpFlags = NULL; - mScale = Vec3(1.) / scale; - mCenter = Vec3( - center.x * float(mpFlagMod->getSizeX()), - center.y * float(mpFlagMod->getSizeY()), - center.z * float(mpFlagMod->getSizeZ())); - mRadiusSqr = radius * float(mpFlagMod->getSizeX()); - mRadiusSqr = mRadiusSqr*mRadiusSqr; - mILen = 1. / (Real)dst->getMaxSize(); - applyOperatorToGridsWithoutFlags(this, mpFlagMod); - }; - - ~goSetBallFluid() { }; - void resetVariables() { }; - void buildCallList() { - gaFlagMod.gridAccInit(mpFlagMod, AM_WRITE, gaCalls); - if(mpVel) gaVel.gridAccInit(mpVel, AM_WRITE, gaCalls); - if(mpDist) gaDist.gridAccInit(mpDist, AM_READWRITE, gaCalls); - if(mpNorm) gaNorm.gridAccInit(mpNorm, AM_READWRITE, gaCalls); - }; - - inline void operator() (int i, int j, int k) { - if (gaFlagMod.write(i,j,k) == FOBSTACLE) - return; - //Real d[3]; - Vec3 d; - d[0] = mCenter.x - i; - d[1] = mCenter.y - j; -#if DDF_DIMENSION==2 - //const Real d = dx*dx + dy*dy; - d[2] = 0.; -#else - d[2] = mCenter.z - k; -#endif - d *= mScale; - - //const Real d = dx*dx + dy*dy + dz*dz; - if(mCylinderAxis>=0) d[mCylinderAxis] = 0.; - const Real dist = normNoSqrt(d); - - if (dist < mRadiusSqr) - { - if(mpVel) { - Vec3 &v = gaVel.write(i,j,k); - if(gaFlagMod.write(i,j,k) == mType) { - //v += mVelSet; - //v *= 0.5; // warning, depends on init order... - // NT CJW test, dont overwrite!? - } else { - v = mVelSet; - } - } - - // set flag - //gaFlagMod.write(i,j,k) = mType; - if(fgIsObstacle(mType)) - gaFlagMod.write(i,j,k) = mType; - else - gaFlagMod.write(i,j,k) |= mType; - - } else if (mpDist && mpNorm) { - Real ds = sqrt(dist); - Real oldDist = gaDist(i,j,k), newDist = (ds - sqrt(mRadiusSqr)) * mILen; - if (oldDist==0 || newDist<oldDist) { - gaDist.write(i,j,k) = newDist; - gaNorm.write(i,j,k) = -d / ds; - } - } - - }; - void reduce(goSetBallFluid &op) { }; - - protected: - Grid<int> *mpFlagMod; - Grid<Real> *mpDist; - Grid<Vec3> *mpNorm; - GridAccessor<int,0> gaFlagMod; - GridAccessor<Real,0> gaDist; - GridAccessor<Vec3,0> gaNorm; - Vec3 mCenter; - Vec3 mScale; - Real mRadiusSqr,mILen; - int mType, mCylinderAxis; - - // optional velocity - Grid<Vec3> *mpVel; - GridAccessor<Vec3,0> gaVel; - Vec3 mVelSet; -}; // goSetBallFluid - -class sinitSphere : public SolverPlugin { - public: - sinitSphere() : SolverPlugin() { }; - ~sinitSphere() { }; - - virtual bool parseParams(const ParamSet& params) { - mGrid = params.FindOneString("gridname", "flags"); - mCenter = params.FindOneVector("center", Vec3(0.5,0.5,0.5)); - mRadius = params.FindOneFloat("radius", 0.2); - mType = params.FindOneInt("type", FOBSTACLE); - mDist = params.FindOneString("dist", ""); - mNorm = params.FindOneString("norm", ""); - return true; - }; - virtual bool initPlugin() { return true; }; - - virtual bool performStep(Real dt) { - debMsg("sinitSphere","step "<<dt); - Grid<int>* grflags = mpPlParams->getGridInt(mGrid); - Grid<Real>* dist = mDist.empty() ? NULL : mpPlParams->getGridReal(mDist); - Grid<Vec3>* norm = mNorm.empty() ? NULL : mpPlParams->getGridVec3(mNorm); - - goSetBallFluid(grflags, mCenter, 1., mRadius, mType, -1, NULL, Vec3(0.), dist, norm); - return true; - }; - protected: - std::string mGrid, mDist, mNorm; - Vec3 mCenter; - Real mRadius; - int mType; -}; - -class sinitBox : public SolverPlugin { - public: - sinitBox() : SolverPlugin() { }; - ~sinitBox() { }; - - virtual bool parseParams(const ParamSet& params) { - mGrid = params.FindOneString("gridname", "flags"); - mPos1 = params.FindOneVector("pos1", Vec3(0.)); - mPos2 = params.FindOneVector("pos2", Vec3(0.)); - mType = params.FindOneInt("type", FOBSTACLE); - mDist = params.FindOneString("dist", ""); - mNorm = params.FindOneString("norm", ""); - return true; - }; - virtual bool initPlugin() { return true; }; - - virtual bool performStep(Real dt) { - debMsg("sinitBox","step "<<dt); - Grid<int>* grflags = mpPlParams->getGridInt(mGrid); - Grid<Real>* dist = mDist.empty() ? NULL : mpPlParams->getGridReal(mDist); - Grid<Vec3>* norm = mNorm.empty() ? NULL : mpPlParams->getGridVec3(mNorm); - - goSetBoxFluid(grflags, mPos1, mPos2, mType, false, NULL, Vec3(0.), dist, norm); - return true; - }; - protected: - std::string mGrid, mDist, mNorm; - Vec3 mPos1, mPos2; - int mType; -}; - -//***************************************************************************** - -SolverPlugin* MakeInitPlugin(std::string name) { - - if(name.compare( string("set-constant") )==0) { - return new sinitSetConstant; - } else if(name.compare( string("set-conditional") )==0) { - return new spluginSetConditional; - } else if (name.compare( string("init-box-domain") )==0) { - return new sinitBoxDomain; - } else if (name.compare( string("init-sphere") )==0) { - return new sinitSphere; - } else if (name.compare( string("init-box") )==0) { - return new sinitBox; - } - return NULL; -} - -}; // DDF - diff --git a/intern/smoke/intern/source/operators.h b/intern/smoke/intern/source/operators.h deleted file mode 100644 index cbccfa80597..00000000000 --- a/intern/smoke/intern/source/operators.h +++ /dev/null @@ -1,922 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Basic functions for applying operators to grids - * - *****************************************************************************/ - -#ifndef DDF_OPERATORS_H -#define DDF_OPERATORS_H - -#include "grid.h" -#if DDF_OPENMP==1 -#include <omp.h> -#endif // DDF_OPENMP==1 - -namespace DDF { - -// globals, allocated in globals.cpp -// id's of seperate passes (for debugging) -extern int gGridPassCounter; - - - -//***************************************************************************** -// operators without openmp - -template<class Operator, class GridClass> -void applyOperatorWithBoundSimple(Operator *opOrg, GridClass *grid, int bound) -{ - int passid = ++gGridPassCounter; - opOrg->resetVariables(); - - Operator *op = opOrg; - op->getGaCalls().clear(); - op->buildCallList(); - //FlagGrid *pFlags = op->getFlags(); // FLAGMOD - nVec3i s(0,0,0),e(grid->getSize()); - - for(size_t gi=0; gi<op->getGaCalls().size(); gi++) { - op->getGaCalls()[gi]->lockRegion(nVec3i(s), nVec3i(e), passid); - } - -#if DDF_DIMENSION==3 - for(int k=0+bound; k<grid->getSizeZ()-bound; k++) { -#else // DDF_DIMENSION==3 - { const int k=gPatchSize/2; -#endif // DDF_DIMENSION==3 - for(int j=0+bound; j<grid->getSizeY()-bound; j++) - for(int i=0+bound; i<grid->getSizeX()-bound; i++) { - (*op)(i,j,k); - } - } - - for(size_t gi=0; gi<op->getGaCalls().size(); gi++) { - op->getGaCalls()[gi]->unlockRegion(passid); - } - - - // perform operator reduction - opOrg->reduce(*op); - - // DEBUG - check if patch has not the right passid!? -} - -template<class Operator> -void applyOperatorToGridsSimple(Operator *opOrg) -{ - applyOperatorWithBoundSimple(opOrg, opOrg->getFlags(), 0); -} - -//***************************************************************************** -// operators with openmp - -template<class Operator, class GridClass> -void applyOperatorWithBoundToGrid(Operator *opOrg, GridClass *grid, int bound) -{ - int passid = ++gGridPassCounter; - opOrg->resetVariables(); - -# if DDF_OPENMP==1 -# pragma omp parallel default(shared) - { // omp region - const int id = omp_get_thread_num(); - const int Nthrds = omp_get_num_threads(); -# else - { // non omp - const int id=0; // , Nthrds=1; -# endif - - Operator myop = *opOrg; - Operator *op = &myop; -# pragma omp critical (BUILDCALLLIST) - { - op->setThreadId(id); - op->resetVariables(); - op->getGaCalls().clear(); - op->buildCallList(); - } - //FlagGrid *pFlags = op->getFlags(); // FLAGMOD - - int gridsize = grid->getSizeZ(); - // divide up domain along z dir - // for 2d, parallelize along Y instead - if(gDim==2) gridsize = grid->getSizeY(); -# if (DDF_OPENMP==1) - - const int totalSize = gridsize -2* bound; - const int kStart = ( id * (totalSize / Nthrds) ) + bound ; - int kEnd = ( (id+1) * (totalSize / Nthrds) ) + bound; - - // make sure the last thread covers everything - if(id == Nthrds-1) kEnd = gridsize -bound; - - // init region for write accesses - nVec3i s = nVec3i( 0 ); - nVec3i e = nVec3i( grid->getSize() ); - s[2] = kStart; - e[2] = kEnd; - - // fix access in 2D - if(gDim==2) { - s[1]= kStart; - e[1]= kEnd; - - s[2]=gPatchSize/2; - e[2] = s[2]+1; - } - - if(0) debMsg("T","thread "<<id<<"/"<<Nthrds<<" k="<<kStart<<"-"<<kEnd<<" , totS="<<totalSize<<" gridK="<<gridsize<<" bound="<<bound ); -# else - // constants for single threaded version - const int kStart = 0 + bound; - const int kEnd = gridsize - bound; - nVec3i s = nVec3i( 0 ); - nVec3i e = nVec3i( grid->getSize() ); -# endif - - for(size_t gi=0; gi<op->getGaCalls().size(); gi++) { - op->getGaCalls()[gi]->lockRegion(nVec3i(s), nVec3i(e), passid); - } - - // loop over grid -# if DDF_DIMENSION==3 - for(int k=kStart; k<kEnd; k++) { - for(int j=0+bound; j<grid->getSizeY()-bound; j++) -# else // DDF_DIMENSION==3 - const int k=gPatchSize/2; - for(int j=kStart; j<kEnd; j++) { -# endif // DDF_DIMENSION==3 - for(int i=0+bound; i<grid->getSizeX()-bound; i++) { - (*op)(i,j,k); - } - } // parallel loop - - - for(size_t gi=0; gi<op->getGaCalls().size(); gi++) { - op->getGaCalls()[gi]->unlockRegion(passid); - } - - // perform operator reduction -# pragma omp critical (REDUCE) - { opOrg->reduce(myop); } - - //debMsg("P","id "<<id<<"/"<<Nthrds<<", pids"<<npids<<" idsum"<<idsum); - } // omp region -} - -template<class Operator, class GridClass> -void applyOperatorToGridsWithoutFlags(Operator *opOrg, GridClass *grid) -{ - applyOperatorWithBoundToGrid(opOrg, grid, 0); -} - -template<class Operator> -void applyOperatorToGrids(Operator *opOrg) -{ - applyOperatorWithBoundToGrid(opOrg, opOrg->getFlags(), 0); -} - - - - - - -//***************************************************************************** -// base class for grid operators -// currently only manages flag access -class GridOpBase { - public: - GridOpBase() : - mpFlags(NULL), gaFlags(), gaCalls() - { - getGaCalls().clear(); - //gGridPassCounter++; debMsg("GridPass","pass="<<gGridPassCounter); - }; - virtual ~GridOpBase() {}; - - // init flag grid - inline void setFlags(FlagGrid *set) { - mpFlags=set; - if(mpFlags) { - gaFlags.gridAccInit(mpFlags, AM_READ, gaCalls); - } else { - errFatal("GridOpBase::setFlags","Flags pointer not set!", SIMWORLD_GENERICERROR); - } - } - // some operators dont need a flag pointer, use this function to zero it, setFlags requires a valid one! - inline void setNullFlagPointer() { - mpFlags = NULL; - } - // virtual, not time ciritcal - important for e.g. reduction, see below - virtual void resetVariables() { }; - - // set & get flag grid access - inline FlagGrid *getFlags() { return mpFlags; } - inline GridAccessor<int,0>& getFlagAcc() { return gaFlags; } - inline int getThreadId() { return gaCalls.threadId; } - inline std::vector<GridAccessorBase*>& getGaCalls() { return gaCalls.calls; } - inline void setThreadId(int set) { gaCalls.threadId=set; } - - // Warning - make sure copying works, e.g., dont build call list - // before each thread has own operator copy - - // Function to be implemented: - // void resetVariables(): - // - reset fields that are modified during sweep (e.g. dotproduct - // reset to zeroo) - // - this can be called multiple times, e.g., for reducing - // ! crucial for correct multi threading ! , dont modify such - // fields in constructor or buildCallList - // void buildCallList(): - // - init grid accessors, add to gaCalls.calls - // - call setFlags(mpFlags) to init base op - // void operator() (int i, int j, int k) : - // - perform actual computation - // - note, flag handling has to be done in operator - // (e.g., const int currFlag = getFlagAcc()(i,j,k); ) - // void reduce(Operator &op) : - // - reduce results from operator "op" to current one - // - needed for multithreaded operator execution - // ... getValue() : - // - return result of computations - - protected: - //! allow access to flag grid - FlagGrid *mpFlags; - GridAccessor<int,0> gaFlags; - GaCallContainer gaCalls; -}; // GridOpBase - -// same as GridOpBase, but allows access to the border of -// the flag array -template<int BORDER> -class GridOpBaseFlagbord { - public: - GridOpBaseFlagbord() : - mpFlags(NULL), gaFlags(), gaCalls() - { - getGaCalls().clear(); - }; - virtual ~GridOpBaseFlagbord() {}; - - // init flag grid - inline void setFlags(FlagGrid *set) { - mpFlags=set; - if(mpFlags) { - gaFlags.gridAccInit(mpFlags, AM_READ, gaCalls); - } - } - // virtual, not time ciritcal - important for e.g. reduction, see below - virtual void resetVariables() { }; - - // set & get flag grid access - inline FlagGrid *getFlags() { return mpFlags; } - inline GridAccessor<int, BORDER>& getFlagAcc() { return gaFlags; } - inline int getThreadId() { return gaCalls.threadId; } - inline std::vector<GridAccessorBase*>& getGaCalls() { return gaCalls.calls; } - inline void setThreadId(int set) { gaCalls.threadId=set; } - - protected: - //! allow access to flag grid - FlagGrid *mpFlags; - GridAccessor<int, BORDER> gaFlags; - GaCallContainer gaCalls; -}; // GridOpBaseFlagbord - - - -//***************************************************************************** -// test operator, does nothing -class GridOpDummy : public GridOpBase { - public: - GridOpDummy(FlagGrid *flags) : GridOpBase() { - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~GridOpDummy() { }; - void buildCallList() { - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { -#if DDF_DEBUG==1 - i=j=k= 0; -#endif - }; - void reduce(GridOpDummy &op) { }; -}; // GridOpDummy */ - - - -//***************************************************************************** -// touch operator, resets memory in threaded fashion -template<class Scalar> -class GridOpTouchMemory : public GridOpBase { - public: - GridOpTouchMemory(FlagGrid *flags, Grid<Scalar> *gDst, Scalar val) : GridOpBase() { - mValue = val; - mpDst = gDst; - flags = NULL; - // TODO remove mpFlags = flags; - applyOperatorToGridsWithoutFlags(this, mpDst); - }; - ~GridOpTouchMemory() { }; - void resetVariables() { }; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - setNullFlagPointer(); - }; - inline void operator() (int i, int j, int k) { - //debMsg("a","b "<<PRINT_IJK<<" = "<<mValue<<", "<<mpDst->getSize() ); - gaDst.write(i,j,k) = mValue; - }; - void reduce(GridOpTouchMemory &op) { }; - protected: - Grid<Scalar> *mpDst; - GridAccessor<Scalar,0> gaDst; - Scalar mValue; -}; // GridOpTouchMemory */ - - -//***************************************************************************** -// copy whole grid -template<class SCALAR> -class goCopyGrid : public GridOpBase { - public: - goCopyGrid(Grid<SCALAR> *gDst, Grid<SCALAR> *gSrc) : GridOpBase() { - mpDst = gDst; - mpSrc = gSrc; - const bool useMemcpy = true; - - // sanity check - if(mpSrc->getNumElements() != mpDst->getNumElements() ) { - errFatal("goCopyGrid","Invalid grid sizes! "<< mpSrc->getNumElements() <<" vs "<< mpDst->getNumElements(), SIMWORLD_GRIDERROR ); - } - - if(useMemcpy) { - // direct copy - memcpy( &mpDst->getGlobal(0,0,0) , &mpSrc->getGlobal(0,0,0), mpDst->getNumElements() * sizeof(SCALAR) ); - } else { - // parallel transfer - applyOperatorToGridsWithoutFlags(this, mpDst); - } - }; - ~goCopyGrid() { }; - void resetVariables() { }; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - gaSrc.gridAccInit(mpSrc, AM_READ, gaCalls); - setNullFlagPointer(); - }; - inline void operator() (int i, int j, int k) { - gaDst.write(i,j,k) = gaSrc(i,j,k); - }; - void reduce(goCopyGrid &op) { }; - protected: - Grid<SCALAR> *mpDst; - Grid<SCALAR> *mpSrc; - GridAccessor<SCALAR,0> gaDst; - GridAccessor<SCALAR,0> gaSrc; -}; // goCopyGrid */ - -// copy one element of a vector to a scalar grid -template<class Scalar,int NUM> -class goCopyVec3ToScalar : public GridOpBase { - public: - goCopyVec3ToScalar(Grid<Scalar> *gDst, Grid<Vec3> *gSrc) : GridOpBase() { - mpDst = gDst; - mpSrc = gSrc; - applyOperatorToGridsWithoutFlags(this, mpDst); - }; - ~goCopyVec3ToScalar() { }; - void resetVariables() { }; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - gaSrc.gridAccInit(mpSrc, AM_READ, gaCalls); - setNullFlagPointer(); - }; - inline void operator() (int i, int j, int k) { - Real spass=gaSrc(i,j,k)[NUM]; - gaDst.write(i,j,k) = gaSrc(i,j,k)[NUM]; - }; - void reduce(goCopyVec3ToScalar &op) { }; - protected: - Grid<Scalar> *mpDst; - Grid<Vec3> *mpSrc; - GridAccessor<Scalar,0> gaDst; - GridAccessor<Vec3,0> gaSrc; -}; // goCopyVec3ToScalar */ - -// copy one element of a vector from a scalar grid -template<class Scalar,int NUM> -class goCopyScalarToVec3 : public GridOpBase { - public: - goCopyScalarToVec3(Grid<Vec3> *gDst, Grid<Scalar> *gSrc) : GridOpBase() { - mpDst = gDst; - mpSrc = gSrc; - applyOperatorToGridsWithoutFlags(this, mpDst); - }; - ~goCopyScalarToVec3() { }; - void resetVariables() { }; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - gaSrc.gridAccInit(mpSrc, AM_READ, gaCalls); - setNullFlagPointer(); - }; - inline void operator() (int i, int j, int k) { - gaDst.write(i,j,k)[NUM] = gaSrc(i,j,k); - }; - void reduce(goCopyScalarToVec3 &op) { }; - protected: - Grid<Vec3> *mpDst; - Grid<Scalar> *mpSrc; - GridAccessor<Vec3,0> gaDst; - GridAccessor<Scalar,0> gaSrc; -}; // goCopyScalarToVec3 */ - - - -#if DDF_DIMENSION==3 -#define LAPLACEFAC 6. -#else // DDF_DIMENSION==3 -#define LAPLACEFAC 4. -#endif // DDF_DIMENSION==3 - - -//***************************************************************************** -// compute norm (without sqrt) of a vector -class GridOpNormNosqrt : public GridOpBase{ - public: - GridOpNormNosqrt(Grid<Real> *Var, FlagGrid *Flags, Real *result = NULL) : GridOpBase() { - mpVar = Var; - mpFlags = Flags; - applyOperatorToGrids( this ); - if(result) *result = mNorm; - }; - ~GridOpNormNosqrt() {}; - virtual void resetVariables() { - mNorm = 0.; - //outcnt=0; - } - void buildCallList() { - gaVar.gridAccInit(mpVar, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - const Real s = gaVar(i,j,k); - mNorm += s*s; - //debMsg("GridOpNormNosqrt","at "<<PRINT_IJK<<" = "<< mNorm ); - //if(outcnt%1000==0) std::cout<<" "<<mNorm; - //outcnt++; - } - - void reduce(GridOpNormNosqrt &op) { - //debMsg("GridOpNormNosqrt","reduce mNorm"<<mNorm<<" += "<<op.mNorm); - mNorm += op.mNorm; - } - - Real getValue() { return mNorm; } - protected: - //int outcnt; - Real mNorm; - Grid<Real> *mpVar; - GridAccessor<Real,0> gaVar; -}; // GridOpNormNosqrt - - - -//***************************************************************************** -// compute min and max values in grid 1 (better use goCompMinMax below...) -static inline Real _helperMinMaxNorm( Real r ) { - return r; -}; -static inline Real _helperMinMaxNorm( Vec3 r ) { - return normNoSqrt(r); -}; -template<class Scalar> -class goFindMinMax : public GridOpBase{ - public: - goFindMinMax(FlagGrid *flags, Grid<Scalar> *grid) : GridOpBase() { - mpVar = grid; - mpFlags = flags; - resetVariables(); - if(flags) { - // use flags, if supplied to skip obstacle cells - applyOperatorToGrids( this ); - } else { - applyOperatorToGridsWithoutFlags(this, grid); - } - }; - ~goFindMinMax() {}; - virtual void resetVariables() { - //outcnt=0; mNorm = 0.; - mMinLen = 0.5*FP_REAL_MAX; - mMaxLen = -0.5*FP_REAL_MAX; - mMinVal = 0.; - mMaxVal = 0.; - mMinPos = mMaxPos = 0; - mInitedMin = mInitedMax = - mFirstInitRed = false; - } - void buildCallList() { - gaVar.gridAccInit(mpVar, AM_READ, gaCalls); - if(!mpFlags) setNullFlagPointer(); - else setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - const Scalar s = gaVar(i,j,k); - const Real slen = _helperMinMaxNorm( s ); - if((!mpFlags) || (!fgIsObstacle(getFlagAcc()(i,j,k)) )) { - // also max not for obs!? - if((!mInitedMax) || (mMaxLen<slen)) { - mMaxVal = s; - mMaxLen = slen; - mMaxPos = nVec3i(i,j,k); - mInitedMax = true; - } - // minima only in fluid region - if((!mInitedMin) || (mMinLen>slen)) { - mMinVal = s; - mMinLen = slen; - mMinPos = nVec3i(i,j,k); - mInitedMin = true; - } - } - //outcnt++; - //debMsg("goFindMinMax","at "<<PRINT_IJK<<" = "<< s <<","<<off << " min="<<mMinVal<<" at "<<mMinPos<<" max="<<mMaxVal<<" at "<<mMaxPos); - } - - void reduce(goFindMinMax &op) { - // used for reducing with opOrg - if(!mFirstInitRed) { - mMaxVal = op.mMaxVal; - mMaxLen = op.mMaxLen; - mMaxPos = op.mMaxPos; - mMinVal = op.mMinVal; - mMinLen = op.mMinLen; - mMinPos = op.mMinPos; - mFirstInitRed = true; - return; - } - if(mMaxLen<op.mMaxLen) { - mMaxVal = op.mMaxVal; - mMaxLen = op.mMaxLen; - mMaxPos = op.mMaxPos; - } - if(mMinLen>op.mMinLen) { - mMinVal = op.mMinVal; - mMinLen = op.mMinLen; - mMinPos = op.mMinPos; - } - } - - Real mMinLen; - Real mMaxLen; - Scalar mMinVal; - Scalar mMaxVal; - nVec3i mMinPos; - nVec3i mMaxPos; - protected: - //int outcnt; - bool mInitedMin, mInitedMax, mFirstInitRed; - Grid<Scalar> *mpVar; - GridAccessor<Scalar,0> gaVar; -}; // goFindMinMax - - -//***************************************************************************** -// compute min and max values in grid 2 -template<class Value> -class goCompMinMax : public GridOpBase{ - public: - goCompMinMax(Grid<Value> *Var, FlagGrid *Flags) : GridOpBase() { - mpVar = Var; - mpFlags = Flags; - applyOperatorToGrids( this ); - }; - ~goCompMinMax() {}; - virtual void resetVariables() { - // todo, add debug check for min/max inits!? - mMinAbs = 1e10; - mMaxAbs = -1e10; - mMin = mMax = 0.; - mMinPos = mMaxPos = 0; - //outcnt=0; - } - void buildCallList() { - gaVar.gridAccInit(mpVar, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - const Value s = gaVar(i,j,k); - const Real sabs = normHelper(s); - //mNorm += s*s; - if(sabs>mMaxAbs) { - mMaxAbs = sabs; - mMax = s; - mMaxPos = nVec3i(i,j,k); - } - if(sabs<mMinAbs) { - mMinAbs = sabs; - mMin = s; - mMinPos = nVec3i(i,j,k); - } - } - - void reduce(goCompMinMax &op) { - //debMsg("goCompMinMax","reduce mNorm"<<mNorm<<" += "<<op.mNorm); - //mNorm += op.mNorm; - if(op.mMaxAbs>mMaxAbs) { - mMaxAbs = op.mMaxAbs; - mMax = op.mMax; - mMaxPos = op.mMaxPos; - } - if(op.mMinAbs<mMinAbs) { - mMinAbs = op.mMinAbs; - mMin = op.mMin; - mMinPos = op.mMinPos; - } - } - - Value getMinValue() { return mMin; } - Value getMaxValue() { return mMax; } - Real getMinAbsValue() { return mMinAbs; } - Real getMaxAbsValue() { return mMaxAbs; } - Real getMinPosValue() { return mMinPos; } - Real getMaxPosValue() { return mMaxPos; } - string toString() { - std::ostringstream out; - out << "min="<<mMin<<" ("<<mMinAbs<<") at "<<mMinPos<< - " max="<<mMax<<" ("<<mMaxAbs<<") at "<<mMaxPos ; - return out.str(); - } - protected: - //int outcnt; - Real mMinAbs, mMaxAbs; - Value mMin, mMax; - nVec3i mMinPos, mMaxPos; - Grid<Value> *mpVar; - GridAccessor<Real,0> gaVar; -}; // goCompMinMax - -//***************************************************************************** -// subtract the entries of grid 2 from grid 1, store result to destination -// grid, and sum up the total difference -template<class Value> -class GridOpDifference : public GridOpBase{ - public: - GridOpDifference(Grid<Value>* Dst, Grid<Value>* Var1, Grid<Value>* Var2, FlagGrid *Flags) : GridOpBase() { - mpDst = Dst; - mpVar1 = Var1; - mpVar2 = Var2; - mpFlags = Flags; - applyOperatorToGrids( this ); - } - ~GridOpDifference() {}; - void buildCallList() { - gaDst.gridAccInit(mpDst, DDF::AM_WRITE, gaCalls); - gaVar1.gridAccInit(mpVar1, DDF::AM_READ, gaCalls); - gaVar2.gridAccInit(mpVar2, DDF::AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - Value diff; - if (gaFlags(i,j,k) != FOBSTACLE) - diff = gaVar2(i,j,k)-gaVar1(i,j,k); - else - diff = 0; - gaDst.write(i,j,k) = diff; - mDiffSum += diff; - } - - void reduce(GridOpDifference &op) { - mDiffSum += op.mDiffSum; - } - - Value getDiffSum(void) { return mDiffSum; } - - protected: - Grid<Value> *mpDst, *mpVar1, *mpVar2; - GridAccessor<Value,0> gaDst; - GridAccessor<Value,0> gaVar1; - GridAccessor<Value,0> gaVar2; - - Value mDiffSum; -}; // GridOpDifference */ - -//***************************************************************************** -// sum of two grids -template<class T> -class goSum : public GridOpBase{ - public: - goSum(Grid<T>* dst, Grid<T>* grid1, FlagGrid *flags) : GridOpBase(), - mpDst(dst), mpVar1(grid1) { - mpFlags = flags; - applyOperatorToGrids( this ); - } - ~goSum() {}; - void buildCallList() { - gaDst.gridAccInit(mpDst, DDF::AM_READWRITE, gaCalls); - gaVar1.gridAccInit(mpVar1, DDF::AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - if (gaFlags(i,j,k) != FOBSTACLE) - gaDst.write(i,j,k) += gaVar1(i,j,k); - else - gaDst.write(i,j,k) = 0; - } - - void reduce(goSum &op) {} - - protected: - Grid<T> *mpDst, *mpVar1; - GridAccessor<T,0> gaDst; - GridAccessor<T,0> gaVar1; -}; // goSum - -//***************************************************************************** -// scale a grid -template<class T> -class goScale : public GridOpBase{ - public: - goScale(Grid<T>* dst, FlagGrid *flags, Real s) : GridOpBase(), - mpDst(dst), mScale(s) { - mpFlags = flags; - applyOperatorToGrids( this ); - } - ~goScale() {}; - void buildCallList() { - gaDst.gridAccInit(mpDst, DDF::AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - if (gaFlags(i,j,k) != FOBSTACLE) - gaDst.write(i,j,k) *= mScale; - } - - void reduce(goScale &op) { }; - - protected: - Grid<T> *mpDst; - Real mScale; - GridAccessor<T,0> gaDst; -}; // goScale - - - -//***************************************************************************** -// multiply entries of both input grids, and store them in destination grid -class GridOpMultiplyEntries : public GridOpBase{ - public: - GridOpMultiplyEntries(Grid<Real> *Dst, Grid<Real> *Var1, Grid<Real> *Var2, FlagGrid *Flags) : GridOpBase() { - mpDst = Dst; - mpVar1 = Var1; - mpVar2 = Var2; - mpFlags = Flags; - applyOperatorToGrids( this ); - } - ~GridOpMultiplyEntries() {}; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - gaVar1.gridAccInit(mpVar1, AM_READ, gaCalls); - gaVar2.gridAccInit(mpVar2, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - gaDst.write(i,j,k) = gaVar1(i,j,k)*gaVar2(i,j,k); - } - - void reduce(GridOpMultiplyEntries &op) { } - protected: - Grid<Real> *mpDst, *mpVar1, *mpVar2; - GridAccessor<Real,0> gaDst; - GridAccessor<Real,0> gaVar1; - GridAccessor<Real,0> gaVar2; -}; // GridOpMultiplyEntries */ - - -//***************************************************************************** -// compute dot product of two vectors (saved in grid format) - -// use current precision (single/double) -class goDotProdReal : public GridOpBase{ - public: - goDotProdReal(Grid<Real> *Var1, Grid<Real> *Var2, FlagGrid *Flags, Real *result = NULL) : - GridOpBase() { - mpVar1 = Var1; - mpVar2 = Var2; - mpFlags = Flags; - mDot = 0.; - applyOperatorToGrids( this ); - if(result) *result = mDot; - } - ~goDotProdReal() {}; - virtual void resetVariables() { - mDot = 0.; - } - void buildCallList() { - gaVar1.gridAccInit(mpVar1, AM_READ, gaCalls); - gaVar2.gridAccInit(mpVar2, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - mDot += gaVar1(i,j,k)*gaVar2(i,j,k); - } - - void reduce(goDotProdReal &op) { - //debMsg("goDotProdReal","reduce mDot"<<mDot<<" += "<<op.mDot); - mDot += op.mDot; - } - inline Real getValue() { return mDot; } - protected: - Real mDot; - Grid<Real> *mpVar1, *mpVar2; - GridAccessor<Real,0> gaVar1; - GridAccessor<Real,0> gaVar2; -}; // goDotProdReal */ - -// use enforced double precision (default) -class goDotProd : public GridOpBase{ - public: - goDotProd(Grid<Real> *Var1, Grid<Real> *Var2, FlagGrid *Flags, Real *result = NULL) : - GridOpBase() { - mpVar1 = Var1; - mpVar2 = Var2; - mpFlags = Flags; - mDot = 0.; - applyOperatorToGrids( this ); - if(result) *result = mDot; - } - ~goDotProd() {}; - virtual void resetVariables() { - mDot = 0.; - } - void buildCallList() { - gaVar1.gridAccInit(mpVar1, AM_READ, gaCalls); - gaVar2.gridAccInit(mpVar2, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - mDot += (double)( gaVar1(i,j,k)*gaVar2(i,j,k) ); - } - - void reduce(goDotProd &op) { - //debMsg("goDotProd","reduce mDot"<<mDot<<" += "<<op.mDot); - mDot += op.mDot; - } - inline Real getValue() { return (Real)mDot; } - protected: - double mDot; - Grid<Real> *mpVar1, *mpVar2; - GridAccessor<Real,0> gaVar1; - GridAccessor<Real,0> gaVar2; -}; // goDotProd */ - -template<class T> -class fsSetConstant : public GridOpBase { - public: - fsSetConstant(FlagGrid *flags, Grid<T> *dst, T value) : - GridOpBase(), mpDst(dst), mVal(value) { - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsSetConstant() { }; - void resetVariables() { }; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - // add forces and update empty cells free surface boundaries - inline void operator() (int i, int j, int k) { - gaDst.write(i,j,k) = mVal; - }; - void reduce(fsSetConstant &op) { }; - - protected: - Grid<T> *mpDst; - GridAccessor<T,0> gaDst; - // value to set - T mVal; -}; // fsSetConstant */ - - -}; // namespace DDF - -#endif // DDF_OPERATORS_H - diff --git a/intern/smoke/intern/source/poissonsolvers.cpp b/intern/smoke/intern/source/poissonsolvers.cpp deleted file mode 100644 index 279675a0a3e..00000000000 --- a/intern/smoke/intern/source/poissonsolvers.cpp +++ /dev/null @@ -1,1032 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Plugins for calculating pressure correction and diffusion - * - *****************************************************************************/ - -#include "fluidsolver.h" -#include "solverplugin.h" -#include "paramset.h" -#include "conjugategrad.h" - -#include <fstream> -#include <sstream> - -namespace DDF { - - -// ***************************************************************************** -// pressure solve -// optional modifications: -// - global volume correction value (set by compute volume plugin, passed over via mpPlParams) -// - per cell density values (grid), scales RHS values -// - surface tension values (grid), adds -class fsPrMakeRhs : public GridOpBaseFlagbord<1> { - public: - fsPrMakeRhs(FlagGrid *flags, Grid<Real> *rhs, Grid<Vec3> *vel, Real corr, - Grid<Real> *dens, Grid<Real> *percell) : - GridOpBaseFlagbord<1>(), mpRhs(rhs), mpVel(vel), mpPerCellCorrection(percell) , - mCorr(corr), mpDensity(dens) { - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsPrMakeRhs() { }; - void resetVariables() { }; - void buildCallList() { - gaVel.gridAccInit(mpVel, AM_READ, gaCalls); - gaRhs.gridAccInit(mpRhs, AM_WRITE, gaCalls); - if(mpDensity) { - gaDens.gridAccInit(mpDensity, AM_READ, gaCalls); - } - if(mpPerCellCorrection) { - gaPerCellCorr.gridAccInit(mpPerCellCorrection, AM_READ, gaCalls); - } - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - if (!fgIsFluid(getFlagAcc()(i,j,k)) ) { - gaRhs.write(i,j,k) = 0.; - return; - } - - Real set = 0.; - set += (gaVel(i,j,k)[0] - gaVel(i+1,j,k)[0]); - set += (gaVel(i,j,k)[1] - gaVel(i,j+1,k)[1]); -# if DDF_DIMENSION==3 - set += (gaVel(i,j,k)[2] - gaVel(i,j,k+1)[2]); -# endif - gaRhs.write(i,j,k) = set + mCorr; - - // multiply RHS by density value, if given... - if(mpDensity) gaRhs.write(i,j,k) *= gaDens(i,j,k); - if(mpPerCellCorrection) gaRhs.write(i,j,k) += gaPerCellCorr(i,j,k); - }; - - void reduce(fsPrMakeRhs &op) { }; - protected: - Grid<Real> *mpRhs; - Grid<Vec3> *mpVel; - Grid<Real> *mpPerCellCorrection; - GridAccessor<Real,0> gaRhs; - GridAccessor<Vec3,1> gaVel; - GridAccessor<Real,0> gaPerCellCorr; - Real mCorr; - // optional density - Grid<Real> *mpDensity; - GridAccessor<Real,0> gaDens; -}; // fsPrMakeRhs */ - -class fsPrMakeMatrix : public GridOpBaseFlagbord<1> { - public: - fsPrMakeMatrix(FlagGrid *flags, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) : - GridOpBaseFlagbord<1>(), mpA0(A0), mpAi(Ai), mpAj(Aj), mpAk(Ak) { - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsPrMakeMatrix() { }; - void resetVariables() { }; - void buildCallList() { - gaA0.gridAccInit(mpA0, AM_WRITE, gaCalls); - gaAi.gridAccInit(mpAi, AM_WRITE, gaCalls); - gaAj.gridAccInit(mpAj, AM_WRITE, gaCalls); - gaAk.gridAccInit(mpAk, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - const int currFlag = getFlagAcc()(i,j,k); - if (!fgIsFluid(currFlag) ) return; - - if (!fgIsObstacle(getFlagAcc()(i-1,j,k)) ) gaA0.write(i,j,k) += 1.; - if (!fgIsObstacle(getFlagAcc()(i+1,j,k)) ) gaA0.write(i,j,k) += 1.; - if (fgIsFluid(getFlagAcc()(i+1,j,k)) ) gaAi.write(i,j,k) = -1.; - - if (!fgIsObstacle(getFlagAcc()(i,j-1,k)) ) gaA0.write(i,j,k) += 1.; - if (!fgIsObstacle(getFlagAcc()(i,j+1,k)) ) gaA0.write(i,j,k) += 1.; - if (fgIsFluid(getFlagAcc()(i,j+1,k)) ) gaAj.write(i,j,k) = -1.; - -# if DDF_DIMENSION==3 - if (!fgIsObstacle(getFlagAcc()(i,j,k-1)) ) gaA0.write(i,j,k) += 1.; - if (!fgIsObstacle(getFlagAcc()(i,j,k+1)) ) gaA0.write(i,j,k) += 1.; - if (fgIsFluid(getFlagAcc()(i,j,k+1)) ) gaAk.write(i,j,k) = -1.; -# endif - }; - void reduce(fsPrMakeMatrix &op) { }; - protected: - Grid<Real> *mpA0, *mpAi, *mpAj, *mpAk; - GridAccessor<Real,0> gaA0, gaAi, gaAj, gaAk; -}; // fsPrMakeMatrix */ - -class fsPrCorrVels : public GridOpBaseFlagbord<1> { - public: - fsPrCorrVels(FlagGrid *flags, Grid<Vec3> *vel, Grid<Real> *press, Grid<Real> *dens) : - GridOpBaseFlagbord<1>(), mpPress(press), mpVel(vel), - mpDensity(dens) { - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsPrCorrVels() { }; - void resetVariables() { }; - void buildCallList() { - gaVel.gridAccInit(mpVel, AM_WRITE, gaCalls); - gaPress.gridAccInit(mpPress, AM_WRITE, gaCalls); - if(mpDensity) { - gaDens.gridAccInit(mpDensity, AM_READ, gaCalls); - } - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - const int currFlag = getFlagAcc()(i,j,k); - if (!fgIsFluid(currFlag) ) return; - //if (fgIsObstacle(currFlag) ) return; - Real scale = 1.; - //if(mpDensity) scale = 1. / gaDens(i,j,k); - Real densCurr = 1.; - if(mpDensity) densCurr = gaDens(i,j,k); - - if (fgIsFluid(getFlagAcc()(i-1,j,k)) ) { - if(mpDensity) { - scale = 1. / (0.5* (densCurr + gaDens(i-1,j,k)) ); - } - gaVel.write(i,j,k)[0] -= scale* (gaPress(i,j,k) - gaPress(i-1,j,k) ); - } - if (fgIsFluid(getFlagAcc()(i,j-1,k)) ) { - if(mpDensity) { - scale = 1. / (0.5* (densCurr + gaDens(i,j-1,k)) ); - } - gaVel.write(i,j,k)[1] -= scale* (gaPress(i,j,k) - gaPress(i,j-1,k) ); - } - if (fgIsFluid(getFlagAcc()(i,j,k-1)) ) { - if(mpDensity) { - scale = 1. / (0.5* (densCurr + gaDens(i,j,k-1)) ); - } - gaVel.write(i,j,k)[2] -= scale* (gaPress(i,j,k) - gaPress(i,j,k-1) ); - } - }; - void reduce(fsPrCorrVels &op) { }; - protected: - Grid<Real> *mpPress; - Grid<Vec3> *mpVel; - GridAccessor<Real,1> gaPress; - GridAccessor<Vec3,0> gaVel; - // optional density - Grid<Real> *mpDensity; - GridAccessor<Real,0> gaDens; -}; // fsPrCorrVels */ - - -// overwrite domain sides with default stencil -// TODO set sides individually? -static void setOpenBound( int bound, Grid<Real>* A0, Grid<Real>* Ai, Grid<Real>* Aj, Grid<Real>* Ak, Grid<Vec3>* vel ) -{ - Real fac = 6.; - if(gDim==2) fac = 4.; - - if(!bound) return; - - // set velocities - const int iMax = A0->getSizeX()-2; - const int iMin = 1; - const int jMax = A0->getSizeY()-2; - const int jMin = 1; - const int kMax = A0->getSizeZ()-2; - const int kMin = 1; - - // TODO on/off per side... - // TODO smoothen? - bool dox = false; - bool doy = true; - bool doz = false; - - // set velocities - if(dox) - for(int j=0;j<A0->getSizeY();j++) - for(int k=0;k<A0->getSizeZ();k++) { - vel->getGlobal(iMax+1,j,k) = vel->getGlobal(iMax,j,k); - vel->getGlobal(iMin-1,j,k) = vel->getGlobal(iMin,j,k); - } - - if(doy) - for(int i=0;i<A0->getSizeX();i++) - for(int k=0;k<A0->getSizeZ();k++) { - vel->getGlobal(i,jMax+1,k) = vel->getGlobal(i,jMax,k); - vel->getGlobal(i,jMin-1,k) = vel->getGlobal(i,jMin,k); - } - - if(doz) - for(int i=0;i<A0->getSizeX();i++) - for(int j=0;j<A0->getSizeY();j++) { - vel->getGlobal(i,j,kMax+1) = vel->getGlobal(i,j,kMax); - vel->getGlobal(i,j,kMin-1) = vel->getGlobal(i,j,kMin); - } - - // set matrix stencils at boundary - if(dox) { - for(int i=0;i<= 1;i++) - for(int j=0;j<A0->getSizeY();j++) - for(int k=0;k<A0->getSizeZ();k++) { - A0->getGlobal(i,j,k) = fac; - Ai->getGlobal(i,j,k) = -1.; - Aj->getGlobal(i,j,k) = -1.; - if(gDim==3) Ak->getGlobal(i,j,k) = -1.; - } - for(int i=A0->getSizeX()-2;i<=A0->getSizeX()-1;i++) - for(int j=0;j<A0->getSizeY();j++) - for(int k=0;k<A0->getSizeZ();k++) { - A0->getGlobal(i,j,k) = fac; - Ai->getGlobal(i,j,k) = -1.; - Aj->getGlobal(i,j,k) = -1.; - if(gDim==3) Ak->getGlobal(i,j,k) = -1.; - } - } - - if(doy) { - for(int i=0;i<A0->getSizeX();i++) - for(int j=0;j<= 1;j++) - for(int k=0;k<A0->getSizeZ();k++) { - A0->getGlobal(i,j,k) = fac; - Ai->getGlobal(i,j,k) = -1.; - Aj->getGlobal(i,j,k) = -1.; - if(gDim==3) Ak->getGlobal(i,j,k) = -1.; - } - for(int i=0;i<A0->getSizeX();i++) - for(int j=A0->getSizeY()-2;j<=A0->getSizeY()-1;j++) - for(int k=0;k<A0->getSizeZ();k++) { - A0->getGlobal(i,j,k) = fac; - Ai->getGlobal(i,j,k) = -1.; - Aj->getGlobal(i,j,k) = -1.; - if(gDim==3) Ak->getGlobal(i,j,k) = -1.; - } - } - - if(doz) - if(gDim==3) { - for(int i=0;i<A0->getSizeX();i++) - for(int j=0;j<A0->getSizeY();j++) - for(int k=0;k<= 1;k++) { - A0->getGlobal(i,j,k) = fac; - Ai->getGlobal(i,j,k) = -1.; - Aj->getGlobal(i,j,k) = -1.; - if(gDim==3) Ak->getGlobal(i,j,k) = -1.; - } - - for(int i=0;i<A0->getSizeX();i++) - for(int j=0;j<A0->getSizeY();j++) - for(int k=A0->getSizeZ()-2;k<=A0->getSizeZ()-1;k++) { - A0->getGlobal(i,j,k) = fac; - Ai->getGlobal(i,j,k) = 1.; - Aj->getGlobal(i,j,k) = 1.; - if(gDim==3) Ak->getGlobal(i,j,k) = 1.; - } - } - - debMsg("FluidSolver::solvePressure","Open boundaries set"); -} - -static void setBottomOutflow( Grid<Real>* rhs, int height, std::string dir) { // char dir ) { - const int iMax = rhs->getSizeX()-2; - const int iMin = 1; - const int jMax = rhs->getSizeY()-2; - const int jMin = 1; - const int kMax = rhs->getSizeZ()-2; - const int kMin = 1; - debMsg("setBottomOutflow","Active, using dir='"<<dir<<"' "); - - // remove rhs/divergence at bottom - for(int trs=0; trs<(int)dir.length(); trs++) { - - switch(dir[trs]) { - case 'x': // -x - debMsg("setBottomOutflow","Active, -X"); - for(int i=0; i< height;i++) - for(int j=0;j<rhs->getSizeY();j++) - for(int k=0;k<rhs->getSizeZ();k++) { - rhs->getGlobal(i,j,k) = 0.; - } - break; - case 'X': // +x - debMsg("setBottomOutflow","Active, +X"); - for(int i=rhs->getSizeX()-1-height; i< rhs->getSizeX();i++) - for(int j=0;j<rhs->getSizeY();j++) - for(int k=0;k<rhs->getSizeZ();k++) { - rhs->getGlobal(i,j,k) = 0.; - } - break; - case 'y': // -y - debMsg("setBottomOutflow","Active, -Y"); - for(int i=0;i<rhs->getSizeX();i++) - for(int j=0;j<= height;j++) - for(int k=0;k<rhs->getSizeZ();k++) { - rhs->getGlobal(i,j,k) = 0.; - } - break; - case 'Y': // +y - debMsg("setBottomOutflow","Active, +Y"); - for(int i=0;i<rhs->getSizeX();i++) - for(int j=rhs->getSizeY()-1-height; j< rhs->getSizeY();j++) - for(int k=0;k<rhs->getSizeZ();k++) { - rhs->getGlobal(i,j,k) = 0.; - } - break; - case 'z': // -z - debMsg("setBottomOutflow","Active, -Z"); - for(int i=0;i<rhs->getSizeX();i++) - for(int j=0;j<= rhs->getSizeY();j++) - for(int k=0;k<height;k++) { - rhs->getGlobal(i,j,k) = 0.; - } - break; - case 'Z': // +z - debMsg("setBottomOutflow","Active, +Z"); - for(int i=0;i<rhs->getSizeX();i++) - for(int j=0;j<rhs->getSizeY();j++) - for(int k=rhs->getSizeZ()-1-height; k< rhs->getSizeZ();k++) { - rhs->getGlobal(i,j,k) = 0.; - } - break; - - default: - errFatal("setBottomOutflow","Invalid dir "<<dir<<" ",SIMWORLD_GENERICERROR); - } // dir - - } // string -} - -// apply stored symmetric matix -// simple version - no inclusion of e.g., surface tension forces -class goApplyMatrix : public GridOpBase{ - public: - goApplyMatrix(Grid<Real> *Dst, Grid<Real> *Src, - Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak, - FlagGrid *Flags, - Grid<Real> *unusedReal, - Grid<Vec3> *unusedVec ) : GridOpBase(), - mpA0(A0), mpAi(Ai), mpAj(Aj), mpAk(Ak) { - mpDst = Dst; mpSrc = Src; - //mpMat = Mat; - mpFlags = Flags; - applyOperatorToGrids(this); - }; - ~goApplyMatrix() { }; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - gaSrc.gridAccInit(mpSrc, AM_READ, gaCalls); - gaA0.gridAccInit(mpA0, AM_READ, gaCalls); - gaAi.gridAccInit(mpAi, AM_READ, gaCalls); - gaAj.gridAccInit(mpAj, AM_READ, gaCalls); - gaAk.gridAccInit(mpAk, AM_READ, gaCalls); - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - if(!fgIsFluid(getFlagAcc()(i,j,k)) ) { - //gaDst.write(i,j,k) = 0.; // org - gaDst.write(i,j,k) = gaSrc(i,j,k); - //gaDst.write(i,j,k) = gaSrc(i,j,k) * gaA0(i ,j ,k); - return; - } - - gaDst.write(i,j,k) = - gaSrc(i ,j ,k) * gaA0(i ,j ,k) - + gaSrc(i-1,j,k) * gaAi(i-1,j,k) - + gaSrc(i+1,j,k) * gaAi(i ,j,k) - + gaSrc(i,j-1,k) * gaAj(i,j-1,k) - + gaSrc(i,j+1,k) * gaAj(i,j ,k) - + gaSrc(i,j,k-1) * gaAk(i,j,k-1) - + gaSrc(i,j,k+1) * gaAk(i,j,k ); - } - - void getRidOfWarning() { }; - void reduce(goApplyMatrix &op) { getRidOfWarning(); } - protected: - Grid<Real> *mpDst, *mpSrc; - GridAccessor<Real,0> gaDst; - GridAccessor<Real,1> gaSrc; - - Grid<Real> *mpA0, *mpAi, *mpAj, *mpAk; - GridAccessor<Real,1> gaA0, gaAi, gaAj, gaAk; -}; // goApplyMatrix - -//***************************************************************************** - -// add forces to vels -class spluginSolvePressure : public SolverPlugin { - public: - spluginSolvePressure() : SolverPlugin(), - mVels("-unn1-"), mFlags("-unn1-"), - mPress("-unn1-"), mRhs("-unn1-"), - mRes("-unn1-"), mSrch("-unn1-"), - mTmp("-unn1-"), mDensity("-unn1-"), mOpenBound(0), - mBottomOutflow(0), mBottomOutflowDir("X"), - mStPerCellCor("-unn2-"), mUseResNorm(true), mPcMethod(0), - mNamePcA0("PCA0"), mNamePcAi("PCAi"), mNamePcAj("PCAj"), mNamePcAk("PCAk") - { }; - ~spluginSolvePressure() { }; - - virtual bool parseParams(const ParamSet& params) { - mVels = params.FindOneString("vel", mVels ); - mPress = params.FindOneString("pressure", mPress ); - mDensity = params.FindOneString("density", mDensity ); - mStPerCellCor = params.FindOneString("st-per-cell-corr", mStPerCellCor ); - - // optional grids for preconditining, not all PCs need all four grids! - mNamePcA0 = params.FindOneString("grid-pca0", mNamePcA0 ); - mNamePcAi = params.FindOneString("grid-pcai", mNamePcAi ); - mNamePcAj = params.FindOneString("grid-pcaj", mNamePcAj ); - mNamePcAk = params.FindOneString("grid-pcak", mNamePcAk ); - - mOpenBound = params.FindOneInt("openbound", mOpenBound ); - mPcMethod = params.FindOneInt("precondition", mPcMethod ); - mUseResNorm = params.FindOneInt("use-res-norm", mUseResNorm ); - - mBottomOutflow = params.FindOneInt("bottom-outflow", mBottomOutflow ); - //std::string boStr = std::string("y"); - mBottomOutflowDir = params.FindOneString("bottom-outflow-dir", mBottomOutflowDir ); - //if(boStr.length()>=1) { mBottomOutflowDir = boStr[0]; } - - return true; - }; - virtual bool initPlugin() { - debMsg("spluginSolvePressure","init"); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spluginSolvePressure","step "<<dt<<" velsgrid:"<<mVels<<", precond:"<<mPcMethod<<", use-res-norm:"<<mUseResNorm); - - // TODO fixme, hard coded names for now - mVels = std::string("vel-curr"); - mFlags = std::string("flags"); - mPress = std::string("pressure"); - mRhs = std::string("rhs"); - mRes = std::string("residual"); - mSrch = std::string("search"); - mTmp = std::string("tmp"); - - std::ostringstream pdebug; - const bool debugSP= false; - Grid<Vec3> *currVel = mpPlParams->getGridVec3( mVels ); - FlagGrid* pFlags = mpPlParams->getGridInt( mFlags ); - Grid<Real>* pPressure = mpPlParams->getGridReal( mPress ); - Grid<Real>* pRhs = mpPlParams->getGridReal( mRhs ); - Grid<Real>* pResidual = mpPlParams->getGridReal( mRes ); - Grid<Real>* pSearch = mpPlParams->getGridReal( mSrch ); - Grid<Real>* pTmp = mpPlParams->getGridReal( mTmp ); - - Grid<Real>* pA0 = mpPlParams->getGridReal( "A0" ); - Grid<Real>* pAi = mpPlParams->getGridReal( "Ai" ); - Grid<Real>* pAj = mpPlParams->getGridReal( "Aj" ); - Grid<Real>* pAk = mpPlParams->getGridReal( "Ak" ); - - Grid<Real>* pDens = NULL; - if(mpPlParams->haveGridReal( mDensity )) { - pDens = mpPlParams->getGridReal( mDensity ); - debMsg("spluginSolvePressure","Pressure correction RHS using density grid '"<<mDensity<<"' "); - } - - Grid<Real>* pStPerCellCorr = NULL; - if(mpPlParams->haveGridReal( mStPerCellCor )) { - pStPerCellCorr = mpPlParams->getGridReal( mStPerCellCor ); - debMsg("spluginSolvePressure","Pressure correction RHS using per cell ST-correction grid '"<<mStPerCellCor<<"' "); - } - - if (debugSP) { - pdebug<<"\n PRE \n\n"; - pdebug<<"P \n"<< pPressure->toString() <<" \n"; - pdebug<<"CURRVEL \n"<< currVel->toString() <<" \n"; - } - - // reset necessary - GridOpTouchMemory<Real>(pFlags, pA0, 0.); - GridOpTouchMemory<Real>(pFlags, pAi, 0.); - GridOpTouchMemory<Real>(pFlags, pAj, 0.); - GridOpTouchMemory<Real>(pFlags, pAk, 0.); - fsPrMakeMatrix(pFlags, pA0,pAi,pAj,pAk); - setOpenBound(mOpenBound, pA0,pAi,pAj,pAk, currVel); - - // compute divergence and init right hand side - fsPrMakeRhs(pFlags, pRhs, currVel, - mpPlParams->getDivergenceCorrection() // usually is zero, set by compute-volume-correction plugin - , pDens , pStPerCellCorr ); - if(mBottomOutflow>0) { - setBottomOutflow(pRhs, mBottomOutflow, mBottomOutflowDir); - } - - const int maxIter = (int)(mpPlParams->mCgMaxIterFac *VMAX(pFlags->getSize()) ); - if (1) { - GridCgInterface *gcg = NULL; - - GridCg<goApplyMatrix> *mgcg = new GridCg<goApplyMatrix>( - pPressure, pRhs, pResidual, pSearch, pFlags, pTmp, pA0,pAi,pAj,pAk ); - gcg = mgcg; - gcg->setAccuracy( mpPlParams->mCgAccuracy ); - gcg->setUseResNorm( mUseResNorm ); - - // optional preconditioning, with optional grids - Grid<Real> *pPCA0 = NULL, *pPCAi=NULL, *pPCAj=NULL, *pPCAk=NULL; - if(mpPlParams->haveGridReal( mNamePcA0 )) - pPCA0 = mpPlParams->getGridReal( mNamePcA0 ); - if(mpPlParams->haveGridReal( mNamePcAi )) - pPCAi = mpPlParams->getGridReal( mNamePcAi ); - if(mpPlParams->haveGridReal( mNamePcAj )) - pPCAj = mpPlParams->getGridReal( mNamePcAj ); - if(mpPlParams->haveGridReal( mNamePcAk )) - pPCAk = mpPlParams->getGridReal( mNamePcAk ); - gcg->setPreconditioner( mPcMethod, pPCA0, pPCAi, pPCAj, pPCAk ); - - for (int iter=0; iter<maxIter; iter++) { - if (!gcg->iterate()) iter=maxIter; - } - debMsg("FluidSolver::solvePressure","iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma() ); - delete gcg; - } else { - // debug tests - for (int iter=0; iter<4*maxIter; iter++) { - goJacobiSolver(pTmp, pPressure, pRhs, pFlags); - goCopyGrid<Real>(pPressure, pTmp); - } - debMsg("FluidSolver::solvePressure","jacobi iterations:"<<4*maxIter ); - } - fsPrCorrVels(pFlags, currVel, pPressure, pDens); - - if (debugSP) { - goCompMinMax<Real> mm = goCompMinMax<Real>(pPressure, pFlags); - debMsg("FluidSolver::solvePressure","minmax "<< mm.toString() ); - - pdebug<<"\n POST \n\n"; - pdebug<<"RHS \n"<< pRhs->toString() <<" \n"; - pdebug<<"P \n"<< pPressure->toString() <<" \n"; - pdebug<<"CURRVEL \n"<< currVel->toString() <<" \n"; - - pdebug<<"A0 \n"<< pA0->toString() <<" \n"; - pdebug<<"Ai \n"<< pAi->toString() <<" \n"; - pdebug<<"Aj \n"<< pAj->toString() <<" \n"; - pdebug<<"Ak \n"<< pAk->toString() <<" \n"; - std::fstream df; // DEBUG - df.open("debugOut_pressure.txt", std::ios::out); - df << pdebug.str(); - df.close(); // DEBUG - } - - return true; - }; - - protected: - // grid names to swap - std::string mVels, mFlags, mPress, mRhs, mRes, mSrch, mTmp, mDensity; - // open boundaries? - int mOpenBound; - int mBottomOutflow; - std::string mBottomOutflowDir; - // grid name to for optional curvatuere/surface tension grid - std::string mStPerCellCor; - - // use residual norm or max entry? - bool mUseResNorm; - // preconditiong - int mPcMethod; - std::string mNamePcA0, mNamePcAi, mNamePcAj, mNamePcAk; -}; - -//***************************************************************************** - -template < class Scalar > -class GridOpDiffuse : public GridOpBase { - public: - GridOpDiffuse(Grid<Scalar>* pSrc,Grid<Scalar>* pDst, FlagGrid* flags, Real str) - : GridOpBase(), mpSrc(pSrc), mpDst(pDst), mStrength(str) { - mpFlags = flags; - applyOperatorToGrids( this ); - } - ~GridOpDiffuse() {}; - void resetVariables() { } - void reduce(GridOpDiffuse &op) { } - - void buildCallList() { - gaSrc.gridAccInit(mpSrc, DDF::AM_WRITE, gaCalls); - gaDst.gridAccInit(mpDst, DDF::AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) { - if(!fgIsFluid(getFlagAcc()(i,j,k)) ) { - gaDst.write(i,j,k) = gaSrc(i,j,k); - return; - } - - const Scalar curr = gaSrc(i,j,k); - Scalar avg = 0.; - - if(1 && fgIsFluid(getFlagAcc()(i+1,j,k)) ) { - avg += gaSrc(i+1,j,k); - } else { avg += curr; } - - if(1 && fgIsFluid(getFlagAcc()(i-1,j,k)) ) { - avg += gaSrc(i-1,j,k); - } else { avg += curr; } - - if(1 && fgIsFluid(getFlagAcc()(i,j+1,k)) ) { - avg += gaSrc(i,j+1,k); - } else { avg += curr; } - - if(1 && fgIsFluid(getFlagAcc()(i,j-1,k)) ) { - avg += gaSrc(i,j-1,k); - } else { avg += curr; } - - if(gDim==3) { - if(1 && fgIsFluid(getFlagAcc()(i,j,k+1)) ) { - avg += gaSrc(i,j,k+1); - } else { avg += curr; } - - if(1 && fgIsFluid(getFlagAcc()(i,j,k-1)) ) { - avg += gaSrc(i,j,k-1); - } else { avg += curr; } - } - - avg *= (gDim==3 ? 1./6. : 1./4.); - //gaDst.write(i,j,k) = (1.-mStrength) * curr + mStrength * avg; - gaDst.write(i,j,k) = avg*mStrength -curr*mStrength + curr; - } - - protected: - Grid<Scalar> *mpSrc, *mpDst; - GridAccessor<Scalar,1> gaSrc; - GridAccessor<Scalar,0> gaDst; - Real mStrength; -}; // GridOpDiffuse */ - -class spDiffuseGrid : public SolverPlugin { - public: - spDiffuseGrid() : - SolverPlugin(), - mDest("real-temp") , mDestVec("vec-temp"), mDiffusivity(1.) - { }; - ~spDiffuseGrid() { }; - - virtual bool parseParams(const ParamSet& params) { - mDiffusivity = params.FindOneFloat("diff", mDiffusivity ); - mSrc = params.FindOneString("src-real", mSrc ); - mSrcVec = params.FindOneString("src-vec3", mSrcVec ); - mDest = params.FindOneString("dst-real", mDest ); - mDestVec = params.FindOneString("dst-vec3", mDestVec ); - return true; - }; - virtual bool initPlugin() { return true; }; - - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - FlagGrid* pFlags = mpPlParams->getGridInt( "flags" ); - Real diff = mDiffusivity * dt; - //if(diff<0. || diff>1.) debMsg("spDiffuseGrid","WARNING - diffusion param invalid!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); - //CLAMP(diff, (Real)0.,(Real)1.); - - int cnt=0; - while(diff > 0.) { - debMsg("spDiffuseGrid","str"<<mDiffusivity<<",dt="<<dt<<", diff="<<diff<<". from "<<mSrc<<","<<mSrcVec<<" to "<<mDest<<","<<mDestVec); - - if(mSrc.length()>0) { - Grid<Real>* pSrc = mpPlParams->getGridReal(mSrc); - Grid<Real>* pDest = mpPlParams->getGridReal(mDest); - GridOpDiffuse<Real> godiv(pSrc, pDest, pFlags, (diff>1.? 1.:diff) ); - cnt++; - - swapGrids(mpPlParams, mSrc, mDest); - } - if(mSrcVec.length()>0) { - Grid<Vec3>* pSrcv = mpPlParams->getGridVec3(mSrcVec); - Grid<Vec3>* pDestv = mpPlParams->getGridVec3(mDestVec); - GridOpDiffuse<Vec3> godiv(pSrcv, pDestv, pFlags, (diff>1.? 1.:diff) ); - cnt++; - - swapGrids(mpPlParams, mSrcVec, mDestVec); - } - - diff -= 1.; - } - - if(cnt==0 && mDiffusivity>0.) { - errFatal("spDiffuse","No grid for diffusion found or given!", SIMWORLD_PLUGINERROR); - return false; - } - //debMsg("spDiffuseGrid","abs avg="<<godiv.getAbsAvg()<<",abs max="<<godiv.getAbsMax()); - return true; - }; - - protected: - std::string mSrc, mSrcVec; - std::string mDest, mDestVec; - Real mDiffusivity; -}; - - -class fsDiffMakeMatrix : public GridOpBaseFlagbord<1> { - public: - fsDiffMakeMatrix(FlagGrid *flags, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak, Real coeff) : - GridOpBaseFlagbord<1>(), mpA0(A0), mpAi(Ai), mpAj(Aj), mpAk(Ak), mCoeff(coeff) { - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsDiffMakeMatrix() { }; - void resetVariables() { }; - void buildCallList() { - gaA0.gridAccInit(mpA0, AM_WRITE, gaCalls); - gaAi.gridAccInit(mpAi, AM_WRITE, gaCalls); - gaAj.gridAccInit(mpAj, AM_WRITE, gaCalls); - gaAk.gridAccInit(mpAk, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - inline void operator() (int i, int j, int k) { - const int currFlag = getFlagAcc()(i,j,k); - - //gaA0.write(i,j,k) = 5.; gaAi.write(i,j,k) = -1.; gaAj.write(i,j,k) = -1.; gaAk.write(i,j,k) = 0.; return; - - Real& a0 = gaA0.write(i,j,k); - a0 = 1.; - - // handle diffusion across free surface boundaries, e.g. for velocity - if (fgIsEmpty(getFlagAcc()(i,j,k)) ) { - if (fgIsFluid(getFlagAcc()(i+1,j,k)) ) { - gaAi.write(i,j,k) -= mCoeff; - } - if (fgIsFluid(getFlagAcc()(i,j+1,k)) ) { - gaAj.write(i,j,k) -= mCoeff; - } - if (gDim==3 && fgIsFluid(getFlagAcc()(i,j,k+1)) ) { - gaAk.write(i,j,k) -= mCoeff; - } - } - - if (!fgIsFluid(currFlag) ) return; - - if (!fgIsObstacle(getFlagAcc()(i+1,j,k)) ) { - a0 += mCoeff; - } - if (!fgIsObstacle(getFlagAcc()(i-1,j,k)) ) { - a0 += mCoeff; - } - if(1) { - gaAi.write(i,j,k) -= mCoeff; - } - - if (!fgIsObstacle(getFlagAcc()(i,j+1,k)) ) { - a0 += mCoeff; - } - if (!fgIsObstacle(getFlagAcc()(i,j-1,k)) ) { - a0 += mCoeff; - } - //if (fgIsFluid(getFlagAcc()(i,j+1,k)) ) { - //if ( (fgIsFluid(getFlagAcc()(i,j-1,k)) ) && (fgIsFluid(getFlagAcc()(i,j+1,k)) ) ) { - if(1) { - //if (fgIsFluid(getFlagAcc()(i,j+1,k)) ) { - gaAj.write(i,j,k) -= mCoeff; - } - -# if DDF_DIMENSION==3 - if (!fgIsObstacle(getFlagAcc()(i,j,k+1)) ) { - a0 += mCoeff; - } - if (!fgIsObstacle(getFlagAcc()(i,j,k-1)) ) { - a0 += mCoeff; - } - //if (fgIsFluid(getFlagAcc()(i,j,k+1)) ) { - if(1) { - gaAk.write(i,j,k) -= mCoeff; - } -# endif - - //debMsg("D "," at "<<PRINT_IJK<<"a = "<< gaA0.write(i,j,k)<<", "<< gaAi.write(i,j,k)<<", "<< gaAj.write(i,j,k)<<", "<< gaAk.write(i,j,k)<<", "); - }; - void reduce(fsDiffMakeMatrix &op) { }; - protected: - Grid<Real> *mpA0, *mpAi, *mpAj, *mpAk; - GridAccessor<Real,0> gaA0, gaAi, gaAj, gaAk; - Real mCoeff; -}; // fsDiffMakeMatrix */ - -// add forces to vels -class spluginSolveDiffusion : public SolverPlugin { - public: - spluginSolveDiffusion() : SolverPlugin(), - mDst("-unnamed1-"), mRhs("-unnamed1-"), - mRes("-unnamed1-"), mSrch("-unnamed1-"), - mTmp("-unnamed1-"), mOpenBound(0), - mDiffusion(0.), mAccuracy(1.), mMaxIter(1.) { }; - ~spluginSolveDiffusion() { }; - - virtual bool parseParams(const ParamSet& params) { - mDst = params.FindOneString("dst-real", mDst ); - // source = rhs - mRhs = params.FindOneString("src-real", mRhs ); - - mVec3Dst = params.FindOneString("dst-vec3", mVec3Dst ); - mVec3Rhs = params.FindOneString("src-vec3", mVec3Rhs ); - - mOpenBound = params.FindOneInt("openbound", mOpenBound ); - mDiffusion = params.FindOneFloat("diffusion", mDiffusion ); - - // CG parameters, modify basic fluid solver settings, default = 1 - mAccuracy = params.FindOneFloat("accuracy", mAccuracy ); - mMaxIter = params.FindOneFloat("max-iter", mMaxIter); - return true; - }; - virtual bool initPlugin() { - debMsg("spluginSolveDiffusion","init"); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - - const Real dx = mpPlParams->getDeltaX(); - const Real coeff = dt * mDiffusion / (dx*dx); - - debMsg("spluginSolveDiffusion","step "<<dt<<" diffusionCoeff:"<<mDiffusion<<" -> coeff="<<coeff); - - // TODO fixme, hard coded names for now - mRes = std::string("residual"); - mSrch = std::string("search"); - mTmp = std::string("tmp"); - - std::ostringstream pdebug; - const bool debugSP= false; - FlagGrid* pFlags = mpPlParams->getFluidSolver()->getGridFlags(); // getGridInt( mFlags ); - Grid<Real>* pResidual = mpPlParams->getGridReal( mRes ); - Grid<Real>* pSearch = mpPlParams->getGridReal( mSrch ); - Grid<Real>* pTmp = mpPlParams->getGridReal( mTmp ); - - Grid<Real>* pA0 = mpPlParams->getGridReal( "A0" ); - Grid<Real>* pAi = mpPlParams->getGridReal( "Ai" ); - Grid<Real>* pAj = mpPlParams->getGridReal( "Aj" ); - Grid<Real>* pAk = mpPlParams->getGridReal( "Ak" ); - - GridOpTouchMemory<Real>(pFlags, pA0, 0.); - GridOpTouchMemory<Real>(pFlags, pAi, 0.); - GridOpTouchMemory<Real>(pFlags, pAj, 0.); - GridOpTouchMemory<Real>(pFlags, pAk, 0.); - - if( (mpPlParams->haveGridVec3( mVec3Rhs )) && (mpPlParams->haveGridVec3( mVec3Dst )) ) { - // vec3 version - Grid<Vec3>* pVec3Rhs = mpPlParams->getGridVec3( mVec3Rhs ); - Grid<Vec3>* pVec3Dst = mpPlParams->getGridVec3( mVec3Dst ); - - // temp real versions, make sure these grids are not used multiply! - Grid<Real>* pRhs = mpPlParams->getGridReal( mRhs ); - Grid<Real>* pDst = mpPlParams->getGridReal( mDst ); - - // setup diffusion matrix - fsDiffMakeMatrix(pFlags, pA0,pAi,pAj,pAk, coeff); - - int maxIter = (int)(mMaxIter *mpPlParams->mCgMaxIterFac *VMAX(pFlags->getSize()) ); - if(maxIter <= 0) maxIter = 1; - - - if(1) { - goCopyVec3ToScalar<Real,0>(pRhs, pVec3Rhs); - //goCopyVec3ToScalar<Real,0>(pDst, pVec3Dst); - goCopyVec3ToScalar<Real,0>(pDst, pVec3Rhs); - - GridCg<goApplyMatrix> gcg = GridCg<goApplyMatrix>(pDst, pRhs, pResidual, pSearch, pFlags, pTmp, pA0,pAi,pAj,pAk ); - gcg.setAccuracy( mAccuracy *mpPlParams->mCgAccuracy ); - gcg.solve( maxIter ); - debMsg("FluidSolver::solveDiffusion Vec3","iterations:"<<gcg.getIterations()<<", res:"<<gcg.getSigma() ); - - goCopyScalarToVec3<Real,0>(pVec3Dst,pDst); - } else { - goCopyVec3ToScalar<Real,0>(pRhs,pVec3Rhs); - goCopyScalarToVec3<Real,0>(pVec3Dst,pRhs); - } - - - if(1) { - goCopyVec3ToScalar<Real,1>(pRhs,pVec3Rhs); - //goCopyVec3ToScalar<Real,1>(pDst,pVec3Dst); - goCopyVec3ToScalar<Real,1>(pDst,pVec3Rhs); - - GridCg<goApplyMatrix> gcg = GridCg<goApplyMatrix>(pDst, pRhs, pResidual, pSearch, pFlags, pTmp, pA0,pAi,pAj,pAk ); - gcg.setAccuracy( mAccuracy *mpPlParams->mCgAccuracy ); - gcg.solve( maxIter ); - debMsg("FluidSolver::solveDiffusion Vec3","iterations:"<<gcg.getIterations()<<", res:"<<gcg.getSigma() ); - - goCopyScalarToVec3<Real,1>(pVec3Dst,pDst); - } else { - goCopyVec3ToScalar<Real,1>(pRhs,pVec3Rhs); - goCopyScalarToVec3<Real,1>(pVec3Dst,pRhs); - } - - - if(1) { - goCopyVec3ToScalar<Real,2>(pRhs,pVec3Rhs); - goCopyVec3ToScalar<Real,2>(pDst,pVec3Dst); - - GridCg<goApplyMatrix> gcg = GridCg<goApplyMatrix>(pDst, pRhs, pResidual, pSearch, pFlags, pTmp, pA0,pAi,pAj,pAk ); - gcg.setAccuracy( mAccuracy *mpPlParams->mCgAccuracy ); - gcg.solve( maxIter ); - debMsg("FluidSolver::solveDiffusion Vec3","iterations:"<<gcg.getIterations()<<", res:"<<gcg.getSigma() ); - - goCopyScalarToVec3<Real,2>(pVec3Dst,pDst); - } else { - goCopyVec3ToScalar<Real,2>(pRhs,pVec3Rhs); - goCopyScalarToVec3<Real,2>(pVec3Dst,pRhs); - } - - swapGrids(mpPlParams, mVec3Dst, mVec3Rhs); - - const bool debugDIFF = false; - if (debugDIFF) { - goCompMinMax<Real> mm = goCompMinMax<Real>(pDst, pFlags); - debMsg("FluidSolver::solvePressure","minmax "<< mm.toString() ); - - pdebug<<"\n POST \n\n"; - pdebug<<"RHS \n"<< pRhs->toString() <<" \n"; - pdebug<<"Dst \n"<< pDst->toString() <<" \n"; - - pdebug<<"A0 \n"<< pA0->toString() <<" \n"; - pdebug<<"Ai \n"<< pAi->toString() <<" \n"; - pdebug<<"Aj \n"<< pAj->toString() <<" \n"; - pdebug<<"Ak \n"<< pAk->toString() <<" \n"; - std::fstream df; // DEBUG - df.open("debugOut_diffusionVec.txt", std::ios::out); - df << pdebug.str(); - df.close(); // DEBUG - } - - } else if( (mpPlParams->haveGridReal( mRhs )) && (mpPlParams->haveGridReal( mDst )) ) { - // real version - Grid<Real>* pRhs = mpPlParams->getGridReal( mRhs ); - Grid<Real>* pDst = mpPlParams->getGridReal( mDst ); - - // setup diffusion matrix - fsDiffMakeMatrix(pFlags, pA0,pAi,pAj,pAk, coeff); - - int maxIter = (int)(mMaxIter *mpPlParams->mCgMaxIterFac *VMAX(pFlags->getSize()) ); - if(maxIter <= 0) maxIter = 1; - - GridCg<goApplyMatrix> *gcg = new GridCg<goApplyMatrix>(pDst, pRhs, pResidual, pSearch, pFlags, pTmp, pA0,pAi,pAj,pAk ); - gcg->setAccuracy( mAccuracy *mpPlParams->mCgAccuracy ); - - for (int iter=0; iter<maxIter; iter++) { - if (!gcg->iterate()) iter=maxIter; - } - debMsg("FluidSolver::solveDiffusion Real","iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma() ); - delete gcg; - - const bool debugDIFF = false; - if (debugDIFF) { - goCompMinMax<Real> mm = goCompMinMax<Real>(pDst, pFlags); - debMsg("FluidSolver::solvePressure","minmax "<< mm.toString() ); - - pdebug<<"\n POST \n\n"; - pdebug<<"RHS \n"<< pRhs->toString() <<" \n"; - pdebug<<"Dst \n"<< pDst->toString() <<" \n"; - - pdebug<<"A0 \n"<< pA0->toString() <<" \n"; - pdebug<<"Ai \n"<< pAi->toString() <<" \n"; - pdebug<<"Aj \n"<< pAj->toString() <<" \n"; - pdebug<<"Ak \n"<< pAk->toString() <<" \n"; - std::fstream df; // DEBUG - df.open("debugOut_diffusionReal.txt", std::ios::out); - df << pdebug.str(); - df.close(); // DEBUG - } - - swapGrids(mpPlParams, mDst, mRhs); - } - - return true; - }; - - protected: - // grid names to swap - std::string mDst, mRhs, mRes, mSrch, mTmp; - std::string mVec3Dst, mVec3Rhs; - // open boundaries? - int mOpenBound; - // diffusivity - Real mDiffusion, mAccuracy, mMaxIter; -}; - -// create one of the standard hard coded plugins -SolverPlugin* MakePoissionSolverPlugins(std::string name) { - - if(name.compare( "solve-pressure")==0) { - return new spluginSolvePressure; - - } else if(name.compare( string("diffuse-grid") )==0) { - return new spDiffuseGrid; - - } else if(name.compare( string("solve-diffusion") )==0) { - return new spluginSolveDiffusion; - - } - - return NULL; -} - -} // end namespace DDF - diff --git a/intern/smoke/intern/source/smoke.cpp b/intern/smoke/intern/source/smoke.cpp deleted file mode 100644 index 38143171b6a..00000000000 --- a/intern/smoke/intern/source/smoke.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include "smoke.h" - -using namespace std; -using namespace DDF; - -#include <limits.h> - -void FLUID_3D::init() -{ - printf("-------------------- SMOKE INIT A-------------------------\n"); - { // static scene - printf("init res %d, %d, %d\n", _res[0], _res[1], _res[2]); - SolverObject* solverInit = new SolverObject( "makescene", nVec3i ( _res[0], _res[1], _res[2] ), DDF_GRID_NO_FREE ); // 200, 80, 150 - solverInit->createVec3Grid ( "normal", DDF_GRID_NO_FREE ); - solverInit->createRealGrid ( "dist", DDF_GRID_NO_FREE ); - solverInit->addInitPlugin ( "init-box-domain", IntArg ( "flag-inside",FFLUID ) + IntArg ( "flag-border",FINFLOW ) + IntArg("flag-floor", FOBSTACLE) ); - // obstacles - solverInit->addInitPlugin ( "init-sphere", VecArg("center",Vec3(0.25,0.6,0.35)) + RealArg("radius",0.1) + StringArg("norm","normal")+StringArg("dist","dist")); - solverInit->addInitPlugin ( "init-box", VecArg("pos1",Vec3(0.2,0.0,0.3)) + VecArg("pos2",Vec3(0.3,0.6,0.4)) + StringArg("norm","normal")+StringArg("dist","dist")); - solverInit->addInitPlugin ( "init-box", VecArg("pos1",Vec3(0.3,0.0,0.65)) + VecArg("pos2",Vec3(0.5,0.3,0.9)) + StringArg("norm","normal")+StringArg("dist","dist")); - solverInit->addInitPlugin ( "init-box", VecArg("pos1",Vec3(0.6,0.0,0.3)) + VecArg("pos2",Vec3(0.65,0.4,0.5)) + StringArg("norm","normal")+StringArg("dist","dist")); - // smoke seed - solverInit->addInitPlugin ( "init-sphere", VecArg("center",Vec3(0.3,0.65,0.35)) + RealArg("radius",0.1) + IntArg("type", FDENSITYSOURCE)); - solverInit->addInitPlugin ( "init-box", VecArg("pos1",Vec3(0.25,0.0,0.3)) + VecArg("pos2",Vec3(0.35,0.65,0.4)) + IntArg("type", FDENSITYSOURCE)); - solverInit->addInitPlugin ( "init-box", VecArg("pos1",Vec3(0.35,0.0,0.65)) + VecArg("pos2",Vec3(0.55,0.35,0.9)) + IntArg("type", FDENSITYSOURCE)); - solverInit->addInitPlugin ( "init-box", VecArg("pos1",Vec3(0.65,0.0,0.3)) + VecArg("pos2",Vec3(0.7,0.45,0.5)) + IntArg("type", FDENSITYSOURCE)); - - // solverInit->addInitPlugin ( "dump-universal", StringArg ( "grid", "flags" ) + StringArg ( "override-name","scene/static-flags" ) + IntArg ( "single-dump", 1 ) ); - // solverInit->addInitPlugin ( "dump-universal", StringArg ( "grid", "dist" ) + StringArg ( "override-name","scene/static-dist" ) + IntArg ( "single-dump", 1 ) ); - // solverInit->addInitPlugin ( "dump-universal", StringArg ( "grid", "normal" ) + StringArg ( "override-name","scene/static-normal" ) + IntArg ( "single-dump", 1 ) ); - - _solvers.push_back(solverInit); - } - - initAllSolvers(); - - // advanceAllSolvers(); // DG TODO disabled for testing purposed - - // finalizeAllSolvers(); // DG TODO disabled for testing purposed - - _flags = _solvers[0]->getParams().getGridInt("flags"); - _normal = _solvers[0]->getParams().getGridVec3("normal"); - _dist = _solvers[0]->getParams().getGridReal("dist"); - - freeAllSolvers(); - - { - Vec3 inflow (0.4, 0, 0); - const int nFrames = 50; - precompute("static", inflow, nFrames, false); - } - - printf("-------------------- SMOKE INIT B-------------------------\n"); - { - Vec3 inflow (0.4, 0, 0); - SolverObject* solverStep = new SolverObject( "run_static", _flags); - - solverStep->getParams().mU0 = inflow; - solverStep->getParams().mTimestepAnim = 0.005; - - // create grids - solverStep->createVec3Grid ( "mean-flow", _meanVel ); - solverStep->createRealGrid ( "dist", _dist ); - solverStep->createVec3Grid ( "vorticity", DDF_GRID_NO_FREE ); - solverStep->createVec3Grid ( "ABL" ); - solverStep->createVec3Grid ( "pre-ABL", _abl ); - solverStep->createVec3Grid ( "vort" ); - solverStep->createRealGrid ( "pdf" ); - solverStep->createRealGrid ( "density", DDF_GRID_NO_FREE ); - solverStep->addStandardSolverGrids(); - solverStep->createNoiseField("noise", Vec3(0.), Vec3(50,50,50), -0.4, 20.0 /* 2.0 */, 0.002); - - // program solverStep initialization process - // solverStep->addInitPlugin ( "load-universal", StringArg("grid","dist") + StringArg("file","scene/static-dist.gz")); - // solverStep->addInitPlugin ( "load-universal", StringArg("grid","mean-flow") + StringArg("file","scene/static-mean.gz")); - // solverStep->addInitPlugin ( "load-universal", StringArg("grid","pre-ABL") + StringArg("file","scene/static-abl.gz")); - - // program solver main loop - solverStep->addPlugin ( "copy-grid", StringArg ( "src","mean-flow" ) + StringArg ( "dest","vel-curr") ); - solverStep->addPlugin ("init-density-inflow", StringArg("density","density") + RealArg("target-value",0.7) + IntArg("flag", FDENSITYSOURCE) + StringArg("noise","noise")); - solverStep->addPlugin ( "gen-vpart", StringArg ("source","pre-ABL") + StringArg ("flow","ABL") + StringArg("dist","dist") + StringArg("pdf","pdf") + - RealArg("thres-vort", 2e-2) + RealArg("thres-pdf",5e-5) + RealArg("mult-pdf",1) + RealArg("scale-flow", 0.94) + RealArg("max-bl",0.15) + - RealArg("min-dist", 3) + RealArg("min-rad", 3) + RealArg("max-rad", 7) + RealArg("vortex-gain", 2.5) + RealArg("fade-in", 0)); - - solverStep->addPlugin ( "semi-lagr-advect-vec3", StringArg ( "vel-src","ABL" ) + IntArg ( "mac", 0) ); - solverStep->addPlugin ( "apply-vpart", StringArg ( "vorticity", "vorticity" ) ); - solverStep->addPlugin ( "advect-vpart"); - solverStep->addPlugin ( "merge-vpart", StringArg("ndist","dist") + RealArg("init-time", 30) + RealArg("decay-time",450) + RealArg("merge-dist",0.8) + - RealArg("dissipate-radius",1) + RealArg("radius-cascade",1.5) ); - solverStep->addPlugin ("compute-vorticity", StringArg("vorticity","vort")); - solverStep->addPlugin ("maccormack-advect-real", StringArg("real-src","density")); - // solverStep->addPlugin( "dump-df3", IntArg("max-frames",200) + StringArg("gridname","density") + StringArg("prefix","sta") + RealArg("start-time",0) + IntArg("pbrt",1) + StringArg ( "override-name", "render/static" )); - - _solvers.push_back(solverStep); - } - - initAllSolvers(); - - _vorticity = _solvers[0]->getParams().getGridVec3("vorticity"); - _density = _solvers[0]->getParams().getGridReal("density"); - - _init = 1; - -} - -// static precompute -void FLUID_3D::precompute(const std::string& name, const Vec3& inflow, int frames, bool dynamic, const Vec3& rotAxis, Real rotSpeed) -{ - bool rotate = (rotSpeed != 0.); - SolverObject* solverPreCalc = new SolverObject( "precompute", _flags ); - - // create grids - solverPreCalc->createVec3Grid ( "normal", _normal ); - solverPreCalc->createRealGrid ( "dist", _dist ); - solverPreCalc->createVec3Grid ( "mean-vel", DDF_GRID_NO_FREE ); - solverPreCalc->createVec3Grid ( "abl", DDF_GRID_NO_FREE ); - solverPreCalc->addStandardSolverGrids(); - - // additional grids for rot. precomputation -#if 0 - // DG: not supoprted yet: possible problems with "flags" grid loading into obstacle-flags? - if (rotate) { - solverPreCalc->createIntGrid ("obstacle-flags"); - solverPreCalc->createIntGrid ("empty-flags"); - solverPreCalc->addInitPlugin ( "load-universal", StringArg("grid","obstacle-flags") + StringArg("file","scene/" + name + "-flags.gz")); - solverPreCalc->addInitPlugin ( "init-box-domain", StringArg("gridname","empty-flags") + IntArg ( "flag-inside",FFLUID ) + IntArg ( "flag-border",FINFLOW ) ); - } -#endif - // load grids, initialize fluid velocities - // solverPreCalc->addInitPlugin ( "load-universal", StringArg("grid","dist") + StringArg("file","scene/" + name + "-dist.gz")); - // solverPreCalc->addInitPlugin ( "load-universal", StringArg("grid","normal") + StringArg("file","scene/" + name + "-normal.gz")); - solverPreCalc->addInitPlugin ( "set-conditional", StringArg ( "gridname","vel-curr" ) + VecArg ( "target-vec",inflow ) + IntArg ( "flag", FFLUID ) ); - - // program solver main loop - solverPreCalc->addPlugin ( "set-conditional", StringArg ( "gridname","vel-curr" ) + VecArg ( "target-vec",inflow ) + IntArg ( "flag", FINFLOW ) ); - solverPreCalc->addPlugin ( "maccormack-advect-vec3", StringArg ( "vel-src", "vel-curr" ) ); - solverPreCalc->addPlugin ( "set-noslip-bcs", StringArg ( "grid","vel-curr" ) ); - solverPreCalc->addPlugin ( "diffuse-grid", StringArg ( "src-vec3", "vel-curr" ) + RealArg ( "diff", 0.3 ) ); - if (rotate) - solverPreCalc->addPlugin ("set-moving-obs-bcs", StringArg("obstacle","obstacle-flags") + StringArg("flags-src","empty-flags") + - VecArg("obs-rot-axis", rotAxis) + RealArg("obs-rot-vel", rotSpeed) + VecArg("obs-center", Vec3(0.5,0.5,0.5))); - solverPreCalc->addPlugin ( "solve-pressure", IntArg ( "openbound",0 ) ); - if (rotate) - solverPreCalc->addPlugin ( "average", StringArg ( "gridname","vel-curr" ) + StringArg ( "sumgrid","mean-vel" ) + IntArg ( "from", frames ) + IntArg ( "frames", 3 ) + IntArg ( "post-quit",1 ) + IntArg("stride", frames) ); - else - solverPreCalc->addPlugin ( "average", StringArg ( "gridname","vel-curr" ) + StringArg ( "sumgrid","mean-vel" ) + IntArg ( "from", frames ) + IntArg ( "frames", frames ) + IntArg ( "post-quit",1 ) ); - - // program final steps - solverPreCalc->addEndPlugin ( "calc-abl", StringArg ("mean-vel","mean-vel") + StringArg ("dist","dist") + StringArg("normal","normal") + StringArg("abl","abl") + RealArg("d", 1.7)); - -#if 0 - // DG: dynamic not supported yet - if (dynamic) - solverPreCalc->addEndPlugin ( "add-database", StringArg("grid","abl") + StringArg("normal","normal") + VecArg("u0",rotate ? (rotSpeed*rotAxis):inflow)); - else { - solverPreCalc->addEndPlugin ( "dump-universal", StringArg ( "grid","abl" ) + StringArg ( "override-name","scene/" + name + "-abl" ) + IntArg ( "single-dump", 1 ) ); - solverPreCalc->addEndPlugin ( "dump-universal", StringArg ( "grid","mean-vel" ) + StringArg ( "override-name","scene/" + name + "-mean" ) + IntArg ( "single-dump", 1 ) ); - } -#endif - - _solvers.push_back(solverPreCalc); - - initAllSolvers(); - - /* Calculate all requested frames */ - /* DG TODO: Can I precalc one frame at a time instead of all at once? */ - while(!advanceAllSolvers()) {}; - - finalizeAllSolvers(); - - _abl = _solvers[0]->getParams().getGridVec3("abl"); - _meanVel = _solvers[0]->getParams().getGridVec3("mean-vel"); - - freeAllSolvers(); -} - -void FLUID_3D::step() -{ - // run(); - - /* Calculate all requested frames */ - /* DG TODO: Can I precalc one frame at a time instead of all at once? */ - advanceAllSolvers(); - -} - -void FLUID_3D::del() -{ - finalizeAllSolvers(); - freeAllSolvers(); - - _init = 0; -}
\ No newline at end of file diff --git a/intern/smoke/intern/source/smoke.h b/intern/smoke/intern/source/smoke.h deleted file mode 100644 index fa20137cb1b..00000000000 --- a/intern/smoke/intern/source/smoke.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef DDF_SMOKE_H -#define DDF_SMOKE_H - -#include "globals.h" -#include "fluidsolver.h" - -#include "solverparams.h" -#include "paramset.h" -#include "solverplugin.h" -#include "solverinit.h" - -namespace DDF -{ - class FLUID_3D - { - private: - vector<SolverObject*> _solvers; - - /* DG: use 'public' for variables shared with blender ! */ - - private: - // functions taken over from standard main - bool advanceAllSolvers() - { - for (unsigned i=0;i<_solvers.size();i++) { - if (_solvers[i]->performStep()) return true; - } - return false; - } - - void finalizeAllSolvers() - { - for (unsigned i=0;i<_solvers.size();i++) - _solvers[i]->finalize(); - } - - void initAllSolvers() - { - for (int i = 0; i < _solvers.size(); i++) - _solvers[i]->forceInit(); - } - - void freeAllSolvers() - { - // finalizeAllSolvers(); // DG: I call this directly from code - - for (unsigned i=0;i<_solvers.size();i++) - delete _solvers[i]; - - _solvers.clear(); - } - - public: - int _res[3]; - - bool _init; - - /* Init */ - Grid<int> *_flags; - Grid<Vec3> *_normal; - Grid<Real> *_dist; - - /* Precompute */ - Grid<Vec3> *_meanVel; - Grid<Vec3> *_abl; - - /* Run */ - Grid<Real> *_density; - Grid<Vec3> *_vorticity; - - FLUID_3D(int res[3]) - { - _flags = NULL; - _normal = NULL; - _dist = NULL; - - _meanVel = NULL; - _abl = NULL; - - _density = NULL; - _vorticity = NULL; - - _res[0] = res[0]; - _res[1] = res[1]; - _res[2] = res[2]; - - _init = 0; - }; - - ~FLUID_3D() - { - freeAllSolvers(); - - delete _flags; - delete _normal; - delete _dist; - - delete _meanVel; - delete _abl; - - delete _density; - delete _vorticity; - }; - - void init(); - - void precompute(const std::string& name, const Vec3& inflow, int frames, bool dynamic, const Vec3& rotAxis = Vec3(0.), Real rotSpeed = 0.); - void step(); - - void del(); - }; - -}; - - -#endif /* DDF_SMOKE_H */
\ No newline at end of file diff --git a/intern/smoke/intern/source/smokeplugins.cpp b/intern/smoke/intern/source/smokeplugins.cpp deleted file mode 100644 index 88dccf38543..00000000000 --- a/intern/smoke/intern/source/smokeplugins.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Plugins for seeding smoke - * - *****************************************************************************/ - -#include "fluidsolver.h" -#include "solverplugin.h" -#include "paramset.h" - -#include "waveletnoise.h" -using WAVELETNOISE::WaveletNoiseField; - - -namespace DDF { - - -//***************************************************************************** -// helper plugin - -// optionally, write out inflow values for file export -class fsInitDensityInflow : public GridOpBase { - public: - fsInitDensityInflow(FlagGrid *flags, Grid<Real> *dst , Grid<Real> *writeGrid, Real target, int flag, - WaveletNoiseField* noise = NULL) : - GridOpBase(), mpDst(dst), mpWriteGrid(writeGrid), - mTargetValue(target), mFlag(flag), mpNoise(noise) { - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsInitDensityInflow() { }; - void resetVariables() { }; - void reduce(fsInitDensityInflow &op) { }; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - if(mpWriteGrid) gaWriteGrid.gridAccInit(mpWriteGrid, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - // add forces and update empty cells free surface boundaries - inline void operator() (int i, int j, int k) { - if(mpWriteGrid) gaWriteGrid.write(i,j,k) = 0.; - - // safety - always write - if( (getFlagAcc()(i,j,k) & mFlag) == 0) return; - Real& v = gaDst.write(i,j,k); - - if(!mpNoise) { - // constant - if(v<mTargetValue) v = mTargetValue; - } else { - const Real targ = mpNoise->evaluate( Vec3(i, j, k) ) * mTargetValue; - if(v<targ) v = targ; - } - - //debMsg("at"," "<<PRINT_IJK<<" flag ="<< getFlagAcc()(i,j,k)<<" smoke "<< gaDst.write(i,j,k)); - if(mpWriteGrid) gaWriteGrid.write(i,j,k) = v; - }; - - protected: - Grid<Real> *mpDst, *mpWriteGrid; - GridAccessor<Real,0> gaDst; - GridAccessor<Real,0> gaWriteGrid; - Real mTargetValue; - int mFlag; - // optional noise eval - WaveletNoiseField* mpNoise; -}; // fsInitDensityInflow */ - -class fsInflowVecApply : public GridOpBase { - public: - fsInflowVecApply(FlagGrid *flags, Grid<Vec3> *dst , Vec3 target, - WaveletNoiseField* noise = NULL, bool set=false, Real noiseThresh=0.) : - GridOpBase(), mpDst(dst), - mTargetValue(target), mpNoise(noise), mSet(set), mNoiseThreshold(noiseThresh) { - debMsg("fsInflowVecApply","noise thresh "<<mNoiseThreshold); - if(mNoiseThreshold>=0. && !mpNoise) { - errFatal("fsInflowVecApply","Noise treshhold needs noise field!",SIMWORLD_PLUGINERROR); - } - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsInflowVecApply() { }; - void resetVariables() { }; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - // add forces and update empty cells free surface boundaries - inline void operator() (int i, int j, int k) { - if(! fgIsInflow(getFlagAcc()(i,j,k)) ) return; - Vec3& v = gaDst.write(i,j,k); - - if(!mpNoise) { - // constant - if(!mSet) v += mTargetValue; - else v = mTargetValue; - } else if(mNoiseThreshold<=0.) { - // use noise... - - if(!mSet) { - // add - v[0] += mpNoise->evaluate( Vec3(i, j, k) ) * mTargetValue[0]; - v[1] += mpNoise->evaluate( Vec3(i+100., j, k) ) * mTargetValue[0]; - v[2] += mpNoise->evaluate( Vec3(i, j+200., k) ) * mTargetValue[0]; - } else { - // overwrite old - v[0] = mpNoise->evaluate( Vec3(i, j, k) ) * mTargetValue[0]; - v[1] = mpNoise->evaluate( Vec3(i+100., j, k) ) * mTargetValue[0]; - v[2] = mpNoise->evaluate( Vec3(i, j+200., k) ) * mTargetValue[0]; - } - } else { - // use noise threshold... - - if(!mSet) { - // add - errFatal("fsInflowVecApply","Noise treshhold only works with set=1",SIMWORLD_PLUGINERROR); - } else { - // overwrite old - if( mpNoise->evaluate( Vec3(i, j, k) ) > mNoiseThreshold ) { - v = mTargetValue; - //debMsg("vec"," "<<PRINT_IJK); - } - } - } - }; - void reduce(fsInflowVecApply &op) { }; - - protected: - Grid<Vec3> *mpDst; - GridAccessor<Vec3,0> gaDst; - Vec3 mTargetValue; - WaveletNoiseField* mpNoise; - bool mSet; - // dont set noise values, but set constant value if noise is smaller than threshold - Real mNoiseThreshold; -}; // fsInflowVecApply */ - -class spluginInitDensityInflow : public SolverPlugin { - public: - spluginInitDensityInflow() : SolverPlugin(), - mDensName("-unnamed-"), mWriteName(""), - mNoiseName(""), - mAnimOutCounter(0), mTargetValue(1.), mTargetVec(0.), mSet(false), - mNoiseThresh(0.) { - debMsg("spluginInitDensityInflow","cons"); - }; - ~spluginInitDensityInflow() { - debMsg("spluginInitDensityInflow","des"); - }; - - virtual bool parseParams(const ParamSet& params) { - debMsg("spluginInitDensityInflow","parse"); - mDensName = params.FindOneString("density", mDensName ); - mFlag = params.FindOneInt("flag", FINFLOW); - mVecName = params.FindOneString("vecgridname", mVecName ); - mWriteName = params.FindOneString("write-grid", mWriteName ); - mTargetValue = params.FindOneFloat("target-value", mTargetValue ); - - mSet = 0 < params.FindOneInt("set", mSet ); - - // preinit vec in case only real value is given - mTargetVec = Vec3(mTargetValue); - mTargetVec = params.FindOneVector("target-vec", mTargetVec ); - - mNoiseName = params.FindOneString("noise", mNoiseName ); - mNoiseThresh = params.FindOneFloat("noise-threshold", mNoiseThresh ); - return true; - }; - virtual bool initPlugin() { - debMsg("spluginInitDensityInflow","init"); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spluginInitDensityInflow"," dt="<<dt<<" dest:"<<mDensName<<"/"<<mVecName ); - //Grid<Real>* dens = mpPlParams->getGridReal(mDensName); - Grid<Real>* writeGrid = NULL; - if(mWriteName.length()>0) { - writeGrid = mpPlParams->getGridReal(mWriteName); - } - - WaveletNoiseField* noise = NULL; - if(mNoiseName.length()>0) - noise = mpPlParams->getNoiseField(mNoiseName); - - Grid<Real>* dens = NULL; - if(mpPlParams->haveGridReal(mDensName)) dens = mpPlParams->getGridReal(mDensName); - Grid<Vec3>* srcVecGrid = NULL; - if(mpPlParams->haveGridVec3(mVecName)) srcVecGrid = mpPlParams->getGridVec3(mVecName); - - GridBase* baseGrid = NULL; - if(dens) { - baseGrid = dens; - } else if(srcVecGrid) { - baseGrid = srcVecGrid; - } else { - errFatal("spluginInitDensityInflow","Provide either 'density'='"<<mDensName<<"', or 'vecgridname'='"<<mVecName<<"' ",SIMWORLD_PLUGINERROR); - } - - if(dens) { - fsInitDensityInflow(mpPlParams->getFluidSolver()->getGridFlags(), dens, - writeGrid, mTargetValue, mFlag,noise); - - /* writing out grids should now be done with the "dump-grip-scalar" plugin */ - } - if(srcVecGrid) { - // sanity checks - if(dens) { - errFatal("spluginInitDensityInflow","Error, can't do real-grid and vec-grid handling at same time!", SIMWORLD_PLUGINERROR); - } - - // apply... - fsInflowVecApply(mpPlParams->getFluidSolver()->getGridFlags(), srcVecGrid, - mTargetVec, noise, mSet, mNoiseThresh); - } - - return true; - }; - - protected: - // grid names to swap - std::string mDensName, mWriteName, mVecName; - std::string mNoiseName; - int mAnimOutCounter, mFlag; - Real mTargetValue; - Vec3 mTargetVec; - bool mSet; - int mDoLevelset; - Real mNoiseThresh; -}; - - -//***************************************************************************** - -SolverPlugin* MakeSmokePlugin(std::string name) { - - if(name.compare( string("init-density-inflow") )==0) { - return new spluginInitDensityInflow; - } - return NULL; -} - - -} // end namespace DDF - - diff --git a/intern/smoke/intern/source/solverinit.cpp b/intern/smoke/intern/source/solverinit.cpp deleted file mode 100644 index 40fa67e0ec5..00000000000 --- a/intern/smoke/intern/source/solverinit.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Class to setup the fluid solver (alternative to Parser/lexer) - * - *****************************************************************************/ - - -#include "solverinit.h" -#include "paramset.h" -#include "solverplugin.h" -#include "waveletnoise.h" -#include <map> - -// global solver lists for GLUTGUI -extern map<string, DDF::FluidSolver*> gFluidSolvers; -extern DDF::FluidSolver *gpFsolver; -extern map<string, WAVELETNOISE::WaveletNoiseField*> gNoiseFields; - -namespace DDF { -#if DDF_GLUTGUI == 1 -extern ParamSet gGlutGuiParams; -#endif - -// declaration from fileio.cpp -extern nVec3i getUniversalGridSize(const string& file); - -//****************************************************************************** -// PluginArgument class - -template<> PluginArgument::PluginArgument(const IntArg& pe) { - mParam.AddInt(pe.mName, pe.mValue); -} -template<> PluginArgument::PluginArgument(const RealArg& pe) { - mParam.AddFloat(pe.mName, pe.mValue); -} -template<> PluginArgument::PluginArgument(const StringArg& pe) { - mParam.AddString(pe.mName, pe.mValue); -} -template<> PluginArgument::PluginArgument(const VecArg& pe) { - mParam.AddVector(pe.mName, pe.mValue); -} - -PluginArgument operator+ (const PluginArgument& t, const PluginArgument& s) -{ - PluginArgument n; - n.mParam.AddSet(t.mParam); - n.mParam.AddSet(s.mParam); - return n; -} - -//****************************************************************************** -// SolverObject class - -SolverObject::SolverObject(const string& name, const nVec3i& gridSize, int gridFlags) -{ - init(name, gridSize, gridFlags); -} - -SolverObject::SolverObject(const string& name, const std::string& flagGridFile) -{ - nVec3i size = getUniversalGridSize(flagGridFile); - init(name, size); - addInitPlugin ("load-universal", StringArg("grid","flags") + StringArg("file",flagGridFile)); -} - -SolverObject::SolverObject(const std::string& name, const SolverObject& source, int multiplier, int gridFlags) -{ - nVec3i size = source.getParams().getGridSize() * multiplier; - init(name, size, gridFlags); - getParams().setMultiplier(multiplier); - getParams().adaptInit(&source.getParams()); -} - -SolverObject::SolverObject(const string& name, Grid<int> *flags) -{ - nVec3i size = flags->getSize(); - init(name, size); - createIntGrid("srcflags", flags); - addInitPlugin ("load-universal", StringArg("grid","flags") + StringArg("srcgrid", "srcflags")); -} - -SolverObject::~SolverObject() -{ - delete mSolver; -} - -// initialize default solver params -void SolverObject::init(const string& name, const nVec3i& size, int gridFlags) -{ - ParamSet par; - par.AddInt("host-vorticity-system", 1); - par.AddFloat("timestep", 1.0); - par.AddVector("gridsize", vec2R(size)); - par.AddFloat("cg-max-iter-fac", 0.30); - par.AddFloat("cg-accuracy", 0.001); - // setup plugin lists - mInitPlugins.clear(); - mPlugins.clear(); - mEndPlugins.clear(); - mStarted = false; - - // create solver - SolverParams* solverParam = new SolverParams("p_" + name); - solverParam->initFromParamSet(par); - mSolver = new FluidSolver("s_" + name); - mSolver->setParams(solverParam); - - // create default grids - createIntGrid("flags", gridFlags); - createVec3Grid("vel-curr"); - createRealGrid("pressure"); - - // globally register solver - gFluidSolvers[mSolver->getName()] = mSolver; - if (gpFsolver == NULL) gpFsolver = mSolver; - - // setup GUI params - #if DDF_GLUTGUI == 1 - gGlutGuiParams.AddString("solvername", gpFsolver->getName()); - #endif -} - -void SolverObject::forceInit() { - if (!mStarted) { - // start solver - mSolver->initFluid(); - mSolver->addInitPlugins(mInitPlugins); - mSolver->addPlugins(mPlugins); - mSolver->addEndPlugins(mEndPlugins); - mSolver->runInitPlugins(); - mSolver->setSolverInited(true); - mStarted = true; - } -} - -void SolverObject::addStandardSolverGrids() -{ - createVec3Grid("vec-temp"); - createRealGrid("real-temp"); - createRealGrid("temp1"); - createRealGrid("temp2"); - createRealGrid("tmp"); - createRealGrid("residual"); - createRealGrid("rhs"); - createRealGrid("search"); - createRealGrid("A0"); - createRealGrid("Ai"); - createRealGrid("Aj"); - createRealGrid("Ak"); -} - -void SolverObject::finalize() -{ - mSolver->finalize(); -} - -bool SolverObject::performStep() -{ - if (!mStarted) forceInit(); - for(int i=0; i< mSolver->getParams()->mStepFactor; i++) - mSolver->simulateFluid(); - - return mSolver->getParams()->getQuit(); -} - -void SolverObject::createIntGrid(const std::string& name, int gridFlags) -{ - const nVec3i gridsize = mSolver->getParams()->getGridSize(); - Grid<int> *grid = new Grid<int>(name); - grid->initGridMem(gridsize[0], gridsize[1], gridsize[2]); - mSolver->getParams()->mGridsInt[name] = grid; - grid->setGridFlags(gridFlags); - grid->setDisplayFlags(/* hideInGui */ 1); -} - -void SolverObject::createRealGrid(const std::string& name, int gridFlags) -{ - const nVec3i gridsize = mSolver->getParams()->getGridSize(); - Grid<Real> *grid = new Grid<Real>(name); - grid->initGridMem(gridsize[0], gridsize[1], gridsize[2]); - mSolver->getParams()->mGridsReal[name] = grid; - grid->setGridFlags(gridFlags); - grid->setDisplayFlags(/* hideInGui */ 1); -} - -void SolverObject::createVec3Grid(const std::string& name, int gridFlags) -{ - const nVec3i gridsize = mSolver->getParams()->getGridSize(); - Grid<Vec3> *grid = new Grid<Vec3>(name); - grid->initGridMem(gridsize[0], gridsize[1], gridsize[2]); - mSolver->getParams()->mGridsVec3[name] = grid; - grid->setGridFlags(gridFlags); - grid->setDisplayFlags(/* hideInGui */ 1); -} - -/* Use existing arrays */ -void SolverObject::createIntGrid(const std::string& name, Grid<int> *grid) -{ - mSolver->getParams()->mGridsInt[name] = grid; -} - -void SolverObject::createRealGrid(const std::string& name, Grid<Real> *grid) -{ - mSolver->getParams()->mGridsReal[name] = grid; -} - -void SolverObject::createVec3Grid(const std::string& name, Grid<Vec3> *grid) -{ - mSolver->getParams()->mGridsVec3[name] = grid; -} - -void SolverObject::createNoiseField(const string& name, const Vec3& posOffset, const Vec3& posScale, Real valOffset, Real valScale, Real timeAnim) -{ - // set params - ParamSet p; - p.AddVector("pos-offset", posOffset); - p.AddVector("pos-scale", posScale); - p.AddFloat("val-offset", valOffset); - p.AddFloat("val-scale", valScale); - p.AddFloat("time-anim", timeAnim); - p.AddBool("clamp",true); - p.AddFloat("clamp-neg",0.); - p.AddFloat("clamp-pos",1.); - - WAVELETNOISE::WaveletNoiseField *f = new WAVELETNOISE::WaveletNoiseField(name, p, getParams().getGridSize()); - p.ReportUnused(); - - // register globally - gNoiseFields[name] = f; - getParams().addNoiseField(f, name); -} - -SolverPlugin* SolverObject::createPlugin(const std::string& name, const PluginArgument& p) -{ - SolverPlugin* plugin = SolverPlugin::makePlugin(name); - if (!plugin) - errFatal("SolverObject::createPlugin","Can't create plugin " << name, SIMWORLD_ERRPARSE); - - plugin->setPluginParams(&getParams()); - plugin->SolverPlugin::parseParams(p.mParam); - if (!plugin->parseParams(p.mParam)) - errFatal("SolverObject::createPlugin","Error parsing arguments of plugin " << name, SIMWORLD_ERRPARSE); - - p.mParam.ReportUnused(); - return plugin; -} - -void SolverObject::addPlugin(const std::string& name, const PluginArgument& p) { - mPlugins.push_back(createPlugin(name, p)); -} -void SolverObject::addInitPlugin(const std::string& name, const PluginArgument& p) { - mInitPlugins.push_back(createPlugin(name, p)); -} -void SolverObject::addEndPlugin(const std::string& name, const PluginArgument& p) { - mEndPlugins.push_back(createPlugin(name, p)); -} - -} // DDF diff --git a/intern/smoke/intern/source/solverinit.h b/intern/smoke/intern/source/solverinit.h deleted file mode 100644 index e62363ecc91..00000000000 --- a/intern/smoke/intern/source/solverinit.h +++ /dev/null @@ -1,83 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Class to setup the fluid solver (alternative to Parser/lexer) - * - *****************************************************************************/ - -#ifndef DDFSOLVERINIT_H - -#include "fluidsolver.h" -#include "paramset.h" - -namespace DDF -{ - template<class T> class PluginArgumentElement { - public: - PluginArgumentElement(const std::string& name, const T& value) : mName(name), mValue(value) {} - - std::string mName; - T mValue; - }; - - // shortcuts - typedef PluginArgumentElement<string> StringArg; - typedef PluginArgumentElement<int> IntArg; - typedef PluginArgumentElement<Real> RealArg; - typedef PluginArgumentElement<Vec3> VecArg; - - // helper class to easily link plugin arguments - class PluginArgument { - public: - PluginArgument() {}; - template<class T> PluginArgument(const PluginArgumentElement<T>& pe); - - ParamSet mParam; - }; - PluginArgument operator+ (const PluginArgument&, const PluginArgument&); - - - // Wrapper class for a solver - class SolverObject - { - public: - SolverObject(const std::string& name, const nVec3i& gridSize, int gridFlags = 0); - SolverObject(const std::string& name, const std::string& flagGridFile); - SolverObject(const std::string& name, const SolverObject& source, int multiplier, int gridFlags); - SolverObject(const string& name, Grid<int> *flags); - ~SolverObject(); - - bool performStep(); - void finalize(); - - void createIntGrid(const std::string& name, int gridFlags = 0); - void createRealGrid(const std::string& name, int gridFlags = 0); - void createVec3Grid(const std::string& name, int gridFlags = 0); - void createIntGrid(const std::string& name, Grid<int> *grid); - void createRealGrid(const std::string& name, Grid<Real> *grid); - void createVec3Grid(const std::string& name, Grid<Vec3> *grid); - void createNoiseField(const std::string& name, const Vec3& posOffset, const Vec3& posScale, Real valOffset, Real valScale, Real timeAnim); - void addPlugin(const std::string& name, const PluginArgument& arg = PluginArgument()); - void addInitPlugin(const std::string& name, const PluginArgument& arg = PluginArgument()); - void addEndPlugin(const std::string& name, const PluginArgument& arg = PluginArgument()); - SolverParams& getParams() { return *(mSolver->getParams()); } - const SolverParams& getParams() const { return *(mSolver->getParams()); } - void forceInit(); - void addStandardSolverGrids(); - - protected: - void init(const std::string& name, const nVec3i& gridSize, int gridFlags = 0); - SolverPlugin* createPlugin(const std::string& name, const PluginArgument&); - - FluidSolver* mSolver; - std::vector<SolverPlugin*> mInitPlugins, mPlugins, mEndPlugins; - bool mStarted; - }; -}; - -#endif diff --git a/intern/smoke/intern/source/solverparams.cpp b/intern/smoke/intern/source/solverparams.cpp deleted file mode 100644 index eb0604fca13..00000000000 --- a/intern/smoke/intern/source/solverparams.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Class to store solver parameters - * - *****************************************************************************/ - -#include "solverparams.h" -#include "paramset.h" -#include "waveletnoise.h" -namespace DDF { - -//***************************************************************************** -// default init -SolverParams::SolverParams(const std::string& name) : - mName(name), - mMaxTimestep(0.5), mCflFactor(1.), - //mSurfaceTracker(0), // by default, no surface - mTimestepLevelsetFactor(1.0), - mCgMaxIterFac(1.), mCgAccuracy(5.0 * gVecEpsilon), - mTimestepAnim(0.5), mAnimOutputFile("animout_"), mOutputProgram(0), - mStepFactor(1), - mGridsReal(), mGridsVec3(), mGridsInt(), - mInited(false), mQuit(false), mSimTime(-1.), - mTimestep(0.5), - mGridSize(-1), mDeltaX(-1.), - mDimMax(-1), // updated in setSize - mAdaptInit(false), mAdaptDtScale(1.), - mAdapGridMultiplier(-1.), - mNoiseFields(), - mDivergenceCorrection(0.), - mpFluidSolver(NULL) -{ - mU0 = Vec3(0.); -}; - -// adapt init from another solver (eg set timestep) -bool SolverParams::adaptInit(const SolverParams* const otherParams) -{ - // use mAdapGridMultiplier ? - if(mAdapGridMultiplier > 0.) { - // round size - nVec3i s = otherParams->getGridSize(); - Vec3 ds = Vec3(s[0],s[1],s[2]); - ds *= mAdapGridMultiplier; - setGridSize( nVec3i( (int)ds[0], (int)ds[1], (int)ds[2] )); - } - - mAdaptDtScale = 1. / (double)otherParams->mDimMax * (double)mDimMax; - mTimestep = otherParams->mTimestep * mAdaptDtScale; - debMsg("SolverParams","adaptInit, gridsize="<<mGridSize<<", dt="<<mTimestep ); - - mAdaptInit = true; - - return true; -} - -//***************************************************************************** -// free grids etc. -SolverParams::~SolverParams() { - for(std::map<string, Grid<Real>* >::iterator iter=mGridsReal.begin(); - iter!=mGridsReal.end(); iter++) { - if( (*iter).second && !((*iter).second->getGridFlags() & DDF_GRID_NO_FREE)) - delete (*iter).second; - } - mGridsReal.clear(); - for(std::map<string, Grid<int>* >::iterator iter=mGridsInt.begin(); - iter!=mGridsInt.end(); iter++) { - if( (*iter).second && !((*iter).second->getGridFlags() & DDF_GRID_NO_FREE)) - delete (*iter).second; - } - mGridsInt.clear(); - for(std::map<string, Grid<Vec3>* >::iterator iter=mGridsVec3.begin(); - iter!=mGridsVec3.end(); iter++) { - if( (*iter).second && !((*iter).second->getGridFlags() & DDF_GRID_NO_FREE)) - delete (*iter).second; - } - mGridsVec3.clear(); -} - -bool SolverParams::verifyInit(string caller) { - if(!mInited) { - errMsg("SolverParams::verifyInit","Not inited at all! "<<caller); - return false; - } - if(mGridSize[0]<=0 || - mGridSize[1]<=0 || - mGridSize[2]<=0 || - mGridSize[0]>10000 || - mGridSize[1]>10000 || - mGridSize[2]>10000 || - false ) { - errMsg("SolverParams::verifyInit","Invalid gridsize "<<mGridSize); - return false; - } - return true; -} - - -// initialize from parsed paramset -bool SolverParams::initFromParamSet(const ParamSet ¶ms) { - // reset values, might be copied from previous settings - mInited =false; - mGridsReal.clear(); - mGridsInt.clear(); - mGridsVec3.clear(); - mpFluidSolver = NULL; - - // either init from vector or int - DDF::Vec3 sizeVec = params.FindOneVector("gridsize", vec2R(mGridSize) ); - int sizeInt = params.FindOneInt("gridsize", -1); - if(sizeInt>0) { - setGridSize( DDF::nVec3i(sizeInt) ); - } else { - setGridSize( vec2I(sizeVec) ); - } - // use adapt init multiplier? -1 for off - mAdapGridMultiplier = params.FindOneFloat("adap-grid-multiplier", mAdapGridMultiplier); - - mU0 = params.FindOneVector("u0", mU0); - mHostVorticitySystem = params.FindOneInt("host-vorticity-system", 0) != 0; - - mTimestep = params.FindOneFloat("timestep", mTimestep ); - mMaxTimestep = mTimestep; - mCflFactor = params.FindOneFloat("cflfactor", mCflFactor ); - mTimestepLevelsetFactor = params.FindOneFloat("timestep_levelset_factor", mTimestepLevelsetFactor ); - - mCgMaxIterFac = params.FindOneFloat("cg-max-iter-fac", mCgMaxIterFac ); - mCgAccuracy = params.FindOneFloat("cg-accuracy", mCgAccuracy ); - - mOutputProgram = params.FindOneInt("outputprogram", mOutputProgram); - if(mOutputProgram == 1) debMsg("Params","Output program set to blender..."); - - mTimestepAnim = params.FindOneFloat("timestep_anim", mTimestepAnim ); - if (mAdapGridMultiplier>1) mTimestepAnim*=mAdapGridMultiplier; - - mAnimOutputFile = params.FindOneString("animfile", mAnimOutputFile); - mStepFactor = params.FindOneInt("step-factor", mStepFactor); - - setInited(true); - // check sanity... (requires mInited = true) - if(!verifyInit("ddfParseGlobals")) { - setInited(false); - } - - return isInited(); -} - -//***************************************************************************** -// get grids - -Grid<int>* SolverParams::getGridInt(std::string name) { - if(mGridsInt.find(name) != mGridsInt.end() && mGridsInt[name]!=NULL) { - return mGridsInt[name]; - } else { - errFatal("SolverParams::getGridInt","'"<< name <<"' int grid required! "<<this->toString(), SIMWORLD_GRIDERROR); - } - return NULL; -} - -Grid<Real>* SolverParams::getGridReal(std::string name) { - if(mGridsReal.find(name) != mGridsReal.end() && mGridsReal[name]!=NULL) { - return mGridsReal[name]; - } else { - errFatal("SolverParams::getGridReal","'"<< name <<"' real grid required! "<<this->toString(), SIMWORLD_GRIDERROR); - } - return NULL; -} - -Grid<Vec3>* SolverParams::getGridVec3(std::string name) { - if(mGridsVec3.find(name) != mGridsVec3.end() && mGridsVec3[name]!=NULL) { - return mGridsVec3[name]; - } else { - errFatal("SolverParams::getGridVec3","'"<< name <<"' vec3 grid required! "<<this->toString(), SIMWORLD_GRIDERROR); - } - return NULL; -} - - -void SolverParams::setGridInt(std::string name, Grid<int>* set) { - mGridsInt[name] = set; -} -void SolverParams::setGridReal(std::string name, Grid<Real>* set) { - mGridsReal[name] = set; -} -void SolverParams::setGridVec3(std::string name, Grid<Vec3>* set) { - mGridsVec3[name] = set; -} - -bool SolverParams::haveGridInt(std::string name) { - if(mGridsInt.find(name) != mGridsInt.end() && mGridsInt[name]!=NULL) { - return true; - } - return false; - //return ( mGridsInt[name] != NULL); -} -bool SolverParams::haveGridReal(std::string name) { - if(mGridsReal.find(name) != mGridsReal.end() && mGridsReal[name]!=NULL) { - return true; - } - return false; - //return ( mGridsReal[name] != NULL); -} -bool SolverParams::haveGridVec3(std::string name) { - if(mGridsVec3.find(name) != mGridsVec3.end() && mGridsVec3[name]!=NULL) { - return true; - } - return false; - //return ( mGridsVec3[name] != NULL); -} -bool SolverParams::haveGridAny(std::string name) { - return ( haveGridInt(name) || - haveGridReal(name) || - haveGridVec3(name) ); -} - -//***************************************************************************** -// noise fields - -void SolverParams::addNoiseField(WAVELETNOISE::WaveletNoiseField* f, std::string name) -{ - mNoiseFields[name] = f; - Real dt = mNoiseFields[name]->getTimeAnim(); - // rescaling not necessary anymore - //debMsg("ADAP"," dt="<<dt<<" scale="<<mAdaptDtScale ); - mNoiseFields[name]->setTimeAnim( dt ); -} - -WAVELETNOISE::WaveletNoiseField* SolverParams::getNoiseField(std::string name) { - if(mNoiseFields.find(name) != mNoiseFields.end() && mNoiseFields[name]!=NULL) { - return mNoiseFields[name]; - } else { - errFatal("SolverParams::getNoiseField","'"<< name <<"' noise field required! "<<this->toString(), SIMWORLD_GRIDERROR); - } - return NULL; -} - - -// increase noise times -void SolverParams::addToNoiseTime(Real dt) { - - // scale by size because time anim is essentially - // a diagonal movement... - const Real dtFac = 1./(Real)mDimMax; - - for(std::map<std::string, WAVELETNOISE::WaveletNoiseField*>::iterator - iter=mNoiseFields.begin(); iter != mNoiseFields.end(); iter++) { - WAVELETNOISE::WaveletNoiseField* pntval = (WAVELETNOISE::WaveletNoiseField*)( (*iter).second ); - - //debMsg("SolverParams","addToNoiseTime, increased by "<<dt); - pntval->increaseTime(dt * dtFac); - //pntval->increaseTime(1.); - } -} - -//***************************************************************************** -// helper - -//void helperPrintMap(std::map<std::string, T*>& pmap, std::string caller) { -std::string SolverParams::printGridMaps() { - std::ostringstream out; - out << helperPrintMap(mGridsInt,"SolverParams::printGridMaps - int"); - out << helperPrintMap(mGridsReal,"SolverParams::printGridMaps - real"); - out << helperPrintMap(mGridsVec3,"SolverParams::printGridMaps - vec3"); - return out.str(); -} - -std::string SolverParams::toString() { - std::ostringstream out; - out << "SolverParams: gridsize="<<mGridSize<<" dt="<<mTimestep<<" cflfac="<<mCflFactor ; - return out.str(); -} - -} // DDF - diff --git a/intern/smoke/intern/source/solverparams.h b/intern/smoke/intern/source/solverparams.h deleted file mode 100644 index 2edf7373edd..00000000000 --- a/intern/smoke/intern/source/solverparams.h +++ /dev/null @@ -1,169 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Class to store solver parameters - * - *****************************************************************************/ - -#ifndef DDF_SOLVERPARAMS_H -#define DDF_SOLVERPARAMS_H - -#include "grid.h" -class ParamSet; - -namespace WAVELETNOISE { class WaveletNoiseField; } - -namespace DDF { - -class GeomFile; -class FluidSolver; - - -class SolverParams { - public: - // cons - SolverParams(const std::string& name=""); - // des - ~SolverParams(); - // check that globals have been inited, and are ok - bool verifyInit(string caller); - // initializer from parsed paramset - bool initFromParamSet(const ParamSet ¶ms); - // adapt init from another solver (eg set timestep) - bool adaptInit(const SolverParams* const otherParams); - - // solver name (from config) - std::string mName; - - // time step (maximal value, might be smaller due to cflfac) - Real mMaxTimestep; - // cfl multiplier to change time step according to max velocitites - Real mCflFactor; - - // size of timestep for level set tracker (mTimestep * factor) - Real mTimestepLevelsetFactor; - - // cg pressure solver control: max iteration factor - Real mCgMaxIterFac; - // desired accuracy - Real mCgAccuracy; - - //! time step for animation output (<0 for no output) - Real mTimestepAnim; - //! output name prefix - std::string mAnimOutputFile; - //! output for blender or other program? - int mOutputProgram; - - //! step factor for fixed dt solver comparison - int mStepFactor; - - // VP stuff - Vec3 mU0; - bool mHostVorticitySystem; - - // grids - std::map<string, Grid<Real>* > mGridsReal; - std::map<string, Grid<Vec3>* > mGridsVec3; - std::map<string, Grid<int>* > mGridsInt; - - //! access functions - void setInited(bool set) { mInited=set; } - bool isInited() const { return mInited; } - void setQuit(bool set) { mQuit=set; } - bool getQuit() const { return mQuit; } - void setFluidSolver(FluidSolver* set) { mpFluidSolver=set; } - FluidSolver* getFluidSolver() const { return mpFluidSolver; } - - Real getDt() const { return mTimestep; } - Real getTimestep() const { return mTimestep; } - void setTimestep(Real set) { mTimestep = set; } - - //! get/set grids in a secure(er) way - Grid<int>* getGridInt(std::string name); - Grid<Real>* getGridReal(std::string name); - Grid<Vec3>* getGridVec3(std::string name); - void setGridInt(std::string name, Grid<int>* set); - void setGridReal(std::string name, Grid<Real>* set); - void setGridVec3(std::string name, Grid<Vec3>* set); - void getGridType(std::string name, Grid<int>* &set) { set = getGridInt(name); }; - void getGridType(std::string name, Grid<Real>* &set) { set = getGridReal(name); }; - void getGridType(std::string name, Grid<Vec3>* &set) { set = getGridVec3(name); }; - - //! get noise field - WAVELETNOISE::WaveletNoiseField* getNoiseField(std::string name); - //! add noise field - void addNoiseField(WAVELETNOISE::WaveletNoiseField* f, std::string name); - void addToNoiseTime(Real dt); - - //! debug output - std::string printGridMaps(); - std::string toString(); - //! check if gridname exists - bool haveGridInt(std::string name); - bool haveGridReal(std::string name); - bool haveGridVec3(std::string name); - bool haveGridAny(std::string name); - - void setGridSize(nVec3i set) { mGridSize=set; mDimMax=VMAX(set); mDeltaX=1./(Real)mDimMax; } - nVec3i getGridSize() const { return mGridSize; } - // compute spatial discretization, currently given by dimMax, - // might differ in future - inline Real getDeltaX() const { return mDeltaX; } - // max dim. - inline int getDimMax() const { return mDimMax; } - - // simulation time - inline Real getSimTime() const { return mSimTime; } - inline void addToSimTime(Real add) { mSimTime += add; } - - // div. corr. - inline Real getDivergenceCorrection() const { return mDivergenceCorrection; } - inline void setDivergenceCorrection(Real set) { mDivergenceCorrection = set; } - - inline Real getMultiplier() { return mAdapGridMultiplier; } - inline void setMultiplier(Real v) { mAdapGridMultiplier = v; } - - protected: - // global settings - bool mInited; - // quit? - bool mQuit; - // current time - Real mSimTime; - - // time step (maximal value, might be smaller due to cflfac) - Real mTimestep; - - // size of simulation grid - nVec3i mGridSize; - // size of a cell, spatial discr. dx, set by gridsize - Real mDeltaX; - // max. dimension - int mDimMax; - - // adapt init - bool mAdaptInit; - double mAdaptDtScale; - // gridsize multiplier for adapted init - Real mAdapGridMultiplier; - - //! noise field storage - std::map<string, WAVELETNOISE::WaveletNoiseField* > mNoiseFields; - - //! pass divergence correction on to poisson solver, e.g. for volume correction - Real mDivergenceCorrection; - - //! simplify access to "parent" fluid solver - FluidSolver* mpFluidSolver; -}; - -}; // DDF - -#endif // DDF_SOLVERPARAMS_H - diff --git a/intern/smoke/intern/source/solverplugin.h b/intern/smoke/intern/source/solverplugin.h deleted file mode 100644 index 44467966f25..00000000000 --- a/intern/smoke/intern/source/solverplugin.h +++ /dev/null @@ -1,120 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Base class for Plugins - * - *****************************************************************************/ - -#ifndef DDF_SOLVERPLUGIN_H -#define DDF_SOLVERPLUGIN_H - -#include "globals.h" -class ParamSet; - -namespace DDF { -class SolverParams; - -// base functions for a plugin -// plugin handling implementation in solver.cpp, -// base methods implemented in stdplugins.cpp -class SolverPlugin { - public: - // cons - SolverPlugin(); - // des - virtual ~SolverPlugin(); - - // get parameters, e.g. grid names - virtual bool parseParams(const ParamSet& params); - // init plugin, return failure - virtual bool initPlugin() = 0; - // optional method, called after main loop is finished - virtual void finish(); - - // perform step with given dt, return failure - virtual bool performStep(Real dt) = 0; - - inline void setPluginParams(SolverParams* set) { mpPlParams=set; } - - inline void setName(std::string set) { mName=set; } - inline std::string getName() { return mName; } - - // check for start & end time of plugin - bool isCurrentlyActive(double t); - - static SolverPlugin* makePlugin(const std::string& name); - - protected: - // parameter storage - SolverParams* mpPlParams; - - // store plugin name for debugging - std::string mName; - - // debugging - enable plugin only in an interval - Real mTimeStart, mTimeStop; - - bool mWasActive; - Real mSingleTime; - - Real mInterval, mLastActive; - -}; // SolverPlugin - - -// create one of the plugins, e.g., advection or init steps - -// stdplugins.cpp -SolverPlugin* MakeStandardPlugin(std::string name); - -// stdplugins.cpp -SolverPlugin* MakeAdvectionPlugin(std::string name); - -// initplugins.cpp -SolverPlugin* MakeInitPlugin(std::string name); - -// vortexplugins.cpp -SolverPlugin* MakeVortexPlugin(std::string name); - -// fileio.cpp -SolverPlugin* MakeIoPlugin(std::string name); - -// poissonsolvers.cpp -SolverPlugin* MakePoissionSolverPlugins(std::string name); - -// animplugins.cpp -SolverPlugin* MakeAnimPlugin(std::string name); - -// smokeplugins.cpp -SolverPlugin* MakeSmokePlugin(std::string name); - -// helper function for plugins moving data from one grid to another -bool swapGrids(SolverParams* params, std::string mGrid1, std::string mGrid2); - -//************************************ -// invoke plugins -inline SolverPlugin* SolverPlugin::makePlugin(const std::string& name) -{ - SolverPlugin *plugin = MakeStandardPlugin(name); - if(!plugin) plugin = MakeInitPlugin(name); - if(!plugin) plugin = MakeAdvectionPlugin(name); - if(!plugin) plugin = MakeIoPlugin(name); - if(!plugin) plugin = MakePoissionSolverPlugins(name); - if(!plugin) plugin = MakeVortexPlugin(name); - if(!plugin) plugin = MakeAnimPlugin(name); - if(!plugin) plugin = MakeSmokePlugin(name); - - if(plugin) plugin->setName(name); - return plugin; -} -}; // DDF - - -#endif // DDF_SOLVERPLUGIN_H - - diff --git a/intern/smoke/intern/source/stdplugins.cpp b/intern/smoke/intern/source/stdplugins.cpp deleted file mode 100644 index c7bed7f0bdb..00000000000 --- a/intern/smoke/intern/source/stdplugins.cpp +++ /dev/null @@ -1,429 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Basic plugins (copy, set_bounds, etc.) - * - *****************************************************************************/ - -#include "fluidsolver.h" -#include "solverplugin.h" -#include "paramset.h" - -#include "matrixbase.h" - -// safety boundary for semi lagrange advection step -#define SLADVBOUND 2 - -namespace DDF { - -static inline bool doSetVelocity(int nbflag, int myflag) { - if (fgIsObstacle(nbflag) && !fgIsInflow(myflag) ) { - return false; - } - return true; -} - -//***************************************************************************** - -class fsSetNoslipBcs : public GridOpBaseFlagbord<1> { - public: - fsSetNoslipBcs(FlagGrid *flags, Grid<Vec3> *src) : - GridOpBaseFlagbord<1>(), mpVecgrid(src) { - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsSetNoslipBcs() { }; - void resetVariables() { }; - void buildCallList() { - gaVecgrid.gridAccInit(mpVecgrid, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - // set velocity at NB cell, given current flag myflag? - inline bool __doSetVelocity(int nbflag, int myflag) { - if (fgIsObstacle(nbflag) && !fgIsInflow(myflag) ) { - return false; - } - return true; - } - - // add forces and update empty cells free surface boundaries - inline void operator() (int i, int j, int k) { - int myFlag = getFlagAcc()(i,j,k); - Vec3& vel = gaVecgrid.write(i,j,k); - - if ( !doSetVelocity(myFlag, myFlag) ) { - vel = Vec3(0.); - return; - } - - if (fgIsEmpty(myFlag) ) - return; - - if (fgIsFluid(myFlag) ) { - // only add for faces that are between fluid/fluid fl/empty cells - if ( !doSetVelocity(getFlagAcc()(i-1,j,k), myFlag) ) { vel[0] = 0.; } - - if ( !doSetVelocity(getFlagAcc()(i,j-1,k), myFlag) ) { vel[1] = 0.; } - - if ( (!doSetVelocity(getFlagAcc()(i,j,k-1), myFlag) ) && (gDim==3) ) { vel[2] = 0.; } - - return; - } - }; - void reduce(fsSetNoslipBcs &op) { }; - - protected: - Grid<Vec3> *mpVecgrid; - GridAccessor<Vec3,1> gaVecgrid; - Vec3 mForce; - int mModFunc; - Real mThresh; - -}; // fsSetNoslipBcs */ - -// add forces to vels -class spSetNoslipBcs : public SolverPlugin { - public: - spSetNoslipBcs() : SolverPlugin(), mVel("-unnamed1-") { }; - ~spSetNoslipBcs() { }; - virtual bool initPlugin() { return true; }; - virtual bool parseParams(const ParamSet& params) { - mVel = params.FindOneString("grid", mVel ); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spSetNoslipBcs","step "<<dt<<" velsgrid:"<<mVel<<" to "<<mVel); - Grid<Vec3>* velsrc = mpPlParams->getGridVec3(mVel); - fsSetNoslipBcs(mpPlParams->getFluidSolver()->getGridFlags(), velsrc ); - return true; - }; - protected: - std::string mVel; -}; - -// copy source grid to destination -class spluginCopyGrid : public SolverPlugin { - public: - spluginCopyGrid() : SolverPlugin(), - mSrc("-unnamed1-"), - mDest("-unnamed2-") - { }; - ~spluginCopyGrid() { }; - - virtual bool parseParams(const ParamSet& params) { - mDest = params.FindOneString("dest", mDest ); - mSrc = params.FindOneString("src", mSrc ); - return true; - }; - virtual bool initPlugin() { - debMsg("spluginCopyGrid","init"); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spluginCopyGrid","step "<<dt); - if(mpPlParams->haveGridInt(mSrc) && 1) { - Grid<int>* dest = mpPlParams->getGridInt(mDest); - Grid<int>* src = mpPlParams->getGridInt(mSrc); - goCopyGrid<int>(dest, src); - } else if(mpPlParams->haveGridReal(mSrc) && 1) { - Grid<Real>* dest = mpPlParams->getGridReal(mDest); - Grid<Real>* src = mpPlParams->getGridReal(mSrc); - goCopyGrid<Real>(dest, src); - } else if(mpPlParams->haveGridVec3(mSrc) && 1) { - Grid<Vec3>* dest = mpPlParams->getGridVec3(mDest); - Grid<Vec3>* src = mpPlParams->getGridVec3(mSrc); - goCopyGrid<Vec3>(dest, src); - } - return true; - }; - - protected: - std::string mSrc, mDest; -}; - -// copy one element of a vector to a scalar grid -template<class Scalar,int NUM> -class goGetVec3NormToScalar : public GridOpBase { - public: - goGetVec3NormToScalar(Grid<Scalar> *gDst, Grid<Vec3> *gSrc) : GridOpBase() { - mpDst = gDst; - mpSrc = gSrc; - applyOperatorToGridsWithoutFlags(this, mpDst); - }; - ~goGetVec3NormToScalar() { }; - void resetVariables() { }; - void buildCallList() { - gaDst.gridAccInit(mpDst, AM_WRITE, gaCalls); - gaSrc.gridAccInit(mpSrc, AM_READ, gaCalls); - setNullFlagPointer(); - }; - inline void operator() (int i, int j, int k) { - gaDst.write(i,j,k) = norm(gaSrc(i,j,k)); - }; - void reduce(goGetVec3NormToScalar &op) { }; - protected: - Grid<Scalar> *mpDst; - Grid<Vec3> *mpSrc; - GridAccessor<Scalar,0> gaDst; - GridAccessor<Vec3,0> gaSrc; -}; // goGetVec3NormToScalar */ - -class spluginGetNorm : public SolverPlugin { - public: - spluginGetNorm() : SolverPlugin(), - mSrc("-unnamed-"), mDest("-unnamed2-"),mode(0) { }; - ~spluginGetNorm() { }; - - virtual bool parseParams(const ParamSet& params) { - mSrc = params.FindOneString("src", mSrc ); - mDest = params.FindOneString("dest", mDest ); - return true; - }; - virtual bool initPlugin() { return true; }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spluginGetNorm","step "<<dt); - Grid<int>* flags = mpPlParams->getGridInt("flags"); - - Grid<Vec3>* src = mpPlParams->getGridVec3(mSrc); - Grid<Real>* dest = mpPlParams->getGridReal(mDest); - goGetVec3NormToScalar<Real,0>(dest,src); - return true; - }; - - protected: - // grid names to swap - std::string mSrc,mDest; - int mode; -}; - -// Obtain time-averaged field -class spluginAverage : public SolverPlugin { - public: - spluginAverage() : SolverPlugin(), mSummed(0),mStrideCount(0) { }; - ~spluginAverage() { }; - - virtual bool parseParams(const ParamSet& params) { - mGrid = params.FindOneString("gridname", "vel-curr"); - mSumGrid = params.FindOneString("sumgrid", ""); - mFrom = params.FindOneInt("from", 0); - mStride = params.FindOneInt("stride",1); - mPostQuit = params.FindOneInt("post-quit", 0) != 0; - mFrames = params.FindOneInt("frames", 100); - mStrideCount = mStride-1; - return true; - }; - virtual bool initPlugin() { return true; }; - - virtual void finish() { - if (mSummed == 0) return; - Grid<int>* flags = mpPlParams->getGridInt("flags"); - if (mpPlParams->haveGridVec3(mGrid)) - goScale<Vec3>(mpPlParams->getGridVec3(mSumGrid), flags, 1./(Real)mSummed); - else if (mpPlParams->haveGridReal(mGrid)) - goScale<Real>(mpPlParams->getGridReal(mSumGrid), flags, 1./(Real)mSummed); - else - errMsg("spluginAverage","can't find grid " << mGrid << " or wrong type"); - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - if (mFrom > 0) { - debMsg("spluginAverage","will start in " << mFrom << " frames"); - --mFrom; - } else { - if (mSummed < mFrames) { - ++mStrideCount; - if (mStrideCount == mStride) { - mStrideCount = 0; - debMsg("spluginAverage", "taking snapshot -- " << mSummed+1 << " frames recorded so far" ); - - Grid<int>* flags = mpPlParams->getGridInt("flags"); - if (mpPlParams->haveGridVec3(mGrid)) - goSum<Vec3>(mpPlParams->getGridVec3(mSumGrid), mpPlParams->getGridVec3(mGrid), flags); - else if (mpPlParams->haveGridReal(mGrid)) - goSum<Real>(mpPlParams->getGridReal(mSumGrid), mpPlParams->getGridReal(mGrid), flags); - else - errMsg("spluginAverage","can't find grid " << mGrid << " or wrong type"); - mSummed++; - if (mSummed == mFrames && mPostQuit) - mpPlParams->setQuit(true); - } - } - } - return true; - }; - - protected: - // grid names to swap - std::string mGrid, mSumGrid; - int mSummed, mFrom, mFrames,mStride, mStrideCount; - bool mPostQuit; -}; - -// Dummy plugin -class spluginDummy : public SolverPlugin { - public: - spluginDummy() : SolverPlugin() { }; - ~spluginDummy() { }; - - virtual bool parseParams(const ParamSet& params) { return true; } - virtual bool initPlugin() { return true; }; - - virtual bool performStep(Real dt) { return true; }; -}; - - -//***************************************************************************** - -// solver plugin implementation -SolverPlugin::SolverPlugin() : - mpPlParams(NULL), mName("-"), mTimeStart(-1.), mTimeStop(1.0e10), - mWasActive(false), mSingleTime(-1.), mInterval(-1.), mLastActive(0.) -{ -}; - -SolverPlugin::~SolverPlugin() { -}; - -void SolverPlugin::finish() { -}; - -// get parameters, e.g. grid names -bool SolverPlugin::parseParams(const ParamSet& params) { - mTimeStart = params.FindOneFloat("plugin-start", mTimeStart ); - mTimeStop = params.FindOneFloat("plugin-stop", mTimeStop ); - mSingleTime = params.FindOneFloat("plugin-single-time", mSingleTime ); - mInterval = params.FindOneFloat("plugin-interval", mInterval ); - if(mTimeStop<mTimeStart) { - mTimeStop = mTimeStart = -1.; - } - - if (mSingleTime>=0.) { - debMsg("SolverPlugin::parseParams","Single time active "<<mSingleTime); - } else { - if(mInterval>=0.) { - debMsg("SolverPlugin::parseParams","Interval active "<<mInterval); - mLastActive = -mInterval; - if(mTimeStart!=-1.) { - mLastActive = mTimeStart-mInterval; - } - } - } - - return true; -} - -// check for start & end time of plugin -bool SolverPlugin::isCurrentlyActive(double t) { - // all timings off, return true by default - //if( mTimeStart<= -1. && mTimeStop>=1.0e10 && mSingleTime <= -1. ) { return true; } - - // else: single time? - if(mSingleTime >= 0.) { - if(t >= mSingleTime && !mWasActive) { - mWasActive = true; - return true; - } else { - return false; - } - } - - // else: times given & valid, check: - if(t < mTimeStart || t > mTimeStop) { - return false; - } - - if(mInterval >= 0.) { - if(t > mLastActive+mInterval) { - mLastActive += mInterval; - return true; - } else { - return false; - } - } - - return true; -} - -//***************************************************************************** - -bool swapGrids(SolverParams* params, std::string mGrid1, std::string mGrid2) -{ - if(0) debMsg("swapGrids","DEBUG: "<<params->printGridMaps() ); - - // distinguish data types - // replace pointers in maps, and then change - // names in grid classes too! - GridBase *g1=NULL, *g2=NULL; - if(params->haveGridInt(mGrid1) && 1) { - Grid<int>* tmp = params->getGridInt(mGrid1); - Grid<int>* grid2 = params->getGridInt(mGrid2); - params->setGridInt(mGrid1, grid2); - params->setGridInt(mGrid2, tmp); - g1 = tmp; g2 = grid2; - - //grid2->setName(mGrid1); - //tmp->setName(mGrid2); - } else if(params->haveGridReal(mGrid1) && 1) { - Grid<Real>* tmp = params->getGridReal(mGrid1); - Grid<Real>* grid2 = params->getGridReal(mGrid2); - params->setGridReal(mGrid1, grid2); - params->setGridReal(mGrid2, tmp); - g1 = tmp; g2 = grid2; - - //grid2->setName(mGrid1); - //tmp->setName(mGrid2); - } else if(params->haveGridVec3(mGrid1) && 1) { - Grid<Vec3>* tmp = params->getGridVec3(mGrid1); - Grid<Vec3>* grid2 = params->getGridVec3(mGrid2); - params->setGridVec3(mGrid1, grid2); - params->setGridVec3(mGrid2, tmp); - g1 = tmp; g2 = grid2; - } else { - return false; - } - - int tmp1 = g1->getDisplayFlags(); - g1->setDisplayFlags( g2->getDisplayFlags() ); - g2->setDisplayFlags( tmp1 ); - - g2->setName(mGrid1); - g1->setName(mGrid2); - - if(0) debMsg("swapGrids","DEBUG: "<<params->printGridMaps() ); - return true; -} - - - -// create one of the standard hard coded plugins -SolverPlugin* MakeStandardPlugin(std::string name) { - if(name.compare( "copy-grid")==0) { - return new spluginCopyGrid; - } else if(name.compare( "dummy")==0) { - return new spluginDummy; - } else if(name.compare( "set-noslip-bcs")==0) { - return new spSetNoslipBcs; - } else if(name.compare( "average" )==0) { - return new spluginAverage; - } else if(name.compare( string("get-vec3-norm") )==0) { - return new spluginGetNorm; - } - return NULL; -} - - -} // end namespace DDF - diff --git a/intern/smoke/intern/source/vortexpart.cpp b/intern/smoke/intern/source/vortexpart.cpp deleted file mode 100644 index f36afe5a2b5..00000000000 --- a/intern/smoke/intern/source/vortexpart.cpp +++ /dev/null @@ -1,667 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Vortex particle classes - * - *****************************************************************************/ - - -#include "vortexpart.h" - -// get rid of MSVC ambiguities be enforcing single precision -#ifdef WIN32 -#define pow powf -#endif - -#if DDF_DIMENSION==2 -#define FOR_KERNEL(rd) for (int j=-(rd),k=0,idx=0;j<=rd;++j) for (int i=-(rd);i<=rd;++i,++idx) -#else -#define FOR_KERNEL(rd) for (int k=-(rd),idx=0;k<=rd;++k) for (int j=-(rd);j<=rd;++j) for (int i=-(rd);i<=rd;++i,++idx) -#endif - -using namespace std; -namespace DDF { - -const Real PI = (Real)M_PI; -const Real MININV=1e-8,MININV2=1e-16; -inline Real SQR(DDF::Real x, DDF::Real y, DDF::Real z) { return x*x+y*y+z*z; } -inline Real SQRn(DDF::Real x, DDF::Real y, DDF::Real z) { DDF::Real v=x*x+y*y+z*z; if(v<MININV2){x+=MININV;return x*x+y*y+z*z;} return v; } - -#ifdef DEBUG_VORTEXPATH -std::list<LineElement> gVortexPath = std::list<LineElement>(); -#endif - -// ****************************************************************** -// -// VORTEX PARTICLE CONSTANTS -// -// ****************************************************************** - -const Real VortexParticleGaussian::msLogCutoff = sqrt(3.); // 3 is for cutoff at 1e-3 of the exponential term - -// workaround for missing erf function in win32 MSVC -#ifndef WIN32 -const static Real VPGaussian_msAreaMult_erf = erf( VortexParticleGaussian::msLogCutoff); -#else -const static Real VPGaussian_msAreaMult_erf = 0.9953222650; // hard coded value for 1e-4 cutoff -#endif - -#if DDF_DIMENSION==3 -const Real VortexParticleGaussian::msAreaMult = pow(PI, 1.5) * VPGaussian_msAreaMult_erf * exp(-1.); -#else -const Real VortexParticleGaussian::msAreaMult = 2.* PI * exp(-1.); -#endif -// move particles away from obstacles -const Real VortexParticle::msRepulsion = .5; -// attenuate particle near obstacles, remove amount of strength per timestep -const Real VortexParticle::msAttenuation = 0.1; -// if set to true, magnitude is preserved, otherwise decay is allowed -const bool VortexParticle::msStretchingPreserve = false; - -// Default values, may be changed via plugin -Real VortexParticle::msRadiusCascade = 2.; // split into particles of new_radius = radius/msRadiusCascade. If this param is small, many weak particles form -Real VortexParticle::msDissipateRadius = 1.; // dissipate particles smaller than this radius -Real VortexParticle::msDecayTime = 450.0; // factor to time before splitting -Real VortexParticle::msInitialTime = 20.5; // factor to time before entering inertial subrange -Vec3 VortexParticle::msU0 = Vec3(0.); // velocity scale (inflow speed etc.) -RandomStream VorticitySystem::randStream(13322223); - -// ****************************************************************** -// -// GENERAL PARTICLE FUNCTIONS -// -// ****************************************************************** - -// irad is related to the kernel distribution. orad is the cutoff radius -VortexParticle::VortexParticle(const Vec3& p, const Vec3& s, Real irad, Real orad) - : mPos(p),mStrength(s),mForce(0.),mFlags(0),mIRad(irad),mORad(orad), mAttenuate(0.) -{ - // time before entering inertial subrange - Real meantime = msInitialTime * pow(norm(msU0),-1./3.); - mTime = meantime * (1. + .5*(2.*VorticitySystem::rnd()-1.) ); -} - -inline void VortexParticle::advance(const Vec3& v) -{ -#if DEBUG_VORTEXPATH==1 - LineElement le; - le.p0 = mPos; - mPos += v; - le.p1 = mPos; - Real c = std::max(std::max(fabs(mStrength.x),fabs(mStrength.y)),fabs(mStrength.z)); - le.r = fabs(mStrength.x)/c; - le.g = fabs(mStrength.y)/c; - le.b = fabs(mStrength.z)/c; - le.a = 1.0; - le.s = mIRad; - gVortexPath.push_front(le); -#else - mPos += v; -#endif -} - -// calculate velocity gradient matrix at particles position by trilinear interpolation -inline Vec3 velGradient(Grid<Vec3>* grid, const Vec3& pos, int idx) -{ - Vec3 res; - for (int n=0;n<3;n++) - { - // translate grid (MAC) - Vec3 cpos (pos); - cpos[n] += .5; cpos[idx] -= 0.5; - nVec3i id(vec2I(cpos)), nid(id+1), nd(id), nnd(nid); - Vec3 a (cpos-vec2R(id)), na (-a+1.); - nd[n]++; nnd[n]++; - - // trilinear interpolation - res[n] = na.x * na.y * na.z * ( (*grid)( nd.x, nd.y, nd.z)[idx]-(*grid)( id.x, id.y, id.z)[idx]) + - na.x * na.y * a.z * ( (*grid)( nd.x, nd.y,nnd.z)[idx]-(*grid)( id.x, id.y,nid.z)[idx]) + - na.x * a.y * na.z * ( (*grid)( nd.x,nnd.y, nd.z)[idx]-(*grid)( id.x,nid.y, id.z)[idx]) + - na.x * a.y * a.z * ( (*grid)( nd.x,nnd.y,nnd.z)[idx]-(*grid)( id.x,nid.y,nid.z)[idx]) + - a.x * na.y * na.z * ( (*grid)(nnd.x, nd.y, nd.z)[idx]-(*grid)(nid.x, id.y, id.z)[idx]) + - a.x * na.y * a.z * ( (*grid)(nnd.x, nd.y,nnd.z)[idx]-(*grid)(nid.x, id.y,nid.z)[idx]) + - a.x * a.y * na.z * ( (*grid)(nnd.x,nnd.y, nd.z)[idx]-(*grid)(nid.x,nid.y, id.z)[idx]) + - a.x * a.y * a.z * ( (*grid)(nnd.x,nnd.y,nnd.z)[idx]-(*grid)(nid.x,nid.y,nid.z)[idx]); - } - return res; -} - -// perform vortex stretching -void VortexParticle::vortexStretch(Grid<Vec3>* pVel, Real dt, Real mult) -{ - Vec3 spos = mPos*mult; - // gradient - Vec3 s; - s.x = dot(mStrength,velGradient(pVel,spos,0)); - s.y = dot(mStrength,velGradient(pVel,spos,1)); - s.z = dot(mStrength,velGradient(pVel,spos,2)); - - Vec3 nstr = mStrength + dt * s; - Real oldStr2 = normNoSqrt(mStrength); - Real newStr2 = normNoSqrt(nstr); - - // do not allow the magnitude to grow - if (newStr2 > MININV2 && (newStr2 > oldStr2 || msStretchingPreserve)) - nstr *= sqrt(oldStr2 / newStr2); - - // apply vorticity update - mStrength = nstr; -} - -// reset the timer for decay; used after particle splitting etc. -void VortexParticle::setDecayTimer() -{ - Real meantime = msDecayTime * pow(norm(msU0),-1./3.) * ( pow(mIRad,-2./3.) - pow(mIRad * msRadiusCascade,-2./3.)); - mTime = meantime * (1. + .5*(2.*VorticitySystem::rnd()-1.) ); -} - -string VortexParticle::toString() { - std::ostringstream out; - out<< " pos="<<mPos<<" str="<<mStrength<<" radi="<<mIRad<<","<<mORad; - return out.str(); -} - - -// ****************************************************************** -// -// GAUSSIAN PARTICLE [psi = a*b/2/exp(-r^2/b)] -// -// Kernel used in the paper with b := 2 sqrt(sigma) -// -// ****************************************************************** - -// ATTENTION : For the 2D kernel, some derivations are obsolete. Better doublecheck before using 2D !! - -static float gAvgStr=0., gAvgStrCnt=0.; -VortexParticleGaussian::VortexParticleGaussian(const Vec3& pos, const Vec3& strength, Real irad) - : VortexParticle(pos,strength,irad, msLogCutoff*irad) -{ - mSigma = irad*irad; // w is zero at b=irad^2 - - // measure average strengths - float str = norm(strength); - gAvgStr += str; - gAvgStrCnt += 1.; - - printf("\n-> new particle : radius %g/%g strength [%g %g %g], avg %g,%g\n ",mIRad,mORad,strength.x,strength.y,strength.z, (gAvgStr/gAvgStrCnt), gAvgStrCnt); -} - -// Overlay desired vorticity of all kernels in temporary global grid -// using eq.13 in the paper -void VortexParticleGaussian::buildReference(Grid<Vec3>* pTemp, FlagGrid* flags, Real mult, bool doForces) -{ - // precompute frequently used constants - int irad = 1+(int)ceilf(mIRad*mult); - Real mult2=mult*mult, irad2 = mIRad*mIRad*mult2, isig=-1.0/(mSigma*mult2); - Vec3 spos = mPos*mult; - nVec3i apos = vec2I(spos); - Vec3 subpos = vec2R(apos)-spos; - if (gDim==2) {subpos.z = 0; apos.z = (int)mPos.z;} - Vec3 str = mStrength * (2.0 / mSigma); - Vec3 ndir(mStrength); - Real strength = normalize(ndir); - - // construct kernel - int totalSum=0, obsSum=0,freeSum=0; - Vec3 center(0.); - FOR_KERNEL(irad) - { - int x=apos.x+i, y=apos.y+j, z=apos.z+k; - Vec3 pa(subpos.x+i,subpos.y+j,subpos.z+k); - Real r2= SQR(pa.x,pa.y,pa.z); - if (r2 < irad2) - { - if (flags->checkIndexValid(x,y,z)) - { - // Evaluate Kernel - Real dz= dot(pa,ndir), rho2 = r2 - dz*dz; - Real gauss = (-rho2 + mSigma) * exp(isig * r2); - if (gauss>0) - (*pTemp)(x,y,z) += str * gauss; - - // Calculate overlap with air or obstacles - if (!doForces) continue; - if (fgIsEmpty(flags->getGlobal(x,y,z))) - freeSum++; - if (fgIsObstacle(flags->getGlobal(x,y,z))) - { - obsSum++; - center += Vec3(x,y,z); - } - // Delete particles at inflow - if ((flags->getGlobal(x,y,z) & FINFLOW) != 0) {markDelete();} - totalSum++; - } - else {markDelete();} - } - } - - mForce=0.; - mAttenuate=0.; - // Calculate repulsion force and delete invalid particles - if (doForces) - { - // Delete below dissipation radius - if (totalSum <= 1 || mIRad <= msDissipateRadius) - {markDelete(); } - else { - Real obsPart = (Real)obsSum/(Real)totalSum, freePart = (Real)freeSum/(Real)totalSum; - // Delete particles in the air or in obstacles - if (freePart > 0.5 || obsPart > 0.7) - {markDelete();} - else if (obsSum != 0 || freeSum != 0) - { - // Derive origin of repulsion force - Vec3 diff = spos - (center/obsSum); - normalize(diff); - mForce = obsPart * diff; - mAttenuate = (obsPart + freePart) * msAttenuation; -#if DDF_DIMENSION==2 - mForce.z = 0.; -#endif - } - /*std::cout << "totalSum " << totalSum << " obsPart " << obsPart << " freePart " << freePart << std::endl; - std::cout << "force : " << mForce << " attenuate " << mAttenuate << std::endl;*/ - } - } -} - -// merge current particle with particle v -// total vorticity and energy per volume are conserved -bool VortexParticleGaussian::merge(VortexParticle* v) -{ -#if DDF_DIMENSION==2 - Real aA = mIRad*mIRad, bA = v->getRadius()*v->getRadius(); -#else - Real aA = mIRad*mIRad*mIRad, bA = v->getRadius()*v->getRadius()*v->getRadius(); -#endif - //printf("\n* ---------------- MERGING\n[%g %g %g] r%g + [%g %g %g] r%g",mStrength.x,mStrength.y,mStrength.z,mIRad,v->getStrength().x,v->getStrength().y,v->getStrength().z,v->getRadius()); - - // derive new magnitude by conservation laws - const Vec3& aS = mStrength, bS = v->getStrength(); - Real midRatio = 0.5 * (norm(aS)/mIRad + norm(bS)/v->getRadius()); - Real magnitude = norm (aA * aS + bA * bS); - - // new radius and volume - Real r = pow ( magnitude/midRatio, 1./(1.+(Real)gDim)); - Real A = (gDim==2) ? (r*r) : (r*r*r); - - // obtain direction by weighted average - mStrength = aS * (aA/A) + bS * (bA/A); - mIRad = r; - mORad = msLogCutoff * mIRad; - mSigma = r*r; - - // average timers, enter inertial subrange - if ((v->getFlags() & FInertial) != 0) mFlags |= FInertial; - mTime = 0.5 * (mTime + v->getTime()); - - //printf(" -> [%g %g %g] r%g\n\n",mStrength.x,mStrength.y,mStrength.z,mIRad); - return true; -} - -// Split particle -// total vorticity and energy per volume are conserved -VortexParticle* VortexParticleGaussian::split() -{ - // obtain new radius depending on the chosen cascade level - Real bMult = 1.0 / (msRadiusCascade*msRadiusCascade); - // adapt strength using Kolmogorov law - Real aMult = sqrt(0.5) * pow(msRadiusCascade,(Real)gDim-5./6.); - - // set new radii and strength - mSigma *= bMult; - mIRad = sqrt(mSigma); - mORad = msLogCutoff * mIRad; - mStrength *= aMult; - - VortexParticle *p = new VortexParticleGaussian(mPos, mStrength, mIRad); - p->getFlags() |= FInertial; // after splitting, always enter inertial subrange - - return p; -} - -// velocity field induces by the kernel -// (eq. 12 in the paper) -// helper function for applyForce() -inline Vec3 gaussianKernel(const Vec3& pa, Real isig, Real magnitude,const Vec3& sdir) -{ - Real r2 = SQR(pa.x,pa.y,pa.z); - Real z = dot(pa,sdir), z2=z*z; - Real rho2 = r2-z2; - if (rho2 > MININV2 && MININV2) - { - Vec3 ephi = cross(sdir,pa); - Real s = magnitude * sqrt(rho2/r2) * exp(r2*isig); - return ephi*s; - } - return Vec3(0.); -} - -// Apply the kernel to the velocity field -void VortexParticleGaussian::applyForce( - Grid<Vec3>* pVel,Grid<Vec3>* pVort,Grid<Vec3>* pTemp, FlagGrid* flags, - Real mult, Real fadein, bool doForces, Grid<Vec3>* velHelper) -{ - // precalculate frequently used constants - int irad = 1+(int)ceilf(mIRad*mult); - Real mult2=mult*mult, irad2 = mIRad*mIRad*mult2; - Vec3 spos = mPos*mult; - nVec3i apos = vec2I(spos); - Vec3 subpos = vec2R(apos)-spos; - if (gDim==2) {subpos.z = 0; apos.z = (int)mPos.z;} - Vec3 ndir(mStrength); - Real strength=normalize(ndir); - if (strength==0) return; - - // integrate vorticity field of the kernel to obtain weight w_k - Real summRef=0,summDiff=0; - FOR_KERNEL(irad) - { - int x=apos.x+i, y=apos.y+j, z=apos.z+k; - if (flags->checkIndexValid(x,y,z)) - { - Real r2= SQR(subpos.x+i,subpos.y+j,subpos.z+k); - if (r2 < irad2) - { - Real wRef = dot((*pTemp)(x,y,z),ndir); - Real wCur = dot((*pVort)(x,y,z),ndir); - - summRef += wRef; - summDiff += wRef-wCur; - } - } - } - - // don't correct backwards, will cause oscillations - if (summRef >0 && summDiff > 0) - { - Real percentage = summDiff/summRef; - // Only evaluate if deviation from measured vorticity is not neglectable to save comp. time - if (percentage > 0.05) - { - if (percentage > 1.) percentage = 1.; // no jumps > 100% - Real magnitude = percentage*strength; - - // particle fade-in - //debMsg("VortexParticleGaussian","Fadein="<< fadein ); // debug - // NT test if ((mFlags & FInertial)==0 && mTime < fadein * mIRad) - if (mTime < fadein * mIRad) - magnitude *= mTime / (fadein*mIRad); - - // precalculate - int orad = 1+(int)ceilf(mORad*mult); - Real orad2=mORad*mORad*mult2, isig=-1.0/(mSigma*mult2); - - // apply kernel - FOR_KERNEL(orad) - { - int x=apos.x+i, y=apos.y+j, z=apos.z+k; - if (flags->checkIndexValid(x,y,z) && !fgIsObstacle(flags->getGlobal(x,y,z))) - { - Vec3 pa(subpos.x+i,subpos.y+j,subpos.z+k), v(0.); - if (SQR(pa.x,pa.y,pa.z) < orad2) - { - // x direction - if (flags->checkIndexValid(x-1,y,z) && fgIsFluid(flags->getGlobal(x-1,y,z))) - { - Vec3 vp = gaussianKernel(Vec3(pa.x-.5,pa.y,pa.z), isig, magnitude, ndir); - v.x = vp.x; - } - // y direction - if (flags->checkIndexValid(x,y-1,z) && fgIsFluid(flags->getGlobal(x,y-1,z))) - { - Vec3 vp = gaussianKernel(Vec3(pa.x,pa.y-.5,pa.z), isig, magnitude, ndir); - v.y = vp.y; - } - #if DDF_DIMENSION==3 - // z direction - if (flags->checkIndexValid(x,y,z-1) && fgIsFluid(flags->getGlobal(x,y,z-1))) - { - Vec3 vp = gaussianKernel(Vec3(pa.x,pa.y,pa.z-.5), isig, magnitude, ndir); - v.z = vp.z; - } - #endif - (*pVel)(x,y,z) +=v; - if(velHelper) velHelper->getGlobal(x,y,z) += v; - } - } - } - } - } - - // process attenuation for particles trapped in obstacle - // shrink radius and strength, such that str/R = const - if (doForces) - { - if (mAttenuate > 1e-4) - { - Real perc = 1.-mAttenuate; - scale(pow(perc,1./((Real)gDim+1.))); - } - } -} - -// uniform scaling of the particle -void VortexParticleGaussian::scale(Real fac) -{ - mIRad *= fac; - mORad *= fac; - mSigma *= fac*fac; - mStrength *= fac; -} - - -// ****************************************************************** -// -// VORTICITY SYSTEM -// -// ****************************************************************** - -// apply the particles velocity kernel onto the grid -void VorticitySystem::applyForces(Grid<Vec3>* pVel, Grid<Vec3>* pVort, Grid<Vec3>* pTemp,FlagGrid* flags, Real mult, bool doForces, - Grid<Vec3>* velHelper) -{ - std::cout << "----------------------" << mParts.size() <<" parts------------------------" << std::endl; - - const VList::iterator it_end = mParts.end(); - for (VList::iterator it=mParts.begin(); it != it_end; ++it) - { - (*it)->buildReference(pTemp, flags, mult, doForces); - } - for (VList::iterator it=mParts.begin(); it != it_end; ++it) - { - if ((*it)->isDeleted()) continue; - (*it)->applyForce(pVel,pVort,pTemp,flags, - mult, msFadeIn, doForces,velHelper); - } -} - -// perform merge, split and dissipation of particles -void VorticitySystem::merge(FlagGrid* flags, Grid<Real>* ndist, Grid<Vec3>* vel,Real dt, Real mergeDist) -{ - Real mergeDist2 = mergeDist*mergeDist; - - // Update timer, split - for (VList::iterator it=mParts.begin(); it != mParts.end(); ++it) - { - VortexParticle *p = *it; - if (p->isDeleted()) continue; - p->getTime() -= dt; - if (VortexParticle::doDecay() && p->getTime() <= 0) - { - // dissipatation - if (p->getRadius() <= VortexParticle::msDissipateRadius) - {p->markDelete(); } - // particle splitting - else if ((p->getFlags() & VortexParticle::FInertial) != 0) - { - //printf("split before : %g,%g,%g / r%g\n",p->getStrength().x,p->getStrength().y,p->getStrength().z,p->getRadius()); - VortexParticle* pn = p->split(); - pn->setDecayTimer(); - pn->getFlags() |= VortexParticle::FInertial; - - // slightly modify new particle position, so that they don't lump together - Vec3 ndir (rnd(),rnd(),rnd()); - Real nDP1 = sqrt(p->getRadius()) * (0.5+1.*rnd()); - Real nDP3 = 3. * dt*norm(mpFsolver->interpolateVpVelocity(p->getPos(), vel)); - ndir *= std::max(std::min(nDP1,nDP3),(Real)1.2) / norm(ndir); - if (gDim==2) ndir.z=0; - pn->advance(ndir); - p->advance(-ndir); - - // slightly modify new particle axis, so that they don't lump together -#if DDF_DIMENSION==3 - Vec3 nang (rnd(),rnd(),rnd()); - Real str = norm(p->getStrength()); - nang *= 0.1 * str / norm(nang); - Vec3 pnew = (p->getStrength()+nang); - Real pnewn = norm(pnew); - if (pnewn > MININV) - p->getStrength() = pnew * (str / pnewn); - pnew = (pn->getStrength()-nang); - pnewn = norm(pnew); - if (pnewn > MININV) - pn->getStrength() = pnew * (str / pnewn); -#endif - mParts.insert(it,pn); - - //printf("split 1: %g,%g,%g / r%g\n",p->getStrength().x,p->getStrength().y,p->getStrength().z,p->getRadius()); - //printf("split 2 : %g,%g,%g / r%g\n",pn->getStrength().x,pn->getStrength().y,pn->getStrength().z,pn->getRadius()); - } - p->getFlags() |= VortexParticle::FInertial; - p->setDecayTimer(); - } - else if(VortexParticle::doDecay() && (p->getFlags() & VortexParticle::FInertial) == 0) - { - // transfer to inertial range if particle leaves near-wall region - nVec3i pos(vec2I(p->getPos()+.5)); - if ((*ndist).getGlobal(pos.x,pos.y,pos.z) == 0) - { - Real timeLeft = p->getTime(); - p->getFlags() |= VortexParticle::FInertial; - p->setDecayTimer(); - p->getTime() = 0.5* (p->getTime() + timeLeft); - } - } - } - - // Particle merging - const VList::iterator it_end = mParts.end(); - for (VList::iterator it=mParts.begin(); it != it_end; ++it) - { - VortexParticle* p1 = *it; - if (!p1->canMerge()) continue; - VList::iterator it2=it; - for (++it2; it2 != it_end; ++it2) - { - VortexParticle* p2 = *it2; - Real d2 = normNoSqrt(p1->getPos()-p2->getPos()); - // Merge if distance smaller then merge radius - if (p2->canMerge() && - d2 < (p1->getMergeR2()+ p2->getMergeR2())*mergeDist2 && - d2 < 4.*min(p1->getMergeR2(), p2->getMergeR2())*mergeDist2) - { - // Merging probability scales with axis alignment of the two particles - Real angle = acos(dot(p1->getStrength(),p2->getStrength())/(norm(p1->getStrength())*norm(p2->getStrength()))); - Real prob = 1.-angle/PI; - Real rand = rnd(); - if (rand >= prob) continue; - - Real dist = norm(p1->getPos()-p2->getPos()); - if (p1->merge(p2)) - { - p2->markDelete(); cout << "MRG - " << p1->getPos() << " d " << dist << endl; - break; - } - } - } - } - - // remove particles marked for deletation - for (VList::iterator it=mParts.begin(); it != mParts.end();) - if ((*it)->isDeleted()) - { - delete *it; - it = mParts.erase(it); - } - else - ++it; -} - -// particle advection and vortex stretching -void VorticitySystem::advectParticles(Grid<Vec3>* pVel, FlagGrid* flags, Real dt, Real mult) -{ - const int numParticles = mParts.size(); - -#if DEBUG_VORTEXPATH==1 - for (std::list<LineElement>::iterator it=gVortexPath.begin(); it != gVortexPath.end();) - { - it->a -= 0.015; - if (it->a < 0) - it = gVortexPath.erase(it); - else - ++it; - } -#endif - - { - int i=0; - const VList::iterator it_end = mParts.end(); - for (VList::iterator it=mParts.begin(); it != it_end;++i) - { - VortexParticle& p = *(*it); - // Second-order Heun/RK2 step - Vec3 pos1 = p.getPos(); - Vec3 v1 = mpFsolver->interpolateVpVelocity(pos1*mult, pVel); - Vec3 pos2 = pos1 + v1*dt; - Vec3 v2 = mpFsolver->interpolateVpVelocity(pos2*mult, pVel); - Vec3 v = (v1+v2)*0.5; - // remove deleted particles (only used if no merge plugin is invoked) - if (p.isDeleted() ) - { - delete *it; - it = mParts.erase(it); - } - else - { - // update vorticity (vortex stretching) -#if DDF_DIMENSION==3 - p.vortexStretch(pVel, dt, mult); -#endif - // update position - v += dt*p.getForce() * VortexParticle::msRepulsion; - p.advance(v*dt); - ++it; - } - } - } -} - - -// constructor -VorticitySystem::VorticitySystem(FluidSolver *fs) : - mpFsolver(fs) -{ - VortexParticle::msU0 = fs->getParams()->mU0; - - // init defaults - msFadeIn = 2.; -}; - -// destructor -VorticitySystem::~VorticitySystem() -{ - for (VList::iterator it=mParts.begin(); it != mParts.end();) { - delete *it; - it = mParts.erase(it); - } -} - -} // namespace DDF - diff --git a/intern/smoke/intern/source/vortexpart.h b/intern/smoke/intern/source/vortexpart.h deleted file mode 100644 index 6e14a6c5f32..00000000000 --- a/intern/smoke/intern/source/vortexpart.h +++ /dev/null @@ -1,140 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Vortex Particle classes - * - *****************************************************************************/ - -#ifndef DDFVORTEXPART_H - -#include <list> -#include "globals.h" -#include "fluidsolver.h" -#include "randomstream.h" - -#define DEBUG_VORTEXPATH 1 - -namespace DDF { - -#ifdef DEBUG_VORTEXPATH -// for debugging: draws a line behind the particles -struct LineElement { - Vec3 p0, p1; - Real r,g,b,a,s; -}; -extern std::list<LineElement> gVortexPath; -#endif - - -class VortexParticle{ - public: - VortexParticle(const Vec3& p, const Vec3& s, Real irad, Real orad); - virtual ~VortexParticle() {}; - - // check if particle should split - static inline bool doDecay() { return msDecayTime != 0; } - inline Vec3& getPos() {return mPos; }; - inline Vec3& getStrength() {return mStrength; }; - inline const Vec3& getPos() const {return mPos; }; - // radius in which particles merge - inline Real getMergeR2() { return mIRad * mIRad; } - inline Real getRadius() { return mIRad; } - inline Vec3& getForce() { return mForce; }; - inline Real& getTime() { return mTime; }; - int& getFlags() { return mFlags; }; - bool isDeleted() { return (mFlags & FDelete) == 1; }; - bool canMerge() { return (mFlags & (FDelete | FInertial)) == 0; } - // mark for deletation in the next timestep - void markDelete() { mFlags |= 1; }; - // use this to advect the particle - inline void advance(const Vec3& v); - void setDecayTimer(); - - virtual void scale(Real fac) = 0; - // merge this particle with particle v - virtual bool merge(VortexParticle* v) = 0; - // split into two particles, radius controlled by msRadiusCascade - virtual VortexParticle* split() = 0; - // add particles vorticity to desired vorticity grid (w_D) - virtual void buildReference(Grid<Vec3>* pTemp, FlagGrid* flags, Real mult, bool doForces) = 0; - // apply vortex stretching - virtual void vortexStretch(Grid<Vec3>* pVel, Real dt, Real mult); - // apply particles velocity kernel to simulation - virtual void applyForce(Grid<Vec3>* pVel,Grid<Vec3>* pVort,Grid<Vec3>* pTemp, FlagGrid* flags, - Real mult, Real fadein, bool doForces, Grid<Vec3>* velHelper = NULL) = 0; - virtual std::string toString(); - - static const Real msRepulsion, msAttenuation; // factor for repulsion, attenuation forces when particles is near a wall - static const bool msStretchingPreserve; // preserve vortex strength in vortex stretching (only rotate axis) ? - static Real msDecayTime; // Factor to the decay timescale - static Real msInitialTime; // Factor to the transition time to inertial subrange - static Real msRadiusCascade; // Factor to wavenumber in decay (i.e. 0.5 -> radius is halfed). Controls granularity of decay. - static Real msDissipateRadius; // Particle below this radius are dissipated (usually 0.5..1 grid cells) - static Vec3 msU0; // Global velocity scale (inflow etc.) - - enum Flag { FDelete = 1, FInertial = 2}; - - protected: - Vec3 mPos, mStrength, mForce; - int mFlags; - Real mIRad, mORad, mTime, mAttenuate; -}; - -class VortexParticleGaussian : public VortexParticle{ - public: - VortexParticleGaussian(const Vec3& pos, const Vec3& strength, Real irad); - - void scale(Real fac); - bool merge(VortexParticle* v); - VortexParticle* split(); - void buildReference(Grid<Vec3>* pTemp, FlagGrid* flags, Real mult, bool doForces); - void applyForce(Grid<Vec3>* pVel,Grid<Vec3>* pVort,Grid<Vec3>* pTemp, FlagGrid* flags, - Real mult, Real fadein, bool doForces, Grid<Vec3>* velHelper = NULL); - static Real getAreaMultiplier() { return msAreaMult; } - - static const Real msLogCutoff, msAreaMult; - protected: - Real mSigma; -}; - -class VorticitySystem -{ - public: - typedef std::list<VortexParticle*> VList; - - VorticitySystem(FluidSolver *fs); - ~VorticitySystem(); - - inline VList& getParticles() { return mParts; } - static inline Real rnd() { return randStream.getReal(); } - static inline Real rndg() { return randStream.getRandNorm(0.,1.); } - - // apply all particles to velocity grid - void applyForces(Grid<Vec3>* pVel, Grid<Vec3>* pVort, Grid<Vec3>* pTemp, FlagGrid* flags, Real mult, bool doForces, Grid<Vec3>* velHelper = NULL); - void advectParticles(Grid<Vec3>* pVel, FlagGrid* flags, Real dt, Real multiplier); - void registerPrecomp(vector<Real>* dat) { mpPrecomp = dat; } - // merge & split particles - void merge (FlagGrid* flags, Grid<Real>* ndist,Grid<Vec3>* vel, Real dt, Real mergeDist); - vector<Real>* getPrecomp() { return mpPrecomp; } - - Real getFadeIn() const { return msFadeIn; } - void setFadeIn(Real set) { msFadeIn = set; } - - protected: - VList mParts; - DDF::FluidSolver * mpFsolver; - vector<Real> * mpPrecomp; - static RandomStream randStream; - Real msFadeIn; -}; - - -} - -#define DDFVORTEXPART_H -#endif diff --git a/intern/smoke/intern/source/vortexplugins.cpp b/intern/smoke/intern/source/vortexplugins.cpp deleted file mode 100644 index 170e8d1a9bf..00000000000 --- a/intern/smoke/intern/source/vortexplugins.cpp +++ /dev/null @@ -1,931 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Plugins to access vortex particles - * - *****************************************************************************/ - -#include "fluidsolver.h" -#include "solverplugin.h" -#include "paramset.h" - -#include "randomstream.h" -#include "vortexpart.h" -#include <zlib.h> - -using namespace std; - -namespace DDF { - -// declare external accesors -extern void closeDatabaseWriter(); -extern std::vector<Vec3> initDatabaseWriter(const string&, int, int); - -#if DDF_DIMENSION==3 -#define FOR_KERNEL(rad) for (int z=-rad;z<=rad;z++) for (int y=-rad;y<=rad;y++) for (int x=-rad;x<=rad;x++) -#else -#define FOR_KERNEL(rad) for (int y=-rad,z=0;y<=rad;y++) for (int x=-rad;x<=rad;x++) -#endif - -//***************************************************************************** -// Invoke vortex particle advection, vortex stretching -class spluginAdvectVPart : public SolverPlugin { - public: - spluginAdvectVPart() : SolverPlugin(), mGrid("vel-curr") - { }; - ~spluginAdvectVPart() { }; - - virtual bool parseParams(const ParamSet& params) { - mGrid = params.FindOneString("gridname",mGrid); - mSolver = params.FindOneString("from-solver",""); // use particles hostsed on a different solver - return true; - }; - virtual bool initPlugin() { - debMsg("spluginAdvectVPart","init"); - return true; - }; - - // perform step with given dt - virtual bool performStep(Real dt) { - debMsg("spluginAdvectVPart","step "<<dt); - FlagGrid* flags = mpPlParams->getGridInt("flags"); - Grid<Vec3>* vel = mpPlParams->getGridVec3(mGrid); - - FluidSolver* solver = mSolver.empty() ? mpPlParams->getFluidSolver() : ddfWorldFindSolver(mSolver); - Real multiplier = mpPlParams->getMultiplier(); - if (multiplier <=0) multiplier = 1.; - solver->getVorticitySys()->advectParticles(vel, flags, dt/multiplier, multiplier); - return true; - }; - - protected: - string mGrid, mSolver; -}; - - -//***************************************************************************** -// Gridop : compute vorticity of velocity grid -// output vorticity is centered on ijk -class fsComputeVort : public GridOpBaseFlagbord<1> { - public: - fsComputeVort(FlagGrid *flags, Grid<Vec3> *vel, Grid<Vec3> *vort, Real dx) : - GridOpBaseFlagbord<1>(), mpVel(vel), mpVort(vort) { - mDxInv = 1.0; - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsComputeVort() { }; - void resetVariables() { }; - void buildCallList() { - gaVel.gridAccInit(mpVel, AM_READ, gaCalls); - gaVort.gridAccInit(mpVort, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) - { - int flag = getFlagAcc()(i,j,k); - if(!fgIsFluid(flag)) { - gaVort.write(i,j,k) = Vec3(0.); - return; - } - #define getv(i,j,k) (!fgIsFluid(getFlagAcc()(i,j,k))?v0:gaVel(i,j,k)) - Vec3 w(0.),v0 (gaVel(i,j,k)); - for (int l=0;l<4;l++) // averaging kernel to get center value - { - if (gDim==3) - { - w[0] += (Real)_b[l] * (getv(i,j+_b[l],k+_a[l])[2] - getv(i,j+_a[l],k+_b[l])[1]); - w[1] += (Real)_b[l] * (getv(i+_a[l],j,k+_b[l])[0] - getv(i+_b[l],j,k+_a[l])[2]); - } - w[2] += (Real)_b[l] * (getv(i+_b[l],j+_a[l],k)[1] - getv(i+_a[l],j+_b[l],k)[0]); - } - #undef getv - - gaVort.write(i,j,k) = w*(mDxInv*0.25); - }; - void reduce(fsComputeVort &op) { }; - - protected: - Grid<Vec3> *mpVel; - Grid<Vec3> *mpVort; - GridAccessor<Vec3,1> gaVel; - GridAccessor<Vec3,0> gaVort; - - static const int _a[4],_b[4]; - Real mDxInv; -}; -const int fsComputeVort::_a[4]={ 1, 0, 1, 0}; -const int fsComputeVort::_b[4]={ 1, 1,-1,-1}; - - -//***************************************************************************** -// Plugin to invoke vorticity computation of velocity grid -class spluginComputeVorticity : public SolverPlugin { - public: - spluginComputeVorticity() : SolverPlugin(), - mGrid("vel-curr"),mVort("-unnamed-") { - }; - ~spluginComputeVorticity() { }; - - virtual bool parseParams(const ParamSet& params) { - mGrid = params.FindOneString("velocity", mGrid ); - mVort = params.FindOneString("vorticity", mVort ); - return true; - }; - virtual bool initPlugin() { - debMsg("spluginComputeVorticity","init"); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spluginComputeVorticity"," dt="<<dt<<" vel:"<<mGrid ); - Grid<Vec3>* vel = mpPlParams->getGridVec3(mGrid); - Grid<Vec3>* vort = mpPlParams->getGridVec3(mVort); - fsComputeVort(mpPlParams->getFluidSolver()->getGridFlags(),vel,vort,mpPlParams->getDeltaX()); - return true; - }; - - protected: - std::string mGrid, mVort; -}; - -//***************************************************************************** -// Apply velocity kernel of the vortex particles to velocity grid -class spluginApplyVParts : public SolverPlugin { - public: - spluginApplyVParts() : SolverPlugin(), - mGrid("vel-curr"), mVort("unnamed"),mTemp("vec-temp") { - }; - ~spluginApplyVParts() { }; - - virtual bool parseParams(const ParamSet& params) { - mGrid = params.FindOneString("velocity", mGrid ); - mVort = params.FindOneString("vorticity", mVort ); // current measured vorticity - mTemp = params.FindOneString("temp", mTemp ); // temporary grid for storing reference vorticity field - mSolver = params.FindOneString("from-solver", ""); // use vortex particles hosted on a different solver - mDoForces = params.FindOneInt("doforces", 1) != 0; // activate repulsion forces - return true; - }; - virtual bool initPlugin() {return true;}; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spluginApplyVParts"," dt="<<dt<<" vel:"<<mGrid ); - FlagGrid* flags = mpPlParams->getGridInt("flags"); - Grid<Vec3>* vel = mpPlParams->getGridVec3(mGrid); - Grid<Vec3>* vort = mpPlParams->getGridVec3(mVort); - Grid<Vec3>* temp = mpPlParams->getGridVec3(mTemp); - Grid<Vec3>* velhelp = NULL; - if (mpPlParams->haveGridVec3("vel-helper")) mpPlParams->getGridVec3("vel-helper"); // helper grid shows only induced velocity - FluidSolver* solver = mSolver.empty() ? mpPlParams->getFluidSolver() : ddfWorldFindSolver(mSolver); - Real multiplier = mpPlParams->getMultiplier(); - if (multiplier <0) multiplier = 1.; // multiplier due to grid rescaling - temp->clearGrid(); - - solver->getVorticitySys()->applyForces(vel,vort,temp, flags,multiplier,mDoForces, velhelp); - - return true; - }; - - protected: - std::string mGrid, mVort,mTemp,mSolver; - bool mDoForces; -}; - -//***************************************************************************** -// Merge, split, dissipate particles -class spluginMergeVParts : public SolverPlugin { - public: - spluginMergeVParts() : SolverPlugin() {}; - ~spluginMergeVParts() { }; - - virtual bool parseParams(const ParamSet& params) { - mDist = params.FindOneString("ndist", "unnamed" ); // Distance field to the obstacles - mInitTime = params.FindOneFloat("init-time", 50.); // Factor to the lifespan in model-dependant range - mDecayTime = params.FindOneFloat("decay-time", 250. ); // Factor to the time between particle splitting - mMergeDist = params.FindOneFloat("merge-dist", 1.); ; // Factor to the merge radius - mDissipateRadius = params.FindOneFloat("dissipate-radius", 1. ); // Radius below which particles are deleted - mRadiusCascade = params.FindOneFloat("radius-cascade", 2.); // On split, particle decay into 2 particles of with radius old_radius/radius_cascade - // a low value leads to frequent splitting - return true; - }; - virtual bool initPlugin() { - debMsg("spluginMergeVParts","init"); - return true; - }; - - // perform step with given dt, return failure - virtual bool performStep(Real dt) { - debMsg("spluginMergeVParts"," dt="<<dt ); - FlagGrid* flags = mpPlParams->getGridInt("flags"); - Grid<Vec3>* vel = mpPlParams->getGridVec3("vel-curr"); - VortexParticle::msDecayTime = mDecayTime; - VortexParticle::msInitialTime = mInitTime; - VortexParticle::msRadiusCascade = mRadiusCascade; - VortexParticle::msDissipateRadius = mDissipateRadius; - mpPlParams->getFluidSolver()->getVorticitySys()->merge(flags, mpPlParams->getGridReal(mDist), vel, dt,mMergeDist); - - return true; - }; - - protected: - std::string mDist; - Real mInitTime,mDecayTime,mMergeDist,mRadiusCascade,mDissipateRadius; -}; - -//***************************************************************************** -// initialize a grid from a grid of another solver (possibly with different resolution) -class spluginInterpolateGridFrom : public SolverPlugin { - public: - spluginInterpolateGridFrom() : SolverPlugin(), - mName("-unnamed1-"), mGridSrc("-unnamed2-"), mGridDst("-unnamed3-"), - mDoFlagsTreatment(0), mCorrectScale(1), mCorrectAdd(0) { - }; - ~spluginInterpolateGridFrom() { }; - - virtual bool parseParams(const ParamSet& params) { - mName = params.FindOneString("name", mName ); // solver name - mGridSrc = params.FindOneString("src", mGridSrc ); // source grid - mGridDst = params.FindOneString("dst", mGridDst ); // dest. grid - mDoFlagsTreatment = params.FindOneInt("do-flags", mDoFlagsTreatment ); // adjust flags ? - mCorrectScale = params.FindOneFloat("correctScale", mCorrectScale); - mCorrectAdd = params.FindOneFloat("correctAdd", mCorrectAdd); - return true; - }; - virtual bool initPlugin() { return true; }; - - virtual bool performStep(Real org_dt); - bool performStepFlags(FluidSolver* src, FluidSolver* dst); - protected: - // name of solver to init from - std::string mName; - // name of src/dst grid - std::string mGridSrc,mGridDst; - - int mDoFlagsTreatment; - - void initSizeScale(GridBase* src, GridBase* dst); - nVec3i m_srcSize; - nVec3i m_dstSize; - Vec3 m_sizeScale; - - float mCorrectScale; - float mCorrectAdd; -}; - -// Helper function to adjust scale size -void spluginInterpolateGridFrom::initSizeScale(GridBase* src, GridBase* dst) { - m_srcSize = src->getSize(); - m_dstSize = dst->getSize(); - m_sizeScale = Vec3( - (Real)m_srcSize[0] / (Real)m_dstSize[0], - (Real)m_srcSize[1] / (Real)m_dstSize[1], - (Real)m_srcSize[2] / (Real)m_dstSize[2] ); - debMsg("spluginInterpolateGridFrom ","scale size = "<<m_sizeScale<<", src="<<m_srcSize<<" to dst="<<m_dstSize); -} - -// NYI, TODO, loop over range, use priority of flags: obstacle>fluid>empty -bool spluginInterpolateGridFrom::performStepFlags(FluidSolver* srcSolver, FluidSolver* dstSolver) -{ - // similar to real grid treatment - if( ( srcSolver->getParams()->haveGridInt(mGridSrc)) && - ( mpPlParams->haveGridInt(mGridDst) ) ) { - FlagGrid* src = srcSolver->getParams()->getGridInt(mGridSrc); - FlagGrid* dst = mpPlParams->getGridInt(mGridDst); - - initSizeScale(src,dst); - - FOR_IJK_GRID_BND(dst,1) { - // linearly interpolate values - Vec3 p = Vec3(i,j,k) * m_sizeScale; - - // for safety reasons, don't overwrite obstacle flags - if( fgIsObstacle(dst->getGlobal(i,j,k)) ) - continue; - // downsizing, no interpol - dst->getGlobal(i,j,k) = src->getGlobal( (int)p[0], (int)p[1], (int)p[2]); - } - - } else { - errFatal("spluginInterpolateGridFrom","Do-flags Grids not found! "<<mGridSrc<<" "<<mGridDst, SIMWORLD_PLUGINERROR); - return false; - } - return true; -} - -// interpolate grid values from another grid of another solver -bool spluginInterpolateGridFrom::performStep(Real org_dt) { - - //Real dt = org_dt * mpPlParams->getDeltaX(); - debMsg("spluginInterpolateGridFrom","name:"<<mName<<"; from="<<mName<<" "<<mGridSrc<<"->"<<mGridDst ); - - FluidSolver* srcSolver = ddfWorldFindSolver(mName); - FluidSolver* dstSolver = mpPlParams->getFluidSolver(); - if(!srcSolver) { - errMsg("spluginInterpolateGridFrom","Source solver '"<<mName<<"' not found!"); - return false; - } - - bool doneSth = false; - - if(mDoFlagsTreatment) { - return performStepFlags(srcSolver, dstSolver); - } - - if( ( srcSolver->getParams()->haveGridVec3(mGridSrc)) && - ( mpPlParams->haveGridVec3(mGridDst) ) ) { - - Grid<Vec3>* src = srcSolver->getParams()->getGridVec3(mGridSrc); - Grid<Vec3>* dst = mpPlParams->getGridVec3(mGridDst); - - //const nVec3i grs = mpPlParams->getFluidSolver()->get GridInitDim(); - const nVec3i grs = src->getSize(); - - int ks = 1; - int ke = grs[2]-1; - if(gDim==2) { - ks = mpPlParams->getFluidSolver()->get2dKstart(); - ke = ks+1; - } - - nVec3i srcSize = src->getSize(); - nVec3i dstSize = dst->getSize(); - Vec3 sizeScale = Vec3( - (Real)srcSize[0] / (Real)dstSize[0], - (Real)srcSize[1] / (Real)dstSize[1], - (Real)srcSize[2] / (Real)dstSize[2] ); - debMsg("scale ","size = "<<sizeScale); - - const Real dtFac = 1./1.; - - FOR_IJK_GRID(dst) { - // linearly interpolate values - Real pi = (Real)(i)*sizeScale[0]; - Real pj = (Real)(j)*sizeScale[1]; - Real pk = (Real)(k)*sizeScale[2]; - dst->getGlobal(i,j,k) = src->getInterpolated(pi, pj, pk) * dtFac * mCorrectScale; // */ - } - doneSth = true; - } // VEC3 - - if( ( srcSolver->getParams()->haveGridReal(mGridSrc)) && - ( mpPlParams->haveGridReal(mGridDst) ) ) { - Grid<Real>* src = srcSolver->getParams()->getGridReal(mGridSrc); - Grid<Real>* dst = mpPlParams->getGridReal(mGridDst); - - nVec3i srcSize = src->getSize(); - nVec3i dstSize = dst->getSize(); - Vec3 sizeScale = Vec3( - (Real)srcSize[0] / (Real)dstSize[0], - (Real)srcSize[1] / (Real)dstSize[1], - (Real)srcSize[2] / (Real)dstSize[2] ); - debMsg("scale ","size = "<<sizeScale); - - FOR_IJK_GRID(dst) { - // linearly interpolate values - Real pi = (Real)(i)*sizeScale[0]; - Real pj = (Real)(j)*sizeScale[1]; - Real pk = (Real)(k)*sizeScale[2]; - dst->getGlobal(i,j,k) = src->getInterpolated(pi, pj, pk) * mCorrectScale + mCorrectAdd; - } - - doneSth = true; - } // REAL - - if(!doneSth) { - errFatal("spluginInterpolateGridFrom","Grids not found! "<<mGridSrc<<" "<<mGridDst, SIMWORLD_PLUGINERROR); - return false; - } - - return true; -}; - - -//***************************************************************************** -// GridOp: update artificial boundary layer -class fsUpdatePdf : public GridOpBase { - public: - fsUpdatePdf(FlagGrid *flags, Grid<Vec3> *ref, Grid<Vec3> *flow, Real scaleFlow, Grid<Vec3> *rans, bool israndom,Real premult) : - GridOpBase(), mScaleFlow(scaleFlow), mVortPreMult(premult), mpRef(ref), mpFlow(flow),mpRans(rans),mIsRandom(israndom) { - mpFlags = flags; - applyOperatorToGrids(this); - }; - ~fsUpdatePdf() { }; - void resetVariables() { }; - void buildCallList() { - gaRef.gridAccInit(mpRef, AM_READ, gaCalls); - gaFlow.gridAccInit(mpFlow, AM_READWRITE, gaCalls); - if (mpRans != NULL) gaRans.gridAccInit(mpRans, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) - { - if(!fgIsFluid(getFlagAcc()(i,j,k))) - return; - - if (mIsRandom) // hard-coded test-case - gaFlow.write(i,j,k) = normNoSqrt(gaRef(i,j,k))==0 ? Vec3(0,0,0) : Vec3(1e3,1e3,1e3); - else - { - Vec3 ref = gaRef(i,j,k); - Real ref2 = normNoSqrt(ref); - if (ref2 > 1e-10) // only set if src is not empty - { - // use source from rans solver, ref contains surface normal - if (mpRans != NULL) - { - ref = cross(ref, gaRans(i,j,k)); - ref2 = normNoSqrt(ref); - } - ref *= mVortPreMult; - ref2 *= mVortPreMult*mVortPreMult; - Real flow = dot(gaFlow(i,j,k),ref), flow2 = flow*flow; - - // min bounding on reference grid - if (flow2 < ref2 || flow<0) - gaFlow.write(i,j,k) = ref; - } - gaFlow.write(i,j,k) *= mScaleFlow; - } - } - void reduce(fsUpdatePdf &op) { }; - - protected: - Real mScaleFlow,mVortPreMult; - Grid<Vec3> *mpRef, *mpFlow, *mpRans; - GridAccessor<Vec3,0> gaRef, gaFlow, gaRans; - bool mIsRandom; -}; - -//***************************************************************************** -// GridOp : Evaluate pdf, generate vortex particles -class fsGenVPart : public GridOpBase { - public: - fsGenVPart(FlagGrid *flags, Grid<Real> *pdf, Grid<Vec3> *flow, Grid<Real> *dist, Real thresVort, VorticitySystem* vsys, Real minRad, Real maxRad, Real mdst, Real threspdf, Real multpdf, Real u02, RandomStream& rnd, - bool israndom, Real randPdf, Real maxbl) : - GridOpBase(), randStream(rnd), mThresVort(thresVort), mThresPdf(threspdf), mMultPdf(multpdf), mMaxRad(maxRad), mMinRad(minRad), mU02(u02), mMinDist(mdst), mMaxBL(maxbl), mpVSys(vsys),mpPdf(pdf), mpDist(dist),mpFlow(flow), - mRandom(israndom), mRandomPdf(randPdf) { - mpFlags = flags; - applyOperatorToGridsSimple(this); - }; - ~fsGenVPart() { }; - void resetVariables() { }; - void buildCallList() { - gaFlow.gridAccInit(mpFlow, AM_READWRITE, gaCalls); - gaPdf.gridAccInit(mpPdf, AM_WRITE, gaCalls); - gaDist.gridAccInit(mpDist, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) - { - if (!fgIsFluid(getFlagAcc()(i,j,k))) return; - - // obtain squared vorticity - Vec3 vvort = gaFlow(i,j,k); - Real vort2 = normNoSqrt(vvort), dist = gaDist(i,j,k); - if (dist <= 0 || vort2 < mThresVort*mThresVort) - { - gaPdf.write(i,j,k) = 0; - return; - } - // obtain reynolds stress field, pdf - Real vort=sqrt(vort2); - Real reyf = vort2 * dist*dist* mU02; - Real pdf = 2. * (fabs(reyf) - mThresPdf) * mMultPdf; - - if (dist < 0 || dist > mMaxBL) pdf=0; // outside allowed range - if (mRandom) pdf = mRandomPdf; // bypass pdf - gaPdf.write(i,j,k) = pdf; - if (pdf<0) pdf=0; - - // random test - Real rnd = randStream.getReal(); - if (rnd >= pdf) return; - - // create particle ! - - // suggested radius - Real radius = randStream.getReal()*(mMaxRad-mMinRad) + mMinRad, radius2=radius*radius; - - // bound kernel radius to wall - int ceilRad = (int)ceil(radius); - FOR_KERNEL(ceilRad) - { - Real cr2=x*x+y*y+z*z; - if (!mRandom && cr2<radius2 && (!mpFlags->checkIndexValid(x+i,y+j,z+k) || fgIsObstacle(mpFlags->getGlobal(x+i,y+j,z+k)) || fgIsInflow(mpFlags->getGlobal(x+i,y+j,z+k)))) - radius2 = cr2; - } - Real sugRad = radius; - radius = sqrt(radius2); - - // reduce radius if particle is too big and weak - Real strength=0; - Vec3 ndir = vvort * (1./vort); - for (;;) // loop to obtain next-best radius - { - if (radius < mMinDist) return; - - // sum vorticity within particle radius - Real wsum = 0, rsum=0; - radius2=radius*radius; - ceilRad = (int)ceil(radius); - FOR_KERNEL(ceilRad) - { - int cr2 = x*x+y*y+z*z; - if (cr2 <= radius2) - { - Real w = dot(gaFlow(i+x,j+y,z+k),ndir); - if (w < 1e-8) continue; - wsum += w; - } - } -#if DDF_DIMENSION == 3 - Real mint = VortexParticleGaussian::getAreaMultiplier()*radius*radius2; // gauss inner kernel integral -#else - Real mint = M_PI*radius2; -#endif - strength = wsum/mint; - - // test if particle is too big for its strength - if (strength > vort || mRandom) - break; - else - radius-= 1.0; - } - - // remove vorticity from ABL - FOR_KERNEL(ceilRad) - { - int cr2 = x*x+y*y+z*z; - if (cr2 <= radius2) - { - Real w = dot(gaFlow(i+x,j+y,z+k),ndir); - if (w < 1e-8) continue; - gaFlow.write(i+x,j+y,z+k) -= ndir*w; - } - } - - // seed particle - Vec3 str = ndir * (strength); - if (mRandom) - { - // hard coded values for test case - const Real vmin=0.01,vmax=0.40; - Real nstr = randStream.getReal()* (vmax-vmin)+vmin; - str = Vec3(randStream.getReal(),randStream.getReal(),randStream.getReal())*2.-1.; - str *= nstr/norm(str); - } - mpVSys->getParticles().push_back(new VortexParticleGaussian(Vec3(i,j,k), str, radius)); - } - void reduce(fsGenVPart &op) { }; - - protected: - RandomStream& randStream; - - Real mThresVort,mThresPdf,mMultPdf; - Real mMaxRad, mMinRad, mU02, mMinDist, mMaxBL; - VorticitySystem* mpVSys; - Grid<Real> *mpPdf, *mpDist; - Grid<Vec3> *mpFlow; - GridAccessor<Real,0> gaPdf, gaDist; - GridAccessor<Vec3,0> gaFlow; - bool mRandom; - Real mRandomPdf; -}; - -//***************************************************************************** -// maintain artificial boundary layer, generate vortex particles -class spluginGenVPart : public SolverPlugin { - public: - spluginGenVPart() : SolverPlugin(), mRandomStream(13322223) {}; - ~spluginGenVPart() { }; - - virtual bool parseParams(const ParamSet& params) { - mGridRef = params.FindOneString("source", "" ); // precomputed ABL source field or surface normal, when using RANS - mGridFlow = params.FindOneString("flow", "" ); // ABL grid - mRans = params.FindOneString("rans", "" ); // RANS solver name, if used - mGridDist = params.FindOneString("dist", "" ); // distance field - mGridPdf = params.FindOneString("pdf", "" ); // pdf output grid - mMultPdf = params.FindOneFloat("mult-pdf", 0 ); // c_P constant in the paper - mThresPdf = params.FindOneFloat("thres-pdf", 0 ); // threshold for pdf below which no seeding will occur - mMaxBL = params.FindOneFloat("max-bl", 0.1 ); // maximal distance to object in which boundary layer is evaluated - mThresVort = params.FindOneFloat("thres-vort", 0 ); // threshold for confined vorticity below which no seeding will occur - mScaleFlow = params.FindOneFloat("scale-flow", 0.99 ); // fade-out for ABL plume - mMinRad = params.FindOneFloat("min-rad", 0 ); // minimum radius for vortex particles - mMinDist = params.FindOneFloat("min-dist", mMinRad ); // minimal distance to wall - mMaxRad = params.FindOneFloat("max-rad", 0 ); // maximum radius for vortex particles - mIsRandom = params.FindOneInt("random", 0 ) != 0; // bypass pdf, use random particles - mRandPdf = params.FindOneFloat("random-pdf", 1.5e-4 ); // probability for random pdf - mVortPreMult = params.FindOneFloat("vortex-gain", 1. ); // vortex gain, beta constant in the paper - mFadein = params.FindOneFloat("fade-in", -1 ); // vortex particle fade-in constant - - if(mIsRandom) debMsg("spluginGenVPart","Randomzied vparts on! Pdf="<<mRandPdf); - - return true; - }; - virtual bool initPlugin() { - if (mFadein >= 0) { - VorticitySystem* vsys = mpPlParams->getFluidSolver()->getVorticitySys(); - vsys->setFadeIn(mFadein); - } - return true; - }; - - bool performStep(Real org_dt) - { - FlagGrid *flags = mpPlParams->getGridInt("flags"); - Grid<Vec3>* ref = mpPlParams->getGridVec3(mGridRef); - Grid<Real>* pdf = mpPlParams->getGridReal(mGridPdf); - Grid<Real>* dist = mpPlParams->getGridReal(mGridDist); - Grid<Vec3>* flow = mpPlParams->getGridVec3(mGridFlow); - - Grid<Vec3>* rans = mRans.empty() ? NULL : ddfWorldFindSolver(mRans)->getParams()->getGridVec3("vel-curr"); - VorticitySystem* vsys = mpPlParams->getFluidSolver()->getVorticitySys(); - Real u0 = norm(mpPlParams->mU0); - if (u0==0) { errMsg("spluginGenVPart","u0 not set !"); exit(1); } - - fsUpdatePdf(flags,ref,flow,mScaleFlow,rans,mIsRandom,mVortPreMult); - fsGenVPart (flags,pdf,flow,dist,mThresVort * u0, vsys, mMinRad, mMaxRad, mMinDist, mThresPdf,mMultPdf,1./(u0*u0), - mRandomStream, mIsRandom, mRandPdf, mMaxBL ); - - return true; - } - protected: - // name of src/dst grid - RandomStream mRandomStream; - std::string mGridRef,mGridFlow,mGridPdf,mGridDist,mRans; - Real mThresPdf, mMultPdf, mScaleFlow, mThresVort,mMinDist; - Real mMinRad, mMaxRad, mVortPreMult, mFadein, mMaxBL; - bool mIsRandom; //,test - Real mRandPdf; -}; - -//***************************************************************************** -// GridOp : calculate boundary layer -class fsCalcABL : public GridOpBaseFlagbord<1> { - public: - fsCalcABL(FlagGrid *flags, Grid<Real> *ndist, Grid<Vec3> *norm, Grid<Vec3> *abl, Grid<Vec3> *vel, Real lABL) : - GridOpBaseFlagbord<1>(), mpDist(ndist), mpNorm(norm), mpABL(abl), mpVel(vel) { - mpFlags = flags; - mMin = (lABL - .5) / (Real)flags->getMaxSize(); - mMax = (lABL + .5) / (Real)flags->getMaxSize(); - applyOperatorToGridsSimple(this); - }; - ~fsCalcABL() { }; - void resetVariables() { }; - void buildCallList() { - gaDist.gridAccInit(mpDist, AM_READ, gaCalls); - gaVel.gridAccInit(mpVel, AM_READ, gaCalls); - gaNorm.gridAccInit(mpNorm, AM_READ, gaCalls); - gaABL.gridAccInit(mpABL, AM_WRITE, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) - { - if (!fgIsFluid(getFlagAcc()(i,j,k))) return; - // inside BL - if (gaDist(i,j,k) > mMin && gaDist(i,j,k) < mMax) - { - // get centered vel - Vec3 v = gaVel(i,j,k); - if (mpFlags->checkIndexValid(i+1,j,k) && fgIsFluid(getFlagAcc()(i+1,j,k))) v.x = 0.5*(v.x + gaVel(i+1,j,k).x); - if (mpFlags->checkIndexValid(i,j+1,k) && fgIsFluid(getFlagAcc()(i,j+1,k))) v.y = 0.5*(v.y + gaVel(i,j+1,k).y); - if (mpFlags->checkIndexValid(i,j,k+1) && fgIsFluid(getFlagAcc()(i,j,k+1))) v.z = 0.5*(v.z + gaVel(i,j,k+1).z); - - // compute ABL - gaABL.write(i,j,k) = -cross(v, gaNorm(i,j,k)); - } - } - void reduce(fsCalcABL &op) { }; - - protected: - Real mMin, mMax; - Grid<Real> *mpDist; - Grid<Vec3> *mpNorm, *mpABL, *mpVel; - GridAccessor<Real,0> gaDist; - GridAccessor<Vec3,0> gaABL,gaNorm; - GridAccessor<Vec3,1> gaVel; -}; - -//***************************************************************************** -// Plugin to calculate boundary layer -class spluginCalcABL : public SolverPlugin { - public: - spluginCalcABL() : SolverPlugin() {}; - ~spluginCalcABL() { }; - - virtual bool parseParams(const ParamSet& params) { - mGridDist = params.FindOneString("dist", "" ); // distance field - mGridNorm = params.FindOneString("normal", "" ); // surface normals - mGridABL = params.FindOneString("abl", "" ); // ABL - mGridVel = params.FindOneString("mean-vel", "" ); // averaged velocity grid - mD = params.FindOneFloat("d", 1.5 ); // boundary layer thickness - return true; - }; - virtual bool initPlugin() {return true; }; - - bool performStep(Real org_dt) - { - FlagGrid *flags = mpPlParams->getGridInt("flags"); - Grid<Vec3>* vel = mpPlParams->getGridVec3(mGridVel); - Grid<Real>* dist = mpPlParams->getGridReal(mGridDist); - Grid<Vec3>* norm = mpPlParams->getGridVec3(mGridNorm); - Grid<Vec3>* abl = mpPlParams->getGridVec3(mGridABL); - - fsCalcABL (flags,dist,norm,abl,vel,mD); - - return true; - } - protected: - // name of src/dst grid - std::string mGridDist, mGridNorm, mGridVel, mGridABL; - Real mD; -}; - -//***************************************************************************** -// GridOp : write database -class fsWriteDatabase : public GridOpBase { - public: - fsWriteDatabase(FlagGrid *flags, Grid<Vec3> *norm, Grid<Vec3> *abl, vector<Vec3>& pos, vector<Vec3>& n, vector<Vec3>& val) : - GridOpBase(), mpABL(abl), mpNorm(norm), mPos(pos), mNormal(n), mValue(val) { - mpFlags = flags; - applyOperatorToGridsSimple(this); - }; - ~fsWriteDatabase() { }; - void resetVariables() { }; - void buildCallList() { - gaNormal.gridAccInit(mpNorm, AM_READ, gaCalls); - gaABL.gridAccInit(mpABL, AM_READ, gaCalls); - setFlags(mpFlags); - }; - - inline void operator() (int i, int j, int k) - { - if (!fgIsFluid(getFlagAcc()(i,j,k))) return; - Vec3 v = gaABL(i,j,k); - if (v.x == 0 && v.y == 0 && v.z == 0) return; - - // store point in pointset - mPos.push_back(Vec3(i,j,k)); - mNormal.push_back(gaNormal(i,j,k)); - mValue.push_back(v); - } - void reduce(fsWriteDatabase &op) { }; - - protected: - Grid<Vec3> *mpABL, *mpNorm; - GridAccessor<Vec3,0> gaABL,gaNormal; - vector<Vec3>& mPos; - vector<Vec3>& mNormal; - vector<Vec3>& mValue; -}; - - -//***************************************************************************** -// Plugin to write database -class spluginWriteDatabase : public SolverPlugin { - public: - spluginWriteDatabase() : SolverPlugin() {}; - ~spluginWriteDatabase() { }; - - virtual bool parseParams(const ParamSet& params) { - mGrid = params.FindOneString("grid", "" ); // ABL Grid - mNormal = params.FindOneString("normal", "" ); // Surface normals - mU0 = params.FindOneVector("u0", Vec3(0.) ); // inflow/rotation axis - return true; - }; - virtual bool initPlugin() {return true; }; - - bool performStep(Real org_dt) - { - FlagGrid *flags = mpPlParams->getGridInt("flags"); - Grid<Vec3>* abl = mpPlParams->getGridVec3(mGrid); - Grid<Vec3>* norm = mpPlParams->getGridVec3(mNormal); - - // obtain sparse list - vector<Vec3> pos, normal, val; - fsWriteDatabase(flags, norm, abl, pos, normal, val); - - if (msNeedHeader) { - // separate header for translation and rotation. Here only identical resolutions are supported. - float grid_divisor = 1; - Vec3 size = vec2R(flags->getSize()); - Vec3 scaling (1.,1.,1.), offset(0,0,0); // in this version these parameters are ignored - int numPoints = pos.size(); - for (int t=0;t<2;t++) { - gzwrite(msGzf, &numPoints, sizeof(int)); - gzwrite(msGzf, &grid_divisor, sizeof(float)); - gzwrite(msGzf, &(size[0]), sizeof(Vec3)); - gzwrite(msGzf, &(scaling[0]), sizeof(Vec3)); - gzwrite(msGzf, &(offset[0]), sizeof(Vec3)); - for (int i=0; i<numPoints; i++) gzwrite(msGzf, &(pos[i][0]), sizeof(Vec3)); - for (int i=0; i<numPoints; i++) gzwrite(msGzf, &(normal[i][0]), sizeof(Vec3)); - for (int i=0; i<(int)msIndexMat.size(); i++) { int idx=msIndexMat[i]+t; gzwrite(msGzf, &(idx), sizeof(int)); } - } - msNeedHeader=false; - } - // write ABL data - gzwrite(msGzf, &(mU0[0]), sizeof(Vec3)); - for (int i=0; i<(int)val.size(); i++) gzwrite(msGzf, &(val[i][0]), sizeof(Vec3)); - - return true; - } - - // open file, write main header - static vector<Vec3> open(const string& name, int nTheta, int nPhi) { - // open database file - msGzf = gzopen((name+".gz").c_str(), "wb9" ); - if (!msGzf) - errFatal("spluginDatabaseWriter", "can't open database file", SIMWORLD_INITERROR); - - // write header - int elements = 2*nTheta*nPhi; - gzwrite(msGzf, &elements,sizeof(int)); - gzwrite(msGzf, &nTheta,sizeof(int)); - gzwrite(msGzf, &nPhi,sizeof(int)); - - // generate angle vectors - float *theta = new float[nTheta]; - for (int i=0;i<nTheta;++i) theta[i] = M_PI * (float)i/(float)(nTheta-1); - gzwrite(msGzf, theta, sizeof(float)*nTheta); - float *phi = new float[nPhi]; - for (int i=0;i<nPhi;++i) phi[i] = 2.*M_PI * (float)i/(float)nPhi; - gzwrite(msGzf, phi, sizeof(float)*nPhi); - - // generate index matrices+axes - vector<Vec3> axes; - msIndexMat.resize(nTheta*nPhi); - for (int i=0, idx=0;i<nTheta;i++) - for (int j=0;j<nPhi;j++) { - axes.push_back( Vec3( sin(theta[i])*cos(phi[j]), cos(theta[i]), sin(theta[i])*sin(phi[j])) ); - msIndexMat[nPhi*i+j] = idx; - idx+=2; - } - - delete[] phi; - delete[] theta; - msNeedHeader = true; - msIndex = 0; - return axes; - } - static void close() { - msNeedHeader = false; - gzclose(msGzf); - } - protected: - std::string mGrid, mNormal; - static gzFile msGzf; - static bool msNeedHeader; - static std::vector<int> msIndexMat; - static int msIndex; - Vec3 mU0; -}; -gzFile spluginWriteDatabase::msGzf = NULL; -bool spluginWriteDatabase::msNeedHeader = false; -vector<int> spluginWriteDatabase::msIndexMat; -int spluginWriteDatabase::msIndex = 0; - -// static callers -vector<Vec3> initDatabaseWriter(const string& file, int nTheta, int nPhi) { - return spluginWriteDatabase::open(file, nTheta, nPhi); -} -void closeDatabaseWriter() { - spluginWriteDatabase::close(); -} - - -//***************************************************************************** - -SolverPlugin* MakeVortexPlugin(std::string name) -{ - if(name.compare( string("advect-vpart") )==0) - return new spluginAdvectVPart; - if(name.compare( string("apply-vpart") )==0) - return new spluginApplyVParts; - if(name.compare( string("merge-vpart") )==0) - return new spluginMergeVParts; - if(name.compare( string("compute-vorticity") )==0) - return new spluginComputeVorticity; - if(name.compare( string("interpolate-grid-from") )==0) - return new spluginInterpolateGridFrom; - if(name.compare( string("gen-vpart") )==0) - return new spluginGenVPart; - if(name.compare( string("calc-abl") )==0) - return new spluginCalcABL; - if(name.compare( string("add-database") )==0) - return new spluginWriteDatabase; - return NULL; -} - -}; // DDF - diff --git a/intern/smoke/intern/util/boundbox.h b/intern/smoke/intern/util/boundbox.h deleted file mode 100644 index 158f72fafd6..00000000000 --- a/intern/smoke/intern/util/boundbox.h +++ /dev/null @@ -1,61 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Bounding box class - * - *****************************************************************************/ - -#ifndef BOUNDBOX_H -#define BOUNDBOX_H - -#include "vectorbase.h" - - -namespace DDF { - -//! bbox for a vector -template<class VecClass> -class BboxVec { - public: - BboxVec() : mStart(0), mEnd(0) { }; - BboxVec(VecClass s, VecClass e) : - mStart(s), mEnd(e) { }; - ~BboxVec() {}; - - bool contains(VecClass p) { - for(int i=0; i<3; i++) if(p[i]<mStart[i]) return false; - for(int i=0; i<3; i++) if(p[i]>mEnd[i]) return false; -// print stats of pressure min/max - return true; - }; - - inline VecClass& getStart() { return mStart; } - inline VecClass& getEnd() { return mEnd; } - - std::string toString() { - std::ostringstream out; - out <<"bbox s:"<<mStart - <<" e:"<<mEnd <<" "; - return out.str(); - }; - - protected: - // region - VecClass mStart; - VecClass mEnd; - -}; // BboxVec - -typedef BboxVec<Vec3> BboxVecr; -typedef BboxVec<nVec3i> BboxVeci; - -} // namespace DDF - -#endif - - diff --git a/intern/smoke/intern/util/globals.cpp b/intern/smoke/intern/util/globals.cpp deleted file mode 100644 index 6c36f0c8a16..00000000000 --- a/intern/smoke/intern/util/globals.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Global functions for logging etc. - * - *****************************************************************************/ - -#include "globals.h" -#include "grid.h" - -#include <stdlib.h> -#include <limits.h> -#include <iostream> -#include <sstream> -#include "waveletnoise.h" -#ifdef WIN32 -// for timing -#include <windows.h> -#else -#include <time.h> -#include <sys/time.h> -#include <sys/times.h> -#endif - -// debugging, global id Counter -long int idCounter = 0; - -namespace DDF { - -// global debug level -// 0=all off, 1=err only, 2=err+warn, >=3=all on -int gDebugLevel = 10; - -// globals for grids.h -int gPatchIdCounter = 0; -int gGridIdCounter = 0; -class PatchManager; -PatchManager *gpPatchManager = NULL; - -// globals for operators.h, misc. debugging profiling -int gGridPassCounter = 0; -double gPatchCount[10] = {0,0,0,0,0, 0,0,0,0,0}; -double gSerialPatchCnt = 0.; -unsigned int gCountApplyOp = 0; -unsigned int gCountApplyOpNoFlag = 0; -unsigned int gCountApplyOpSimple = 0; -unsigned int gCountPatchLocks[10] = {0,0,0,0,0, 0,0,0,0,0}; - -// globals for vectorbase.h -const Real gVecEpsilon = VECTOR_EPSILON; -// instantiate zero vectors -template<> const ntlVector3Dim<float > ntlVector3Dim<float >::ZERO( 0.f, 0.f, 0.f ); -template<> const ntlVector3Dim<double> ntlVector3Dim<double>::ZERO( 0., 0., 0. ); -template<> const ntlVector3Dim<int > ntlVector3Dim<int >::ZERO( 0, 0, 0 ); - -// globals for waveletnoise.h -float* stdTileData = NULL; - -//! for interval debugging output -myTime_t globalIntervalTime = 0; -//! color output setting for messages (0==off, else on) -#ifdef WIN32 -// switch off first call (=-1) -#define DEF_globalColorSetting -1 -#else // WIN32 -// linux etc., on by default (=1) -#define DEF_globalColorSetting -1 -#endif // WIN32 -int globalColorSetting = DEF_globalColorSetting; // linux etc., on by default -int globalFirstEnvCheck = 0; -void resetGlobalColorSetting() { globalColorSetting = DEF_globalColorSetting; } - -// global string for formatting vector output, TODO test!? -#if DDF_DIMENSION==3 -//const char *globVecFormatStr = "[%4.2f,%4.2f,%4.2f]"; -const char *globVecFormatStr = "[%6.4f,%6.4f,%6.4f]"; -#else // DDF_DIMENSION==3 -const char *globVecFormatStr = "[%4.2f,%4.2f]"; -#endif - -// global state & error -int gSimState = 0; -char gSimErrorString[256]; - -void setSimState(int set) { gSimState = set; } -int getSimState(void) { return gSimState; } -int isSimworldOk(void) { return gSimState>=0; } - -void setSimErrorString(char* set) { strncpy(gSimErrorString,set,256); } -char* getSimErrorString(void) { return gSimErrorString; } - -// get string of global settings -string getSettingsString() { - std::ostringstream ret; - ret << - "Settings"<< - //", Bits:"<<((sizeof(int*)==8) ? string("64") : string("32") )<< - ", B:"<<sizeof(int*)<< - ", Dim:"<<DDF::gDim<< - ", Patches: OFF"<< - ", PatchSize:"<<DDF::gPatchSize<< - ", fp.Prec.:"<<FLOATINGPOINT_PRECISION<< - ", Omp:"<<DDF_OPENMP<< - " " - ; -#if DDF_OPENMP==1 - //omp_set_num_threads(2); // test -#pragma omp parallel default(shared) - { // omp region - const int id = omp_get_thread_num(); - const int Nthrds = omp_get_num_threads(); - if(id==0) ret << ", #threads:"<<Nthrds; - } -#endif // DDF_OPENMP==1 - return ret.str(); -} - -//----------------------------------------------------------------------------- -// helper function that converts a string to integer, -// and returns an alternative value if the conversion fails -int convertString2Int(const char *str, int alt) -{ - int val; - char *endptr; - bool success=true; - - val = strtol(str, &endptr, 10); - if( (str==endptr) || - ((str!=endptr) && (*endptr != '\0')) ) success = false; - - if(!success) { - return alt; - } - return val; -} - -//----------------------------------------------------------------------------- -//! helper function that converts a flag field to a readable integer -string convertFlags2String(int flags) { - std::ostringstream ret; - ret <<"("; - int max = sizeof(int)*8; - for(int i=0; i<max; i++) { - if(flags & (1<<31)) ret <<"1"; - else ret<<"0"; - if(i<max-1) { - //ret << ","; - if((i%8)==7) ret << " "; - } - flags = flags << 1; - } - ret <<")"; - return ret.str(); -} - -//----------------------------------------------------------------------------- -// helper function to determine current time -myTime_t getTime() -{ - myTime_t ret = 0; -#ifdef WIN32 - LARGE_INTEGER liTimerFrequency; - QueryPerformanceFrequency(&liTimerFrequency); - LARGE_INTEGER liLastTime; - QueryPerformanceCounter(&liLastTime); - ret = (INT)( ((double)liLastTime.QuadPart / liTimerFrequency.QuadPart)*1000 ); // - mFirstTime; -#else - struct timeval tv; - struct timezone tz; - tz.tz_minuteswest = 0; - tz.tz_dsttime = 0; - gettimeofday(&tv,&tz); - ret = (tv.tv_sec*1000)+(tv.tv_usec/1000); //-mFirstTime; -#endif - return (myTime_t)ret; -} - -//----------------------------------------------------------------------------- -// convert time to readable string -string getTimeString(myTime_t usecs) { - std::ostringstream ret; - //myTime_t us = usecs % 1000; - myTime_t ms = (myTime_t)( (double)usecs / (60.0*1000.0) ); - myTime_t ss = (myTime_t)( ((double)usecs / 1000.0) - ((double)ms*60.0) ); - int ps = (int)( ((double)usecs - (double)ss*1000.0)/10.0 ); - - //ret.setf(ios::showpoint|ios::fixed); - //ret.precision(5); ret.width(7); - - if(ms>0) { - ret << ms<<"m"<< ss<<"s" ; - } else { - if(ps>0) { - ret << ss<<"."; - if(ps<10) { ret <<"0"; } - ret <<ps<<"s" ; - } else { - ret << ss<<"s" ; - } - } - return ret.str(); -} - -//! helper to check if a bounding box was specified in the right way -bool checkBoundingBox(Vec3 s, Vec3 e, string checker) { - if( (s[0]>e[0]) || - (s[1]>e[1]) || - (s[2]>e[2]) ) { - errFatal("checkBoundingBox","Check by '"<<checker<<"' for BB "<<s<<":"<<e<<" failed! Aborting...",SIMWORLD_INITERROR); - return 1; - } - return 0; -} - - - -//----------------------------------------------------------------------------- -// debug message output - -static string col_black ( "\033[0;30m"); -static string col_dark_gray ( "\033[1;30m"); -static string col_bright_gray ( "\033[0;37m"); -static string col_red ( "\033[0;31m"); -static string col_bright_red ( "\033[1;31m"); -static string col_green ( "\033[0;32m"); -static string col_bright_green ( "\033[1;32m"); -static string col_bright_yellow ( "\033[1;33m"); -static string col_yellow ( "\033[0;33m"); -static string col_cyan ( "\033[0;36m"); -static string col_bright_cyan ( "\033[1;36m"); -static string col_purple ( "\033[0;35m"); -static string col_bright_purple ( "\033[1;35m"); -static string col_neutral ( "\033[0m"); -static string col_std = col_bright_gray; - -std::ostringstream globOutstr; -bool globOutstrForce=false; -#define DM_NONE 100 -void messageOutputForce(string from) { - bool org = globOutstrForce; - globOutstrForce = true; - messageOutputFunc(from, DM_NONE, "\n", 0); - globOutstrForce = org; -} - -void messageOutputFunc(string from, int id, string msg, myTime_t interval) { - // fast skip - if((id!=DM_FATAL)&&(gDebugLevel<=0)) return; - - if(interval>0) { - myTime_t currTime = getTime(); - if((currTime - globalIntervalTime)>interval) { - globalIntervalTime = getTime(); - } else { - return; - } - } - - // colors off? - if( (globalColorSetting == -1) || // off for e.g. win32 - ((globalColorSetting==1) && ((id==DM_FATAL)||( getenv("DDF_NOCOLOROUT") )) ) - ) { - // only reset once - col_std = col_black = col_dark_gray = col_bright_gray = - col_red = col_bright_red = col_green = - col_bright_green = col_bright_yellow = - col_yellow = col_cyan = col_bright_cyan = - col_purple = col_bright_purple = col_neutral = ""; - globalColorSetting = 0; - } - - std::ostringstream sout; - - if(id==DM_FATAL) { - // dont print? - if(gDebugLevel==0) return; - sout << "\n\n\n"; // add newline for output - sout << " !!!!!!!!!!!!!!!!!!!!!!!! \n"; // add newline for output - sout << " !!!!!!!!!!!!!!!!!!!!!!!! \n"; // add newline for output - sout << " !!!!!!!!!!!!!!!!!!!!!!!! \n"; // add newline for output - } - - sout << col_cyan<< from; - switch(id) { - case DM_MSG: - sout << col_std << ":"; - break; - case DM_WARNING: - sout << col_bright_red << " warning:" << col_std; - break; - case DM_ERROR: - sout << col_red << " error:" << col_red; - break; - case DM_FATAL: - sout << col_red << " fatal("<<gSimState<<"):" << col_red; - break; - default: - // this shouldnt happen... - sout << col_red << " --- messageOutputFunc error: invalid id ("<<id<<") --- aborting... \n\n" << col_std; - break; - } - sout <<" "<< msg << col_std; - - if(id==DM_FATAL) { - strncpy(gSimErrorString, sout.str().c_str(), 256); - // dont print? - if(gDebugLevel==0) return; - sout << " ! \n"; // add newline for output - sout << " !!!!!!!!!!!!!!!!!!!!!!!! \n"; // add newline for output - sout << " !!!!!!!!!!!!!!!!!!!!!!!! \n"; // add newline for output - sout << " !!!!!!!!!!!!!!!!!!!!!!!! \n\n\n\n\n\n\n"; // add newline for output - sout << "\n"; // add newline for output - } - - // determine output - file==1/stdout==0 / globstr==2 - char filen[256]; - strcpy(filen,"debug_unini.txt"); - int fileout = 0; - /*std::ostringstream mpin; - if(glob_mpindex>=0) { - mpin << "ddf_log_"<< glob_mpindex <<".txt"; - } else { - mpin << "ddf_log_ini.txt"; - } - fileout = 1; - strncpy(filen, mpin.str().c_str(),255); filen[255]='\0';// */ - strncpy(filen, "ddf_debug_log.txt",255); - - //#ifdef WIN32 - // windows causes trouble with direct output - //fileout = 1; - //#endif // WIN32 - -#if WITH_OPENMP==1 - fileout = 2;// buffer out, switch off again... - if(globOutstrForce) fileout=1; -#endif - if(getenv("DDF_FORCESTDOUT")) { - fileout = 0;// always direct out - } - //fprintf(stdout,"out deb %d, %d, '%s',l%d \n",globOutstrForce,fileout, filen, globOutstr.str().size() ); - -#if WITH_OPENMP==1 -#pragma omp critical MESSAGE_DEBUG_OUT -#endif // WITH_OPENMP==1 - { - if(fileout==1) { - // debug level is >0 anyway, so write to file... - FILE *logf = fopen(filen,"a+"); - // dont complain anymore here... - if(logf) { - if(globOutstrForce) { - fprintf(logf, "%s",globOutstr.str().c_str() ); - globOutstr.str(""); // reset - } - fprintf(logf, "%s",sout.str().c_str() ); - fclose(logf); - } - } else if(fileout==2) { - globOutstr << sout.str(); - } else { - // normal stdout output - fprintf(stdout, "%s",sout.str().c_str() ); - fflush(stdout); - } - } // omp crit - - // don't segfault in gui - if(id==DM_FATAL) { - // DEBUG force segfault - *(int *)(0) = 0; - exit(999); - } -#if DDF_GLUTGUI!=1 -#endif -} - -// grids.h implementations -template<> void Grid<int>::setDummyZero() { mZero = 0; } -template<> void Grid<float>::setDummyZero() { mZero = 0.f; } -template<> void Grid<double>::setDummyZero() { mZero = 0.; } -template<> void Grid<Vec3>::setDummyZero() { mZero = Vec3(0.); } - -} // DDF - -// global list -map<string, WAVELETNOISE::WaveletNoiseField*> gNoiseFields; - - - diff --git a/intern/smoke/intern/util/globals.h b/intern/smoke/intern/util/globals.h deleted file mode 100644 index fd8b3fdd742..00000000000 --- a/intern/smoke/intern/util/globals.h +++ /dev/null @@ -1,457 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Declarations for global functions and variables - * - *****************************************************************************/ - - -#ifndef UTILITIES_H -#define UTILITIES_H - - -// "brute force" global defines -#ifndef DDF_DEBUG -#define DDF_DEBUG 0 -#endif // DDF_DEBUG - -// dimension of solver -#ifndef DDF_DIMENSION -#define DDF_DIMENSION 3 -#endif - -// openmp -#ifndef DDF_OPENMP -#define DDF_OPENMP 0 -#endif - -#ifdef WIN32 -// If windows.h is included, it defines a macro min() and max(), -// which can lead to all sorts of weird problems, e.g. conflicts -// with the STL algorithms min() and max(). By #defining NOMINMAX, -// we prevent windows.h from defining these macros. -#define NOMINMAX -#endif - -// this serves as the main include file -// for all kinds of stuff that might be required. -// under windos there seem to be strange -// errors when including the STL header too -// late... -#include <iostream> -#include <map> -#include <vector> -#include <string> -#include <sstream> -#include <math.h> -#include <string.h> -#include <stdio.h> -#if DDF_OPENMP==1 -#include "omp.h" -#endif - -// hack for MSVC6.0 compiler -#ifdef _MSC_VER -# if _MSC_VER < 1300 -# define for if(false); else for -# define map std::map -# define vector std::vector -# define string std::string - // use this define for MSVC6 stuff hereafter - //# define USE_MSVC6FIXES -# else - // _MSC_VER >= 1300 , 7.0 or higher - using std::map; - using std::vector; - using std::string; -# endif -#else // not MSVC6 - // for proper compilers... - using std::map; - using std::vector; - using std::string; -#endif // MSVC6 - -#ifdef __APPLE_CC__ - // apple -#else - -# ifdef WIN32 - // windows values missing, see below -# ifndef snprintf -# define snprintf _snprintf -# endif - // rounding function -# ifndef round - inline double round(double x) { return floor(x + 0.5); } -# endif -# ifndef false -# define false 0 -# endif -# ifndef true -# define true 1 -# endif -# else - // not WIN32 - // floating point limits for linux,*bsd etc... - #include <float.h> -# endif // WIN32 - -#endif // __APPLE_CC__ - -// standard includes -#include "vectorbase.h" - -namespace DDF { - -// dimension variable -const int gDim = DDF_DIMENSION; - -// debugging outputs , debug level 0 (off) to 10 (max) -extern int gDebugLevel; - -// get string of global settings -string getSettingsString(); - -// time measurements -typedef unsigned long myTime_t; - - -// state of the simulation world -// default state -#define SIMWORLD_OK 0 -// error during init -#define SIMWORLD_INITERROR -1 -// error during simulation -#define SIMWORLD_PANIC -2 -// general error -#define SIMWORLD_GENERICERROR -3 -// error in grid handling -#define SIMWORLD_GRIDERROR -4 -// error in grid handling -#define SIMWORLD_ERRPARSE -5 -// error with plugins -#define SIMWORLD_PLUGINERROR -6 - -// access global state of elbeem simulator -void setSimState(int set); -int getSimState(void); -int isSimworldOk(void); - -// access elbeem simulator error string -void setSimErrorString(char* set); -char* getSimErrorString(void); - -// debug messages on/off -#define USE_DEBUG_MESSAGES 1 -#if USE_DEBUG_MESSAGES==1 - -/* debug output function */ -#define DM_MSG 1 -#define DM_WARNING 2 -#define DM_ERROR 3 -#define DM_FATAL 4 -void messageOutputFunc(string from, int id, string msg, myTime_t interval); - -// debugging messages defines -//#define MSGSTREAM std::ostringstream msg; msg.precision(15); msg.width(17); -#define MSGSTREAM std::ostringstream msg; msg.precision(7); msg.width(9); - -#define errMsg(from,mStr) if(DDF::gDebugLevel>0){ MSGSTREAM; msg << mStr <<"\n"; DDF::messageOutputFunc(from, DM_ERROR, msg.str(), 0); } -#define warnMsg(from,mStr) if(DDF::gDebugLevel>1){ MSGSTREAM; msg << mStr <<"\n"; DDF::messageOutputFunc(from, DM_WARNING, msg.str(), 0); } -#define debMsg(from,mStr) if(DDF::gDebugLevel>2){ MSGSTREAM; msg << mStr <<"\n"; DDF::messageOutputFunc(from, DM_MSG, msg.str(), 0); } - -#else -// no messages at all... -# define debMsg(mStr) -# define debMsgId(from,id,mStr,level) -# define errMsg(from,mStr) -# define warnMsg(from,mStr) -#endif - - -// fatal errors - have to be handled -#define errFatal(from,mStr,errCode) { \ - DDF::setSimState(errCode); \ - MSGSTREAM; msg << mStr; \ - DDF::messageOutputFunc(from, DM_FATAL, msg.str(), 0); \ -} - - -//! helper function that converts a string to integer -int convertString2Int(const char *str, int alt); - -//! helper function that converts a flag field to a readable integer -string convertFlags2String(int flags); - -//! get the current system time -myTime_t getTime(); -//! convert time to readable string -string getTimeString(myTime_t usecs); - -//! helper to check if a bounding box was specified in the right way -bool checkBoundingBox(Vec3 s, Vec3 e, string checker); - -//! reset color output for elbeem init -void resetGlobalColorSetting(); - - -/*! print some vector from 3 values e.g. for ux,uy,uz */ -#define PRINT_VEC(x,y,z) " ["<<(x)<<","<<(y)<<","<<(z)<<"] " - -/*! print i,j,k as a vector, as we need ijk all the time */ -#define PRINT_IJK PRINT_VEC(i,j,k) - - -// write png image -int writeImage(const char *fileName, unsigned char **rowsp, int w, int h); - - -// template helper funcs - -// minimum -template < class T > -inline T -MIN( T a, T b ) -{ return (a < b) ? a : b ; } - -// maximum -template < class T > -inline T -MAX( T a, T b ) -{ return (a < b) ? b : a ; } - -// maximum of a vector -template < class T > -inline T -VMAX( ntlVector3Dim<T> a ) -{ - if(a[0]<a[1]) { - if(a[1]<a[2]) return a[2]; - else return a[1]; - } else { - if(a[0]<a[2]) return a[2]; - else return a[0]; - } -} -// minimum of a vector -template < class T > -inline T -VMIN( ntlVector3Dim<T> a ) -{ - if(a[0]>a[1]) { - if(a[1]>a[2]) return a[2]; - else return a[1]; - } else { - if(a[0]>a[2]) return a[2]; - else return a[0]; - } -} - -// swap two values -template < class T > -inline void -TRISWAP( T& a, T& b ) -{ - T tmp = a; - a = b; - b = tmp; -} - -// absolute value -template < class T > -inline T -ABS( T a ) -{ return (0 < a) ? a : -a ; } - -// sign of the value -template < class T > -inline T -SIGNUM( T a ) -{ return (0 < a) ? 1 : -1 ; } - -// sign, returns -1,0,1 depending on sign/value=0 -template < class T > -inline T -SIGNUM0( T a ) -{ return (0 < a) ? 1 : ( a < 0 ? -1 : 0 ) ; } - -// round to nearest integer -inline int -ROUND(double d) -{ return int(d + 0.5); } - -// square function -template < class T > -inline T -SQUARE( T a ) -{ return a*a; } - -// cube function -template < class T > -inline T -CUBEFUNC( T a ) -{ return a*a*a; } - - -// helper class, track min,max and avg of some scalar type T -template<class T> class MinMaxTracker { -public: - MinMaxTracker() { - mMin = 1e20; - mMax = -1e20; - mAccumulation = 0.0; - mCnt = 0; - }; - ~MinMaxTracker() {}; - - // take into account value - inline void check(T& val) { - if (mMin>val) mMin=val; - if (mMax<val) mMax=val; - mAccumulation += val; - mCnt++; - } - - // in out put - - T getMin() {return mMin;} - T getMax() {return mMax;} - T getAvg() {return mAccumulation/(double)(mCnt);} - - std::string str() { - std::ostringstream out; - out <<"min="<<mMin<<", max="<<mMax<<", avg="<<getAvg(); - return out.str(); - } - -protected: - T mMin,mMax, mAccumulation; - int mCnt; -}; // MinMaxTracker - -template<class T> -std::string helperPrintMap(std::map<std::string, T*>& pmap, std::string caller) { - std::ostringstream out; - //debMsg("print map","for '"<<caller<<"', "<<pmap.size()<<" entries "); - out << "print map for '"<<caller<<"', "<<pmap.size()<<" entries "; - int cnt=0; - for(typename std::map<std::string, T*>::iterator iter=pmap.begin(); iter != pmap.end(); iter++) { - long int pntval = (long int)( (*iter).second ); - //debMsg("entry","i "<<cnt<<"/"<<pmap.size()<<" name '"<<(*iter).first <<"' is " << pntval ); - out << "entry "<<cnt<<"/"<<pmap.size()<<" name '"<<(*iter).first <<"' is " << pntval<<", "; - cnt++; - } - return out.str(); -} // helperPrintMap - - -//***************************************************************************** -// utility defines - -#define FOR_IJK(kmin,kmax,jmin,jmax,imin,imax) \ - for (int k=(kmin); k<(kmax); k++) \ - for (int j=(jmin); j<(jmax); j++) \ - for (int i=(imin); i<(imax); i++) /* loop body */ -#define FOR_IJK_GRID(grid) \ - FOR_IJK( (grid)->getMinZLoopValue(), (grid)->getMaxZLoopValue(), 0, (grid)->getSizeY(), 0, (grid)->getSizeX() ) -#define FOR_IJK_GRID_BND(grid,bnd) \ - FOR_IJK( (grid)->getMinZLoopValue(bnd), (grid)->getMaxZLoopValue(bnd), 0+(bnd), (grid)->getSizeY()-(bnd), 0+(bnd), (grid)->getSizeX()-(bnd) ) -#define FOR_IJK_VEC(vecmin, vecmax) \ - FOR_IJK(vecmin[2],vecmax[2],vecmin[1],vecmax[1],vecmin[0],vecmax[0]) - -// reverse loops -#define FOR_IJKREV(kmin,kmax,jmin,jmax,imin,imax) \ - for (int k=(kmin); k>=(kmax); k--) \ - for (int j=(jmin); j>=(jmax); j--) \ - for (int i=(imin); i>=(imax); i--) /* loop body */ -#define FOR_IJKREV_GRID(grid) \ - FOR_IJKREV( (grid)->getMaxZLoopValue()-1,(grid)->getMinZLoopValue(), (grid)->getSizeY()-1, 0, (grid)->getSizeX()-1, 0 ) - -//***************************************************************************** -// clamping helper functions - -// clamp a in range b<= a <= c -// write to a -template < class T > -inline void -CLAMP( T &a, T b , T c ) -{ - if(a < b) a=b; - else if(a > c) a=c; -} - -// clamp , and return value -template < class T > -inline T -CLAMP_RET( T a, T b , T c ) { - if(a < b) return b; - else if(a > c) return c; - return a; -} - -template < class T > -inline T -CLAMP_DOWN_RET( T a, T b ) { - if(a < b) return b; - return a; -} - -template < class T > -inline T -CLAMP_UP_RET( T a, T b ) { - if(a > b) return b; - return a; -} - -// clamp and return whether clamping occured -template < class T > -inline bool -CLAMP_BOOL( T &a, T b , T c ) -{ - if(a < b) { - a=b; - return true; - } - - if(a > c) { - a=c; - return true; - } - return false; -} - -// clamp to grid boundaries -template < class T > -inline void CLAMP_TO_GRID(int &i, int &j, int &k, T grid) { - CLAMP(i, 0, grid->getSizeX()-2 ); - CLAMP(j, 0, grid->getSizeY()-2 ); - CLAMP(k, 0, grid->getSizeZ()-2 ); -} - -// clamp to grid and return whether clamping occured -template < class T > -inline bool CLAMP_TO_GRID_BOOL(int &i, int &j, int &k, T grid) { - bool ret = false; - ret |= CLAMP_BOOL(i, 0, grid->getSizeX()-2 ); - ret |= CLAMP_BOOL(j, 0, grid->getSizeY()-2 ); - ret |= CLAMP_BOOL(k, 0, grid->getSizeZ()-2 ); - return ret; -} - - -// constants for easier neighbor traversal -static const int nbX[6] = {-1,1, 0,0,0,0}; -static const int nbY[6] = { 0,0, -1,1, 0,0}; -static const int nbZ[6] = { 0,0,0,0, -1,1,}; - - -} // DDF - -#endif - diff --git a/intern/smoke/intern/util/matrixbase.h b/intern/smoke/intern/util/matrixbase.h deleted file mode 100644 index 396bd589423..00000000000 --- a/intern/smoke/intern/util/matrixbase.h +++ /dev/null @@ -1,810 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Simple matrix class - * - *****************************************************************************/ - - -#include "vectorbase.h" - -#ifndef NTL_MATRICES_H - -// init matrices with zero always? -#define MATRIX_INIT_ZERO 0 - - -namespace DDF { - - -// a basic simple 4x4 matrix class -template<class Scalar> -class ntlMatrix4x4 -{ - public: - // Constructor - inline ntlMatrix4x4(void ); - // Copy-Constructor - inline ntlMatrix4x4(const ntlMatrix4x4<Scalar> &v ); - // construct a matrix from one Scalar - inline ntlMatrix4x4(Scalar); - // construct a matrix from three Scalars - inline ntlMatrix4x4(Scalar, Scalar, Scalar); - - // Assignment operator - inline const ntlMatrix4x4<Scalar>& operator= (const ntlMatrix4x4<Scalar>& v); - // Assignment operator - inline const ntlMatrix4x4<Scalar>& operator= (Scalar s); - // Assign and add operator - inline const ntlMatrix4x4<Scalar>& operator+= (const ntlMatrix4x4<Scalar>& v); - // Assign and add operator - inline const ntlMatrix4x4<Scalar>& operator+= (Scalar s); - // Assign and sub operator - inline const ntlMatrix4x4<Scalar>& operator-= (const ntlMatrix4x4<Scalar>& v); - // Assign and sub operator - inline const ntlMatrix4x4<Scalar>& operator-= (Scalar s); - // Assign and mult operator - inline const ntlMatrix4x4<Scalar>& operator*= (const ntlMatrix4x4<Scalar>& v); - // Assign and mult operator - inline const ntlMatrix4x4<Scalar>& operator*= (Scalar s); - // Assign and div operator - inline const ntlMatrix4x4<Scalar>& operator/= (const ntlMatrix4x4<Scalar>& v); - // Assign and div operator - inline const ntlMatrix4x4<Scalar>& operator/= (Scalar s); - - - // unary operator - inline ntlMatrix4x4<Scalar> operator- () const; - - // binary operator add - inline ntlMatrix4x4<Scalar> operator+ (const ntlMatrix4x4<Scalar>&) const; - // binary operator add - inline ntlMatrix4x4<Scalar> operator+ (Scalar) const; - // binary operator sub - inline ntlMatrix4x4<Scalar> operator- (const ntlMatrix4x4<Scalar>&) const; - // binary operator sub - inline ntlMatrix4x4<Scalar> operator- (Scalar) const; - // binary operator mult - inline ntlMatrix4x4<Scalar> operator* (const ntlMatrix4x4<Scalar>&) const; - // binary operator mult - inline ntlVector3Dim<Scalar> operator* (const ntlVector3Dim<Scalar>&) const; - // binary operator mult - inline ntlMatrix4x4<Scalar> operator* (Scalar) const; - // binary operator div - inline ntlMatrix4x4<Scalar> operator/ (Scalar) const; - - // init function - //! init identity matrix - inline void initId(); - //! init rotation matrix - inline void initTranslation(Scalar x, Scalar y, Scalar z); - //! init rotation matrix - inline void initRotationX(Scalar rot); - inline void initRotationY(Scalar rot); - inline void initRotationZ(Scalar rot); - inline void initRotationXYZ(Scalar rotx,Scalar roty, Scalar rotz); - //! init scaling matrix - inline void initScaling(Scalar scale); - inline void initScaling(Scalar x, Scalar y, Scalar z); - - //! from 16 value array (init id if all 0) - inline void initFromArray(Scalar *array); - - inline void transpose(); - - //! decompose matrix intro translation, scale, rot and shear - void decompose(ntlVector3Dim<Scalar> &trans,ntlVector3Dim<Scalar> &scale,ntlVector3Dim<Scalar> &rot,ntlVector3Dim<Scalar> &shear); - - //! public to avoid [][] operators - Scalar value[4][4]; //< Storage of maxtrix values - - protected: - -}; - - - - - -//------------------------------------------------------------------------------ -// STREAM FUNCTIONS -//------------------------------------------------------------------------------ - - - -/************************************************************************* - Outputs the object in human readable form using the format - [x,y,z] - */ -template<class Scalar> -std::ostream& -operator<<( std::ostream& os, const ntlMatrix4x4<Scalar>& m ) -{ - for(int i=0; i<4; i++) { - os << '|' << m.value[i][0] << ", " << m.value[i][1] << ", " << m.value[i][2] << ", " << m.value[i][3] << '|'; - } - return os; -} - - - -/************************************************************************* - Reads the contents of the object from a stream using the same format - as the output operator. - */ -template<class Scalar> -std::istream& -operator>>( std::istream& is, ntlMatrix4x4<Scalar>& m ) -{ - char c; - char dummy[3]; - - for(int i=0; i<4; i++) { - is >> c >> m.value[i][0] >> dummy >> m.value[i][1] >> dummy >> m.value[i][2] >> dummy >> m.value[i][3] >> c; - } - return is; -} - - -//------------------------------------------------------------------------------ -// matrix inline FUNCTIONS -//------------------------------------------------------------------------------ - - - -/************************************************************************* - Constructor. - */ -template<class Scalar> -inline ntlMatrix4x4<Scalar>::ntlMatrix4x4( void ) -{ -#if MATRIX_INIT_ZERO==1 - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - value[i][j] = 0.0; - } - } -#endif -} - - - -/************************************************************************* - Copy-Constructor. - */ -template<class Scalar> -inline ntlMatrix4x4<Scalar>::ntlMatrix4x4( const ntlMatrix4x4<Scalar> &v ) -{ - value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3]; - value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3]; - value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3]; - value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3]; -} - - - -/************************************************************************* - Constructor for a vector from a single Scalar. All components of - the vector get the same value. - \param s The value to set - \return The new vector - */ -template<class Scalar> -inline ntlMatrix4x4<Scalar>::ntlMatrix4x4(Scalar s ) -{ - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - value[i][j] = s; - } - } -} - - - -/************************************************************************* - Copy a ntlMatrix4x4 componentwise. - \param v vector with values to be copied - \return Reference to self - */ -template<class Scalar> -inline const ntlMatrix4x4<Scalar>& -ntlMatrix4x4<Scalar>::operator=( const ntlMatrix4x4<Scalar> &v ) -{ - value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3]; - value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3]; - value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3]; - value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3]; - return *this; -} - - -/************************************************************************* - Copy a Scalar to each component. - \param s The value to copy - \return Reference to self - */ -template<class Scalar> -inline const ntlMatrix4x4<Scalar>& -ntlMatrix4x4<Scalar>::operator=(Scalar s) -{ - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - value[i][j] = s; - } - } - return *this; -} - - -/************************************************************************* - Add another ntlMatrix4x4 componentwise. - \param v vector with values to be added - \return Reference to self - */ -template<class Scalar> -inline const ntlMatrix4x4<Scalar>& -ntlMatrix4x4<Scalar>::operator+=( const ntlMatrix4x4<Scalar> &v ) -{ - value[0][0] += v.value[0][0]; value[0][1] += v.value[0][1]; value[0][2] += v.value[0][2]; value[0][3] += v.value[0][3]; - value[1][0] += v.value[1][0]; value[1][1] += v.value[1][1]; value[1][2] += v.value[1][2]; value[1][3] += v.value[1][3]; - value[2][0] += v.value[2][0]; value[2][1] += v.value[2][1]; value[2][2] += v.value[2][2]; value[2][3] += v.value[2][3]; - value[3][0] += v.value[3][0]; value[3][1] += v.value[3][1]; value[3][2] += v.value[3][2]; value[3][3] += v.value[3][3]; - return *this; -} - - -/************************************************************************* - Add a Scalar value to each component. - \param s Value to add - \return Reference to self - */ -template<class Scalar> -inline const ntlMatrix4x4<Scalar>& -ntlMatrix4x4<Scalar>::operator+=(Scalar s) -{ - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - value[i][j] += s; - } - } - return *this; -} - - -/************************************************************************* - Subtract another vector componentwise. - \param v vector of values to subtract - \return Reference to self - */ -template<class Scalar> -inline const ntlMatrix4x4<Scalar>& -ntlMatrix4x4<Scalar>::operator-=( const ntlMatrix4x4<Scalar> &v ) -{ - value[0][0] -= v.value[0][0]; value[0][1] -= v.value[0][1]; value[0][2] -= v.value[0][2]; value[0][3] -= v.value[0][3]; - value[1][0] -= v.value[1][0]; value[1][1] -= v.value[1][1]; value[1][2] -= v.value[1][2]; value[1][3] -= v.value[1][3]; - value[2][0] -= v.value[2][0]; value[2][1] -= v.value[2][1]; value[2][2] -= v.value[2][2]; value[2][3] -= v.value[2][3]; - value[3][0] -= v.value[3][0]; value[3][1] -= v.value[3][1]; value[3][2] -= v.value[3][2]; value[3][3] -= v.value[3][3]; - return *this; -} - - -/************************************************************************* - Subtract a Scalar value from each component. - \param s Value to subtract - \return Reference to self - */ -template<class Scalar> -inline const ntlMatrix4x4<Scalar>& -ntlMatrix4x4<Scalar>::operator-=(Scalar s) -{ - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - value[i][j] -= s; - } - } - return *this; -} - - -/************************************************************************* - Multiply with another vector componentwise. - \param v vector of values to multiply with - \return Reference to self - */ -template<class Scalar> -inline const ntlMatrix4x4<Scalar>& -ntlMatrix4x4<Scalar>::operator*=( const ntlMatrix4x4<Scalar> &v ) -{ - ntlMatrix4x4<Scalar> nv(0.0); - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - - for(int k=0;k<4;k++) - nv.value[i][j] += (value[i][k] * v.value[k][j]); - } - } - *this = nv; - return *this; -} - - -/************************************************************************* - Multiply each component with a Scalar value. - \param s Value to multiply with - \return Reference to self - */ -template<class Scalar> -inline const ntlMatrix4x4<Scalar>& -ntlMatrix4x4<Scalar>::operator*=(Scalar s) -{ - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - value[i][j] *= s; - } - } - return *this; -} - - - -/************************************************************************* - Divide each component by a Scalar value. - \param s Value to divide by - \return Reference to self - */ -template<class Scalar> -inline const ntlMatrix4x4<Scalar>& -ntlMatrix4x4<Scalar>::operator/=(Scalar s) -{ - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - value[i][j] /= s; - } - } - return *this; -} - - -//------------------------------------------------------------------------------ -// unary operators -//------------------------------------------------------------------------------ - - -/************************************************************************* - Build componentwise the negative this vector. - \return The new (negative) vector - */ -template<class Scalar> -inline ntlMatrix4x4<Scalar> -ntlMatrix4x4<Scalar>::operator-() const -{ - ntlMatrix4x4<Scalar> nv; - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - nv[i][j] = -value[i][j]; - } - } - return nv; -} - - - -//------------------------------------------------------------------------------ -// binary operators -//------------------------------------------------------------------------------ - - -/************************************************************************* - Build a vector with another vector added componentwise. - \param v The second vector to add - \return The sum vector - */ -template<class Scalar> -inline ntlMatrix4x4<Scalar> -ntlMatrix4x4<Scalar>::operator+( const ntlMatrix4x4<Scalar> &v ) const -{ - ntlMatrix4x4<Scalar> nv; - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - nv[i][j] = value[i][j] + v.value[i][j]; - } - } - return nv; -} - - -/************************************************************************* - Build a vector with a Scalar value added to each component. - \param s The Scalar value to add - \return The sum vector - */ -template<class Scalar> -inline ntlMatrix4x4<Scalar> -ntlMatrix4x4<Scalar>::operator+(Scalar s) const -{ - ntlMatrix4x4<Scalar> nv; - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - nv[i][j] = value[i][j] + s; - } - } - return nv; -} - - -/************************************************************************* - Build a vector with another vector subtracted componentwise. - \param v The second vector to subtract - \return The difference vector - */ -template<class Scalar> -inline ntlMatrix4x4<Scalar> -ntlMatrix4x4<Scalar>::operator-( const ntlMatrix4x4<Scalar> &v ) const -{ - ntlMatrix4x4<Scalar> nv; - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - nv[i][j] = value[i][j] - v.value[i][j]; - } - } - return nv; -} - - -/************************************************************************* - Build a vector with a Scalar value subtracted componentwise. - \param s The Scalar value to subtract - \return The difference vector - */ -template<class Scalar> -inline ntlMatrix4x4<Scalar> -ntlMatrix4x4<Scalar>::operator-(Scalar s ) const -{ - ntlMatrix4x4<Scalar> nv; - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - nv[i][j] = value[i][j] - s; - } - } - return nv; -} - - - -/************************************************************************* - Build a ntlMatrix4x4 with a Scalar value multiplied to each component. - \param s The Scalar value to multiply with - \return The product vector - */ -template<class Scalar> -inline ntlMatrix4x4<Scalar> -ntlMatrix4x4<Scalar>::operator*(Scalar s) const -{ - ntlMatrix4x4<Scalar> nv; - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - nv[i][j] = value[i][j] * s; - } - } - return nv; -} - - - - -/************************************************************************* - Build a vector divided componentwise by a Scalar value. - \param s The Scalar value to divide by - \return The ratio vector - */ -template<class Scalar> -inline ntlMatrix4x4<Scalar> -ntlMatrix4x4<Scalar>::operator/(Scalar s) const -{ - ntlMatrix4x4<Scalar> nv; - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - nv[i][j] = value[i][j] / s; - } - } - return nv; -} - - - - - -/************************************************************************* - Build a vector with another vector multiplied by componentwise. - \param v The second vector to muliply with - \return The product vector - */ -template<class Scalar> -inline ntlMatrix4x4<Scalar> -ntlMatrix4x4<Scalar>::operator*( const ntlMatrix4x4<Scalar>& v) const -{ - ntlMatrix4x4<Scalar> nv(0.0); - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - - for(int k=0;k<4;k++) - nv.value[i][j] += (value[i][k] * v.value[k][j]); - } - } - return nv; -} - - -template<class Scalar> -inline ntlVector3Dim<Scalar> -ntlMatrix4x4<Scalar>::operator*( const ntlVector3Dim<Scalar>& v) const -{ - ntlVector3Dim<Scalar> nvec(0.0); - for(int i=0; i<3; i++) { - for(int j=0; j<3; j++) { - nvec[i] += (v[j] * value[i][j]); - } - } - // assume normalized w coord - for(int i=0; i<3; i++) { - nvec[i] += (1.0 * value[i][3]); - } - return nvec; -} - - - -//------------------------------------------------------------------------------ -// Other helper functions -//------------------------------------------------------------------------------ - -//! init identity matrix -template<class Scalar> -inline void ntlMatrix4x4<Scalar>::initId() -{ - (*this) = (Scalar)(0.0); - value[0][0] = - value[1][1] = - value[2][2] = - value[3][3] = (Scalar)(1.0); -} - -//! init rotation matrix -template<class Scalar> -inline void ntlMatrix4x4<Scalar>::initTranslation(Scalar x, Scalar y, Scalar z) -{ - //(*this) = (Scalar)(0.0); - this->initId(); - value[0][3] = x; - value[1][3] = y; - value[2][3] = z; -} - -//! init rotation matrix -template<class Scalar> -inline void -ntlMatrix4x4<Scalar>::initRotationX(Scalar rot) -{ - double drot = (double)(rot/360.0*2.0*M_PI); - //? while(drot < 0.0) drot += (M_PI*2.0); - - this->initId(); - value[1][1] = (Scalar) cos(drot); - value[1][2] = (Scalar) sin(drot); - value[2][1] = (Scalar)(-sin(drot)); - value[2][2] = (Scalar) cos(drot); -} -template<class Scalar> -inline void -ntlMatrix4x4<Scalar>::initRotationY(Scalar rot) -{ - double drot = (double)(rot/360.0*2.0*M_PI); - //? while(drot < 0.0) drot += (M_PI*2.0); - - this->initId(); - value[0][0] = (Scalar) cos(drot); - value[0][2] = (Scalar)(-sin(drot)); - value[2][0] = (Scalar) sin(drot); - value[2][2] = (Scalar) cos(drot); -} -template<class Scalar> -inline void -ntlMatrix4x4<Scalar>::initRotationZ(Scalar rot) -{ - double drot = (double)(rot/360.0*2.0*M_PI); - //? while(drot < 0.0) drot += (M_PI*2.0); - - this->initId(); - value[0][0] = (Scalar) cos(drot); - value[0][1] = (Scalar) sin(drot); - value[1][0] = (Scalar)(-sin(drot)); - value[1][1] = (Scalar) cos(drot); -} -template<class Scalar> -inline void -ntlMatrix4x4<Scalar>::initRotationXYZ( Scalar rotx, Scalar roty, Scalar rotz) -{ - ntlMatrix4x4<Scalar> val; - ntlMatrix4x4<Scalar> rot; - this->initId(); - - // org - /*rot.initRotationX(rotx); - (*this) *= rot; - rot.initRotationY(roty); - (*this) *= rot; - rot.initRotationZ(rotz); - (*this) *= rot; - // org */ - - // blender - rot.initRotationZ(rotz); - (*this) *= rot; - rot.initRotationY(roty); - (*this) *= rot; - rot.initRotationX(rotx); - (*this) *= rot; - // blender */ -} - -//! transpose matrix -template<class Scalar> -inline void -ntlMatrix4x4<Scalar>::transpose() -{ - for (int i=0;i<4;i++) - for (int j=i+1;j<4;j++) - { - Scalar a=value[i][j]; - value[i][j]=value[j][i]; - value[j][i]=a; - } -} - -//! init scaling matrix -template<class Scalar> -inline void -ntlMatrix4x4<Scalar>::initScaling(Scalar scale) -{ - this->initId(); - value[0][0] = scale; - value[1][1] = scale; - value[2][2] = scale; -} -//! init scaling matrix -template<class Scalar> -inline void -ntlMatrix4x4<Scalar>::initScaling(Scalar x, Scalar y, Scalar z) -{ - this->initId(); - value[0][0] = x; - value[1][1] = y; - value[2][2] = z; -} - - -//! from 16 value array (init id if all 0) -template<class Scalar> -inline void -ntlMatrix4x4<Scalar>::initFromArray(Scalar *array) -{ - bool allZero = true; - for(int i=0; i<4; i++) { - for(int j=0; j<4; j++) { - value[i][j] = array[i*4+j]; - if(array[i*4+j]!=0.0) allZero=false; - } - } - if(allZero) this->initId(); -} - -//! decompose matrix -template<class Scalar> -void -ntlMatrix4x4<Scalar>::decompose(ntlVector3Dim<Scalar> &trans,ntlVector3Dim<Scalar> &scale,ntlVector3Dim<Scalar> &rot,ntlVector3Dim<Scalar> &shear) { - Vec3 row[3],temp; - - for(int i = 0; i < 3; i++) { - trans[i] = this->value[3][i]; - } - - for(int i = 0; i < 3; i++) { - row[i][0] = this->value[i][0]; - row[i][1] = this->value[i][1]; - row[i][2] = this->value[i][2]; - } - - scale[0] = norm(row[0]); - normalize (row[0]); - - shear[0] = dot(row[0], row[1]); - row[1][0] = row[1][0] - shear[0]*row[0][0]; - row[1][1] = row[1][1] - shear[0]*row[0][1]; - row[1][2] = row[1][2] - shear[0]*row[0][2]; - - scale[1] = norm(row[1]); - normalize (row[1]); - - if(scale[1] != 0.0) - shear[0] /= scale[1]; - - shear[1] = dot(row[0], row[2]); - row[2][0] = row[2][0] - shear[1]*row[0][0]; - row[2][1] = row[2][1] - shear[1]*row[0][1]; - row[2][2] = row[2][2] - shear[1]*row[0][2]; - - shear[2] = dot(row[1], row[2]); - row[2][0] = row[2][0] - shear[2]*row[1][0]; - row[2][1] = row[2][1] - shear[2]*row[1][1]; - row[2][2] = row[2][2] - shear[2]*row[1][2]; - - scale[2] = norm(row[2]); - normalize (row[2]); - - if(scale[2] != 0.0) { - shear[1] /= scale[2]; - shear[2] /= scale[2]; - } - - temp = cross(row[1], row[2]); - if(dot(row[0], temp) < 0.0) { - for(int i = 0; i < 3; i++) { - scale[i] *= -1.0; - row[i][0] *= -1.0; - row[i][1] *= -1.0; - row[i][2] *= -1.0; - } - } - - if(row[0][2] < -1.0) row[0][2] = -1.0; - if(row[0][2] > +1.0) row[0][2] = +1.0; - - rot[1] = asin(-row[0][2]); - - if(fabs(cos(rot[1])) > VECTOR_EPSILON) { - rot[0] = atan2 (row[1][2], row[2][2]); - rot[2] = atan2 (row[0][1], row[0][0]); - } - else { - rot[0] = atan2 (row[1][0], row[1][1]); - rot[2] = 0.0; - } - - rot[0] = (180.0/M_PI)*rot[0]; - rot[1] = (180.0/M_PI)*rot[1]; - rot[2] = (180.0/M_PI)*rot[2]; -} - -//------------------------------------------------------------------------------ -// TYPEDEFS -//------------------------------------------------------------------------------ - - -typedef ntlMatrix4x4<double> ntlMat4d; - -// a 3D vector with single precision -typedef ntlMatrix4x4<float> ntlMat4f; - -// a 3D integer vector -typedef ntlMatrix4x4<int> ntlMat4i; - - - -// default vector typing -// a 3D vector for graphics output, typically float? -typedef ntlMatrix4x4<Real> Mat4; - - -}; // namespace DDF - -#define NTL_MATRICES_H -#endif - - - - diff --git a/intern/smoke/intern/util/paramset.cpp b/intern/smoke/intern/util/paramset.cpp deleted file mode 100644 index 88adc834521..00000000000 --- a/intern/smoke/intern/util/paramset.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/****************************************************************************** - * Parameter storage class - * - * Copyright(c) 1998-2007 Matt Pharr and Greg Humphreys. - * - *****************************************************************************/ - -// paramset.cpp* -#define CORE_SOURCE -#include "globals.h" -#include "paramset.h" - -// ParamSet Macros -#define ADD_PARAM_TYPE(T, vec) \ - (vec).push_back(new ParamSetItem<T>(name, (const T *)data, nItems)) - -#define LOOKUP_PTR(vec) \ - for (size_t i = 0; i < (vec).size(); ++i) \ - if ((vec)[i]->name == name) { \ - *nItems = (vec)[i]->nItems; \ - (vec)[i]->lookedUp = true; \ - return (vec)[i]->data; \ - } \ - return NULL -#define LOOKUP_ONE(vec) \ - for (size_t i = 0; i < (vec).size(); ++i) { \ - if ((vec)[i]->name == name && \ - (vec)[i]->nItems == 1) { \ - (vec)[i]->lookedUp = true; \ - return *((vec)[i]->data); \ -} } \ - return d - -// ParamSet Methods -ParamSet::ParamSet(const ParamSet &p2) { - *this = p2; -} - -void ParamSet::AddSet(const ParamSet &p2) { - unsigned i; - for (i = 0; i < p2.ints.size(); ++i) - AddInt(p2.ints[i]->name, p2.ints[i]->data); - for (i = 0; i < p2.bools.size(); ++i) - AddBool(p2.bools[i]->name, p2.bools[i]->data); - for (i = 0; i < p2.floats.size(); ++i) - AddFloat(p2.floats[i]->name, p2.floats[i]->data); - for (i = 0; i < p2.vectors.size(); ++i) - AddVector(p2.vectors[i]->name, p2.vectors[i]->data); - for (i = 0; i < p2.strings.size(); ++i) - AddString(p2.strings[i]->name, p2.strings[i]->data); -} - -ParamSet &ParamSet::operator=(const ParamSet &p2) { - if (&p2 != this) { - Clear(); unsigned i; - for (i = 0; i < p2.ints.size(); ++i) - ints.push_back(p2.ints[i]->Clone()); - for (i = 0; i < p2.bools.size(); ++i) - bools.push_back(p2.bools[i]->Clone()); - for (i = 0; i < p2.floats.size(); ++i) - floats.push_back(p2.floats[i]->Clone()); - for (i = 0; i < p2.vectors.size(); ++i) - vectors.push_back(p2.vectors[i]->Clone()); - for (i = 0; i < p2.strings.size(); ++i) - strings.push_back(p2.strings[i]->Clone()); - } - return *this; -} - -void ParamSet::override(const ParamSet &p2) { - // note - this only overrides parameters that already - // exist in the paramset! - - if (&p2 != this) { - for (size_t i = 0; i < p2.ints.size(); ++i) { - for (size_t j = 0; j < this->ints.size(); ++j) { - if (p2.ints[i]->name.compare( this->ints[j]->name )==0) { - fprintf(stderr,"Overriding int '%s' \n", this->ints[j]->name.c_str() ); - this->ints[j] = p2.ints[i]->Clone(); - } - } - } - for (size_t i = 0; i < p2.bools.size(); ++i) { - for (size_t j = 0; j < this->bools.size(); ++j) { - if (p2.bools[i]->name.compare( this->bools[j]->name )==0) { - fprintf(stderr,"Overriding bool '%s' \n", this->bools[j]->name.c_str() ); - this->bools[j] = p2.bools[i]->Clone(); - } - } - } - for (size_t i = 0; i < p2.floats.size(); ++i) { - for (size_t j = 0; j < this->floats.size(); ++j) { - if (p2.floats[i]->name.compare( this->floats[j]->name )==0) { - fprintf(stderr,"Overriding float '%s' \n", this->floats[j]->name.c_str() ); - this->floats[j] = p2.floats[i]->Clone(); - } - } - } - for (size_t i = 0; i < p2.vectors.size(); ++i) { - for (size_t j = 0; j < this->vectors.size(); ++j) { - if (p2.vectors[i]->name.compare( this->vectors[j]->name )==0) { - fprintf(stderr,"Overriding vec '%s' \n", this->vectors[j]->name.c_str() ); - this->vectors[j] = p2.vectors[i]->Clone(); - } - } - } - for (size_t i = 0; i < p2.strings.size(); ++i) { - for (size_t j = 0; j < this->strings.size(); ++j) { - if (p2.strings[i]->name.compare( this->strings[j]->name )==0) { - fprintf(stderr,"Overriding string '%s' \n", this->strings[j]->name.c_str() ); - this->strings[j] = p2.strings[i]->Clone(); - } - } - } - } - return; -} - -void ParamSet::AddFloat(const string &name, - const float *data, - int nItems) { - EraseFloat(name); - floats.push_back(new ParamSetItem<float>(name, - data, - nItems)); -} -void ParamSet::AddInt(const string &name, const int *data, int nItems) { - EraseInt(name); - ADD_PARAM_TYPE(int, ints); -} -void ParamSet::AddBool(const string &name, const bool *data, int nItems) { - EraseInt(name); - ADD_PARAM_TYPE(bool, bools); -} - -void ParamSet::AddVector(const string &name, const DDF::Vec3 *data, int nItems) { - EraseVector(name); - ADD_PARAM_TYPE(DDF::Vec3, vectors); -} - -void ParamSet::AddString(const string &name, const string *data, int nItems) { - EraseString(name); - ADD_PARAM_TYPE(string, strings); -} - -bool ParamSet::EraseInt(const string &n) { - for (size_t i = 0; i < ints.size(); ++i) - if (ints[i]->name == n) { - delete ints[i]; - ints.erase(ints.begin() + i); - return true; - } - return false; -} -bool ParamSet::EraseBool(const string &n) { - for (size_t i = 0; i < bools.size(); ++i) - if (bools[i]->name == n) { - delete bools[i]; - bools.erase(bools.begin() + i); - return true; - } - return false; -} - -bool ParamSet::EraseFloat(const string &n) { - for (size_t i = 0; i < floats.size(); ++i) - if (floats[i]->name == n) { - delete floats[i]; - floats.erase(floats.begin() + i); - return true; - } - return false; -} - -bool ParamSet::EraseVector(const string &n) { - for (size_t i = 0; i < vectors.size(); ++i) - if (vectors[i]->name == n) { - delete vectors[i]; - vectors.erase(vectors.begin() + i); - return true; - } - return false; -} - -bool ParamSet::EraseString(const string &n) { - for (size_t i = 0; i < strings.size(); ++i) - if (strings[i]->name == n) { - delete strings[i]; - strings.erase(strings.begin() + i); - return true; - } - return false; -} -float ParamSet::FindOneFloat(const string &name, - float d) const { - for (size_t i = 0; i < floats.size(); ++i) - if (floats[i]->name == name && - floats[i]->nItems == 1) { - floats[i]->lookedUp = true; - return *(floats[i]->data); - } - return d; -} -const float *ParamSet::FindFloat(const string &name, - int *nItems) const { - for (size_t i = 0; i < floats.size(); ++i) - if (floats[i]->name == name) { - *nItems = floats[i]->nItems; - floats[i]->lookedUp = true; - return floats[i]->data; - } - return NULL; -} -const int *ParamSet::FindInt(const string &name, int *nItems) const { - LOOKUP_PTR(ints); -} -const bool *ParamSet::FindBool(const string &name, int *nItems) const { - LOOKUP_PTR(bools); -} -int ParamSet::FindOneInt(const string &name, int d) const { - LOOKUP_ONE(ints); -} -bool ParamSet::FindOneBool(const string &name, bool d) const { - LOOKUP_ONE(bools); -} -const DDF::Vec3 *ParamSet::FindVector(const string &name, int *nItems) const { - LOOKUP_PTR(vectors); -} -DDF::Vec3 ParamSet::FindOneVector(const string &name, const DDF::Vec3 &d) const { - LOOKUP_ONE(vectors); -} -const string *ParamSet::FindString(const string &name, int *nItems) const { - LOOKUP_PTR(strings); -} -string ParamSet::FindOneString(const string &name, const string &d) const { - LOOKUP_ONE(strings); -} - -void ParamSet::ReportUnused() const { - bool haveUnused = false; - -#define CHECK_UNUSED(v, TYPE) \ - for (i = 0; i < (v).size(); ++i) \ - if (!(v)[i]->lookedUp) { haveUnused = true; \ - debMsg("PARAMSET-WARN","Parameter \""<< (v)[i]->name.c_str() <<"\" not used, type=" TYPE); \ - } - size_t i; - CHECK_UNUSED(ints,"int"); - CHECK_UNUSED(bools, "bool"); - CHECK_UNUSED(floats, "float"); - CHECK_UNUSED(vectors, "vec3"); - CHECK_UNUSED(strings, "string"); - - if(haveUnused) { - errFatal("ParamSet::ReportUnused","Stopping...", SIMWORLD_ERRPARSE ); - } -} -void ParamSet::Clear() { -#define DEL_PARAMS(name) \ - for (size_t i = 0; i < (name).size(); ++i) \ - delete (name)[i]; \ - (name).erase((name).begin(), (name).end()) - DEL_PARAMS(ints); - DEL_PARAMS(bools); - DEL_PARAMS(floats); - DEL_PARAMS(vectors); - DEL_PARAMS(strings); -#undef DEL_PARAMS -} -string ParamSet::ToString() const { - string ret; - size_t i; - int j; - string typeString; - const int bufLen = 48*1024*1024; - static char *buf = new char[bufLen]; - char *bufEnd = buf + bufLen; - - for (i = 0; i < ints.size(); ++i) { - char *bufp = buf; - *bufp = '\0'; - ParamSetItem<int> *item = ints[i]; - typeString = "integer "; - // Print _ParamSetItem_ declaration, determine how many to print - int nPrint = item->nItems; - ret += string("\""); - ret += typeString; - ret += item->name; - ret += string("\""); - ret += string(" ["); - for (j = 0; j < nPrint; ++j) - bufp += snprintf(bufp, bufEnd - bufp, "%d ", item->data[j]); - ret += buf; - ret += string("] "); - } - - for (i = 0; i < bools.size(); ++i) { - char *bufp = buf; - *bufp = '\0'; - ParamSetItem<bool> *item = bools[i]; - typeString = "bool "; - // Print _ParamSetItem_ declaration, determine how many to print - int nPrint = item->nItems; - ret += string("\""); - ret += typeString; - ret += item->name; - ret += string("\""); - ret += string(" ["); - for (j = 0; j < nPrint; ++j) - bufp += snprintf(bufp, bufEnd - bufp, "\"%s\" ", item->data[j] ? "true" : "false"); - ret += buf; - ret += string("] "); - } - - for (i = 0; i < floats.size(); ++i) { - char *bufp = buf; - *bufp = '\0'; - ParamSetItem<float> *item = floats[i]; - typeString = "float "; - // Print _ParamSetItem_ declaration, determine how many to print - int nPrint = item->nItems; - ret += string("\""); - ret += typeString; - ret += item->name; - ret += string("\""); - ret += string(" ["); - for (j = 0; j < nPrint; ++j) - bufp += snprintf(bufp, bufEnd - bufp, "%.8g ", item->data[j]); - ret += buf; - ret += string("] "); - } - - for (i = 0; i < vectors.size(); ++i) { - char *bufp = buf; - *bufp = '\0'; - ParamSetItem<DDF::Vec3> *item = vectors[i]; - typeString = "vector "; - // Print _ParamSetItem_ declaration, determine how many to print - int nPrint = item->nItems; - ret += string("\""); - ret += typeString; - ret += item->name; - ret += string("\""); - ret += string(" ["); - for (j = 0; j < nPrint; ++j) - bufp += snprintf(bufp, bufEnd - bufp, "%.8g %.8g %.8g ", item->data[j].x, - item->data[j].y, item->data[j].z); - ret += buf; - ret += string("] "); - } - - for (i = 0; i < strings.size(); ++i) { - char *bufp = buf; - *bufp = '\0'; - ParamSetItem<string> *item = strings[i]; - typeString = "string "; - // Print _ParamSetItem_ declaration, determine how many to print - int nPrint = item->nItems; - ret += string("\""); - ret += typeString; - ret += item->name; - ret += string("\""); - ret += string(" ["); - for (j = 0; j < nPrint; ++j) - bufp += snprintf(bufp, bufEnd - bufp, "\"%s\" ", item->data[j].c_str()); - ret += buf; - ret += string("] "); - } - return ret; -} - - - diff --git a/intern/smoke/intern/util/paramset.h b/intern/smoke/intern/util/paramset.h deleted file mode 100644 index 612345bd775..00000000000 --- a/intern/smoke/intern/util/paramset.h +++ /dev/null @@ -1,113 +0,0 @@ -/****************************************************************************** - * Parameter storage class - * - * Copyright(c) 1998-2007 Matt Pharr and Greg Humphreys. - * - *****************************************************************************/ - -#ifndef PBRT_PARAMSET_H -#define PBRT_PARAMSET_H - -#include "globals.h" -using std::string; -using std::vector; -#if (_MSC_VER >= 1400) // NOBOOK -#include <stdio.h> // NOBOOK -#define snprintf _snprintf // NOBOOK -#endif // NOBOOK - -// forward declaration -template <class T> struct ParamSetItem; - -// ParamSet Declarations -#if DDF_USEPARSER == 1 -#include "parser.h" -class COREDLL ParamSet { -#else -class ParamSet { -#endif -public: - // ParamSet Public Methods - ParamSet() { } - ParamSet &operator=(const ParamSet &p2); - ParamSet(const ParamSet &p2); - void AddSet(const ParamSet &p2); - void AddFloat(const string &, const float *, int nItems = 1); - void AddInt(const string &, const int *, int nItems = 1); - void AddBool(const string &, const bool *, int nItems = 1); - void AddVector(const string &, const DDF::Vec3 *, int nItems = 1); - void AddString(const string &, const string *, int nItems = 1); - - void AddInt(const string &n, int d) { AddInt(n,&d); } - void AddBool(const string &n, bool d) { AddBool(n,&d); } - void AddFloat(const string &n, float d) { AddFloat(n,&d); } - void AddVector(const string &n, const DDF::Vec3& d) { AddVector(n,&d); } - void AddString(const string &n, const string& d) { AddString(n,&d); } - - bool EraseInt(const string &); - bool EraseBool(const string &); - bool EraseFloat(const string &); - bool EraseVector(const string &); - bool EraseString(const string &); - - float FindOneFloat(const string &, float d) const; - int FindOneInt(const string &, int d) const; - bool FindOneBool(const string &, bool d) const; - DDF::Vec3 FindOneVector(const string &, const DDF::Vec3 &d) const; - string FindOneString(const string &, const string &d) const; - //string FindTexture(const string &) const; - - const float *FindFloat(const string &, int *nItems) const; - const int *FindInt(const string &, int *nItems) const; - const bool *FindBool(const string &, int *nItems) const; - const DDF::Vec3 *FindVector(const string &, int *nItems) const; - const string *FindString(const string &, int *nItems) const; - - void override(const ParamSet &p2); - - void ReportUnused() const; - ~ParamSet() { - Clear(); - } - void Clear(); - string ToString() const; -private: - // ParamSet Data - vector<ParamSetItem<int> *> ints; - vector<ParamSetItem<bool> *> bools; - vector<ParamSetItem<float> *> floats; - vector<ParamSetItem<DDF::Vec3> *> vectors; - vector<ParamSetItem<string> *> strings; -}; - -template <class T> struct ParamSetItem { - // ParamSetItem Public Methods - ParamSetItem<T> *Clone() const { - return new ParamSetItem<T>(name, data, nItems); - } - ParamSetItem(const string &name, const T *val, int nItems = 1); - ~ParamSetItem() { - delete[] data; - } - // ParamSetItem Data - string name; - int nItems; - T *data; - bool lookedUp; -}; -// ParamSetItem Methods -template <class T> -ParamSetItem<T>::ParamSetItem(const string &n, - const T *v, - int ni) { - name = n; - nItems = ni; - data = new T[nItems]; - for (int i = 0; i < nItems; ++i) - data[i] = v[i]; - lookedUp = false; -} - - - -#endif // PBRT_PARAMSET_H diff --git a/intern/smoke/intern/util/quaternion.h b/intern/smoke/intern/util/quaternion.h deleted file mode 100644 index d06e7110ea5..00000000000 --- a/intern/smoke/intern/util/quaternion.h +++ /dev/null @@ -1,149 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Basic quaternion class - * - *****************************************************************************/ - -#ifndef UTIL_QUATERIONS_H -#define UTIL_QUATERIONS_H - -#include "matrixbase.h" -#include "vectorbase.h" - - -#define smax(a,b) ((a>b)?(a):(b)) -#define scpysign(a,b) ((a)*(b)>=0?(a):-(a)) - -namespace DDF { - -template<class Scalar> -class Quaternion -{ -public: - Scalar x,y,z,w; - - Quaternion () : x(0),y(0),z(0),w(0) {} - - Quaternion (Scalar nx, Scalar ny, Scalar nz, Scalar nw) : - x(nx),y(ny),z(nz),w(nw) {} - - Quaternion (const Quaternion &q) - { - x=q.x; y=q.y; z=q.z; w=q.w; - } - - Quaternion (const ntlMatrix4x4<Scalar> &M) - { - w = sqrt( smax( 0, 1 + M.value[0][0] + M.value[1][1] + M.value[2][2] ) ) / 2; - x = sqrt( smax( 0, 1 + M.value[0][0] - M.value[1][1] - M.value[2][2] ) ) / 2; - y = sqrt( smax( 0, 1 - M.value[0][0] + M.value[1][1] - M.value[2][2] ) ) / 2; - z = sqrt( smax( 0, 1 - M.value[0][0] - M.value[1][1] + M.value[2][2] ) ) / 2; - x = scpysign( x, M.value[2][1] - M.value[1][2] ); - y = scpysign( y, M.value[0][2] - M.value[2][0] ); - z = scpysign( z, M.value[1][0] - M.value[0][1] ); - } - - Quaternion (const ntlVector3Dim<Scalar>& axis, Scalar angle) - { - Scalar mult = sin(angle*.5); - x = axis.x * mult; - y = axis.y * mult; - z = axis.z * mult; - w = cos (angle*.5); - } - - Quaternion (Scalar rx, Scalar ry, Scalar rz) - { - Quaternion qx(ntlVector3Dim<Scalar> (1.,0.,0.),-rx); - Quaternion qy(ntlVector3Dim<Scalar> (0.,1.,0.),-ry); - Quaternion qz(ntlVector3Dim<Scalar> (0.,0.,1.),-rz); - Quaternion q = qz*qy*qx; - x=q.x; y=q.y; z=q.z; w=q.w; - } - - ntlMatrix4x4<Scalar> getRotMat() const - { - const Scalar x2 = x*x; - const Scalar y2 = y*y; - const Scalar z2 = z*z; - // const float w2 = w*w; - - ntlMatrix4x4<Scalar> M; - M.initId(); - M.value[0][0] = 1 - 2*(y2+z2); - M.value[0][1] = 2*(x*y - w*z); - M.value[0][2] = 2*(x*z+w*y); - M.value[1][0] = 2*(x*y+w*z); - M.value[1][1] = 1-2*(x2+z2); - M.value[1][2] = 2*(y*z-w*x); - M.value[2][0] = 2*(x*z-w*y); - M.value[2][1] = 2*(y*z+w*x); - M.value[2][2] = 1-2*(x2+y2); - return M; - } - - ntlVector3Dim<Scalar> getAxis() const - { - Scalar phi2 = acos(w); - ntlVector3Dim<Scalar> axis = ntlVector3Dim<Scalar> (x,y,z) * (1./sin(phi2)); - normalize(axis); - return axis * 2.* phi2; - } - - inline const Quaternion operator+(const Quaternion &q) const { return Quaternion(x+q.x,y+q.y,z+q.z,w+q.w); }; - inline const Quaternion operator-(const Quaternion &q) const { return Quaternion(x-q.x,y-q.y,z-q.z,w-q.w); }; - inline const Quaternion operator*(const Scalar m) const { return Quaternion(x*m,y*m,z*m,w*m); }; - inline const Quaternion operator-() const { return Quaternion(-x,-y,-z,-w); }; - inline Scalar dot(const Quaternion &q) const { return x*q.x+y*q.y+z*q.z+w*q.w; } - inline Scalar normSq() const { return x*x+y*y+z*z+w*w; } - inline Scalar norm() const { return sqrt(normSq()); } - inline const Quaternion unit() const { Scalar d=1./norm(); return Quaternion(x*d,y*d,z*d,w*d); } - - inline const Quaternion operator*(const Quaternion &q) const - { - ntlVector3Dim<Scalar> v1(x,y,z), v2(q.x,q.y,q.z); - ntlVector3Dim<Scalar> nv = v1*q.w + v2*w + cross(v2,v1); - Scalar nw = w*q.w - (v1.x*v2.x+v1.y*v2.y+v1.z*v2.z); - - return Quaternion(nv.x,nv.y,nv.z,nw); - } - - static const Quaternion slerp(Quaternion q, Quaternion p, Scalar t) - { - Scalar cosphi = q.dot(p); - - if(cosphi < 0.0f) - { - cosphi *= -1.0f; - q = -q; - } - - const Scalar DOT_THRESHOLD = 0.9995f; - if (cosphi > DOT_THRESHOLD) { - // interpolate linearly - return (q + (p - q) * t).unit(); - } - - Scalar sinphi = sqrt(1. - cosphi * cosphi); - Scalar phi = acos(cosphi); - - Quaternion res = q * (sin( phi * (1.-t) ) / sinphi) + p * (sin( phi * t) / sinphi); - - return res; - } -}; - -typedef Quaternion<Real> Quat; - -} - - -#endif // __Quaternion_h__ - - diff --git a/intern/smoke/intern/util/randomstream.h b/intern/smoke/intern/util/randomstream.h deleted file mode 100644 index 9f92bc0c089..00000000000 --- a/intern/smoke/intern/util/randomstream.h +++ /dev/null @@ -1,380 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * A seperate random number stream - * - *****************************************************************************/ - -#ifndef NTL_RANDOMSTREAM_HH -#define NTL_RANDOMSTREAM_HH - -namespace DDF { - -#include <iostream> -#include <limits.h> -#include <stdio.h> -#include <time.h> -#include <math.h> - -class MTRand { - // Data - public: - typedef unsigned long uint32; // unsigned integer type, at least 32 bits - - enum { N = 624 }; // length of state vector - enum { SAVE = N + 1 }; // length of array for save() - - protected: - enum { M = 397 }; // period parameter - - uint32 state[N]; // internal state - uint32 *pNext; // next value to get from state - int left; // number of values left before reload needed - - - //Methods - public: - MTRand( const uint32& oneSeed ); // initialize with a simple uint32 - MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or an array - MTRand(); // auto-initialize with /dev/urandom or time() and clock() - - // Do NOT use for CRYPTOGRAPHY without securely hashing several returned - // values together, otherwise the generator state can be learned after - // reading 624 consecutive values. - - // Access to 32-bit random numbers - double rand(); // real number in [0,1] - double rand( const double& n ); // real number in [0,n] - double randExc(); // real number in [0,1) - double randExc( const double& n ); // real number in [0,n) - double randDblExc(); // real number in (0,1) - double randDblExc( const double& n ); // real number in (0,n) - uint32 randInt(); // integer in [0,2^32-1] - uint32 randInt( const uint32& n ); // integer in [0,n] for n < 2^32 - double operator()() { return rand(); } // same as rand() - - // Access to 53-bit random numbers (capacity of IEEE double precision) - double rand53(); // real number in [0,1) - - // Access to nonuniform random number distributions - double randNorm( const double& mean = 0.0, const double& variance = 1.0 ); - - // Re-seeding functions with same behavior as initializers - void seed( const uint32 oneSeed ); - void seed( uint32 *const bigSeed, const uint32 seedLength = N ); - void seed(); - - // Saving and loading generator state - void save( uint32* saveArray ) const; // to array of size SAVE - void load( uint32 *const loadArray ); // from such array - friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand ); - friend std::istream& operator>>( std::istream& is, MTRand& mtrand ); - - protected: - void initialize( const uint32 oneSeed ); - void reload(); - uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; } - uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; } - uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; } - uint32 mixBits( const uint32& u, const uint32& v ) const - { return hiBit(u) | loBits(v); } - uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const - { - return m ^ (mixBits(s0,s1)>>1) ^ ((~loBit(s1) + 1) & 0x9908b0dfUL); - // return m ^ (mixBits(s0,s1)>>1) ^ (-((int)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; - - register 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; - register int i = 1; - register uint32 j = 0; - register 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 deterministically to produce reproducible runs - seed(123456); - - /* - // Seed the generator with an array from /dev/urandom if available - // Otherwise use a hash of time() and clock() values - - // First try getting an array from /dev/urandom - FILE* urandom = fopen( "/dev/urandom", "rb" ); - if( urandom ) - { - uint32 bigSeed[N]; - register uint32 *s = bigSeed; - register int i = N; - register 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. - register uint32 *s = state; - register uint32 *r = state; - register 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) - register uint32 *p = state; - register int i; - for( i = N - M; i--; ++p ) - *p = twist( p[M], p[0], p[1] ); - for( i = M; --i; ++p ) - *p = twist( p[M-N], p[0], p[1] ); - *p = twist( p[M-N], p[0], state[0] ); - - left = N, pNext = state; -} - - -inline MTRand::uint32 MTRand::hash( time_t t, clock_t c ) -{ - // Get a uint32 from t and c - // Better than uint32(x) in case x is floating point in [0,1] - // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk) - - static uint32 differ = 0; // guarantee time-based seeds will change - - uint32 h1 = 0; - unsigned char *p = (unsigned char *) &t; - for( size_t i = 0; i < sizeof(t); ++i ) - { - h1 *= UCHAR_MAX + 2U; - h1 += p[i]; - } - uint32 h2 = 0; - p = (unsigned char *) &c; - for( size_t j = 0; j < sizeof(c); ++j ) - { - h2 *= UCHAR_MAX + 2U; - h2 += p[j]; - } - return ( h1 + differ++ ) ^ h2; -} - - -inline void MTRand::save( uint32* saveArray ) const -{ - register uint32 *sa = saveArray; - register const uint32 *s = state; - register int i = N; - for( ; i--; *sa++ = *s++ ) {} - *sa = left; -} - - -inline void MTRand::load( uint32 *const loadArray ) -{ - register uint32 *s = state; - register uint32 *la = loadArray; - register int i = N; - for( ; i--; *s++ = *la++ ) {} - left = *la; - pNext = &state[N-left]; -} - - -inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand ) -{ - register const MTRand::uint32 *s = mtrand.state; - register int i = mtrand.N; - for( ; i--; os << *s++ << "\t" ) {} - return os << mtrand.left; -} - - -inline std::istream& operator>>( std::istream& is, MTRand& mtrand ) -{ - register MTRand::uint32 *s = mtrand.state; - register 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 - -private: - MTRand mtr; -}; - - - -} // DDF - -#endif diff --git a/intern/smoke/intern/util/waveletnoise.h b/intern/smoke/intern/util/waveletnoise.h deleted file mode 100644 index 0eb61fbfd96..00000000000 --- a/intern/smoke/intern/util/waveletnoise.h +++ /dev/null @@ -1,600 +0,0 @@ -/****************************************************************************** - * DDF Fluid solver with Turbulence extensions - * - * copyright 2009 Nils Thuerey, Tobias Pfaff - * - * DDF is free software, distributed under the GNU General Public License (GPL v2). - * See the file COPYING for more information. - * - * Generate defined noise textures - * - *****************************************************************************/ - - -#include "randomstream.h" -#include "vectorbase.h" -#include "paramset.h" -using DDF::Real; -using DDF::Vec3; -using DDF::nVec3i; - -namespace DDF { -// global tile data, defined in globals.cpp -extern float* stdTileData; -}; - - -namespace WAVELETNOISE { - -#define NOISE_TILE_SIZE 128 -static const int noiseTileSize = NOISE_TILE_SIZE; -static const char* stdTileName = "noiseTile3d.dqt"; - -//***************************************************************************** -// helper functions - -static 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) - - -//***************************************************************************** -// Wavelet downsampling -static float _aCoeffs[32] = { - 0.000334f,-0.001528f, 0.000410f, 0.003545f,-0.000938f,-0.008233f, 0.002172f, 0.019120f, - -0.005040f,-0.044412f, 0.011655f, 0.103311f,-0.025936f,-0.243780f, 0.033979f, 0.655340f, - 0.655340f, 0.033979f,-0.243780f,-0.025936f, 0.103311f, 0.011655f,-0.044412f,-0.005040f, - 0.019120f, 0.002172f,-0.008233f,-0.000938f, 0.003546f, 0.000410f,-0.001528f, 0.000334f}; -static void Downsample(float *from, float *to, int n, int stride){ - const float *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]; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// Wavelet upsampling -////////////////////////////////////////////////////////////////////////////////////////// -static float _pCoeffs[4] = {0.25f, 0.75f, 0.75f, 0.25f}; -static void Upsample(float *from, float *to, int n, int stride) { - const float *p = &_pCoeffs[2]; - - for (int i = 0; i < n; i++) { - to[i * stride] = 0; - for (int k = i / 2; k <= i / 2 + 1; k++) - to[i * stride] += p[i - 2 * k] * from[modSlow(k, n / 2) * stride]; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// load in an existing noise tile -////////////////////////////////////////////////////////////////////////////////////////// -static bool loadTile(float* const noiseTileData, std::string filename) -{ - FILE* file; - file = fopen(filename.c_str(), "rb"); - - if (file == NULL) { - printf("loadTile: No noise tile '%s' found.\n", filename.c_str()); - return false; - } - - // dimensions - int gridSize = noiseTileSize * noiseTileSize * noiseTileSize; - // noiseTileData memory is managed by caller - int bread = fread((void*)noiseTileData, sizeof(float), gridSize, file); - fclose(file); - printf("Noise tile file loaded.\n"); - - if (bread != gridSize) { - printf("loadTile: Noise tile '%s' is wrong size %d.\n", filename.c_str(), bread); - return false; - } - return true; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// write out an existing noise tile -////////////////////////////////////////////////////////////////////////////////////////// -static void saveTile(float* const noiseTileData, std::string filename) -{ - FILE* file; - file = fopen(filename.c_str(), "wb"); - - if (file == NULL) { - printf("saveTile: No noise tile '%s' found.\n", filename.c_str()); - return; - } - - unsigned len = noiseTileSize * noiseTileSize * noiseTileSize; - if (fwrite((void*)noiseTileData, sizeof(float), len, file) != len) errFatal("saveTile","fwrite failed", SIMWORLD_INITERROR); - fclose(file); - - printf("saveTile: Noise tile file saved.\n"); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// create a new noise tile if necessary -////////////////////////////////////////////////////////////////////////////////////////// -static void GenerateNoiseTile(float* const noiseTileData, std::string filename) { - // if a tile already exists, just use that - if (loadTile(noiseTileData, filename)) return; - - const int n = noiseTileSize; - const int n3 = n*n*n; - std::cout <<"Generating new 3d noise tile size="<<n<<"^3 \n"; - //MTRand twister; - DDF::RandomStream randStream = DDF::RandomStream(13322223); - DDF::RandomStream randStream2 = DDF::RandomStream(1238201283); - - float *temp13 = new float[n3]; - float *temp23 = new float[n3]; - float *noise3 = new float[n3]; - - // initialize - for (int i = 0; i < n3; i++) { - temp13[i] = temp23[i] = - noise3[i] = 0.; - } - - // Step 1. Fill the tile with random numbers in the range -1 to 1. - for (int i = 0; i < n3; i++) { - //noise3[i] = twister.randNorm(); - noise3[i] = (randStream.getFloat() + randStream2.getFloat()) -1.; // produces repeated values?? - noise3[i] = (randStream.getFloat() + randStream2.getFloat()) -1.; - } - - // Steps 2 and 3. Downsample and upsample the tile - for (int iy = 0; iy < n; iy++) - for (int iz = 0; iz < n; iz++) { - const int i = iy * n + iz*n*n; - 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; - 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; - 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 < n3; i++) { - noise3[i] -= temp23[i]; - } - - // Avoid even/odd variance difference by adding odd-offset version of noise to itself. - int offset = n / 2; - if (offset % 2 == 0) offset++; - - int icnt=0; - for (int ix = 0; ix < n; ix++) - for (int iy = 0; iy < n; iy++) - for (int iz = 0; iz < n; iz++) { - temp13[icnt] = noise3[modFast128(ix+offset) + modFast128(iy+offset)*n + modFast128(iz+offset)*n*n]; - icnt++; - } - - for (int i = 0; i < n3; i++) { - noise3[i] += temp13[i]; - } - - for (int i = 0; i < n3; i++) { - noiseTileData[i] = noise3[i]; - } - saveTile(noise3, filename); - - delete[] temp13; - delete[] temp23; - std::cout <<"Generating new 3d noise done\n"; -} - - -#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 -////////////////////////////////////////////////////////////////////////////////////////// -static inline float WNoiseDx(Vec3 p, float *data) { - float 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; - float 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; -} - -static inline float WNoise(Vec3 p, float *data) { - float 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 * 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)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; - float 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 -////////////////////////////////////////////////////////////////////////////////////////// -static inline Vec3 WNoiseVec(const Vec3& p, float *data) -{ - Vec3 final(0.); - float w[3][3]; - float dw[3][3]; - float result = 0; - int xC, yC, zC; - float 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); - - float t0 = midX - (p[0] - 0.5f); - float t1 = midY - (p[1] - 0.5f); - float t2 = midZ - (p[2] - 0.5f); - - // precache all the neighbors for fast access - float 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 - - -//***************************************************************************** -static bool loadStdTile() -{ - if(!DDF::stdTileData) { - DDF::stdTileData = new float[NOISE_TILE_SIZE * NOISE_TILE_SIZE * NOISE_TILE_SIZE]; - } - GenerateNoiseTile(DDF::stdTileData, stdTileName); - return true; -} - -static void freeStdTile() -{ - if(DDF::stdTileData) { - delete [] DDF::stdTileData; - } -} - -static inline float getWNoise(Vec3 p) { -#ifdef DDF_DEBUG -#if DDF_DEBUG==1 - if(!DDF::stdTileData) { - fprintf(stderr,"waveletnoise.h: Fatal, noise not inited!\n"); - exit(1); - } -#endif // DDF_DEBUG==1 -#endif // DDF_DEBUG - return WNoise(p, DDF::stdTileData); -} - -static inline Vec3 getWNoiseVec(Vec3 p) { -#ifdef DDF_DEBUG -#if DDF_DEBUG==1 - if(!DDF::stdTileData) { - fprintf(stderr,"waveletnoise.h: Fatal, noise not inited!\n"); - exit(1); - } -#endif // DDF_DEBUG==1 -#endif // DDF_DEBUG - return WNoiseVec(p, DDF::stdTileData); -} - - -// wrapper for a parametrized field of wavelet noise -class WaveletNoiseField { - public: - WaveletNoiseField(std::string name, const ParamSet ¶ms, nVec3i gridsize) : - mName(name), - mPosOffset(0.), mPosScale(1.), - mValOffset(0.), mValScale(1.), - mClamp(false), mClampNeg(0.), mClampPos(1.), - mTimeAnim(0.) , mTime(0.) - { - - // init params - mPosOffset = params.FindOneVector("pos-offset", mPosOffset ); - mPosScale = params.FindOneVector("pos-scale", mPosScale ); - - mValOffset = params.FindOneFloat("val-offset", mValOffset ); - mValScale = params.FindOneFloat("val-scale", mValScale ); - - mClamp = params.FindOneBool("clamp", mClamp ); - mClampNeg = params.FindOneFloat("clamp-neg", mClampNeg ); - mClampPos = params.FindOneFloat("clamp-pos", mClampPos ); - - mTimeAnim = params.FindOneFloat("time-anim", mTimeAnim ); - - // init inv grid size - mGsInvX = 1. /(Real)gridsize[0]; - mGsInvY = 1. /(Real)gridsize[1]; - mGsInvZ = 1. /(Real)gridsize[2]; - - if(!loadStdTile()) { - errFatal("WaveletNoiseField::WaveletNoiseField","Failed to laod/generate tile! Aborting...", SIMWORLD_INITERROR); - exit(1); - } - debMsg("WaveletNoiseField","Created "<<this->toString() ); - }; - ~WaveletNoiseField() {}; - - //! evaluate noise - inline Real evaluate(Vec3 pos) { - pos[0] *= mGsInvX; - pos[1] *= mGsInvY; - pos[2] *= mGsInvZ; - - // time anim - pos += Vec3(mTime); - - pos[0] *= mPosScale[0]; - pos[1] *= mPosScale[1]; - pos[2] *= mPosScale[2]; - pos += mPosOffset; - - Real v = getWNoise(pos); - - v += mValOffset; - v *= mValScale; - if (mClamp) { - if (v< mClampNeg) v = mClampNeg; - if (v> mClampPos) v = mClampPos; - } - return v; - } - - //! evaluate noise as a vector - inline Vec3 evaluateVec(Vec3 pos) { - pos[0] *= mGsInvX; - pos[1] *= mGsInvY; - pos[2] *= mGsInvZ; - - // time anim - pos += Vec3(mTime); - - pos[0] *= mPosScale[0]; - pos[1] *= mPosScale[1]; - pos[2] *= mPosScale[2]; - pos += mPosOffset; - - Vec3 v = getWNoiseVec(pos); - - 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; - } - - // increase time - void increaseTime(Real dt) { mTime += dt * mTimeAnim; } - - //! helper - std::string 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 ="<<PRINT_VEC(mGsInvX,mGsInvY,mGsInvZ) ; - return out.str(); - } - - Real getTimeAnim() { return mTimeAnim; } - void setTimeAnim(Real set) { mTimeAnim = set; } - - protected: - - //! name - std::string mName; - //! texcoord position and scale - Vec3 mPosOffset, mPosScale; - //! value offset & scale - Real mValOffset, mValScale; - //! clamp? (default 0-1) - bool mClamp; - Real mClampNeg, mClampPos; - // grid size normalization (inverse size) - Real mGsInvX, mGsInvY, mGsInvZ; - // animation over time - Real mTimeAnim, mTime; -}; - - -} // namespace WAVELETNOISE - |