private double[] getSrcImage() { if (Crystal.Bethe.Disks == null || trackBarOutputThickness.Value >= Crystal.Bethe.Disks.Length) { return(null); } var image = new double[ImageWidth * ImageHeight]; var disks = Crystal.Bethe.Disks[trackBarOutputThickness.Value]; var center = new PointD(ImageWidth / 2.0, ImageHeight / 2.0); //中心付近の1ピクセル当たりの角度 foreach (var disk in disks.Where(disk => disk.Intensity.Max() > 1E-20)) { var v = new { x = disk.G.X, y = -disk.G.Y, z = -disk.G.Z };//ここでベクトルのY,Zの符号を反転 var point = Geometriy.GetCrossPoint(0, 0, 1, FormDiffractionSimulator.CameraLength2, new Vector3D(0, 0, 0), new Vector3D(v.x, v.y, v.z + FormDiffractionSimulator.EwaldRadius)); var pt = new PointD(point.X, point.Y); //ptをピクセル座標に変換する var diskCenter = new Point((int)(pt.X / ImagePixelSize + center.X + 0.5), (int)(pt.Y / ImagePixelSize + center.Y + 0.5)); if (diskCenter.X > -ImageWidth * 0.5 && diskCenter.Y > -ImageHeight * 0.5 && diskCenter.X < ImageWidth * 1.5 && diskCenter.Y < ImageHeight * 1.5) { var side = (int)Math.Sqrt(disk.Intensity.Length); for (int y = diskCenter.Y + side / 2, n = 0; y >= diskCenter.Y - side / 2; y--) { for (int x = diskCenter.X + side / 2; x >= diskCenter.X - side / 2; x--) { if (x > -1 && x < ImageWidth && y > -1 && y < ImageHeight && (diskCenter.X - x) * (diskCenter.X - x) + (diskCenter.Y - y) * (diskCenter.Y - y) < (side * side / 4)) { image[y * ImageWidth + x] += disk.Intensity[n]; } n++; } } } } return(image); }
/// <summary> /// 回折スポットおよび指数ラベルの描画 /// </summary> /// <param name="graphics">描画対象のグラフィックオブジェクト</param> /// <param name="drawLabel">ラベルを描画するかどうか</param> /// <param name="outputOnlySpotInformation">このフラグがTrueの場合は、画面描画は行わずにspotの情報だけを返す</param> public List <SpotInformation> GetDiffractionSpots(Matrix3D rotation, IEnumerable <Vector3D> gVector, double coeff) { var spotInformation = new List <SpotInformation>(); double sigma = spotRadiusOnDetector; //描画するスポットを決める foreach (Vector3D g in gVector) { Vector3DBase vec = rotation * g; if (vec.Z > -3 * excitationError) { vec.Y = -vec.Y; vec.Z = -vec.Z;//ここでベクトルのY,Zの符号を反転 double L2 = vec.X * vec.X + vec.Y * vec.Y; double dev = ewaldRadius - Math.Sqrt(L2 + (vec.Z + ewaldRadius) * (vec.Z + ewaldRadius)), dev2 = dev * dev; if (dev2 < 9 * error2) { if (-sinTau * vec.Y + cosTau * (vec.Z + ewaldRadius) > 0)//(vec.X, vec.Y, vec.Z + EwaldRadius) と(0, -sinTau, cosTau) の内積が0より大きい) { //2020/02/03の変更対処済み var point = Geometriy.GetCrossPoint(0, sinTau, -cosTau, cameraLength2, new Vector3D(0, 0, 0), new Vector3D(vec.X, vec.Y, vec.Z + ewaldRadius)); PointD pt = new PointD(point.X, point.Y * cosTau + point.Z * sinTau); //if (IsDetectorArea(pt)) { double intensity = g.RelativeIntensity / (sigma * sqrt2PI) * Math.Exp(-dev2 / error2 / 2); if (intensity > 1E-3) { spotInformation.Add(new SpotInformation(pt.X, pt.Y, intensity * coeff, sigma)); } } } } } } return(spotInformation); }
private void execute(string filename = "") { var n = 0; var initialRot = new Matrix3D(FormDiffractionSimulator.formMain.Crystal.RotationMatrix); var originalAxes = new Matrix3D(OriginalCrystal.A_Axis * 10, OriginalCrystal.B_Axis * 10, OriginalCrystal.C_Axis * 10); //データ数を減らす var numMax = 4; var ptTemp = graphControl.Profile.Pt; var pt = new List <PointD>(); for (int i = 0; i < ptTemp.Count; i += numMax) { var num = Math.Min(numMax, ptTemp.Count - i); var p = new PointD(); for (int j = i; j < i + num; j++) { p += ptTemp[j]; } pt.Add(p / num); } //var pt = graphControl.Profile.Pt; var states = new List <(double depth, double pressure, double thickness)>(); for (int i = 0; i < pt.Count - 1; i++) { states.Add(((pt[i].X + pt[i + 1].X) / 2, (pt[i].Y + pt[i + 1].Y) / 2, pt[i + 1].X - pt[i].X)); } int count = checkBoxOmegaStep.Checked ? numericBoxOmegaTimes.ValueInteger : 1; toolStripProgressBar.Maximum = states.Count * count; toolStripProgressBar.Value = 0; //無回転の時の圧縮面の法線ベクトル int cH = numericBoxShockedPlaneH.ValueInteger, cK = numericBoxShockedPlaneK.ValueInteger, cL = numericBoxShockedPlaneL.ValueInteger; var compressedPlane = (cH * OriginalCrystal.A_Star + cK * OriginalCrystal.B_Star + cL * OriginalCrystal.C_Star).Normarize(); //無回転の時の圧縮面の法線ベクトルを(1,0,0)方向に向ける回転ベクトル var m1 = Matrix3D.Rot(Vector3DBase.VectorProduct(compressedPlane, new Vector3DBase(1, 0, 0)), Math.Acos(compressedPlane.X)); //無回転時の圧縮面と平行なベクトル (int h, int k, int l, Vector3DBase vec)v1 = (-cK, cH, 0, (-cK * OriginalCrystal.A_Axis + cH * OriginalCrystal.B_Axis).Normarize()); (int h, int k, int l, Vector3DBase vec)v2 = (0, -cL, cK, (-cL * OriginalCrystal.B_Axis + cK * OriginalCrystal.C_Axis).Normarize()); if (v1.vec.Length2 < 0.1) { v1 = (-cL, 0, cH, (-cL * OriginalCrystal.A_Axis + cH * OriginalCrystal.C_Axis).Normarize()); } if (v2.vec.Length2 < 0.1) { v2 = (-cL, 0, cH, (-cL * OriginalCrystal.A_Axis + cH * OriginalCrystal.C_Axis).Normarize()); } //回転状態の圧縮面の法線ベクトル var shockDirection = initialRot * compressedPlane; //無回転の時のスリップ面の法線ベクトル var slipPlane = (numericBoxSlipPlaneH.Value * OriginalCrystal.A_Star + numericBoxSlipPlaneK.Value * OriginalCrystal.B_Star + numericBoxSlipPlaneL.Value * OriginalCrystal.C_Star).Normarize(); //回転時のスリップ面と圧縮面の外積ベクトル var rotationAxis2019 = Vector3DBase.AngleBetVectors(slipPlane, compressedPlane) < Math.PI / 2 ? initialRot * Vector3DBase.VectorProduct(slipPlane, compressedPlane) : initialRot *Vector3DBase.VectorProduct(compressedPlane, slipPlane); //(0,0,1)方向をrotationAxis2019に向ける回転ベクトル var m2 = Matrix3D.Rot(Vector3DBase.VectorProduct(new Vector3DBase(0, 0, 1), rotationAxis2019), Math.Acos(rotationAxis2019.Z)); //2018モデル。結晶は圧縮軸に垂直な方向を回転軸として回転すると仮定。その回転軸のリストを設定 List <Vector3DBase> rotationAxes2018 = new List <Vector3DBase>(); var div1 = numericBoxDivisionOfRotationAxis.ValueInteger;//回転軸を分割する数 var initialNormalDirection = Math.Abs(shockDirection.Z) < 0.5 ? new Vector3DBase(shockDirection.Y, -shockDirection.X, 0) : new Vector3DBase(0, -shockDirection.Z, shockDirection.Y); for (int rot = 0; rot < div1; rot++) { rotationAxes2018.Add(Matrix3D.Rot(shockDirection, 2 * Math.PI * rot / div1) * initialNormalDirection); } var div2 = numericBoxDivisionOfRotationAngle.ValueInteger;//回転量を分割する数 double front = graphControl.LineList[0].X, back = graphControl.LineList[1].X; double omegaC = numericBoxCompressedOmega.RadianValue, sigmaOmegaC = numericBoxCompressedOmegaSigma.RadianValue; double omegaR = numericBoxReleasedOmega.RadianValue, sigmaOmegaR = numericBoxReleasedOmegaSigma.RadianValue; double thetaC_A = numericBoxCompressedThetaA.RadianValue, thetaC_B = numericBoxCompressedThetaB.RadianValue; double thetaR_A = numericBoxReleasedThetaA.RadianValue, thetaR_B = numericBoxReleasedThetaB.RadianValue; var absorption = 1.0; var compiledImage = new double[FormDiffractionSimulator.FormDiffractionSimulatorGeometry.DetectorWidth * FormDiffractionSimulator.FormDiffractionSimulatorGeometry.DetectorHeight]; var spots = new List <SpotInformation>(); long beforeSec = 0; //メインループ開始 for (int i = 0; i < states.Count; i++) { FormDiffractionSimulator.SkipDrawing = FormDiffractionSimulator.formMain.SkipDrawing = checkBoxSkipDrawing.Checked; var rotationList = new List <(Matrix3D rot, double weight)>(); if (states[i].depth < front)//Uncompressedの時 { rotationList.Add((Matrix3D.IdentityMatrix, 1)); } else { var time1 = states[i].depth < back ? (states[i].depth - front) / numericBoxUp.Value : (back - front) / numericBoxUp.Value; var time2 = states[i].depth < back ? 0.0 : (states[i].depth - back) / numericBoxUr.Value; var omega = omegaC * time1 + omegaR * time2; var range = 2.0; if (radioButton2018Model.Checked)//2018モデルの時 { var sigmaOmega = Math.Sqrt(time1 * sigmaOmegaC * time1 * sigmaOmegaC + time2 * sigmaOmegaR * time2 * sigmaOmegaR); double start = Math.Max(0, omega - range * sigmaOmega), end = omega + range * sigmaOmega, step = (end - start) / div2; var rotationAngles = new List <PointD>(); for (var speed = start; speed <= end + step / 2; speed += step) { rotationAngles.Add(new PointD(speed, Math.Exp(-(speed - omega) * (speed - omega) / 2 / sigmaOmega / sigmaOmega))); } foreach (var axis in rotationAxes2018) { foreach (var angle in rotationAngles) { rotationList.Add((Matrix3D.Rot(axis, angle.X), angle.Y)); } } } else//2019モデルの時 { double sigmaTheta = states[i].depth < back ? thetaC_A + thetaC_B * time1 : thetaC_A * time1 + thetaR_A + thetaR_B * time2, sigmaTheta2 = sigmaTheta * sigmaTheta; double sigmaOmega = sigmaOmegaC * time1 + sigmaOmegaR * time2, sigmaOmega2 = sigmaOmega * sigmaOmega; double stepTheta = (range * sigmaTheta) / ((int)Math.Sqrt(div1) + 1); double startR = Math.Max(0, omega - range * sigmaOmega), endR = omega + range * sigmaOmega, stepR = (endR - startR) / div2; double stepPhi = (2 * Math.PI) / ((int)Math.Sqrt(div1) + 1); if (stepTheta == 0) { stepTheta = double.PositiveInfinity; } if (stepR == 0) { stepR = double.PositiveInfinity; } for (var theta = stepTheta / 2; theta <= range * sigmaTheta; theta += stepTheta) { for (var phi = 0.0; phi < 2 * Math.PI; phi += stepPhi) { for (var r = startR; r <= endR; r += stepR) { var v = new Vector3DBase(Math.Sin(theta) * Math.Cos(phi), Math.Sin(theta) * Math.Sin(phi), Math.Cos(theta)); rotationList.Add((Matrix3D.Rot(m2 * v, r), Math.Exp(-(r - omega) * (r - omega) / 2 / sigmaOmega2 - theta * theta / 2 / sigmaTheta2) * r * r * Math.Sin(theta))); } } } } } var sum = rotationList.Sum(r => r.weight); rotationList = rotationList.Select(r => (r.rot, r.weight / sum)).ToList(); //ここから、圧縮による格子定数の変化 Matrix3D newAxes = originalAxes; if (states[i].depth >= front) { var volume = EOS.InverseThirdBirchMurnaghan(numericBoxEOS_K0.Value, numericBoxEOS_Kprime.Value, states[i].pressure * 100); if ((states[i].depth < back && radioButtonCompressedUniaxial.Checked) || (states[i].depth >= back && radioButtonReleasedUniaxial.Checked)) { newAxes = m1.Inverse() * new Matrix3D(1 / volume, 0, 0, 0, 1, 0, 0, 0, 1) * m1 * originalAxes; } else { newAxes = new Matrix3D(Math.Pow(1 / volume, 1.0 / 3.0), 0, 0, 0, Math.Pow(1 / volume, 1.0 / 3.0), 0, 0, 0, Math.Pow(1 / volume, 1.0 / 3.0)) * originalAxes; } } var a = new Vector3DBase(newAxes.E11, newAxes.E21, newAxes.E31); var b = new Vector3DBase(newAxes.E12, newAxes.E22, newAxes.E32); var c = new Vector3DBase(newAxes.E13, newAxes.E23, newAxes.E33); FormDiffractionSimulator.SkipDrawing = FormDiffractionSimulator.formMain.SkipDrawing = true; CrystalControl.CellConstants = (a.Length, b.Length, c.Length, Vector3DBase.AngleBetVectors(b, c), Vector3DBase.AngleBetVectors(c, a), Vector3DBase.AngleBetVectors(a, b)); var corrRot = newAxes * new Matrix3D(CrystalControl.Crystal.A_Axis * 10, CrystalControl.Crystal.B_Axis * 10, CrystalControl.Crystal.C_Axis * 10).Inverse(); // ここまで //候補となるgの絞り込み FormDiffractionSimulator.SetVector(true); List <Vector3D> gVector = new List <Vector3D>(); foreach (var g in FormDiffractionSimulator.formMain.Crystal.VectorOfG.Where(g => g.Flag && g.RelativeIntensity > 1E-6)) { var vec = initialRot * corrRot * g; vec.Y = -vec.Y; vec.Z = -vec.Z; //ここでベクトルのY,Zの符号を反転 if (-sinTau * vec.Y + cosTau * (vec.Z + ewaldRadius) > 0) //(vec.X, vec.Y, vec.Z + EwaldRadius) と(0, -sinTau, cosTau) の内積が0より大きい) { //2020/02/03の変更対処済み var point = Geometriy.GetCrossPoint(0, -sinTau, cosTau, cameraLength2, new Vector3D(0, 0, 0), new Vector3D(vec.X, vec.Y, vec.Z + ewaldRadius)); if (IsDetectorArea(new PointD(point.X, point.Y * cosTau + point.Z * sinTau))) { gVector.Add(g); } } }//ここまで //ここから揺動のループ var effectiveThickness = states[i].thickness / (shockDirection * new Vector3DBase(0, 0, 1)); absorption *= Math.Exp(-numericBoxMassAbsorption.Value * FormDiffractionSimulator.formMain.Crystal.Density * effectiveThickness / 10000); foreach (var(rot, weight) in rotationList) { var temp = GetDiffractionSpots(rot * initialRot * corrRot, gVector, states[i].thickness * absorption * absorption * weight);//入射と出射で二回absorptionをかける spots.AddRange(temp); if (n++ % 100 == 0 && !checkBoxSkipDrawing.Checked) { FormDiffractionSimulator.formMain.SetRotation(rot * initialRot * corrRot); } } // if (spots.Count > 100 || i == states.Count - 1) { var image = getImageData(spots); for (int j = 0; j < compiledImage.Length; j++) { compiledImage[j] += image[j]; } spots.Clear(); } toolStripProgressBar.Value++; toolStripStatusLabel1.Text = "Time elapsed: " + (sw.ElapsedMilliseconds / 1000.0).ToString("f1") + " sec., per slice: " + (sw.ElapsedMilliseconds - beforeSec).ToString() + " msec., wait for more " + (sw.ElapsedMilliseconds / 1000.0 / toolStripProgressBar.Value * (toolStripProgressBar.Maximum - toolStripProgressBar.Value)).ToString("f1") + " sec."; beforeSec = sw.ElapsedMilliseconds; Application.DoEvents(); }//メインループここまで compiledImage = compiledImage.Select(intensity => intensity * 1E6).ToArray(); PseudoBitmap pseud = new PseudoBitmap(compiledImage, FormDiffractionSimulator.FormDiffractionSimulatorGeometry.DetectorWidth); Tiff.Writer("temp.tif", compiledImage, 2, FormDiffractionSimulator.FormDiffractionSimulatorGeometry.DetectorWidth); FormDiffractionSimulator.FormDiffractionSimulatorGeometry.ReadImage("temp.tif"); if (filename != "") { File.Copy("temp.tif", filename, true); } FormDiffractionSimulator.SkipDrawing = FormDiffractionSimulator.formMain.SkipDrawing = false; }