File: resample.c

package info (click to toggle)
vis5d 4.3-5
  • links: PTS
  • area: main
  • in suites: slink
  • size: 16,856 kB
  • ctags: 6,127
  • sloc: ansic: 66,158; fortran: 4,470; makefile: 1,683; tcl: 414; sh: 69
file content (471 lines) | stat: -rw-r--r-- 13,414 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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
/* resample.c */


/*
How resampling is done:

For horizontal resampling we need to know which data points to grab from
the input grid so we can compute the weighted average to store in the output
grid.  The SampRow[][] and SampCol[] arrays tell us this.  Pseudocode:

    FOR each row, r, in output grid DO
       FOR each column, c, in output grid DO
          source_row = SampRow[r][c]
          source_col = SampCol[r][c]

          value = weighted average of input_grid[source_row][source_col]
                                  and input_grid[source_row][source_col+1]
                                  and input_grid[source_row+1][source_col]
                                  and input_grid[source_row+1][source_col+1]

          output_grid[r][c] = value;

       ENDFOR
    ENDFOR

The sample locations are the integer parts of SampRow[][] and SampCol[][].
The sample weights are the fractional parts of SampRow[][] and SampCol[][].


Vertical resampling is done similarly.  However, we can't just store a
1-D table of sample locations.  We have to use a 3-D table because the
vertical resampling can vary across the grid when using a Sigma coordinate
systems (i.e. relative to elevation of topography).


The resampler struct contains the resampling tables corresponding to an
input projection and VCS and output projection and VCS.  Since all the
input grids often have the same projection and VCS we often only need one
resampler.

*/




#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "grid.h"
#include "memory.h"
#include "proj.h"
#include "resample.h"
#include "topo.h"
#include "../src/v5d.h"



#define TOPO_FILE "EARTH.TOPO"

#define ABS(X)   ( (X) < 0.0 ? -(X) : (X) )






/*
 * Compute all the information needed to resample a grid from the form
 * specifed by g to the grid specified by outrows, outcols, etc.  This is
 * basically a setup step prior to beginning resampling.  It potentially
 * does a lot of work which shouldn't be done "on the fly" while resampling.
 */
static void init_resampler( struct resampler *r, int outnl )
{
   int p;
#define SAMPROW(R,C)  r->SampRow[ (C) + (R) * r->outC ]
#define SAMPCOL(R,C)  r->SampCol[ (C) + (R) * r->outC ]
#define SAMPLEV(R,C,L)  r->SampLev[ (C) + ((R) + (L) * r->inR) * r->inC ]

   assert( r );

   printf("init_resampler...\n");

   r->inR = r->inproj->Nr;
   r->inC = r->inproj->Nc;
   r->inL = r->invcs->Nl;
   r->outR = r->outproj->Nr;
   r->outC = r->outproj->Nc;
   r->outL = outnl;

   if (r->inproj->Kind==PROJ_EPA) {
      r->Guard = 1;
   }
   else {
      r->Guard = 0;
   }

   /* just a test... */
   if (r->outL!=r->outvcs->Nl) {
      printf("different Nl values!\n");
   }


   if (r->invcs != r->outvcs) {
      /* Vertical resampling is needed */
      int i, j, k;

      r->DoVertical = 1;
      r->SampLev = (float *) MALLOC(r->inR * r->inC * r->outL * sizeof(float));

      if (load_topo(TOPO_FILE)) {
         /* Specify topo resampling by looking at distance in lat/lon */
         /* between two grid points near the center of domain. */
         float lat1, lat2, lon1, lon2;
         rowcol_to_latlon( (float) r->inR/2, (float) r->inC/2,
                           &lat1, &lon1, r->inproj );
         rowcol_to_latlon( (float) r->inR/2+1, (float) r->inC/2+1,
                           &lat2, &lon2, r->inproj );
         set_topo_sampling( ABS(lat2-lat1), ABS(lon2-lon1) );
      }
      else {
         printf("Note: topography file %s not found\n", TOPO_FILE);
      }

      /* Compute locations of vertical samples */
      for (i=0; i<r->inR; i++) {
         for (j=0; j<r->inC; j++) {
            float lat, lon, topo_elev;
            int k1;

            /* Get the elevation of the topo at the lat/lon corresponding */
            /* to this row/column. */
            rowcol_to_latlon( (float) i, (float) j, &lat, &lon, r->inproj );
            topo_elev = elevation( lat, lon, NULL) / 1000.0;

            /* Special case of input grid being 2-D to make sure the data */
            /* shows up in the output grid and not missed when resampling. */
            if (r->invcs->Nl==1) {
               float height1, level1;
               level_to_height( 0.0, &height1, r->invcs, topo_elev );
               if (height_to_level( height1, &level1, r->outvcs, topo_elev )) {
                  k1 = (int) level1;
               }
               else {
                  k1 = -1;
               }
            }
            else {
               k1 = -1;
            }

            for (k=0;k<r->outL;k++) {
               if (k==k1) {
                  /* special case, see above */
                  SAMPLEV(i,j,k) = 0.0;
               }
               else {
                  float height, level, kk;
                  /* convert level k to a height in output vert coord sys */
                  kk = (float) (k + r->outvcs->LowLev);
                  level_to_height( kk, &height, r->outvcs, topo_elev );
                  /* convert the height to a level in input vert coord sys */
                  if (height_to_level( height, &level, r->invcs, topo_elev )) {
                     SAMPLEV(i,j,k) = level;
                  }
                  else {
                     /* out of bounds */
                     SAMPLEV(i,j,k) = -1.0;
                  }
                  assert( r->inproj->Nr > 0 );
                  p = (j) + ((i) + (k) * r->inR) * r->inC;
                  assert( p < r->inR * r->inC * r->outL );
               }
            }
         }
      }
   }
   else {
      r->DoVertical = 0;
   }

   if (r->inproj != r->outproj) {
      float lat, lon, row, col;
      int i, j;

      r->DoHorizontal = 1;
      r->SampRow = (float *) MALLOC( r->outR * r->outC * sizeof(float) );
      r->SampCol = (float *) MALLOC( r->outR * r->outC * sizeof(float) );

      /* Compute location of horizontal samples */
      for (i=0;i<r->outR;i++) {
         for (j=0;j<r->outC;j++) {
            /* (row,col) -> (lat,lon) in output projection */
            rowcol_to_latlon( (float) i, (float) j, &lat, &lon, r->outproj );
            /* (lat,lon) -> (row,col) in input projection */
            if (latlon_to_rowcol( lat, lon, &row, &col, r->inproj )) {
               SAMPROW(i,j) = row;
               SAMPCOL(i,j) = col;
            }
            else {
               SAMPROW(i,j) = -1.0;
               SAMPCOL(i,j) = -1.0;
            }
         }
      }
   }
   else {
      r->DoHorizontal = 0;
   }

   printf("Done  (vert=%d, horiz=%d)\n", r->DoVertical, r->DoHorizontal);
#undef SAMPROW
#undef SAMPCOL
#undef SAMPLEV
}



