/* Generic main function for the tessg* programs. */ #include #include #include #include #include "logger.h" #include "version.h" #include "grav_tess.h" #include "glq.h" #include "constants.h" #include "geometry.h" #include "parsers.h" #include "tessg_main.h" /* Print the help message for tessg* programs */ void print_tessg_help(const char *progname) { printf("Usage: %s MODELFILE [OPTIONS]\n\n", progname); if(strcmp(progname + 4, "pot") == 0) { printf("Calculate the potential due to a tesseroid model on\n"); } else { printf("Calculate the %s component due to a tesseroid model on\n", progname + 4); } printf("specified observation points.\n\n"); printf("Values are calculated in the local coordinate system of the\n"); printf("observation point: x-> North y-> East z-> Up (away from the\n"); printf("center of the Earth).\n"); printf("In order to maintain mainstream convention, component gz is\n"); printf("calculated with z-> Down.\n\n"); printf("All units either SI or degrees!\n\n"); printf("The computation of the gravitational effect of the tesseroids\n"); printf("is done using the Gauss-Legendre Quadrature (GLQ) numerical\n"); printf("integration method.\n\n"); printf("WARNING: Avoid computing directly on top or inside the\n"); printf(" tesseroids! This will break the GLQ and the formulas!\n"); printf("\n"); printf("Input:\n"); printf(" Computation points passed through standard input (stdin).\n"); printf(" Reads 3 or more values per line and inteprets the first 3 as:\n"); printf(" longitude, latitude and height\n"); printf(" of a computation points. Height should be in meters.\n"); printf(" Othervalues in the line are ignored.\n"); printf(" Lines that start with # are ignored as comments.\n"); printf(" Lines should be no longer than 10000 (ten thousand) characters."); printf("\n\n"); printf("Output:\n"); printf(" Printed to standard output (stdout) in the form:\n"); printf(" lon lat height ... result\n"); printf(" ... represents any values that were read from input and\n"); printf(" ignored. In other words, the result is appended to the last\n"); printf(" column of the input. Use this to pipe tessg* programs\n"); printf(" together.\n"); printf(" * Comments about the provenance of the data are inserted into\n"); printf(" the top of the output\n\n"); printf("MODELFILE: File containing the tesseroid model\n"); printf(" * Each tesseroid is specified by the values of its borders\n"); printf(" and density\n"); printf(" * The file should contain one tesseroid per line\n"); printf(" * Each line should have the following column format:\n"); printf(" West East South North Top Bottom Density\n"); printf(" * Top and Bottom should be read as 'height to top' and \n"); printf(" 'height to bottom' from the mean Earth radius. Use negative\n"); printf(" values if bellow the surface, for example when modeling\n"); printf(" deep structures, and positive if above the surface, for\n"); printf(" example when modeling topography.\n"); printf(" * If a line starts with # it will be considered a comment and\n"); printf(" will be ignored.\n\n"); printf("Options:\n"); printf(" -a Disable the automatic subdividing of\n"); printf(" tesseroids. Subdividing is done to ensure the\n"); printf(" GLQ gives accurate results. ONLY USE THIS\n"); printf(" OPTION IF YOU KNOW WHAT YOU ARE DOING!\n"); printf(" -tRATIO Use a custom distance-size ratio for the\n"); printf(" automatic subdivision of tesseroids. ONLY USE\n"); printf(" THIS OPTION IF YOU KNOW WHAT YOU ARE DOING!\n"); printf(" -oOLON/OLAT/OR GLQ order to use in the longitudinal,\n"); printf(" latitudinal and radial integrations,\n"); printf(" respectively. Defaults to 2/2/2.\n"); printf(" Subdividing of tesseroids works best with the\n"); printf(" default order.\n"); printf(" -h Print instructions.\n"); printf(" --version Print version and license information.\n"); printf(" -v Enable verbose printing to stderr.\n"); printf(" -lFILENAME Print log messages to file FILENAME.\n"); print_copyright(); } /* Run the main for a generic tessg* program */ int run_tessg_main(int argc, char **argv, const char *progname, double (*field)(TESSEROID, double, double, double, GLQ, GLQ, GLQ), double ratio) { TESSG_ARGS args; GLQ *glq_lon, *glq_lat, *glq_r; TESSEROID *model; int modelsize, rc, line, points = 0, error_exit = 0, bad_input = 0; char buff[10000]; double lon, lat, height, res; FILE *logfile = NULL, *modelfile = NULL; time_t rawtime; clock_t tstart; struct tm * timeinfo; log_init(LOG_INFO); rc = parse_tessg_args(argc, argv, progname, &args, &print_tessg_help); if(rc == 2) { return 0; } if(rc == 1) { log_warning("Terminating due to bad input"); log_warning("Try '%s -h' for instructions", progname); return 1; } /* Set the appropriate logging level and log to file if necessary */ if(!args.verbose) { log_init(LOG_WARNING); } if(args.logtofile) { logfile = fopen(args.logfname, "w"); if(logfile == NULL) { log_error("unable to create log file %s", args.logfname); log_warning("Terminating due to bad input"); log_warning("Try '%s -h' for instructions", progname); return 1; } log_tofile(logfile, LOG_DEBUG); } /* Check if a custom distance-size ratio is given */ if(args.ratio != 0) { ratio = args.ratio; } /* Print standard verbose */ log_info("%s (Tesseroids project) %s", progname, tesseroids_version); time(&rawtime); timeinfo = localtime(&rawtime); log_info("(local time) %s", asctime(timeinfo)); log_info("Use recursive division of tesseroids: %s", args.adaptative ? "True" : "False"); log_info("Distance-size ratio for recusive division: %g", ratio); /* Make the necessary GLQ structures */ log_info("Using GLQ orders: %d lon / %d lat / %d r", args.lon_order, args.lat_order, args.r_order); glq_lon = glq_new(args.lon_order, -1, 1); glq_lat = glq_new(args.lat_order, -1, 1); glq_r = glq_new(args.r_order, -1, 1); if(glq_lon == NULL || glq_lat == NULL || glq_r == NULL) { log_error("failed to create required GLQ structures"); log_warning("Terminating due to bad input"); log_warning("Try '%s -h' for instructions", progname); if(args.logtofile) fclose(logfile); return 1; } /* Read the tesseroid model file */ log_info("Reading tesseroid model from file %s", args.modelfname); modelfile = fopen(args.modelfname, "r"); if(modelfile == NULL) { log_error("failed to open model file %s", args.modelfname); log_warning("Terminating due to bad input"); log_warning("Try '%s -h' for instructions", progname); if(args.logtofile) fclose(logfile); return 1; } model = read_tess_model(modelfile, &modelsize); fclose(modelfile); if(modelsize == 0) { log_error("tesseroid file %s is empty", args.modelfname); log_warning("Terminating due to bad input"); log_warning("Try '%s -h' for instructions", progname); if(args.logtofile) fclose(logfile); return 1; } if(model == NULL) { log_error("failed to read model from file %s", args.modelfname); log_warning("Terminating due to bad input"); log_warning("Try '%s -h' for instructions", progname); if(args.logtofile) fclose(logfile); return 1; } log_info("Total of %d tesseroid(s) read", modelsize); /* Print a header on the output with provenance information */ if(strcmp(progname + 4, "pot") == 0) { printf("# Potential calculated with %s %s:\n", progname, tesseroids_version); } else { printf("# %s component calculated with %s %s:\n", progname+4, progname, tesseroids_version); } printf("# local time: %s", asctime(timeinfo)); printf("# model file: %s (%d tesseroids)\n", args.modelfname, modelsize); printf("# GLQ order: %d lon / %d lat / %d r\n", args.lon_order, args.lat_order, args.r_order); printf("# Use recursive division of tesseroids: %s\n", args.adaptative ? "True" : "False"); printf("# Distance-size ratio for recusive division: %g\n", ratio); /* Read each computation point from stdin and calculate */ log_info("Calculating (this may take a while)..."); tstart = clock(); for(line = 1; fgets(buff, 10000, stdin) != NULL; line++) { /* Check for comments and blank lines */ if(buff[0] == '#' || buff[0] == '\r' || buff[0] == '\n') { printf("%s", buff); continue; } /* Need to remove \n and \r from end of buff first to print the result in the end */ strstrip(buff); if(sscanf(buff, "%lf %lf %lf", &lon, &lat, &height) != 3) { log_warning("bad/invalid computation point at line %d:", line); log_warning(" '%s'", buff); log_warning("skipping this line and continuing"); bad_input++; continue; } if(args.adaptative) { res = calc_tess_model_adapt(model, modelsize, lon, lat, height + MEAN_EARTH_RADIUS, glq_lon, glq_lat, glq_r, field, ratio); } else { res = calc_tess_model(model, modelsize, lon, lat, height + MEAN_EARTH_RADIUS, glq_lon, glq_lat, glq_r, field); } printf("%s %.15g\n", buff, res); points++; } if(bad_input) { log_warning("Encountered %d bad computation points which were skipped", bad_input); } if(error_exit) { log_warning("Terminating due to error in input"); log_warning("Try '%s -h' for instructions", progname); } else { log_info("Calculated on %d points in %.5g seconds", points, (double)(clock() - tstart)/CLOCKS_PER_SEC); } /* Clean up */ free(model); glq_free(glq_lon); glq_free(glq_lat); glq_free(glq_r); log_info("Done"); if(args.logtofile) fclose(logfile); return 0; }