Skip to content

Commit 24d34aa

Browse files
authored
Merge branch 'main' into feature/grid-save-load
2 parents 45a59de + 9b38123 commit 24d34aa

File tree

8 files changed

+168
-51
lines changed

8 files changed

+168
-51
lines changed

tests/test_001_pec_cubic_cavity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def test_simulation(self):
100100
skip_cells = 12 # no. cells to skip in WP integration
101101
wake = WakeSolver(q=q, sigmaz=sigmaz, beta=beta,
102102
xsource=xs, ysource=ys, xtest=xt, ytest=yt,
103-
save=False, logfile=False, Ez_file='tests/001_Ez.h5',
103+
save=False, Ez_file='tests/001_Ez.h5',
104104
skip_cells=skip_cells,
105105
)
106106

tests/test_007_mpi_lossy_cavity.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,18 @@ class TestMPILossyCavity:
8686
-6.04105997e+01 ,-3.06532160e+01 ,-1.17749936e+01 ,-3.12574866e+00,
8787
-7.35339521e-01 ,-1.13085658e-01 , 7.18247535e-01 , 8.73829036e-02])
8888

89+
gridLogs = {'use_mesh_refinement': False, 'Nx': 60, 'Ny': 60, 'Nz': 140, 'dx': 0.008666666348775227, 'dy': 0.008666666348775227,
90+
'dz': 0.005714285799435207, 'stl_solids': {'cavity': 'tests/stl/007_vacuum_cavity.stl', 'shell': 'tests/stl/007_lossymetal_shell.stl'},
91+
'stl_materials': {'cavity': 'vacuum', 'shell': [30, 1.0, 30]}, 'gridInitializationTime': 0}
92+
93+
solverLogs = {'use_gpu': False, 'use_mpi': False, 'background': 'pec','bc_low': ['pec', 'pec', 'pec'],
94+
'bc_high': ['pec', 'pec', 'pec'],
95+
'dt': 6.970326728398968e-12, 'solverInitializationTime': 0}
96+
97+
wakeSolverLogs = {'ti': 2.8516132094735135e-09, 'q': 1e-09, 'sigmaz': 0.1, 'beta': 1.0,
98+
'xsource': 0.0, 'ysource': 0.0, 'xtest': 0.0, 'ytest': 0.0, 'chargedist': None,
99+
'skip_cells': 10, 'results_folder': 'tests/007_results/', 'wakelength': 10.0, 'simulationTime': 0}
100+
89101
img_folder = 'tests/007_img/'
90102

91103
def test_mpi_import(self):
@@ -326,3 +338,14 @@ def test_long_impedance(self):
326338
assert np.allclose(np.real(wake.Z)[::20], np.real(self.Z), rtol=0.1), "Real Impedance samples failed"
327339
assert np.allclose(np.imag(wake.Z)[::20], np.imag(self.Z), rtol=0.1), "Imag Impedance samples failed"
328340
assert np.cumsum(np.abs(wake.Z))[-1] == pytest.approx(250910.51090497518, 0.1), "Abs Impedance cumsum failed"
341+
342+
def test_log_file(self):
343+
global solver
344+
solver.logger.grid["gridInitializationTime"] = 0 #times can vary
345+
solver.logger.solver["solverInitializationTime"] = 0
346+
solver.logger.wakeSolver["simulationTime"] = 0
347+
logfile = os.path.join(solver.logger.wakeSolver["results_folder"], "wakis.log")
348+
assert os.path.exists(logfile), "Log file not created"
349+
assert solver.logger.grid == self.gridLogs, "Grid logs do not match expected values"
350+
assert solver.logger.solver == self.solverLogs, "Solver logs do not match expected values"
351+
assert solver.logger.wakeSolver == self.wakeSolverLogs, "WakeSolver logs do not match expected values"

wakis/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
from . import materials
1111
from . import wakeSolver
1212
from . import geometry
13+
from . import logger
1314
from . import field_monitors
1415

1516
from .field_monitors import FieldMonitor
1617
from .field import Field
1718
from .gridFIT3D import GridFIT3D
1819
from .solverFIT3D import SolverFIT3D
1920
from .wakeSolver import WakeSolver
21+
from .logger import Logger
2022

2123
from ._version import __version__

wakis/gridFIT3D.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
import h5py
1010

1111
from scipy.optimize import least_squares
12+
import time
1213

1314
from .field import Field
15+
from .logger import Logger
1416

