From cb512b7be12a03d98b66dd3174f27215ff2a71b4 Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Sat, 29 Jul 2017 12:39:35 -0500 Subject: [PATCH 1/2] Add typemap for SourceTime and src_time --- python/meep.i | 31 +++++++++++++++++++ python/tests/test_bend_flux.py | 2 +- python/tests/test_cyl_ellipsoid.py | 2 +- python/tests/test_physical.py | 2 +- python/tests/test_ring.py | 2 +- python/tests/test_source.py | 49 ++++++++++++++++++++++++++++-- python/typemap_utils.cpp | 22 +++++++++++++- 7 files changed, 103 insertions(+), 7 deletions(-) diff --git a/python/meep.i b/python/meep.i index 37fa1fb26..fe84113e2 100644 --- a/python/meep.i +++ b/python/meep.i @@ -45,6 +45,7 @@ extern boolean point_in_objectp(vector3 p, GEOMETRIC_OBJECT o); PyObject *py_callback = NULL; static PyObject *py_geometric_object(); +static PyObject *py_source_time_object(); static PyObject* vec2py(const meep::vec &v); static double py_callback_wrap(const meep::vec &v); static int pyv3_to_v3(PyObject *po, vector3 *v); @@ -152,6 +153,36 @@ static int py_list_to_gobj_list(PyObject *po, geometric_object_list *l); delete[] $1.items; } +// Typemap suite for sources + +%typecheck(SWIG_TYPECHECK_POINTER) const meep::src_time & { + int py_source_time = PyObject_IsInstance($input, py_source_time_object()); + int swig_src_time = PyObject_IsInstance($input, py_meep_src_time_object()); + + $1 = py_source_time || swig_src_time; +} + +%typemap(in) const meep::src_time & { + PyObject *swig_obj = NULL; + void *tmp_ptr = 0; + int tmp_res = 0; + + if(PyObject_IsInstance($input, py_source_time_object())) { + swig_obj = PyObject_GetAttrString($input, "swigobj"); + } else if(PyObject_IsInstance($input, py_meep_src_time_object())) { + swig_obj = $input; + } else { + PyErr_SetString(PyExc_TypeError, "Expected a meep.source.SourceTime or a meep.src_time\n"); + SWIG_fail; + } + + tmp_res = SWIG_ConvertPtr(swig_obj, &tmp_ptr, $1_descriptor, 0); + if(!SWIG_IsOK(tmp_res)) { + SWIG_exception_fail(SWIG_ArgError(tmp_res), "Couldn't convert Python object to meep::src_time"); + } + $1 = reinterpret_cast(tmp_ptr); +} + // Rename python builtins %rename(br_apply) meep::boundary_region::apply; %rename(_is) meep::dft_chunk::is; diff --git a/python/tests/test_bend_flux.py b/python/tests/test_bend_flux.py index 975595a52..879fd3ace 100644 --- a/python/tests/test_bend_flux.py +++ b/python/tests/test_bend_flux.py @@ -56,7 +56,7 @@ def bend_flux(no_bend): df = 0.1 src = GaussianSource(fcen, df) v = mp.volume(mp.vec(1.0 - 0.5 * sx, wvg_ycen), mp.vec(0.0, w)) - f.add_volume_source(mp.Ez, src.swigobj, v) + f.add_volume_source(mp.Ez, src, v) f_start = fcen - 0.5 * df f_end = fcen + 0.5 * df diff --git a/python/tests/test_cyl_ellipsoid.py b/python/tests/test_cyl_ellipsoid.py index 5574849da..a01e5879d 100644 --- a/python/tests/test_cyl_ellipsoid.py +++ b/python/tests/test_cyl_ellipsoid.py @@ -55,7 +55,7 @@ def main(args): src = GaussianSource(fcen, df) src_point = mp.vec(0.0, 0.0) src_size = mp.vec(10.0, 10.0) - f.add_volume_source(src_cmpt, src.swigobj, mp.volume(src_point, src_size)) + f.add_volume_source(src_cmpt, src, mp.volume(src_point, src_size)) f.output_hdf5(mp.Dielectric, f.total_volume()) stop_time = 23.0 diff --git a/python/tests/test_physical.py b/python/tests/test_physical.py index 4b6c58b3c..c97949145 100644 --- a/python/tests/test_physical.py +++ b/python/tests/test_physical.py @@ -39,7 +39,7 @@ def radiating_base(self, sq_ratio, solve_cw=True): f = mp.fields(s) src = ContinuousSource(w) - f.add_point_source(mp.Ez, src.swigobj, self.pnt_src_vec) + f.add_point_source(mp.Ez, src, self.pnt_src_vec) # let the source reach steady state if solve_cw: diff --git a/python/tests/test_ring.py b/python/tests/test_ring.py index 09bbd794d..22b5cb79f 100644 --- a/python/tests/test_ring.py +++ b/python/tests/test_ring.py @@ -57,7 +57,7 @@ def main(args): df = 0.1 src = GaussianSource(fcen, df) v = mp.volume(mp.vec(r + 0.1, 0.0), mp.vec(0.0, 0.0)) - f.add_volume_source(mp.Ez, src.swigobj, v) + f.add_volume_source(mp.Ez, src, v) T = 300.0 stop_time = f.last_source_time() + T diff --git a/python/tests/test_source.py b/python/tests/test_source.py index 5c6b3063e..45af09f1b 100644 --- a/python/tests/test_source.py +++ b/python/tests/test_source.py @@ -1,7 +1,8 @@ import unittest -from meep.geom import Vector3 -from meep.source import EigenModeSource, ContinuousSource +import meep as mp +from meep.geom import Cylinder, Vector3 +from meep.source import EigenModeSource, ContinuousSource, GaussianSource class TestEigenModeSource(unittest.TestCase): @@ -21,5 +22,49 @@ def test_eig_lattice_defaults(self): self.assertEqual(custom_lattice.eig_lattice_center, elc) +class TestSourceTypemaps(unittest.TestCase): + + expected_msg = "Expected a meep.source.SourceTime or a meep.src_time\n" + + def setUp(self): + + def dummy_eps(v): + return 1.0 + + gv = mp.voltwo(16, 16, 10) + gv.center_origin() + sym = mp.mirror(mp.Y, gv) + the_structure = mp.structure(gv, dummy_eps, mp.pml(2), sym) + objects = [] + objects.append(Cylinder(1)) + mp.set_materials_from_geometry(the_structure, objects) + self.f = mp.fields(the_structure) + self.v = mp.volume(mp.vec(1.1, 0.0), mp.vec(0.0, 0.0)) + + def test_typemap_swig(self): + src = mp.gaussian_src_time(0.15, 0.1) + self.f.add_volume_source(mp.Ez, src, self.v) + + def test_typemap_py(self): + src = GaussianSource(0.15, 0.1) + self.f.add_volume_source(mp.Ez, src, self.v) + + def test_typemap_swig_raises(self): + src = mp.gaussian_src_time(0.15, 0.1) + self.assertTrue(src.is_equal(src)) + + with self.assertRaises(TypeError) as error: + src.is_equal(mp.vec()) + self.assertEqual(error.exception.message, self.expected_msg) + + def test_typemap_py_raises(self): + src = GaussianSource(0.15, 0.1) + self.assertTrue(src.swigobj.is_equal(src)) + + with self.assertRaises(TypeError) as error: + src.swigobj.is_equal(Vector3()) + self.assertEqual(error.exception.message, self.expected_msg) + + if __name__ == '__main__': unittest.main() diff --git a/python/typemap_utils.cpp b/python/typemap_utils.cpp index 4af11418e..3f1e1a278 100644 --- a/python/typemap_utils.cpp +++ b/python/typemap_utils.cpp @@ -26,13 +26,33 @@ static PyObject *py_geometric_object() { static PyObject *geometric_object = NULL; if (geometric_object == NULL) { - PyObject *geom_mod = PyImport_ImportModule("geom"); + PyObject *geom_mod = PyImport_ImportModule("meep.geom"); geometric_object = PyObject_GetAttrString(geom_mod, "GeometricObject"); Py_XDECREF(geom_mod); } return geometric_object; } +static PyObject *py_source_time_object() { + static PyObject *source_time_object = NULL; + if (source_time_object == NULL) { + PyObject *source_mod = PyImport_ImportModule("meep.source"); + source_time_object = PyObject_GetAttrString(source_mod, "SourceTime"); + Py_XDECREF(source_mod); + } + return source_time_object; +} + +static PyObject *py_meep_src_time_object() { + static PyObject *src_time = NULL; + if (src_time == NULL) { + PyObject *meep_mod = PyImport_ImportModule("meep"); + src_time = PyObject_GetAttrString(meep_mod, "src_time"); + Py_XDECREF(meep_mod); + } + return src_time; +} + static PyObject* vec2py(const meep::vec &v) { double x = 0, y = 0, z = 0; From 23b7582bffb9ab262ac12c99f264c3383c8f7679 Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Sun, 30 Jul 2017 13:48:36 -0500 Subject: [PATCH 2/2] Fix memory leak --- python/meep.i | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/meep.i b/python/meep.i index fe84113e2..8ceb8898b 100644 --- a/python/meep.i +++ b/python/meep.i @@ -171,12 +171,15 @@ static int py_list_to_gobj_list(PyObject *po, geometric_object_list *l); swig_obj = PyObject_GetAttrString($input, "swigobj"); } else if(PyObject_IsInstance($input, py_meep_src_time_object())) { swig_obj = $input; + Py_XINCREF(swig_obj); } else { PyErr_SetString(PyExc_TypeError, "Expected a meep.source.SourceTime or a meep.src_time\n"); SWIG_fail; } tmp_res = SWIG_ConvertPtr(swig_obj, &tmp_ptr, $1_descriptor, 0); + Py_XDECREF(swig_obj); + if(!SWIG_IsOK(tmp_res)) { SWIG_exception_fail(SWIG_ArgError(tmp_res), "Couldn't convert Python object to meep::src_time"); }