File: transi_test_lam_dirtrans_adjoint.c

package info (click to toggle)
ectrans 1.7.0-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,968 kB
  • sloc: f90: 51,064; ansic: 5,942; cpp: 1,112; python: 488; sh: 127; makefile: 47
file content (153 lines) | stat: -rw-r--r-- 4,612 bytes parent folder | download
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
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
#include "ectrans/transi.h"
#include "transi_test.h"

// ----------------------------------------------------------------------------

double randomDouble() {
    uint64_t r53 = ((uint64_t)(rand()) << 21) ^ (rand() >> 2);
    return (double)r53 / 9007199254740991.0; // 2^53 - 1
}

// ----------------------------------------------------------------------------

void test_lam_dirtrans_adjoint() {

double adjoint_tol = 1.e-6;
printf("test_lam_dirtrans_adjoint()\n");

struct Trans_t trans;
TRANS_CHECK( trans_new(&trans) );

TRANS_CHECK( trans_set_resol_lam(&trans, 20, 18, 2500.0, 2500.0) );
TRANS_CHECK( trans_set_trunc_lam(&trans, 9, 8) );
TRANS_CHECK( trans_setup(&trans) );
TRANS_CHECK( trans_inquire(&trans,"nvalue,mvalue") );

// Number of fields
int nscalar = 2;
int nvordiv = 1;
int nfld  = 2*nvordiv+nscalar;

// Allocate test data
double* rgp1  = calloc( nfld * trans.ngptot, sizeof(double) );
double* rspvor1 = calloc( nvordiv * trans.nspec2, sizeof(double) );
double* rspdiv1 = calloc( nvordiv * trans.nspec2, sizeof(double) );
double* rspscalar1 = calloc( nscalar * trans.nspec2, sizeof(double) );
double* rmeanu1 = calloc( nvordiv, sizeof(double) );
double* rmeanv1 = calloc( nvordiv, sizeof(double) );
double* rgp2 = calloc( nfld * trans.ngptot, sizeof(double) );
double* rspvor2 = calloc( nvordiv * trans.nspec2, sizeof(double) );
double* rspdiv2 = calloc( nvordiv * trans.nspec2, sizeof(double) );
double* rspscalar2 = calloc( nscalar * trans.nspec2, sizeof(double) );
double* rmeanu2 = calloc( nvordiv, sizeof(double) );
double* rmeanv2 = calloc( nvordiv, sizeof(double) );

// Create random grid-point fields
for(int j=0; j<nfld; ++j)
  for( int i=0; i<trans.ngptot; ++i )
    rgp1[j*trans.ngptot+i] = randomDouble();

// Create random spectral fields
for( int i=0; i<trans.nspec2; ++i ) {
  rspvor2[i*nvordiv+0] = randomDouble(); // vorticity
  rspdiv2[i*nvordiv+0] = randomDouble(); // divergence
  rspscalar2[i*nscalar+0] = randomDouble(); // scalar 1
  rspscalar2[i*nscalar+1] = randomDouble(); // scalar 2
}

// Create random mean wind
for( int j=0; j<nvordiv; ++j) {
  rmeanu2[j] = randomDouble();
  rmeanv2[j] = randomDouble();
}

// Apply direct transform
struct DirTrans_t dirtrans = new_dirtrans(&trans);
  dirtrans.nscalar   = nscalar;
  dirtrans.nvordiv   = nvordiv;
  dirtrans.rgp       = rgp1;
  dirtrans.rspscalar = rspscalar1;
  dirtrans.rspvor    = rspvor1;
  dirtrans.rspdiv    = rspdiv1;
  dirtrans.rmeanu    = rmeanu1;
  dirtrans.rmeanv    = rmeanv1;
TRANS_CHECK( trans_dirtrans(&dirtrans) );

// Compute spectral dot product
double adj_value_sp = 0.0;
for( int i=0; i<trans.nspec2; ++i ) {
  adj_value_sp += rspvor1[i] * rspvor2[i];
  adj_value_sp += rspdiv1[i] * rspdiv2[i];
}
for( int j=0; j<nscalar; ++j)
  for( int i=0; i<trans.nspec2; ++i ) {
    adj_value_sp += rspscalar1[i*nscalar+j] * rspscalar2[i*nscalar+j];
}
for( int j=0; j<nvordiv; ++j) {
  adj_value_sp += rmeanu1[j] * rmeanu2[j];
  adj_value_sp += rmeanv1[j] * rmeanv2[j];
}
printf("Spectral product   = %.12f\n", adj_value_sp);

// Apply adjoint of the direct transform
struct DirTransAdj_t dirtrans_adj = new_dirtrans_adj(&trans);
  dirtrans_adj.nscalar   = nscalar;
  dirtrans_adj.nvordiv   = nvordiv;
  dirtrans_adj.rspscalar = rspscalar2;
  dirtrans_adj.rspvor    = rspvor2;
  dirtrans_adj.rspdiv    = rspdiv2;
  dirtrans_adj.rmeanu    = rmeanu2;
  dirtrans_adj.rmeanv    = rmeanv2;
  dirtrans_adj.rgp       = rgp2;
TRANS_CHECK( trans_dirtrans_adj(&dirtrans_adj) );

// Compute grid-point dot product
double adj_value_gp = 0.0;
for(int j=0; j<nfld; ++j)
  for( int i=0; i<trans.ngptot; ++i )
      adj_value_gp += rgp1[j*trans.ngptot+i] * rgp2[j*trans.ngptot+i];
printf("Grid-point product = %.12f\n", adj_value_gp);

// Compare dot products
ASSERT( fabs(adj_value_sp - adj_value_gp ) / fabs( adj_value_gp ) < adjoint_tol );

// Deallocate arrays
free(rgp1);
free(rspvor1);
free(rspdiv1);
free(rspscalar1);
free(rmeanu1);
free(rmeanv1);
free(rgp2);
free(rspvor2);
free(rspdiv2);
free(rspscalar2);
free(rmeanu2);
free(rmeanv2);

TRANS_CHECK( trans_delete(&trans) );

}

// ----------------------------------------------------------------------------

int main ( int arc, char **argv ) {
  trans_use_mpi( test_use_mpi() );

  setbuf(stdout,NULL); // unbuffered stdout

// The adjoint test works for standard gaussian latitude grid
//   with no points on the equator or poles.
// nsmax = nlat - 1

  printf("-----------------------------\n");
  test_lam_dirtrans_adjoint();

  TRANS_CHECK( trans_finalize() );

  return 0;
}