⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dft.cpp

📁 麻省理工的计算光子晶体的程序
💻 CPP
字号:
/* Copyright (C) 2006 Massachusetts Institute of Technology. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include <stdio.h>#include <stdlib.h>#include <math.h>#include "meep.hpp"#include "meep_internals.hpp"namespace meep {struct dft_chunk_data { // for passing to field::loop_in_chunks as void*  double omega_min, domega;  int Nomega;  component c;  complex<double> weight;  bool include_dV_and_interp_weights;  dft_chunk *dft_chunks;};dft_chunk::dft_chunk(fields_chunk *fc_,		     ivec is_, ivec ie_,		     vec s0_, vec s1_, vec e0_, vec e1_,		     double dV0_, double dV1_,		     complex<double> scale_,		     component c_,		     const void *data_) {  dft_chunk_data *data = (dft_chunk_data *) data_;  if (!fc_->f[c_][0])    abort("invalid fields_chunk/component combination in dft_chunk");    fc = fc_;  is = is_;  ie = ie_;  s0 = s0_;  s1 = s1_;  e0 = e0_;  e1 = e1_;  if (data->include_dV_and_interp_weights) {    dV0 = dV0_;    dV1 = dV1_;  }  else {    /* this is for e.g. computing E x H, where we don't want to        multiply by the interpolation weights or the volume twice. */    dV0 = 1;    dV1 = 0;    LOOP_OVER_DIRECTIONS(fc->v.dim, d) {      s0.set_direction(d, 1.0);      s1.set_direction(d, 1.0);      e0.set_direction(d, 1.0);      e1.set_direction(d, 1.0);    }  }  scale = scale_ * data->weight;  c = c_;  fc->v.yee2diel_offsets(c, avg1, avg2);  omega_min = data->omega_min;  domega = data->domega;  Nomega = data->Nomega;  dft_phase = new complex<double>[Nomega];    N = 1;  LOOP_OVER_DIRECTIONS(is.dim, d)    N *= (ie.in_direction(d) - is.in_direction(d)) / 2 + 1;  dft = new complex<double>[N * Nomega];  for (int i = 0; i < N * Nomega; ++i)    dft[i] = 0.0;    next_in_chunk = fc->dft_chunks;  fc->dft_chunks = this;  next_in_dft = data->dft_chunks;}dft_chunk::~dft_chunk() {  delete[] dft;  delete[] dft_phase;  // delete from fields_chunk list  dft_chunk *cur = fc->dft_chunks;  while (cur && cur->next_in_chunk && cur->next_in_chunk != this)    cur = cur->next_in_chunk;  if (cur && cur->next_in_chunk == this)    cur->next_in_chunk = next_in_chunk;  else if (fc->dft_chunks == this)    fc->dft_chunks = next_in_chunk;  delete next_in_dft;}static void add_dft_chunkloop(fields_chunk *fc, int ichunk, component cgrid,			      ivec is, ivec ie,			      vec s0, vec s1, vec e0, vec e1,			      double dV0, double dV1,			      ivec shift, complex<double> shift_phase,			      const symmetry &S, int sn,			      void *chunkloop_data){  dft_chunk_data *data = (dft_chunk_data *) chunkloop_data;  (void) shift; (void) ichunk; // unused  if (cgrid != Dielectric) abort("dft chunks should use the Dielectric grid");    component c = S.transform(data->c, -sn);  if (c >= NUM_FIELD_COMPONENTS || !fc->f[c][0])       return; // this chunk doesn't have component c  data->dft_chunks = new dft_chunk(fc,is,ie,s0,s1,e0,e1,dV0,dV1,				   shift_phase * S.phase_shift(c, sn),				   c, chunkloop_data);}dft_chunk *fields::add_dft(component c, const geometric_volume &where,			   double freq_min, double freq_max, int Nfreq,			   bool include_dV_and_interp_weights,			   complex<double> weight, dft_chunk *chunk_next) {  if (coordinate_mismatch(v.dim, c))    return NULL;  dft_chunk_data data;    data.c = c;  data.omega_min = freq_min * 2*pi;  data.domega = Nfreq <= 1 ? 0.0 :     (freq_max * 2*pi - data.omega_min) / (Nfreq - 1);  data.Nomega = Nfreq;  data.include_dV_and_interp_weights = include_dV_and_interp_weights;  data.dft_chunks = chunk_next;  data.weight = weight * (dt/sqrt(2*pi));  loop_in_chunks(add_dft_chunkloop, (void *) &data, where);  return data.dft_chunks;}dft_chunk *fields::add_dft(const geometric_volume_list *where,			   double freq_min, double freq_max, int Nfreq,			   bool include_dV_and_interp_weights) {  dft_chunk *chunks = 0;  while (where) {    if (is_derived(where->c)) abort("derived_component invalid for dft");    chunks = add_dft(component(where->c), where->gv,		     freq_min, freq_max, Nfreq, include_dV_and_interp_weights,		     where->weight, chunks);    where = where->next;  }  return chunks;}dft_chunk *fields::add_dft_pt(component c, const vec &where,			   double freq_min, double freq_max, int Nfreq) {  return add_dft(c, where, freq_min, freq_max, Nfreq, false);}void fields::update_dfts() {  am_now_working_on(FourierTransforming);  for (int i = 0; i < num_chunks; i++)    if (chunks[i]->is_mine())      chunks[i]->update_dfts(time(), time() - 0.5 * dt);  finished_working();}void fields_chunk::update_dfts(double timeE, double timeH) {  for (dft_chunk *cur = dft_chunks; cur; cur = cur->next_in_chunk) {    cur->update_dft(is_magnetic(cur->c) ? timeH : timeE);  }}void dft_chunk::update_dft(double time) {  if (!fc->f[c][0]) return;  for (int i = 0; i < Nomega; ++i)    dft_phase[i] = polar(1.0, (omega_min + i*domega)*time) * scale;  int numcmp = fc->f[c][1] ? 2 : 1;  int idx_dft = 0;  LOOP_OVER_IVECS(fc->v, is, ie, idx) {    double w = IVEC_LOOP_WEIGHT(s0, s1, e0, e1, dV0 + dV1 * loop_i2);    double f[2]; // real/imag field value at epsilon point    if (avg2)      for (int cmp=0; cmp < numcmp; ++cmp)	f[cmp] = (w * 0.25) * 	  (fc->f[c][cmp][idx] + fc->f[c][cmp][idx+avg1]	   + fc->f[c][cmp][idx+avg2] + fc->f[c][cmp][idx+(avg1+avg2)]);    else if (avg1)      for (int cmp=0; cmp < numcmp; ++cmp)	f[cmp] = (w * 0.5) * (fc->f[c][cmp][idx] + fc->f[c][cmp][idx+avg1]);    else      for (int cmp=0; cmp < numcmp; ++cmp)	f[cmp] = w * fc->f[c][cmp][idx];        if (numcmp == 2) {      complex<double> fc(f[0], f[1]);      for (int i = 0; i < Nomega; ++i)	dft[Nomega * idx_dft + i] += dft_phase[i] * fc;    }    else {      double fr = f[0];      for (int i = 0; i < Nomega; ++i)	dft[Nomega * idx_dft + i] += dft_phase[i] * fr;    }    idx_dft++;  }}void dft_chunk::scale_dft(complex<double> scale) {  for (int i = 0; i < N * Nomega; ++i)    dft[i] *= scale;  if (next_in_dft)    next_in_dft->scale_dft(scale);}void dft_chunk::operator-=(const dft_chunk &chunk) {  if (c != chunk.c || N * Nomega != chunk.N * chunk.Nomega) abort("Mismatched chunks in dft_chunk::operator-=");  for (int i = 0; i < N * Nomega; ++i)    dft[i] -= chunk.dft[i];  if (next_in_dft) {    if (!chunk.next_in_dft) abort("Mismatched chunk lists in dft_chunk::operator-=");    *next_in_dft -= *chunk.next_in_dft;  }}static int dft_chunks_Ntotal(dft_chunk *dft_chunks, int *my_start) {  int n = 0;  for (dft_chunk *cur = dft_chunks; cur; cur = cur->next_in_dft)    n += cur->N * cur->Nomega * 2;  *my_start = partial_sum_to_all(n) - n; // sum(n) for processes before this  return sum_to_all(n);}// Note: the file must have been created in parallel mode, typically via fields::open_h5file.void save_dft_hdf5(dft_chunk *dft_chunks, component c, h5file *file,		   const char *dprefix) {  int istart;  int n = dft_chunks_Ntotal(dft_chunks, &istart);  char dataname[1024];  snprintf(dataname, 1024, "%s%s" "%s_dft", 	   dprefix ? dprefix : "", dprefix && dprefix[0] ? "_" : "", 	   component_name(c));  file->create_data(dataname, 1, &n);  for (dft_chunk *cur = dft_chunks; cur; cur = cur->next_in_dft) {    int Nchunk = cur->N * cur->Nomega * 2;    file->write_chunk(1, &istart, &Nchunk, (double *) cur->dft);    istart += Nchunk;  }  file->done_writing_chunks();}void load_dft_hdf5(dft_chunk *dft_chunks, component c, h5file *file,		   const char *dprefix) {  int istart;  int n = dft_chunks_Ntotal(dft_chunks, &istart);  char dataname[1024];  snprintf(dataname, 1024, "%s%s" "%s_dft", 	   dprefix ? dprefix : "", dprefix && dprefix[0] ? "_" : "",	   component_name(c));  int file_rank, file_dims;  file->read_size(dataname, &file_rank, &file_dims, 1);  if (file_rank != 1 || file_dims != n)    abort("incorrect dataset size (%d vs. %d) in load_dft_hdf5 %s:%s", file_dims, n, file->file_name(), dataname);    for (dft_chunk *cur = dft_chunks; cur; cur = cur->next_in_dft) {    int Nchunk = cur->N * cur->Nomega * 2;    file->read_chunk(1, &istart, &Nchunk, (double *) cur->dft);    istart += Nchunk;  }}dft_flux::dft_flux(const component cE_, const component cH_,		   dft_chunk *E_, dft_chunk *H_, 		   double fmin, double fmax, int Nf){  freq_min = fmin;  Nfreq = Nf;  dfreq = Nf <= 1 ? 0.0 : (fmax - fmin) / (Nf - 1);  E = E_; H = H_;  cE = cE_; cH = cH_;}dft_flux::dft_flux(const dft_flux &f) {  freq_min = f.freq_min; Nfreq = f.Nfreq; dfreq = f.dfreq;  E = f.E; H = f.H;  cE = f.cE; cH = f.cH;}double *dft_flux::flux() {  double *F = new double[Nfreq];  for (int i = 0; i < Nfreq; ++i) F[i] = 0;  for (dft_chunk *curE = E, *curH = H; curE && curH;       curE = curE->next_in_dft, curH = curH->next_in_dft)    for (int k = 0; k < curE->N; ++k)      for (int i = 0; i < Nfreq; ++i)	F[i] += real(curE->dft[k*Nfreq + i]		     * conj(curH->dft[k*Nfreq + i]));  double *Fsum = new double[Nfreq];  sum_to_all(F, Fsum, Nfreq);  delete[] F;  return Fsum;}void dft_flux::save_hdf5(h5file *file, const char *dprefix) {  save_dft_hdf5(E, cE, file, dprefix);  file->prevent_deadlock(); // hackery  save_dft_hdf5(H, cH, file, dprefix);}void dft_flux::load_hdf5(h5file *file, const char *dprefix) {  load_dft_hdf5(E, cE, file, dprefix);  file->prevent_deadlock(); // hackery  load_dft_hdf5(H, cH, file, dprefix);}void dft_flux::save_hdf5(fields &f, const char *fname, const char *dprefix,			 const char *prefix) {  h5file *ff = f.open_h5file(fname, h5file::WRITE, prefix);  save_hdf5(ff, dprefix);  delete ff;}void dft_flux::load_hdf5(fields &f, const char *fname, const char *dprefix,			 const char *prefix) {  h5file *ff = f.open_h5file(fname, h5file::READONLY, prefix);  load_hdf5(ff, dprefix);  delete ff;}void dft_flux::scale_dfts(complex<double> scale) {  if (E) E->scale_dft(scale);  if (H) H->scale_dft(scale);}dft_flux fields::add_dft_flux(const geometric_volume_list *where_,			      double freq_min, double freq_max, int Nfreq) {  dft_chunk *E = 0, *H = 0;  component cE[2] = {Ex,Ey}, cH[2] = {Hy,Hx};  geometric_volume_list *where = S.reduce(where_);  while (where) {    derived_component c = derived_component(where->c);    if (coordinate_mismatch(v.dim, component_direction(c)))      abort("coordinate-type mismatch in add_dft_flux");        switch (c) {    case Sx: cE[0] = Ey, cE[1] = Ez, cH[0] = Hz, cH[1] = Hy; break;    case Sy: cE[0] = Ez, cE[1] = Ex, cH[0] = Hx, cH[1] = Hz; break;    case Sr: cE[0] = Ep, cE[1] = Ez, cH[0] = Hz, cH[1] = Hp; break;    case Sp: cE[0] = Ez, cE[1] = Er, cH[0] = Hr, cH[1] = Hz; break;    case Sz:      if (v.dim == Dcyl)	cE[0] = Er, cE[1] = Ep, cH[0] = Hp, cH[1] = Hr;      else	cE[0] = Ex, cE[1] = Ey, cH[0] = Hy, cH[1] = Hx;       break;    default: abort("invalid flux component!");    }        for (int i = 0; i < 2; ++i) {      E = add_dft(cE[i], where->gv, freq_min, freq_max, Nfreq,		  true, where->weight * double(1 - 2*i), E);      H = add_dft(cH[i], where->gv, freq_min, freq_max, Nfreq,		  false, 1.0, H);    }        where = where->next;  }  return dft_flux(cE[0], cH[0], E, H, freq_min, freq_max, Nfreq);}direction fields::normal_direction(const geometric_volume &where) const {  direction d = where.normal_direction();  if (d == NO_DIRECTION) {    /* hack so that we still infer the normal direction correctly for       volumes with empty dimensions */    geometric_volume where_pad(where);    LOOP_OVER_DIRECTIONS(where.dim, d1)      if (nosize_direction(d1) && where.in_direction(d1) == 0.0)	where_pad.set_direction_max(d1, where.in_direction_min(d1) + 0.1);    d = where_pad.normal_direction();      if (d == NO_DIRECTION)      abort("Could not determine normal direction for given volume.");  }  return d;}dft_flux fields::add_dft_flux(direction d, const geometric_volume &where,			      double freq_min, double freq_max, int Nfreq) {  if (d == NO_DIRECTION)    d = normal_direction(where);  geometric_volume_list gvl(where, direction_component(Sx, d));  return add_dft_flux(&gvl, freq_min, freq_max, Nfreq);}dft_flux fields::add_dft_flux_box(const geometric_volume &where,				  double freq_min, double freq_max, int Nfreq){  geometric_volume_list *faces = 0;  LOOP_OVER_DIRECTIONS(where.dim, d)    if (where.in_direction(d) > 0) {      geometric_volume face(where);      derived_component c = direction_component(Sx, d);      face.set_direction_min(d, where.in_direction_max(d));      faces = new geometric_volume_list(face, c, +1, faces);      face.set_direction_min(d, where.in_direction_min(d));      face.set_direction_max(d, where.in_direction_min(d));      faces = new geometric_volume_list(face, c, -1, faces);    }  dft_flux flux = add_dft_flux(faces, freq_min, freq_max, Nfreq);  delete faces;  return flux;}dft_flux fields::add_dft_flux_plane(const geometric_volume &where,			      double freq_min, double freq_max, int Nfreq) {  return add_dft_flux(NO_DIRECTION, where, freq_min, freq_max, Nfreq);}} // namespace meep

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -