Blender  V3.3
fluid_script.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2016 Blender Foundation. All rights reserved. */
3 
8 #include <string>
9 
11 // LIBRARIES
13 
14 const std::string manta_import =
15  "\
16 from manta import *\n\
17 from math import inf\n\
18 import os.path, shutil, math, sys, gc, multiprocessing, platform, time\n\
19 \n\
20 withMPBake = False # Bake files asynchronously\n\
21 withMPSave = False # Save files asynchronously\n\
22 isWindows = platform.system() != 'Darwin' and platform.system() != 'Linux'\n\
23 # TODO(sebbas): Use this to simulate Windows multiprocessing (has default mode spawn)\n\
24 #try:\n\
25 # multiprocessing.set_start_method('spawn')\n\
26 #except:\n\
27 # pass\n";
28 
30 // DEBUG
32 
33 const std::string manta_debuglevel =
34  "\n\
35 def set_manta_debuglevel(level):\n\
36  setDebugLevel(level=level)\n # level 0 = mute all output from manta\n";
37 
39 // SOLVERS
41 
42 const std::string fluid_solver =
43  "\n\
44 mantaMsg('Solver base')\n\
45 s$ID$ = Solver(name='solver_base$ID$', gridSize=gs_s$ID$, dim=dim_s$ID$)\n";
46 
47 const std::string fluid_solver_noise =
48  "\n\
49 mantaMsg('Solver noise')\n\
50 sn$ID$ = Solver(name='solver_noise$ID$', gridSize=gs_sn$ID$)\n";
51 
52 const std::string fluid_solver_mesh =
53  "\n\
54 mantaMsg('Solver mesh')\n\
55 sm$ID$ = Solver(name='solver_mesh$ID$', gridSize=gs_sm$ID$)\n";
56 
57 const std::string fluid_solver_particles =
58  "\n\
59 mantaMsg('Solver particles')\n\
60 sp$ID$ = Solver(name='solver_particles$ID$', gridSize=gs_sp$ID$)\n";
61 
62 const std::string fluid_solver_guiding =
63  "\n\
64 mantaMsg('Solver guiding')\n\
65 sg$ID$ = Solver(name='solver_guiding$ID$', gridSize=gs_sg$ID$)\n";
66 
67 const std::string fluid_solver_viscosity =
68  "\n\
69 mantaMsg('Solver viscosity')\n\
70 sv$ID$ = Solver(name='solver_viscosity$ID$', gridSize=gs_sv$ID$, dim=dim_s$ID$)\n";
71 
73 // VARIABLES
75 
76 const std::string fluid_variables =
77  "\n\
78 mantaMsg('Fluid variables')\n\
79 dim_s$ID$ = $SOLVER_DIM$\n\
80 res_s$ID$ = $RES$\n\
81 gravity_s$ID$ = vec3($GRAVITY_X$, $GRAVITY_Y$, $GRAVITY_Z$) # in SI unit (e.g. m/s^2)\n\
82 gs_s$ID$ = vec3($RESX$, $RESY$, $RESZ$)\n\
83 maxVel_s$ID$ = 0\n\
84 \n\
85 domainClosed_s$ID$ = $DOMAIN_CLOSED$\n\
86 boundConditions_s$ID$ = '$BOUND_CONDITIONS$'\n\
87 boundaryWidth_s$ID$ = $BOUNDARY_WIDTH$\n\
88 deleteInObstacle_s$ID$ = $DELETE_IN_OBSTACLE$\n\
89 \n\
90 using_smoke_s$ID$ = $USING_SMOKE$\n\
91 using_liquid_s$ID$ = $USING_LIQUID$\n\
92 using_noise_s$ID$ = $USING_NOISE$\n\
93 using_adaptTime_s$ID$ = $USING_ADAPTIVETIME$\n\
94 using_obstacle_s$ID$ = $USING_OBSTACLE$\n\
95 using_guiding_s$ID$ = $USING_GUIDING$\n\
96 using_fractions_s$ID$ = $USING_FRACTIONS$\n\
97 using_invel_s$ID$ = $USING_INVEL$\n\
98 using_outflow_s$ID$ = $USING_OUTFLOW$\n\
99 using_sndparts_s$ID$ = $USING_SNDPARTS$\n\
100 using_speedvectors_s$ID$ = $USING_SPEEDVECTORS$\n\
101 using_diffusion_s$ID$ = $USING_DIFFUSION$\n\
102 \n\
103 # Fluid time params\n\
104 timeScale_s$ID$ = $TIME_SCALE$\n\
105 timeTotal_s$ID$ = $TIME_TOTAL$\n\
106 timePerFrame_s$ID$ = $TIME_PER_FRAME$\n\
107 \n\
108 # In Blender fluid.c: frame_length = DT_DEFAULT * (25.0 / fps) * time_scale\n\
109 # with DT_DEFAULT = 0.1\n\
110 frameLength_s$ID$ = $FRAME_LENGTH$\n\
111 frameLengthUnscaled_s$ID$ = frameLength_s$ID$ / timeScale_s$ID$\n\
112 frameLengthRaw_s$ID$ = 0.1 * 25 # dt = 0.1 at 25 fps\n\
113 \n\
114 dt0_s$ID$ = $DT$\n\
115 cflCond_s$ID$ = $CFL$\n\
116 timestepsMin_s$ID$ = $TIMESTEPS_MIN$\n\
117 timestepsMax_s$ID$ = $TIMESTEPS_MAX$\n\
118 \n\
119 # Start and stop for simulation\n\
120 current_frame_s$ID$ = $CURRENT_FRAME$\n\
121 start_frame_s$ID$ = $START_FRAME$\n\
122 end_frame_s$ID$ = $END_FRAME$\n\
123 \n\
124 # Fluid diffusion / viscosity\n\
125 domainSize_s$ID$ = $FLUID_DOMAIN_SIZE$ # longest domain side in meters\n\
126 kinViscosity_s$ID$ = $FLUID_VISCOSITY$ / (domainSize_s$ID$*domainSize_s$ID$) # kinematic viscosity in m^2/s\n\
127 \n\
128 # Factors to convert Blender units to Manta units\n\
129 ratioMetersToRes_s$ID$ = float(domainSize_s$ID$) / float(res_s$ID$) # [meters / cells]\n\
130 mantaMsg('1 Mantaflow cell is ' + str(ratioMetersToRes_s$ID$) + ' Blender length units long.')\n\
131 \n\
132 ratioResToBLength_s$ID$ = float(res_s$ID$) / float(domainSize_s$ID$) # [cells / blength] (blength: cm, m, or km, ... )\n\
133 mantaMsg('1 Blender length unit is ' + str(ratioResToBLength_s$ID$) + ' Mantaflow cells long.')\n\
134 \n\
135 ratioBTimeToTimestep_s$ID$ = float(1) / float(frameLengthRaw_s$ID$) # the time within 1 blender time unit, see also fluid.c\n\
136 mantaMsg('1 Blender time unit is ' + str(ratioBTimeToTimestep_s$ID$) + ' Mantaflow time units long.')\n\
137 \n\
138 ratioFrameToFramelength_s$ID$ = float(1) / float(frameLengthUnscaled_s$ID$ ) # the time within 1 frame\n\
139 mantaMsg('frame / frameLength is ' + str(ratioFrameToFramelength_s$ID$) + ' Mantaflow time units long.')\n\
140 \n\
141 scaleAcceleration_s$ID$ = ratioResToBLength_s$ID$ * (ratioBTimeToTimestep_s$ID$**2)# [meters/btime^2] to [cells/timestep^2] (btime: sec, min, or h, ...)\n\
142 mantaMsg('scaleAcceleration is ' + str(scaleAcceleration_s$ID$))\n\
143 \n\
144 scaleSpeedFrames_s$ID$ = ratioResToBLength_s$ID$ * ratioFrameToFramelength_s$ID$ # [blength/frame] to [cells/frameLength]\n\
145 mantaMsg('scaleSpeed is ' + str(scaleSpeedFrames_s$ID$))\n\
146 \n\
147 gravity_s$ID$ *= scaleAcceleration_s$ID$ # scale from world acceleration to cell based acceleration\n\
148 \n\
149 # OpenVDB options\n\
150 vdbCompression_s$ID$ = $COMPRESSION_OPENVDB$\n\
151 vdbPrecision_s$ID$ = $PRECISION_OPENVDB$\n\
152 vdbClip_s$ID$ = $CLIP_OPENVDB$\n\
153 \n\
154 # Cache file names\n\
155 file_data_s$ID$ = '$NAME_DATA$'\n\
156 file_noise_s$ID$ = '$NAME_NOISE$'\n\
157 file_mesh_s$ID$ = '$NAME_MESH$'\n\
158 file_meshvel_s$ID$ = '$NAME_MESH$'\n\
159 file_particles_s$ID$ = '$NAME_PARTICLES$'\n\
160 file_guiding_s$ID$ = '$NAME_GUIDING$'";
161 
162 const std::string fluid_variables_noise =
163  "\n\
164 mantaMsg('Fluid variables noise')\n\
165 upres_sn$ID$ = $NOISE_SCALE$\n\
166 gs_sn$ID$ = vec3(upres_sn$ID$*gs_s$ID$.x, upres_sn$ID$*gs_s$ID$.y, upres_sn$ID$*gs_s$ID$.z)\n";
167 
168 const std::string fluid_variables_mesh =
169  "\n\
170 mantaMsg('Fluid variables mesh')\n\
171 upres_sm$ID$ = $MESH_SCALE$\n\
172 gs_sm$ID$ = vec3(upres_sm$ID$*gs_s$ID$.x, upres_sm$ID$*gs_s$ID$.y, upres_sm$ID$*gs_s$ID$.z)\n";
173 
174 const std::string fluid_variables_particles =
175  "\n\
176 mantaMsg('Fluid variables particles')\n\
177 upres_sp$ID$ = $PARTICLE_SCALE$\n\
178 gs_sp$ID$ = vec3(upres_sp$ID$*gs_s$ID$.x, upres_sp$ID$*gs_s$ID$.y, upres_sp$ID$*gs_s$ID$.z)\n";
179 
180 const std::string fluid_variables_guiding =
181  "\n\
182 mantaMsg('Fluid variables guiding')\n\
183 gs_sg$ID$ = vec3($GUIDING_RESX$, $GUIDING_RESY$, $GUIDING_RESZ$)\n\
184 \n\
185 alpha_sg$ID$ = $GUIDING_ALPHA$\n\
186 beta_sg$ID$ = $GUIDING_BETA$\n\
187 gamma_sg$ID$ = $GUIDING_FACTOR$\n\
188 tau_sg$ID$ = 1.0\n\
189 sigma_sg$ID$ = 0.99/tau_sg$ID$\n\
190 theta_sg$ID$ = 1.0\n";
191 
192 const std::string fluid_variables_viscosity =
193  "\n\
194 gs_sv$ID$ = vec3($RESX$*2, $RESY$*2, $RESZ$*2)\n";
195 
196 const std::string fluid_with_obstacle =
197  "\n\
198 using_obstacle_s$ID$ = True\n";
199 
200 const std::string fluid_with_guiding =
201  "\n\
202 using_guiding_s$ID$ = True\n";
203 
204 const std::string fluid_with_fractions =
205  "\n\
206 using_fractions_s$ID$ = True\n";
207 
208 const std::string fluid_with_invel =
209  "\n\
210 using_invel_s$ID$ = True\n";
211 
212 const std::string fluid_with_outflow =
213  "\n\
214 using_outflow_s$ID$ = True\n";
215 
216 const std::string fluid_with_sndparts =
217  "\n\
218 using_sndparts_s$ID$ = True\n";
219 
221 // ADAPTIVE TIME STEPPING
223 
224 const std::string fluid_time_stepping =
225  "\n\
226 mantaMsg('Fluid adaptive time stepping')\n\
227 s$ID$.frameLength = frameLength_s$ID$\n\
228 s$ID$.timestepMin = s$ID$.frameLength / max(1, timestepsMax_s$ID$)\n\
229 s$ID$.timestepMax = s$ID$.frameLength / max(1, timestepsMin_s$ID$)\n\
230 s$ID$.cfl = cflCond_s$ID$\n\
231 s$ID$.timePerFrame = timePerFrame_s$ID$\n\
232 s$ID$.timestep = dt0_s$ID$\n\
233 s$ID$.timeTotal = timeTotal_s$ID$\n\
234 #mantaMsg('timestep: ' + str(s$ID$.timestep) + ' // timPerFrame: ' + str(s$ID$.timePerFrame) + ' // frameLength: ' + str(s$ID$.frameLength) + ' // timeTotal: ' + str(s$ID$.timeTotal) )\n";
235 
236 const std::string fluid_adapt_time_step =
237  "\n\
238 def fluid_adapt_time_step_$ID$():\n\
239  mantaMsg('Fluid adapt time step')\n\
240  \n\
241  # time params are animatable\n\
242  s$ID$.frameLength = frameLength_s$ID$\n\
243  s$ID$.cfl = cflCond_s$ID$\n\
244  s$ID$.timestepMin = s$ID$.frameLength / max(1, timestepsMax_s$ID$)\n\
245  s$ID$.timestepMax = s$ID$.frameLength / max(1, timestepsMin_s$ID$)\n\
246  \n\
247  # ensure that vel grid is full (remember: adaptive domain can reallocate solver)\n\
248  copyRealToVec3(sourceX=x_vel_s$ID$, sourceY=y_vel_s$ID$, sourceZ=z_vel_s$ID$, target=vel_s$ID$)\n\
249  maxVel_s$ID$ = vel_s$ID$.getMax() if vel_s$ID$ else 0\n\
250  if using_adaptTime_s$ID$:\n\
251  mantaMsg('Adapt timestep, maxvel: ' + str(maxVel_s$ID$))\n\
252  s$ID$.adaptTimestep(maxVel_s$ID$)\n";
253 
255 // GRIDS
257 
258 const std::string fluid_alloc =
259  "\n\
260 mantaMsg('Fluid alloc data')\n\
261 flags_s$ID$ = s$ID$.create(FlagGrid, name='$NAME_FLAGS$')\n\
262 vel_s$ID$ = s$ID$.create(MACGrid, name='$NAME_VELOCITY$', sparse=True)\n\
263 velTmp_s$ID$ = s$ID$.create(MACGrid, name='$NAME_VELOCITYTMP$', sparse=True)\n\
264 x_vel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_VELOCITY_X$')\n\
265 y_vel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_VELOCITY_Y$')\n\
266 z_vel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_VELOCITY_Z$')\n\
267 pressure_s$ID$ = s$ID$.create(RealGrid, name='$NAME_PRESSURE$')\n\
268 phiObs_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHIOBS$')\n\
269 phiSIn_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHISIN$') # helper for static flow objects\n\
270 phiIn_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHIIN$')\n\
271 phiOut_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHIOUT$')\n\
272 forces_s$ID$ = s$ID$.create(Vec3Grid, name='$NAME_FORCES$')\n\
273 x_force_s$ID$ = s$ID$.create(RealGrid, name='$NAME_FORCES_X$')\n\
274 y_force_s$ID$ = s$ID$.create(RealGrid, name='$NAME_FORCES_Y$')\n\
275 z_force_s$ID$ = s$ID$.create(RealGrid, name='$NAME_FORCES_Z$')\n\
276 obvel_s$ID$ = None\n\
277 \n\
278 # Set some initial values\n\
279 phiObs_s$ID$.setConst(9999)\n\
280 phiSIn_s$ID$.setConst(9999)\n\
281 phiIn_s$ID$.setConst(9999)\n\
282 phiOut_s$ID$.setConst(9999)\n\
283 \n\
284 # Keep track of important objects in dict to load them later on\n\
285 fluid_data_dict_final_s$ID$ = { 'vel' : vel_s$ID$ }\n\
286 fluid_data_dict_resume_s$ID$ = { 'phiObs' : phiObs_s$ID$, 'phiIn' : phiIn_s$ID$, 'phiOut' : phiOut_s$ID$, 'flags' : flags_s$ID$, 'velTmp' : velTmp_s$ID$ }\n";
287 
288 const std::string fluid_alloc_obstacle =
289  "\n\
290 mantaMsg('Allocating obstacle data')\n\
291 numObs_s$ID$ = s$ID$.create(RealGrid, name='$NAME_NUMOBS$')\n\
292 phiObsSIn_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHIOBSSIN$') # helper for static obstacle objects\n\
293 phiObsIn_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHIOBSIN$')\n\
294 obvel_s$ID$ = s$ID$.create(MACGrid, name='$NAME_OBVEL$')\n\
295 obvelC_s$ID$ = s$ID$.create(Vec3Grid, name='$NAME_OBVELC$')\n\
296 x_obvel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_OBVEL_X$')\n\
297 y_obvel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_OBVEL_Y$')\n\
298 z_obvel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_OBVEL_Z$')\n\
299 \n\
300 # Set some initial values\n\
301 phiObsSIn_s$ID$.setConst(9999)\n\
302 phiObsIn_s$ID$.setConst(9999)\n\
303 \n\
304 if 'fluid_data_dict_resume_s$ID$' in globals():\n\
305  fluid_data_dict_resume_s$ID$.update(phiObsIn=phiObsIn_s$ID$)\n";
306 
307 const std::string fluid_alloc_guiding =
308  "\n\
309 mantaMsg('Allocating guiding data')\n\
310 velT_s$ID$ = s$ID$.create(MACGrid, name='$NAME_VELT$')\n\
311 weightGuide_s$ID$ = s$ID$.create(RealGrid, name='$NAME_WEIGHTGUIDE$')\n\
312 numGuides_s$ID$ = s$ID$.create(RealGrid, name='$NAME_NUMGUIDES$')\n\
313 phiGuideIn_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHIGUIDEIN$')\n\
314 guidevelC_s$ID$ = s$ID$.create(Vec3Grid, name='$NAME_GUIDEVELC$')\n\
315 x_guidevel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_GUIDEVEL_X$')\n\
316 y_guidevel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_GUIDEVEL_Y$')\n\
317 z_guidevel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_GUIDEVEL_Z$')\n\
318 \n\
319 # Final guide vel grid needs to have independent size\n\
320 guidevel_sg$ID$ = sg$ID$.create(MACGrid, name='$NAME_VELOCITY_GUIDE$')\n\
321 \n\
322 # Keep track of important objects in dict to load them later on\n\
323 fluid_guiding_dict_s$ID$ = { 'guidevel' : guidevel_sg$ID$ }\n";
324 
325 const std::string fluid_alloc_fractions =
326  "\n\
327 mantaMsg('Allocating fractions data')\n\
328 fractions_s$ID$ = s$ID$.create(MACGrid, name='$NAME_FRACTIONS$')\n";
329 
330 const std::string fluid_alloc_invel =
331  "\n\
332 mantaMsg('Allocating initial velocity data')\n\
333 invelC_s$ID$ = s$ID$.create(VecGrid, name='$NAME_INVELC$')\n\
334 x_invel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_INVEL_X$')\n\
335 y_invel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_INVEL_Y$')\n\
336 z_invel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_INVEL_Z$')\n";
337 
338 const std::string fluid_alloc_outflow =
339  "\n\
340 mantaMsg('Allocating outflow data')\n\
341 phiOutSIn_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHIOUTSIN$') # helper for static outflow objects\n\
342 phiOutIn_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHIOUTIN$')\n\
343 \n\
344 # Set some initial values\n\
345 phiOutSIn_s$ID$.setConst(9999)\n\
346 phiOutIn_s$ID$.setConst(9999)\n\
347 \n\
348 if 'fluid_data_dict_resume_s$ID$' in globals():\n\
349  fluid_data_dict_resume_s$ID$.update(phiOutIn=phiOutIn_s$ID$)\n";
350 
352 // PRE / POST STEP
354 
355 const std::string fluid_pre_step =
356  "\n\
357 def fluid_pre_step_$ID$():\n\
358  mantaMsg('Fluid pre step')\n\
359  \n\
360  phiObs_s$ID$.setConst(9999)\n\
361  phiOut_s$ID$.setConst(9999)\n\
362  \n\
363  # Main vel grid is copied in adapt time step function\n\
364  \n\
365  if using_obstacle_s$ID$:\n\
366  # Average out velocities from multiple obstacle objects at one cell\n\
367  x_obvel_s$ID$.safeDivide(numObs_s$ID$)\n\
368  y_obvel_s$ID$.safeDivide(numObs_s$ID$)\n\
369  z_obvel_s$ID$.safeDivide(numObs_s$ID$)\n\
370  copyRealToVec3(sourceX=x_obvel_s$ID$, sourceY=y_obvel_s$ID$, sourceZ=z_obvel_s$ID$, target=obvelC_s$ID$)\n\
371  \n\
372  if using_invel_s$ID$:\n\
373  copyRealToVec3(sourceX=x_invel_s$ID$, sourceY=y_invel_s$ID$, sourceZ=z_invel_s$ID$, target=invelC_s$ID$)\n\
374  \n\
375  if using_guiding_s$ID$:\n\
376  weightGuide_s$ID$.multConst(0)\n\
377  weightGuide_s$ID$.addConst(alpha_sg$ID$)\n\
378  interpolateMACGrid(source=guidevel_sg$ID$, target=velT_s$ID$)\n\
379  velT_s$ID$.multConst(vec3(gamma_sg$ID$))\n\
380  \n\
381  x_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
382  y_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
383  z_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
384  copyRealToVec3(sourceX=x_force_s$ID$, sourceY=y_force_s$ID$, sourceZ=z_force_s$ID$, target=forces_s$ID$)\n\
385  \n\
386  # If obstacle has velocity, i.e. is a moving obstacle, switch to dynamic preconditioner\n\
387  if using_smoke_s$ID$ and using_obstacle_s$ID$ and obvelC_s$ID$.getMax() > 0:\n\
388  mantaMsg('Using dynamic preconditioner')\n\
389  preconditioner_s$ID$ = PcMGDynamic\n\
390  else:\n\
391  mantaMsg('Using static preconditioner')\n\
392  preconditioner_s$ID$ = PcMGStatic\n";
393 
394 const std::string fluid_post_step =
395  "\n\
396 def fluid_post_step_$ID$():\n\
397  mantaMsg('Fluid post step')\n\
398  \n\
399  # Copy vel grid to reals grids (which Blender internal will in turn use for vel access)\n\
400  copyVec3ToReal(source=vel_s$ID$, targetX=x_vel_s$ID$, targetY=y_vel_s$ID$, targetZ=z_vel_s$ID$)\n\
401  if using_guiding_s$ID$:\n\
402  copyVec3ToReal(source=guidevel_sg$ID$, targetX=x_guidevel_s$ID$, targetY=y_guidevel_s$ID$, targetZ=z_guidevel_s$ID$)\n";
403 
405 // DESTRUCTION
407 
408 const std::string fluid_delete_all =
409  "\n\
410 mantaMsg('Deleting fluid')\n\
411 # Clear all helper dictionaries first\n\
412 mantaMsg('Clear helper dictionaries')\n\
413 if 'liquid_data_dict_final_s$ID$' in globals(): liquid_data_dict_final_s$ID$.clear()\n\
414 if 'liquid_data_dict_resume_s$ID$' in globals(): liquid_data_dict_resume_s$ID$.clear()\n\
415 if 'liquid_mesh_dict_s$ID$' in globals(): liquid_mesh_dict_s$ID$.clear()\n\
416 if 'liquid_meshvel_dict_s$ID$' in globals(): liquid_meshvel_dict_s$ID$.clear()\n\
417 if 'liquid_particles_final_dict_s$ID$' in globals(): liquid_particles_final_dict_s$ID$.clear()\n\
418 if 'liquid_particles_resume_dict_s$ID$' in globals(): liquid_particles_resume_dict_s$ID$.clear()\n\
419 \n\
420 if 'smoke_data_dict_final_s$ID$' in globals(): smoke_data_dict_final_s$ID$.clear()\n\
421 if 'smoke_data_dict_resume_s$ID$' in globals(): smoke_data_dict_resume_s$ID$.clear()\n\
422 if 'smoke_noise_dict_final_s$ID$' in globals(): smoke_noise_dict_final_s$ID$.clear()\n\
423 if 'smoke_noise_dict_resume_s$ID$' in globals(): smoke_noise_dict_resume_s$ID$.clear()\n\
424 \n\
425 if 'fluid_data_dict_final_s$ID$' in globals(): fluid_data_dict_final_s$ID$.clear()\n\
426 if 'fluid_data_dict_resume_s$ID$' in globals(): fluid_data_dict_resume_s$ID$.clear()\n\
427 if 'fluid_guiding_dict_s$ID$' in globals(): fluid_guiding_dict_s$ID$.clear()\n\
428 if 'fluid_vel_dict_s$ID$' in globals(): fluid_vel_dict_s$ID$.clear()\n\
429 \n\
430 # Delete all children from objects (e.g. pdata for particles)\n\
431 mantaMsg('Release solver childrens children')\n\
432 for var in list(globals()):\n\
433  if var.endswith('_pp$ID$') or var.endswith('_mesh$ID$'):\n\
434  del globals()[var]\n\
435 \n\
436 # Now delete children from solver objects\n\
437 mantaMsg('Release solver children')\n\
438 for var in list(globals()):\n\
439  if var.endswith('_s$ID$') or var.endswith('_sn$ID$') or var.endswith('_sm$ID$') or var.endswith('_sp$ID$') or var.endswith('_sg$ID$'):\n\
440  del globals()[var]\n\
441 \n\
442 # Extra cleanup for multigrid and fluid guiding\n\
443 mantaMsg('Release multigrid')\n\
444 if 's$ID$' in globals(): releaseMG(s$ID$)\n\
445 if 'sn$ID$' in globals(): releaseMG(sn$ID$)\n\
446 mantaMsg('Release fluid guiding')\n\
447 releaseBlurPrecomp()\n\
448 \n\
449 # Release unreferenced memory (if there is some left, can in fact happen)\n\
450 gc.collect()\n\
451 \n\
452 # Now it is safe to delete solver objects (always need to be deleted last)\n\
453 mantaMsg('Delete base solver')\n\
454 if 's$ID$' in globals(): del s$ID$\n\
455 mantaMsg('Delete noise solver')\n\
456 if 'sn$ID$' in globals(): del sn$ID$\n\
457 mantaMsg('Delete mesh solver')\n\
458 if 'sm$ID$' in globals(): del sm$ID$\n\
459 mantaMsg('Delete particle solver')\n\
460 if 'sp$ID$' in globals(): del sp$ID$\n\
461 mantaMsg('Delete guiding solver')\n\
462 if 'sg$ID$' in globals(): del sg$ID$\n\
463 \n\
464 # Release unreferenced memory (if there is some left)\n\
465 gc.collect()\n";
466 
468 // BAKE
470 
471 /* This has to match the behavior of BLI_path_frame,
472  * for positive and negative frame numbers. */
473 const std::string fluid_cache_helper =
474  "\n\
475 def fluid_cache_get_framenr_formatted_$ID$(framenr):\n\
476  return str(framenr).zfill(4) if framenr >= 0 else str(framenr).zfill(5)\n";
477 
478 const std::string fluid_bake_multiprocessing =
479  "\n\
480 def fluid_cache_multiprocessing_start_$ID$(function, framenr, file_name=None, format_data=None, format_noise=None, format_mesh=None, format_particles=None, format_guiding=None, path_data=None, path_noise=None, path_mesh=None, path_particles=None, path_guiding=None, dict=None, do_join=True, resumable=False):\n\
481  mantaMsg('Multiprocessing cache')\n\
482  if __name__ == '__main__':\n\
483  args = (framenr,)\n\
484  if file_name:\n\
485  args += (file_name,)\n\
486  if format_data:\n\
487  args += (format_data,)\n\
488  if format_noise:\n\
489  args += (format_noise,)\n\
490  if format_mesh:\n\
491  args += (format_mesh,)\n\
492  if format_particles:\n\
493  args += (format_particles,)\n\
494  if format_guiding:\n\
495  args += (format_guiding,)\n\
496  if path_data:\n\
497  args += (path_data,)\n\
498  if path_noise:\n\
499  args += (path_noise,)\n\
500  if path_mesh:\n\
501  args += (path_mesh,)\n\
502  if path_particles:\n\
503  args += (path_particles,)\n\
504  if path_guiding:\n\
505  args += (path_guiding,)\n\
506  if dict:\n\
507  args += (dict,)\n\
508  args += (resumable,)\n\
509  p$ID$ = multiprocessing.Process(target=function, args=args)\n\
510  p$ID$.start()\n\
511  if do_join:\n\
512  p$ID$.join()\n";
513 
514 const std::string fluid_bake_data =
515  "\n\
516 def bake_fluid_process_data_$ID$(framenr, format_data, path_data):\n\
517  mantaMsg('Bake fluid data')\n\
518  \n\
519  s$ID$.frame = framenr\n\
520  s$ID$.frameLength = frameLength_s$ID$\n\
521  s$ID$.timeTotal = timeTotal_s$ID$\n\
522  \n\
523  start_time = time.time()\n\
524  if using_smoke_s$ID$:\n\
525  smoke_adaptive_step_$ID$(framenr)\n\
526  if using_liquid_s$ID$:\n\
527  liquid_adaptive_step_$ID$(framenr)\n\
528  mantaMsg('--- Step: %s seconds ---' % (time.time() - start_time))\n\
529 \n\
530 def bake_fluid_data_$ID$(path_data, framenr, format_data):\n\
531  if not withMPBake or isWindows:\n\
532  bake_fluid_process_data_$ID$(framenr, format_data, path_data)\n\
533  else:\n\
534  fluid_cache_multiprocessing_start_$ID$(function=bake_fluid_process_data_$ID$, framenr=framenr, format_data=format_data, path_data=path_data, do_join=False)\n";
535 
536 const std::string fluid_bake_noise =
537  "\n\
538 def bake_noise_process_$ID$(framenr, format_noise, path_noise):\n\
539  mantaMsg('Bake fluid noise')\n\
540  \n\
541  sn$ID$.frame = framenr\n\
542  sn$ID$.frameLength = frameLength_s$ID$\n\
543  sn$ID$.timeTotal = timeTotal_s$ID$\n\
544  sn$ID$.timestep = frameLength_s$ID$ # no adaptive timestep for noise\n\
545  \n\
546  smoke_step_noise_$ID$(framenr)\n\
547 \n\
548 def bake_noise_$ID$(path_noise, framenr, format_noise):\n\
549  if not withMPBake or isWindows:\n\
550  bake_noise_process_$ID$(framenr, format_noise, path_noise)\n\
551  else:\n\
552  fluid_cache_multiprocessing_start_$ID$(function=bake_noise_process_$ID$, framenr=framenr, format_noise=format_noise, path_noise=path_noise)\n";
553 
554 const std::string fluid_bake_mesh =
555  "\n\
556 def bake_mesh_process_$ID$(framenr, format_data, format_mesh, path_mesh):\n\
557  mantaMsg('Bake fluid mesh')\n\
558  \n\
559  sm$ID$.frame = framenr\n\
560  sm$ID$.frameLength = frameLength_s$ID$\n\
561  sm$ID$.timeTotal = timeTotal_s$ID$\n\
562  sm$ID$.timestep = frameLength_s$ID$ # no adaptive timestep for mesh\n\
563  \n\
564  #if using_smoke_s$ID$:\n\
565  # TODO(sebbas): Future update could include smoke mesh (vortex sheets)\n\
566  if using_liquid_s$ID$:\n\
567  liquid_step_mesh_$ID$()\n\
568  liquid_save_mesh_$ID$(path_mesh, framenr, format_mesh)\n\
569  if using_speedvectors_s$ID$:\n\
570  liquid_save_meshvel_$ID$(path_mesh, framenr, format_data)\n\
571 \n\
572 def bake_mesh_$ID$(path_mesh, framenr, format_data, format_mesh):\n\
573  if not withMPBake or isWindows:\n\
574  bake_mesh_process_$ID$(framenr, format_data, format_mesh, path_mesh)\n\
575  else:\n\
576  fluid_cache_multiprocessing_start_$ID$(function=bake_mesh_process_$ID$, framenr=framenr, format_data=format_data, format_mesh=format_mesh, path_mesh=path_mesh)\n";
577 
578 const std::string fluid_bake_particles =
579  "\n\
580 def bake_particles_process_$ID$(framenr, format_particles, path_particles, resumable):\n\
581  mantaMsg('Bake secondary particles')\n\
582  \n\
583  sp$ID$.frame = framenr\n\
584  sp$ID$.frameLength = frameLength_s$ID$\n\
585  sp$ID$.timeTotal = timeTotal_s$ID$\n\
586  sp$ID$.timestep = frameLength_s$ID$ # no adaptive timestep for particles\n\
587  \n\
588  #if using_smoke_s$ID$:\n\
589  # TODO(sebbas): Future update could include smoke particles (e.g. fire sparks)\n\
590  if using_liquid_s$ID$:\n\
591  liquid_step_particles_$ID$()\n\
592  liquid_save_particles_$ID$(path_particles, framenr, format_particles, resumable)\n\
593 \n\
594 def bake_particles_$ID$(path_particles, framenr, format_particles, resumable):\n\
595  if not withMPBake or isWindows:\n\
596  bake_particles_process_$ID$(framenr, format_particles, path_particles, resumable)\n\
597  else:\n\
598  fluid_cache_multiprocessing_start_$ID$(function=bake_particles_process_$ID$, framenr=framenr, format_particles=format_particles, path_particles=path_particles, resumable=resumable)\n";
599 
600 const std::string fluid_bake_guiding =
601  "\n\
602 def bake_guiding_process_$ID$(framenr, format_guiding, path_guiding, resumable):\n\
603  mantaMsg('Bake fluid guiding')\n\
604  \n\
605  # Average out velocities from multiple guiding objects at one cell\n\
606  x_guidevel_s$ID$.safeDivide(numGuides_s$ID$)\n\
607  y_guidevel_s$ID$.safeDivide(numGuides_s$ID$)\n\
608  z_guidevel_s$ID$.safeDivide(numGuides_s$ID$)\n\
609  copyRealToVec3(sourceX=x_guidevel_s$ID$, sourceY=y_guidevel_s$ID$, sourceZ=z_guidevel_s$ID$, target=guidevelC_s$ID$)\n\
610  \n\
611  mantaMsg('Extrapolating guiding velocity')\n\
612  # ensure velocities inside of guiding object, slightly add guiding vels outside of object too\n\
613  extrapolateVec3Simple(vel=guidevelC_s$ID$, phi=phiGuideIn_s$ID$, distance=6, inside=True)\n\
614  extrapolateVec3Simple(vel=guidevelC_s$ID$, phi=phiGuideIn_s$ID$, distance=3, inside=False)\n\
615  resampleVec3ToMac(source=guidevelC_s$ID$, target=guidevel_sg$ID$)\n\
616  \n\
617  fluid_save_guiding_$ID$(path_guiding, framenr, format_guiding, resumable)\n\
618 \n\
619 def bake_guiding_$ID$(path_guiding, framenr, format_guiding, resumable):\n\
620  if not withMPBake or isWindows:\n\
621  bake_guiding_process_$ID$(framenr, format_guiding, path_guiding, resumable)\n\
622  else:\n\
623  fluid_cache_multiprocessing_start_$ID$(function=bake_guiding_process_$ID$, framenr=framenr, format_guiding=format_guiding, path_guiding=path_guiding, resumable=resumable)\n";
624 
626 // IMPORT
628 
629 const std::string fluid_file_import =
630  "\n\
631 def fluid_file_import_s$ID$(dict, path, framenr, file_format, file_name=None):\n\
632  mantaMsg('Fluid file import, frame: ' + str(framenr))\n\
633  try:\n\
634  framenr = fluid_cache_get_framenr_formatted_$ID$(framenr)\n\
635  # New cache: Try to load the data from a single file\n\
636  loadCombined = 0\n\
637  if file_name is not None:\n\
638  file = os.path.join(path, file_name + '_' + framenr + file_format)\n\
639  if os.path.isfile(file):\n\
640  if file_format == '.vdb':\n\
641  loadCombined = load(name=file, objects=list(dict.values()), worldSize=domainSize_s$ID$)\n\
642  elif file_format == '.bobj.gz' or file_format == '.obj':\n\
643  for name, object in dict.items():\n\
644  if os.path.isfile(file):\n\
645  loadCombined = object.load(file)\n\
646  \n\
647  # Old cache: Try to load the data from separate files, i.e. per object with the object based load() function\n\
648  if not loadCombined:\n\
649  for name, object in dict.items():\n\
650  file = os.path.join(path, name + '_' + framenr + file_format)\n\
651  if os.path.isfile(file):\n\
652  loadCombined = object.load(file)\n\
653  \n\
654  if not loadCombined:\n\
655  mantaMsg('Could not load file ' + str(file))\n\
656  \n\
657  except Exception as e:\n\
658  mantaMsg('Exception in Python fluid file import: ' + str(e))\n\
659  pass # Just skip file load errors for now\n";
660 
661 const std::string fluid_load_guiding =
662  "\n\
663 def fluid_load_guiding_$ID$(path, framenr, file_format):\n\
664  mantaMsg('Fluid load guiding, frame ' + str(framenr))\n\
665  guidevel_sg$ID$.setName('$NAME_VELOCITY_GUIDE$')\n\
666  fluid_file_import_s$ID$(dict=fluid_guiding_dict_s$ID$, path=path, framenr=framenr, file_format=file_format, file_name=file_guiding_s$ID$)\n\
667  \n\
668  copyVec3ToReal(source=guidevel_sg$ID$, targetX=x_guidevel_s$ID$, targetY=y_guidevel_s$ID$, targetZ=z_guidevel_s$ID$)\n";
669 
670 const std::string fluid_load_vel =
671  "\n\
672 def fluid_load_vel_$ID$(path, framenr, file_format):\n\
673  mantaMsg('Fluid load vel, frame ' + str(framenr))\n\
674  guidevel_sg$ID$.setName('$NAME_VELOCITY$') # for loading data the guidevel grid will pretend to be the vel grid\n\
675  fluid_vel_dict_s$ID$ = { 'vel' : guidevel_sg$ID$ }\n\
676  fluid_file_import_s$ID$(dict=fluid_vel_dict_s$ID$, path=path, framenr=framenr, file_format=file_format, file_name=file_data_s$ID$)\n";
677 
679 // EXPORT
681 
682 const std::string fluid_file_export =
683  "\n\
684 def fluid_file_export_s$ID$(framenr, file_format, path, dict, file_name=None, mode_override=True, skip_subframes=True, clipGrid=None):\n\
685  if skip_subframes and ((timePerFrame_s$ID$ + dt0_s$ID$) < frameLength_s$ID$):\n\
686  return\n\
687  mantaMsg('Fluid file export, frame: ' + str(framenr))\n\
688  try:\n\
689  framenr = fluid_cache_get_framenr_formatted_$ID$(framenr)\n\
690  if not os.path.exists(path):\n\
691  os.makedirs(path)\n\
692  \n\
693  # New cache: Try to save the data to a single file\n\
694  saveCombined = 0\n\
695  if file_name is not None:\n\
696  file = os.path.join(path, file_name + '_' + framenr + file_format)\n\
697  if not os.path.isfile(file) or mode_override:\n\
698  if file_format == '.vdb':\n\
699  saveCombined = save(name=file, objects=list(dict.values()), worldSize=domainSize_s$ID$, skipDeletedParts=True, compression=vdbCompression_s$ID$, precision=vdbPrecision_s$ID$, clip=vdbClip_s$ID$, clipGrid=clipGrid, meta=True)\n\
700  elif file_format == '.bobj.gz' or file_format == '.obj':\n\
701  for name, object in dict.items():\n\
702  if not os.path.isfile(file) or mode_override:\n\
703  saveCombined = object.save(file)\n\
704  \n\
705  # Old cache: Try to save the data to separate files, i.e. per object with the object based save() function\n\
706  if not saveCombined:\n\
707  for name, object in dict.items():\n\
708  file = os.path.join(path, name + '_' + framenr + file_format)\n\
709  if not os.path.isfile(file) or mode_override: object.save(file)\n\
710  \n\
711  except Exception as e:\n\
712  mantaMsg('Exception in Python fluid file export: ' + str(e))\n\
713  pass # Just skip file save errors for now\n";
714 
715 const std::string fluid_save_guiding =
716  "\n\
717 def fluid_save_guiding_$ID$(path, framenr, file_format, resumable):\n\
718  mantaMsg('Fluid save guiding, frame ' + str(framenr))\n\
719  dict = fluid_guiding_dict_s$ID$\n\
720  if not withMPSave or isWindows:\n\
721  fluid_file_export_s$ID$(dict=dict, framenr=framenr, file_format=file_format, path=path, file_name=file_guiding_s$ID$)\n\
722  else:\n\
723  fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, file_name=file_guiding_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=dict, do_join=False)\n";
724 
726 // STANDALONE MODE
728 
729 const std::string fluid_standalone =
730  "\n\
731 gui = None\n\
732 if (GUI):\n\
733  gui=Gui()\n\
734  gui.show()\n\
735  gui.pause()\n\
736 \n\
737 cache_resumable = $CACHE_RESUMABLE$\n\
738 cache_dir = '$CACHE_DIR$'\n\
739 file_format_data = '$CACHE_DATA_FORMAT$'\n\
740 file_format_mesh = '$CACHE_MESH_FORMAT$'\n\
741 \n\
742 # How many frame to load from cache\n\
743 from_cache_count = 100\n\
744 \n\
745 loop_count = 0\n\
746 while current_frame_s$ID$ <= end_frame_s$ID$:\n\
747  \n\
748  # Load already simulated data from cache:\n\
749  if loop_count < from_cache_count:\n\
750  load_data(current_frame_s$ID$, cache_resumable)\n\
751  \n\
752  # Otherwise simulate new data\n\
753  else:\n\
754  while(s$ID$.frame <= current_frame_s$ID$):\n\
755  if using_adaptTime_s$ID$:\n\
756  fluid_adapt_time_step_$ID$()\n\
757  step(current_frame_s$ID$)\n\
758  \n\
759  current_frame_s$ID$ += 1\n\
760  loop_count += 1\n\
761  \n\
762  if gui:\n\
763  gui.pause()\n";
764 
766 // SCRIPT SECTION HEADERS
768 
769 const std::string header_libraries =
770  "\n\
771 ######################################################################\n\
772 ## LIBRARIES\n\
773 ######################################################################\n";
774 
775 const std::string header_main =
776  "\n\
777 ######################################################################\n\
778 ## MAIN\n\
779 ######################################################################\n";
780 
781 const std::string header_prepost =
782  "\n\
783 ######################################################################\n\
784 ## PRE/POST STEPS\n\
785 ######################################################################\n";
786 
787 const std::string header_steps =
788  "\n\
789 ######################################################################\n\
790 ## STEPS\n\
791 ######################################################################\n";
792 
793 const std::string header_import =
794  "\n\
795 ######################################################################\n\
796 ## IMPORT\n\
797 ######################################################################\n";
798 
799 const std::string header_grids =
800  "\n\
801 ######################################################################\n\
802 ## GRIDS\n\
803 ######################################################################\n";
804 
805 const std::string header_solvers =
806  "\n\
807 ######################################################################\n\
808 ## SOLVERS\n\
809 ######################################################################\n";
810 
811 const std::string header_variables =
812  "\n\
813 ######################################################################\n\
814 ## VARIABLES\n\
815 ######################################################################\n";
816 
817 const std::string header_time =
818  "\n\
819 ######################################################################\n\
820 ## ADAPTIVE TIME\n\
821 ######################################################################\n";
822 
823 const std::string header_gridinit =
824  "\n\
825 ######################################################################\n\
826 ## DOMAIN INIT\n\
827 ######################################################################\n";
const std::string header_import
Definition: fluid_script.h:793
const std::string fluid_save_guiding
Definition: fluid_script.h:715
const std::string fluid_with_guiding
Definition: fluid_script.h:200
const std::string fluid_file_import
Definition: fluid_script.h:629
const std::string fluid_alloc_fractions
Definition: fluid_script.h:325
const std::string fluid_pre_step
Definition: fluid_script.h:355
const std::string header_gridinit
Definition: fluid_script.h:823
const std::string fluid_with_outflow
Definition: fluid_script.h:212
const std::string header_main
Definition: fluid_script.h:775
const std::string fluid_alloc
Definition: fluid_script.h:258
const std::string fluid_bake_data
Definition: fluid_script.h:514
const std::string fluid_standalone
Definition: fluid_script.h:729
const std::string fluid_variables_noise
Definition: fluid_script.h:162
const std::string fluid_with_fractions
Definition: fluid_script.h:204
const std::string header_steps
Definition: fluid_script.h:787
const std::string fluid_alloc_invel
Definition: fluid_script.h:330
const std::string fluid_solver_viscosity
Definition: fluid_script.h:67
const std::string fluid_variables_particles
Definition: fluid_script.h:174
const std::string fluid_with_invel
Definition: fluid_script.h:208
const std::string fluid_solver_particles
Definition: fluid_script.h:57
const std::string fluid_solver_mesh
Definition: fluid_script.h:52
const std::string fluid_alloc_obstacle
Definition: fluid_script.h:288
const std::string manta_import
Definition: fluid_script.h:14
const std::string fluid_load_vel
Definition: fluid_script.h:670
const std::string fluid_file_export
Definition: fluid_script.h:682
const std::string fluid_bake_noise
Definition: fluid_script.h:536
const std::string fluid_alloc_outflow
Definition: fluid_script.h:338
const std::string fluid_bake_guiding
Definition: fluid_script.h:600
const std::string fluid_delete_all
Definition: fluid_script.h:408
const std::string manta_debuglevel
Definition: fluid_script.h:33
const std::string header_grids
Definition: fluid_script.h:799
const std::string fluid_bake_multiprocessing
Definition: fluid_script.h:478
const std::string fluid_with_sndparts
Definition: fluid_script.h:216
const std::string header_time
Definition: fluid_script.h:817
const std::string header_libraries
Definition: fluid_script.h:769
const std::string fluid_variables
Definition: fluid_script.h:76
const std::string header_solvers
Definition: fluid_script.h:805
const std::string fluid_adapt_time_step
Definition: fluid_script.h:236
const std::string header_variables
Definition: fluid_script.h:811
const std::string header_prepost
Definition: fluid_script.h:781
const std::string fluid_solver_noise
Definition: fluid_script.h:47
const std::string fluid_alloc_guiding
Definition: fluid_script.h:307
const std::string fluid_variables_viscosity
Definition: fluid_script.h:192
const std::string fluid_cache_helper
Definition: fluid_script.h:473
const std::string fluid_time_stepping
Definition: fluid_script.h:224
const std::string fluid_bake_mesh
Definition: fluid_script.h:554
const std::string fluid_solver
Definition: fluid_script.h:42
const std::string fluid_bake_particles
Definition: fluid_script.h:578
const std::string fluid_solver_guiding
Definition: fluid_script.h:62
const std::string fluid_post_step
Definition: fluid_script.h:394
const std::string fluid_load_guiding
Definition: fluid_script.h:661
const std::string fluid_variables_guiding
Definition: fluid_script.h:180
const std::string fluid_variables_mesh
Definition: fluid_script.h:168
const std::string fluid_with_obstacle
Definition: fluid_script.h:196