File: AlgorithmUpdate.cc

package info (click to toggle)
purify 2.0.0-5
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 58,688 kB
  • sloc: cpp: 8,410; python: 375; makefile: 7
file content (133 lines) | stat: -rw-r--r-- 6,097 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "purify/config.h"
#include "AlgorithmUpdate.h"

namespace purify {

AlgorithmUpdate::AlgorithmUpdate(const purify::Params &params, const utilities::vis_params &uv_data,
                                 sopt::algorithm::ImagingProximalADMM<t_complex> &padmm,
                                 std::ostream &stream, const MeasurementOperator &measurements,
                                 const sopt::LinearTransform<sopt::Vector<sopt::t_complex>> &Psi)
    : params(params), stats(read_params_to_stats(params)), uv_data(uv_data), out_diagnostic(stream),
      padmm(padmm), c_start(std::clock()), Psi(Psi), measurements(measurements){};

bool AlgorithmUpdate::operator()(const Vector<t_complex> &x) {
  std::clock_t c_end = std::clock();
  stats.total_time = (c_end - c_start) / CLOCKS_PER_SEC; // total time for solver to run in seconds
  // Getting things ready for l1 and l2 norm calculation
  Image<t_complex> const image = Image<t_complex>::Map(x.data(), params.height, params.width);
  Vector<t_complex> const y_residual
      = ((uv_data.vis - measurements.degrid(image)).array() * uv_data.weights.array().real());
  stats.l2_norm = y_residual.stableNorm();
  Vector<t_complex> const alpha = Psi.adjoint() * x;
  // updating parameter
  AlgorithmUpdate::modify_gamma(alpha);
  auto new_l1_norm = alpha.lpNorm<1>();
  stats.l1_variation = std::abs(stats.l1_norm - new_l1_norm)/stats.l1_norm;
  stats.l1_norm = new_l1_norm;
  if(params.run_diagnostic) {
    std::string const outfile_fits = params.name + "_solution_" + params.weighting + "_update.fits";
    std::string const outfile_upsample_fits
        = params.name + "_solution_" + params.weighting + "_update_upsample.fits";
    std::string const residual_fits
        = params.name + "_residual_" + params.weighting + "_update.fits";
    std::string const residual_fits_scaled
        = params.name + "_residual_" + params.weighting + "_update_scaled.fits";

    auto const residual = measurements.grid(y_residual);
    AlgorithmUpdate::save_figure(x, outfile_fits, "JY/PIXEL", 1);
    if(params.upsample_ratio != 1)
      AlgorithmUpdate::save_figure(x, outfile_upsample_fits, "JY/PIXEL", params.upsample_ratio);
    AlgorithmUpdate::save_figure(Image<t_complex>::Map(residual.data(), residual.size(), 1),
                                 residual_fits, "JY/BEAM", 1);
    AlgorithmUpdate::save_figure(Image<t_complex>::Map(residual.data(), residual.size(), 1)
                                     / params.psf_norm,
                                 residual_fits_scaled, "JY/BEAM", 1);
    stats.rms
        = utilities::standard_deviation(Image<t_complex>::Map(residual.data(), residual.size(), 1));
    stats.dr = utilities::dynamic_range(image, residual);
    stats.max = residual.matrix().real().maxCoeff();
    stats.min = residual.matrix().real().minCoeff();
    // printing log information to stream
    AlgorithmUpdate::print_to_stream(out_diagnostic);
  }
  AlgorithmUpdate::print_to_stream(std::cout);
  stats.iter++;

  return true;
}

void AlgorithmUpdate::modify_gamma(Vector<t_complex> const &alpha) {
  // modifies gamma value in padmm

  // setting information for updating parameters
  if(params.run_diagnostic or (params.adapt_gamma and params.adapt_iter)) {
    stats.new_purify_gamma = alpha.cwiseAbs().maxCoeff() * params.beta;
    stats.relative_gamma = std::abs(stats.new_purify_gamma - padmm.gamma()) / padmm.gamma();
    std::cout << "Relative variation of step size = " << stats.relative_gamma << '\n';
    std::cout << "Old step size = " << padmm.gamma() << '\n';
    std::cout << "New step size = " << stats.new_purify_gamma << '\n';
  }
  if(stats.iter < params.adapt_iter and stats.relative_gamma > params.relative_gamma_adapt
     and stats.new_purify_gamma > 0 and params.adapt_gamma) {
    padmm.gamma(stats.new_purify_gamma);
  }

  // Information saved for diagnostics
  if(stats.iter == 0) {
    stats.new_purify_gamma = padmm.gamma(); // so that first value on plot is not zero.
  }
}

void AlgorithmUpdate::print_to_stream(std::ostream &stream) {
  if(stats.iter == 0)
    stream
        << "i Gamma RelativeGamma DynamicRange RMS(Res) Max(Res) Min(Res) l1_norm l2_norm l1_variation Time(sec)"
        << std::endl;
  stream << stats.iter << " ";
  stream << stats.new_purify_gamma << " ";
  stream << stats.relative_gamma << " ";
  stream << stats.dr << " ";
  stream << stats.rms << " ";
  stream << stats.max << " ";
  stream << stats.min << " ";
  stream << stats.l1_norm << " ";
  stream << stats.l2_norm << " ";
  stream << stats.l1_variation << " ";
  stream << stats.total_time << " ";
  stream << std::endl;
}

void AlgorithmUpdate::save_figure(const Vector<t_complex> &image,
                                  std::string const &output_file_name, std::string const &units,
                                  t_real const &upsample_ratio) {
  // Saves update images to fits files, with correct headers
  auto header = AlgorithmUpdate::create_header(uv_data, params);
  header.fits_name = output_file_name;
  header.pix_units = units;
  std::printf("Saving %s \n", header.fits_name.c_str());
  header.cell_x /= upsample_ratio;
  header.cell_y /= upsample_ratio;
  Image<t_complex> temp_image = Image<t_complex>::Map(image.data(), params.height, params.width);
  if(upsample_ratio != 1) {
    temp_image = utilities::re_sample_image(temp_image, upsample_ratio);
  }
  pfitsio::write2d_header(temp_image.real(), header);
}

pfitsio::header_params AlgorithmUpdate::create_header(purify::utilities::vis_params const &uv_data,
                                                      purify::Params const &params) {
  // header information
  pfitsio::header_params header;
  header.mean_frequency = uv_data.average_frequency;
  header.ra = uv_data.ra;
  header.dec = uv_data.dec;
  header.cell_x = params.cellsizex;
  header.cell_y = params.cellsizey;
  header.niters = stats.iter;
  header.hasconverged = false;
  header.residual_convergence = params.residual_convergence;
  header.relative_variation = params.relative_variation;
  header.epsilon = params.epsilon;
  return header;
}
}