/* List of resamplers */
#define MAX_RESAMPLERS 1000
static struct resampler *ResamplerList[MAX_RESAMPLERS];
static int NumResamplers = 0;


/*
 * Given an input and output projection/VCS returns a resampler struct
 * which will do the needed resampling.
 */
struct resampler *get_resampler( struct projection *inproj,
                                 struct vcs *invcs,
                                 struct projection *outproj,
                                 struct vcs *outvcs,
                                 int outnl )
{
   int i;

   assert( inproj );
   assert( invcs );
   assert( outproj );
   assert( outvcs );

   /* See if the same resampler is already defined */
   for (i=0;i<NumResamplers;i++) {
      if (   ResamplerList[i]->inproj==inproj
          && ResamplerList[i]->invcs==invcs
          && ResamplerList[i]->outproj==outproj
          && ResamplerList[i]->outvcs==outvcs
          && ResamplerList[i]->outL==outnl) {
         /* Found identical resampler in list */
         return ResamplerList[i];
      }
   }

   /* didn't find resampler in list, make new one */
   if (NumResamplers<MAX_RESAMPLERS) {
      struct resampler *r;
      r = (struct resampler *) MALLOC( sizeof(struct resampler) );
      r->inproj = inproj;
      r->invcs = invcs;
      r->outproj = outproj;
      r->outvcs = outvcs;
      init_resampler( r, outnl );
      ResamplerList[NumResamplers] = r;
      NumResamplers++;
      return r;
   }
   else {
      assert( NumResamplers < MAX_RESAMPLERS );
      return NULL;
   }
}



/*
 * Deallocate all resamplers
 */
void free_resamplers( void )
{
   int i;

   for (i=0;i<NumResamplers;i++) {
      if (ResamplerList[i]->DoVertical) {
         free( ResamplerList[i]->SampLev );
      }
      if (ResamplerList[i]->DoHorizontal) {
         free( ResamplerList[i]->SampRow );
         free( ResamplerList[i]->SampCol );
      }
      free( ResamplerList[i] );
   }

   NumResamplers = 0;
}



static void compare( int n, float *a, float *b )
{
   int i, same;
   same = 0;
   for (i=0;i<n;i++) {
      if (a[i]==b[i]) {
         same++;
      }
   }
   printf("%d of %d values are same\n", same, n );
}



/*
 * Resample a 3-D grid to a new vertical coordinate system.
 * Input:  r - pointer to a resampler struct
 *         indata - input grid data
 *         outdata - pointer to buffer to store output grid
 * Output:  outdata - contains resampled grid data
 */
