00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "Timeseries.hh"
00020 #include <algorithm>
00021
00022 Timeseries::Timeseries(IceGrid *g, string name, string dimension_name) {
00023 com = g->com;
00024 rank = g->rank;
00025
00026 dimension.init(dimension_name, dimension_name, com, rank);
00027 var.init(name, dimension_name, com, rank);
00028
00029 short_name = name;
00030 }
00031
00032 Timeseries::Timeseries(MPI_Comm c, PetscMPIInt r, string name, string dimension_name) {
00033 com = c;
00034 rank = r;
00035 dimension.init(dimension_name, dimension_name, com, rank);
00036 var.init(name, dimension_name, com, rank);
00037
00038 short_name = name;
00039 }
00040
00042 PetscErrorCode Timeseries::read(const char filename[]) {
00043 PetscErrorCode ierr;
00044
00045 ierr = dimension.read(filename, time); CHKERRQ(ierr);
00046 bool is_increasing = true;
00047 for (unsigned int j = 1; j < time.size(); ++j) {
00048 if (time[j] - time[j-1] < 1e-16) {
00049 is_increasing = false;
00050 break;
00051 }
00052 }
00053 if (!is_increasing) {
00054 ierr = PetscPrintf(com, "PISM ERROR: dimension '%s' has to be strictly increasing (read from '%s').\n",
00055 dimension.short_name.c_str(), filename);
00056 PetscEnd();
00057 }
00058
00059 ierr = var.read(filename, values); CHKERRQ(ierr);
00060
00061 if (time.size() != values.size()) {
00062 ierr = PetscPrintf(com, "PISM ERROR: variables %s and %s in %s have different numbers of values.\n",
00063 dimension.short_name.c_str(),
00064 var.short_name.c_str(),
00065 filename); CHKERRQ(ierr);
00066 PetscEnd();
00067 }
00068
00069 ierr = var.report_range(values); CHKERRQ(ierr);
00070
00071 return 0;
00072 }
00073
00075 PetscErrorCode Timeseries::write(const char filename[]) {
00076 PetscErrorCode ierr;
00077
00078
00079 ierr = dimension.write(filename, 0, time); CHKERRQ(ierr);
00080 ierr = var.write(filename, 0, values); CHKERRQ(ierr);
00081
00082 return 0;
00083 }
00084
00086
00089 double Timeseries::operator()(double t) {
00090
00091 vector<double>::iterator end = time.end(), j;
00092
00093 j = lower_bound(time.begin(), end, t);
00094
00095 if (j == end)
00096 return values.back();
00097
00098 int i = j - time.begin();
00099
00100 if (i == 0) {
00101 return values[0];
00102 }
00103
00104 double dt = time[i] - time[i - 1];
00105 double dv = values[i] - values[i - 1];
00106
00107 return values[i - 1] + (t - time[i - 1]) / dt * dv;
00108 }
00109
00111
00114 double Timeseries::operator[](unsigned int j) const {
00115
00116 if (j >= values.size()) {
00117 PetscPrintf(com, "ERROR: Timeseries %s: operator[]: invalid argument: size=%d, index=%d\n",
00118 var.short_name.c_str(), values.size(), j);
00119 PetscEnd();
00120 }
00121
00122 return values[j];
00123 }
00124
00126 PetscErrorCode Timeseries::append(double t, double v) {
00127 time.push_back(t);
00128 values.push_back(v);
00129 return 0;
00130 }
00131
00133 PetscErrorCode Timeseries::set_units(string units, string glaciological_units) {
00134 if (!units.empty())
00135 var.set_units(units);
00136 if (!glaciological_units.empty())
00137 var.set_glaciological_units(glaciological_units);
00138 return 0;
00139 }
00140
00142 PetscErrorCode Timeseries::set_dimension_units(string units, string glaciological_units) {
00143 if (!units.empty())
00144 dimension.set_units(units);
00145 if (!glaciological_units.empty())
00146 dimension.set_glaciological_units(glaciological_units);
00147 return 0;
00148 }
00149
00151 PetscErrorCode Timeseries::set_attr(string name, string value) {
00152 var.set_string(name, value);
00153 return 0;
00154 }
00155
00157 PetscErrorCode Timeseries::set_attr(string name, double value) {
00158 var.set(name, value);
00159 return 0;
00160 }
00161
00163
00166 int Timeseries::length() {
00167 return values.size();
00168 }
00169
00170
00171
00172
00173 DiagnosticTimeseries::DiagnosticTimeseries(IceGrid *g, string name, string dimension_name)
00174 : Timeseries(g, name, dimension_name) {
00175
00176 buffer_size = 10000;
00177 start = 0;
00178 }
00179
00180 DiagnosticTimeseries::DiagnosticTimeseries(MPI_Comm c, PetscMPIInt r, string name, string dimension_name)
00181 : Timeseries(c, r, name, dimension_name) {
00182
00183 buffer_size = 10000;
00184 start = 0;
00185 }
00186
00188 DiagnosticTimeseries::~DiagnosticTimeseries() {
00189 flush();
00190 }
00191
00193
00195 PetscErrorCode DiagnosticTimeseries::append(double T, double V) {
00196
00197 t.push_back(T);
00198 v.push_back(V);
00199
00200 if (t.size() == 3) {
00201 t.pop_front();
00202 v.pop_front();
00203 }
00204
00205 return 0;
00206 }
00207
00210 PetscErrorCode DiagnosticTimeseries::interp(double T) {
00211 PetscErrorCode ierr;
00212
00213 if (t.empty()) {
00214 SETERRQ(1, "DiagnosticTimeseries::interp(...): interpolation buffer is empty");
00215 }
00216
00217
00218 if (t.size() == 1) {
00219 if (PetscAbs(T - t[0]) < 1e-8) {
00220 time.push_back(T);
00221 values.push_back(v[0]);
00222 }
00223 return 0;
00224 }
00225
00226 if ((T < t[0]) || (T > t[1])) {
00227 SETERRQ1(1, "DiagnosticTimeseries::interp(...): requested time %f is not within the last time-step!",
00228 T);
00229 }
00230
00231
00232 double tmp = v[0] + (T - t[0]) / (t[1] - t[0]) * (v[1] - v[0]);
00233
00234 time.push_back(T);
00235 values.push_back(tmp);
00236
00237 if (time.size() == buffer_size) {
00238 ierr = flush(); CHKERRQ(ierr);
00239 }
00240
00241 return 0;
00242 }
00243
00245 PetscErrorCode DiagnosticTimeseries::flush() {
00246 PetscErrorCode ierr;
00247 NCTool nc(com, rank);
00248 int len;
00249
00250
00251
00252 if (output_filename.empty())
00253 return 0;
00254
00255
00256
00257
00258 ierr = nc.open_for_reading(output_filename.c_str()); CHKERRQ(ierr);
00259 ierr = nc.get_dim_length(dimension.short_name.c_str(), &len); CHKERRQ(ierr);
00260 ierr = nc.close(); CHKERRQ(ierr);
00261
00262 if (len == (int)start) {
00263 ierr = dimension.write(output_filename.c_str(), start, time); CHKERRQ(ierr);
00264 }
00265 ierr = var.write(output_filename.c_str(), start, values); CHKERRQ(ierr);
00266
00267 start += time.size();
00268 time.clear();
00269 values.clear();
00270
00271 return 0;
00272 }