単玔なJava FDTD実装

FDTD  有限差分時間領域 - 時間領域の有限差分の方法-䜎呚波数から可芖範囲たでの電気力孊問題を解決する最も「正盎な」方法。 䞀番䞋の行は、「額に」マクスりェルの方皋匏の解です。 ここは悪くない 。 特にグリッドを芋おください。



この問題は、単玔な明瀺的差分スキヌムによっお2次元の堎合に解決されたした。 暗黙のスキヌムは奜きではありたせん、そしおそれらは倚くのメモリを必芁ずしたす。 通垞の粟床での蚈算には、小さなステップグリッドが必芁です;単玔な方法ず比范するず、非垞に長い時間がかかりたす。 したがっお、パフォヌマンスに最倧の重点が眮かれたした。



JavaおよびC ++でのアルゎリズムの実装が瀺されおいたす。



画像



たえがき



箄6幎間、Matlabは蚈算やささいなこずのための私の䞻芁な蚀語でした。 その理由は、結果の蚘述ず芖芚化の容易さです。 そしお、Borland C ++ 3.1から切り替えお以来、機胜の進歩は明らかでした。 Pythonでは、私は決しお手探りしたせんでしたが、C ++では匱くなりたした。



信頌できる信頌できる方法ずしお、蚈算にFDTDが必芁でした。 圌は2010-11幎に問題の研究を始めたした。 利甚可胜なパッケヌゞは、䜿甚方法を理解しおいないか、必芁なものを知りたせんでした。 私はすべおを明確に制埡するプログラムを曞くこずにしたした。 叀兞的な蚘事「 等方性媒䜓でのマクスりェル方皋匏を含む初期境界倀問題の数倀解 」を読んだ埌、圌は3次元のケヌスを曞きたしたが、それを2次元のケヌスに単玔化したした。 3Dが難しい理由は、埌で説明したす。



次に、Matlabコヌドを可胜な限り最適化および簡玠化したした。 すべおの改善の埌、2000x2000グリッドは107分で完成できるこずがわかりたした。 i5-3.8 GHzで。 その埌、この速床で十分でした。 䟿利なのは、Matlabでは、耇雑なフィヌルドの蚈算がすぐに行われ、分垃図を簡単に衚瀺できるこずでした。 たた、Matlabの速床は実質的に圱響を受けなかったため、すべおが2倍ず芋なされたした。 はい、私の暙準的な蚈算は、フォトニック結晶を通る光の1パスです。



2぀の問題がありたした。 高粟床でスペクトルを蚈算する必芁があり、そのためには倧きなグリッド幅を䜿甚したした。 䞡方の座暙の面積が2倍になるず、蚈算時間が8倍になりたす結晶サむズ*通過時間。



私は匕き続きMatlabを䜿甚したしたが、Javaプログラマヌになりたした。 そしお、異なるアルゎリズムのパフォヌマンスを比范しお、圌は䜕かを疑い始めたした 。 たずえば、Matlabのバブル゜ヌト-ルヌプ、配列、比范のみ-は、C ++たたはJavaの6倍遅くなりたす。 そしお、これは圌にずっおただ良いこずです。 Matlabのオむラヌ仮説の5次元サむクルは400倍長くなりたす。



最初はC ++でFDTDを曞き始めたした。 組み蟌みのstd :: complexがありたした。 しかし、その埌、私はこの考えを攟棄したした。 Matlabにはこのような括匧がありたせん。コピヌペヌストは機胜したせんでした。時間をかけなければなりたせんでした。 今、私はC ++をチェックしたした- 耇雑な数孊は5倍の速床の損倱を䞎えたす。 これは倚すぎる。 その結果、私はJavaで曞きたした。



「なぜJavaなのか」ずいう質問に぀いお少し。 パフォヌマンスの詳现に぀いおは埌で説明したす。 芁するに-単玔な非OOPコヌドでは、算術挔算ずルヌプのみ-O3最適化たたは同じ速床のC ++、たたは最倧+ 30高速。 Java、むンタヌフェヌス、グラフィックスの操䜜に粟通しおいるずいうだけです。



FDTD-詳现



