File: ring-ll.cpp

package info (click to toggle)
meep 1.7.0-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 26,468 kB
  • sloc: cpp: 27,370; python: 10,574; lisp: 1,213; makefile: 438; sh: 28
file content (175 lines) | stat: -rw-r--r-- 6,685 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/***************************************************************/
/* C++ port of meep/examples/ring.ctl, using the               */
/* "low-level" meep C++ interface stack, which consists of     */
/* libmeep_geom + libctlgeom + libmeep                         */
/***************************************************************/
/*
; Calculating 2d ring-resonator modes, from the Meep tutorial.
*/

#include <stdio.h>
#include <stdlib.h>
#include <complex>
#include <vector>

#include "meep.hpp"

#include "ctl-math.h"
#include "ctlgeom.h"

#include "meepgeom.hpp"

using namespace meep;
using namespace std::complex_literals;

typedef std::complex<double> cdouble;

vector3 v3(double x, double y=0.0, double z=0.0)
{
  vector3 v;
  v.x=x; v.y=y; v.z=z;
  return v;
}

/***************************************************************/
/* dummy material function needed to pass to structure( )      */
/* constructor as a placeholder before we can call             */
/* set_materials_from_geometry                                 */
/***************************************************************/
double dummy_eps(const vec &) { return 1.0; }

