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

📄 maxwell.c

📁 MIT开发出来的计算光子晶体的软件
💻 C
字号:
/* 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 <stdlib.h>#include <stdio.h>#include <math.h>#include "../config.h"#include <check.h>#include "maxwell.h"/* This file is has too many #ifdef's...blech. */#define MIN2(a,b) ((a) < (b) ? (a) : (b))#define MAX2(a,b) ((a) > (b) ? (a) : (b))maxwell_data *create_maxwell_data(int nx, int ny, int nz,				  int *local_N, int *N_start, int *alloc_N,				  int num_bands,				  int max_fft_bands){     int n[3], rank = (nz == 1) ? (ny == 1 ? 1 : 2) : 3;     maxwell_data *d = 0;     int fft_data_size;     n[0] = nx;     n[1] = ny;     n[2] = nz;#ifndef HAVE_FFTW#  error Non-FFTW FFTs are not currently supported.#endif     #ifdef HAVE_FFTW     CHECK(sizeof(fftw_real) == sizeof(real),	   "floating-point type is inconsistent with FFTW!");#endif     CHK_MALLOC(d, maxwell_data, 1);     d->nx = nx;     d->ny = ny;     d->nz = nz;          d->max_fft_bands = MIN2(num_bands, max_fft_bands);     maxwell_set_num_bands(d, num_bands);     d->current_k[0] = d->current_k[1] = d->current_k[2] = 0.0;     d->parity = NO_PARITY;     d->last_dim_size = d->last_dim = n[rank - 1];     /* ----------------------------------------------------- */#ifndef HAVE_MPI      d->local_nx = nx; d->local_ny = ny;     d->local_x_start = d->local_y_start = 0;     *local_N = *alloc_N = nx * ny * nz;     *N_start = 0;     d->other_dims = *local_N / d->last_dim;     d->fft_data = 0;  /* initialize it here for use in specific planner? */#  ifdef HAVE_FFTW#    ifdef SCALAR_COMPLEX     d->fft_output_size = fft_data_size = nx * ny * nz;     d->plan = fftwnd_create_plan_specific(rank, n, FFTW_BACKWARD,					   FFTW_ESTIMATE | FFTW_IN_PLACE,					   (fftw_complex*) d->fft_data,					   3 * d->num_fft_bands,					   (fftw_complex*) d->fft_data,					   3 * d->num_fft_bands);     d->iplan = fftwnd_create_plan_specific(rank, n, FFTW_FORWARD,					    FFTW_ESTIMATE | FFTW_IN_PLACE,					    (fftw_complex*) d->fft_data,					    3 * d->num_fft_bands,					    (fftw_complex*) d->fft_data,					    3 * d->num_fft_bands);#    else /* not SCALAR_COMPLEX */     d->last_dim_size = 2 * (d->last_dim / 2 + 1);     d->fft_output_size = (fft_data_size = d->other_dims * d->last_dim_size)/2;     d->plan = rfftwnd_create_plan_specific(rank, n, FFTW_COMPLEX_TO_REAL,					    FFTW_ESTIMATE | FFTW_IN_PLACE,					    (fftw_real*) d->fft_data,					    3 * d->num_fft_bands,					    (fftw_real*) d->fft_data,					    3 * d->num_fft_bands);     d->iplan = rfftwnd_create_plan_specific(rank, n, FFTW_REAL_TO_COMPLEX,					     FFTW_ESTIMATE | FFTW_IN_PLACE,					     (fftw_real*) d->fft_data,					     3 * d->num_fft_bands,					     (fftw_real*) d->fft_data,					     3 * d->num_fft_bands);#    endif /* not SCALAR_COMPLEX */#  endif /* HAVE_FFTW */#else /* HAVE_MPI */     /* ----------------------------------------------------- */#  ifdef HAVE_FFTW     CHECK(rank > 1, "rank < 2 MPI computations are not supported");#    ifdef SCALAR_COMPLEX     d->iplan = fftwnd_mpi_create_plan(MPI_COMM_WORLD, rank, n,				       FFTW_FORWARD,				       FFTW_ESTIMATE | FFTW_IN_PLACE);     {	  int nt[3]; /* transposed dimensions for reverse FFT */	  nt[0] = n[1]; nt[1] = n[0]; nt[2] = n[2]; 	  d->plan = fftwnd_mpi_create_plan(MPI_COMM_WORLD, rank, nt,					   FFTW_BACKWARD,					   FFTW_ESTIMATE | FFTW_IN_PLACE);     }     fftwnd_mpi_local_sizes(d->iplan, &d->local_nx, &d->local_x_start,			    &d->local_ny, &d->local_y_start,			    &fft_data_size);          d->fft_output_size = nx * d->local_ny * nz;#    else /* not SCALAR_COMPLEX */     CHECK(rank > 1, "rank < 2 MPI computations are not supported");     d->iplan = rfftwnd_mpi_create_plan(MPI_COMM_WORLD, rank, n,					FFTW_REAL_TO_COMPLEX,					FFTW_ESTIMATE | FFTW_IN_PLACE);     /* Unlike fftwnd_mpi, we do *not* pass transposed dimensions for	the reverse transform here--we always pass the dimensions of the	original real array, and rfftwnd_mpi assumes that if one	transform is transposed, then the other is as well. */     d->plan = rfftwnd_mpi_create_plan(MPI_COMM_WORLD, rank, n,				       FFTW_COMPLEX_TO_REAL,				       FFTW_ESTIMATE | FFTW_IN_PLACE);     rfftwnd_mpi_local_sizes(d->iplan, &d->local_nx, &d->local_x_start,			     &d->local_ny, &d->local_y_start,			     &fft_data_size);     d->last_dim_size = 2 * (d->last_dim / 2 + 1);     if (rank == 2)	  d->fft_output_size = nx * d->local_ny * nz;     else	  d->fft_output_size = nx * d->local_ny * (d->last_dim_size / 2);#    endif /* not SCALAR_COMPLEX */          *local_N = d->local_nx * ny * nz;     *N_start = d->local_x_start * ny * nz;     *alloc_N = *local_N;     d->other_dims = *local_N / d->last_dim;#  endif /* HAVE_FFTW */#endif /* HAVE_MPI */     /* ----------------------------------------------------- */#ifdef HAVE_FFTW     CHECK(d->plan && d->iplan, "FFTW plan creation failed");#endif     CHK_MALLOC(d->eps_inv, symmetric_matrix, d->fft_output_size);     /* A scratch output array is required because the "ordinary" arrays	are not in a cartesian basis (or even a constant basis). */     fft_data_size *= d->max_fft_bands;     CHK_MALLOC(d->fft_data, scalar, 3 * fft_data_size);     CHK_MALLOC(d->k_plus_G, k_data, *local_N);     CHK_MALLOC(d->k_plus_G_normsqr, real, *local_N);     d->eps_inv_mean = 1.0;     d->local_N = *local_N;     d->N_start = *N_start;     d->alloc_N = *alloc_N;     d->N = nx * ny * nz;     return d;}void destroy_maxwell_data(maxwell_data *d){     if (d) {#ifdef HAVE_FFTW#  ifdef HAVE_MPI#    ifdef SCALAR_COMPLEX	  fftwnd_mpi_destroy_plan(d->plan);	  fftwnd_mpi_destroy_plan(d->iplan);#    else /* not SCALAR_COMPLEX */	  rfftwnd_mpi_destroy_plan(d->plan);	  rfftwnd_mpi_destroy_plan(d->iplan);#    endif /* not SCALAR_COMPLEX */#  else /* not HAVE_MPI */#    ifdef SCALAR_COMPLEX	  fftwnd_destroy_plan(d->plan);	  fftwnd_destroy_plan(d->iplan);#    else /* not SCALAR_COMPLEX */	  rfftwnd_destroy_plan(d->plan);	  rfftwnd_destroy_plan(d->iplan);#    endif /* not SCALAR_COMPLEX */#  endif /* not HAVE_MPI */#endif /* HAVE FFTW */	  free(d->eps_inv);	  free(d->fft_data);	  free(d->k_plus_G);	  free(d->k_plus_G_normsqr);	  free(d);     }}void maxwell_set_num_bands(maxwell_data *d, int num_bands){     d->num_bands = num_bands;     d->num_fft_bands = MIN2(num_bands, d->max_fft_bands);}/* compute a = b x c */static void compute_cross(real *a0, real *a1, real *a2,			  real b0, real b1, real b2,			  real c0, real c1, real c2){     *a0 = b1 * c2 - b2 * c1;     *a1 = b2 * c0 - b0 * c2;     *a2 = b0 * c1 - b1 * c0;}/* Set the current k point for the Maxwell solver.  k is given in the   basis of the reciprocal lattice vectors, G1, G2, and G3. */void update_maxwell_data_k(maxwell_data *d, real k[3],			   real G1[3], real G2[3], real G3[3]){     int nx = d->nx, ny = d->ny, nz = d->nz;     int cx = MAX2(1,d->nx/2), cy = MAX2(1,d->ny/2), cz = MAX2(1,d->nz/2);     k_data *kpG = d->k_plus_G;     real *kpGn2 = d->k_plus_G_normsqr;     int x, y, z;     real kx, ky, kz;     kx = G1[0]*k[0] + G2[0]*k[1] + G3[0]*k[2];     ky = G1[1]*k[0] + G2[1]*k[1] + G3[1]*k[2];     kz = G1[2]*k[0] + G2[2]*k[1] + G3[2]*k[2];     d->zero_k = kx == 0.0 && ky == 0.0 && kz == 0.0;     d->current_k[0] = kx;     d->current_k[1] = ky;     d->current_k[2] = kz;     /* make sure current parity is still valid: */     set_maxwell_data_parity(d, d->parity);     for (x = d->local_x_start; x < d->local_x_start + d->local_nx; ++x) {	  int kxi = (x >= cx) ? (x - nx) : x;	  for (y = 0; y < ny; ++y) {	       int kyi = (y >= cy) ? (y - ny) : y;	       for (z = 0; z < nz; ++z, kpG++, kpGn2++) {		    int kzi = (z >= cz) ? (z - nz) : z;		    real kpGx, kpGy, kpGz, a, b, c, leninv;		    /* Compute k+G (noting that G is negative because		       of the choice of sign in the FFTW Fourier transform): */		    kpGx = kx - (G1[0]*kxi + G2[0]*kyi + G3[0]*kzi);		    kpGy = ky - (G1[1]*kxi + G2[1]*kyi + G3[1]*kzi);		    kpGz = kz - (G1[2]*kxi + G2[2]*kyi + G3[2]*kzi);		    a = kpGx*kpGx + kpGy*kpGy + kpGz*kpGz;		    kpG->kmag = sqrt(a);		    *kpGn2 = a;		    		    /* Now, compute the two normal vectors: */		    /* (Note that we choose them so that m has odd/even		       parity in z/y, and n is even/odd in z/y.) */		    if (a == 0) {			 kpG->nx = 0.0; kpG->ny = 1.0; kpG->nz = 0.0;			 kpG->mx = 0.0; kpG->my = 0.0; kpG->mz = 1.0;		    }		    else {			 if (kpGx == 0.0 && kpGy == 0.0) {			      /* put n in the y direction if k+G is in z: */			      kpG->nx = 0.0;			      kpG->ny = 1.0;			      kpG->nz = 0.0;			 }			 else {			      /* otherwise, let n = z x (k+G), normalized: */			      compute_cross(&a, &b, &c,					    0.0, 0.0, 1.0,					    kpGx, kpGy, kpGz);			      leninv = 1.0 / sqrt(a*a + b*b + c*c);			      kpG->nx = a * leninv;			      kpG->ny = b * leninv;			      kpG->nz = c * leninv;			 }			 			 /* m = n x (k+G), normalized */			 compute_cross(&a, &b, &c,				       kpG->nx, kpG->ny, kpG->nz,				       kpGx, kpGy, kpGz);			 leninv = 1.0 / sqrt(a*a + b*b + c*c);			 kpG->mx = a * leninv;			 kpG->my = b * leninv;			 kpG->mz = c * leninv;		    }#ifdef DEBUG#define DOT(u0,u1,u2,v0,v1,v2) ((u0)*(v0) + (u1)*(v1) + (u2)*(v2))		    /* check orthogonality */		    CHECK(fabs(DOT(kpGx, kpGy, kpGz,				   kpG->nx, kpG->ny, kpG->nz)) < 1e-6,			  "vectors not orthogonal!");		    CHECK(fabs(DOT(kpGx, kpGy, kpGz,				   kpG->mx, kpG->my, kpG->mz)) < 1e-6,			  "vectors not orthogonal!");		    CHECK(fabs(DOT(kpG->mx, kpG->my, kpG->mz,				   kpG->nx, kpG->ny, kpG->nz)) < 1e-6,			  "vectors not orthogonal!");		    /* check normalization */		    CHECK(fabs(DOT(kpG->nx, kpG->ny, kpG->nz,				   kpG->nx, kpG->ny, kpG->nz) - 1.0) < 1e-6,			  "vectors not unit vectors!");		    CHECK(fabs(DOT(kpG->mx, kpG->my, kpG->mz,				   kpG->mx, kpG->my, kpG->mz) - 1.0) < 1e-6,			  "vectors not unit vectors!");#endif	       }	  }     }}void set_maxwell_data_parity(maxwell_data *d, int parity){     if ((parity & EVEN_Z_PARITY) && (parity & ODD_Z_PARITY))	  parity &= ~(EVEN_Z_PARITY | ODD_Z_PARITY);     if (d->current_k[2] != 0.0)	  parity &= ~(EVEN_Z_PARITY | ODD_Z_PARITY);     if ((parity & EVEN_Y_PARITY) && (parity & ODD_Y_PARITY))	  parity &= ~(EVEN_Y_PARITY | ODD_Y_PARITY);     if (d->current_k[1] != 0.0)	  parity &= ~(EVEN_Y_PARITY | ODD_Y_PARITY);     d->parity = parity;}maxwell_target_data *create_maxwell_target_data(maxwell_data *md, 						real target_frequency){     maxwell_target_data *d;     CHK_MALLOC(d, maxwell_target_data, 1);     d->d = md;     d->target_frequency = target_frequency;     return d;}void destroy_maxwell_target_data(maxwell_target_data *d){     if (d) {	  free(d);     }}

⌨️ 快捷键说明

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