Blender V4.3
liquid_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// VARIABLES
14
15const std::string liquid_variables =
16 "\n\
17mantaMsg('Liquid variables')\n\
18narrowBandWidth_s$ID$ = 3\n\
19combineBandWidth_s$ID$ = narrowBandWidth_s$ID$ - 1\n\
20adjustedNarrowBandWidth_s$ID$ = $PARTICLE_BAND_WIDTH$ # only used in adjustNumber to control band width\n\
21particleNumber_s$ID$ = $PARTICLE_NUMBER$\n\
22minParticles_s$ID$ = $PARTICLE_MINIMUM$\n\
23maxParticles_s$ID$ = $PARTICLE_MAXIMUM$\n\
24radiusFactor_s$ID$ = $PARTICLE_RADIUS$\n\
25using_mesh_s$ID$ = $USING_MESH$\n\
26using_final_mesh_s$ID$ = $USING_IMPROVED_MESH$\n\
27using_fractions_s$ID$ = $USING_FRACTIONS$\n\
28using_apic_s$ID$ = $USING_APIC$\n\
29using_viscosity_s$ID$ = $USING_VISCOSITY$\n\
30fracThreshold_s$ID$ = $FRACTIONS_THRESHOLD$\n\
31fracDistance_s$ID$ = $FRACTIONS_DISTANCE$\n\
32flipRatio_s$ID$ = $FLIP_RATIO$\n\
33concaveUpper_s$ID$ = $MESH_CONCAVE_UPPER$\n\
34concaveLower_s$ID$ = $MESH_CONCAVE_LOWER$\n\
35meshRadiusFactor_s$ID$ = $MESH_PARTICLE_RADIUS$\n\
36smoothenPos_s$ID$ = $MESH_SMOOTHEN_POS$\n\
37smoothenNeg_s$ID$ = $MESH_SMOOTHEN_NEG$\n\
38randomness_s$ID$ = $PARTICLE_RANDOMNESS$\n\
39surfaceTension_s$ID$ = $LIQUID_SURFACE_TENSION$\n\
40maxSysParticles_s$ID$ = $PP_PARTICLE_MAXIMUM$\n\
41viscosityValue_s$ID$ = $VISCOSITY_VALUE$\n";
42
43const std::string liquid_variables_particles =
44 "\n\
45tauMin_wc_sp$ID$ = $SNDPARTICLE_TAU_MIN_WC$\n\
46tauMax_wc_sp$ID$ = $SNDPARTICLE_TAU_MAX_WC$\n\
47tauMin_ta_sp$ID$ = $SNDPARTICLE_TAU_MIN_TA$\n\
48tauMax_ta_sp$ID$ = $SNDPARTICLE_TAU_MAX_TA$\n\
49tauMin_k_sp$ID$ = $SNDPARTICLE_TAU_MIN_K$\n\
50tauMax_k_sp$ID$ = $SNDPARTICLE_TAU_MAX_K$\n\
51k_wc_sp$ID$ = $SNDPARTICLE_K_WC$\n\
52k_ta_sp$ID$ = $SNDPARTICLE_K_TA$\n\
53k_b_sp$ID$ = $SNDPARTICLE_K_B$\n\
54k_d_sp$ID$ = $SNDPARTICLE_K_D$\n\
55lMin_sp$ID$ = $SNDPARTICLE_L_MIN$\n\
56lMax_sp$ID$ = $SNDPARTICLE_L_MAX$\n\
57c_s_sp$ID$ = 0.4 # classification constant for snd parts\n\
58c_b_sp$ID$ = 0.77 # classification constant for snd parts\n\
59pot_radius_sp$ID$ = $SNDPARTICLE_POTENTIAL_RADIUS$\n\
60update_radius_sp$ID$ = $SNDPARTICLE_UPDATE_RADIUS$\n\
61using_snd_pushout_sp$ID$ = $SNDPARTICLE_BOUNDARY_PUSHOUT$\n";
62
64// GRIDS & MESH & PARTICLESYSTEM
66
67const std::string liquid_alloc =
68 "\n\
69mantaMsg('Liquid alloc')\n\
70phiParts_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHIPARTS$')\n\
71phi_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHI$')\n\
72phiTmp_s$ID$ = s$ID$.create(LevelsetGrid, name='$NAME_PHITMP$')\n\
73velOld_s$ID$ = s$ID$.create(MACGrid, name='$NAME_VELOLD$')\n\
74velParts_s$ID$ = s$ID$.create(MACGrid, name='$NAME_VELPARTS$')\n\
75mapWeights_s$ID$ = s$ID$.create(MACGrid, name='$NAME_MAPWEIGHTS$')\n\
76fractions_s$ID$ = None # allocated dynamically\n\
77curvature_s$ID$ = None\n\
78\n\
79pp_s$ID$ = s$ID$.create(BasicParticleSystem, name='$NAME_PARTS$')\n\
80pVel_pp$ID$ = pp_s$ID$.create(PdataVec3, name='$NAME_PARTSVELOCITY$')\n\
81\n\
82pCx_pp$ID$ = None\n\
83pCy_pp$ID$ = None\n\
84pCz_pp$ID$ = None\n\
85if using_apic_s$ID$:\n\
86 pCx_pp$ID$ = pp_s$ID$.create(PdataVec3)\n\
87 pCy_pp$ID$ = pp_s$ID$.create(PdataVec3)\n\
88 pCz_pp$ID$ = pp_s$ID$.create(PdataVec3)\n\
89\n\
90# Acceleration data for particle nbs\n\
91pindex_s$ID$ = s$ID$.create(ParticleIndexSystem, name='$NAME_PINDEX$')\n\
92gpi_s$ID$ = s$ID$.create(IntGrid, name='$NAME_GPI$')\n\
93\n\
94# Keep track of important objects in dict to load them later on\n\
95liquid_data_dict_final_s$ID$ = { 'pVel' : pVel_pp$ID$, 'pp' : pp_s$ID$ }\n\
96liquid_data_dict_resume_s$ID$ = { 'phiParts' : phiParts_s$ID$, 'phi' : phi_s$ID$, 'phiTmp' : phiTmp_s$ID$ }\n";
97
98const std::string liquid_alloc_mesh =
99 "\n\
100mantaMsg('Liquid alloc mesh')\n\
101phiParts_sm$ID$ = sm$ID$.create(LevelsetGrid, name='$NAME_PHIPARTS_MESH$')\n\
102phi_sm$ID$ = sm$ID$.create(LevelsetGrid, name='$NAME_PHI_MESH$')\n\
103pp_sm$ID$ = sm$ID$.create(BasicParticleSystem, name='$NAME_PP_MESH$')\n\
104flags_sm$ID$ = sm$ID$.create(FlagGrid, name='$NAME_FLAGS_MESH$')\n\
105mesh_sm$ID$ = sm$ID$.create(Mesh, name='$NAME_MESH$')\n\
106\n\
107if using_speedvectors_s$ID$:\n\
108 mVel_mesh$ID$ = mesh_sm$ID$.create(MdataVec3, name='$NAME_VELOCITYVEC_MESH$')\n\
109 vel_sm$ID$ = sm$ID$.create(MACGrid, name='$NAME_VELOCITY_MESH$')\n\
110\n\
111# Acceleration data for particle nbs\n\
112pindex_sm$ID$ = sm$ID$.create(ParticleIndexSystem, name='$NAME_PINDEX_MESH$')\n\
113gpi_sm$ID$ = sm$ID$.create(IntGrid, name='$NAME_GPI_MESH$')\n\
114\n\
115# Set some initial values\n\
116phiParts_sm$ID$.setConst(9999)\n\
117phi_sm$ID$.setConst(9999)\n\
118\n\
119# Keep track of important objects in dict to load them later on\n\
120liquid_mesh_dict_s$ID$ = { 'lMesh' : mesh_sm$ID$ }\n\
121\n\
122if using_speedvectors_s$ID$:\n\
123 liquid_meshvel_dict_s$ID$ = { 'lVelMesh' : mVel_mesh$ID$ }\n";
124
125const std::string liquid_alloc_viscosity =
126 "\n\
127# Viscosity grids\n\
128volumes_s$ID$ = sv$ID$.create(RealGrid)\n\
129viscosity_s$ID$ = s$ID$.create(RealGrid)\n\
130viscosity_s$ID$.setConst(viscosityValue_s$ID$)\n";
131
132const std::string liquid_alloc_curvature =
133 "\n\
134mantaMsg('Liquid alloc curvature')\n\
135curvature_s$ID$ = s$ID$.create(RealGrid, name='$NAME_CURVATURE$')\n";
136
137const std::string liquid_alloc_particles =
138 "\n\
139ppSnd_sp$ID$ = sp$ID$.create(BasicParticleSystem, name='$NAME_PARTS_PARTICLES$')\n\
140pVelSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataVec3, name='$NAME_PARTSVEL_PARTICLES$')\n\
141pForceSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataVec3, name='$NAME_PARTSFORCE_PARTICLES$')\n\
142pLifeSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataReal, name='$NAME_PARTSLIFE_PARTICLES$')\n\
143vel_sp$ID$ = sp$ID$.create(MACGrid, name='$NAME_VELOCITY_PARTICLES$')\n\
144flags_sp$ID$ = sp$ID$.create(FlagGrid, name='$NAME_FLAGS_PARTICLES$')\n\
145phi_sp$ID$ = sp$ID$.create(LevelsetGrid, name='$NAME_PHI_PARTICLES$')\n\
146phiObs_sp$ID$ = sp$ID$.create(LevelsetGrid, name='$NAME_PHIOBS_PARTICLES$')\n\
147phiOut_sp$ID$ = sp$ID$.create(LevelsetGrid, name='$NAME_PHIOUT_PARTICLES$')\n\
148normal_sp$ID$ = sp$ID$.create(VecGrid, name='$NAME_NORMAL_PARTICLES$')\n\
149neighborRatio_sp$ID$ = sp$ID$.create(RealGrid, name='$NAME_NEIGHBORRATIO_PARTICLES$')\n\
150trappedAir_sp$ID$ = sp$ID$.create(RealGrid, name='$NAME_TRAPPEDAIR_PARTICLES$')\n\
151waveCrest_sp$ID$ = sp$ID$.create(RealGrid, name='$NAME_WAVECREST_PARTICLES$')\n\
152kineticEnergy_sp$ID$ = sp$ID$.create(RealGrid, name='$NAME_KINETICENERGY_PARTICLES$')\n\
153\n\
154# Set some initial values\n\
155phi_sp$ID$.setConst(9999)\n\
156phiObs_sp$ID$.setConst(9999)\n\
157phiOut_sp$ID$.setConst(9999)\n\
158\n\
159# Keep track of important objects in dict to load them later on\n\
160liquid_particles_dict_final_s$ID$ = { 'pVelSnd' : pVelSnd_pp$ID$, 'pLifeSnd' : pLifeSnd_pp$ID$, 'ppSnd' : ppSnd_sp$ID$ }\n\
161liquid_particles_dict_resume_s$ID$ = { 'trappedAir' : trappedAir_sp$ID$, 'waveCrest' : waveCrest_sp$ID$, 'kineticEnergy' : kineticEnergy_sp$ID$ }\n";
162
163const std::string liquid_init_phi =
164 "\n\
165# Prepare domain\n\
166phi_s$ID$.initFromFlags(flags_s$ID$)\n\
167phiIn_s$ID$.initFromFlags(flags_s$ID$)\n";
168
170// STEP FUNCTIONS
172
173const std::string liquid_adaptive_step =
174 "\n\
175def liquid_adaptive_step_$ID$(framenr):\n\
176 mantaMsg('Manta step, frame ' + str(framenr))\n\
177 s$ID$.frame = framenr\n\
178 \n\
179 fluid_pre_step_$ID$()\n\
180 \n\
181 flags_s$ID$.initDomain(boundaryWidth=1 if using_fractions_s$ID$ else 0, phiWalls=phiObs_s$ID$, outflow=boundConditions_s$ID$)\n\
182 \n\
183 if using_obstacle_s$ID$:\n\
184 mantaMsg('Extrapolating object velocity')\n\
185 # ensure velocities inside of obs object, slightly add obvels outside of obs object\n\
186 # extrapolate with phiObsIn before joining (static) phiObsSIn grid to prevent flows into static obs\n\
187 extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=6, inside=True)\n\
188 extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=3, inside=False)\n\
189 resampleVec3ToMac(source=obvelC_s$ID$, target=obvel_s$ID$)\n\
190 \n\
191 mantaMsg('Initializing obstacle levelset')\n\
192 phiObsIn_s$ID$.join(phiObsSIn_s$ID$) # Join static obstacle map\n\
193 phiObsIn_s$ID$.floodFill(boundaryWidth=1)\n\
194 extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=6, inside=True)\n\
195 extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=3, inside=False)\n\
196 phiObs_s$ID$.join(phiObsIn_s$ID$)\n\
197 \n\
198 # Additional sanity check: fill holes in phiObs which can result after joining with phiObsIn\n\
199 phiObs_s$ID$.floodFill(boundaryWidth=2 if using_fractions_s$ID$ else 1)\n\
200 extrapolateLsSimple(phi=phiObs_s$ID$, distance=6, inside=True)\n\
201 extrapolateLsSimple(phi=phiObs_s$ID$, distance=3)\n\
202 \n\
203 mantaMsg('Initializing fluid levelset')\n\
204 phiIn_s$ID$.join(phiSIn_s$ID$) # Join static flow map\n\
205 extrapolateLsSimple(phi=phiIn_s$ID$, distance=6, inside=True)\n\
206 extrapolateLsSimple(phi=phiIn_s$ID$, distance=3)\n\
207 phi_s$ID$.join(phiIn_s$ID$)\n\
208 \n\
209 if using_outflow_s$ID$:\n\
210 phiOutIn_s$ID$.join(phiOutSIn_s$ID$) # Join static outflow map\n\
211 phiOut_s$ID$.join(phiOutIn_s$ID$)\n\
212 \n\
213 if using_fractions_s$ID$:\n\
214 updateFractions(flags=flags_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$, boundaryWidth=boundaryWidth_s$ID$, fracThreshold=fracThreshold_s$ID$)\n\
215 setObstacleFlags(flags=flags_s$ID$, phiObs=phiObs_s$ID$, phiOut=phiOut_s$ID$, fractions=fractions_s$ID$, phiIn=phiIn_s$ID$)\n\
216 \n\
217 if using_obstacle_s$ID$:\n\
218 # TODO(sebbas): Enable flags check again, currently produces unstable particle behavior\n\
219 phi_s$ID$.subtract(o=phiObsIn_s$ID$) #, flags=flags_s$ID$, subtractType=FlagObstacle)\n\
220 \n\
221 # add initial velocity: set invel as source grid to ensure const vels in inflow region, sampling makes use of this\n\
222 if using_invel_s$ID$:\n\
223 extrapolateVec3Simple(vel=invelC_s$ID$, phi=phiIn_s$ID$, distance=6, inside=True)\n\
224 # Using cell centered invels, a false isMAC flag ensures correct interpolation\n\
225 pVel_pp$ID$.setSource(grid=invelC_s$ID$, isMAC=False)\n\
226 # reset pvel grid source before sampling new particles - ensures that new particles are initialized with 0 velocity\n\
227 else:\n\
228 pVel_pp$ID$.setSource(grid=None, isMAC=False)\n\
229 \n\
230 pp_s$ID$.maxParticles = maxSysParticles_s$ID$ # remember, 0 means no particle cap\n\
231 sampleLevelsetWithParticles(phi=phiIn_s$ID$, flags=flags_s$ID$, parts=pp_s$ID$, discretization=particleNumber_s$ID$, randomness=randomness_s$ID$)\n\
232 flags_s$ID$.updateFromLevelset(phi_s$ID$)\n\
233 \n\
234 mantaMsg('Liquid step / s$ID$.frame: ' + str(s$ID$.frame))\n\
235 liquid_step_$ID$()\n\
236 \n\
237 s$ID$.step()\n\
238 \n\
239 fluid_post_step_$ID$()\n";
240
241const std::string liquid_step =
242 "\n\
243def liquid_step_$ID$():\n\
244 mantaMsg('Liquid step')\n\
245 \n\
246 mantaMsg('Advecting particles')\n\
247 pp_s$ID$.advectInGrid(flags=flags_s$ID$, vel=vel_s$ID$, integrationMode=IntRK4, deleteInObstacle=deleteInObstacle_s$ID$, stopInObstacle=False, skipNew=True)\n\
248 \n\
249 mantaMsg('Pushing particles out of obstacles')\n\
250 if using_obstacle_s$ID$ and using_fractions_s$ID$ and fracDistance_s$ID$ > 0:\n\
251 # Optional: Increase distance between fluid and obstacles (only obstacles, not borders)\n\
252 pushOutofObs(parts=pp_s$ID$, flags=flags_s$ID$, phiObs=phiObsIn_s$ID$, thresh=fracDistance_s$ID$)\n\
253 pushOutofObs(parts=pp_s$ID$, flags=flags_s$ID$, phiObs=phiObs_s$ID$)\n\
254 \n\
255 # save original states for later (used during mesh / secondary particle creation)\n\
256 # but only save the state at the beginning of an adaptive frame\n\
257 if not s$ID$.timePerFrame:\n\
258 phiTmp_s$ID$.copyFrom(phi_s$ID$)\n\
259 velTmp_s$ID$.copyFrom(vel_s$ID$)\n\
260 \n\
261 mantaMsg('Advecting phi')\n\
262 advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=phi_s$ID$, order=1) # first order is usually enough\n\
263 mantaMsg('Advecting velocity')\n\
264 advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=vel_s$ID$, order=2)\n\
265 \n\
266 # create level set of particles\n\
267 gridParticleIndex(parts=pp_s$ID$, flags=flags_s$ID$, indexSys=pindex_s$ID$, index=gpi_s$ID$)\n\
268 unionParticleLevelset(parts=pp_s$ID$, indexSys=pindex_s$ID$, flags=flags_s$ID$, index=gpi_s$ID$, phi=phiParts_s$ID$, radiusFactor=radiusFactor_s$ID$)\n\
269 \n\
270 # combine level set of particles with grid level set\n\
271 phi_s$ID$.addConst(1.) # shrink slightly\n\
272 phi_s$ID$.join(phiParts_s$ID$)\n\
273 extrapolateLsSimple(phi=phi_s$ID$, distance=narrowBandWidth_s$ID$+2, inside=True)\n\
274 extrapolateLsSimple(phi=phi_s$ID$, distance=3)\n\
275 phi_s$ID$.setBoundNeumann(0) # make sure no particles are placed at outer boundary\n\
276 \n\
277 if not domainClosed_s$ID$ or using_outflow_s$ID$:\n\
278 resetOutflow(flags=flags_s$ID$, phi=phi_s$ID$, parts=pp_s$ID$, index=gpi_s$ID$, indexSys=pindex_s$ID$)\n\
279 flags_s$ID$.updateFromLevelset(phi_s$ID$)\n\
280 \n\
281 # combine particle velocities with advected grid velocities\n\
282 if using_apic_s$ID$:\n\
283 apicMapPartsToMAC(flags=flags_s$ID$, vel=vel_s$ID$, parts=pp_s$ID$, partVel=pVel_pp$ID$, cpx=pCx_pp$ID$, cpy=pCy_pp$ID$, cpz=pCz_pp$ID$)\n\
284 else:\n\
285 mapPartsToMAC(vel=velParts_s$ID$, flags=flags_s$ID$, velOld=velOld_s$ID$, parts=pp_s$ID$, partVel=pVel_pp$ID$, weight=mapWeights_s$ID$)\n\
286 \n\
287 extrapolateMACFromWeight(vel=velParts_s$ID$, distance=2, weight=mapWeights_s$ID$)\n\
288 combineGridVel(vel=velParts_s$ID$, weight=mapWeights_s$ID$, combineVel=vel_s$ID$, phi=phi_s$ID$, narrowBand=combineBandWidth_s$ID$, thresh=0)\n\
289 velOld_s$ID$.copyFrom(vel_s$ID$)\n\
290 \n\
291 # forces & pressure solve\n\
292 addGravity(flags=flags_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, scale=False)\n\
293 \n\
294 mantaMsg('Adding external forces')\n\
295 addForceField(flags=flags_s$ID$, vel=vel_s$ID$, force=forces_s$ID$)\n\
296 \n\
297 extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=2, intoObs=True if using_fractions_s$ID$ else False)\n\
298 \n\
299 # vel diffusion / viscosity!\n\
300 if using_diffusion_s$ID$:\n\
301 mantaMsg('Viscosity')\n\
302 # diffusion param for solve = const * dt / dx^2\n\
303 alphaV = kinViscosity_s$ID$ * s$ID$.timestep * float(res_s$ID$*res_s$ID$)\n\
304 setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
305 cgSolveDiffusion(flags_s$ID$, vel_s$ID$, alphaV)\n\
306 \n\
307 mantaMsg('Curvature')\n\
308 getLaplacian(laplacian=curvature_s$ID$, grid=phi_s$ID$)\n\
309 curvature_s$ID$.clamp(-1.0, 1.0)\n\
310 \n\
311 setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
312 if using_viscosity_s$ID$:\n\
313 viscosity_s$ID$.setConst(viscosityValue_s$ID$)\n\
314 applyViscosity(flags=flags_s$ID$, phi=phi_s$ID$, vel=vel_s$ID$, volumes=volumes_s$ID$, viscosity=viscosity_s$ID$)\n\
315 \n\
316 setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
317 if using_guiding_s$ID$:\n\
318 mantaMsg('Guiding and pressure')\n\
319 PD_fluid_guiding(vel=vel_s$ID$, velT=velT_s$ID$, flags=flags_s$ID$, phi=phi_s$ID$, curv=curvature_s$ID$, surfTens=surfaceTension_s$ID$, fractions=fractions_s$ID$, weight=weightGuide_s$ID$, blurRadius=beta_sg$ID$, pressure=pressure_s$ID$, tau=tau_sg$ID$, sigma=sigma_sg$ID$, theta=theta_sg$ID$, zeroPressureFixing=domainClosed_s$ID$)\n\
320 else:\n\
321 mantaMsg('Pressure')\n\
322 solvePressure(flags=flags_s$ID$, vel=vel_s$ID$, pressure=pressure_s$ID$, curv=curvature_s$ID$, surfTens=surfaceTension_s$ID$, fractions=fractions_s$ID$, obvel=obvel_s$ID$ if using_fractions_s$ID$ else None, zeroPressureFixing=domainClosed_s$ID$)\n\
323 \n\
324 extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=4, intoObs=True if using_fractions_s$ID$ else False)\n\
325 setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
326 \n\
327 if not using_fractions_s$ID$:\n\
328 extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$)\n\
329 \n\
330 # set source grids for resampling, used in adjustNumber!\n\
331 pVel_pp$ID$.setSource(grid=vel_s$ID$, isMAC=True)\n\
332 adjustNumber(parts=pp_s$ID$, vel=vel_s$ID$, flags=flags_s$ID$, minParticles=minParticles_s$ID$, maxParticles=maxParticles_s$ID$, phi=phi_s$ID$, exclude=phiObs_s$ID$, radiusFactor=radiusFactor_s$ID$, narrowBand=adjustedNarrowBandWidth_s$ID$)\n\
333 \n\
334 if using_apic_s$ID$:\n\
335 apicMapMACGridToParts(partVel=pVel_pp$ID$, cpx=pCx_pp$ID$, cpy=pCy_pp$ID$, cpz=pCz_pp$ID$, parts=pp_s$ID$, vel=vel_s$ID$, flags=flags_s$ID$)\n\
336 else:\n\
337 flipVelocityUpdate(vel=vel_s$ID$, velOld=velOld_s$ID$, flags=flags_s$ID$, parts=pp_s$ID$, partVel=pVel_pp$ID$, flipRatio=flipRatio_s$ID$)\n";
338
339const std::string liquid_step_mesh =
340 "\n\
341def liquid_step_mesh_$ID$():\n\
342 mantaMsg('Liquid step mesh')\n\
343 \n\
344 # no upres: just use the loaded grids\n\
345 if upres_sm$ID$ <= 1:\n\
346 phi_sm$ID$.copyFrom(phi_s$ID$)\n\
347 \n\
348 # with upres: recreate grids\n\
349 else:\n\
350 interpolateGrid(target=phi_sm$ID$, source=phi_s$ID$)\n\
351 \n\
352 # create surface\n\
353 pp_sm$ID$.readParticles(pp_s$ID$)\n\
354 gridParticleIndex(parts=pp_sm$ID$, flags=flags_sm$ID$, indexSys=pindex_sm$ID$, index=gpi_sm$ID$)\n\
355 \n\
356 if using_final_mesh_s$ID$:\n\
357 mantaMsg('Liquid using improved particle levelset')\n\
358 improvedParticleLevelset(pp_sm$ID$, pindex_sm$ID$, flags_sm$ID$, gpi_sm$ID$, phiParts_sm$ID$, meshRadiusFactor_s$ID$, smoothenPos_s$ID$, smoothenNeg_s$ID$, concaveLower_s$ID$, concaveUpper_s$ID$)\n\
359 else:\n\
360 mantaMsg('Liquid using union particle levelset')\n\
361 unionParticleLevelset(pp_sm$ID$, pindex_sm$ID$, flags_sm$ID$, gpi_sm$ID$, phiParts_sm$ID$, meshRadiusFactor_s$ID$)\n\
362 \n\
363 phi_sm$ID$.addConst(1.) # shrink slightly\n\
364 phi_sm$ID$.join(phiParts_sm$ID$)\n\
365 extrapolateLsSimple(phi=phi_sm$ID$, distance=narrowBandWidth_s$ID$+2, inside=True)\n\
366 extrapolateLsSimple(phi=phi_sm$ID$, distance=3)\n\
367 phi_sm$ID$.setBoundNeumann(0) # make sure no particles are placed at outer boundary\n\
368 \n\
369 # Vert vel vector needs to pull data from vel grid with correct dim\n\
370 if using_speedvectors_s$ID$:\n\
371 interpolateMACGrid(target=vel_sm$ID$, source=vel_s$ID$)\n\
372 mVel_mesh$ID$.setSource(grid=vel_sm$ID$, isMAC=True)\n\
373 \n\
374 # Set 0.5 boundary at walls + account for extra wall thickness in fractions mode + account for grid scaling:\n\
375 # E.g. at upres=1 we expect 1 cell border (or 2 with fractions), at upres=2 we expect 2 cell border (or 4 with fractions), etc.\n\
376 # Use -1 since setBound() starts counting at 0 (and additional -1 for fractions to account for solid/fluid interface cells)\n\
377 phi_sm$ID$.setBound(value=0.5, boundaryWidth=(upres_sm$ID$*2)-2 if using_fractions_s$ID$ else upres_sm$ID$-1)\n\
378 phi_sm$ID$.createMesh(mesh_sm$ID$)\n";
379
380const std::string liquid_step_particles =
381 "\n\
382def liquid_step_particles_$ID$():\n\
383 mantaMsg('Secondary particles step')\n\
384 \n\
385 # no upres: just use the loaded grids\n\
386 if upres_sp$ID$ <= 1:\n\
387 vel_sp$ID$.copyFrom(velTmp_s$ID$)\n\
388 phiObs_sp$ID$.copyFrom(phiObs_s$ID$)\n\
389 phi_sp$ID$.copyFrom(phiTmp_s$ID$)\n\
390 phiOut_sp$ID$.copyFrom(phiOut_s$ID$)\n\
391 \n\
392 # with upres: recreate grids\n\
393 else:\n\
394 # create highres grids by interpolation\n\
395 interpolateMACGrid(target=vel_sp$ID$, source=velTmp_s$ID$)\n\
396 interpolateGrid(target=phiObs_sp$ID$, source=phiObs_s$ID$)\n\
397 interpolateGrid(target=phi_sp$ID$, source=phiTmp_s$ID$)\n\
398 interpolateGrid(target=phiOut_sp$ID$, source=phiOut_s$ID$)\n\
399 \n\
400 # phiIn not needed, bwidth to 0 because we are omitting flags.initDomain()\n\
401 setObstacleFlags(flags=flags_sp$ID$, phiObs=phiObs_sp$ID$, phiOut=phiOut_sp$ID$, phiIn=None, boundaryWidth=0)\n\
402 flags_sp$ID$.updateFromLevelset(levelset=phi_sp$ID$)\n\
403 \n\
404 # Actual secondary particle simulation\n\
405 flipComputeSecondaryParticlePotentials(potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, normal=normal_sp$ID$, phi=phi_sp$ID$, radius=pot_radius_sp$ID$, tauMinTA=tauMin_ta_sp$ID$, tauMaxTA=tauMax_ta_sp$ID$, tauMinWC=tauMin_wc_sp$ID$, tauMaxWC=tauMax_wc_sp$ID$, tauMinKE=tauMin_k_sp$ID$, tauMaxKE=tauMax_k_sp$ID$, scaleFromManta=ratioMetersToRes_s$ID$)\n\
406 flipSampleSecondaryParticles(mode='single', flags=flags_sp$ID$, v=vel_sp$ID$, pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, lMin=lMin_sp$ID$, lMax=lMax_sp$ID$, potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, k_ta=k_ta_sp$ID$, k_wc=k_wc_sp$ID$)\n\
407 flipUpdateSecondaryParticles(mode='linear', pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, f_sec=pForceSnd_pp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, neighborRatio=neighborRatio_sp$ID$, radius=update_radius_sp$ID$, gravity=gravity_s$ID$, scale=False, k_b=k_b_sp$ID$, k_d=k_d_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$)\n\
408 if using_snd_pushout_sp$ID$:\n\
409 pushOutofObs(parts=ppSnd_sp$ID$, flags=flags_sp$ID$, phiObs=phiObs_sp$ID$, shift=1.0)\n\
410 flipDeleteParticlesInObstacle(pts=ppSnd_sp$ID$, flags=flags_sp$ID$) # delete particles inside obstacle and outflow cells\n\
411 \n\
412 # Print debug information in the console\n\
413 if 0:\n\
414 debugGridInfo(flags=flags_sp$ID$, grid=trappedAir_sp$ID$, name='Trapped Air')\n\
415 debugGridInfo(flags=flags_sp$ID$, grid=waveCrest_sp$ID$, name='Wave Crest')\n\
416 debugGridInfo(flags=flags_sp$ID$, grid=kineticEnergy_sp$ID$, name='Kinetic Energy')\n";
417
419// IMPORT
421
422const std::string liquid_load_data =
423 "\n\
424def liquid_load_data_$ID$(path, framenr, file_format, resumable):\n\
425 mantaMsg('Liquid load data')\n\
426 dict = { **fluid_data_dict_final_s$ID$, **fluid_data_dict_resume_s$ID$, **liquid_data_dict_final_s$ID$, **liquid_data_dict_resume_s$ID$ } if resumable else { **fluid_data_dict_final_s$ID$, **liquid_data_dict_final_s$ID$ }\n\
427 fluid_file_import_s$ID$(dict=dict, path=path, framenr=framenr, file_format=file_format, file_name=file_data_s$ID$)\n\
428 \n\
429 copyVec3ToReal(source=vel_s$ID$, targetX=x_vel_s$ID$, targetY=y_vel_s$ID$, targetZ=z_vel_s$ID$)\n";
430
431const std::string liquid_load_mesh =
432 "\n\
433def liquid_load_mesh_$ID$(path, framenr, file_format):\n\
434 mantaMsg('Liquid load mesh')\n\
435 dict = liquid_mesh_dict_s$ID$\n\
436 fluid_file_import_s$ID$(dict=dict, path=path, framenr=framenr, file_format=file_format, file_name=file_mesh_s$ID$)\n\
437\n\
438def liquid_load_meshvel_$ID$(path, framenr, file_format):\n\
439 mantaMsg('Liquid load meshvel')\n\
440 dict = liquid_meshvel_dict_s$ID$\n\
441 fluid_file_import_s$ID$(dict=dict, path=path, framenr=framenr, file_format=file_format, file_name=file_meshvel_s$ID$)\n";
442
443const std::string liquid_load_particles =
444 "\n\
445def liquid_load_particles_$ID$(path, framenr, file_format, resumable):\n\
446 mantaMsg('Liquid load particles')\n\
447 dict = { **liquid_particles_dict_final_s$ID$, **liquid_particles_dict_resume_s$ID$ } if resumable else { **liquid_particles_dict_final_s$ID$ }\n\
448 fluid_file_import_s$ID$(dict=dict, path=path, framenr=framenr, file_format=file_format, file_name=file_particles_s$ID$)\n";
449
451// EXPORT
453
454const std::string liquid_save_data =
455 "\n\
456def liquid_save_data_$ID$(path, framenr, file_format, resumable):\n\
457 mantaMsg('Liquid save data')\n\
458 dict = { **fluid_data_dict_final_s$ID$, **fluid_data_dict_resume_s$ID$, **liquid_data_dict_final_s$ID$, **liquid_data_dict_resume_s$ID$ } if resumable else { **fluid_data_dict_final_s$ID$, **liquid_data_dict_final_s$ID$ }\n\
459 if not withMPSave or isWindows:\n\
460 fluid_file_export_s$ID$(dict=dict, path=path, framenr=framenr, file_format=file_format, file_name=file_data_s$ID$)\n\
461 else:\n\
462 fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, file_name=file_data_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=dict, do_join=False)\n";
463
464const std::string liquid_save_mesh =
465 "\n\
466def liquid_save_mesh_$ID$(path, framenr, file_format):\n\
467 mantaMsg('Liquid save mesh')\n\
468 dict = liquid_mesh_dict_s$ID$\n\
469 if not withMPSave or isWindows:\n\
470 fluid_file_export_s$ID$(dict=dict, path=path, framenr=framenr, file_format=file_format, file_name=file_mesh_s$ID$)\n\
471 else:\n\
472 fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, file_name=file_mesh_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=dict, do_join=False)\n\
473\n\
474def liquid_save_meshvel_$ID$(path, framenr, file_format):\n\
475 mantaMsg('Liquid save mesh vel')\n\
476 dict = liquid_meshvel_dict_s$ID$\n\
477 if not withMPSave or isWindows:\n\
478 fluid_file_export_s$ID$(dict=dict, path=path, framenr=framenr, file_format=file_format)\n\
479 else:\n\
480 fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=dict, do_join=False)\n";
481
482const std::string liquid_save_particles =
483 "\n\
484def liquid_save_particles_$ID$(path, framenr, file_format, resumable):\n\
485 mantaMsg('Liquid save particles')\n\
486 dict = { **liquid_particles_dict_final_s$ID$, **liquid_particles_dict_resume_s$ID$ } if resumable else { **liquid_particles_dict_final_s$ID$ }\n\
487 if not withMPSave or isWindows:\n\
488 fluid_file_export_s$ID$(dict=dict, path=path, framenr=framenr, file_format=file_format, file_name=file_particles_s$ID$)\n\
489 else:\n\
490 fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, file_name=file_particles_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=dict, do_join=False)\n";
491
493// STANDALONE MODE
495
496const std::string liquid_standalone =
497 "\n\
498# Helper function to call cache load functions\n\
499def load_data(frame, cache_resumable):\n\
500 liquid_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data, cache_resumable)\n\
501 if using_sndparts_s$ID$:\n\
502 liquid_load_particles_$ID$(os.path.join(cache_dir, 'particles'), frame, file_format_data, cache_resumable)\n\
503 if using_mesh_s$ID$:\n\
504 liquid_load_mesh_$ID$(os.path.join(cache_dir, 'mesh'), frame, file_format_mesh)\n\
505 if using_guiding_s$ID$:\n\
506 fluid_load_guiding_$ID$(os.path.join(cache_dir, 'guiding'), frame, file_format_data)\n\
507\n\
508# Helper function to call step functions\n\
509def step(frame):\n\
510 liquid_adaptive_step_$ID$(frame)\n\
511 if using_mesh_s$ID$:\n\
512 liquid_step_mesh_$ID$()\n\
513 if using_sndparts_s$ID$:\n\
514 liquid_step_particles_$ID$()\n";
const std::string liquid_alloc_viscosity
const std::string liquid_variables
const std::string liquid_variables_particles
const std::string liquid_alloc_particles
const std::string liquid_alloc
const std::string liquid_alloc_curvature
const std::string liquid_alloc_mesh
const std::string liquid_init_phi