thliebig / openEMS

openEMS is a free and open-source electromagnetic field solver using the EC-FDTD method.
http://openEMS.de
GNU General Public License v3.0
413 stars 146 forks source link

Are simulations supposed to be stochastic? #131

Closed KJ7LNW closed 8 months ago

KJ7LNW commented 8 months ago

I was getting up to speed on running simulations in python by making some structural changes to the simple patch antenna tutorial. The intention was to not make any computation changes until I had a good understanding of the graphs, how it worked, and how to maintain accuracy in the result.

While testing, I became confused when simple non-computational changes would produce slightly different values in the result. Thinking that the computation was repeatedly accurate, I assumed my code was to blame. However, it seems that multiple runs of that same tutorial produce different outputs almost every time!

To troubleshoot this and confirm this theory, I modified the simple patch antenna tutorial to display only the maximum impedance measurement that is graphed, and ran it multiple times without any other changes. The patch for that is below. I also set it to run a single thread, but even in single threaded mode it still produced varying results with every run. Here are the results for several single thread runs:

Zin max: (50.293444034445436+12.902222998582193j)
Zin max: (50.2795311795257+12.909637994936727j)
Zin max: (50.132137545630755+12.932930709438082j)
Zin max: (50.25600889357559+12.89932799535785j)
Zin max: (50.07321784196435+12.936819094877194j)
Zin max: (48.00902276073828+13.137620977536136j)

I realize that these values change by only a relatively small amount, but all we care about is consistency for testing/validating. We want them to be the same within floating point rounding error, so within 1e-6 or better. Below is the patch that I used for testing.

Questions:

Is this expected behavior?

Thank you for your help!

-Eric

diff --git a/python/Tutorials/Simple_Patch_Antenna.py b/python/Tutorials/Simple_Patch_Antenna.py
index c59dd09..53cdf0e 100644
--- a/python/Tutorials/Simple_Patch_Antenna.py
+++ b/python/Tutorials/Simple_Patch_Antenna.py
@@ -111,7 +111,7 @@ if 0:  # debugging only
     os.system(AppCSXCAD_BIN + ' "{}"'.format(CSX_file))

 if not post_proc_only:
-    FDTD.Run(Sim_Path, verbose=3, cleanup=True)
+    FDTD.Run(Sim_Path, verbose=3, cleanup=True, numThreads=1)

 ### Post-processing and plotting
@@ -146,6 +146,8 @@ else:
     legend()

 Zin = port.uf_tot/port.if_tot
+print("Zin max: {}".format(max(Zin)))
+quit()
 figure()
 plot(f/1e9, np.real(Zin), 'k-', linewidth=2, label='$\Re\{Z_{in}\}$')
 plot(f/1e9, np.imag(Zin), 'r--', linewidth=2, label='$\Im\{Z_{in}\}$')
thliebig commented 8 months ago

Hi, the FDTD algorithm is very deterministic and should give consistent results (even with multiple threads), but openEMS does check minimum every ~4s if the energy has decayed enough to stop. And this means the number of total timesteps simulated can vary depending on the machine and workload. If you want this to be more stable, disable the energy decay stop criteria and always run a fixed number of steps.

KJ7LNW commented 8 months ago

Got it, thanks!