Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix memory leaks in structure and fields load during checkpointing #1872

Merged
merged 6 commits into from
Jan 1, 2022

Conversation

oskooi
Copy link
Collaborator

@oskooi oskooi commented Dec 29, 2021

Fixes two memory leaks introduced in #1738 and reported by the address sanitizer.

cc @kkg4theweb

@oskooi oskooi added the bug label Dec 29, 2021
src/fields_dump.cpp Outdated Show resolved Hide resolved
src/structure_dump.cpp Outdated Show resolved Hide resolved
@oskooi
Copy link
Collaborator Author

oskooi commented Dec 30, 2021

While this PR with the latest commit (e2eae75) fixes the memory leak in the C++ unit test dump_load.cpp, it is causing the Python unit test test_dump_load.py to fail. The failing Python unit test involves time stepping the fields in a reference simulation until t=15, saving the fields at t=15, and running until t=20. The fields at some arbitrary monitor point are saved at every 1 time units and the results are compared to a second test simulation which involves loading the fields from the reference simulation at t=15. What is strange is that both simulations produce identical results for t=15 and t=16 but then the test simulation starts to diverge.

Using MPI version 3.1, 1 processes
Saving temp files to dir: /tmp/meepTwK9OZ
Running test_load_dump_fields_2d
-----------
Initializing structure...
Halving computational cell along direction y
time for choose_chunkdivision = 0.000271299 s
Working in 2D dimensions.
Computational cell is 5 x 5 x 0 with resolution 50
     block, center = (0,0,0)
          size (1,1,1e+20)
          axes (1,0,0), (0,1,0), (0,0,1)
          dielectric constant epsilon diagonal = (10.24,10.24,10.24)
     block, center = (1,0,0)
          size (1,1,1e+20)
          axes (1,0,0), (0,1,0), (0,0,1)
          dielectric constant epsilon diagonal = (13,13,13)
time for set_epsilon = 0.0707238 s
-----------
run 0 finished at t = 15.0 (1500 timesteps)
creating epsilon from file "/tmp/meepTwK9OZ/test_load_dump_fields/structure.h5" (1)...
Dumped structure to file: /tmp/meepTwK9OZ/test_load_dump_fields/structure.h5 (True)
creating fields output file "/tmp/meepTwK9OZ/test_load_dump_fields/fields.h5" (1)...
Dumped fields to file: /tmp/meepTwK9OZ/test_load_dump_fields/fields.h5 (True)
run 1 finished at t = 20.0 (2000 timesteps)
-----------
Initializing structure...
Halving computational cell along direction y
time for choose_chunkdivision = 9.4034e-05 s
Working in 2D dimensions.
Computational cell is 5 x 5 x 0 with resolution 50
time for set_epsilon = 0.0330667 s
-----------
Working in 2D dimensions.
Computational cell is 5 x 5 x 0 with resolution 50
time for set_epsilon = 0.0333062 s
-----------
reading epsilon from file "/tmp/meepTwK9OZ/test_load_dump_fields/structure.h5" (1)...
Loaded structure from file: /tmp/meepTwK9OZ/test_load_dump_fields/structure.h5 (True)
reading fields from file "/tmp/meepTwK9OZ/test_load_dump_fields/fields.h5" (1)...
Loaded fields from file: /tmp/meepTwK9OZ/test_load_dump_fields/fields.h5 (True)
on time step 1500 (time=15), 2.0487 s/step
run 0 finished at t = 20.0 (2000 timesteps)
F
======================================================================
FAIL: test_load_dump_fields_2d (__main__.TestLoadDump)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_dump_load.py", line 257, in test_load_dump_fields_2d
    self._load_dump_fields_2d()
  File "test_dump_load.py", line 251, in _load_dump_fields_2d
    self.assertAlmostEqual(ref_field_points[t], v)
AssertionError: 0.3447239547967911 != 0.34472334384918213 within 7 places

----------------------------------------------------------------------
Ran 1 test in 0.464s

FAILED (failures=1)

Here are the results from the two runs.

ref:, 15.0, 0.42263978719711304
ref:, 16.0, 0.3860078901052475
ref:, 17.0, 0.3447239547967911
ref:, 18.0, 0.30143244564533234
ref:, 19.0, 0.25082115083932877
ref:, 20.0, 0.19293657690286636

test:, 15.0, 0.42263978719711304
test:, 16.0, 0.3860078901052475
test:, 17.0, 0.34472334384918213 ***
test:, 18.0, 0.3033006340265274 ***
test:, 19.0, 0.2514386847615242 ***
test:, 20.0, 0.18865110725164413 ***

