38 x_min, x_max, y_min, y_max, z_min, z_max = bounds
40 x = np.linspace(x_min, x_max, n, dtype=float)
41 y = np.linspace(y_min, y_max, n, dtype=float)
42 z = np.linspace(z_min, z_max, n, dtype=float)
44 X, Y, Z = np.meshgrid(x, y, z, indexing=
"ij")
47 grid.dimensions = (n, n, n)
48 grid.origin = (x[0], y[0], z[0])
49 grid.spacing = (x[1] - x[0], y[1] - y[0], z[1] - z[0])
66 grid = grid_template.copy()
68 sdf_vals = sdf_func(delta_t, t, X, Y, Z, tx, ty, tz, block_id)
69 sdf_vals = np.asarray(sdf_vals, dtype=float)
72 if sdf_vals.shape != X.shape:
73 if sdf_vals.size == X.size:
75 sdf_vals = sdf_vals.reshape(X.shape)
78 f
"sdf() returned array with shape {sdf_vals.shape}, "
79 f
"but expected {X.shape} or flat of size {X.size}"
82 grid[
"SDF"] = sdf_vals.ravel(order=
"F")
85 surface = grid.contour([ISO_VALUE], scalars=
"SDF")
89 if surface.n_points == 0:
117 n_steps = len(load_steps)
119 print(
"No time steps to process.")
123 print(f
"Using {n_procs} worker process(es) for {n_steps} time steps.")
125 bounds = (-grid_size, grid_size, -grid_size, grid_size, -grid_size, grid_size)
126 sdf_path_str = str(sdf_path)
142 tasks.append(task_args)
149 with Pool(processes=n_procs)
as pool:
150 pool.map(_process_time_steps_chunk, tasks)
154 Worker function for multiprocessing.
185 grid, X, Y, Z =
make_grid(bounds=bounds, n=resolution)
192 dt = delta_times[idx]
196 for block_id
in block_ids:
197 vals = sdf_func(dt, t, X, Y, Z, 0.0, 0.0, 0.0, block_id)
198 vals = np.asarray(vals)
201 if vals.shape != X.shape:
202 if vals.size == X.size:
203 vals = vals.reshape(X.shape)
206 f
"sdf() returned shape {vals.shape}, "
207 f
"expected {X.shape} or flat size {X.size}"
210 if combined_sdf
is None:
211 combined_sdf = np.empty_like(vals)
214 combined_sdf[...] = vals
217 np.minimum(combined_sdf, vals, out=combined_sdf)
219 if combined_sdf
is None or first_block:
220 print(f
"[step {ls}] no SDF values, skipping")
225 grid[
"SDF"] = combined_sdf.ravel(order=
"F")
227 surface = grid.contour([ISO_VALUE], scalars=
"SDF")
229 print(f
"[step {ls}] contour generation failed, skipping")
232 if surface.n_points == 0:
233 print(f
"[step {ls}] empty surface, skipping")
236 filename = f
"{output_prefix}{ls}.stl"
237 surface.save(filename)
238 print(f
"[step {ls}] saved STL surface to {filename}")
242 grid[
"SDF"] = combined_sdf.ravel(order=
"F")
243 filename = f
"{output_prefix}{ls}.vti"
245 print(f
"[step {ls}] saved VTI volume to {filename}")
312 pat_loadstep = re.compile(
313 r"Load step\s+(\d+)\s+Time\s+([0-9.+-eE]+)\s+delta time\s+([0-9.+-eE]+)"
320 with log_path.open(
"r", encoding=
"utf-8")
as f:
322 line = re.sub(
r"\x1b\[[0-9;]*m",
"", line)
323 m = pat_loadstep.search(line)
326 load_steps.append(int(m.group(1)))
327 total_times.append(float(m.group(2)))
328 delta_times.append(float(m.group(3)))
331 print(f
"Extracted {len(load_steps)} time entries from 'Load step' lines.")
332 return load_steps, total_times, delta_times
336 r"\[petsc\]\s+(\d+)\s+TS\s+dt\s+([0-9.+-eE]+)\s+time\s+([0-9.+-eE]+)",
344 with log_path.open(
"r", encoding=
"utf-8")
as f:
346 line = re.sub(
r"\x1b\[[0-9;]*m",
"", line)
347 m = pat_ts.search(line)
350 load_steps.append(int(m.group(1)))
351 delta_times.append(float(m.group(2)))
352 total_times.append(float(m.group(3)))
356 "No time-step data found. Tried patterns:\n"
357 " - 'Load step <n> Time <t> delta time <dt>'\n"
358 " - '[petsc] <n> TS dt <dt> time <t>'"
361 print(f
"Extracted {len(load_steps)} time entries from PETSc TS lines.")
362 return load_steps, total_times, delta_times
406 module_name =
"sdf_module_from_file"
408 spec = importlib.util.spec_from_file_location(module_name, sdf_path)
409 if spec
is None or spec.loader
is None:
410 raise RuntimeError(f
"Cannot create import spec for {sdf_path}")
412 module = importlib.util.module_from_spec(spec)
413 sys.modules[module_name] = module
414 spec.loader.exec_module(module)
416 if not hasattr(module,
"sdf"):
417 raise RuntimeError(f
"The SDF file {sdf_path} does not define a function named 'sdf'.")
419 sdf_func = getattr(module,
"sdf")
421 if not callable(sdf_func):
422 raise RuntimeError(f
"'sdf' in {sdf_path} is not callable.")
425 sig = inspect.signature(sdf_func)
426 param_names = list(sig.parameters.keys())
428 if param_names != EXPECTED_SDF_ARGS:
430 f
"sdf() in {sdf_path} has wrong parameters.\n"
431 f
"Expected: ({', '.join(EXPECTED_SDF_ARGS)})\n"
432 f
"Got: ({', '.join(param_names)})"
generate_sdf_meshes_parallel(sdf_path, block_ids, load_steps, total_times, delta_times, output_prefix, surface_only, grid_size, resolution, n_procs)
sdf_block_to_surface(sdf_func, delta_t, t, block_id, grid_template, X, Y, Z, tx=0.0, ty=0.0, tz=0.0)