1517
try:
1618
from mpi4py import MPI
@@ -91,6 +93,13 @@ def __init__(self, xmin=None, xmax=None,
9193
self.stl_translate = stl_translate
9294
self.stl_scale = stl_scale
9395
self.stl_colors = stl_colors
96+
self.update_logger(['stl_solids', 'stl_materials'])
97+
if stl_rotate != [0., 0., 0.]:
98+
self.update_logger(['stl_rotate'])
99+
if stl_translate != [0., 0., 0.]:
100+
self.update_logger(['stl_translate'])
101+
if stl_scale != 1.0:
102+
self.update_logger(['stl_scale'])
94103

95104
if stl_solids is not None:
96105
self._prepare_stl_dicts()
@@ -192,6 +201,8 @@ def __init__(self, xmin=None, xmax=None,
192201
if verbose:
193202
print(f'Total grid initialization time: {time.time() - t0} s')
194203

204+
self.gridInitializationTime = time.time()-t0
205+
self.update_logger(['gridInitializationTime'])
195206

196207
def compute_grid(self):
197208
X, Y, Z = np.meshgrid(self.x, self.y, self.z, indexing='ij')
@@ -1027,4 +1038,10 @@ def load_from_h5(self, filename):
10271038
print(f' * STL solids imported:\n\
10281039
{list(self.stl_solids.keys())}')
10291040
print(f' * STL solids assigned materials [eps_r, mu_r, sigma]:\n\
1030-
{list(self.stl_materials.values())}')
1041+
{list(self.stl_materials.values())}')
1042+
def update_logger(self, attrs):
1043+
"""
1044+
Assigns the parameters handed via attrs to the logger
1045+
"""
1046+
for atr in attrs:
1047+
self.logger.grid[atr] = getattr(self, atr)

wakis/logger.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# copyright ################################# #
2+
# This file is part of the wakis Package. #
3+
# Copyright (c) CERN, 2025. #
4+
# ########################################### #
5+
6+
from tqdm import tqdm
7+
8+
import numpy as np
9+
import time
10+
import h5py
11+
import os
12+
import json
13+
14+
from scipy.constants import c as c_light, epsilon_0 as eps_0, mu_0 as mu_0
15+
from scipy.sparse import csc_matrix as sparse_mat
16+
from scipy.sparse import diags, hstack, vstack
17+
18+
19+
20+
class Logger():
21+
22+
def __init__(self):
23+
self.grid = {}
24+
self.solver = {}
25+
self.wakeSolver = {}
26+
27+
def save_logs(self):
28+
"""
29+
Save all logs (grid, solver, wakeSolver) into log-file inside the results folder.
30+
"""
31+
logfile = os.path.join(self.wakeSolver["results_folder"], "wakis.log")
32+
33+
# Write sections
34+
if not os.path.exists(self.wakeSolver["results_folder"]):
35+
os.mkdir(self.wakeSolver["results_folder"])
36+
37+
with open(logfile, "w", encoding="utf-8") as fh:
38+
fh.write("Simulation Parameters\n")
39+
fh.write("""=====================\n\n""")
40+
41+
sections = [
42+
("WakeSolver Logs", self.wakeSolver),
43+
("Solver Logs", self.solver),
44+
("Grid Logs", self.grid),
45+
]
46+
47+
for title, data in sections:
48+
fh.write(f"\n## {title} ##\n")
49+
if not data:
50+
fh.write("(empty)\n")
51+
continue
52+
53+
# convert non-serializable values to strings recursively
54+
def _convert(obj):
55+
if isinstance(obj, dict):
56+
return {k: _convert(v) for k, v in obj.items()}
57+
if isinstance(obj, (list, tuple)):
58+
return [_convert(v) for v in obj]
59+
try:
60+
json.dumps(obj)
61+
return obj
62+
except Exception:
63+
return str(obj)
64+
65+
clean = _convert(data)
66+
fh.write(json.dumps(clean, indent=2, ensure_ascii=False))
67+
fh.write("\n")

wakis/routines.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import numpy as np
77
import h5py
8+
import time
89
from tqdm import tqdm
910
from wakis.sources import Beam
1011

@@ -299,6 +300,7 @@ def save_to_h5(self, hf, field, x, y, z, comp, n):
299300
plot_from = int(self.ti/self.dt)
300301

301302
print('Running electromagnetic time-domain simulation...')
303+
t0 = time.time()
302304
for n in tqdm(range(Nt)):
303305

304306
# Initial condition
@@ -342,4 +344,9 @@ def save_to_h5(self, hf, field, x, y, z, comp, n):
342344

343345
# Compute wakefield magnitudes is done inside WakeSolver
344346
self.wake.solve(compute_plane=compute_plane)
345-
347+
348+
# Forward parameters to logger
349+
self.logger.wakeSolver=self.wake.logger.wakeSolver
350+
self.logger.wakeSolver["wakelength"]=wakelength
351+
self.logger.wakeSolver["simulationTime"]=time.time()-t0
352+
self.logger.save_logs()

wakis/solverFIT3D.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from .materials import material_lib
1616
from .plotting import PlotMixin
1717
from .routines import RoutinesMixin
18+
from .logger import Logger
1819

1920
try:
2021
from cupyx.scipy.sparse import csc_matrix as gpu_sparse_mat
@@ -92,8 +93,8 @@ def __init__(self, grid, wake=None, cfln=0.5, dt=None,
9293
'''
9394

9495
self.verbose = verbose
95-
if verbose:
96-
t0 = time.time()
96+
t0 = time.time()
97+
self.logger = Logger()
9798

9899
# Flags
99100
self.step_0 = True
@@ -110,10 +111,11 @@ def __init__(self, grid, wake=None, cfln=0.5, dt=None,
110111
self.one_step = self._one_step
111112
if use_stl:
112113
self.use_conductors = False
114+
self.update_logger(['use_gpu', 'use_mpi'])
113115

114116
# Grid
115117
self.grid = grid
116-
118+
self.background = bg
117119
self.Nx = self.grid.Nx
118120
self.Ny = self.grid.Ny
119121
self.Nz = self.grid.Nz
@@ -131,6 +133,7 @@ def __init__(self, grid, wake=None, cfln=0.5, dt=None,
131133
self.iA = self.grid.iA
132134
self.tL = self.grid.tL
133135
self.itA = self.grid.itA
136+
self.update_logger(['grid','background'])
134137

135138
# Wake computation
136139
self.wake = wake
@@ -177,7 +180,8 @@ def __init__(self, grid, wake=None, cfln=0.5, dt=None,
177180
print('Applying boundary conditions...')
178181
self.bc_low = bc_low
179182
self.bc_high = bc_high
180-
self.apply_bc_to_C()
183+
self.update_logger(['bc_low', 'bc_high'])
184+
self.apply_bc_to_C()
181185

182186
# Materials
183187
if verbose:
@@ -207,6 +211,7 @@ def __init__(self, grid, wake=None, cfln=0.5, dt=None,
207211
self.pml_hi = 1.e-1
208212
self.pml_func = np.geomspace
209213
self.fill_pml_sigmas()
214+
self.update_logger(['n_pml'])
210215

211216
# Timestep calculation
212217
if verbose:
@@ -217,6 +222,7 @@ def __init__(self, grid, wake=None, cfln=0.5, dt=None,
217222
else:
218223
self.dt = dt
219224
self.dt = dtype(self.dt)
225+
self.update_logger(['dt'])
220226

221227
if self.use_conductivity: # relaxation time criterion tau
222228

@@ -261,6 +267,9 @@ def __init__(self, grid, wake=None, cfln=0.5, dt=None,
261267
if verbose:
262268
print(f'Total solver initialization time: {time.time() - t0} s')
263269

270+
self.solverInitializationTime = time.time() - t0
271+
self.update_logger(['solverInitializationTime'])
272+
264273
def update_tensors(self, tensor='all'):
265274
'''Update tensor matrices after
266275
Field ieps, imu or sigma have been modified
@@ -1118,4 +1127,14 @@ def reset_fields(self):
11181127
for d in ['x', 'y', 'z']:
11191128
self.E[:, :, :, d] = 0.0
11201129
self.H[:, :, :, d] = 0.0
1121-
self.J[:, :, :, d] = 0.0
1130+
self.J[:, :, :, d] = 0.0
1131+
1132+
def update_logger(self, attrs):
1133+
"""
1134+
Assigns the parameters handed via attrs to the logger
1135+
"""
1136+
for atr in attrs:
1137+
if atr == 'grid':
1138+
self.logger.grid = self.grid.logger.grid
1139+
else:
1140+
self.logger.solver[atr] = getattr(self, atr)

0 commit comments

Comments
 (0)