src/fields_dump.cpp Outdated Show resolved Hide resolved
@oskooi
Copy link
Collaborator Author

oskooi commented Dec 31, 2021

I think I have tracked down the cause of the two failing tests. There seems to be a bug in saving/load the fields in the PML regions. This can be demonstrated by simply removing pml_layers from the Simulation object which causes both of the failing tests shown below to pass. It's unclear though why this is related to this PR.

# Tests dumping/loading of fields & structure in 2d.
def _load_dump_fields_2d(self, single_parallel_file=True):
resolution = 50
cell = mp.Vector3(5, 5)
sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.4), center=mp.Vector3(), component=mp.Ez)
one_by_one = mp.Vector3(1, 1, mp.inf)
geometry = [mp.Block(material=mp.Medium(index=3.2), center=mp.Vector3(), size=one_by_one),
mp.Block(material=mp.Medium(epsilon=13), center=mp.Vector3(1), size=one_by_one)]
pml_layers = [mp.PML(0.5)]
symmetries = [mp.Mirror(mp.Y)]
sim1 = mp.Simulation(resolution=resolution,
cell_size=cell,
boundary_layers=pml_layers,
geometry=geometry,
symmetries=symmetries,
sources=[sources])

# Tests dumping/loading of fields & structure in 3d.
def _load_dump_fields_3d(self, single_parallel_file=True):
resolution = 15
cell = mp.Vector3(2.6, 2.2, 2.3)
sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.4), center=mp.Vector3(), component=mp.Hx)
one_by_one_by_one = mp.Vector3(1, 1, 1)
geometry = [mp.Block(material=mp.Medium(index=2.4), center=mp.Vector3(), size=one_by_one_by_one),
mp.Block(material=mp.Medium(epsilon=7.9), center=mp.Vector3(1), size=one_by_one_by_one)]
pml_layers = [mp.PML(0.5)]
symmetries = [mp.Mirror(mp.Y,phase=-1),mp.Mirror(mp.Z,phase=-1)]
sim1 = mp.Simulation(resolution=resolution,
cell_size=cell,
boundary_layers=pml_layers,
geometry=geometry,
symmetries=symmetries,
sources=[sources])

@codecov-commenter
Copy link

codecov-commenter commented Jan 1, 2022

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 50.28%. Comparing base (e28f391) to head (6349c9b).
Report is 313 commits behind head on master.

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@             Coverage Diff             @@
##           master    #1872       +/-   ##
===========================================
- Coverage   73.40%   50.28%   -23.13%     
===========================================
  Files          17       17               
  Lines        4896     4914       +18     
===========================================
- Hits         3594     2471     -1123     
- Misses       1302     2443     +1141     

see 16 files with indirect coverage changes

@oskooi
Copy link
Collaborator Author

oskooi commented Jan 1, 2022

This is finally working. The bug was a bit subtle to track down and has to do with the fact that during the fields initialization of fields_chunk::alloc_f H = B in the PML region:

meep/src/fields.cpp

Lines 475 to 483 in e41a735

/* initially, we just set H == B ... later on, we lazily allocate
H fields if needed (if mu != 1 or in PML) in update_eh */
component bc = direction_component(Bx, component_direction(c));
if (!f[bc][cmp]) {
f[bc][cmp] = new realnum[gv.ntot()];
for (size_t i = 0; i < gv.ntot(); i++)
f[bc][cmp][i] = 0.0;
}
f[c][cmp] = f[bc][cmp];

H is lazily allocated during the first timestep in fields_chunk::update_eh:

meep/src/update_eh.cpp

Lines 166 to 172 in e41a735

// lazily allocate any E/H fields that are needed (H==B initially)
if (i == 0 && f[ec][cmp] == f[dc][cmp] &&
(s->chi1inv[ec][d_ec] || have_f_minus_p || dsigw != NO_DIRECTION)) {
f[ec][cmp] = new realnum[gv.ntot()];
memcpy(f[ec][cmp], f[dc][cmp], gv.ntot() * sizeof(realnum));
allocated_eh = true;
}

The problem here is that when the saved fields are being loaded from the HDF5 file, H = B (because fields::step() and thus fields_chunk::update_eh has not yet been invoked) and thus the saved H fields were never actually being loaded into a separate H fields array. The H fields in the PML region were being assigned to the saved B fields in the PML region which is why the results were slightly different from the reference simulation. The fix involved manually allocating the fields array for H in the PML region within fields::load_fields_chunk_field (rather than in fields_chunk::update_eh) so that the saved H fields from could be then be correctly loaded from the file into the H fields array.

