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