void resample_vertical( struct resampler *r, float *indata, float *outdata )
{
   int i, j, k;

   assert( r );
   assert( indata );
   assert( outdata );

   assert( r->invcs != r->outvcs );

#define INDATA(R,C,L)    indata[  ((L) * r->inC + (C)) * r->inR + (R) ]
#define OUTDATA(R,C,L)   outdata[ ((L) * r->inC + (C)) * r->inR + (R) ]
#define SAMPLEV(R,C,L)   r->SampLev[ (C) + ((R) + (L) * r->inR) * r->inC ]

   for (i=0; i<r->inR; i++) {      /* was outR */
      for (j=0; j<r->inC; j++) {   /* was outC */
         for (k=0; k<r->outL; k++) {
            int level;
            float weight;
            float val;

            level = (int) SAMPLEV( i, j, k );
            weight = SAMPLEV( i, j, k ) - (float) level;

            if (level>=0 && level<r->inL) {
               /* compute weighted average of levels 'level' and 'level+1' */
               if (weight==0.0) {
                  val = OUTDATA(i,j,k) = INDATA(i,j,level);
               }
               else {
                  float v1 = INDATA(i,j,level);
                  float v2 = INDATA(i,j,level+1);
#ifdef DEBUG
                  assert( level+1 < r->inL || weight==0.0 );
#endif
                  if (IS_MISSING(v1) || IS_MISSING(v2)) {
                     val = OUTDATA(i, j, k) = MISSING;
                  }
                  else {
                     val = OUTDATA(i, j, k) = v1 * (1.0F-weight) + v2 * weight;
                  }
               }
#ifdef DEBUG
               assert( val==val );
#endif
            }
            else {
               /* out of bounds */
               OUTDATA(i, j, k) = MISSING;
            }

         }
      }
   }

#ifdef DEBUG
   for (k=0;k<r->inL;k++) {
      compare( r->inR * r->inC, &INDATA(0,0,k), &OUTDATA(0,0,k) );
   }
#endif

#undef INDATA
#undef OUTDATA
#undef SAMPLEV
}



/*
 * Resample a 3-D grid to a new projection.
 * Input:  r - pointer to a resampler struct
 *         indata - input data
 *         outdata - pointer to buffer to store new data
 * Output:  outdata - contains the resampled data
 */
void resample_horizontal( struct resampler *r, float *indata, float *outdata )
{
#define INDATA( R, C, L )    indata[  ((L) * r->inC + (C)) * r->inR + (R) ]
#define OUTDATA( R, C, L )   outdata[ ((L) * r->outC + (C)) * r->outR + (R) ]
#define SAMPROW(R,C)   SampRow[ (C) + (R) * r->outC ]
#define SAMPCOL(R,C)   SampCol[ (C) + (R) * r->outC ]
   int i, j, k;
   int miss;
   int minrow, maxrow, mincol, maxcol;

   assert( r );
   assert( indata );
   assert( outdata );
   assert( r->inproj != r->outproj );

   miss = 0;

   /* bounds of valid grid points of input grid */
   minrow = r->Guard;
   maxrow = r->inR - 1 - r->Guard;
   mincol = r->Guard;
   maxcol = r->inC - 1 - r->Guard;


   for (i=0;i<r->outR;i++) {
      for (j=0;j<r->outC;j++) {
         int row, col;
         float alpha, beta;

         row = (int) r->SAMPROW( i, j );
         col = (int) r->SAMPCOL( i, j );
         alpha = r->SAMPROW( i, j ) - (float) row;
         beta  = r->SAMPCOL( i, j ) - (float) col;

         if (row>=minrow && col>=mincol && row<=maxrow && col<=maxcol) {
            /* get weighted average of four neighbors around (row,col) */
            /* in the input data */
            for (k=0;k<r->outL;k++) {
               float v00, v01, v10, v11;

               int dr = (row != maxrow);  /* tricky! */
               int dc = (col != maxcol);
               v00 = INDATA( row,    col,    k );
               v01 = INDATA( row,    col+dc, k );
               v10 = INDATA( row+dr, col,    k );
               v11 = INDATA( row+dr, col+dc, k );

               if (   IS_MISSING(v00) || IS_MISSING(v01)
                   || IS_MISSING(v10) || IS_MISSING(v11)) {
                  OUTDATA( i, j, k ) = MISSING;
                  miss++;
               }
               else {
                  float t0 = v00 * (1.0-beta) + v01 * beta;
                  float t1 = v10 * (1.0-beta) + v11 * beta;
                  float value;
                  value = OUTDATA( i, j, k ) = t0 * (1.0-alpha) + t1 * alpha;
               }
            }
         }
         else {
            /* (row,col) is outside domain of input grid */
            for (k=0; k<r->outL; k++) {
               OUTDATA( i, j, k ) = MISSING;
               miss++;
            }
         }

      }
   }

#undef INDATA
#undef OUTDATA
#undef SAMPROW
#undef SAMPCOL
}