/***************************************************************/
/***************************************************************/
/***************************************************************/
int main(int argc, char *argv[])
{
  initialize mpi(argc, argv);

  double n=3.4;     // index of waveguide
  double w=1.0;     // width of waveguide
  double r=1.0;     // inner radius of ring

  double pad=4;     // padding between waveguide and edge of PML
  double dpml=2;    // thickness of PML

  double sxy        = 2.0*(r+w+pad+dpml);  // cell size
  double resolution = 10.0;

  // (set-param! resolution 10)
  // (set! geometry-lattice (make lattice (size sxy sxy no-size)))
  geometry_lattice.size.x=sxy;
  geometry_lattice.size.y=sxy;
  geometry_lattice.size.z=0.0;
  grid_volume gv = voltwo(sxy, sxy, resolution);
  gv.center_origin();

  // (set! symmetries (list (make mirror-sym (direction Y))))
  //symmetry sym=mirror(Y, gv);
  symmetry sym=identity();

  // (set! pml-layers (list (make pml (thickness dpml))))
  // ; exploit the mirror symmetry in structure+source:
  structure the_structure(gv, dummy_eps, pml(dpml), sym);

  // ; Create a ring waveguide by two overlapping cylinders - later objects
  // ; take precedence over earlier objects, so we put the outer cylinder first.
  // ; and the inner (air) cylinder second.
  // (set! geometry (list
  //	(make cylinder (center 0 0) (height infinity)
  //		(radius (+ r w)) (material (make dielectric (index n))))
  // 	(make cylinder (center 0 0) (height infinity)
  // 		(radius r) (material air))))
  meep_geom::material_type dielectric = meep_geom::make_dielectric(n*n);
  geometric_object objects[2];
  vector3 v3zero = {0.0, 0.0, 0.0};
  vector3 zaxis  = {0.0, 0.0, 1.0};
  objects[0] = make_cylinder(dielectric, v3zero, r+w, ENORMOUS, zaxis);
  objects[1] = make_cylinder(meep_geom::vacuum,  v3zero, r, ENORMOUS, zaxis);
  geometric_object_list g={ 2, objects };
  meep_geom::set_materials_from_geometry(&the_structure, g);
  fields f(&the_structure);

  // ; If we don't want to excite a specific mode symmetry, we can just
  // ; put a single point source at some arbitrary place, pointing in some
  // ; arbitrary direction.  We will only look for TM modes (E out of the plane).
  // (set! sources (list
  //              (make source
  //                (src (make gaussian-src (frequency fcen) (fwidth df)))
  //                (component Ez) (center (+ r 0.1) 0))))
  double fcen = 0.15;  // ; pulse center frequency
  double df   = 0.1;   // ; df
  gaussian_src_time src(fcen, df);
  volume v( vec(r+0.1,0.0), vec(0.0, 0.0) );
  f.add_volume_source(Ez, src, v);

  // (run-sources+ 300
  // 	(at-beginning output-epsilon)
  // 	(after-sources (harminv Ez (vector3 (+ r 0.1)) fcen df)))
  while( f.round_time() < f.last_source_time() )
   f.step();

  double T = 300.0;
  double stop_time = f.round_time() + T;
  std::vector<cdouble> fieldData;
  vec eval_pt(r+0.1,0.0);
  while( f.round_time() < stop_time )
   { f.step();
     fieldData.push_back( f.get_field(Ez, eval_pt) );
   };

  #define MAXBANDS 100
  cdouble amp[MAXBANDS];
  double freq_re[MAXBANDS];
  double freq_im[MAXBANDS];
  double err[MAXBANDS];
  master_printf("starting do_harminv...\n");
  int bands=do_harminv( &fieldData[0], fieldData.size(), f.dt,
                        fcen-0.5*df, fcen+0.5*df, MAXBANDS,
                        amp, freq_re, freq_im, err);
  master_printf("harminv0: | real(freq) | imag(freq)  |     Q      |  abs(amp)  |          amp          | err\n");
  master_printf("--------------------------------------------------------------------------------------------\n");
  for(int nb=0; nb<bands; nb++)
   master_printf("harminv0: | %.4e | %+.4e | %.4e | %.4e | {%+.2e,%+.2e} | %.1e \n",
                  freq_re[nb], freq_im[nb], 0.5*freq_re[nb]/freq_im[nb],
                  abs(amp[nb]), real(amp[nb]), imag(amp[nb]), err[nb]);

  // test comparison with expected values
  int ref_bands=3;
  double ref_freq_re[3] = {  1.1807e-01, 1.4716e-01,  1.7525e-01  };
  double ref_freq_im[3] = { -7.6133e-04, -2.1156e-04, -5.2215e-05 };
  cdouble ref_amp[3]    = { -8.28e-04-1.34e-03i, +1.23e-03-1.25e-02i, +2.83e-03-6.52e-04i};
  if (bands!=3)
   abort("harminv found only %i/%i bands\n",bands,ref_bands);
  for(int nb=0; nb<bands; nb++)
   if (    fabs(freq_re[nb]-ref_freq_re[nb]) > 1.0e-2*fabs(ref_freq_re[nb])
        || fabs(freq_im[nb]-ref_freq_im[nb]) > 1.0e-2*fabs(ref_freq_im[nb])
        ||  abs(    amp[nb]-    ref_amp[nb]) > 1.0e-2* abs(    ref_amp[nb])

      )
    abort("harminv band %i disagrees with ref: {re f, im f, re A, im A}={%e,%e,%e,%e}!= {%e,%e,%e,%e}\n",
           nb, freq_re[nb],     freq_im[nb],     real(amp[nb]),     imag(amp[nb]),
               ref_freq_re[nb], ref_freq_im[nb], real(ref_amp[nb]), imag(ref_amp[nb]));

  master_printf("all harminv results match reference values\n");

  // ; Output fields for one period at the end.  (If we output
  // ; at a single time, we might accidentally catch the Ez field
  // ; when it is almost zero and get a distorted view.)
  // (run-until (/ 1 fcen) (at-every (/ 1 fcen 20) output-efield-z))
  double DeltaT = 1.0/(20*fcen);
  double NextOutputTime = f.round_time() + DeltaT;
  while( f.round_time() < 1.0/fcen )
   { f.step();
     if ( f.round_time() >= NextOutputTime  )
      { f.output_hdf5(Ez, f.total_volume());
        NextOutputTime += DeltaT;
      };
   };

  // this seems to be necessary to prevent failures
  all_wait();

  // success if we made it here
  return 0;

}