CyberShake BBP Integration

From SCECpedia
Revision as of 02:52, 12 February 2020 by Scottcal (talk | contribs) (→‎Example)
Jump to navigationJump to search

This page details the process of integrating CyberShake with the Broadband Platform, so that we can produce stochastic high-frequency seismograms in CyberShake as a complement to deterministic low-frequency seismograms.

We performed a similar integration process for CyberShake 1.4 and CyberShake Study 15.12. This time, we would like to avoid maintaining a separate CyberShake version of the high-frequency stochastic codes. Instead, we would like to invoke the BBP codes from CyberShake, so that as new modifications are made to BBP, CyberShake can use these new codes without requiring the entire integration process again.

Approach

We have identified the following BBP executables, or elements, which are needed in CyberShake:

  • srf2stoch (C)
  • hb_high (Fortran)
  • wcc_getpeak (C)
  • wcc_siteamp14 (C)
  • wcc_tfilter (C)
  • wcc_resamp_arbdt (C)
  • wcc_add (C)
  • integ_diff (C)

As part of the BBP, each of these pieces of code contains a main() function, which typically works as follows:

main() {
  // Parse command-line parameters
  // Open and read input files into input data structure
  // Execute science kernel, populating output data structure
  // Open and write output files from output data structure
}

For CyberShake, we would like to be able to use the science kernels of the BBP elements, but provide CyberShake-specific parameters, pass data structures around in memory between multiple elements, and read from and write to different data formats. To accomplish this, we propose extracting the science kernels from the main() functions and creating subroutines with them, separating the I/O from the scientific calculations. Following this approach, a revised main method would contain:

main() {
  // Open and read input files into input data structure
  science_kernel_subroutine(command-line arguments, input_data_structure, output_data_structure)
  // Open and write output files from output data structure
}

science_kernel_subroutine(command-line arguments, input_data_structure, output_data_structure) {
  // Use input data structure for processing
  // Place results in output data structure
}

Then, in the CyberShake codebase, we would use this function as follows:

// Open and read input files into input data structure
// Allocate memory for output data structure
// Create parameter string with CyberShake-specific parameters for getpar to parse
science_kernel_subroutine(parameter_string, input_data_structure, output_data_structure)
// Do additional processing with output data structure
// Open and write output data structure to file

The intent is that these changes would be pushed out to the BBP codebase and also to Rob Graves, so that future revisions work from this refactored version and are straightforward to integrate with CyberShake.

Example

As an example, below we show the proposed modifications for wcc_getpeak. wcc_getpeak doesn't have an output data structure; in the BBP the result is printed, whereas in the subroutine it is returned.

Change Original code Modified code
Subroutine prototype

float wcc_getpeak(int param_string_len, char** param_string, float* seis, struct statdata* head1);

Extract science kernel into subroutine

int main(ac,av) {
...
float max = -1.0e+20;
float min = 1.0e+20;
int inbin = 0;
int outbin = 0;
int keepsign = 0;
float scale = 1.0;
...
s1 = NULL;
s1 = read_wccseis(infile,&head1,s1,inbin);
for(i=0;i<head1.nt;i++)
 {
 if(s1[i] > max)
  max = s1[i];
 if(s1[i] < min)
  min = s1[i];
 }
...

...
s1 = NULL;
s1 = read_wccseis(infile,&head1,s1,inbin);

float peak = wcc_getpeak(ac, av, s1, head1);

printf("%10.2f %13.5e %s\n",head1.edist,peak,head1.stat);
}

float wcc_getpeak(int param_string_len, char** param_string, float* s1, struct statdata* head1) {
 float max = -1.0e+20;
 float min = 1.0e+20;
 int keepsign = 0;
 float scale = 1.0;
...
 for(i=0;i<head1->nt;i++)
  {
  if(s1[i] > max)
   max = s1[i];
  if(s1[i] < min)
   min = s1[i];
  }
 ...

Relocate parsing of non-I/O parameters to subroutine

int main(ac,av) {
...
sprintf(infile,"stdin");

setpar(ac,av);
getpar("infile","s",infile);
getpar("inbin","d",&inbin);
getpar("keepsign","d",&keepsign);
getpar("scale","f",&scale);
endpar();

s1 = NULL;
s1 = read_wccseis(infile,&head1,s1,inbin);
...

float wcc_getpeak(int param_string_len, char** param_string, float* s1, struct statdata* head1) {
 float max = -1.0e+20;
 float min = 1.0e+20;
 int keepsign = 0;
 float scale = 1.0;

 setpar(param_string_len, param_string);
 getpar("keepsign","d",&keepsign);
 getpar("scale","f",&scale);
 endpar();

 for(i=0;i<head1->nt;i++)
...

Retain I/O in main function

int main(ac,av)
...
char infile[128];

float max = -1.0e+20;
float min = 1.0e+20;
int inbin = 0;
int outbin = 0;
int keepsign = 0;
float scale = 1.0;

sprintf(infile,"stdin");

setpar(ac,av);
getpar("infile","s",infile);
getpar("inbin","d",&inbin);
getpar("keepsign","d",&keepsign);
getpar("scale","f",&scale);
endpar();

s1 = NULL;
s1 = read_wccseis(infile,&head1,s1,inbin);

for(i=0;i<head1.nt;i++)
...

int main(ac,av)
...
char infile[128];

int inbin = 0;
int outbin = 0;

sprintf(infile,"stdin");

setpar(ac,av);
getpar("infile","s",infile);
getpar("inbin","d",&inbin);
endpar();

s1 = NULL;
s1 = read_wccseis(infile,&head1,s1,inbin);

float peak = wcc_getpeak(ac, av, s1, head1);

Here is a way CyberShake code could use this modified code:

...
float* seis = malloc(nt*sizeof(float));
fread(fp_in, sizeof(float), nt, seis);
struct statdata head1;
head1.nt = nt;
char** param_string = NULL;
float peak = wcc_getpeak(param_string, 0, seis, &head1);
...