I added a comment to explain all this in fields::load_fields_chunk_field.

@oskooi oskooi merged commit d7101c4 into NanoComp:master Jan 1, 2022
@oskooi oskooi deleted the struct_fields_load_mem_leak branch January 1, 2022 02:41
mochen4 pushed a commit to mochen4/meep that referenced this pull request Feb 16, 2022
…anoComp#1872)

* fix memory leaks in structure and fields load during checkpointing

* delete the chi1inv and fields array if it exists and reallocate

* in unit test, set gaussian source cutoff to 0 due to off-by-1 timestep counter bug

* remove cutoff=0 from unit tests

* lazily allocate H only if B is not NULL

* allocate fields array for H in PML region
mochen4 pushed a commit to mochen4/meep that referenced this pull request Feb 16, 2022
…anoComp#1872)

* fix memory leaks in structure and fields load during checkpointing

* delete the chi1inv and fields array if it exists and reallocate

* in unit test, set gaussian source cutoff to 0 due to off-by-1 timestep counter bug

* remove cutoff=0 from unit tests

* lazily allocate H only if B is not NULL

* allocate fields array for H in PML region
stevengj added a commit that referenced this pull request Mar 10, 2022
* first draft of loop_in_chunks using grid_vol calculations

* try to only use owned points in loop_in_chunks

* don't unpad if !use_symmetry

* stop vscode from complaining about comments

* rm hack to loop over centered grid

* fix and example

* almost fix

* before fix

* one more loop over num_chunk

* include set

* different approach

* minor

* include climits

* include climits

* fix retval

* clean up

* using flipped

* add missing changes

* fix bug

* fix pml

