-
Notifications
You must be signed in to change notification settings - Fork 7
/
hc.c
294 lines (246 loc) · 8.51 KB
/
hc.c
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
#include "hc.h"
/*
implementation of Hager & O'Connell (1981) method of solving mantle
circulation given internal density anomalies, only radially varying
viscosity, and either free-slip or plate velocity boundary condition
at surface
based on Hager & O'Connell (1981), Hager & Clayton (1989), and
Steinberger (2000)
the original code is due to Brad Hager, Rick O'Connell, and was
largely modified by Bernhard Steinberger
this version by Thorsten Becker ([email protected])
>>> SOME COMMENTS FROM THE ORIGINAL CODE <<<
C * It uses the following Numerical Recipes (Press et al.) routines:
C four1, realft, gauleg, rk4, rkdumb, ludcmp, lubksb;
C !!!!!!!!!!!!!!!!!!! rkqc, odeint !!!!!!!!!! take out !!!!!!
C and the following routines by R.J. O'Connell:
C shc2d, shd2c, ab2cs, cs2ab, plmbar, plvel2sh, pltgrid, pltvel,
C vshd2c, plmbar1.
C Further subroutines are: kinsub, evalpa,
C torsol (all based on "kinflow" by Hager & O'Connell),
C densub and evppot (based on "denflow" by Hager & O'Connell),
C sumsub (based on "sumkd" by Hager & O'Connell, but
C substantially speeded up),
C convert, derivs and shc2dd (based on R.J. O'Connell's shc2d).
C
C bugs found:
C * The combination of (1) high viscosity lithosphere
C (2) compressible flow (3) kinematic (plate driven) flow
C doesn't work properly. The problem presumably only occurs
C at degree 1 (I didn't make this sure) but this is sufficient
C to screw up everything. It will usually work to reduce the
C contrast between lithospheric and asthenospheric viscosity.
C Then make sure that (1) two viscosity structures give similar
C results for incompressible and (2) incompressible and compressible
C reduced viscosity look similar (e.g. anomalous mass flux vs. depth)
<<< END OLD COMMENTS
*/
int main(int argc, char **argv)
{
struct hcs *model; /* main structure, make sure to initialize with
zeroes */
struct sh_lms *sol_spectral=NULL, *geoid = NULL; /* solution expansions */
struct sh_lms *pvel=NULL; /* local plate velocity expansion */
int nsol,lmax,i;
FILE *out;
struct hc_parameters p[1]; /* parameters */
char filename[HC_CHAR_LENGTH],file_prefix[10];
HC_PREC *sol_spatial = NULL; /* spatial solution,
e.g. velocities */
static hc_boolean geoid_binary = FALSE; /* type of geoid output */
static HC_CPREC unitya[1] = {1.0};
strncpy(p->main_program_name,argv[0],HC_CHAR_LENGTH);
/*
(1)
initialize the model structure, this is needed to initialize some
of the default values before callign the parameter handling
routine this call also involves initializing the hc parameter
structure
*/
hc_struc_init(&model);
/*
(2)
init parameters to default values
*/
hc_init_parameters(p);
/*
handle command line arguments
*/
hc_handle_command_line(argc,argv,1,p);
/*
begin main program part
*/
#ifdef __TIMESTAMP__
if(p->verbose)
fprintf(stderr,"%s: starting version compiled on %s\n",argv[0],__TIMESTAMP__);
#else
if(p->verbose)
fprintf(stderr,"%s: starting main program\n",argv[0]);
#endif
/*
(3)
initialize all variables
- choose the internal spherical harmonics convention
- assign constants
- assign phase boundaries, if any
- read in viscosity structure
- assign density anomalies
- read in plate velocities
*/
hc_init_main(model,SH_RICK,p);
nsol = (model->nradp2) * 3; /*
number of solutions (r,pol,tor) * (nlayer+2)
total number of layers is nlayer +2,
because CMB and surface are added
to intermediate layers which are
determined by the spacing of the
density model
*/
if(p->free_slip) /* maximum degree is determined by the
density expansion */
lmax = model->dens_anom[0].lmax;
else /* max degree is determined by the
plate velocities */
lmax = model->pvel.p[0].lmax; /* shouldn't be larger than that*/
/*
make sure we have room for the plate velocities
*/
sh_allocate_and_init(&pvel,2,lmax,model->sh_type,1,p->verbose,FALSE);
/* init done */
/*
SOLUTION PART
*/
/*
make room for the spectral solution on irregular grid
*/
sh_allocate_and_init(&sol_spectral,nsol,lmax,model->sh_type,HC_VECTOR,
p->verbose,FALSE);
if(p->compute_geoid == 1)
/* make room for geoid solution at surface */
sh_allocate_and_init(&geoid,1,model->dens_anom[0].lmax,
model->sh_type,HC_SCALAR,p->verbose,FALSE);
else if(p->compute_geoid == 2) /* all layers (or kernels) */
sh_allocate_and_init(&geoid,model->nradp2,model->dens_anom[0].lmax,
model->sh_type,HC_SCALAR,p->verbose,FALSE);
/*
solve poloidal and toroidal part and sum
*/
if(!p->free_slip)
hc_select_pvel(p->pvel_time,&model->pvel,pvel,p->verbose);
hc_solve(model,p->free_slip,p->solution_mode,sol_spectral,
TRUE,TRUE,TRUE,p->print_pt_sol,p->compute_geoid,
pvel,model->dens_anom,geoid,
p->verbose,p->print_kernel_only);
/*
OUTPUT PART
*/
if(!p->print_kernel_only){
/*
output of spherical harmonics solution
*/
switch(p->solution_mode){
case HC_VEL:
sprintf(file_prefix,"vel");break;
case HC_RTRACTIONS:
sprintf(file_prefix,"rtrac");break;
case HC_HTRACTIONS:
sprintf(file_prefix,"htrac");break;
default:
HC_ERROR(argv[0],"solution mode undefined");break;
}
if(p->sol_binary_out)
sprintf(filename,"%s.%s",file_prefix,HC_SOLOUT_FILE_BINARY);
else
sprintf(filename,"%s.%s",file_prefix,HC_SOLOUT_FILE_ASCII);
if(p->verbose)
fprintf(stderr,"%s: writing spherical harmonics solution to %s\n",
argv[0],filename);
out = hc_fopen(filename,"w","main",p->main_program_name);
hc_print_spectral_solution(model,sol_spectral,out,
p->solution_mode,
p->sol_binary_out,p->verbose);
fclose(out);
/* */
if(p->print_density_field){
/*
print the density field
*/
sprintf(file_prefix,"dscaled");
if(p->sol_binary_out)
sprintf(filename,"%s.%s",file_prefix,HC_SOLOUT_FILE_BINARY);
else
sprintf(filename,"%s.%s",file_prefix,HC_SOLOUT_FILE_ASCII);
if(p->verbose)
fprintf(stderr,"%s: writing scaled density anomaly field to %s\n",
argv[0],filename);
out = hc_fopen(filename,"w","main",p->main_program_name);
hc_print_dens_anom(model,out,p->sol_binary_out,p->verbose);
fclose(out);
}
if(p->print_spatial){
/*
we wish to use the spatial solution
expand velocities to spatial base, compute spatial
representation
*/
hc_compute_sol_spatial(model,sol_spectral,&sol_spatial,
p->verbose);
/*
output of spatial solution
*/
sprintf(filename,"%s.%s",file_prefix,HC_SPATIAL_SOLOUT_FILE);
/* print lon lat z v_r v_theta v_phi */
hc_print_spatial_solution(model,sol_spectral,sol_spatial,
filename,HC_LAYER_OUT_FILE,
p->solution_mode,p->sol_binary_out,
p->verbose);
}
} /* end non-kernel branch */
/* compute the geoid? */
if(p->compute_geoid){
/*
print geoid solution
*/
if(p->print_kernel_only)
sprintf(filename,"%s",HC_GEOID_KERNEL_FILE);
else
sprintf(filename,"%s",HC_GEOID_FILE);
if(p->verbose)
fprintf(stderr,"%s: writing geoid %sto %s, %s\n",argv[0],
((p->print_kernel_only)?("kernels "):("")),filename,
(p->compute_geoid == 1)?("at surface"):("all layers"));
out = hc_fopen(filename,"w","main",p->main_program_name);
if(p->print_kernel_only){
hc_print_geoid_kernel(geoid,model->r,model->nradp2,out,p->verbose);
}else{ /* geoid solutions */
if(p->compute_geoid == 1) /* surface layer */
hc_print_sh_scalar_field(geoid,out,FALSE,geoid_binary,p->verbose);
else{ /* all layers */
for(i=0;i < model->nradp2;i++){
sh_print_parameters_to_stream((geoid+i),1,i,model->nradp2,
HC_Z_DEPTH(model->r[i]),out,
FALSE,geoid_binary,p->verbose);
sh_print_coefficients_to_stream((geoid+i),1,out,
unitya,geoid_binary,p->verbose);
}
}
}
fclose(out);
}
/*
free memory
*/
sh_free_expansion(sol_spectral,nsol);
/* local copies of plate velocities */
sh_free_expansion(pvel,2);
/* */
if(p->compute_geoid == 1) /* only one layer */
sh_free_expansion(geoid,1);
else if(p->compute_geoid == 2) /* all layers */
sh_free_expansion(geoid,model->nradp2);
free(sol_spatial);
if(p->verbose)
fprintf(stderr,"%s: done\n",argv[0]);
hc_struc_free(&model);
return 0;
}