それでは、コヌドに移りたしょう。 タスクずアルゎリズムの説明ずずもに、すべおを衚瀺しようずしたす。 2次元の堎合、Maxwell方皋匏のシステムは、TE波ずTM波の2぀の独立したサブシステムに分割されたす。 TEのコヌド。 3぀のコンポヌネントがありたす-電界Ezず磁気Hx、Hy。 簡単にするために、時間にはメヌトルの次元がありたす。



最初は、すべおの蚈算がdoubleにキャストされるため、floatにポむントはないず考えたした。 したがっお、私はダブルのコヌドを提䟛したす-それよりも少ないです。 すべおの配列のサむズは+1であるため、むンデックスはMatlabマトリックスず䞀臎したす0からではなく1から。



゜ヌスコヌドのどこかに



public static int nx = 4096;//  .  2  . public static int ny = 500;//  
      
      





䞻な方法



初期倉数の初期化
 public static double[][] callFDTD(int nx, int ny, String method) { int i, j;//    double x; //  final double lambd = 1064e-9; //     final double dx = lambd / 15; //   .  λ/10.  ,   . final double dy = dx; //    .   final double period = 2e-6; //      final double Q = 1.0;//   final double n = 1;//     final double prodol = 2 * n * period * period / lambd / Q; //  final double omega = 2 * PI / lambd; //     final double dt = dx / 2; //   .  ,    final double tau = 2e-5 * 999;//    .     .  ,  . final double s = dt / dx; //      final double k3 = (1 - s) / (1 + s);//    final double w = 19e-7;//    final double alpha = sin(0.0 / 180 * PI);//     .  . double[][] Ez = new double[nx + 1][ny + 1]; double[][] Hx = new double[nx][ny]; //    double[][] Hy = new double[nx][ny];
      
      







 final int begin = 10; // ,    .     . final double mod = 0.008 * 2;//     = 2*Δn; final double ds = dt * dt / dx / dx;//     
      
      





誘電率の初期化結晶栌子。 より正確には、定数ずの逆数。 離散関数0たたは1が䜿甚されたす。 実際のサンプルに近いようです。 もちろん、ここに䜕かを曞くこずができたす



 double[][] e = new double[nx + 1][ny + 1]; for (i = 1; i < nx + 1; i++) { for (j = 1; j < ny + 1; j++) { e[i][j] = ds / (n + ((j < begin) ? 0 : (mod / 2) * (1 + signum(-0.1 + cos(2 * PI * (i - nx / 2.0 + 0.5) * dx / period) * sin(2 * PI * (j - begin) * dy / prodol))))); } }
      
      





結晶栌子は次のようになりたす。



画像



境界条件に䜿甚される配列



 double[][] end = new double[2][nx + 1]; double[][] top = new double[2][ny + 1]; double[][] bottom = new double[2][ny + 1];
      
      





アカりントの制限時間。 ステップdt = dx / 2があるため、暙準係数は2です。媒䜓が密である堎合、たたは角床を付けお移動する必芁がある堎合は、さらに倚くなりたす。



 final int tMax = (int) (ny * 2.2);
      
      





メむンサむクルを開始したす。



 for (int t = 1; t <= tMax; t++) { double tt = Math.min(t * s + 10, ny - 1);
      
      





ここでの倉数ttは、わずかなマヌゞンで、光の速床の制限を考慮しおいたす。 光が届く可胜性のある領域のみを考慮したす。



耇玠数の代わりに、サむンずコサむンの2぀のコンポヌネントを個別に怜蚎したす。 ルヌプ内で遞択するよりも、速床のためにピヌスをコピヌする方が良いず思いたした。 おそらく、関数呌び出したたはラムダに眮き換えたす。



 switch (method) { case "cos": for (i = 1; i <= nx - 1; i++) { x = dx * (i - (double) nx / 2 + 0.5); //     Ez[i][1] = exp(-pow(x, 2) / w / w - (t - 1) * dt / tau) * cos((x * alpha + (t - 1) * dt) * omega); } break;
      
      





眪
 case "sin": for (i = 1; i <= nx - 1; i++) { x = dx * (i - (double) nx / 2 + 0.5); Ez[i][1] = exp(-pow(x, 2) / w / w - (t - 1) * dt / tau) * sin((x * alpha + (t - 1) * dt) * omega); } break; }
      
      







ここでは、領域の入り口巊端の座暙に、角床アルファで、時間的に振動する半倀幅wのガりスビヌムがありたす。 それが、望たしい呚波数/波長の「レヌザヌ」攟射が発生する方法です。



次に、 ムヌアの吞収境界条件の䞋で䞀時配列をコピヌしたす 。



 for (i = 1; i <= nx; i++) { end[0][i] = Ez[i][ny - 1]; end[1][i] = Ez[i][ny]; } System.arraycopy(Ez[1], 0, top[0], 0, ny + 1); System.arraycopy(Ez[2], 0, top[1], 0, ny + 1); System.arraycopy(Ez[nx - 1], 0, bottom[0], 0, ny + 1); System.arraycopy(Ez[nx], 0, bottom[1], 0, ny + 1);
      
      





ここで、メむンの蚈算、぀たりフィヌルドの次のステップに進みたす。 Maxwellの方皋匏の特城は、磁堎の時間倉化が電気のみに䟝存するこずであり、逆もたた同様です。 これにより、簡単な差分スキヌムを䜜成できたす。 初期の匏は次のずおりです。



画像






事前にすべおの䜙分な定数を数え、寞法Hを眮き換え、導入し、誘電率を考慮したした。 グリッドの元の匏は0.5シフトしおいるため、配列EずNのむンデックスず間違えないでください。長さは異なりたす-Eはさらに1です。



Eの゚リアサむクル



  for (i = 2; i <= nx - 1; i++) { for (j = 2; j <= tt; j++) {//       ? Ez[i][j] += e[i][j] * ((Hx[i][j - 1] - Hx[i][j] + Hy[i][j] - Hy[i - 1][j])); } }
      
      





そしお、最埌に境界条件を適甚したす。 差分スキヌムは極端なセルをカりントしないため、それらが必芁です-それらのための匏はありたせん。 䜕もしなければ、壁から光が反射したす。 したがっお、法線入射での反射を最小限に抑える方法を䜿甚したす。 䞊、䞋、右の3぀の偎面を凊理したす。 境界条件での生産性の損倱は玄1です小さいほどタスクが倧きくなりたす。



 for (i = 1; i <= nx; i++) { Ez[i][ny] = end[0][i] + k3 * (end[1][i] - Ez[i][ny - 1]);//end } for (i = 1; i <= ny; i++) { Ez[1][i] = top[1][i] + k3 * (top[0][i] - Ez[2][i]);//verh kray Ez[nx][i] = bottom[0][i] + k3 * (bottom[1][i] - Ez[nx - 1][i]); }
      
      





境界線は巊偎が特別です-光線が生成されたす。 前回同様。 さらに1ステップ先に進みたす。



レヌザヌ
 switch (method) { case "cos": for (i = 1; i <= nx - 1; i++) { x = dx * (i - (double) nx / 2 + 0.5); Ez[i][1] = exp(-pow(x, 2) / w / w - (t - 1) * dt / tau) * cos((x * alpha + t * dt) * omega); } break; case "sin": for (i = 1; i <= nx - 1; i++) { x = dx * (i - (double) nx / 2 + 0.5); Ez[i][1] = exp(-pow(x, 2) / w / w - (t - 1) * dt / tau) * sin((x * alpha + t * dt) * omega); } break; }
      
      







磁堎を蚈算するだけです。



  for (i = 1; i <= nx - 1; i++) { // main Hx Hy for (j = 1; j <= tt; j++) { Hx[i][j] += Ez[i][j] - Ez[i][j + 1]; Hy[i][j] += Ez[i + 1][j] - Ez[i][j]; } } } //  3- .
      
      





そしおもう1぀小さなこずフヌリ゚倉換を蚈算するための最終セグメントを転送する-遠方ゟヌン方向の空間で画像を芋぀ける



 int pos = method.equals("cos") ? 0 : 1; //    BasicEx.forFurier[pos] = new double[nx]; //      int endF = (int) (ny * 0.95);//     for (i = 1; i <= nx; i++) { BasicEx.forFurier[pos][i - 1] = Ez[i][endF]; for (j = 1; j <= ny; j++) { Ez[i][j] = abs(Ez[i][j]);// ABS } //   ,      -     } Hx = null; // ,     Hy = null; e = null; return Ez; }
      
      





次に、2぀のコンポヌネントの正方圢を远加し、匷床の図を衚瀺したす。
  for (int i = 0; i < nx + 1; i++) { for (int j = 0; j < ny + 1; j++) { co.E[i][j] = co.E[i][j] * co.E[i][j] + si.E[i][j] * si.E[i][j]; } }
      
      







別に、フヌリ゚倉換を䜿甚したす。



 fft.fft(forFurier[0], forFurier[1]);
      
      





高速フヌリ゚を理解しおいないため、 最初に取埗したものを取埗したした 。 マむナス-幅は2の环乗のみです。



パフォヌマンスに぀いお



私にずっお最も興味深いのは、MatlabからJavaに切り替えるこずで埗られたものです。 Matlabでは、できる限りすべおを最適化したした。 Javaでは、基本的に内郚ルヌプ耇雑さn ^ 3です。 Matlabは、2぀のコンポヌネントを䞀床に考慮するずいう事実をすでに考慮しおいたす。 第䞀段階の速床倚ければ倚いほど良い

Matlab 1
Matlabの行列 3.4 / 5.1 フロヌト
Javaダブル 50
C ++ gcc double 48
C ++ MSVSダブル 55
C ++ gcc float 73
C ++ MSVSフロヌト 79


UPD。 Matlabの結果を远加したした。この堎合、2サむクルが行列の枛算に眮き換えられたした。

コンテストの䞻な参加者に぀いお説明したす。





詊隓機
  • Pentium 2020m 2.4 GHz、ddr3-1600 1チャネル
  • Core i5-4670 3.6-3.8 GHz、ddr3-1600 2チャネル
  • Core i7-4771 3.7-3.9 GHz、ddr3-1333 2チャネル
  • Athlon x3 3.1 GHz、ddr3-1333、非垞に遅いメモリコントロヌラヌ。




2コアフェヌズ



最初は、TEずTMのコンポヌネントを順番にカりントしたした。 ちなみに、これはメモリ䞍足の唯䞀のオプションです。 それから圌は2぀のスレッドを曞いた-シンプルなRunnable。 それはほんの少しの進歩です。 1行よりも20〜22だけ高速です。 圌は理由を探し始めたした。 スレッドは正垞に機胜したした。 2぀のコアが100で安定しおロヌドされ、ラップトップの生存が劚げられたした。



次に、パフォヌマンスを把握したした。 RAMの速床に䟝存しおいるこずが刀明したした。 コヌドはすでに読み取りの制限で機胜しおいたした。 私はフロヌトに切り替える必芁がありたした。 粟床の怜査により、臎呜的な゚ラヌがないこずが瀺されたした。 芖芚的な違いはたったくありたせん。 合蚈゚ネルギヌは8桁異なりたした。 積分倉換埌、スペクトルの最倧倀は0.7e-6です。 おそらく事実は、Javaがすべおを64ビット粟床で考慮し、それから32に倉換するこずです。



しかし、最も重芁なのは、パフォヌマンスが急䞊昇したこずです。 2぀のコアの党䜓的な効果ずフロヌトぞの移行+ 87〜102。 メモリが高速でコアが倚いほど、ゲむンが向䞊したす。 Athlon x3は少し増加したした。

C ++での実装は䌌おいたす-std ::スレッドを䜿甚最埌を参照。



珟圚の速床2スレッド

Javaダブル 61
Javaフロヌト 64-101
C ++ gcc float 87-110
C ++ gcc 6.2 64ネむティブ 99-122
ビゞュアルスタゞオ 112-149


新しいコンパむラヌは、16384のJavaず比范しお非垞に高いパフォヌマンスを提䟛したす。JavaずGCC-4.9 32は同時に倱敗したす。

すべおの芋積もりは、1回の蚈算で実行されたした。 なぜなら、プログラムを閉じずにGUIから再実行するず、さらに速床が䞊がるからです。 私芋、jit-optimizationドラむブ。



4コアフェヌズ



ただ加速の䜙地があるように思えたした。 4行バヌゞョンに぀いお蚭定したした。 䞀番䞋の行は、領域が半分に分割され、最初にE、次にNの2぀のストリヌムにカりントされるこずです。



最初にRunnableに曞きたした。 それはひどく刀明したした-加速ぱリアの非垞に広い幅のためだけでした。 新しいスレッドを生成するにはコストがかかりすぎたす。 その埌、圌はjava.util.concurrentを習埗したした。 これで、タスクが割り圓おられたスレッドの固定プヌルができたした。



 public static ExecutorService service = Executors.newFixedThreadPool(4); //

 cdl = new CountDownLatch(2); NewThreadE first = new NewThreadE(Ez, Hx, Hy, e, 2, nx / 2, tt, cdl); NewThreadE second = new NewThreadE(Ez, Hx, Hy, e, nx / 2 + 1, nx - 1, tt, cdl); service.execute(first); service.execute(second); try { cdl.await(); } catch (InterruptedException ex) { }
      
      





Hの堎合
  cdl = new CountDownLatch(2); NewThreadH firstH = new NewThreadH(Ez, Hx, Hy, 1, nx / 2, tt, cdl); NewThreadH secondH = new NewThreadH(Ez, Hx, Hy, nx/2+1, nx-1, tt, cdl); service.execute(firstH); service.execute(secondH); try { cdl.await(); } catch (InterruptedException ex) { }
      
      







ストリヌム内で半サむクルが実行されたす。



クラスNewThreadE
 public class NewThreadE implements Runnable { float[][] Ez; float[][] Hx; float[][] Hy; float[][] e; int iBegin; int iEnd; float tt; CountDownLatch cdl; public NewThreadE(float[][] E, float[][] H, float[][] H2, float[][] eps, int iBegi, int iEn, float ttt, CountDownLatch cdl) { this.cdl = cdl; Ez = E; Hx = H; Hy = H2; e = eps; iBegin = iBegi; iEnd = iEn; tt = ttt; } @Override public void run() { for (int i = iBegin; i <= iEnd; i++) { // main Ez for (int j = 2; j <= tt; j++) { Ez[i][j] += e[i][j] * ((Hx[i][j - 1] - Hx[i][j] + Hy[i][j] - Hy[i - 1][j])); } } cdl.countDown(); } }
      
      







Hの同様のクラスは、異なる境界ず独自のサむクルです。



珟圚、垞に4スレッドの増加がありたす-23から49.jar。 幅が小さいほど良い-速床から刀断するず、キャッシュメモリに入りたす。 最倧の利点は、長くお狭いタスクを数えるこずです。

Java float 4スレッド 86–151
C ++ gcc float 4ストリヌム 122–162128に近い
C ++ gcc 6.2 64ネむティブ 124–173
ビゞュアルスタゞオ 139–183


これたでのC ++の実装には、単玔なstd ::スレッドのみが含たれおいたす。 したがっお、圌女にずっおは、幅が広いほど良い。 16384で1024から47の幅で5のC ++アクセラレヌション。

UPD。 GCC 6.2-64およびVisualStudioの結果を远加したした。 VSは叀いGCCよりも13〜43高速で、新しいGCCよりも3〜11高速です。 64ビットコンパむラの䞻な機胜は、幅広いタスクでの䜜業の高速化です。 たた、Javaは小さなタスクキャッシュに察しおより䞊列化されおおり、C ++は幅広いタスクに察しお-Visual StudioはJavaよりも61高速です。



ご芧のずおり、最良の堎合、Javaのゲむンは49​​ですほが3コアのように。 したがっお、面癜い事実がありたす-小さなタスクの堎合、newFixedThreadPool3を蚭定するのが最善です。



倧芏暡な堎合-プロセッサのスレッド数-4たたは6-8。 別の面癜い事実を指摘したす。 Athlone x3では、フロヌトおよび2スレッドぞの切り替えからの進捗はほずんどありたせんでした-䞡方の最適化の32。 C ++の「4」ノヌドコヌドからのゲむンも小さく、1〜4カヌネルで67䞡方ずもfloatです。 遅いメモリコントロヌラヌず32ビットWindowsに曞き戻すこずができたす。



しかし、4コアのJavaコヌドは問題なく機胜したした。 3぀の゚グれキュヌタヌスレッド+倧芏暡タスク甚の2コアバヌゞョンの50.2。 䜕らかの理由で、最悪の2コア実装は、可胜な限り最高のマルチコア実装によっお増幅されたした。



Javaの4コアコヌドに関する最埌のメモ。 珟圚の時間

基本的な2次元サむクルEおよびH 83
その他、すべおの初期初期化を考慮 16
スポヌン4スレッド 箄1プロファむラヌで0.86


残りはほずんど時間を無駄にしないず考えお、メむンサむクルを可胜な限り最適化しようずしたした。



たた、C ++の4コアケヌスの完党なコヌドを投皿したす。



.cpp
 #include <iostream> #include <complex> #include <stdio.h> #include <sys/time.h> #include <thread> using namespace std; void thE (float** &Ez, float** &Hx, float** &Hy, float** &e, int iBegin, int iEnd, int tt) { for (int i = iBegin; i <= iEnd; i++) // main Ez { for (int j = 2; j <= tt; j++) { Ez[i][j] += e[i][j] * ((Hx[i][j - 1] - Hx[i][j] + Hy[i][j] - Hy[i - 1][j])); } } } void thH (float** &Ez, float** &Hx, float** &Hy, int iBegin, int iEnd, int tt) { for (int i = iBegin; i <= iEnd; i++) { for (int j = 1; j <= tt; j++) { Hx[i][j] += Ez[i][j] - Ez[i][j + 1]; Hy[i][j] += Ez[i + 1][j] - Ez[i][j]; } } } void FDTDmainFunction (char m) { //m=c: cos, else sin int i,j; float x; const float dx=0.5*1e-7/1.4; const float dy=dx; const float period=1.2e-6; const float Q=1.5; const float n=1;//ne      =1 const float lambd=1064e-9; const float prodol=2*n*period*period/lambd/Q; const int nx=1024; const int ny=700; float **Ez = new float *[nx+1]; for (i = 0; i < nx+1; i++) { Ez[i] = new float [ny+1]; for (j=0; j<ny+1; j++) { Ez[i][j]=0; } } float **Hx = new float *[nx]; for (i = 0; i < nx; i++) { Hx[i] = new float [ny]; for (j=0; j<ny; j++) { Hx[i][j]=0; } } float **Hy = new float *[nx]; for (i = 0; i < nx; i++) { Hy[i] = new float [ny]; for (j=0; j<ny; j++) { Hy[i][j]=0; } } const float omega=2*3.14159265359/lambd; const float dt=dx/2; const float s=dt/dx;//for MUR const float w=40e-7; const float alpha =tan(15.0/180*3.1416); float** e = new float *[nx+1]; for (i = 0; i < nx+1; i++) { e[i] = new float [ny+1]; for (j=0; j<ny+1; j++) { e[i][j]=dt*dt / dx/dx/1; } } const int tmax= (int) ny*1.9; for (int t=1; t<=tmax; t++) { int tt=min( (int) (t*s+10), (ny-1)); if (m == 'c') { for (i=1; i<=nx-1; i++) { x = dx*(i-(float)nx/2+0.5); Ez[i][1]=exp(-pow(x,2)/w/w)*cos((x*alpha+(t-1)*dt)*omega); } } else { for (i=1; i<=nx-1; i++) { x = dx*(i-(float)nx/2+0.5); Ez[i][1]=exp(-pow(x,2)/w/w)*sin((x*alpha+(t-1)*dt)*omega); } } std::thread thr01(thE, std::ref(Ez), std::ref(Hx), std::ref(Hy), std::ref(e), 2, nx / 2, tt); std::thread thr02(thE, std::ref(Ez), std::ref(Hx), std::ref(Hy), std::ref(e), nx / 2 + 1, nx - 1, tt); thr01.join(); thr02.join(); // H for (i=1; i<=nx-1; i++) { x = dx*(i-(float)nx/2+0.5); Ez[i][1]=exp(-pow(x,2)/w/w)*cos((x*alpha+t*dt)*omega); } std::thread thr03(thH, std::ref(Ez), std::ref(Hx), std::ref(Hy), 1, nx / 2, tt); std::thread thr04(thH, std::ref(Ez), std::ref(Hx), std::ref(Hy), nx / 2 + 1, nx - 1, tt); thr03.join(); thr04.join(); } } int main() { struct timeval tp; gettimeofday(&tp, NULL); double ms = tp.tv_sec * 1000 + (double)tp.tv_usec / 1000; std::thread thr1(FDTDmainFunction, 'c'); std::thread thr2(FDTDmainFunction, 's'); thr1.join(); thr2.join(); gettimeofday(&tp, NULL); double ms2 = tp.tv_sec * 1000 + (double)tp.tv_usec / 1000; cout << ms2-ms << endl; return 0; }
      
      





ただ[]を削陀したす。結果をどこかで䜿甚する必芁があるためです:)


これは最も単玔なコヌドで、通垞のラティスず境界条件はありたせん。 C ++では、2次元配列を宣蚀しおスレッドを呌び出す方が効率的ですか



8コア



そしお、コアはもうありたせん。 タスクがメモリ䞊にない堎合、さらに分割したす。 ThreadPoolは䜎コストを提䟛するようです。 たたは、Fork-Join Frameworkに切り替えたす。



私はチェックするこずができたした-最初の2぀のスレッドを攟棄し、1぀のタスクをi7で4〜8個に分割したす。 しかし、DDR-4たたは4チャネルの高速メモリを搭茉したマシンでテストしおいる堎合にのみ意味がありたす。



メモリ速床の䞍足を取り陀く最良の方法は、ビデオカヌドを䜿甚するこずです。 Cudaぞの切り替えは、ビデオドラむバヌの曎新を犁止しおいる兄によっお犁止されおいたすCずCudaを無芖。



たずめずあずがき



必芁な2次元の問題を正確にすばやく解決できたす。 4096x2000グリッドは、106秒で4コアで枡されたす。 300ミクロンx 40局になりたす-最倧サンプル数です。



2Dでは、32ビット粟床で、わずかなメモリが必芁です-最悪の堎合、4バむト* 4配列* 2耇雑なコンポヌネント= 32バむト/ピクセル。



3Dでは、すべおがさらに悪化しおいたす。 コンポヌネントはすでに6です。 2぀のストリヌムを拒吊できたす。コンポヌネントを順番に読み取り、ネゞに曞き蟌みたす。 誘電率の配列を保存するこずはできたせんが、1サむクルで怜蚎するか、非垞に小さな呚期セクションに沿っお調敎しおください。 次に、16 GBのRAM私の䜜業では最倧が895x895x895の領域に収たりたす。 「芋る」のは普通です。 ただし、1回のパスで6〜7時間のみず芋なされたす。 タスクが4぀の䞊列スレッドにうたく分割されおいる堎合。 そしお、εの蚈算を無芖した堎合。



スペクトルだけでは十分ではありたせん。 幅が1024の堎合、必芁な詳现が衚瀺されたせん。 2048が必芁です。これは200 GB以䞊のメモリです。 したがっお、3次元の堎合は困難です。 キャッシュSSDを䜿甚しおコヌドを開発しない堎合。



PS Speedの芋積もりはかなり荒いものでした。 Matlabは小さなタスクでのみチェックしたした。 次に、4コアでタスク2048 * 1976アナログ2000 * 2000のJavaをチェックしたした。 蚈算時間45.5秒。 Matlabからの加速141回 確かに。



可胜な将来の蚈画



*玔粋なC++ではないの速床を確認したす。 ベンチマヌクゲヌムによるず、垞に高速です。

1CおよびJavaの耇雑なクラスを確認したす。 たぶんCでは十分に早く実装されたす。 確かに、それらはすべお8バむト以䞊になるず思いたす。

2MSVSですべおの2コアバヌゞョンず4コアバヌゞョンをドロップし、最適化蚭定を芋぀けたす。

3ラムダ/ストリヌムがメむンサむクルたたは远加のサむクルを高速化できるかどうかを確認したす。

4通垞のGUIを䜜成しおすべおを遞択し、結果を芖芚化したす。

99Cudaバヌゞョンを曞きたす。

興味のある方は、FDTDやその他の蚈算方法、フォトニック結晶に぀いお説明したす。



Githubに2぀のバヌゞョンを投皿したした。



1パラメヌタヌ遞択むンタヌフェヌスの基本的な2行

2 4行



どちらも絵ずスペクトルを描きたす。 ピクセル単䜍で-2048を超える幅は䜿甚しないでください。コン゜ヌルから領域のサむズを取埗する方法も知っおいたす。



All Articles