* Fix memory leaks in SWIG wrappers. (#1826)

* Fix memory leaks in SWIG wrappers.

* move delete into material_free

Co-authored-by: Steven G. Johnson <[email protected]>

* Fix adjoint gradient with conductivities (#1830)

* damp_fix

* increase run time

Co-authored-by: Mo Chen <[email protected]>

* plot geometry for dispersive materials without initializing structure object (#1827)

* plot geometry without initializing structure class

* update docstrings

* rotate epsilon grid by 90 degrees to properly orient axes

* add support for dispersive ε

* update markdown pages from docstrings

* make frequency and resolution parameters of plot2D dictionary keys of eps_parameters

* reinstate frequency parameter of plot2D and add warning that it is deprecated

* fix order of frequency check

* unit test for `get_epsilon_grid` (#1835)

* unit test for get_epsilon_grid

* fix

* limit test points to homogeneous regions (i.e. no material interfaces) and away from potential chunk boundaries

* support for single-precision floating point for fields array functions (#1833)

* switch dft-related functions to using realnum from double

* more fixes

* more type conversions from double to realnum

* adjust check tolerance of tests/integrate.cpp based on floating-point precision

* more fixes

* rebase from master from fix merge conflicts

* slight adjustment to tolerances in unit tests and update docs

* remove type check in test_adjoint_solver.py

* revert return types of integration functions to double

* revert return type of process_dft_component to double

* cleanup

* Fix memory leaks (#1839)

* Fix memory leaks

* Add kkg to authors list

* Fix for Issue #1834  (#1840)

* Fix memory leaks

* Add kkg to authors list

* Expose set_default_material and use it in libpympb/pympb.cpp

* use unique_ptr (C++11) instead of make_unique (C++14) (#1844)

* Use None instead of empty list in constructors (#1846)

* use None

* minor fix

Co-authored-by: Mo Chen <[email protected]>

* Define what happens when `β=∞` and `u=η` (#1842)

* define what happens when beta=inf and u=0.5

* use eta not 0.5

* Update src/meepgeom.cpp

Co-authored-by: Steven G. Johnson <[email protected]>

* fix for arrays (#1845)

* minor improvements to docs (#1848)

* update homebrew instructions for hdf5 and openblas

(fixes #1850)

* recommend python3 on macos

* silence compiler warnings

* whoops, missing commit

* tests need scipy and autograd

* missing sudo

* parameterized package is also used for tests

* h5py and jax on mac

* note on autogen.sh for git clone

* xcode installation shortcut

* bug fix for get_epsilon_point and cell boundary in parallel simulation (#1849)

* bug fix for get_epsilon_point and cell boundary in parallel simulation

* check for six digits in test_material_grid.py because of single precision

* unit test for conductivity (#1857)

* unit test for conductivity

* describe in the docs how to model the attenutation coefficient using conductivity

* Update python/tests/test_conductivity.py

Co-authored-by: Steven G. Johnson <[email protected]>

* Fix the failure message for absorber 1D test (#1859)

* add missing fixed field phase to MPB unit test (#1860)

* fix memory leak in array-slice-ll.cpp (#1865)

* fix memory leak in array-slice-ll.cpp

* reinstate line break

* fix memory leak in cyl-ellipsoid-ll.cpp (#1866)

* level parameter for contour plot calls epsilon data (#1869)

* fix heap buffer overflow error for update E from D in cylindrical coordinates (#1871)

* Add cylindrical coordinates support for `plot2d` (#1873)

* add visualization support for plot2d

* bug fix with cartesian plotting

* fix near-field monitor position in cylindrical coordinate tutorial (#1874)

* fix memory leaks in structure and fields load during checkpointing (#1872)

* fix memory leaks in structure and fields load during checkpointing

* delete the chi1inv and fields array if it exists and reallocate

* in unit test, set gaussian source cutoff to 0 due to off-by-1 timestep counter bug

* remove cutoff=0 from unit tests

* lazily allocate H only if B is not NULL

* allocate fields array for H in PML region

* fix two memory leaks in geom_epsilon class (#1877)

* fix two memory leaks in geom_epsilon class

* delete global variable default_material at the end of unit tests

* add unset_default_material function to class meep_geom

* include ring-ll.cpp in C++ unit tests (#1878)

* include ring-ll.cpp in C++ unit tests

* only validate Harminv modes with error below some threshold

* fix and example

* first draft of loop_in_chunks using grid_vol calculations

* try to only use owned points in loop_in_chunks

* don't unpad if !use_symmetry

* stop vscode from complaining about comments

* rm hack to loop over centered grid

* almost fix

* before fix

* one more loop over num_chunk

* include set

* different approach

* minor

* include climits

* include climits

* fix retval

* clean up

* using flipped

* add missing changes

* fix bug

* fix pml

* Fix memory leaks in SWIG wrappers. (#1826)

* Fix memory leaks in SWIG wrappers.

* move delete into material_free

Co-authored-by: Steven G. Johnson <[email protected]>

* Fix adjoint gradient with conductivities (#1830)

* damp_fix

* increase run time

Co-authored-by: Mo Chen <[email protected]>

* plot geometry for dispersive materials without initializing structure object (#1827)

* plot geometry without initializing structure class

* update docstrings

* rotate epsilon grid by 90 degrees to properly orient axes

* add support for dispersive ε

* update markdown pages from docstrings

* make frequency and resolution parameters of plot2D dictionary keys of eps_parameters

* reinstate frequency parameter of plot2D and add warning that it is deprecated

* fix order of frequency check

* unit test for `get_epsilon_grid` (#1835)

* unit test for get_epsilon_grid

* fix

* limit test points to homogeneous regions (i.e. no material interfaces) and away from potential chunk boundaries

* support for single-precision floating point for fields array functions (#1833)

* switch dft-related functions to using realnum from double

* more fixes

* more type conversions from double to realnum

* adjust check tolerance of tests/integrate.cpp based on floating-point precision

* more fixes

* rebase from master from fix merge conflicts

* slight adjustment to tolerances in unit tests and update docs

* remove type check in test_adjoint_solver.py

* revert return types of integration functions to double

* revert return type of process_dft_component to double

* cleanup

* Fix memory leaks (#1839)

* Fix memory leaks

* Add kkg to authors list

* Fix for Issue #1834  (#1840)

* Fix memory leaks

* Add kkg to authors list

* Expose set_default_material and use it in libpympb/pympb.cpp

* use unique_ptr (C++11) instead of make_unique (C++14) (#1844)

* Use None instead of empty list in constructors (#1846)

* use None

* minor fix

Co-authored-by: Mo Chen <[email protected]>

* Define what happens when `β=∞` and `u=η` (#1842)

* define what happens when beta=inf and u=0.5

* use eta not 0.5

* Update src/meepgeom.cpp

Co-authored-by: Steven G. Johnson <[email protected]>

* fix for arrays (#1845)

* minor improvements to docs (#1848)

* update homebrew instructions for hdf5 and openblas

(fixes #1850)

* recommend python3 on macos

* silence compiler warnings

* whoops, missing commit

* tests need scipy and autograd

* missing sudo

* parameterized package is also used for tests

* h5py and jax on mac

* note on autogen.sh for git clone

* xcode installation shortcut

* bug fix for get_epsilon_point and cell boundary in parallel simulation (#1849)

* bug fix for get_epsilon_point and cell boundary in parallel simulation

* check for six digits in test_material_grid.py because of single precision

* unit test for conductivity (#1857)

* unit test for conductivity

* describe in the docs how to model the attenutation coefficient using conductivity

* Update python/tests/test_conductivity.py

Co-authored-by: Steven G. Johnson <[email protected]>

* Fix the failure message for absorber 1D test (#1859)

* add missing fixed field phase to MPB unit test (#1860)

* fix memory leak in array-slice-ll.cpp (#1865)

* fix memory leak in array-slice-ll.cpp

* reinstate line break

* fix memory leak in cyl-ellipsoid-ll.cpp (#1866)

* level parameter for contour plot calls epsilon data (#1869)

* fix heap buffer overflow error for update E from D in cylindrical coordinates (#1871)

* Add cylindrical coordinates support for `plot2d` (#1873)

* add visualization support for plot2d

* bug fix with cartesian plotting

* fix near-field monitor position in cylindrical coordinate tutorial (#1874)

* fix memory leaks in structure and fields load during checkpointing (#1872)

* fix memory leaks in structure and fields load during checkpointing

* delete the chi1inv and fields array if it exists and reallocate

* in unit test, set gaussian source cutoff to 0 due to off-by-1 timestep counter bug

* remove cutoff=0 from unit tests

* lazily allocate H only if B is not NULL

* allocate fields array for H in PML region

* fix two memory leaks in geom_epsilon class (#1877)

* fix two memory leaks in geom_epsilon class

* delete global variable default_material at the end of unit tests

* add unset_default_material function to class meep_geom

* include ring-ll.cpp in C++ unit tests (#1878)

* include ring-ll.cpp in C++ unit tests

* only validate Harminv modes with error below some threshold

* fix and example

* first draft of loop_in_chunks using grid_vol calculations

* try to only use owned points in loop_in_chunks

* don't unpad if !use_symmetry

* stop vscode from complaining about comments

* rm hack to loop over centered grid

* almost fix

* before fix

* one more loop over num_chunk

* include set

* different approach

* minor

* include climits

* include climits

* fix retval

* clean up

* using flipped

* add missing changes

* fix bug

* fix pml

* Fix adjoint gradient with conductivities (#1830)

* damp_fix

* increase run time

Co-authored-by: Mo Chen <[email protected]>

* plot geometry for dispersive materials without initializing structure object (#1827)

* plot geometry without initializing structure class

* update docstrings

* rotate epsilon grid by 90 degrees to properly orient axes

* add support for dispersive ε

* update markdown pages from docstrings

* make frequency and resolution parameters of plot2D dictionary keys of eps_parameters

* reinstate frequency parameter of plot2D and add warning that it is deprecated

* fix order of frequency check

* support for single-precision floating point for fields array functions (#1833)

* switch dft-related functions to using realnum from double

* more fixes

* more type conversions from double to realnum

* adjust check tolerance of tests/integrate.cpp based on floating-point precision

* more fixes

* rebase from master from fix merge conflicts

* slight adjustment to tolerances in unit tests and update docs

* remove type check in test_adjoint_solver.py

* revert return types of integration functions to double

* revert return type of process_dft_component to double

* cleanup

* Fix memory leaks (#1839)

* Fix memory leaks

* Add kkg to authors list

* Fix for Issue #1834  (#1840)

* Fix memory leaks

* Add kkg to authors list

* Expose set_default_material and use it in libpympb/pympb.cpp

* use unique_ptr (C++11) instead of make_unique (C++14) (#1844)

* update homebrew instructions for hdf5 and openblas

(fixes #1850)

* rm hack to loop over centered grid

* almost fix

* one more loop over num_chunk

* different approach

* include climits

* include climits

* clean up

* using flipped

* Revert "fix pml"

This reverts commit 9ed741e.

* fix rebase

* fix rebase

* fix rebase

* fix rebase

* fix rebase

* fix error

* increase tol

* cleanup

* cleanup

Co-authored-by: Steven G. Johnson <[email protected]>
Co-authored-by: Mo Chen <[email protected]>
Co-authored-by: Mo Chen <[email protected]>
Co-authored-by: Krishna Gadepalli <[email protected]>
Co-authored-by: Ardavan Oskooi <[email protected]>
Co-authored-by: Steven G. Johnson <[email protected]>
Co-authored-by: Alec Hammond <[email protected]>
Co-authored-by: Andreas Hoenselaar <[email protected]>
Co-authored-by: simbilod <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants