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

📄 fields.c

📁 麻省理工的计算光子晶体的程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Copyright (C) 1999, 2000, 2001, 2002, 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 <ctype.h>#include <stddef.h>#include "../src/config.h"#include <mpiglue.h>#include <mpi_utils.h>#include <check.h>#include <matrixio.h>#include <maxwell.h>#include <ctl-io.h>#include <ctlgeom.h>#include "mpb.h"#include "field-smob.h"/**************************************************************************//* The following routines take the eigenvectors computed by solve-kpoint   and compute the field (D, H, or E) in position space for one of the bands.   This field is stored in the global curfield (actually an alias for   mdata->fft_data, since the latter is unused and big enough).  This   field can then be manipulated with subsequent "*-field-*" functions   below.  You can also get the scalar field, epsilon.   All of these functions are designed to be called by the user   via Guile. */void get_dfield(int which_band){     if (!mdata) {	  mpi_one_fprintf(stderr,			  "init-params must be called before get-dfield!\n");	  return;     }     if (!kpoint_index) {	  mpi_one_fprintf(stderr,			  "solve-kpoint must be called before get-dfield!\n");	  return;     }     if (which_band < 1 || which_band > H.p) {	  mpi_one_fprintf(stderr,			  "must have 1 <= band index <= num_bands (%d)\n",H.p);	  return;     }     curfield = (scalar_complex *) mdata->fft_data;     curfield_band = which_band;     curfield_type = 'd';     maxwell_compute_d_from_H(mdata, H, curfield, which_band - 1, 1);     /* Here, we correct for the fact that compute_d_from_H actually	computes just (k+G) x H, whereas the actual D field is	i/omega i(k+G) x H...so, there is an added factor of -1/omega.         We also divide by the cell volume so that the integral of |H|^2        or of D*E is unity.  (From the eigensolver + FFT, they are        initially normalized to sum to nx*ny*nz.) */     {	  int i, N;	  double scale;	  N = mdata->fft_output_size;	  if (freqs.items[which_band - 1] != 0.0) {	       scale = -1.0 / freqs.items[which_band - 1];	  }	  else	       scale = -1.0; /* arbitrary */	  scale /= sqrt(Vol);	  for (i = 0; i < 3*N; ++i) {	       curfield[i].re *= scale;	       curfield[i].im *= scale;	  }     }}void get_hfield(integer which_band){     if (!mdata) {	  mpi_one_fprintf(stderr,			  "init-params must be called before get-hfield!\n");	  return;     }     if (!kpoint_index) {	  mpi_one_fprintf(stderr,			  "solve-kpoint must be called before get-hfield!\n");	  return;     }     if (which_band < 1 || which_band > H.p) {	  mpi_one_fprintf(stderr,			  "must have 1 <= band index <= num_bands (%d)\n",H.p);	  return;     }     curfield = (scalar_complex *) mdata->fft_data;     curfield_band = which_band;     curfield_type = 'h';     maxwell_compute_h_from_H(mdata, H, curfield, which_band - 1, 1);     /* Divide by the cell volume so that the integral of |H|^2        or of D*E is unity.  (From the eigensolver + FFT, they are        initially normalized to sum to nx*ny*nz.) */     {	  int i, N;	  double scale;	  N = mdata->fft_output_size;	  scale = 1.0 / sqrt(Vol);	  for (i = 0; i < 3*N; ++i) {	       curfield[i].re *= scale;	       curfield[i].im *= scale;	  }     }}void get_efield_from_dfield(void){     if (!curfield || curfield_type != 'd') {	  mpi_one_fprintf(stderr, "get-dfield must be called before "		  "get-efield-from-dfield!\n");	  return;     }     CHECK(mdata, "unexpected NULL mdata");     maxwell_compute_e_from_d(mdata, curfield, 1);     curfield_type = 'e';}void get_efield(integer which_band){     get_dfield(which_band);     get_efield_from_dfield();}/* Extract the mean epsilon from the effective inverse dielectric tensor,   which contains two eigenvalues that correspond to the mean epsilon,   and one which corresponds to the harmonic mean. */static real mean_epsilon(const symmetric_matrix *eps_inv){     real eps_eigs[3];     maxwell_sym_matrix_eigs(eps_eigs, eps_inv);     /* the harmonic mean should be the largest eigenvalue (smallest	epsilon), so we'll ignore it and average the other two: */     return 2.0 / (eps_eigs[0] + eps_eigs[1]);}/* get the dielectric function, and compute some statistics */void get_epsilon(void){     int i, N, last_dim, last_dim_stored, nx, nz, local_y_start;     real *epsilon;     real eps_mean = 0, eps_inv_mean = 0, eps_high = -1e20, eps_low = 1e20;     int fill_count = 0;     if (!mdata) {	  mpi_one_fprintf(stderr,			  "init-params must be called before get-epsilon!\n");	  return;     }     curfield = (scalar_complex *) mdata->fft_data;     epsilon = (real *) curfield;     curfield_band = 0;     curfield_type = 'n';     /* get epsilon.  Recall that we actually have an inverse	dielectric tensor at each point; define an average index by	the inverse of the average eigenvalue of the 1/eps tensor.	i.e. 3/(trace 1/eps). */     N = mdata->fft_output_size;     last_dim = mdata->last_dim;     last_dim_stored =	  mdata->last_dim_size / (sizeof(scalar_complex)/sizeof(scalar));     nx = mdata->nx; nz = mdata->nz; local_y_start = mdata->local_y_start;     for (i = 0; i < N; ++i) {          epsilon[i] = mean_epsilon(mdata->eps_inv + i);	  if (epsilon[i] < eps_low)	       eps_low = epsilon[i];	  if (epsilon[i] > eps_high)	       eps_high = epsilon[i];	  eps_mean += epsilon[i];	  eps_inv_mean += 1/epsilon[i];	  if (epsilon[i] > 1.0001)	       ++fill_count;#ifndef SCALAR_COMPLEX	  /* most points need to be counted twice, by rfftw output symmetry: */	  {	       int last_index;#  ifdef HAVE_MPI	       if (nz == 1) /* 2d calculation: 1st dim. is truncated one */		    last_index = i / nx + local_y_start;	       else		    last_index = i % last_dim_stored;#  else	       last_index = i % last_dim_stored;#  endif	       if (last_index != 0 && 2*last_index != last_dim) {		    eps_mean += epsilon[i];		    eps_inv_mean += 1/epsilon[i];		    if (epsilon[i] > 1.0001)			 ++fill_count;	       }	  }#endif     }     mpi_allreduce_1(&eps_mean, real, SCALAR_MPI_TYPE,		     MPI_SUM, MPI_COMM_WORLD);     mpi_allreduce_1(&eps_inv_mean, real, SCALAR_MPI_TYPE,		     MPI_SUM, MPI_COMM_WORLD);     mpi_allreduce_1(&eps_low, real, SCALAR_MPI_TYPE,		     MPI_MIN, MPI_COMM_WORLD);     mpi_allreduce_1(&eps_high, real, SCALAR_MPI_TYPE,		     MPI_MAX, MPI_COMM_WORLD);     mpi_allreduce_1(&fill_count, int, MPI_INT,                   MPI_SUM, MPI_COMM_WORLD);     N = mdata->nx * mdata->ny * mdata->nz;     eps_mean /= N;     eps_inv_mean = N/eps_inv_mean;     mpi_one_printf("epsilon: %g-%g, mean %g, harm. mean %g, "		    "%g%% > 1, %g%% \"fill\"\n",		    eps_low, eps_high, eps_mean, eps_inv_mean,		    (100.0 * fill_count) / N, 		    eps_high == eps_low ? 100.0 :		    100.0 * (eps_mean-eps_low) / (eps_high-eps_low));}/* get the specified component of the dielectric tensor,   or the inverse tensor if inv != 0 */void get_epsilon_tensor(int c1, int c2, int imag, int inv){     int i, N;     real *epsilon;     int conj = 0, offset = 0;     curfield_type = '-'; /* only used internally, for now */     epsilon = (real *) mdata->fft_data;     N = mdata->fft_output_size;     switch (c1 * 3 + c2) {	 case 0:	      offset = offsetof(symmetric_matrix, m00);	      break;	 case 1:	      offset = offsetof(symmetric_matrix, m01);	      break;	 case 2:	      offset = offsetof(symmetric_matrix, m02);	      break;	 case 3:	      offset = offsetof(symmetric_matrix, m01); /* = conj(m10) */	      conj = imag;	      break;	 case 4:	      offset = offsetof(symmetric_matrix, m11);	      break;	 case 5:	      offset = offsetof(symmetric_matrix, m12);	      break;	 case 6:	      offset = offsetof(symmetric_matrix, m02); /* = conj(m20) */	      conj = imag;	      break;	 case 7:	      offset = offsetof(symmetric_matrix, m12); /* = conj(m21) */	      conj = imag;	      break;	 case 8:	      offset = offsetof(symmetric_matrix, m22);	      break;     }#ifdef WITH_HERMITIAN_EPSILON     if (c1 != c2 && imag)	  offset += offsetof(scalar_complex, im);#endif     for (i = 0; i < N; ++i) {	  if (inv) {	       epsilon[i] = 		    *((real *) (((char *) &mdata->eps_inv[i]) + offset));	  }	  else {	       symmetric_matrix eps;	       maxwell_sym_matrix_invert(&eps, &mdata->eps_inv[i]);	       epsilon[i] = *((real *) (((char *) &eps) + offset));	  }	  if (conj)	       epsilon[i] = -epsilon[i];     }     }/**************************************************************************//* Replace curfield (either d or h) with the scalar energy density function,   normalized to one.  While we're at it, compute some statistics about   the relative strength of different field components.  Also return   the integral of the energy density, which should be unity. */number_list compute_field_energy(void){     int i, N, last_dim, last_dim_stored, nx, nz, local_y_start;     real comp_sum2[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, comp_sum[6];     real energy_sum = 0.0;     real *energy_density = (real *) curfield;     number_list retval = { 0, 0 };     if (!curfield || !strchr("dh", curfield_type)) {	  mpi_one_fprintf(stderr, "The D or H field must be loaded first.\n");	  return retval;     }     N = mdata->fft_output_size;     last_dim = mdata->last_dim;     last_dim_stored =	  mdata->last_dim_size / (sizeof(scalar_complex)/sizeof(scalar));     nx = mdata->nx; nz = mdata->nz; local_y_start = mdata->local_y_start;     for (i = 0; i < N; ++i) {	  scalar_complex field[3];	  real	       comp_sqr0,comp_sqr1,comp_sqr2,comp_sqr3,comp_sqr4,comp_sqr5;	  /* energy is either |curfield|^2 or |curfield|^2 / epsilon,	     depending upon whether it is H or D. */	  if (curfield_type == 'h') {	       field[0] =   curfield[3*i];	       field[1] = curfield[3*i+1];	       field[2] = curfield[3*i+2];	  }	  else	       assign_symmatrix_vector(field, mdata->eps_inv[i], curfield+3*i);	  comp_sum2[0] += comp_sqr0 = field[0].re *   curfield[3*i].re;	  comp_sum2[1] += comp_sqr1 = field[0].im *   curfield[3*i].im;	  comp_sum2[2] += comp_sqr2 = field[1].re * curfield[3*i+1].re;	  comp_sum2[3] += comp_sqr3 = field[1].im * curfield[3*i+1].im;	  comp_sum2[4] += comp_sqr4 = field[2].re * curfield[3*i+2].re;	  comp_sum2[5] += comp_sqr5 = field[2].im * curfield[3*i+2].im;	  /* Note: here, we write to energy_density[i]; this is	     safe, even though energy_density is aliased to curfield,	     since energy_density[i] is guaranteed to come at or before	     curfield[i] (which we are now done with). */	  energy_sum += energy_density[i] = 	       comp_sqr0+comp_sqr1+comp_sqr2+comp_sqr3+comp_sqr4+comp_sqr5;#ifndef SCALAR_COMPLEX	  /* most points need to be counted twice, by rfftw output symmetry: */	  {	       int last_index;#  ifdef HAVE_MPI	       if (nz == 1) /* 2d calculation: 1st dim. is truncated one */		    last_index = i / nx + local_y_start;	       else		    last_index = i % last_dim_stored;#  else	       last_index = i % last_dim_stored;#  endif	       if (last_index != 0 && 2*last_index != last_dim) {		    energy_sum += energy_density[i];		    comp_sum2[0] += comp_sqr0;		    comp_sum2[1] += comp_sqr1;		    comp_sum2[2] += comp_sqr2;		    comp_sum2[3] += comp_sqr3;		    comp_sum2[4] += comp_sqr4;		    comp_sum2[5] += comp_sqr5;	       }	  }

⌨️ 快捷键说明

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