public static Quaternion FromLogQuaternion(Vector3DBase v) { double theta = v.Length; v = v / theta * Math.Sin(theta); return(new Quaternion(Math.Cos(theta), v.X, v.Y, v.Z)); }
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string) && value is Vector3DBase) { Vector3DBase g = (Vector3DBase)value; return(string.Format("{0}, {1}, {2}", g.X, g.Y, g.Z)); } return(base.ConvertTo(context, culture, value, destinationType)); }
/// <summary> /// シュミット上の点を返す /// </summary> /// <param name="vec"></param> /// <returns></returns> public static PointD ConvertVectorToSchmidt(Vector3DBase vec) { if (vec == null) { return(new PointD(-100, -100)); } var v = Vector3DBase.Normarize(vec); return(v.Z >= -0.999999 ? new PointD(v.X / Math.Sqrt(1 + v.Z), v.Y / Math.Sqrt(1 + v.Z)) : new PointD(-100, -100)); }
/// <summary> /// ピクセルが対応する逆空間ベクトルを計算し、ReciprocalVectorsにセットする /// </summary> /// <returns></returns> private void SetReciporocalVectors() { ReciprocalVectors = new Vector3DBase[ImageWidth * ImageHeight]; Parallel.For(0, ImageHeight, y => { for (int x = 0; x < ImageWidth; x++) { ReciprocalVectors[y * ImageWidth + x] = convertClientToReciprocalSpace(x, y); } }); }
//public enum Setting { XYX, XYZ, XZX, XZY, YXY, YXZ, YZX, YZY, ZXY, ZXZ, ZYX, ZYZ} /// <summary> /// 任意のセッティングのオイラー角に分解する. => MathNet.FindMinimumの方が簡単なので、お蔵入り /// </summary> /// <param name="rot"></param> /// <param name="setting"></param> /// <returns></returns> public static double[] DecomposeMatrix(Matrix3D rot, Vector3DBase v1, Vector3DBase v2, Vector3DBase v3) { Matrix3D funcRot(double[] angle) => Matrix3D.Rot(v1, angle[0]) * Matrix3D.Rot(v2, angle[1]) * Matrix3D.Rot(v3, angle[2]); var func = new Marquardt.Function( new Func <double[], double[], double>((x, prm) => { var res = funcRot(prm); if (x[0] == 0.0) { return(res.E11); } else if (x[0] == 1.0) { return(res.E12); } else if (x[0] == 2.0) { return(res.E13); } else if (x[0] == 3.0) { return(res.E21); } else if (x[0] == 4.0) { return(res.E22); } else if (x[0] == 5.0) { return(res.E23); } else if (x[0] == 6.0) { return(res.E31); } else if (x[0] == 7.0) { return(res.E32); } else if (x[0] == 8.0) { return(res.E33); } else { return(0); } }), new[] { 0.1, 0.2, 0.3 }); var obsValues = new[] {
public Matrix3D(Vector3DBase v1, Vector3DBase v2, Vector3DBase v3) { E11 = v1.X; E21 = v1.Y; E31 = v1.Z; E12 = v2.X; E22 = v2.Y; E32 = v2.Z; E13 = v3.X; E23 = v3.Y; E33 = v3.Z; }
/// <summary> /// 対数Quatanion (方向が回転軸で長さがθ/2のベクトル)を得る. /// </summary> /// <param name="q"></param> /// <returns></returns> public static Vector3DBase ToLogQuaternion(Quaternion q) { Vector3DBase v = new Vector3DBase(q.X, q.Y, q.Z); double theta = Math.Acos(q.W); if (q.W >= 1) { return(v); } else { return(v / v.Length * theta); } }
private void numericBoxStrain_ValueChanged(object sender, EventArgs e) { skipCrystalChangedEvent = true; var m = StrainMatrix * new Matrix3D(originalCrystal.A_Axis, originalCrystal.B_Axis, originalCrystal.C_Axis);//この歪の計算は間違っている!直さなければ。。。 var a = new Vector3DBase(m.E11, m.E21, m.E31); var b = new Vector3DBase(m.E12, m.E22, m.E32); var c = new Vector3DBase(m.E13, m.E23, m.E33); numericBoxA.Value = a.Length * 10; numericBoxB.Value = b.Length * 10; numericBoxC.Value = c.Length * 10; numericBoxAlpha.RadianValue = Vector3DBase.AngleBetVectors(b, c); numericBoxBeta.RadianValue = Vector3DBase.AngleBetVectors(c, a); numericBoxGamma.RadianValue = Vector3DBase.AngleBetVectors(a, b); CrystalControl.symmetryControl.CellConstants = (numericBoxA.Value, numericBoxB.Value, numericBoxC.Value, numericBoxAlpha.RadianValue, numericBoxBeta.RadianValue, numericBoxGamma.RadianValue); Application.DoEvents(); skipCrystalChangedEvent = false; calculateStress(); }
/// <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); }
public Vector3DBase(Vector3DBase v) { X = v.X; Y = v.Y; Z = v.Z; }
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; }
private Profile Mindex() { if (crystal == null || crystal.Crystallites == null) { return(null); } Profile p = new Profile(); for (int i = 0; i <= 120; i++) { p.Pt.Add(new PointD(i, 0)); } Random rn = new Random(); Vector3DBase a = new Vector3DBase(1, 0, 0); Vector3DBase b = new Vector3DBase(0, 1, 0); Vector3DBase c = new Vector3DBase(0, 0, 1); Vector3DBase[] v1 = divideVector(a, crystal.Symmetry); Vector3DBase[] v2 = divideVector(b, crystal.Symmetry); Vector3DBase[] v3 = divideVector(c, crystal.Symmetry); List <Matrix3D> symmetryMat = new List <Matrix3D>(); for (int i = 0; i < v1.Length; i++) { if (new Matrix3D(v1[i], v2[i], v3[i]).Determinant() > 0) { symmetryMat.Add(new Matrix3D(v1[i], v2[i], v3[i])); } } Parallel.For(0, crystal.Crystallites.TotalCrystalline, i => { Matrix3D m1, m2; lock (lockObject) { m1 = crystal.Crystallites.Rotations[rn.Next(crystal.Crystallites.TotalCrystalline)]; m2 = crystal.Crystallites.Rotations[rn.Next(crystal.Crystallites.TotalCrystalline)]; } double dia = double.MinValue; Matrix3D r = m1.Transpose() * m2; for (int j = 0; j < symmetryMat.Count; j++) { Matrix3D r2 = r * symmetryMat[j]; dia = Math.Max((r2.E11 + r2.E22 + r2.E33 - 1) / 2, dia); dia = Math.Max((-r2.E11 - r2.E22 + r2.E33 - 1) / 2, dia); dia = Math.Max((r2.E11 - r2.E22 - r2.E33 - 1) / 2, dia); dia = Math.Max((-r2.E11 + r2.E22 - r2.E33 - 1) / 2, dia); } if (dia >= -1 && dia <= 1) { int angle = (int)Math.Round(Math.Acos(dia) / Math.PI * 180, MidpointRounding.AwayFromZero); if (angle >= 0 && angle <= 120) { p.Pt[angle] += new PointD(0, 1); } } }); for (int i = 0; i <= 120; i++) { p.Pt[i] = new PointD(p.Pt[i].X, p.Pt[i].Y / crystal.Crystallites.TotalCrystalline); } return(p); }
private Vector3DBase[] divideVector(Vector3DBase baseVec, Symmetry sym) { List <Vector3DBase> vec = new List <Vector3DBase>(); double x = baseVec.X, y = baseVec.Y, z = baseVec.Z; double sqrt3 = Math.Sqrt(3); switch (sym.LaueGroupNumber) { case 0: //unknown vec.Add(baseVec); break; case 1: //-1 vec.Add(new Vector3DBase(x, y, z)); vec.Add(new Vector3DBase(-x, -y, -z)); break; case 2: // 2/m switch (sym.MainAxis) { case "a": vec.Add(new Vector3DBase(x, y, z)); vec.Add(new Vector3DBase(-x, -y, -z)); vec.Add(new Vector3DBase(-x, y, z)); vec.Add(new Vector3DBase(x, -y, -z)); break; case "b": vec.Add(new Vector3DBase(x, y, z)); vec.Add(new Vector3DBase(-x, -y, -z)); vec.Add(new Vector3DBase(x, -y, z)); vec.Add(new Vector3DBase(-x, y, -z)); break; case "c": vec.Add(new Vector3DBase(x, y, z)); vec.Add(new Vector3DBase(-x, -y, -z)); vec.Add(new Vector3DBase(x, y, -z)); vec.Add(new Vector3DBase(-x, -y, z)); break; } break; case 3: // mmm vec.Add(new Vector3DBase(x, y, z)); vec.Add(new Vector3DBase(-x, -y, -z)); vec.Add(new Vector3DBase(-x, y, z)); vec.Add(new Vector3DBase(x, -y, -z)); vec.Add(new Vector3DBase(x, -y, z)); vec.Add(new Vector3DBase(-x, y, -z)); vec.Add(new Vector3DBase(x, y, -z)); vec.Add(new Vector3DBase(-x, -y, z)); break; case 4: //4/m vec.Add(new Vector3DBase(+x, +y, +z)); vec.Add(new Vector3DBase(-x, -y, +z)); vec.Add(new Vector3DBase(-y, +x, +z)); vec.Add(new Vector3DBase(+y, -x, +z)); vec.Add(new Vector3DBase(+x, +y, -z)); vec.Add(new Vector3DBase(-x, -y, -z)); vec.Add(new Vector3DBase(-y, +x, -z)); vec.Add(new Vector3DBase(+y, -x, -z)); break; case 5: //4/mmm vec.Add(new Vector3DBase(+x, +y, +z)); vec.Add(new Vector3DBase(-x, -y, +z)); vec.Add(new Vector3DBase(-y, +x, +z)); vec.Add(new Vector3DBase(+y, -x, +z)); vec.Add(new Vector3DBase(+x, -y, +z)); vec.Add(new Vector3DBase(-x, +y, +z)); vec.Add(new Vector3DBase(+y, +x, +z)); vec.Add(new Vector3DBase(-y, -x, +z)); vec.Add(new Vector3DBase(+x, +y, -z)); vec.Add(new Vector3DBase(-x, -y, -z)); vec.Add(new Vector3DBase(-y, +x, -z)); vec.Add(new Vector3DBase(+y, -x, -z)); vec.Add(new Vector3DBase(+x, -y, -z)); vec.Add(new Vector3DBase(-x, +y, -z)); vec.Add(new Vector3DBase(+y, +x, -z)); vec.Add(new Vector3DBase(-y, -x, -z)); break; case 6: //-3 if (sym.SpaceGroupHMsubStr != "R") //Hexaセルの場合 { vec.Add(new Vector3DBase(+x, +y, +z)); vec.Add(new Vector3DBase(+(-x - sqrt3 * y) / 2, +(+sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(+(-x + sqrt3 * y) / 2, +(-sqrt3 * x - y) / 2, +z)); vec.Add(-vec[0]); vec.Add(-vec[1]); vec.Add(-vec[2]); } else //Rhomboセルの場合 未完成 { } break; case 7: //-3m 未完成 if (sym.SpaceGroupHMsubStr != "R") //Hexaセルの場合 { vec.Add(new Vector3DBase(+x, +y, +z)); vec.Add(new Vector3DBase(+(-x - sqrt3 * y) / 2, +(+sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(+(-x + sqrt3 * y) / 2, +(-sqrt3 * x - y) / 2, +z)); vec.Add(-vec[0]); vec.Add(-vec[1]); vec.Add(-vec[2]); if (sym.SpaceGroupHallStr.Contains("\"")) //3m1の場合 { vec.Add(new Vector3DBase(-x, +y, +z)); vec.Add(new Vector3DBase(-(-x - sqrt3 * y) / 2, +(+sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(-(-x + sqrt3 * y) / 2, +(-sqrt3 * x - y) / 2, +z)); } else { vec.Add(new Vector3DBase(+x, -y, +z)); vec.Add(new Vector3DBase(+(-x - sqrt3 * y) / 2, -(+sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(+(-x + sqrt3 * y) / 2, -(-sqrt3 * x - y) / 2, +z)); } vec.Add(-vec[6]); vec.Add(-vec[7]); vec.Add(-vec[8]); } else //Rhomboセルの場合 未完成 { } break; case 8: //6/m vec.Add(new Vector3DBase(+x, +y, +z)); vec.Add(new Vector3DBase(+(-x - sqrt3 * y) / 2, +(+sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(+(-x + sqrt3 * y) / 2, +(-sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(-x, -y, +z)); vec.Add(new Vector3DBase(-(-x - sqrt3 * y) / 2, -(+sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(-(-x + sqrt3 * y) / 2, -(-sqrt3 * x - y) / 2, +z)); vec.Add(-vec[0]); vec.Add(-vec[1]); vec.Add(-vec[2]); vec.Add(-vec[3]); vec.Add(-vec[4]); vec.Add(-vec[5]); break; case 9: //6/mmm vec.Add(new Vector3DBase(+x, +y, +z)); vec.Add(new Vector3DBase(+(-x - sqrt3 * y) / 2, +(+sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(+(-x + sqrt3 * y) / 2, +(-sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(-x, -y, +z)); vec.Add(new Vector3DBase(-(-x - sqrt3 * y) / 2, -(+sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(-(-x + sqrt3 * y) / 2, -(-sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(-x, +y, +z)); vec.Add(new Vector3DBase(-(-x - sqrt3 * y) / 2, +(+sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(-(-x + sqrt3 * y) / 2, +(-sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(+x, -y, +z)); vec.Add(new Vector3DBase(+(-x - sqrt3 * y) / 2, -(+sqrt3 * x - y) / 2, +z)); vec.Add(new Vector3DBase(+(-x + sqrt3 * y) / 2, -(-sqrt3 * x - y) / 2, +z)); vec.Add(-vec[0]); vec.Add(-vec[1]); vec.Add(-vec[2]); vec.Add(-vec[3]); vec.Add(-vec[4]); vec.Add(-vec[5]); vec.Add(-vec[6]); vec.Add(-vec[7]); vec.Add(-vec[8]); vec.Add(-vec[9]); vec.Add(-vec[10]); vec.Add(-vec[11]); break; case 10: //m3 vec.Add(new Vector3DBase(+x, +y, +z)); vec.Add(new Vector3DBase(-x, -y, +z)); vec.Add(new Vector3DBase(-x, +y, -z)); vec.Add(new Vector3DBase(+x, -y, -z)); vec.Add(new Vector3DBase(+z, +x, +y)); vec.Add(new Vector3DBase(-z, -x, +y)); vec.Add(new Vector3DBase(-z, +x, -y)); vec.Add(new Vector3DBase(+z, -x, -y)); vec.Add(new Vector3DBase(+y, +z, +x)); vec.Add(new Vector3DBase(-y, -z, +x)); vec.Add(new Vector3DBase(-y, +z, -x)); vec.Add(new Vector3DBase(+y, -z, -x)); vec.Add(new Vector3DBase(-x, -y, -z)); vec.Add(new Vector3DBase(+x, +y, -z)); vec.Add(new Vector3DBase(+x, -y, +z)); vec.Add(new Vector3DBase(-x, +y, +z)); vec.Add(new Vector3DBase(-z, -x, -y)); vec.Add(new Vector3DBase(+z, +x, -y)); vec.Add(new Vector3DBase(+z, -x, +y)); vec.Add(new Vector3DBase(-z, +x, +y)); vec.Add(new Vector3DBase(-y, -z, -x)); vec.Add(new Vector3DBase(+y, +z, -x)); vec.Add(new Vector3DBase(+y, -z, +x)); vec.Add(new Vector3DBase(-y, +z, +x)); break; case 11: //m3m vec.Add(new Vector3DBase(+x, +y, +z)); vec.Add(new Vector3DBase(-x, -y, +z)); vec.Add(new Vector3DBase(-x, +y, -z)); vec.Add(new Vector3DBase(+x, -y, -z)); vec.Add(new Vector3DBase(+z, +x, +y)); vec.Add(new Vector3DBase(-z, -x, +y)); vec.Add(new Vector3DBase(-z, +x, -y)); vec.Add(new Vector3DBase(+z, -x, -y)); vec.Add(new Vector3DBase(+y, +z, +x)); vec.Add(new Vector3DBase(-y, -z, +x)); vec.Add(new Vector3DBase(-y, +z, -x)); vec.Add(new Vector3DBase(+y, -z, -x)); vec.Add(new Vector3DBase(-x, -y, -z)); vec.Add(new Vector3DBase(+x, +y, -z)); vec.Add(new Vector3DBase(+x, -y, +z)); vec.Add(new Vector3DBase(-x, +y, +z)); vec.Add(new Vector3DBase(-z, -x, -y)); vec.Add(new Vector3DBase(+z, +x, -y)); vec.Add(new Vector3DBase(+z, -x, +y)); vec.Add(new Vector3DBase(-z, +x, +y)); vec.Add(new Vector3DBase(-y, -z, -x)); vec.Add(new Vector3DBase(+y, +z, -x)); vec.Add(new Vector3DBase(+y, -z, +x)); vec.Add(new Vector3DBase(-y, +z, +x)); vec.Add(new Vector3DBase(+y, +x, +z)); vec.Add(new Vector3DBase(-y, -x, +z)); vec.Add(new Vector3DBase(-y, +x, -z)); vec.Add(new Vector3DBase(+y, -x, -z)); vec.Add(new Vector3DBase(+z, +y, +x)); vec.Add(new Vector3DBase(-z, -y, +x)); vec.Add(new Vector3DBase(-z, +y, -x)); vec.Add(new Vector3DBase(+z, -y, -x)); vec.Add(new Vector3DBase(+x, +z, +y)); vec.Add(new Vector3DBase(-x, -z, +y)); vec.Add(new Vector3DBase(-x, +z, -y)); vec.Add(new Vector3DBase(+x, -z, -y)); vec.Add(new Vector3DBase(-y, -x, -z)); vec.Add(new Vector3DBase(+y, +x, -z)); vec.Add(new Vector3DBase(+y, -x, +z)); vec.Add(new Vector3DBase(-y, +x, +z)); vec.Add(new Vector3DBase(-z, -y, -x)); vec.Add(new Vector3DBase(+z, +y, -x)); vec.Add(new Vector3DBase(+z, -y, +x)); vec.Add(new Vector3DBase(-z, +y, +x)); vec.Add(new Vector3DBase(-x, -z, -y)); vec.Add(new Vector3DBase(+x, +z, -y)); vec.Add(new Vector3DBase(+x, -z, +y)); vec.Add(new Vector3DBase(-x, +z, +y)); break; } return(vec.ToArray()); }
public double[][] generateDensityArrayNormal(double angleResolution) { if (crystal == null || crystal.Crystallites == null) { return(null); } int x = (int)numericUpDown1.Value, y = (int)numericUpDown2.Value, z = (int)numericUpDown3.Value; //double[][] pixelsを初期化 int radialDivision = (int)(Math.PI / angleResolution / 2); double[][] pixels = new double[radialDivision][]; for (int i = 0; i < radialDivision; i++) { double circumference = (i + 0.5) / radialDivision * Math.PI * 2; int sectorDivision = (int)Math.Round(circumference * radialDivision, MidpointRounding.ToEven); pixels[i] = new double[sectorDivision]; for (int j = 0; j < pixels[i].Length; j++) { pixels[i][j] = 0; } } //前回の条件と同じとき if (index != null && index.Length == Crystal.Crystallites.Rotations.Length) { if (x == justBeforeX && y == justBeforeY && z == justBeforeZ && angleResolution == justBeforeResolution && crystal.Crystallites.Rotations.Length == justBeforeCrystallineNumber && justBeforePoleFigureMode == radioButtonPoleFigure.Checked && justBeforePlanesMode == radioButtonPlanes.Checked) { for (int i = 0; i < crystal.Crystallites.Rotations.Length; i++) { foreach (int p in index[i]) { pixels[p / ushort.MaxValue][p % ushort.MaxValue] += crystal.Crystallites.Density[i] * crystal.Crystallites.SolidAngle[i]; } } for (int radial = 0; radial < pixels.Length; radial++) { double area = (1.0 + 2 * radial) / pixels[radial].Length; for (int sector = 0; sector < pixels[radial].Length; sector++) { pixels[radial][sector] /= 10000 * area; } } return(pixels); } } else { index = new uint[Crystal.Crystallites.Rotations.Length][]; } justBeforeX = x; justBeforeY = y; justBeforeZ = z; justBeforeCrystallineNumber = crystal.Crystallites.Rotations.Length; justBeforeResolution = angleResolution; justBeforePoleFigureMode = radioButtonPoleFigure.Checked; justBeforePlanesMode = radioButtonPlanes.Checked; Symmetry sym = crystal.Symmetry; Vector3DBase[] srcVector; //Normal if (radioButtonPoleFigure.Checked) { if (radioButtonPlanes.Checked) {//計算する面指数と等価な指数を算出 var indices = SymmetryStatic.GenerateEquivalentPlanes(x, y, z, sym); srcVector = new Vector3DBase[indices.Length]; for (int k = 0; k < indices.Length; k++) { srcVector[k] = crystal.A_Star * indices[k].H + crystal.B_Star * indices[k].K + crystal.C_Star * indices[k].L; if (srcVector[k].Length2 > 0) { srcVector[k] /= srcVector[k].Length; } } } else {//計算する軸指数と等価な指数を算出 var indices = SymmetryStatic.GenerateEquivalentAxes(x, y, z, sym); //indices = new AxisIndex[] { new AxisIndex(0, 0, 1) }; srcVector = new Vector3DBase[indices.Length]; for (int k = 0; k < indices.Length; k++) { srcVector[k] = crystal.A_Axis * indices[k].U + crystal.B_Axis * indices[k].V + crystal.C_Axis * indices[k].W; if (srcVector[k].Length2 > 0) { srcVector[k] /= srcVector[k].Length; } } } } //Inverse else { srcVector = new Vector3DBase[] { new Vector3DBase(x, y, z) }; if (srcVector[0].Length2 > 0) { srcVector[0] /= srcVector[0].Length; } } List <uint> tempIndex = new List <uint>(); for (int i = 0; i < crystal.Crystallites.Rotations.Length; i++) { tempIndex.Clear(); Matrix3D rot = crystal.Crystallites.Rotations[i] * Crystallite.TiltMatrix; Vector3DBase[] vectors = new Vector3DBase[srcVector.Length]; if (radioButtonPoleFigure.Checked)//PoleFigureのとき { for (int j = 0; j < vectors.Length; j++) { vectors[j] = rot * srcVector[j]; } } else//InversePoleFigureのとき { vectors = divideVector(rot.Transpose() * srcVector[0], sym); } foreach (Vector3DBase v in vectors) { if (v.Z > 0) { PointD pt = new PointD(v.X / Math.Sqrt(1 + v.Z), v.Y / Math.Sqrt(1 + v.Z)); int radial = (int)Math.Round(pt.Length * radialDivision - 0.5, MidpointRounding.ToEven); if (radial < pixels.Length) { int sector = (int)Math.Round(Math.Atan2(pt.Y, pt.X) / 2 / Math.PI * pixels[radial].Length, MidpointRounding.ToEven); if (sector < 0) { sector += pixels[radial].Length; } //lock (lockObject) pixels[radial][sector] += crystal.Crystallites.Density[i] * crystal.Crystallites.SolidAngle[i]; tempIndex.Add((uint)(radial * ushort.MaxValue + sector)); } } } index[i] = tempIndex.ToArray(); } //最後に面積を計算して規格化 for (int radial = 0; radial < pixels.Length; radial++) { double area = (1.0 + 2 * radial) / pixels[radial].Length; for (int sector = 0; sector < pixels[radial].Length; sector++) { pixels[radial][sector] /= 10000 * area; } } return(pixels); }
/// <summary> /// v1をなるべくv2に近づけるような回転行列を求める。戻り値は、残差の二乗和を個数で割ったもの /// </summary> /// <param name="v1"></param> /// <param name="v2"></param> /// <param name="result"></param> /// <returns></returns> public static double GetRotationMatrix(Vector3DBase[] v1, Vector3DBase[] v2, ref Matrix3D result, Matrix3D initialRotation = null) { if (initialRotation == null) { //初期回転行列を求める initialRotation = new Matrix3D(); } var euler = Euler.GetEulerAngle(initialRotation); int length = v1.Length; double phi = euler.Phi, theta = euler.Theta, psi = euler.Psi; double phi_New, theta_New, psi_New; Matrix3D rot = initialRotation, rot_New; Vector3DBase[,] diff = new Vector3DBase[3, length]; var Alpha = new DMat(3, 3); var Beta = new DMat(3, 1); Vector3DBase[] ResidualCurrent = new Vector3DBase[length]; Vector3DBase[] ResidualNew = new Vector3DBase[length]; double ResidualSquareCurrent, ResidualSquareNew = 0; int count = 0; //現在の残差を計算 ResidualSquareCurrent = 0; for (int i = 0; i < length; i++) { ResidualCurrent[i] = rot * v1[i] - v2[i]; ResidualSquareCurrent += ResidualCurrent[i] * ResidualCurrent[i]; } double lambda = 1; while (lambda < 1000000000 && count < 3000)//lambdaが大きくなりすぎた時か、試行回数が一定以上になった時、止める { count++; double cosPhi = Math.Cos(phi), sinPhi = Math.Sin(phi), cosTheta = Math.Cos(theta), sinTheta = Math.Sin(theta), cosPsi = Math.Cos(psi), sinPsi = Math.Sin(psi); for (int i = 0; i < length; i++)//偏微分を作る 「回転行列の偏微分」というMathematicaファイルを参照 { //∂F/∂phi diff[0, i] = new Vector3DBase( v1[i].X * (-cosPsi * sinPhi - cosPhi * cosTheta * sinPsi) + v1[i].Y * (cosPhi * cosPsi * cosTheta - sinPhi * sinPsi) + v1[i].Z * cosPhi * sinTheta, v1[i].Y * (-cosPsi * cosTheta * sinPhi - cosPhi * sinPsi) + v1[i].X * (-cosPhi * cosPsi + cosTheta * sinPhi * sinPsi) - v1[i].Z * sinPhi * sinTheta, 0 ); //∂F/∂theta diff[1, i] = new Vector3DBase( v1[i].Z * cosTheta * sinPhi - v1[i].Y * cosPsi * sinPhi * sinTheta + v1[i].X * sinPhi * sinPsi * sinTheta, v1[i].Z * cosPhi * cosTheta - v1[i].Y * cosPhi * cosPsi * sinTheta + v1[i].X * cosPhi * sinPsi * sinTheta, -v1[i].Y * cosPsi * cosTheta + v1[i].X * cosTheta * sinPsi - v1[i].Z * sinTheta ); //∂F/∂psi diff[2, i] = new Vector3DBase( v1[i].X * (-cosPsi * cosTheta * sinPhi - cosPhi * sinPsi) + v1[i].Y * (cosPhi * cosPsi - cosTheta * sinPhi * sinPsi), v1[i].Y * (-cosPsi * sinPhi - cosPhi * cosTheta * sinPsi) + v1[i].X * (-cosPhi * cosPsi * cosTheta + sinPhi * sinPsi), v1[i].X * cosPsi * sinTheta + v1[i].Y * sinPsi * sinTheta ); } //行列Alpha, Betaを作る for (int k = 0; k < 3; k++) { for (int l = 0; l < 3; l++) { Alpha[k, l] = 0; for (int i = 0; i < length; i++) { Alpha[k, l] += diff[k, i] * diff[l, i]; } if (k == l) { Alpha[k, l] *= (1 + lambda); } } Beta[k, 0] = 0; for (int i = 0; i < length; i++) { Beta[k, 0] += ResidualCurrent[i] * diff[k, i]; } } if (!Alpha.TryInverse(out Matrix alphaInv)) { return(-1); } var delta = alphaInv * Beta; phi_New = phi - delta[0, 0]; theta_New = theta - delta[1, 0]; psi_New = psi + delta[2, 0]; //あたらしいパラメータでの残差の二乗和を計算 ResidualSquareNew = 0; rot_New = Euler.SetEulerAngle(phi_New, theta_New, psi_New); for (int i = 0; i < length; i++) { ResidualNew[i] = rot_New * v1[i] - v2[i]; ResidualSquareNew += ResidualNew[i] * ResidualNew[i]; } if (ResidualSquareCurrent > ResidualSquareNew) //新旧の残差の二乗和を比較 { //改善したとき if ((ResidualSquareCurrent - ResidualSquareNew) / ResidualSquareCurrent > 0.0000000001 || count < 15 || lambda > 1) { //改善率が0.0000000001 以上 (まだまだ改善の余地がある)、あるいはcountが15以下 (回数が少ない)、あるいはlambdaが1より大きいとき (まだまだ改善の余地がある) ResidualSquareCurrent = ResidualSquareNew; //残差の二乗和を書き換える lambda *= 0.4; //lambdaを小さくする for (int i = 0; i < length; i++) { ResidualCurrent[i] = ResidualNew[i]; //残差行列を書き換える } phi = phi_New; theta = theta_New; psi = psi_New; //新旧パラメータを書き換える } else { break; } } else//改善しなかったとき { lambda *= 2.5;//lambdaを大きくする } } return(ResidualSquareCurrent); }