pktools  2.6.3
Processing Kernel for geospatial data
pkkalman.cc
1 /**********************************************************************
2 pkkalman.cc: produce kalman filtered raster time series
3 Copyright (C) 2008-2014 Pieter Kempeneers
4 
5 This file is part of pktools
6 
7 pktools is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 pktools is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with pktools. If not, see <http://www.gnu.org/licenses/>.
19 ***********************************************************************/
20 #include <sstream>
21 #include <vector>
22 #include <algorithm>
23 #include "base/Optionpk.h"
24 #include "base/Vector2d.h"
25 #include "imageclasses/ImgReaderGdal.h"
26 #include "imageclasses/ImgWriterGdal.h"
27 #include "algorithms/StatFactory.h"
28 #include "algorithms/ImgRegression.h"
29 
30 /******************************************************************************/
76 using namespace std;
77 /*------------------
78  Main procedure
79  ----------------*/
80 int main(int argc,char **argv) {
81  Optionpk<string> direction_opt("dir","direction","direction to run model (forward|backward|smooth)","forward");
82  Optionpk<string> model_opt("mod","model","model input datasets, e.g., MODIS (use: -mod model1 -mod model2 etc.)");
83  Optionpk<string> observation_opt("obs","observation","observation input datasets, e.g., landsat (use: -obs obs1 -obs obs2 etc.)");
84  Optionpk<int> tmodel_opt("tmod","tmodel","time sequence of model input. Sequence must have exact same length as model input. Leave empty to have default sequence 0,1,2,etc.");
85  Optionpk<int> tobservation_opt("tobs","tobservation","time sequence of observation input. Sequence must have exact same length as observation input)");
86  Optionpk<string> projection_opt("a_srs", "a_srs", "Override the projection for the output file (leave blank to copy from input file, use epsg:3035 to use European projection and force to European grid");
87  Optionpk<string> outputfw_opt("ofw", "outputfw", "Output raster dataset for forward model");
88  Optionpk<string> outputbw_opt("obw", "outputbw", "Output raster dataset for backward model");
89  Optionpk<string> outputfb_opt("ofb", "outputfb", "Output raster dataset for smooth model");
90  Optionpk<double> modnodata_opt("modnodata", "modnodata", "invalid value for model input", 0);
91  Optionpk<double> obsnodata_opt("obsnodata", "obsnodata", "invalid value for observation input", 0);
92  Optionpk<double> modoffset_opt("modoffset", "modoffset", "offset used to read model input dataset (value=offset+scale*readValue)");
93  Optionpk<double> obsoffset_opt("obsoffset", "obsoffset", "offset used to read observation input dataset (value=offset+scale*readValue)");
94  Optionpk<double> modscale_opt("modscale", "modscale", "scale used to read model input dataset (value=offset+scale*readValue)");
95  Optionpk<double> obsscale_opt("obsscale", "obsscale", "scale used to read observation input dataset (value=offset+scale*readValue)");
96  Optionpk<double> eps_opt("eps", "eps", "epsilon for non zero division", 0.00001);
97  Optionpk<double> uncertModel_opt("um", "uncertmodel", "Multiply this value with std dev of first model image to obtain uncertainty of model",2);
98  Optionpk<double> uncertObs_opt("uo", "uncertobs", "Uncertainty of valid observations",0);
99  Optionpk<double> weight_opt("w", "weight", "Penalize outliers in measurement via weights. Use first weight to penalize small measurements wrt model and second weight to penalize large measurements wrt model");
100  Optionpk<double> deltaObs_opt("dobs", "deltaobs", "Lower and upper thresholds for relative pixel differences (in percentage): (observation-model)/model. For instance to force the observation within a +/- 10 % interval, use: -dobs -10 -dobs 10 (equivalent to -dobs 10). Leave empty to always update on observation");
101  Optionpk<double> uncertNodata_opt("unodata", "uncertnodata", "Uncertainty in case of no-data values in observation", 10000);
102  Optionpk<double> regTime_opt("rt", "regtime", "Weight for regression in time series", 1.0);
103  Optionpk<double> regSensor_opt("rs", "regsensor", "Weight for regression model - measurement (model - observation).");
104  Optionpk<int> down_opt("down", "down", "Downsampling factor for reading model data to calculate regression");
105  Optionpk<float> threshold_opt("th", "threshold", "threshold for selecting samples (randomly). Provide probability in percentage (>0) or absolute (<0).", 0);
106  Optionpk<int> minreg_opt("minreg", "minreg", "Minimum number of pixels to take into account for regression", 5, 2);
107  // Optionpk<bool> regObs_opt("regobs", "regobs", "Perform regression between modeled and observed value",false);
108  // Optionpk<double> checkDiff_opt("diff", "diff", "Flag observation as invalid if difference with model is above uncertainty",false);
109  Optionpk<unsigned short> window_opt("win", "window", "window size for calculating regression (use 0 for global)", 0);
110  // Optionpk<string> mask_opt("m", "mask", "Use the first band of the specified file as a validity mask. Nodata values can be set with the option msknodata.");
111  // Optionpk<double> msknodata_opt("msknodata", "msknodata", "Mask value(s) not to consider for filtering. First value will be set in output image.", 0);
112 
113  Optionpk<string> oformat_opt("of", "oformat", "Output image format (see also gdal_translate). Empty string: inherit from input image","GTiff",2);
114  Optionpk<string> option_opt("co", "co", "Creation option for output file. Multiple options can be specified.");
115  Optionpk<short> verbose_opt("v", "verbose", "verbose mode when positive", 0);
116 
117  bool doProcess;//stop process when program was invoked with help option (-h --help)
118  try{
119  doProcess=direction_opt.retrieveOption(argc,argv);
120  model_opt.retrieveOption(argc,argv);
121  observation_opt.retrieveOption(argc,argv);
122  tmodel_opt.retrieveOption(argc,argv);
123  tobservation_opt.retrieveOption(argc,argv);
124  projection_opt.retrieveOption(argc,argv);
125  outputfw_opt.retrieveOption(argc,argv);
126  outputbw_opt.retrieveOption(argc,argv);
127  outputfb_opt.retrieveOption(argc,argv);
128  modnodata_opt.retrieveOption(argc,argv);
129  obsnodata_opt.retrieveOption(argc,argv);
130  modoffset_opt.retrieveOption(argc,argv);
131  modscale_opt.retrieveOption(argc,argv);
132  obsoffset_opt.retrieveOption(argc,argv);
133  obsscale_opt.retrieveOption(argc,argv);
134  eps_opt.retrieveOption(argc,argv);
135  uncertModel_opt.retrieveOption(argc,argv);
136  uncertObs_opt.retrieveOption(argc,argv);
137  weight_opt.retrieveOption(argc,argv);
138  deltaObs_opt.retrieveOption(argc,argv);
139  uncertNodata_opt.retrieveOption(argc,argv);
140  regTime_opt.retrieveOption(argc,argv);
141  regSensor_opt.retrieveOption(argc,argv);
142  down_opt.retrieveOption(argc,argv);
143  threshold_opt.retrieveOption(argc,argv);
144  minreg_opt.retrieveOption(argc,argv);
145  // regObs_opt.retrieveOption(argc,argv);
146  // checkDiff_opt.retrieveOption(argc,argv);
147  window_opt.retrieveOption(argc,argv);
148  // mask_opt.retrieveOption(argc,argv);
149  // msknodata_opt.retrieveOption(argc,argv);
150  oformat_opt.retrieveOption(argc,argv);
151  option_opt.retrieveOption(argc,argv);
152  verbose_opt.retrieveOption(argc,argv);
153  }
154  catch(string predefinedString){
155  std::cout << predefinedString << std::endl;
156  exit(0);
157  }
158  if(!doProcess){
159  std::cerr << "short option -h shows basic options only, use long option --help to show all options" << std::endl;
160  exit(0);//help was invoked, stop processing
161  }
162 
163  if(deltaObs_opt.size()==1){
164  if(deltaObs_opt[0]<=0)
165  deltaObs_opt.push_back(-deltaObs_opt[0]);
166  else
167  deltaObs_opt.insert(deltaObs_opt.begin(),-deltaObs_opt[0]);
168  }
169  if(weight_opt.size()==1){
170  weight_opt.push_back(weight_opt[0]);
171  }
172 
173  if(down_opt.empty()){
174  std::cerr << "short option -h shows basic options only, use long option --help to show all options" << std::endl;
175  exit(0);//help was invoked, stop processing
176  }
177  try{
178  ostringstream errorStream;
179  if(model_opt.size()<2){
180  errorStream << "Error: no model dataset selected, use option -mod" << endl;
181  throw(errorStream.str());
182  }
183  if(observation_opt.size()<1){
184  errorStream << "Error: no observation dataset selected, use option -obs" << endl;
185  throw(errorStream.str());
186  }
187  if(direction_opt[0]=="smooth"){
188  if(outputfw_opt.empty()){
189  errorStream << "Error: output forward datasets is not provided, use option -ofw" << endl;
190  throw(errorStream.str());
191  }
192  if(outputbw_opt.empty()){
193  errorStream << "Error: output backward datasets is not provided, use option -obw" << endl;
194  throw(errorStream.str());
195  }
196  if(outputfb_opt.empty()){
197  errorStream << "Error: output smooth datasets is not provided, use option -ofb" << endl;
198  throw(errorStream.str());
199  }
200  }
201  else{
202  if(direction_opt[0]=="forward"&&outputfw_opt.empty()){
203  errorStream << "Error: output forward datasets is not provided, use option -ofw" << endl;
204  throw(errorStream.str());
205  }
206  else if(direction_opt[0]=="backward"&&outputbw_opt.empty()){
207  errorStream << "Error: output backward datasets is not provided, use option -obw" << endl;
208  throw(errorStream.str());
209  }
210 
211  if(model_opt.size()<observation_opt.size()){
212  errorStream << "Error: sequence of models should be larger than observations" << endl;
213  throw(errorStream.str());
214  }
215  if(tmodel_opt.size()!=model_opt.size()){
216  if(tmodel_opt.empty())
217  cout << "Warning: time sequence is not provided, self generating time sequence from 0 to " << model_opt.size() << endl;
218  else
219  cout << "Warning: time sequence provided (" << tmodel_opt.size() << ") does not match number of model raster datasets (" << model_opt.size() << ")" << endl;
220  tmodel_opt.clear();
221  for(int tindex=0;tindex<model_opt.size();++tindex)
222  tmodel_opt.push_back(tindex);
223  }
224  if(tobservation_opt.size()!=observation_opt.size()){
225  errorStream << "Error: time sequence for observation must match size of observation dataset" << endl;
226  throw(errorStream.str());
227  }
228  }
229  }
230  catch(string errorString){
231  std::cout << errorString << std::endl;
232  exit(1);
233  }
234 
236  stat.setNoDataValues(modnodata_opt);
238  // vector<ImgReaderGdal> imgReaderModel(model_opt.size());
239  // vector<ImgReaderGdal> imgReaderObs(observation_opt.size());
240  ImgReaderGdal imgReaderModel1;
241  ImgReaderGdal imgReaderModel2;
242  ImgReaderGdal imgReaderObs;
243  ImgWriterGdal imgWriterEst;
244 
245  imgReaderObs.open(observation_opt[0]);
246 
247  int ncol=imgReaderObs.nrOfCol();
248  int nrow=imgReaderObs.nrOfRow();
249  if(projection_opt.empty())
250  projection_opt.push_back(imgReaderObs.getProjection());
251  double geotransform[6];
252  imgReaderObs.getGeoTransform(geotransform);
253 
254  string imageType=imgReaderObs.getImageType();
255  if(oformat_opt.size())//default
256  imageType=oformat_opt[0];
257  if(option_opt.findSubstring("INTERLEAVE=")==option_opt.end()){
258  string theInterleave="INTERLEAVE=";
259  theInterleave+=imgReaderObs.getInterleave();
260  option_opt.push_back(theInterleave);
261  }
262 
263  if(down_opt.empty()){
264  imgReaderModel1.open(model_opt[0]);
265  double resModel=imgReaderModel1.getDeltaX();
266  double resObs=imgReaderObs.getDeltaX();
267  int down=static_cast<int>(ceil(resModel/resObs));
268  if(!(down%2))
269  down+=1;
270  down_opt.push_back(down);
271  imgReaderModel1.close();
272  }
273  imgReaderObs.close();
274 
275  if(regSensor_opt.empty())
276  regSensor_opt.push_back(1.0/down_opt[0]);
277  //hiero
278  // ImgReaderGdal maskReader;
279  // double colMask=0;
280  // double rowMask=0;
281 
282  // if(mask_opt.size()){
283  // try{
284  // if(verbose_opt[0]>=1)
285  // std::cout << "opening mask image file " << mask_opt[0] << std::endl;
286  // maskReader.open(mask_opt[0]);
287  // maskReader.setNoData(msknodata_opt);
288  // }
289  // catch(string error){
290  // cerr << error << std::endl;
291  // exit(2);
292  // }
293  // catch(...){
294  // cerr << "error catched" << std::endl;
295  // exit(1);
296  // }
297  // }
298 
299  int obsindex=0;
300 
301  const char* pszMessage;
302  void* pProgressArg=NULL;
303  GDALProgressFunc pfnProgress=GDALTermProgress;
304  double progress=0;
305 
306  imgreg.setDown(down_opt[0]);
307  imgreg.setThreshold(threshold_opt[0]);
308 
309  double c0modGlobal=0;//time regression coefficient c0 (offset) calculated on entire image
310  double c1modGlobal=1;//time regression coefficient c1 (scale) calculated on entire image
311  double c0mod=0;//time regression coefficient c0 (offset) calculated on local window
312  double c1mod=1;//time regression coefficient c1 (scale) calculated on local window
313 
314  double c0obs=0;//offset
315  double c1obs=1;//scale
316  double errObs=uncertNodata_opt[0];//start with high initial value in case we do not have first observation at time 0
317 
318  vector<int> relobsindex;
319  // cout << tmodel_opt << endl;
320  // cout << tobservation_opt << endl;
321 
322  for(int tindex=0;tindex<tobservation_opt.size();++tindex){
323  vector<int>::iterator modit;
324  modit=upper_bound(tmodel_opt.begin(),tmodel_opt.end(),tobservation_opt[tindex]);
325  int relpos=modit-tmodel_opt.begin()-1;
326  assert(relpos>=0);//todo: for now, we assume model is available at time before first measurement
327  relobsindex.push_back(relpos);
328  if(verbose_opt[0])
329  cout << "observation " << tindex << ": " << "relative position in model time series is " << relpos << ", date of observation is (tobservation_opt[tindex]): " << tobservation_opt[tindex] << ", relobsindex.back(): " << relobsindex.back() << ", filename observation: " << observation_opt[tindex] << ", filename of corresponding model: " << model_opt[relpos] << endl;
330  // if(verbose_opt[0])
331  // cout << "tobservation_opt[tindex] " << tobservation_opt[tindex] << " " << relobsindex.back() << endl;
332  }
333 
334  int ndigit=log(1.0*tmodel_opt.back())/log(10.0)+1;
335 
336  double geox=0;
337  double geoy=0;
338 
339  if(find(direction_opt.begin(),direction_opt.end(),"forward")!=direction_opt.end()){
341  cout << "Running forward model" << endl;
342  obsindex=0;
343  //initialization
344  string output;
345  if(outputfw_opt.size()==model_opt.size()){
346  output=outputfw_opt[0];
347  }
348  else{
349  ostringstream outputstream;
350  outputstream << outputfw_opt[0] << "_";
351  outputstream << setfill('0') << setw(ndigit) << tmodel_opt[0];
352  outputstream << ".tif";
353  //test
354  // outputstream << outputfw_opt[0] << "_" << tmodel_opt[0] << ".tif";
355  output=outputstream.str();
356  }
357  if(verbose_opt[0])
358  cout << "Opening image " << output << " for writing " << endl;
359 
360  imgWriterEst.open(output,ncol,nrow,2,GDT_Float32,imageType,option_opt);
361  imgWriterEst.setProjectionProj4(projection_opt[0]);
362  imgWriterEst.setGeoTransform(geotransform);
363  imgWriterEst.GDALSetNoDataValue(obsnodata_opt[0]);
364 
365  if(verbose_opt[0]){
366  cout << "processing time " << tmodel_opt[0] << endl;
367  if(obsindex<relobsindex.size())
368  cout << "next observation " << tmodel_opt[relobsindex[obsindex]] << endl;
369  else
370  cout << "There is no next observation" << endl;
371  }
372 
373  try{
374  imgReaderModel1.open(model_opt[0]);
375  imgReaderModel1.setNoData(modnodata_opt);
376  if(modoffset_opt.size())
377  imgReaderModel1.setOffset(modoffset_opt[0]);
378  if(modscale_opt.size())
379  imgReaderModel1.setScale(modscale_opt[0]);
380  }
381  catch(string errorString){
382  cerr << errorString << endl;
383  }
384  catch(...){
385  cerr << "Error opening file " << model_opt[0] << endl;
386  }
387 
388  //calculate standard deviation of image to serve as model uncertainty
389  GDALRasterBand* rasterBand;
390  rasterBand=imgReaderModel1.getRasterBand(0);
391  double minValue, maxValue, meanValue, stdDev;
392  void* pProgressData;
393  rasterBand->ComputeStatistics(0,&minValue,&maxValue,&meanValue,&stdDev,pfnProgress,pProgressData);
394  double modRow=0;
395  double modCol=0;
396  if(relobsindex[0]>0){//initialize output_opt[0] as model[0]
397  //write first model as output
398  if(verbose_opt[0])
399  cout << "write first model as output" << endl;
400  for(int irow=0;irow<nrow;++irow){
401  vector<double> estReadBuffer;
402  vector<double> estWriteBuffer(ncol);
403  vector<double> uncertWriteBuffer(ncol);
404  // vector<double> lineMask;
405  imgWriterEst.image2geo(0,irow,geox,geoy);
406  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
407  if(modRow<0||modRow>=imgReaderModel1.nrOfRow()){
408  cerr << "Error: geo coordinates (" << geox << "," << geoy << ") not covered in model image " << imgReaderModel1.getFileName() << endl;
409  assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow());
410  }
411  try{
412  imgReaderModel1.readData(estReadBuffer,GDT_Float64,modRow);
413  //simple nearest neighbor
414  //stat.nearUp(estReadBuffer,estWriteBuffer);
415 
416  // double oldRowMask=-1;//keep track of row mask to optimize number of line readings
417  for(int icol=0;icol<ncol;++icol){
418  imgWriterEst.image2geo(icol,irow,geox,geoy);
419  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
420  double modValue=estReadBuffer[modCol];
421  if(imgReaderModel1.isNoData(modValue)){
422  estWriteBuffer[icol]=obsnodata_opt[0];
423  uncertWriteBuffer[icol]=uncertNodata_opt[0];
424  }
425  else{
426  //todo: should take into account regression model-obs...
427  estWriteBuffer[icol]=modValue;
428  uncertWriteBuffer[icol]=uncertModel_opt[0]*stdDev;
429  }
430  }
431  imgWriterEst.writeData(estWriteBuffer,GDT_Float64,irow,0);
432  imgWriterEst.writeData(uncertWriteBuffer,GDT_Float64,irow,1);
433  }
434  catch(string errorString){
435  cerr << errorString << endl;
436  }
437  catch(...){
438  cerr << "Error writing file " << imgWriterEst.getFileName() << endl;
439  }
440  }
441  }
442  else{//we have a measurement
443  if(verbose_opt[0])
444  cout << "we have a measurement at initial time" << endl;
445  imgReaderObs.open(observation_opt[0]);
446  imgReaderObs.getGeoTransform(geotransform);
447  imgReaderObs.setNoData(obsnodata_opt);
448  if(obsoffset_opt.size())
449  imgReaderObs.setOffset(obsoffset_opt[0]);
450  if(obsscale_opt.size())
451  imgReaderObs.setScale(obsscale_opt[0]);
452 
453  if(regSensor_opt[0]>0)
454  errObs=regSensor_opt[0]*imgreg.getRMSE(imgReaderModel1,imgReaderObs,c0obs,c1obs,0,0,verbose_opt[0]);
455  else{
456  c0obs=0;
457  c1obs=1;
458  errObs=0;
459  }
460  if(verbose_opt[0])
461  cout << "c0obs, c1obs: " << c0obs << ", " << c1obs << endl;
462 
463  for(int irow=0;irow<nrow;++irow){
464  vector<double> estReadBuffer;
465  imgWriterEst.image2geo(0,irow,geox,geoy);
466  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
467  assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow());
468  imgReaderModel1.readData(estReadBuffer,GDT_Float64,modRow);
469  vector<double> obsLineBuffer;
470  vector<double> estWriteBuffer(ncol);
471  vector<double> uncertWriteBuffer(ncol);
472  vector<double> uncertObsLineBuffer;
473  // vector<double> lineMask;
474  // imgReaderObs.readData(estWriteBuffer,GDT_Float64,irow,0);
475  imgReaderObs.readData(obsLineBuffer,GDT_Float64,irow,0);
476 
477  if(imgReaderObs.nrOfBand()>1)
478  imgReaderObs.readData(uncertObsLineBuffer,GDT_Float64,irow,1);
479  // double oldRowMask=-1;//keep track of row mask to optimize number of line readings
480  for(int icol=0;icol<ncol;++icol){
481  imgWriterEst.image2geo(icol,irow,geox,geoy);
482  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
483  assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow());
484  double modValue=estReadBuffer[modCol];
485  if(imgReaderModel1.isNoData(modValue)){//model is nodata: retain observation
486  estWriteBuffer[icol]=obsLineBuffer[icol];
487  if(imgReaderObs.isNoData(obsLineBuffer[icol])){
488  estWriteBuffer[icol]=obsnodata_opt[0];
489  uncertWriteBuffer[icol]=uncertNodata_opt[0];
490  }
491  else if(uncertObsLineBuffer.size()>icol)
492  uncertWriteBuffer[icol]=uncertObsLineBuffer[icol];
493  else
494  uncertWriteBuffer[icol]=uncertObs_opt[0];
495  }
496  else{//model is valid: calculate estimate from model
497  double errMod=uncertModel_opt[0]*stdDev;
498  errMod*=regTime_opt[0];
499  // double certNorm=(errMod*errMod+errObs*errObs);
500  // double certMod=errObs*errObs/certNorm;
501  // double certObs=errMod*errMod/certNorm;
502  // double regTime=0;
503  // double regSensor=(c0obs+c1obs*modValue)*certMod;
504  // estWriteBuffer[icol]=regTime+regSensor;
505  estWriteBuffer[icol]=modValue;
506  double totalUncertainty=errMod;
507  // if(errMod<eps_opt[0])
508  // totalUncertainty=errObs;
509  // else if(errObs<eps_opt[0])
510  // totalUncertainty=errMod;
511  // else{
512  // totalUncertainty=1.0/errMod/errMod+1/errObs/errObs;
513  // totalUncertainty=sqrt(1.0/totalUncertainty);
514  // }
515  uncertWriteBuffer[icol]=totalUncertainty;//in case observation is not valid
516  }
517  // uncertWriteBuffer[icol]+=uncertReadBuffer[icol];
518  //measurement update
519  if(!imgReaderObs.isNoData(obsLineBuffer[icol])){
520  double kalmanGain=1;
521  double uncertObs=uncertObs_opt[0];
522  if(uncertObsLineBuffer.size()>icol)
523  uncertObs=uncertObsLineBuffer[icol];
524  else if(weight_opt.size()||deltaObs_opt.size()){
525  vector<double> obsWindowBuffer;//buffer for observation to calculate average corresponding to model pixel
526  int minCol=(icol>down_opt[0]/2) ? icol-down_opt[0]/2 : 0;
527  int maxCol=(icol+down_opt[0]/2<imgReaderObs.nrOfCol()) ? icol+down_opt[0]/2 : imgReaderObs.nrOfCol()-1;
528  int minRow=(irow>down_opt[0]/2) ? irow-down_opt[0]/2 : 0;
529  int maxRow=(irow+down_opt[0]/2<imgReaderObs.nrOfRow()) ? irow+down_opt[0]/2 : imgReaderObs.nrOfRow()-1;
530 
531  imgReaderObs.readDataBlock(obsWindowBuffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0);
532  statfactory::StatFactory statobs;
533  statobs.setNoDataValues(obsnodata_opt);
534  double obsMeanValue=(statobs.mean(obsWindowBuffer)-c0obs)/c1obs;
535  double difference=obsMeanValue-modValue;
536  if(modValue){
537  double relativeDifference=difference/modValue;
538  if(deltaObs_opt.size()){
539  assert(deltaObs_opt.size()>1);
540  if(100*relativeDifference<deltaObs_opt[0])//lower bound
541  kalmanGain=0;
542  else if(100*relativeDifference>deltaObs_opt[1])//upper bound
543  kalmanGain=0;
544  }
545  else if(weight_opt.size()){
546  assert(weight_opt.size()>1);
547  if(obsMeanValue<modValue)
548  uncertObs=weight_opt[0]*relativeDifference;
549  else if(obsMeanValue>modValue)
550  uncertObs=weight_opt[1]*relativeDifference;
551  }
552  }
553  if(uncertObs<=0)
554  uncertObs=0;
555  if(verbose_opt[0]>1)
556  cout << "obsMeanValue:" << obsMeanValue << ", modValue: " << modValue << endl;
557  }
558  if(kalmanGain>0){
559  if((uncertWriteBuffer[icol]+uncertObs)>eps_opt[0])
560  kalmanGain=uncertWriteBuffer[icol]/(uncertWriteBuffer[icol]+uncertObs);
561  }
562  assert(kalmanGain<=1);
563  estWriteBuffer[icol]+=kalmanGain*(obsLineBuffer[icol]-estWriteBuffer[icol]);
564  uncertWriteBuffer[icol]*=(1-kalmanGain);
565  }
566  }
567  imgWriterEst.writeData(estWriteBuffer,GDT_Float64,irow,0);
568  imgWriterEst.writeData(uncertWriteBuffer,GDT_Float64,irow,1);
569  }
570  imgReaderObs.close();
571  ++obsindex;
572  }
573  imgReaderModel1.close();
574  imgWriterEst.close();
575 
576  for(int modindex=1;modindex<model_opt.size();++modindex){
577  if(verbose_opt[0]){
578  cout << "processing time " << tmodel_opt[modindex] << endl;
579  if(obsindex<relobsindex.size())
580  cout << "next observation " << tmodel_opt[relobsindex[obsindex]] << endl;
581  else
582  cout << "There is no next observation" << endl;
583  }
584  string output;
585  if(outputfw_opt.size()==model_opt.size())
586  output=outputfw_opt[modindex];
587  else{
588  ostringstream outputstream;
589  outputstream << outputfw_opt[0] << "_";
590  outputstream << setfill('0') << setw(ndigit) << tmodel_opt[modindex];
591  outputstream << ".tif";
592  // outputstream << outputfw_opt[0] << "_" << tmodel_opt[modindex] << ".tif";
593  output=outputstream.str();
594  }
595 
596  //two band output band0=estimation, band1=uncertainty
597  imgWriterEst.open(output,ncol,nrow,2,GDT_Float32,imageType,option_opt);
598  imgWriterEst.setProjectionProj4(projection_opt[0]);
599  imgWriterEst.setGeoTransform(geotransform);
600  imgWriterEst.GDALSetNoDataValue(obsnodata_opt[0]);
601 
602  //calculate regression between two subsequence model inputs
603  imgReaderModel1.open(model_opt[modindex-1]);
604  imgReaderModel1.setNoData(modnodata_opt);
605  if(modoffset_opt.size())
606  imgReaderModel1.setOffset(modoffset_opt[0]);
607  if(modscale_opt.size())
608  imgReaderModel1.setScale(modscale_opt[0]);
609  imgReaderModel2.open(model_opt[modindex]);
610  imgReaderModel2.setNoData(modnodata_opt);
611  if(modoffset_opt.size())
612  imgReaderModel2.setOffset(modoffset_opt[0]);
613  if(modscale_opt.size())
614  imgReaderModel2.setScale(modscale_opt[0]);
615  //calculate regression
616  //we could re-use the points from second image from last run, but
617  //to keep it general, we must redo it (overlap might have changed)
618 
619  pfnProgress(progress,pszMessage,pProgressArg);
620 
621  if(verbose_opt[0])
622  cout << "Calculating regression for " << imgReaderModel1.getFileName() << " " << imgReaderModel2.getFileName() << endl;
623 
624  double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0modGlobal,c1modGlobal,0,0);
625  errMod*=regTime_opt[0];
626 
627  // double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0modGlobal,c1modGlobal,verbose_opt[0]);
628  if(verbose_opt[0])
629  cout << "c0modGlobal, c1modGlobal: " << c0modGlobal << ", " << c1modGlobal << endl;
630 
631  bool update=false;
632  if(obsindex<relobsindex.size()){
633  update=(relobsindex[obsindex]==modindex);
634  }
635  if(update){
636  if(verbose_opt[0])
637  cout << "***update " << relobsindex[obsindex] << " = " << modindex << " " << observation_opt[obsindex] << " ***" << endl;
638 
639  imgReaderObs.open(observation_opt[obsindex]);
640  imgReaderObs.getGeoTransform(geotransform);
641  imgReaderObs.setNoData(obsnodata_opt);
642  if(obsoffset_opt.size())
643  imgReaderObs.setOffset(obsoffset_opt[0]);
644  if(obsscale_opt.size())
645  imgReaderObs.setScale(obsscale_opt[0]);
646  //calculate regression between model and observation
647  if(verbose_opt[0])
648  cout << "Calculating regression for " << imgReaderModel2.getFileName() << " " << imgReaderObs.getFileName() << endl;
649  if(regSensor_opt[0]>0)
650  errObs=regSensor_opt[0]*imgreg.getRMSE(imgReaderModel2,imgReaderObs,c0obs,c1obs,0,0,verbose_opt[0]);
651  else{
652  c0obs=0;
653  c1obs=1;
654  errObs=0;
655  }
656  if(verbose_opt[0])
657  cout << "c0obs, c1obs: " << c0obs << ", " << c1obs << endl;
658  }
659  //prediction (also to fill cloudy pixels in update mode)
660  string input;
661  if(outputfw_opt.size()==model_opt.size())
662  input=outputfw_opt[modindex-1];
663  else{
664  ostringstream outputstream;
665  outputstream << outputfw_opt[0] << "_";
666  outputstream << setfill('0') << setw(ndigit) << tmodel_opt[modindex-1];
667  outputstream << ".tif";
668  // outputstream << outputfw_opt[0] << "_" << tmodel_opt[modindex-1] << ".tif";
669  input=outputstream.str();
670  }
671  if(verbose_opt[0])
672  cout << "opening " << input << endl;
673  ImgReaderGdal imgReaderEst(input);
674  imgReaderEst.setNoData(obsnodata_opt);
675  if(obsoffset_opt.size())
676  imgReaderEst.setOffset(obsoffset_opt[0]);
677  if(obsscale_opt.size())
678  imgReaderEst.setScale(obsscale_opt[0]);
679 
680  vector< vector<double> > obsLineVector(down_opt[0]);
681  vector<double> obsLineBuffer;
682  vector<double> obsWindowBuffer;//buffer for observation to calculate average corresponding to model pixel
683  vector<double> model1LineBuffer;
684  vector<double> model2LineBuffer;
685  vector<double> model1buffer;//buffer for model 1 to calculate time regression based on window
686  vector<double> model2buffer;//buffer for model 2 to calculate time regression based on window
687  vector<double> uncertObsLineBuffer;
688  vector<double> estReadBuffer;
689  // vector<double> estWindowBuffer;//buffer for estimate to calculate average corresponding to model pixel
690  vector<double> uncertReadBuffer;
691  vector<double> estWriteBuffer(ncol);
692  vector<double> uncertWriteBuffer(ncol);
693  // vector<double> lineMask;
694 
695  //initialize obsLineVector if update
696  if(update){
697  if(verbose_opt[0])
698  cout << "initialize obsLineVector" << endl;
699  assert(down_opt[0]%2);//window size must be odd
700  for(int iline=-down_opt[0]/2;iline<down_opt[0]/2+1;++iline){
701  if(iline<0)//replicate line 0
702  imgReaderObs.readData(obsLineVector[iline+down_opt[0]/2],GDT_Float64,0,0);
703  else
704  imgReaderObs.readData(obsLineVector[iline+down_opt[0]/2],GDT_Float64,iline,0);
705  }
706  }
707  for(int irow=0;irow<imgWriterEst.nrOfRow();++irow){
708  //do not read from imgReaderObs, because we read entire window for each pixel...
709  imgReaderEst.readData(estReadBuffer,GDT_Float64,irow,0);
710  imgReaderEst.readData(uncertReadBuffer,GDT_Float64,irow,1);
711  //read model2 in case current estimate is nodata
712  imgReaderEst.image2geo(0,irow,geox,geoy);
713  imgReaderModel2.geo2image(geox,geoy,modCol,modRow);
714  assert(modRow>=0&&modRow<imgReaderModel2.nrOfRow());
715  imgReaderModel2.readData(model2LineBuffer,GDT_Float64,modRow,0);
716 
717  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
718  assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow());
719  imgReaderModel1.readData(model1LineBuffer,GDT_Float64,modRow,0);
720 
721  if(update){
722  int maxRow=(irow+down_opt[0]/2<imgReaderEst.nrOfRow()) ? irow+down_opt[0]/2 : imgReaderEst.nrOfRow()-1;
723  obsLineVector.erase(obsLineVector.begin());
724  imgReaderObs.readData(obsLineBuffer,GDT_Float64,maxRow,0);
725  obsLineVector.push_back(obsLineBuffer);
726  obsLineBuffer=obsLineVector[down_opt[0]/2];
727  // imgReaderObs.readData(obsLineBuffer,GDT_Float64,irow,0);
728  if(imgReaderObs.nrOfBand()>1)
729  imgReaderObs.readData(uncertObsLineBuffer,GDT_Float64,irow,1);
730  }
731  // double oldRowMask=-1;//keep track of row mask to optimize number of line readings
732  for(int icol=0;icol<imgWriterEst.nrOfCol();++icol){
733  imgReaderEst.image2geo(icol,irow,geox,geoy);
734  int minCol=(icol>down_opt[0]/2) ? icol-down_opt[0]/2 : 0;
735  int maxCol=(icol+down_opt[0]/2<imgReaderEst.nrOfCol()) ? icol+down_opt[0]/2 : imgReaderEst.nrOfCol()-1;
736  int minRow=(irow>down_opt[0]/2) ? irow-down_opt[0]/2 : 0;
737  int maxRow=(irow+down_opt[0]/2<imgReaderEst.nrOfRow()) ? irow+down_opt[0]/2 : imgReaderEst.nrOfRow()-1;
738  if(update){
739  obsWindowBuffer.clear();
740  for(int iline=0;iline<obsLineVector.size();++iline){
741  for(int isample=minCol;isample<=maxCol;++isample){
742  assert(isample<obsLineVector[iline].size());
743  obsWindowBuffer.push_back(obsLineVector[iline][isample]);
744  }
745  }
746  // imgReaderObs.readDataBlock(obsWindowBuffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0);
747  }
748  double estValue=estReadBuffer[icol];
749  double estMeanValue=0;//stat.mean(estWindowBuffer);
750  double nvalid=0;
751  //time update
752  imgReaderModel2.geo2image(geox,geoy,modCol,modRow);
753  assert(modRow>=0&&modRow<imgReaderModel2.nrOfRow());
754  double modValue=model2LineBuffer[modCol];
755  bool estNodata=imgReaderEst.isNoData(estValue);//validity of current estimate
756  if(estNodata){
757  //we have not found any valid data yet, better here to take the current model value if valid
758  if(imgReaderModel2.isNoData(modValue)){//if both estimate and model are no-data, set obs to nodata
759  estWriteBuffer[icol]=obsnodata_opt[0];
760  uncertWriteBuffer[icol]=uncertNodata_opt[0];
761  }
762  else{
763  estWriteBuffer[icol]=modValue;
764  uncertWriteBuffer[icol]=uncertModel_opt[0]*stdDev;
765  }
766  }
767  else{
768  if(window_opt[0]>0){
769  try{
770  // imgReaderModel2.geo2image(geox,geoy,modCol,modRow);//did that already
771  minCol=(modCol>window_opt[0]/2) ? modCol-window_opt[0]/2 : 0;
772  maxCol=(modCol+window_opt[0]/2<imgReaderModel2.nrOfCol()) ? modCol+window_opt[0]/2 : imgReaderModel2.nrOfCol()-1;
773  minRow=(modRow>window_opt[0]/2) ? modRow-window_opt[0]/2 : 0;
774  maxRow=(modRow+window_opt[0]/2<imgReaderModel2.nrOfRow()) ? modRow+window_opt[0]/2 : imgReaderModel2.nrOfRow()-1;
775  imgReaderModel2.readDataBlock(model2buffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0);
776 
777  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
778  assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow());
779  minCol=(modCol>window_opt[0]/2) ? modCol-window_opt[0]/2 : 0;
780  maxCol=(modCol+window_opt[0]/2<imgReaderModel1.nrOfCol()) ? modCol+window_opt[0]/2 : imgReaderModel1.nrOfCol()-1;
781  minRow=(modRow>window_opt[0]/2) ? modRow-window_opt[0]/2 : 0;
782  maxRow=(modRow+window_opt[0]/2<imgReaderModel1.nrOfRow()) ? modRow+window_opt[0]/2 : imgReaderModel1.nrOfRow()-1;
783  imgReaderModel1.readDataBlock(model1buffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0);
784  // imgReaderEst.image2geo(icol,irow,geox,geoy);
785  }
786  catch(string errorString){
787  cerr << "Error reading data block for " << minCol << "-" << maxCol << ", " << minRow << "-" << maxRow << endl;
788  }
789  //erase no-data from buffer
790  vector<double>::iterator it1=model1buffer.begin();
791  vector<double>::iterator it2=model2buffer.begin();
792  while(it1!=model1buffer.end()&&it2!=model2buffer.end()){
793  //erase nodata
794  bool modNodata=false;
795  modNodata=modNodata||imgReaderModel1.isNoData(*it1);
796  modNodata=modNodata||imgReaderModel2.isNoData(*it2);
797  if(modNodata){
798  model1buffer.erase(it1);
799  model2buffer.erase(it2);
800  }
801  else{
802  ++it1;
803  ++it2;
804  }
805  }
806  if(model1buffer.size()>minreg_opt[0]&&model2buffer.size()>minreg_opt[0]){
807  errMod=stat.linear_regression_err(model1buffer,model2buffer,c0mod,c1mod);
808  errMod*=regTime_opt[0];
809  }
810  else{//use global regression...
811  c0mod=c0modGlobal;
812  c1mod=c1modGlobal;
813  }
814  }
815  else{
816  c0mod=c0modGlobal;
817  c1mod=c1modGlobal;
818  }
819  double certNorm=(errMod*errMod+errObs*errObs);
820  double certMod=errObs*errObs/certNorm;
821  double certObs=errMod*errMod/certNorm;
822  double regTime=(c0mod+c1mod*estValue)*certObs;
823  double regSensor=(c0obs+c1obs*modValue)*certMod;
824  // double regSensor=(c0obs+c1obs*estValue)*certObs;
825  estWriteBuffer[icol]=regTime+regSensor;
826  //test
827  // if(regTime<regSensor){
828  // cout << "regTime = (" << c0mod << "+" << c1mod << "*" << estValue << ")*" << certObs << " = " << regTime << endl;
829  // cout << "regSensor = (" << c0obs << "+" << c1obs << "*" << modValue << ")*" << certMod << " = " << regSensor << endl;
830  // assert(regTime+regSensor>0);
831  // assert(regTime+regSensor<=1);
832  // }
833 
834  double totalUncertainty=0;
835  if(errMod<eps_opt[0])
836  totalUncertainty=errObs;
837  else if(errObs<eps_opt[0])
838  totalUncertainty=errMod;
839  else{
840  totalUncertainty=1.0/errMod/errMod+1/errObs/errObs;
841  totalUncertainty=sqrt(1.0/totalUncertainty);
842  }
843  uncertWriteBuffer[icol]=totalUncertainty+uncertReadBuffer[icol];
844  }
845  //measurement update
846  if(update&&!imgReaderObs.isNoData(obsLineBuffer[icol])){
847  double kalmanGain=1;
848  double uncertObs=uncertObs_opt[0];
849  if(uncertObsLineBuffer.size()>icol)
850  uncertObs=uncertObsLineBuffer[icol];
851  else if(weight_opt.size()>1||deltaObs_opt.size()){
852  statfactory::StatFactory statobs;
853  statobs.setNoDataValues(obsnodata_opt);
854  double obsMeanValue=(statobs.mean(obsWindowBuffer)-c0obs)/c1obs;
855  double difference=obsMeanValue-modValue;
856  if(modValue){
857  double relativeDifference=difference/modValue;
858  if(deltaObs_opt.size()){
859  assert(deltaObs_opt.size()>1);
860  if(100*relativeDifference<deltaObs_opt[0])//lower bound
861  kalmanGain=0;
862  else if(100*relativeDifference>deltaObs_opt[1])//upper bound
863  kalmanGain=0;
864  }
865  else if(weight_opt.size()){
866  assert(weight_opt.size()>1);
867  if(obsMeanValue<modValue)
868  uncertObs=weight_opt[0]*relativeDifference;
869  else if(obsMeanValue>modValue)
870  uncertObs=weight_opt[1]*relativeDifference;
871  }
872  }
873  if(uncertObs<=0)
874  uncertObs=0;
875  if(verbose_opt[0]>1)
876  cout << "obsMeanValue:" << obsMeanValue << ", modValue: " << modValue << endl;
877  }
878  if(kalmanGain>0){
879  if((uncertWriteBuffer[icol]+uncertObs)>eps_opt[0])
880  kalmanGain=uncertWriteBuffer[icol]/(uncertWriteBuffer[icol]+uncertObs);
881  }
882  assert(kalmanGain<=1);
883  estWriteBuffer[icol]+=kalmanGain*(obsLineBuffer[icol]-estWriteBuffer[icol]);
884  uncertWriteBuffer[icol]*=(1-kalmanGain);
885  }
886  }
887  imgWriterEst.writeData(estWriteBuffer,GDT_Float64,irow,0);
888  imgWriterEst.writeData(uncertWriteBuffer,GDT_Float64,irow,1);
889  progress=static_cast<float>((irow+1.0)/imgWriterEst.nrOfRow());
890  pfnProgress(progress,pszMessage,pProgressArg);
891  }
892 
893  imgWriterEst.close();
894  imgReaderEst.close();
895 
896  if(update){
897  imgReaderObs.close();
898  ++obsindex;
899  }
900  imgReaderModel1.close();
901  imgReaderModel2.close();
902  }
903  }
904  if(find(direction_opt.begin(),direction_opt.end(),"backward")!=direction_opt.end()){
906  cout << "Running backward model" << endl;
907  obsindex=relobsindex.size()-1;
908  //initialization
909  string output;
910  if(outputbw_opt.size()==model_opt.size())
911  output=outputbw_opt.back();
912  else{
913  ostringstream outputstream;
914  outputstream << outputbw_opt[0] << "_";
915  outputstream << setfill('0') << setw(ndigit) << tmodel_opt.back();
916  outputstream << ".tif";
917  // outputstream << outputbw_opt[0] << "_" << tmodel_opt.back() << ".tif";
918  output=outputstream.str();
919  }
920  if(verbose_opt[0])
921  cout << "Opening image " << output << " for writing " << endl;
922  imgWriterEst.open(output,ncol,nrow,2,GDT_Float32,imageType,option_opt);
923  imgWriterEst.setProjectionProj4(projection_opt[0]);
924  imgWriterEst.setGeoTransform(geotransform);
925  imgWriterEst.GDALSetNoDataValue(obsnodata_opt[0]);
926 
927  if(verbose_opt[0]){
928  cout << "processing time " << tmodel_opt.back() << endl;
929  if(obsindex<relobsindex.size())
930  cout << "next observation " << tmodel_opt[relobsindex[obsindex]] << endl;
931  else
932  cout << "There is no next observation" << endl;
933  }
934 
935  try{
936  imgReaderModel1.open(model_opt.back());
937  imgReaderModel1.setNoData(modnodata_opt);
938  if(modoffset_opt.size())
939  imgReaderModel1.setOffset(modoffset_opt[0]);
940  if(modscale_opt.size())
941  imgReaderModel1.setScale(modscale_opt[0]);
942  }
943  catch(string errorString){
944  cerr << errorString << endl;
945  }
946  catch(...){
947  cerr << "Error opening file " << model_opt[0] << endl;
948  }
949 
950  //calculate standard deviation of image to serve as model uncertainty
951  GDALRasterBand* rasterBand;
952  rasterBand=imgReaderModel1.getRasterBand(0);
953  double minValue, maxValue, meanValue, stdDev;
954  void* pProgressData;
955  rasterBand->ComputeStatistics(0,&minValue,&maxValue,&meanValue,&stdDev,pfnProgress,pProgressData);
956  double modRow=0;
957  double modCol=0;
958  if(relobsindex.back()<model_opt.size()-1){//initialize output_opt.back() as model[0]
959  //write last model as output
960  if(verbose_opt[0])
961  cout << "write last model as output" << endl;
962  for(int irow=0;irow<nrow;++irow){
963  vector<double> estReadBuffer;
964  vector<double> estWriteBuffer(ncol);
965  vector<double> uncertWriteBuffer(ncol);
966  // vector<double> lineMask;
967  imgWriterEst.image2geo(0,irow,geox,geoy);
968  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
969  assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow());
970  try{
971  imgReaderModel1.readData(estReadBuffer,GDT_Float64,modRow);
972  //simple nearest neighbor
973  //stat.nearUp(estReadBuffer,estWriteBuffer);
974 
975  // double oldRowMask=-1;//keep track of row mask to optimize number of line readings
976  for(int icol=0;icol<imgWriterEst.nrOfCol();++icol){
977  imgWriterEst.image2geo(icol,irow,geox,geoy);
978  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
979  double modValue=estReadBuffer[modCol];
980  if(imgReaderModel1.isNoData(modValue)){
981  estWriteBuffer[icol]=obsnodata_opt[0];
982  uncertWriteBuffer[icol]=uncertNodata_opt[0];
983  }
984  else{
985  estWriteBuffer[icol]=modValue;
986  uncertWriteBuffer[icol]=uncertModel_opt[0]*stdDev;
987  }
988  }
989  imgWriterEst.writeData(estWriteBuffer,GDT_Float64,irow,0);
990  imgWriterEst.writeData(uncertWriteBuffer,GDT_Float64,irow,1);
991  }
992  catch(string errorString){
993  cerr << errorString << endl;
994  }
995  catch(...){
996  cerr << "Error writing file " << imgWriterEst.getFileName() << endl;
997  }
998  }
999  }
1000  else{//we have an measurement at end time
1001  if(verbose_opt[0])
1002  cout << "we have an measurement at end time" << endl;
1003  imgReaderObs.open(observation_opt.back());
1004  imgReaderObs.getGeoTransform(geotransform);
1005  imgReaderObs.setNoData(obsnodata_opt);
1006  if(obsoffset_opt.size())
1007  imgReaderObs.setOffset(obsoffset_opt[0]);
1008  if(obsscale_opt.size())
1009  imgReaderObs.setScale(obsscale_opt[0]);
1010 
1011  if(regSensor_opt[0]>0)
1012  errObs=regSensor_opt[0]*imgreg.getRMSE(imgReaderModel1,imgReaderObs,c0obs,c1obs,0,0,verbose_opt[0]);
1013  else{
1014  c0obs=0;
1015  c1obs=1;
1016  errObs=0;
1017  }
1018  if(verbose_opt[0])
1019  cout << "c0obs, c1obs: " << c0obs << ", " << c1obs << endl;
1020 
1021  for(int irow=0;irow<nrow;++irow){
1022  vector<double> estReadBuffer;
1023  imgWriterEst.image2geo(0,irow,geox,geoy);
1024  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
1025  assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow());
1026  imgReaderModel1.readData(estReadBuffer,GDT_Float64,modRow);
1027  vector<double> obsLineBuffer;
1028  vector<double> estWriteBuffer(ncol);
1029  vector<double> uncertWriteBuffer(ncol);
1030  vector<double> uncertObsLineBuffer;
1031  // vector<double> lineMask;
1032  // imgReaderObs.readData(estWriteBuffer,GDT_Float64,irow,0);
1033  imgReaderObs.readData(obsLineBuffer,GDT_Float64,irow,0);
1034 
1035  if(imgReaderObs.nrOfBand()>1)
1036  imgReaderObs.readData(uncertObsLineBuffer,GDT_Float64,irow,1);
1037  // double oldRowMask=-1;//keep track of row mask to optimize number of line readings
1038  for(int icol=0;icol<imgWriterEst.nrOfCol();++icol){
1039  imgWriterEst.image2geo(icol,irow,geox,geoy);
1040  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
1041  assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow());
1042  double modValue=estReadBuffer[modCol];
1043  if(imgReaderModel1.isNoData(modValue)){//model is nodata: retain observation
1044  estWriteBuffer[icol]=obsLineBuffer[icol];
1045  if(imgReaderObs.isNoData(obsLineBuffer[icol])){
1046  estWriteBuffer[icol]=obsnodata_opt[0];
1047  uncertWriteBuffer[icol]=uncertNodata_opt[0];
1048  }
1049  else if(uncertObsLineBuffer.size()>icol)
1050  uncertWriteBuffer[icol]=uncertObsLineBuffer[icol];
1051  else
1052  uncertWriteBuffer[icol]=uncertObs_opt[0];
1053  }
1054  else{//model is valid: calculate estimate from model
1055  double errMod=uncertModel_opt[0]*stdDev;
1056  errMod*=regTime_opt[0];
1057  // double certNorm=(errMod*errMod+errObs*errObs);
1058  // double certMod=errObs*errObs/certNorm;
1059  // double certObs=errMod*errMod/certNorm;
1060  // double regTime=0;
1061  // double regSensor=(c0obs+c1obs*modValue)*certMod;
1062  // estWriteBuffer[icol]=regTime+regSensor;
1063  estWriteBuffer[icol]=modValue;
1064  double totalUncertainty=errMod;
1065  // if(errMod<eps_opt[0])
1066  // totalUncertainty=errObs;
1067  // else if(errObs<eps_opt[0])
1068  // totalUncertainty=errMod;
1069  // else{
1070  // totalUncertainty=1.0/errMod/errMod+1/errObs/errObs;
1071  // totalUncertainty=sqrt(1.0/totalUncertainty);
1072  // }
1073  uncertWriteBuffer[icol]=totalUncertainty;//in case observation is not valid
1074  }
1075  //measurement update
1076  if(!imgReaderObs.isNoData(obsLineBuffer[icol])){
1077  double kalmanGain=1;
1078  double uncertObs=uncertObs_opt[0];
1079  if(uncertObsLineBuffer.size()>icol)
1080  uncertObs=uncertObsLineBuffer[icol];
1081  else if(weight_opt.size()>1||deltaObs_opt.size()){
1082  vector<double> obsWindowBuffer;//buffer for observation to calculate average corresponding to model pixel
1083  int minCol=(icol>down_opt[0]/2) ? icol-down_opt[0]/2 : 0;
1084  int maxCol=(icol+down_opt[0]/2<imgReaderObs.nrOfCol()) ? icol+down_opt[0]/2 : imgReaderObs.nrOfCol()-1;
1085  int minRow=(irow>down_opt[0]/2) ? irow-down_opt[0]/2 : 0;
1086  int maxRow=(irow+down_opt[0]/2<imgReaderObs.nrOfRow()) ? irow+down_opt[0]/2 : imgReaderObs.nrOfRow()-1;
1087 
1088  imgReaderObs.readDataBlock(obsWindowBuffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0);
1089  statfactory::StatFactory statobs;
1090  statobs.setNoDataValues(obsnodata_opt);
1091  double obsMeanValue=(statobs.mean(obsWindowBuffer)-c0obs)/c1obs;
1092  double difference=obsMeanValue-modValue;
1093  if(modValue){
1094  double relativeDifference=difference/modValue;
1095  if(deltaObs_opt.size()){
1096  assert(deltaObs_opt.size()>1);
1097  if(100*relativeDifference<deltaObs_opt[0])//lower bound
1098  kalmanGain=0;
1099  else if(100*relativeDifference>deltaObs_opt[1])//upper bound
1100  kalmanGain=0;
1101  }
1102  else if(weight_opt.size()){
1103  assert(weight_opt.size()>1);
1104  if(obsMeanValue<modValue)
1105  uncertObs=weight_opt[0]*relativeDifference;
1106  else if(obsMeanValue>modValue)
1107  uncertObs=weight_opt[1]*relativeDifference;
1108  }
1109  }
1110  if(uncertObs<=0)
1111  uncertObs=0;
1112  if(verbose_opt[0]>1)
1113  cout << "obsMeanValue:" << obsMeanValue << ", modValue: " << modValue << endl;
1114  }
1115  if(kalmanGain>0){
1116  if((uncertWriteBuffer[icol]+uncertObs)>eps_opt[0])
1117  kalmanGain=uncertWriteBuffer[icol]/(uncertWriteBuffer[icol]+uncertObs);
1118  }
1119  assert(kalmanGain<=1);
1120  estWriteBuffer[icol]+=kalmanGain*(obsLineBuffer[icol]-estWriteBuffer[icol]);
1121  uncertWriteBuffer[icol]*=(1-kalmanGain);
1122  }
1123  }
1124  imgWriterEst.writeData(estWriteBuffer,GDT_Float64,irow,0);
1125  imgWriterEst.writeData(uncertWriteBuffer,GDT_Float64,irow,1);
1126  }
1127  imgReaderObs.close();
1128  --obsindex;
1129  }
1130  imgReaderModel1.close();
1131  imgWriterEst.close();
1132 
1133  for(int modindex=model_opt.size()-2;modindex>=0;--modindex){
1134  if(verbose_opt[0]){
1135  cout << "processing time " << tmodel_opt[modindex] << endl;
1136  if(obsindex<relobsindex.size())
1137  cout << "next observation " << tmodel_opt[relobsindex[obsindex]] << endl;
1138  else
1139  cout << "There is no next observation" << endl;
1140  }
1141  string output;
1142  if(outputbw_opt.size()==model_opt.size())
1143  output=outputbw_opt[modindex];
1144  else{
1145  ostringstream outputstream;
1146  outputstream << outputbw_opt[0] << "_";
1147  outputstream << setfill('0') << setw(ndigit) << tmodel_opt[modindex];
1148  outputstream << ".tif";
1149  // outputstream << outputbw_opt[0] << "_" << tmodel_opt[modindex] << ".tif";
1150  output=outputstream.str();
1151  }
1152 
1153  //two band output band0=estimation, band1=uncertainty
1154  imgWriterEst.open(output,ncol,nrow,2,GDT_Float32,imageType,option_opt);
1155  imgWriterEst.setProjectionProj4(projection_opt[0]);
1156  imgWriterEst.setGeoTransform(geotransform);
1157  imgWriterEst.GDALSetNoDataValue(obsnodata_opt[0]);
1158 
1159  //calculate regression between two subsequence model inputs
1160  imgReaderModel1.open(model_opt[modindex+1]);
1161  imgReaderModel1.setNoData(modnodata_opt);
1162  if(modoffset_opt.size())
1163  imgReaderModel1.setOffset(modoffset_opt[0]);
1164  if(modscale_opt.size())
1165  imgReaderModel1.setScale(modscale_opt[0]);
1166  imgReaderModel2.open(model_opt[modindex]);
1167  imgReaderModel2.setNoData(modnodata_opt);
1168  if(modoffset_opt.size())
1169  imgReaderModel2.setOffset(modoffset_opt[0]);
1170  if(modscale_opt.size())
1171  imgReaderModel2.setScale(modscale_opt[0]);
1172  //calculate regression
1173  //we could re-use the points from second image from last run, but
1174  //to keep it general, we must redo it (overlap might have changed)
1175 
1176  pfnProgress(progress,pszMessage,pProgressArg);
1177 
1178  if(verbose_opt[0])
1179  cout << "Calculating regression for " << imgReaderModel1.getFileName() << " " << imgReaderModel2.getFileName() << endl;
1180 
1181  double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0modGlobal,c1modGlobal,0,0);
1182  errMod*=regTime_opt[0];
1183 
1184  // double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0modGlobal,c1modGlobal,verbose_opt[0]);
1185  if(verbose_opt[0])
1186  cout << "c0modGlobal, c1modGlobal: " << c0modGlobal << ", " << c1modGlobal << endl;
1187 
1188  bool update=false;
1189  if(obsindex<relobsindex.size()){
1190  update=(relobsindex[obsindex]==modindex);
1191  }
1192  if(update){
1193  if(verbose_opt[0])
1194  cout << "***update " << relobsindex[obsindex] << " = " << modindex << " " << observation_opt[obsindex] << " ***" << endl;
1195 
1196  imgReaderObs.open(observation_opt[obsindex]);
1197  imgReaderObs.getGeoTransform(geotransform);
1198  imgReaderObs.setNoData(obsnodata_opt);
1199  if(obsoffset_opt.size())
1200  imgReaderObs.setOffset(obsoffset_opt[0]);
1201  if(obsscale_opt.size())
1202  imgReaderObs.setScale(obsscale_opt[0]);
1203  //calculate regression between model and observation
1204  if(verbose_opt[0])
1205  cout << "Calculating regression for " << imgReaderModel2.getFileName() << " " << imgReaderObs.getFileName() << endl;
1206  if(regSensor_opt[0]>0)
1207  errObs=regSensor_opt[0]*imgreg.getRMSE(imgReaderModel2,imgReaderObs,c0obs,c1obs,0,0,verbose_opt[0]);
1208  else{
1209  c0obs=0;
1210  c1obs=1;
1211  errObs=0;
1212  }
1213  if(verbose_opt[0])
1214  cout << "c0obs, c1obs: " << c0obs << ", " << c1obs << endl;
1215  }
1216  //prediction (also to fill cloudy pixels in update mode)
1217  string input;
1218  if(outputbw_opt.size()==model_opt.size())
1219  input=outputbw_opt[modindex+1];
1220  else{
1221  ostringstream outputstream;
1222  outputstream << outputbw_opt[0] << "_";
1223  outputstream << setfill('0') << setw(ndigit) << tmodel_opt[modindex+1];
1224  outputstream << ".tif";
1225  // outputstream << outputbw_opt[0] << "_" << tmodel_opt[modindex+1] << ".tif";
1226  input=outputstream.str();
1227  }
1228  ImgReaderGdal imgReaderEst(input);
1229  imgReaderEst.setNoData(obsnodata_opt);
1230  if(obsoffset_opt.size())
1231  imgReaderEst.setOffset(obsoffset_opt[0]);
1232  if(obsscale_opt.size())
1233  imgReaderEst.setScale(obsscale_opt[0]);
1234 
1235  vector< vector<double> > obsLineVector(down_opt[0]);
1236  vector<double> obsLineBuffer;
1237  vector<double> obsWindowBuffer;//buffer for observation to calculate average corresponding to model pixel
1238  vector<double> model1LineBuffer;
1239  vector<double> model2LineBuffer;
1240  vector<double> model1buffer;//buffer for model 1 to calculate time regression based on window
1241  vector<double> model2buffer;//buffer for model 2 to calculate time regression based on window
1242  vector<double> uncertObsLineBuffer;
1243  vector<double> estReadBuffer;
1244  // vector<double> estWindowBuffer;//buffer for estimate to calculate average corresponding to model pixel
1245  vector<double> uncertReadBuffer;
1246  vector<double> estWriteBuffer(ncol);
1247  vector<double> uncertWriteBuffer(ncol);
1248  // vector<double> lineMask;
1249 
1250  //initialize obsLineVector
1251  if(update){
1252  assert(down_opt[0]%2);//window size must be odd
1253  for(int iline=-down_opt[0]/2;iline<down_opt[0]/2+1;++iline){
1254  if(iline<0)//replicate line 0
1255  imgReaderObs.readData(obsLineVector[iline+down_opt[0]/2],GDT_Float64,0,0);
1256  else
1257  imgReaderObs.readData(obsLineVector[iline+down_opt[0]/2],GDT_Float64,iline,0);
1258  }
1259  }
1260  for(int irow=0;irow<imgWriterEst.nrOfRow();++irow){
1261  assert(irow<imgReaderEst.nrOfRow());
1262  //do not read from imgReaderObs, because we read entire window for each pixel...
1263  imgReaderEst.readData(estReadBuffer,GDT_Float64,irow,0);
1264  imgReaderEst.readData(uncertReadBuffer,GDT_Float64,irow,1);
1265  //read model2 in case current estimate is nodata
1266  imgReaderEst.image2geo(0,irow,geox,geoy);
1267  imgReaderModel2.geo2image(geox,geoy,modCol,modRow);
1268  assert(modRow>=0&&modRow<imgReaderModel2.nrOfRow());
1269  imgReaderModel2.readData(model2LineBuffer,GDT_Float64,modRow,0);
1270 
1271  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
1272  assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow());
1273  imgReaderModel1.readData(model1LineBuffer,GDT_Float64,modRow,0);
1274 
1275  if(update){
1276  int maxRow=(irow+down_opt[0]/2<imgReaderEst.nrOfRow()) ? irow+down_opt[0]/2 : imgReaderEst.nrOfRow()-1;
1277  obsLineVector.erase(obsLineVector.begin());
1278  imgReaderObs.readData(obsLineBuffer,GDT_Float64,maxRow,0);
1279  obsLineVector.push_back(obsLineBuffer);
1280  obsLineBuffer=obsLineVector[down_opt[0]/2];
1281  // imgReaderObs.readData(obsLineBuffer,GDT_Float64,irow,0);
1282  if(imgReaderObs.nrOfBand()>1)
1283  imgReaderObs.readData(uncertObsLineBuffer,GDT_Float64,irow,1);
1284  }
1285  // double oldRowMask=-1;//keep track of row mask to optimize number of line readings
1286  for(int icol=0;icol<imgWriterEst.nrOfCol();++icol){
1287  imgReaderEst.image2geo(icol,irow,geox,geoy);
1288  int minCol=(icol>down_opt[0]/2) ? icol-down_opt[0]/2 : 0;
1289  int maxCol=(icol+down_opt[0]/2<imgReaderEst.nrOfCol()) ? icol+down_opt[0]/2 : imgReaderEst.nrOfCol()-1;
1290  int minRow=(irow>down_opt[0]/2) ? irow-down_opt[0]/2 : 0;
1291  int maxRow=(irow+down_opt[0]/2<imgReaderEst.nrOfRow()) ? irow+down_opt[0]/2 : imgReaderEst.nrOfRow()-1;
1292  if(update){
1293  obsWindowBuffer.clear();
1294  for(int iline=0;iline<obsLineVector.size();++iline){
1295  for(int isample=minCol;isample<=maxCol;++isample){
1296  assert(isample<obsLineVector[iline].size());
1297  obsWindowBuffer.push_back(obsLineVector[iline][isample]);
1298  }
1299  }
1300  // imgReaderObs.readDataBlock(obsWindowBuffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0);
1301  }
1302  double estValue=estReadBuffer[icol];
1303  double estMeanValue=0;//stat.mean(estWindowBuffer);
1304  double nvalid=0;
1305  //time update
1306  imgReaderModel2.geo2image(geox,geoy,modCol,modRow);
1307  assert(modRow>=0&&modRow<imgReaderModel2.nrOfRow());
1308  double modValue=model2LineBuffer[modCol];
1309  bool estNodata=imgReaderEst.isNoData(estValue);
1310  if(estNodata){
1311  //we have not found any valid data yet, better here to take the current model value if valid
1312  if(imgReaderModel2.isNoData(modValue)){//if both estimate and model are no-data, set obs to nodata
1313  estWriteBuffer[icol]=obsnodata_opt[0];
1314  uncertWriteBuffer[icol]=uncertNodata_opt[0];
1315  }
1316  else{
1317  estWriteBuffer[icol]=modValue;
1318  uncertWriteBuffer[icol]=uncertModel_opt[0]*stdDev;
1319  }
1320  }
1321  else{
1322  if(window_opt[0]>0){
1323  try{
1324  // imgReaderModel2.geo2image(geox,geoy,modCol,modRow);//did that already
1325  minCol=(modCol>window_opt[0]/2) ? modCol-window_opt[0]/2 : 0;
1326  maxCol=(modCol+window_opt[0]/2<imgReaderModel2.nrOfCol()) ? modCol+window_opt[0]/2 : imgReaderModel2.nrOfCol()-1;
1327  minRow=(modRow>window_opt[0]/2) ? modRow-window_opt[0]/2 : 0;
1328  maxRow=(modRow+window_opt[0]/2<imgReaderModel2.nrOfRow()) ? modRow+window_opt[0]/2 : imgReaderModel2.nrOfRow()-1;
1329  imgReaderModel2.readDataBlock(model2buffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0);
1330 
1331  imgReaderModel1.geo2image(geox,geoy,modCol,modRow);
1332  assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow());
1333  minCol=(modCol>window_opt[0]/2) ? modCol-window_opt[0]/2 : 0;
1334  maxCol=(modCol+window_opt[0]/2<imgReaderModel1.nrOfCol()) ? modCol+window_opt[0]/2 : imgReaderModel1.nrOfCol()-1;
1335  minRow=(modRow>window_opt[0]/2) ? modRow-window_opt[0]/2 : 0;
1336  maxRow=(modRow+window_opt[0]/2<imgReaderModel1.nrOfRow()) ? modRow+window_opt[0]/2 : imgReaderModel1.nrOfRow()-1;
1337  imgReaderModel1.readDataBlock(model1buffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0);
1338  // imgReaderEst.image2geo(icol,irow,geox,geoy);
1339  }
1340  catch(string errorString){
1341  cerr << "Error reading data block for " << minCol << "-" << maxCol << ", " << minRow << "-" << maxRow << endl;
1342  }
1343  //erase no-data from buffer
1344  vector<double>::iterator it1=model1buffer.begin();
1345  vector<double>::iterator it2=model2buffer.begin();
1346  while(it1!=model1buffer.end()&&it2!=model2buffer.end()){
1347  //erase nodata
1348  bool modNodata=false;
1349  modNodata=modNodata||imgReaderModel1.isNoData(*it1);
1350  modNodata=modNodata||imgReaderModel2.isNoData(*it2);
1351  if(modNodata){
1352  model1buffer.erase(it1);
1353  model2buffer.erase(it2);
1354  }
1355  else{
1356  ++it1;
1357  ++it2;
1358  }
1359  }
1360  if(model1buffer.size()>minreg_opt[0]&&model2buffer.size()>minreg_opt[0]){
1361  errMod=stat.linear_regression_err(model1buffer,model2buffer,c0mod,c1mod);
1362  errMod*=regTime_opt[0];
1363  }
1364  else{//use global regression...
1365  c0mod=c0modGlobal;
1366  c1mod=c1modGlobal;
1367  }
1368  }
1369  else{
1370  c0mod=c0modGlobal;
1371  c1mod=c1modGlobal;
1372  }
1373  double certNorm=(errMod*errMod+errObs*errObs);
1374  double certMod=errObs*errObs/certNorm;
1375  double certObs=errMod*errMod/certNorm;
1376  double regTime=(c0mod+c1mod*estValue)*certObs;
1377 
1378  // double regSensor=(c0obs+c1obs*estValue)*certObs;
1379  double regSensor=(c0obs+c1obs*modValue)*certMod;
1380  estWriteBuffer[icol]=regTime+regSensor;
1381  double totalUncertainty=0;
1382  if(errMod<eps_opt[0])
1383  totalUncertainty=errObs;
1384  else if(errObs<eps_opt[0])
1385  totalUncertainty=errMod;
1386  else{
1387  totalUncertainty=1.0/errMod/errMod+1/errObs/errObs;
1388  totalUncertainty=sqrt(1.0/totalUncertainty);
1389  }
1390  uncertWriteBuffer[icol]=totalUncertainty+uncertReadBuffer[icol];
1391  }
1392  //measurement update
1393  if(update&&!imgReaderObs.isNoData(obsLineBuffer[icol])){
1394  double kalmanGain=1;
1395  double uncertObs=uncertObs_opt[0];
1396  if(uncertObsLineBuffer.size()>icol)
1397  uncertObs=uncertObsLineBuffer[icol];
1398  else if(weight_opt.size()>1||deltaObs_opt.size()){
1399  statfactory::StatFactory statobs;
1400  statobs.setNoDataValues(obsnodata_opt);
1401  double obsMeanValue=(statobs.mean(obsWindowBuffer)-c0obs)/c1obs;
1402  double difference=obsMeanValue-modValue;
1403  if(modValue){
1404  double relativeDifference=difference/modValue;
1405  if(deltaObs_opt.size()){
1406  assert(deltaObs_opt.size()>1);
1407  if(100*relativeDifference<deltaObs_opt[0])//lower bound
1408  kalmanGain=0;
1409  else if(100*relativeDifference>deltaObs_opt[1])//upper bound
1410  kalmanGain=0;
1411  }
1412  else if(weight_opt.size()){
1413  assert(weight_opt.size()>1);
1414  if(obsMeanValue<modValue)
1415  uncertObs=weight_opt[0]*relativeDifference;
1416  else if(obsMeanValue>modValue)
1417  uncertObs=weight_opt[1]*relativeDifference;
1418  }
1419  }
1420  if(uncertObs<=0)
1421  uncertObs=0;
1422  if(verbose_opt[0]>1)
1423  cout << "obsMeanValue:" << obsMeanValue << ", modValue: " << modValue << endl;
1424  }
1425  if(kalmanGain>0){
1426  if((uncertWriteBuffer[icol]+uncertObs)>eps_opt[0])
1427  kalmanGain=uncertWriteBuffer[icol]/(uncertWriteBuffer[icol]+uncertObs);
1428  }
1429  assert(kalmanGain<=1);
1430  estWriteBuffer[icol]+=kalmanGain*(obsLineBuffer[icol]-estWriteBuffer[icol]);
1431  uncertWriteBuffer[icol]*=(1-kalmanGain);
1432  }
1433  }
1434  imgWriterEst.writeData(estWriteBuffer,GDT_Float64,irow,0);
1435  imgWriterEst.writeData(uncertWriteBuffer,GDT_Float64,irow,1);
1436  progress=static_cast<float>((irow+1.0)/imgWriterEst.nrOfRow());
1437  pfnProgress(progress,pszMessage,pProgressArg);
1438  }
1439 
1440  imgWriterEst.close();
1441  imgReaderEst.close();
1442 
1443  if(update){
1444  imgReaderObs.close();
1445  --obsindex;
1446  }
1447  imgReaderModel1.close();
1448  imgReaderModel2.close();
1449  }
1450  }
1451  if(find(direction_opt.begin(),direction_opt.end(),"smooth")!=direction_opt.end()){
1453  cout << "Running smooth model" << endl;
1454  obsindex=0;
1455  for(int modindex=0;modindex<model_opt.size();++modindex){
1456  if(verbose_opt[0]){
1457  cout << "processing time " << tmodel_opt[modindex] << endl;
1458  if(obsindex<relobsindex.size())
1459  cout << "next observation " << tmodel_opt[relobsindex[obsindex]] << endl;
1460  else
1461  cout << "There is no next observation" << endl;
1462  }
1463  string output;
1464  if(outputfb_opt.size()==model_opt.size())
1465  output=outputfb_opt[modindex];
1466  else{
1467  ostringstream outputstream;
1468  outputstream << outputfb_opt[0] << "_";
1469  outputstream << setfill('0') << setw(ndigit) << tmodel_opt[modindex];
1470  outputstream << ".tif";
1471  // outputstream << outputfb_opt[0] << "_" << tmodel_opt[modindex] << ".tif";
1472  output=outputstream.str();
1473  }
1474 
1475  //two band output band0=estimation, band1=uncertainty
1476  imgWriterEst.open(output,ncol,nrow,2,GDT_Float32,imageType,option_opt);
1477  imgWriterEst.setProjectionProj4(projection_opt[0]);
1478  imgWriterEst.setGeoTransform(geotransform);
1479  imgWriterEst.GDALSetNoDataValue(obsnodata_opt[0]);
1480 
1481  //open forward and backward estimates
1482  //we assume forward in model and backward in observation...
1483 
1484  string inputfw;
1485  string inputbw;
1486  if(outputfw_opt.size()==model_opt.size())
1487  inputfw=outputfw_opt[modindex];
1488  else{
1489  ostringstream outputstream;
1490  outputstream << outputfw_opt[0] << "_";
1491  outputstream << setfill('0') << setw(ndigit) << tmodel_opt[modindex];
1492  outputstream << ".tif";
1493  // outputstream << outputfw_opt[0] << "_" << tmodel_opt[modindex] << ".tif";
1494  inputfw=outputstream.str();
1495  }
1496  if(outputbw_opt.size()==model_opt.size())
1497  inputbw=outputbw_opt[modindex];
1498  else{
1499  ostringstream outputstream;
1500  outputstream << outputbw_opt[0] << "_";
1501  outputstream << setfill('0') << setw(ndigit) << tmodel_opt[modindex];
1502  outputstream << ".tif";
1503  // outputstream << outputbw_opt[0] << "_" << tmodel_opt[modindex] << ".tif";
1504  inputbw=outputstream.str();
1505  }
1506  ImgReaderGdal imgReaderForward(inputfw);
1507  ImgReaderGdal imgReaderBackward(inputbw);
1508  imgReaderForward.setNoData(obsnodata_opt);
1509  if(obsoffset_opt.size())
1510  imgReaderForward.setOffset(obsoffset_opt[0]);
1511  if(obsscale_opt.size())
1512  imgReaderForward.setScale(obsscale_opt[0]);
1513  imgReaderBackward.setNoData(obsnodata_opt);
1514  if(obsoffset_opt.size())
1515  imgReaderBackward.setOffset(obsoffset_opt[0]);
1516  if(obsscale_opt.size())
1517  imgReaderBackward.setScale(obsscale_opt[0]);
1518 
1519  vector<double> estForwardBuffer;
1520  vector<double> estBackwardBuffer;
1521  vector<double> uncertObsLineBuffer;
1522  vector<double> uncertForwardBuffer;
1523  vector<double> uncertBackwardBuffer;
1524  vector<double> uncertReadBuffer;
1525  vector<double> estWriteBuffer(ncol);
1526  vector<double> uncertWriteBuffer(ncol);
1527  // vector<double> lineMask;
1528 
1529  bool update=false;
1530  if(obsindex<relobsindex.size()){
1531  update=(relobsindex[obsindex]==modindex);
1532  }
1533 
1534  if(update){
1535  if(verbose_opt[0])
1536  cout << "***update " << relobsindex[obsindex] << " = " << modindex << " " << observation_opt[obsindex] << " ***" << endl;
1537  imgReaderObs.open(observation_opt[obsindex]);
1538  imgReaderObs.getGeoTransform(geotransform);
1539  imgReaderObs.setNoData(obsnodata_opt);
1540  if(obsoffset_opt.size())
1541  imgReaderObs.setOffset(obsoffset_opt[0]);
1542  if(obsscale_opt.size())
1543  imgReaderObs.setScale(obsscale_opt[0]);
1544  //calculate regression between model and observation
1545  }
1546 
1547  pfnProgress(progress,pszMessage,pProgressArg);
1548 
1549  for(int irow=0;irow<imgWriterEst.nrOfRow();++irow){
1550  assert(irow<imgReaderForward.nrOfRow());
1551  assert(irow<imgReaderBackward.nrOfRow());
1552  imgReaderForward.readData(estForwardBuffer,GDT_Float64,irow,0);
1553  imgReaderBackward.readData(estBackwardBuffer,GDT_Float64,irow,0);
1554  imgReaderForward.readData(uncertForwardBuffer,GDT_Float64,irow,1);
1555  imgReaderBackward.readData(uncertBackwardBuffer,GDT_Float64,irow,1);
1556 
1557  if(update){
1558  imgReaderObs.readData(estWriteBuffer,GDT_Float64,irow,0);
1559  if(imgReaderObs.nrOfBand()>1)
1560  imgReaderObs.readData(uncertObsLineBuffer,GDT_Float64,irow,1);
1561  }
1562 
1563  // double oldRowMask=-1;//keep track of row mask to optimize number of line readings
1564  for(int icol=0;icol<imgWriterEst.nrOfCol();++icol){
1565  imgWriterEst.image2geo(icol,irow,geox,geoy);
1566  double A=estForwardBuffer[icol];
1567  double B=estBackwardBuffer[icol];
1568  double C=uncertForwardBuffer[icol]*uncertForwardBuffer[icol];
1569  double D=uncertBackwardBuffer[icol]*uncertBackwardBuffer[icol];
1570  double uncertObs=uncertObs_opt[0];
1571 
1572  // if(update){//check for nodata in observation
1573  // if(imgReaderObs.isNoData(estWriteBuffer[icol]))
1574  // uncertObs=uncertNodata_opt[0];
1575  // else if(uncertObsLineBuffer.size()>icol)
1576  // uncertObs=uncertObsLineBuffer[icol];
1577  // }
1578 
1579  double noemer=(C+D);
1580  //todo: consistently check for division by zero...
1581  if(imgReaderForward.isNoData(A)&&imgReaderBackward.isNoData(B)){
1582  estWriteBuffer[icol]=obsnodata_opt[0];
1583  uncertWriteBuffer[icol]=uncertNodata_opt[0];
1584  }
1585  else if(imgReaderForward.isNoData(A)){
1586  estWriteBuffer[icol]=B;
1587  uncertWriteBuffer[icol]=uncertBackwardBuffer[icol];
1588  }
1589  else if(imgReaderForward.isNoData(B)){
1590  estWriteBuffer[icol]=A;
1591  uncertWriteBuffer[icol]=uncertForwardBuffer[icol];
1592  }
1593  else{
1594  if(noemer<eps_opt[0]){//simple average if both uncertainties are ~>0
1595  estWriteBuffer[icol]=0.5*(A+B);
1596  uncertWriteBuffer[icol]=uncertObs;
1597  }
1598  else{
1599  estWriteBuffer[icol]=(A*D+B*C)/noemer;
1600  double P=0;
1601  if(C>eps_opt[0])
1602  P+=1.0/C;
1603  if(D>eps_opt[0])
1604  P+=1.0/D;
1605  if(uncertObs*uncertObs>eps_opt[0])
1606  P-=1.0/uncertObs/uncertObs;
1607  if(P>eps_opt[0])
1608  P=sqrt(1.0/P);
1609  else
1610  P=0;
1611  uncertWriteBuffer[icol]=P;
1612  }
1613  }
1614  }
1615  imgWriterEst.writeData(estWriteBuffer,GDT_Float64,irow,0);
1616  imgWriterEst.writeData(uncertWriteBuffer,GDT_Float64,irow,1);
1617  progress=static_cast<float>((irow+1.0)/imgWriterEst.nrOfRow());
1618  pfnProgress(progress,pszMessage,pProgressArg);
1619  }
1620 
1621  imgWriterEst.close();
1622  imgReaderForward.close();
1623  imgReaderBackward.close();
1624  if(update){
1625  imgReaderObs.close();
1626  ++obsindex;
1627  }
1628  }
1629  }
1630  // if(mask_opt.size())
1631  // maskReader.close();
1632 }
1633