// (0.2.0) /// <summary> /// 指定したディレクトリのparaファイルを読み込み,Scanparameterオブジェクトを生成します. /// </summary> /// <param name="directory"></param> /// <returns></returns> public static async Task <ScanParameter> GenerateAsync(string directory) { var parameter = new ScanParameter(); await parameter.LoadFromAsync(directory); return(parameter); }
public static ScanParameter Generate(string directory) { var parameter = new ScanParameter(); parameter.LoadFrom(directory); return(parameter); }
private async Task OutputFittedCsv(StreamWriter writer, ScanParameter originalParameter, EqualIntervalData targetData, FittingProfile.FittingResult result, bool outputConvolution) { for (int k = 0; k < originalParameter.PointsCount; k++) { List <string> cols = new List <string>(); // 0列: エネルギー値 cols.Add((originalParameter.Start + k * originalParameter.Step + result.Shift).ToString("f2")); // 1列: 測定データ cols.Add(targetData[k].ToString("f3")); // 2~N列: 各成分(標準データ×ゲイン) decimal conv = 0; for (int j = 0; j < result.Standards.Count; j++) { var intensity = result.GetGainedStandard(j, k); conv += intensity; cols.Add(intensity.ToString("f3")); } // 最終列: 成分の総和 if (outputConvolution) { cols.Add(conv.ToString("f3")); } await writer.WriteLineAsync(string.Join(",", cols)); } }
// とりあえず. public void LoadFrom(string directory) { // パラメータを読み込む。 _scanParameter = ScanParameter.Generate(directory); // データを読み込む。 using (var reader = new BinaryReader(new FileStream(Path.Combine(directory, "data"), FileMode.Open, FileAccess.Read))) { _data = EqualIntervalData.Generate(reader); } }
/// <summary> /// 与えられたパラメータによりシフトされたデータ列を返します. /// </summary> /// <param name="parameter">エネルギー軸の範囲の情報だけを用いています.</param> /// <param name="m"></param> /// <returns></returns> public async Task <IList <decimal> > GetDataAsync(ScanParameter parameter, int m, decimal shift = 0, decimal gain = 1) { if (m <= 0) { throw new ArgumentException("mには正の値を与えて下さい."); } var ws = await WideScan.GenerateAsync(this.DirectoryName); return(ws.Differentiate(m) .GetInterpolatedData(parameter.Start - shift, parameter.Step, parameter.PointsCount) .Select(d => d * ws.Parameter.NormalizationGain / parameter.NormalizationGain * gain).ToList()); }
public async Task LoadFromAsync(string directory) { // パラメータを読み込む。 _scanParameter = await ScanParameter.GenerateAsync(directory); // データを読み込む。 using (var reader = new BinaryReader(new FileStream(Path.Combine(directory, "data"), FileMode.Open, FileAccess.Read))) { _data = await EqualIntervalData.GenerateAsync(reader); } //Loaded(this, EventArgs.Empty); }
public async Task LoadFromAsync(string directory) { using (var reader = new StreamReader(new FileStream(Path.Combine(directory, "para"), FileMode.Open, FileAccess.Read))) { while (reader.Peek() > -1) { var line = await reader.ReadLineAsync(); var cols = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); if (cols.Count() > 1) { switch (cols[0]) { case "$AP_SPC_WSTART": Start = Convert.ToDecimal(cols[1]); break; case "$AP_SPC_WSTOP": Stop = Convert.ToDecimal(cols[1]); break; case "$AP_SPC_WSTEP": Step = Convert.ToDecimal(cols[1]); break; // とりあえず無視する。 //case "$AP_SPC_WPOINTS": // _scanParameter.noPoints = Convert.ToInt32(cols[1]); // break; // 正規化に関しては、とりあえず電流とdwellだけ考慮する。Tiltや加速電圧はあとで考える。 case "$AP_PCURRENT": Current = ScanParameter.ConvertPressure(cols[1]); break; case "$AP_SPC_WDWELL": Dwell = Convert.ToDecimal(cols[1]) * 1e-3M; break; case "$AP_SPC_W_XSHIFT": XShift = Convert.ToDecimal(cols[1]); break; case "$AP_STGTILT": Tilt = Convert.ToDouble(cols[1]); break; } } } } }
// (0.1.0)メソッド名をFitからOutputに変更.というか,これどこにおけばいいのかな? private async Task <Gnuplot> Output( ScanParameter originalParameter, FittingProfile profile, EqualIntervalData target_data, FittingProfile.FittingResult result) { // フィッティングした結果をチャートにする? // ★とりあえずFixedなデータは表示しない。 bool output_convolution = result.Standards.Count > 1; // それには、csvを出力する必要がある。 //string fitted_csv_path = Path.Combine(FittingCondition.OutputDestination, $"{FittingCondition.Name}_{layer}.csv"); using (var csv_writer = new StreamWriter(GetCsvFileName(profile.Name))) { await OutputFittedCsv(csv_writer, originalParameter, target_data, result, output_convolution).ConfigureAwait(false); } // チャート出力の準備? return(ConfigureChart(result, profile, output_convolution)); }
// (0.1.0)メソッド名をFitからOutputに変更.というか,これどこにおけばいいのかな? #region *CSVを出力して,グラフ描画の準備を行う(Output) /// <summary> /// フィッティングした結果から,チャートの出力を設定します. /// </summary> /// <param name="cycle"></param> /// <param name="originalParameter"></param> /// <param name="profile"></param> /// <param name="target_data"></param> /// <param name="result"></param> /// <returns></returns> private async Task <Gnuplot> Output( int cycle, ScanParameter originalParameter, FittingProfile profile, EqualIntervalData target_data, FittingProfile.FittingResult result) { // フィッティングした結果をチャートにする? // ★とりあえずFixedなデータは表示しない。 Trace.WriteLine($"Let's start outputting! cycle{cycle} {DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}]"); bool output_convolution = result.Standards.Count > 1; // それには、csvを出力する必要がある。 using (var csv_writer = new StreamWriter(GetCsvFileName(cycle, profile.Name))) { await OutputFittedCsv(csv_writer, originalParameter, target_data, result, output_convolution); } Trace.WriteLine($"CSV output Completed! cycle{cycle} {DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}]"); // チャート出力の準備? return(ConfigureChart(result, profile, output_convolution, cycle)); #region こうすると,1024バイトほど書き込んだところで落ちる. // どう違うのかはよくわかっていない. /* * Gnuplot chartConfiguration; * // chartConfigurationを構成して返す処理とcsv出力処理が入り交じっているので注意.(こういう書き方しか思いつかなかった.) * using (var csv_writer = new StreamWriter(GetCsvFileName(cycle, profile.Name))) * { * //var outputCsvTask = OutputFittedCsv(csv_writer, originalParameter, target_data, result, output_convolution); * //chartConfiguration = ConfigureChart(cycle, result, profile, output_convolution); * //await outputCsvTask; * await OutputFittedCsv(csv_writer, originalParameter, target_data, result, output_convolution); * } * return chartConfiguration; */ #endregion }
// (0.3.0)Tiltを考慮. #region *パラメータを読み込む(ReadParaPeakAsync) /// <summary> /// para.peakファイルを読み込みます。 /// </summary> /// <param name="directory"></param> /// <returns></returns> protected async Task <ROISpectra[]> ReadParaPeakAsync(string directory) { // $AP_DEP_ROI_NOFEXE 6 /* * $AP_DEP_ROI_EXEMOD 1 1 * $AP_DEP_ROI_NAME 1 Ti * $AP_DEP_ROI_START 1 404.00 * $AP_DEP_ROI_STOP 1 431.00 * $AP_DEP_ROI_STEP 1 0.50 * $AP_DEP_ROI_POINTS 1 55 * $AP_DEP_ROI_DWELL 1 200 * $AP_DEP_ROI_SWEEPS 1 5 * $AP_DEP_ROI_ACQRSF 1 0.414 */ //ROIParameters[0] = new ROIParameter(); ROISpectra[] roi_spectra = null; decimal? current = null; double? tilt = null; using (var reader = new StreamReader(new FileStream(Path.Combine(directory, "para"), FileMode.Open, FileAccess.Read))) { while (reader.Peek() > -1) { var line = await reader.ReadLineAsync(); var cols = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); if (cols.Count() > 1) { switch (cols[0]) { case "$AP_DEP_CYCLES": Cycles = Convert.ToInt32(cols[1]); break; case "$AP_PCURRENT": current = ScanParameter.ConvertPressure(cols[1], cols[2]); break; case "$AP_STGTILT": tilt = Convert.ToDouble(cols[1]); break; case "$AP_DEP_ROI_NOFEXE": int count = Convert.ToInt32(cols[1]); roi_spectra = new ROISpectra[count]; for (int i = 0; i < count; i++) { // ここで各要素を初期化しておく。 roi_spectra[i] = new ROISpectra(); } break; //goto SCAN_ROI; // switch内でループから脱出するための黒魔術。 } } } } if (roi_spectra == null) { throw new Exception("para.peakファイルに $AP_DEP_ROI_NOFEXEキーがありませんでした。"); } // roi_parametersが初期化されていることを保証するために、ループを2つに分ける。 //SCAN_ROI: int ch; using (var reader = new StreamReader(new FileStream(Path.Combine(directory, "para.peak"), FileMode.Open, FileAccess.Read))) { while (reader.Peek() > -1) { var line = reader.ReadLine(); var cols = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); if (cols.Count() > 1) { switch (cols[0]) { case "$AP_DEP_ROI_NAME": ch = Convert.ToInt32(cols[1]) - 1; roi_spectra[ch].Name = cols[2]; break; case "$AP_DEP_ROI_START": ch = Convert.ToInt32(cols[1]) - 1; roi_spectra[ch].Parameter.Start = Convert.ToDecimal(cols[2]); break; case "$AP_DEP_ROI_STOP": ch = Convert.ToInt32(cols[1]) - 1; roi_spectra[ch].Parameter.Stop = Convert.ToDecimal(cols[2]); break; case "$AP_DEP_ROI_STEP": ch = Convert.ToInt32(cols[1]) - 1; roi_spectra[ch].Parameter.Step = Convert.ToDecimal(cols[2]); break; //case "$AP_DEP_ROI_POINTS": // ch = Convert.ToInt32(cols[1]) - 1; // ROIParameters[ch].noPoints = Convert.ToInt32(cols[2]); // break; case "$AP_DEP_ROI_DWELL": ch = Convert.ToInt32(cols[1]) - 1; roi_spectra[ch].Parameter.Dwell = Convert.ToInt32(cols[2]) * 1e-3M; // ここでcurrentを設定する。 roi_spectra[ch].Parameter.Current = current.Value; // HasValueでないことは想定していない。 // ※AP_STGTILTがAP_DEP_ROI_NOFEXEより後に出てくるので,ここでは値が設定されていない! roi_spectra[ch].Parameter.Tilt = tilt.Value; // HasValueでないことは想定していない。 break; } } } } return(roi_spectra); }
/// <summary> /// シフトを考慮した固定参照データを読み込みます. /// </summary> /// <param name="references"></param> /// <param name="parameter"></param> /// <returns></returns> static async Task <List <List <decimal> > > LoadShiftedFixedStandardsData(ICollection <FixedSpectrum> references, ScanParameter parameter) { List <List <decimal> > standards = new List <List <decimal> >(); foreach (var item in references) { var ws = await WideScan.GenerateAsync(item.DirectoryName); standards.Add( ws.Differentiate(3) .GetInterpolatedData(parameter.Start - item.Shift, parameter.Step, parameter.PointsCount) .Select(d => d * ws.Parameter.NormalizationGain / parameter.NormalizationGain * item.Gain).ToList() ); } return(standards); }
FitForOneShiftResult DecideShift(EqualIntervalData targetData, ScanParameter originalParameter) { var gains = new Dictionary <decimal, Vector <double> >(); Dictionary <decimal, decimal> residuals = new Dictionary <decimal, decimal>(); var best_fit_result = new FitForOneShiftResult(); List <decimal> shiftList = new List <decimal>(); // 1回目 for (int m = -6; m < 7; m++) { shiftList.Add(0.5M * m); // とりあえず。 } Trace.WriteLine($"SearchShift START!! {DateTime.Now:O} [{Thread.CurrentThread.ManagedThreadId}]"); best_fit_result = SearchBestShift(shiftList, best_fit_result); var best_shift = best_fit_result.Shift; Trace.WriteLine($"SearchShift Completed!! {DateTime.Now:O} [{Thread.CurrentThread.ManagedThreadId}]"); Trace.WriteLine($"シフト値は {best_shift} がよさそうだよ!"); // 2回目 shiftList.Clear(); for (int i = 1; i < 5; i++) { shiftList.Add(best_shift + 0.1M * i); shiftList.Add(best_shift - 0.1M * i); } return(SearchBestShift(shiftList, best_fit_result)); #region ローカル関数 #region **与えられたシフト量から最適なものを探す(SearchBestShift) FitForOneShiftResult SearchBestShift( IEnumerable <decimal> shiftCandidates, FitForOneShiftResult previousResult) { var best_result = previousResult; // ※たぶん,メンバ変数にする必要がある. var _cancellation_token = new CancellationToken(); object lockObject = new object(); var loopResult = Parallel.ForEach <decimal, FitForOneShiftResult>( shiftCandidates, new ParallelOptions { CancellationToken = _cancellation_token }, () => best_result, (shift, state, best) => { return(FitForOneShift(shift)); }, (result) => { lock (lockObject) { if (!best_result.Residual.HasValue || best_result.Residual.Value > result.Residual.Value) { best_result = result; } } } ); return(best_result); #region ローカル関数 #region ***1つのシフト量に対してフィッティングを行う(FitForOneShift) // とりあえず同期版を使う. // IO待ちのメソッドではないので,asyncにしない方がよい? FitForOneShiftResult FitForOneShift(decimal shift) { Trace.WriteLine($"shift : {shift} {DateTime.Now:O} [{Thread.CurrentThread.ManagedThreadId}]"); var shifted_parameter = originalParameter.GetShiftedParameter(shift); // ここを非同期にすると,制御が返らなくなる? // シフトされた参照スペクトルを読み込む。 var standards = LoadShiftedStandardsData(ReferenceSpectra, shifted_parameter); // フィッティングを行い、 //Trace.WriteLine($"Cycle {cycle}"); var gain = GetOptimizedGains(WithOffset, targetData, standards.ToArray()); //gains.Add(shift, ); for (int j = 0; j < ReferenceSpectra.Count; j++) { Trace.WriteLine($" {ReferenceSpectra[j].Name} : {gain[j]} [{Thread.CurrentThread.ManagedThreadId}]"); } Trace.WriteLine($" Const : {gain[ReferenceSpectra.Count]} [{Thread.CurrentThread.ManagedThreadId}]"); // 残差を取得する。 var residual = EqualIntervalData.GetTotalSquareResidual(targetData, gain.ToArray(), standards.ToArray()); // 残差2乗和 //residuals.Add(shift, residual); Trace.WriteLine($"residual = {residual} [{Thread.CurrentThread.ManagedThreadId}]"); return(new FitForOneShiftResult { Gain = gain, Shift = shift, Residual = residual }); } #endregion #endregion } #endregion #endregion }
/// <summary> /// /// </summary> /// <param name="cycle">対象サイクル.デバッグ出力にしか使用していません.</param> /// <param name="data"></param> /// <param name="originalParameter"></param> /// <returns></returns> //public async Task<FittingResult> FitOneCycle(int cycle, EqualIntervalData data, ScanParameter originalParameter) public FittingResult FitOneCycle(int cycle, EqualIntervalData data, ScanParameter originalParameter) { #region 固定参照スペクトルを取得する。(一時的にコメントアウト中) /* * List<decimal> fixed_data = new List<decimal>(); * if (FixedSpectra.Count > 0) * { * var v_data = await FixedSpectra.ForEachAsync( * async sp => await sp.GetShiftedDataAsync(d_data.Parameter, 3), 10); * * for (int j = 0; j < v_data.First().Count; j++) * { * fixed_data.Add(v_data.Sum(one => one[j])); * } * } */ #endregion /// フィッティング対象となるデータ。すなわち、もとのデータからFixされた分を差し引いたデータ。 //var target_data = fixed_data.Count > 0 ? data.Substract(fixed_data) : data; // なんだけど、とりあえずはFixedを考慮しない。 var target_data = data; if (!FixEnergyShift) { #region A.最適なエネルギーシフト量を見つける場合 Trace.WriteLine($"Cycle {cycle} START!! {DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}]"); var best_fitting_result = DecideShift(target_data, originalParameter); var best_shift = best_fitting_result.Shift; Trace.WriteLine($" {cycle} 本当に最適なシフト値は {best_shift} だよ!"); Trace.WriteLine($"Cycle {cycle} END!! {DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}]"); // シフトされた参照スペクトルを読み込む。 var best_shifted_parameter = originalParameter.GetShiftedParameter(best_shift); //var best_standards = LoadShiftedStandardsDataAsync(ReferenceSpectra, best_shifted_parameter); var best_standards = LoadShiftedStandardsData(ReferenceSpectra, best_shifted_parameter); var best_gain = best_fitting_result.Gain; return(new FittingResult { Shift = best_shift, Gains = best_gain.Select(d => Convert.ToDecimal(d)).ToArray(), Standards = best_standards }); #endregion } else { #region B.エネルギーシフト量を自分で与える場合 var shifted_parameter = originalParameter.GetShiftedParameter(FixedEnergyShift); // シフトされた参照スペクトルを読み込む。 var standards = LoadShiftedStandardsData(ReferenceSpectra, shifted_parameter); // フィッティングを行い、 Trace.WriteLine($"Cycle {cycle}"); var gains = GetOptimizedGains(WithOffset, target_data, standards.ToArray()); for (int j = 0; j < ReferenceSpectra.Count; j++) { Trace.WriteLine($" {ReferenceSpectra[j].Name} : {gains[j]}"); } Trace.WriteLine($" Const : {gains[ReferenceSpectra.Count]}"); return(new FittingResult { Shift = FixedEnergyShift, Standards = standards, Gains = gains.Select(d => Convert.ToDecimal(d)).ToArray() }); #endregion } // 出力は呼び出し元で行う! }
public ROISpectra() { Parameter = new ScanParameter(); }
/// <summary> /// 与えられたパラメータによりシフトされたデータ列を返します. /// </summary> /// <param name="parameter">エネルギー軸の範囲の情報だけを用いています.</param> /// <param name="m"></param> /// <returns></returns> public async Task <IList <decimal> > GetShiftedDataAsync(ScanParameter parameter, int m) { return(await GetDataAsync(parameter, m, Shift, Gain)); }