├── .gitignore ├── source ├── 3D_Mag_Inv_Tess.o ├── compile.sh ├── obs_position.h ├── getopt_cmdline.h ├── constants.h ├── geometry.h ├── IversionMagnetic_tess_3D_V12_cmdline.cpp ├── Basic_function_general.h ├── linalg.h ├── logger.h ├── parsers.h ├── glq.h ├── Para_inv_open12.h ├── grav_tess.h ├── Basic_inv_Prepare12.h ├── Basic_Function12.h ├── Para_inv_Variable12.h └── Basic_Function_inv12.h ├── Inv_example ├── 3D_Mag_Inv_Tess.o └── para_inv_AllcomponetV12.dat ├── LICENSE.txt └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | -------------------------------------------------------------------------------- /source/3D_Mag_Inv_Tess.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KICIOLLO/3D_Mag_Inv_Tess/HEAD/source/3D_Mag_Inv_Tess.o -------------------------------------------------------------------------------- /Inv_example/3D_Mag_Inv_Tess.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KICIOLLO/3D_Mag_Inv_Tess/HEAD/Inv_example/3D_Mag_Inv_Tess.o -------------------------------------------------------------------------------- /source/compile.sh: -------------------------------------------------------------------------------- 1 | # Intel OneMKL version: 2021.03 2 | icpc IversionMagnetic_tess_3D_V12_cmdline.cpp -o 3D_Mag_Inv_Tess.o -mkl=parallel -qopenmp -std=c++11 3 | -------------------------------------------------------------------------------- /source/obs_position.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | /* 6 | Data structures for observation positions and functions that operate on them. 7 | */ 8 | 9 | #ifndef _COMPUTATIONAL_POSITION_H_ 10 | #define _COMPUTATIONAL_POSITION_H_ 11 | 12 | 13 | /* Store information on a observe position */ 14 | typedef struct obs_position_struct { 15 | /* lon, lat in degrees (WGS84 ellipsoid). height are the atitude above the Geoid */ 16 | double lon; 17 | double lat; 18 | double height; 19 | double Bx; /* x-component of ambient magnetic field */ 20 | double By; /* y-component of ambient magnetic field */ 21 | double Bz; /* z-component of ambient magnetic field */ 22 | } OBSPOS; 23 | 24 | typedef struct obs_position_mag_struct { 25 | /* lon, lat in degrees (WGS84 ellipsoid). height are the atitude above the Geoid */ 26 | double lon; 27 | double lat; 28 | double height; 29 | 30 | double deltaT; 31 | double deltaTerr; 32 | double deltaT_2; 33 | double deltaTerr_2; 34 | double deltaTHax; 35 | double deltaTerrHax; 36 | double deltaTHay; 37 | double deltaTerrHay; 38 | double deltaTZa; 39 | double deltaTerrZa; 40 | double deltaTTa; 41 | double deltaTerrTa; 42 | 43 | double Bx; /* x-component of ambient magnetic field */ 44 | double By; /* y-component of ambient magnetic field */ 45 | double Bz; /* z-component of ambient magnetic field */ 46 | } OBSMAGPOS; 47 | 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /source/getopt_cmdline.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct globalArgs_t { 4 | int ForwardOrNot; /* -F option */ 5 | int InversionOrNot; /* -I option */ 6 | int randomized; /* --randomize option */ 7 | } globalArgs; 8 | 9 | static const char *optString = "FIh?"; 10 | 11 | static const struct option longOpts[] = { 12 | { "ForwardModeling", no_argument, NULL, 'F' }, 13 | { "Inversion", no_argument, NULL, 'I' }, 14 | { "randomize", no_argument, NULL, 0 }, 15 | { "help", no_argument, NULL, 'h' }, 16 | { NULL, no_argument, NULL, 0 } 17 | }; 18 | 19 | /* Display program usage, and exit. 20 | */ 21 | void display_usage( void ) 22 | { 23 | puts( "3D_ForwModel_Inversion - 3D ForwardModeling and Inversion of Magnetic Data" ); 24 | puts( "Please input 3D_ForwModel_Inversion -h for help ~"); 25 | /* ... */ 26 | exit( EXIT_FAILURE ); 27 | } 28 | 29 | void display_help( void ) 30 | { 31 | printf("usage: 3D_ForwModel_Inversion [options]\n\n"); 32 | printf("options:\n"); 33 | printf(" -F 3D forward modeling of magnetic parameters\n"); 34 | printf(" -I 3D inversion of magnetic data (all types)\n"); 35 | printf(" -h List descriptions of available modules\n\n"); 36 | printf("Caution -F and -I can not be used simultaneously\n"); 37 | } 38 | 39 | void print_information( void ) 40 | { 41 | /* ... */ 42 | printf( "ForwardModeling: %d\n", globalArgs.ForwardOrNot ); 43 | printf( "Inversion : %d\n", globalArgs.InversionOrNot ); 44 | printf( "randomized: %d\n", globalArgs.randomized ); 45 | } -------------------------------------------------------------------------------- /Inv_example/para_inv_AllcomponetV12.dat: -------------------------------------------------------------------------------- 1 | -----Please_input_the_observed_data_file: 2 | Inv_deltaT_example_20201119.dat 3 | -----Please_input_the_[mesh]_file: 4 | Mesh_Mr_forFM_forInv_20201119.xyz 5 | -----Please_input_the_[alpha-s_-x_-y_-z]: 6 | 1 1 1 1 7 | -----Please_input_the_parameter_whether_U_need_[GCV]_to_calculate 8 | -----the_best_regularization_parameter_or_not: 9 | 1 10 | -----Please_input_the_[TYPE]_of_the_depth_weighting_function(1_for_1998_usual_weighting_and_2_for_2000_based_on_sensitivity) 11 | -----and_[uniform_altitude(z0_upward_positive)]_for_1: 12 | 2 13 | 5000 14 | -----Please_input_the_[beta_value]_of_the_depth_weighting_function_[default_value]_[3_for_1]_and_[1_for_2] 15 | -----and_[regularization_parameter]_for_THIS_inversion: 16 | 1 17 | -10.6 18 | -----Please_input_the_parameter_which_bound_constrained_method_you_choosed 19 | 2 20 | -----Please_input_the_[_reference_model]_[origin_model]_[minimum_model]_[maximum_model] 21 | 0 0.001 0 10 22 | -----Please_input_the_[parameter]_whether_using_a_spatial_weighting_function_and_[the_file's_name]: 23 | 1 24 | SpatialWeight_forInv_20201119.xyz 25 | -----Please_input_the_parameter_whether_using_a_[non_uniform_reference_model]_and_[the_file's_name]: 26 | 0 27 | ref_data.dat 28 | -----Please_input_the_parameter_whether_using_a_[non_uniform_origin_model]_and_[the_file's_name]: 29 | 0 30 | sus_ori.dat 31 | -----Please_input_the_parameter_whether_using_a_[non_uniform_minimum_model]_and_[the_file's_name]: 32 | 0 33 | sus_min.dat 34 | -----Please_input_the_parameter_whether_using_a_[non_uniform_maximum_model]_and_[the_file's_name]: 35 | 0 36 | sus_max.dat -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2012-2015, Leonardo Uieda 4 | Copyright (c) 2017-2020, Eldar Baykiev 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of Leonardo Uieda nor the names of any contributors* 18 | may be used to endorse or promote products derived from this software 19 | without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | * Contributors to the magnetic-tesseroids and original tesseroids source and binary forms, which are under BSD 3-Clause License -------------------------------------------------------------------------------- /source/constants.h: -------------------------------------------------------------------------------- 1 | /* 2 | Define constants used, like the gravitational constant and unit conversions. 3 | 4 | Values are assigned in file constants.c 5 | 6 | All values are in SI units! 7 | */ 8 | 9 | #ifndef _TESSEROIDS_CONSTANTS_H_ 10 | #define _TESSEROIDS_CONSTANTS_H_ 11 | 12 | /* Mean Earth radius [\f$ m \f$] */ 13 | const double MEAN_EARTH_RADIUS = 6371200.0; 14 | const double EARTH_RADIUS_IGRF_KM = 6371.2; 15 | 16 | /* The gravitational constant [\f$ m^3*kg^{-1}*s^{-1} \f$] */ 17 | const double G = 0.00000000006673; 18 | 19 | 20 | 21 | /* Conversion factor from SI units to Eotvos 22 | [\f$ \frac{1}{s^2} = 10^9\ Eotvos \f$] */ 23 | const double SI2EOTVOS = 1000000000.0; 24 | const double EOTVOS2SI = 0.000000001; 25 | 26 | /* Conversion factor from SI units to mGal 27 | [\f$ 1 \frac{m}{s^2} = 10^5\ mGal \f$] */ 28 | const double SI2MGAL = 100000.0; 29 | 30 | /* Pi */ 31 | #ifdef __cplusplus 32 | const double PI = 3.1415926535897932384626433832795; 33 | #else 34 | #define PI 3.1415926535897932384626433832795 35 | #endif 36 | 37 | /* minimum distance-to-size ratio for potential computations to be accurate */ 38 | const double TESSEROID_POT_SIZE_RATIO = 1.5; 39 | /* Minimum distance-to-size ratio for gravity computations to be accurate */ 40 | const double TESSEROID_GX_SIZE_RATIO = 3; 41 | const double TESSEROID_GY_SIZE_RATIO = 3; 42 | const double TESSEROID_GZ_SIZE_RATIO = 2; 43 | /* Minimum distance-to-size ratio for gravity gradient computations to be 44 | accurate */ 45 | const double TESSEROID_GXX_SIZE_RATIO = 3; 46 | const double TESSEROID_GXY_SIZE_RATIO = 4.5; 47 | const double TESSEROID_GXZ_SIZE_RATIO = 4; 48 | const double TESSEROID_GYY_SIZE_RATIO = 3; 49 | const double TESSEROID_GYZ_SIZE_RATIO = 4; 50 | const double TESSEROID_GZZ_SIZE_RATIO = 3; 51 | 52 | const double M_0 = 4 * (PI) * 0.0000001; 53 | 54 | const double DEG2RAD = (PI)/180.0; 55 | 56 | 57 | #define FALSE 0 58 | #define TRUE 1 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /source/geometry.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "constants.h" 6 | #include "logger.h" 7 | /* 8 | Data structures for geometric elements and functions that operate on them. 9 | Defines the TESSEROID, SPHERE, and PRISM structures. 10 | */ 11 | 12 | #ifndef _TESSEROIDS_GEOMETRY_H_ 13 | #define _TESSEROIDS_GEOMETRY_H_ 14 | 15 | 16 | /* Store information on a tesseroid */ 17 | typedef struct tess_struct { 18 | /* s, n, w, e in degrees. r1 and r2 are the smaller and larger radius */ 19 | double density; /* in SI units */ 20 | double w; /* western longitude border in degrees */ 21 | double e; /* eastern longitude border in degrees */ 22 | double s; /* southern latitude border in degrees */ 23 | double n; /* northern latitude border in degrees */ 24 | double top; /* top depth in SI units */ 25 | double bot; /* bottom depth in SI units */ 26 | double r1; /* smallest radius border in SI units */ 27 | double r2; /* largest radius border in SI units */ 28 | double suscept; /* magnetic susceptibility */ 29 | double Bx; /* x-component of ambient magnetic field */ 30 | double By; /* y-component of ambient magnetic field */ 31 | double Bz; /* z-component of ambient magnetic field */ 32 | //double Rx; 33 | //double Ry; 34 | //double Rz; 35 | } TESSEROID; 36 | 37 | 38 | /* Split a tesseroid into 8. */ 39 | void split_tess(TESSEROID tess, TESSEROID *split) 40 | { 41 | double dlon = 0.5*(tess.e - tess.w), 42 | dlat = 0.5*(tess.n - tess.s), 43 | dr = 0.5*(tess.r2 - tess.r1), 44 | ws[2], ss[2], r1s[2]; 45 | int i, j, k, t = 0; 46 | 47 | ws[0] = tess.w; 48 | ws[1] = tess.w + dlon; 49 | ss[0] = tess.s; 50 | ss[1] = tess.s + dlat; 51 | r1s[0] = tess.r1; 52 | r1s[1] = tess.r1 + dr; 53 | for (k = 0; k < 2; k++) 54 | { 55 | for (j = 0; j < 2; j++) 56 | { 57 | for (i = 0; i < 2; i++) 58 | { 59 | split[t].w = ws[i]; 60 | split[t].e = ws[i] + dlon; 61 | split[t].s = ss[j]; 62 | split[t].n = ss[j] + dlat; 63 | split[t].r1 = r1s[k]; 64 | split[t].r2 = r1s[k] + dr; 65 | split[t].density = tess.density; 66 | t++; 67 | } 68 | } 69 | } 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /source/IversionMagnetic_tess_3D_V12_cmdline.cpp: -------------------------------------------------------------------------------- 1 | #include "Basic_Function12.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | #ifdef MAC 6 | ccommand(argc, argv); 7 | #endif 8 | 9 | char fpara_filename[256]; // the filename of the parameter file 10 | 11 | int iarg; 12 | char args[13][MAXREAD]; 13 | 14 | for (iarg=0; iargerr_flag > 0){ 54 | cout<< " --- Error(s) exist in the parameter files: "<err_num > 0){ 61 | cout<< " --- Erros(s) exist when reading files for inversion."<err_num > 0){ 73 | cout<< " --- Erros(s) exist when reading files for inversion."< 2 | #include 3 | #include "mkl.h" 4 | // obtaining the maximum value in a double type vector 5 | double max_value_vector(int num_vector, double * value_vector, int absolute_ornot) 6 | { 7 | int i; 8 | double result; 9 | if (absolute_ornot == 0) { 10 | result = value_vector[0]; 11 | for (i = 1; i value_vector[i]) 46 | result = value_vector[i]; 47 | } 48 | } 49 | else if (absolute_ornot == 1) { 50 | result = fabs(value_vector[0]); 51 | for (i = 1; i fabs(value_vector[i])) 53 | result = fabs(value_vector[i]); 54 | } 55 | } 56 | else { 57 | cout << "Function min_value_vector : the third parameter is neither 0 nor 1, has been set as 0" << endl; 58 | result = value_vector[0]; 59 | for (i = 1; i value_vector[i]) 61 | result = value_vector[i]; 62 | } 63 | } 64 | return result; 65 | } 66 | 67 | 68 | // some functions for Wavelet transform and compression (e.g., Li and Oldenburg, 2003) 69 | // some functions for Wavelet transform and compression (e.g., Li and Oldenburg, 2003) 70 | // some functions for Wavelet transform and compression (e.g., Li and Oldenburg, 2003) 71 | // some functions for Wavelet transform and compression (e.g., Li and Oldenburg, 2003) 72 | double cal_r_wavelet_19(double * G_temp_waveletTrans, int num_vector,double relative_thrhd) 73 | { 74 | double max_G_t_w = max_value_vector(num_vector,G_temp_waveletTrans,1); 75 | double absolute_thrhd = max_G_t_w*relative_thrhd; 76 | int i,j; 77 | 78 | double ffzi = 0,ffmu = 0; 79 | for(i=0;i= abo_r){ 119 | k_max = k_min; 120 | k_min = k_min/2; 121 | r_min = cal_r_wavelet_19(G_temp_waveletTrans, num_vector, k_min); 122 | if(fabs(r_min-abo_r) <= 0.001){ 123 | result = k_min; 124 | return result; 125 | } 126 | } 127 | 128 | while(r_max <= abo_r){ 129 | k_min = k_max; 130 | k_max = k_max*2; 131 | r_max = cal_r_wavelet_19(G_temp_waveletTrans, num_vector, k_max); 132 | if(fabs(r_max-abo_r) <= 0.001){ 133 | result = k_max; 134 | return result; 135 | } 136 | } 137 | 138 | double k_min_max_2; 139 | double r_min_max_2; 140 | while(k_max - k_min > k_err_stop){ 141 | k_min_max_2 = (k_max+k_min)/2; 142 | r_min_max_2 = cal_r_wavelet_19(G_temp_waveletTrans, num_vector, k_min_max_2); 143 | 144 | if(fabs(r_min_max_2-abo_r) <= 0.001){ 145 | result = k_min_max_2; 146 | return result; 147 | } 148 | else{ 149 | if(r_min_max_2 > abo_r){ 150 | k_max = k_min_max_2; 151 | } 152 | else{ 153 | k_min = k_min_max_2; 154 | } 155 | } 156 | } 157 | 158 | k_min_max_2 = (k_max+k_min)/2; 159 | 160 | result = k_min_max_2; 161 | 162 | return result; 163 | 164 | } 165 | 166 | 167 | // Recovering a vector in one row of a sparse matrix 168 | int convertSparseMtx2Vector(double * G_T_wavelet_value,MKL_INT * columns_deltaT,MKL_INT * rowIndex_deltaT, int Nmod_waveletFull, int row_num, double * vector_extract) 169 | { 170 | int i,j; 171 | if(row_num > Nmod_waveletFull){ 172 | cout< 3 | 4 | #ifndef _LINALG_H_ 5 | #define _LINALG_H_ 6 | 7 | void conv_vect(double *vect, double lon1, double lat1, double lon2, double lat2, double *res) 8 | { 9 | double a1 = DEG2RAD * lat1; 10 | double b1 = DEG2RAD * lon1; 11 | double a2 = DEG2RAD * lat2; 12 | double b2 = DEG2RAD * lon2; 13 | 14 | double cos_a1 = cos(PI / 2.0 - a1); 15 | double sin_a1 = sin(PI / 2.0 - a1); 16 | double cos_a2 = cos(PI / 2.0 - a2); 17 | double sin_a2 = sin(PI / 2.0 - a2); 18 | 19 | double cos_b1 = cos(b1); 20 | double sin_b1 = sin(b1); 21 | double cos_b2 = cos(b2); 22 | double sin_b2 = sin(b2); 23 | 24 | double Z1[9] = { cos_b1, -sin_b1, 0.0, sin_b1, cos_b1, 0.0, 0.0, 0.0, 1.0 }; 25 | double Y1[9] = { cos_a1, 0.0, sin_a1, 0.0, 1.0, 0.0, -sin_a1, 0.0, cos_a1 }; 26 | 27 | double Z2[9] = { cos_b2, -sin_b2, 0.0, sin_b2, cos_b2, 0.0, 0.0, 0.0, 1.0 }; 28 | double Y2[9] = { cos_a2, 0.0, sin_a2, 0.0, 1.0, 0.0, -sin_a2, 0.0, cos_a2 }; 29 | 30 | double Z1Y1[9] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; 31 | double Z2Y2t[9] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; 32 | for (int i = 0; i != 3; ++i) 33 | { 34 | for (int j = 0; j != 3; ++j) 35 | { 36 | double sum1 = 0; 37 | double sum2 = 0; 38 | for (int k = 0; k != 3; ++k) 39 | { 40 | sum1 += Z1[3 * i + k] * Y1[3 * k + j]; 41 | sum2 += Z2[3 * i + k] * Y2[3 * k + j]; 42 | } 43 | Z1Y1[3 * i + j] = sum1; 44 | Z2Y2t[3 * j + i] = sum2; 45 | } 46 | } 47 | 48 | double E[9] = { -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 }; 49 | 50 | 51 | double EZ2Y2t[9]; 52 | for (int i = 0; i != 3; ++i) 53 | { 54 | for (int j = 0; j != 3; ++j) 55 | { 56 | double sum = 0; 57 | for (int k = 0; k != 3; ++k) 58 | { 59 | sum += E[3 * i + k] * Z2Y2t[3 * k + j]; 60 | } 61 | EZ2Y2t[3 * i + j] = sum; 62 | } 63 | } 64 | 65 | 66 | double EZ2Y2tZ1Y1[9]; 67 | for (int i = 0; i != 3; ++i) 68 | { 69 | for (int j = 0; j != 3; ++j) 70 | { 71 | double sum = 0; 72 | for (int k = 0; k != 3; ++k) 73 | { 74 | sum += EZ2Y2t[3 * i + k] * Z1Y1[3 * k + j]; 75 | } 76 | EZ2Y2tZ1Y1[3 * i + j] = sum; 77 | } 78 | } 79 | 80 | double EZ2Y2tZ1Y1E[9]; 81 | for (int i = 0; i != 3; ++i) 82 | { 83 | for (int j = 0; j != 3; ++j) 84 | { 85 | double sum = 0; 86 | for (int k = 0; k != 3; ++k) 87 | { 88 | sum += EZ2Y2tZ1Y1[3 * i + k] * E[3 * k + j]; 89 | } 90 | EZ2Y2tZ1Y1E[3 * i + j] = sum; 91 | } 92 | } 93 | 94 | 95 | for (int i = 0; i != 3; ++i) 96 | { 97 | res[i] = 0; 98 | for (int j = 0; j != 3; ++j) 99 | { 100 | res[i] = res[i] + EZ2Y2tZ1Y1E[3 * i + j] * vect[j]; 101 | } 102 | } 103 | 104 | return; 105 | } 106 | 107 | void conv_vect_fast(double *vect, double lon1, double lat1, double lon2, double lat2, double *res) 108 | { 109 | double a1 = DEG2RAD * lat1; 110 | double b1 = DEG2RAD * lon1; 111 | double a2 = DEG2RAD * lat2; 112 | double b2 = DEG2RAD * lon2; 113 | 114 | double cos_a1 = cos(PI / 2.0 - a1); 115 | double sin_a1 = sin(PI / 2.0 - a1); 116 | double cos_a2 = cos(PI / 2.0 - a2); 117 | double sin_a2 = sin(PI / 2.0 - a2); 118 | 119 | double cos_b1 = cos(b1); 120 | double sin_b1 = sin(b1); 121 | double cos_b2 = cos(b2); 122 | double sin_b2 = sin(b2); 123 | 124 | double Z1Y1[9] = { cos_a1*cos_b1, -sin_b1, cos_b1*sin_a1, cos_a1*sin_b1, cos_b1, sin_a1*sin_b1, -sin_a1, 0, cos_a1 }; 125 | double Z2Y2t[9] = { -cos_a2 * cos_b2, -cos_a2 * sin_b2, sin_a2, -sin_b2, cos_b2, 0, cos_b2*sin_a2, sin_a2*sin_b2, cos_a2 }; 126 | 127 | double R[9]; 128 | for (int i = 0; i != 3; ++i) 129 | { 130 | for (int j = 0; j != 3; ++j) 131 | { 132 | double sum = 0; 133 | for (int k = 0; k != 3; ++k) 134 | { 135 | sum += Z2Y2t[3 * i + k] * Z1Y1[3 * k + j]; 136 | } 137 | R[3 * i + j] = sum; 138 | } 139 | } 140 | 141 | R[0] = -R[0]; 142 | R[3] = -R[3]; 143 | R[6] = -R[6]; 144 | 145 | for (int i = 0; i != 3; ++i) 146 | { 147 | res[i] = 0; 148 | for (int j = 0; j != 3; ++j) 149 | { 150 | res[i] += R[3 * i + j] * vect[j]; 151 | } 152 | } 153 | 154 | return; 155 | } 156 | 157 | void from_loc_sphr_to_cart(double* columnvect_xyzloc, double colatitude, double longitude, double* columnvect_res) 158 | { 159 | /*IMPORTANT: this subroutine is in the coordinate system NED*/ 160 | 161 | 162 | double phi = colatitude * DEG2RAD; 163 | double lambda = longitude * DEG2RAD; 164 | 165 | double cos_phi = cos(phi); 166 | double sin_phi = sin(phi); 167 | double cos_lambda = cos(lambda); 168 | double sin_lambda = sin(lambda); 169 | 170 | double columnvect_phi_unit[3] = { -sin_phi * cos_lambda, -sin_phi * sin_lambda, cos_phi }; 171 | double columnvect_lambda_unit[3] = { -sin_lambda, cos_lambda, 0 }; 172 | double columnvect_r_unit[3] = { cos_phi*cos_lambda, cos_phi*sin_lambda, sin_phi }; 173 | 174 | columnvect_res[0] = columnvect_phi_unit[0] * columnvect_xyzloc[0] + columnvect_lambda_unit[0] * columnvect_xyzloc[1] + columnvect_r_unit[0] * columnvect_xyzloc[2]; 175 | columnvect_res[1] = columnvect_phi_unit[1] * columnvect_xyzloc[0] + columnvect_lambda_unit[1] * columnvect_xyzloc[1] + columnvect_r_unit[1] * columnvect_xyzloc[2]; 176 | columnvect_res[2] = columnvect_phi_unit[2] * columnvect_xyzloc[0] + columnvect_lambda_unit[2] * columnvect_xyzloc[1] + columnvect_r_unit[2] * columnvect_xyzloc[2]; 177 | 178 | return; 179 | } 180 | 181 | void from_cart_to_loc_sphr(double* columnvect_xyzglob, double colatitude, double longitude, double* columnvect_res) 182 | { 183 | /*IMPORTANT: this subroutine is in the coordinate system NED*/ 184 | 185 | 186 | double phi = colatitude * DEG2RAD; 187 | double lambda = longitude * DEG2RAD; 188 | 189 | double cos_phi = cos(phi); 190 | double sin_phi = sin(phi); 191 | double cos_lambda = cos(lambda); 192 | double sin_lambda = sin(lambda); 193 | 194 | double rowvect_phi_unit[3] = { -sin_phi * cos_lambda, -sin_phi * sin_lambda, cos_phi }; 195 | double rowvect_lambda_unit[3] = { -sin_lambda, cos_lambda, 0 }; 196 | double rowvect_r_unit[3] = { cos_phi*cos_lambda, cos_phi*sin_lambda, sin_phi }; 197 | 198 | columnvect_res[0] = rowvect_phi_unit[0] * columnvect_xyzglob[0] + rowvect_phi_unit[1] * columnvect_xyzglob[1] + rowvect_phi_unit[2] * columnvect_xyzglob[2]; 199 | columnvect_res[1] = rowvect_lambda_unit[0] * columnvect_xyzglob[0] + rowvect_lambda_unit[1] * columnvect_xyzglob[1] + rowvect_lambda_unit[2] * columnvect_xyzglob[2]; 200 | columnvect_res[2] = rowvect_r_unit[0] * columnvect_xyzglob[0] + rowvect_r_unit[1] * columnvect_xyzglob[1] + rowvect_r_unit[2] * columnvect_xyzglob[2]; 201 | 202 | return; 203 | } 204 | 205 | void from_loc_sphr_to_loc_sphr(double* columnvect_xyzloc, double colatitude1, double longitude1, double colatitude2, double longitude2, double* columnvect_res) 206 | { 207 | double columnvect_xyzglob[3]; 208 | from_loc_sphr_to_cart(columnvect_xyzloc, colatitude1, longitude1, columnvect_xyzglob); 209 | from_cart_to_loc_sphr(columnvect_xyzglob, colatitude2, longitude2, columnvect_res); 210 | return; 211 | } 212 | 213 | #endif 214 | -------------------------------------------------------------------------------- /source/logger.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | /* 5 | Functions to set up logging. 6 | 7 | Examples 8 | -------- 9 | 10 | Logging to stderr: 11 | 12 | #include "logger.h" 13 | 14 | void my_func(){ 15 | log_info("From my_func!\n"); 16 | } 17 | 18 | int main(){ 19 | // Enable logging to stderr in debug level 20 | // will only print messages of level DEBUG or higher 21 | log_init(LOG_DEBUG); 22 | log_debug("debug line. The code is %d", LOG_DEBUG); 23 | log_info("info line. The code is %d", LOG_INFO); 24 | log_warning("warning line. The code is %d", LOG_WARNING); 25 | log_error("error line. The code is %d", LOG_ERROR); 26 | my_func(); 27 | return 0; 28 | } 29 | 30 | will print: 31 | 32 | DEBUG: debug line. The code is 0 33 | info line. The code is 1 34 | WARNING: warning line. The code is 2 35 | ERROR: error line. The code is 3 36 | From my_func! 37 | 38 | If function log_init() is not called than logging to stderr is disabled and no 39 | messages will be printed. 40 | 41 | Logging to a file: 42 | 43 | #include 44 | #include "logger.h" 45 | 46 | void my_func(){ 47 | log_info("From my_func!\n"); 48 | log_debug("Should not appear in log file\n"); 49 | } 50 | 51 | int main(){ 52 | // Enable logging to file "log.txt" in info level 53 | // will not print DEBUG level messages 54 | // since log_init was not called, there is no logging to stderr 55 | FILE *logfile = fopen("log.txt", "w"); 56 | log_tofile(logfile, LOG_INFO); 57 | log_debug("debug line. The code is %d", LOG_DEBUG); 58 | log_info("info line. The code is %d", LOG_INFO); 59 | log_warning("warning line. The code is %d", LOG_WARNING); 60 | log_error("error line. The code is %d", LOG_ERROR); 61 | my_func(); 62 | return 0; 63 | } 64 | 65 | File log.txt will look like: 66 | 67 | info line. The code is 1 68 | WARNING: warning line. The code is 2 69 | ERROR: error line. The code is 3 70 | From my_func! 71 | 72 | Note that you can combine loggin to stderr and to a file with different 73 | levels in the same program. 74 | */ 75 | 76 | #ifndef _TESSEROIDS_LOGGER_H_ 77 | #define _TESSEROIDS_LOGGER_H_ 78 | 79 | /* Needed for definition of FILE */ 80 | #include 81 | 82 | 83 | /** Logging level for debug messages */ 84 | #define LOG_DEBUG 1 85 | /** Logging level for general information */ 86 | #define LOG_INFO 2 87 | /** Logging level for warning messages */ 88 | #define LOG_WARNING 3 89 | /** Logging level for error messages */ 90 | #define LOG_ERROR 4 91 | 92 | 93 | /** Keep the information on the global logger */ 94 | typedef struct logger_struct 95 | { 96 | int level; /**< level of logging */ 97 | int filelogging; /**< flag to know wether loggint to a file is enabled */ 98 | int file_level; /**< logging level for the file */ 99 | FILE *logfile; /**< file to log to */ 100 | 101 | } LOGGER; 102 | 103 | 104 | /** Global logger struct. Only declare in the main program! */ 105 | //LOGGER logger; 106 | 107 | 108 | /** Setup logging to stderr. 109 | 110 | @param level level of logging to be made. Can be one of: 111 | - LOG_DEBUG 112 | - LOG_INFO 113 | - LOG_WARNING 114 | - LOG_ERROR 115 | */ 116 | void log_init(int level); 117 | 118 | 119 | /** Set logging to a file. 120 | 121 | @param logfile FILE pointer to the already open file to log to. 122 | @param level level of logging to be made to the file. Can be one of: 123 | - LOG_DEBUG 124 | - LOG_INFO 125 | - LOG_WARNING 126 | - LOG_ERROR 127 | */ 128 | void log_tofile(FILE *logfile, int level); 129 | 130 | 131 | /** Log a message at debug level. 132 | 133 | Pass parameters in the same format as printf() 134 | 135 | Prints a newline at the end. 136 | */ 137 | void log_debug(const char *fmt, ...); 138 | 139 | 140 | /** Log a message at info level. 141 | 142 | Pass parameters in the same format as printf() 143 | 144 | Does not print "INFO: " in front of the message when logging 145 | 146 | Prints a newline at the end. 147 | */ 148 | void log_info(const char *fmt, ...); 149 | 150 | 151 | /** Log a message at warning level. 152 | 153 | Pass parameters in the same format as printf() 154 | 155 | Prints a newline at the end. 156 | */ 157 | void log_warning(const char *fmt, ...); 158 | 159 | 160 | /** Log a message at error level. 161 | 162 | Pass parameters in the same format as printf() 163 | 164 | Prints a newline at the end. 165 | */ 166 | void log_error(const char *fmt, ...); 167 | 168 | /* Initialize the logger so that it doesn't print by default */ 169 | LOGGER logger = { 100, 0, 100, NULL }; 170 | 171 | 172 | /* Setup logging to stderr.*/ 173 | void log_init(int level) 174 | { 175 | logger.level = level; 176 | } 177 | 178 | 179 | /* Set logging to a file. */ 180 | void log_tofile(FILE *logfile, int level) 181 | { 182 | logger.filelogging = 1; 183 | logger.logfile = logfile; 184 | logger.file_level = level; 185 | } 186 | 187 | 188 | /* Log a message at debug level */ 189 | void log_debug(const char *fmt, ...) 190 | { 191 | char msg[10000]; 192 | va_list args; 193 | va_start(args, fmt); 194 | vsprintf(msg, fmt, args); 195 | va_end(args); 196 | 197 | if (logger.level <= LOG_DEBUG) 198 | { 199 | fprintf(stderr, "DEBUG: %s\n", msg); 200 | } 201 | 202 | if (logger.filelogging && (logger.file_level <= LOG_DEBUG)) 203 | { 204 | fprintf(logger.logfile, "DEBUG: %s\n", msg); 205 | } 206 | } 207 | 208 | 209 | /* Log a message at info level */ 210 | void log_info(const char *fmt, ...) 211 | { 212 | char msg[10000]; 213 | va_list args; 214 | va_start(args, fmt); 215 | vsprintf(msg, fmt, args); 216 | va_end(args); 217 | 218 | if (logger.level <= LOG_INFO) 219 | { 220 | fprintf(stderr, "%s\n", msg); 221 | } 222 | 223 | if (logger.filelogging && logger.file_level <= LOG_INFO) 224 | { 225 | fprintf(logger.logfile, "%s\n", msg); 226 | } 227 | } 228 | 229 | 230 | /* Log a message at warning level */ 231 | void log_warning(const char *fmt, ...) 232 | { 233 | char msg[10000]; 234 | va_list args; 235 | va_start(args, fmt); 236 | vsprintf(msg, fmt, args); 237 | va_end(args); 238 | 239 | if (logger.level <= LOG_WARNING) 240 | { 241 | fprintf(stderr, "WARNING: %s\n", msg); 242 | } 243 | 244 | if (logger.filelogging && logger.file_level <= LOG_WARNING) 245 | { 246 | fprintf(logger.logfile, "WARNING: %s\n", msg); 247 | } 248 | } 249 | 250 | 251 | /* Log a message at error level */ 252 | void log_error(const char *fmt, ...) 253 | { 254 | char msg[10000]; 255 | va_list args; 256 | va_start(args, fmt); 257 | vsprintf(msg, fmt, args); 258 | va_end(args); 259 | 260 | if (logger.level <= LOG_ERROR) 261 | { 262 | fprintf(stderr, "ERROR: %s\n", msg); 263 | } 264 | 265 | if (logger.filelogging && logger.file_level <= LOG_ERROR) 266 | { 267 | fprintf(logger.logfile, "ERROR: %s\n", msg); 268 | } 269 | } 270 | #endif 271 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 3D_Mag_Inv_Tess 2 | An open-source, parallel C++ code for constrained 3D inversion magnetic data in spherical coordinates. 3 | 4 | Thanks for the below Important references: 5 | 1. The framework of this constrained 3D inversion technique is based on a series of papers and researches by Dr. Yaoguo Li, Dr. Peter Lelièvre, and Dr. Douglas Oldenburg (e.g., Li and Oldenburg, 1996, 1998, 2003; Lelièvre & Oldenburg, 2009). 6 | 2. [Eldar Baykiev](https://github.com/eldarbaykiev) provided an open-source algorithm [magnetic-tesseroids]( magnetic-tesseroids) (Baykiev et al., 2016), which we referred as the forward modelling part in this program. 7 | 3. We followed some writing styles of the NGDC's [Geomagnetic Field Modeling software for the IGRF and WMM](https://www.ngdc.noaa.gov/IAGA/vmod/igrf.html) . 8 | 9 |
  • Baykiev, E., Ebbing, J., Brönner, M., & Fabian, K. (2016). Forward modeling magnetic fields of induced and remanent magnetization in the lithosphere using tesseroids. Computers & Geosciences, 96, 124-135. doi: 10.1016/j.cageo.2016.08.004
  • 10 | 11 |
  • Lelièvre, P. G., & Oldenburg, D. W. (2009). A comprehensive study of including structural orientation information in geophysical inversions. Geophysical Journal International, 178, 623-637. doi: 10.1111/j.1365-246X.2009.04188.x
  • 12 | 13 |
  • Li, Y., & Oldenburg, D. W. (1996). 3-D inversion of magnetic data. Geophysics, 61(2), 394-408. doi: 10.1190/1.1443968
  • 14 | 15 |
  • Li, Y., & Oldenburg, D. W. (1998). 3-D inversion of gravity data. Geophysics, 63(1), 109-119. doi: 10.1190/1.1887478
  • 16 | 17 |
  • Li, Y., & Oldenburg, D. (2003). Fast inversion of large‐scale magnetic data using wavelet transforms and a logarithmic barrier method. Geophysical Journal International, 152, 251-265. doi: 10.1046/j.1365-246X.2003.01766.x
  • 18 | 19 | # Compilation Instructions 20 | ## Required software packages 21 | - Intel c++ compiler: icpc >= 2021.3.0 22 | - Intel one Math Kernel Library (>=2021.3) 23 | 24 | ## Compilation in Linux system or Windows Subsystem for Linux 25 | ```sh 26 | icpc IversionMagnetic_tess_3D_V12_cmdline.cpp -o 3D_Mag_Inv_Tess.o -mkl=parallel -qopenmp -std=c++11 27 | ``` 28 | 29 | # User Guides 30 | ## Command Line 31 | 1. For help 32 | ```sh 33 | ./3D_Mag_Inv_Tess.o h 34 | ``` 35 | 36 | 2. Using a parameter file (recommanded) 37 | ```sh 38 | ./3D_Mag_Inv_Tess.o f parameter_file 39 | ``` 40 | The parameter file's content can refer to the "para_example.dat", which includes information about the magnetic_anomaly_file, mesh_file, and parameters used for inversion. 41 | 42 | 3. Using a simple cmd line 43 | ```sh 44 | ./3D_Mag_Inv_Tess.o mag_anomaly_file mesh_file regu_para 45 | ``` 46 | Only the magnetic anomaly file, mesh file, and the used regularization parameter are used in this simple inversion, other parameters are all default values or settings. 47 | 48 | ## Parameter file 49 | ``` 50 | -----Please_input_the_observed_data_file: 51 | magnetic_anomaly_filename.extention 52 | -----Please_input_the_[mesh]_file: 53 | mesh_filename.extention 54 | -----Please_input_the_[alpha-s_-x_-y_-z]: 55 | 1 1 1 1 56 | -----Please_input_the_parameter_whether_U_need_[GCV]_to_calculate 57 | -----the_best_regularization_parameter_or_not: 58 | 1 59 | -----Please_input_the_[TYPE]_of_the_depth_weighting_function(1_for_1998_usual_weighting_and_2_for_2000_based_on_sensitivity) 60 | -----and_[uniform_altitude(z0_upward_positive)]_for_1: 61 | 2 62 | 5000 63 | -----Please_input_the_[beta_value]_of_the_depth_weighting_function_[default_value]_[3_for_1]_and_[1_for_2] 64 | -----and_[regularization_parameter]_for_THIS_inversion: 65 | 1 66 | 5.8 67 | -----Please_input_the_parameter_which_bound_constrained_method_you_choosed 68 | 2 69 | -----Please_input_the_[_reference_model]_[origin_model]_[minimum_model]_[maximum_model] 70 | 0 0.001 0 10 71 | -----Please_input_the_[parameter]_whether_using_a_spatial_weighting_function_and_[the_file's_name]: 72 | 1 73 | SpatialWeight_forInv_20201119.xyz 74 | -----Please_input_the_parameter_whether_using_a_[non_uniform_reference_model]_and_[the_file's_name]: 75 | 0 76 | ref_data.dat 77 | -----Please_input_the_parameter_whether_using_a_[non_uniform_origin_model]_and_[the_file's_name]: 78 | 0 79 | sus_ori.dat 80 | -----Please_input_the_parameter_whether_using_a_[non_uniform_minimum_model]_and_[the_file's_name]: 81 | 0 82 | sus_min.dat 83 | -----Please_input_the_parameter_whether_using_a_[non_uniform_maximum_model]_and_[the_file's_name]: 84 | 0 85 | sus_max.dat 86 | ``` 87 | **Notice**: all the lines with "-----" as beginings can not be deleted or add new lines. 88 | 89 | ## Anomaly file 90 | Eight columns are needed. 91 | (**coor_lon**, **coor_lat**, **coor_alt**) are the coordinates of the observation position of the **total-field_anomaly** whose error is **standard_deviation**. 92 | (**IGRF_x**, **IGRF_y**, **IGRF_z**) are the three components of the reference field which can be obtained using IGRF software. 93 | 94 | ``` 95 | coor_lon coor_lat coor_alt IGRF_x IGRF_y IGRF_z total-field_anomaly standard_deviation 96 | ``` 97 | For example, 98 | ``` 99 | 83.05 42.05 5000 27159.7 1042.7 47821.1 -3.86481238 1 100 | ``` 101 | 102 | ## Mesh file 103 | Eleven columns are needed. 104 | **lon_min** : western longitude border in degrees 105 | **lon_max** : eastern longitude border in degree 106 | **lat_min** : southern latitude border in degrees 107 | **lat_max** : northern latitude border in degrees 108 | **top** : top depth 109 | **bot** : bottom depth 110 | **density** : Unit value (=1000 kg/m3) 111 | **susceptibility** : Unit value (=1) 112 | **IGRF_x** : x-component of ambient magnetic field 113 | **IGRF_y** : y-component of ambient magnetic field 114 | **IGRF_z** : z-component of ambient magnetic field 115 | 116 | For example, 117 | ``` 118 | 83 83.1 42 42.1 0 -5000 1000 1 23100 1300 53000 119 | ``` 120 | 121 | **Notice**: The above coordinates in both the anomaly and the mesh file are longitudes and latitudes in a geocentric spherical coordinates system, and the altitudes are relative to the Earth's mean radius. 122 | 123 | 124 | ## Spatial weighting functions 125 | Seven columns are needed. 126 | ``` 127 | w_s w_x diff_x w_y diff_y w_z diff_z 128 | ``` 129 | 130 | ## Reference/Initial/Minimum/Maximum model 131 | Single column file of which row number equals to the number of the cells in the mesh file. 132 | 133 | # Example 134 | A folder named "Inv_example" includes parameter file, anomaly file, mesh file, and spatial weighting functions file. 135 | The number of the observation positions and the cells in mesh file are 3500 and 39287, respectively. 136 | Due to the sensitivity kernel matrices have the largest memory demand, before running an inversion test we can just estimate its demand. 137 | For example, 3500 × 39287 × 8 byte ≈ 1.025 Gb; 138 | In the present version of this software, we need four sensitivity kernel matrices with same memory demands, that are related to the three components of the anomalous vector and the total-field anomaly. 139 | Thus, for this example the total memory demand of four large matrices should be larger than 1.025 × 4 ≈ 4.1 Gb. 140 | Considering there are other smaller matrices and many temp vectors that also need space, so a hardware with memory larger than 5 Gb is recommended for running this example. 141 | 142 | 143 | # Contact 144 | Shida Sun (shidasun.cug@gmail.com, sdsun@hgu.edu.cn) 145 | -------------------------------------------------------------------------------- /source/parsers.h: -------------------------------------------------------------------------------- 1 | /* 2 | Input and output parsing tools. 3 | */ 4 | 5 | 6 | #ifndef _TESSEROIDS_PARSERS_H_ 7 | #define _TESSEROIDS_PARSERS_H_ 8 | 9 | /* Needed for definition of TESSEROID and PRISM */ 10 | #include "geometry.h" 11 | // needed for definition of OBSPOS 12 | #include "obs_position.h" 13 | /* Need for the definition of FILE */ 14 | #include 15 | #include "logger.h" 16 | // #include "version.h" 17 | #include "constants.h" 18 | /** Store basic input arguments and option flags */ 19 | typedef struct basic_args 20 | { 21 | char *inputfname; /**< name of the input file */ 22 | int verbose; /**< flag to indicate if verbose printing is enabled */ 23 | int logtofile; /**< flag to indicate if logging to a file is enabled */ 24 | char *logfname; /**< name of the log file */ 25 | } BASIC_ARGS; 26 | 27 | typedef struct tessh_args 28 | { 29 | int lon_order; /**< glq order in longitude integration */ 30 | int lat_order; /**< glq order in latitude integration */ 31 | int r_order; /**< glq order in radial integration */ 32 | char *modelfname; /**< name of the file with the tesseroid model */ 33 | int verbose; /**< flag to indicate if verbose printing is enabled */ 34 | int logtofile; /**< flag to indicate if logging to a file is enabled */ 35 | char *logfname; /**< name of the log file */ 36 | int adaptative; /**< flat to indicate wether to use the adaptative size 37 | of tesseroid algorithm */ 38 | double ratio1; /**< distance-size ratio used for recusive division */ 39 | double ratio2; /**< distance-size ratio used for recusive division */ 40 | double ratio3; /**< distance-size ratio used for recusive division */ 41 | } TESSB_ARGS; 42 | 43 | 44 | typedef struct gradcalc_args 45 | { 46 | int gridbx_set; 47 | int gridby_set; 48 | int gridbz_set; 49 | 50 | char* gridbx_fn; 51 | char* gridby_fn; 52 | char* gridbz_fn; 53 | 54 | int out_set; 55 | 56 | 57 | int bz_NEU_NED; 58 | int bz_NEU_NED_set; 59 | 60 | int verbose; /**< flag to indicate if verbose printing is enabled */ 61 | int logtofile; /**< flag to indicate if logging to a file is enabled */ 62 | 63 | } GRADCALC_ARGS; 64 | 65 | 66 | /* Strip trailing spaces and newlines from the end of a string */ 67 | void strstrip(char *str) 68 | { 69 | int i; 70 | for (i = strlen(str) - 1; i >= 0; i--) 71 | { 72 | if (str[i] != ' ' && str[i] != '\n' && str[i] != '\r' && str[i] != '\0') 73 | break; 74 | } 75 | str[i + 1] = '\0'; 76 | } 77 | 78 | 79 | /* Read a single tesseroid from a string */ 80 | int gets_mag_tess(const char *str, TESSEROID *tess) 81 | { 82 | double w, e, s, n, top, bot, dens, suscept, Bx, By, Bz, Rx, Ry, Rz; 83 | int nread, nchars; 84 | 85 | nread = sscanf(str, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf%n", &w, &e, &s, 86 | &n, &top, &bot, &dens, &suscept, &Bx, &By, &Bz, &nchars); 87 | if (nread != 11 || str[nchars] != '\0') 88 | { 89 | return 1; 90 | } 91 | tess->w = w; 92 | tess->e = e; 93 | tess->s = s; 94 | tess->n = n; 95 | tess->top = top; 96 | tess->bot = bot; 97 | tess->r1 = MEAN_EARTH_RADIUS + bot; 98 | tess->r2 = MEAN_EARTH_RADIUS + top; 99 | tess->density = dens; 100 | tess->suscept = suscept; 101 | tess->Bx = Bx; 102 | tess->By = By; 103 | tess->Bz = Bz; 104 | //tess->Rx = Rx; 105 | //tess->Ry = Ry; 106 | //tess->Rz = Rz; 107 | return 0; 108 | } 109 | 110 | 111 | 112 | //ELDAR BAYKIEV//////////////////////////////// 113 | TESSEROID * read_mag_tess_model(FILE *modelfile, unsigned long long *size) 114 | { 115 | TESSEROID *model, *tmp; 116 | unsigned long long buffsize = 300ULL; 117 | int line, badinput = 0, error_exit = 0; 118 | char sbuff[10000]; 119 | 120 | /* Start with a single buffer allocation and expand later if necessary */ 121 | model = (TESSEROID *)malloc(buffsize * sizeof(TESSEROID)); 122 | if (model == NULL) 123 | { 124 | log_error("problem allocating initial memory to load tesseroid model."); 125 | return NULL; 126 | } 127 | *size = 0ULL; 128 | for (line = 1; !feof(modelfile); line++) 129 | { 130 | if (fgets(sbuff, 10000, modelfile) == NULL) 131 | { 132 | if (ferror(modelfile)) 133 | { 134 | log_error("problem encountered reading line %d.", line); 135 | error_exit = 1; 136 | break; 137 | } 138 | } 139 | else 140 | { 141 | /* Check for comments and blank lines */ 142 | if (sbuff[0] == '#' || sbuff[0] == '\r' || sbuff[0] == '\n') 143 | { 144 | continue; 145 | } 146 | if (*size == buffsize) 147 | { 148 | buffsize += buffsize; 149 | tmp = (TESSEROID *)realloc(model, buffsize * sizeof(TESSEROID)); 150 | if (tmp == NULL) 151 | { 152 | /* Need to free because realloc leaves unchanged in case of 153 | error */ 154 | free(model); 155 | log_error("problem expanding memory for tesseroid model.\nModel is too big."); 156 | return NULL; 157 | } 158 | model = tmp; 159 | } 160 | /* Remove any trailing spaces or newlines */ 161 | strstrip(sbuff); 162 | if (gets_mag_tess(sbuff, &model[*size])) 163 | { 164 | log_warning("bad/invalid tesseroid at line %d.", line); 165 | badinput = 1; 166 | continue; 167 | } 168 | (*size)++; 169 | } 170 | } 171 | if (badinput || error_exit) 172 | { 173 | free(model); 174 | return NULL; 175 | } 176 | /* Adjust the size of the model */ 177 | if (*size != 0) 178 | { 179 | tmp = (TESSEROID *)realloc(model, (*size) * sizeof(TESSEROID)); 180 | if (tmp == NULL) 181 | { 182 | /* Need to free because realloc leaves unchanged in case of 183 | error */ 184 | free(model); 185 | log_error("problem freeing excess memory for tesseroid model."); 186 | return NULL; 187 | } 188 | model = tmp; 189 | // free(tmp); 190 | } 191 | return model; 192 | } 193 | 194 | /* Read a single rectangular prism from a string */ 195 | 196 | /* Read a single observe position from a string */ 197 | int gets_mag_obspos(const char *str, OBSPOS *obs_pos) 198 | { 199 | int nread, nchars; 200 | double lon, lat, height; 201 | double Bx, By, Bz; 202 | nread = sscanf(str, "%lf %lf %lf %lf %lf %lf%n", &lon, &lat, &height, 203 | &Bx, &By, &Bz, &nchars); 204 | if (nread != 6 || str[nchars] != '\0') 205 | { 206 | return 1; 207 | } 208 | obs_pos->lon = lon; 209 | obs_pos->lat = lat; 210 | obs_pos->height = height; 211 | obs_pos->Bx = Bx; 212 | obs_pos->By = By; 213 | obs_pos->Bz = Bz; 214 | return 0; 215 | } 216 | 217 | // SHIDA SUN //////////////////////////////// 218 | OBSPOS * read_mag_pos_position(FILE *obspos_file, unsigned long long *size) 219 | { 220 | OBSPOS *obs_pos, *tmp; 221 | unsigned long long buffsize = 300ULL; 222 | int line, badinput = 0, error_exit = 0; 223 | char sbuff[10000]; 224 | 225 | /* Start with a single buffer allocation and expand later if necessary */ 226 | obs_pos = (OBSPOS *)malloc(buffsize * sizeof(OBSPOS)); 227 | if (obs_pos == NULL) 228 | { 229 | log_error("problem allocating initial memory to load observe positions."); 230 | return NULL; 231 | } 232 | *size = 0ULL; 233 | for (line = 1; !feof(obspos_file); line++) 234 | { 235 | if (fgets(sbuff, 10000, obspos_file) == NULL) 236 | { 237 | if (ferror(obspos_file)) 238 | { 239 | log_error("problem encountered reading line %d.", line); 240 | error_exit = 1; 241 | break; 242 | } 243 | } 244 | else 245 | { 246 | /* Check for comments and blank lines */ 247 | if (sbuff[0] == '#' || sbuff[0] == '\r' || sbuff[0] == '\n') 248 | { 249 | continue; 250 | } 251 | if (*size == buffsize) 252 | { 253 | buffsize += buffsize; 254 | tmp = (OBSPOS *)realloc(obs_pos, buffsize * sizeof(OBSPOS)); 255 | if (tmp == NULL) 256 | { 257 | /* Need to free because realloc leaves unchanged in case of 258 | error */ 259 | free(obs_pos); 260 | log_error("problem expanding memory for observe positions.\nobs_pos is too big."); 261 | return NULL; 262 | } 263 | obs_pos = tmp; 264 | } 265 | /* Remove any trailing spaces or newlines */ 266 | strstrip(sbuff); 267 | if (gets_mag_obspos(sbuff, &obs_pos[*size])) 268 | { 269 | log_warning("bad/invalid OBSPOS at line %d.", line); 270 | badinput = 1; 271 | continue; 272 | } 273 | (*size)++; 274 | } 275 | } 276 | if (badinput || error_exit) 277 | { 278 | free(obs_pos); 279 | return NULL; 280 | } 281 | /* Adjust the size of the obs_pos */ 282 | if (*size != 0) 283 | { 284 | tmp = (OBSPOS *)realloc(obs_pos, (*size) * sizeof(OBSPOS)); 285 | if (tmp == NULL) 286 | { 287 | /* Need to free because realloc leaves unchanged in case of 288 | error */ 289 | free(obs_pos); 290 | log_error("problem freeing excess memory for OBSPOS obs_pos."); 291 | return NULL; 292 | } 293 | obs_pos = tmp; 294 | } 295 | return obs_pos; 296 | } 297 | 298 | 299 | /* Read a single observe position and magnetic data from a string */ 300 | int gets_mag_obspos_mag_err(const char *str, OBSMAGPOS *obs_pos_mag) 301 | { 302 | int nread, nchars; 303 | double lon, lat, height; 304 | double Bx, By, Bz; 305 | double tmp1,tmp1_err; 306 | double tmp2,tmp2_err; 307 | double tmp3,tmp3_err; 308 | double tmp4,tmp4_err; 309 | double tmp5,tmp5_err; 310 | double tmp6,tmp6_err; 311 | 312 | nread = sscanf(str, "%lf %lf %lf %lf %lf %lf %lf %lf%n", 313 | &lon, &lat, &height, &Bx, &By, &Bz, 314 | &tmp1, &tmp1_err, 315 | // &tmp2, &tmp2_err, &tmp3, &tmp3_err, 316 | // &tmp4, &tmp4_err, &tmp5, &tmp5_err, &tmp6, &tmp6_err, 317 | &nchars); 318 | 319 | if (nread != 8 || str[nchars] != '\0') 320 | { 321 | return 1; 322 | } 323 | 324 | tmp2 = 0; 325 | tmp2_err = 0; 326 | tmp3 = 0; 327 | tmp3_err = 0; 328 | 329 | tmp4 = 0; 330 | tmp4_err = 0; 331 | tmp5 = 0; 332 | tmp5_err = 0; 333 | tmp6 = 0; 334 | tmp6_err = 0; 335 | 336 | 337 | obs_pos_mag->lon = lon; 338 | obs_pos_mag->lat = lat; 339 | obs_pos_mag->height = height; 340 | obs_pos_mag->Bx = Bx; 341 | obs_pos_mag->By = By; 342 | obs_pos_mag->Bz = Bz; 343 | obs_pos_mag->deltaT = tmp1; 344 | obs_pos_mag->deltaTerr = tmp1_err; 345 | obs_pos_mag->deltaTHax = tmp2; 346 | obs_pos_mag->deltaTerrHax = tmp2_err; 347 | obs_pos_mag->deltaTHay = tmp3; 348 | obs_pos_mag->deltaTerrHay = tmp3_err; 349 | obs_pos_mag->deltaTZa = tmp4; 350 | obs_pos_mag->deltaTerrZa = tmp4_err; 351 | obs_pos_mag->deltaTTa = tmp5; 352 | obs_pos_mag->deltaTerrTa = tmp5_err; 353 | obs_pos_mag->deltaT_2 = tmp6; 354 | obs_pos_mag->deltaTerr_2 = tmp6_err; 355 | return 0; 356 | } 357 | 358 | 359 | // SHIDA SUN //////////////////////////////// 360 | OBSMAGPOS * read_mag_pos_position_magdata_err(FILE *OBSMAGPOS_file, unsigned long long *size) 361 | { 362 | OBSMAGPOS *obs_pos_mag, *tmp; 363 | unsigned long long buffsize = 300ULL; 364 | int line, badinput = 0, error_exit = 0; 365 | char sbuff[10000]; 366 | 367 | /* Start with a single buffer allocation and expand later if necessary */ 368 | obs_pos_mag = (OBSMAGPOS *)malloc(buffsize * sizeof(OBSMAGPOS)); 369 | if (obs_pos_mag == NULL) 370 | { 371 | log_error("problem allocating initial memory to load observe positions."); 372 | return NULL; 373 | } 374 | *size = 0ULL; 375 | for (line = 1; !feof(OBSMAGPOS_file); line++) 376 | { 377 | if (fgets(sbuff, 10000, OBSMAGPOS_file) == NULL) 378 | { 379 | if (ferror(OBSMAGPOS_file)) 380 | { 381 | log_error("problem encountered reading line %d.", line); 382 | error_exit = 1; 383 | break; 384 | } 385 | } 386 | else 387 | { 388 | /* Check for comments and blank lines */ 389 | if (sbuff[0] == '#' || sbuff[0] == '\r' || sbuff[0] == '\n') 390 | { 391 | continue; 392 | } 393 | if (*size == buffsize) 394 | { 395 | buffsize += buffsize; 396 | tmp = (OBSMAGPOS *)realloc(obs_pos_mag, buffsize * sizeof(OBSMAGPOS)); 397 | if (tmp == NULL) 398 | { 399 | /* Need to free because realloc leaves unchanged in case of 400 | error */ 401 | free(obs_pos_mag); 402 | log_error("problem expanding memory for observe positions.\nobs_pos_mag is too big."); 403 | return NULL; 404 | } 405 | obs_pos_mag = tmp; 406 | } 407 | /* Remove any trailing spaces or newlines */ 408 | strstrip(sbuff); 409 | if (gets_mag_obspos_mag_err(sbuff, &obs_pos_mag[*size])) 410 | { 411 | log_warning("bad/invalid OBSMAGPOS at line %d.", line); 412 | badinput = 1; 413 | continue; 414 | } 415 | (*size)++; 416 | } 417 | } 418 | if (badinput || error_exit) 419 | { 420 | free(obs_pos_mag); 421 | return NULL; 422 | } 423 | /* Adjust the size of the obs_pos_mag */ 424 | if (*size != 0) 425 | { 426 | tmp = (OBSMAGPOS *)realloc(obs_pos_mag, (*size) * sizeof(OBSMAGPOS)); 427 | if (tmp == NULL) 428 | { 429 | /* Need to free because realloc leaves unchanged in case of 430 | error */ 431 | free(obs_pos_mag); 432 | log_error("problem freeing excess memory for OBSMAGPOS obs_pos_mag."); 433 | return NULL; 434 | } 435 | obs_pos_mag = tmp; 436 | } 437 | return obs_pos_mag; 438 | } 439 | 440 | #endif 441 | -------------------------------------------------------------------------------- /source/glq.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "constants.h" 4 | #include "logger.h" 5 | /* 6 | Functions for implementing a Gauss-Legendre Quadrature numerical integration 7 | (Hildebrand, 1987). 8 | 9 | Usage example 10 | ------------- 11 | 12 | To integrate the cossine function from 0 to 90 degrees: 13 | 14 | #include 15 | #include 16 | #include 17 | #include "src/c/glq.h" 18 | 19 | int main(){ 20 | // Create a new glq structure 21 | GLQ *glq; 22 | double result = 0, a = 0, b = 0.5*3.14; 23 | int i; 24 | 25 | glq = glq_new(5, a, b); 26 | 27 | if(glq == NULL){ 28 | printf("malloc error"); 29 | return 1; 30 | } 31 | 32 | // Calculate the integral 33 | for(i = 0; i < glq->order; i++) 34 | result += glq->weights[i]*cos(glq->nodes[i]); 35 | 36 | // Need to multiply by a scale factor of the integration limits 37 | result *= 0.5*(b - a); 38 | 39 | printf("Integral of cossine from 0 to 90 degrees = %lf\n", result); 40 | 41 | // Free allocated memory 42 | glq_free(glq); 43 | 44 | return 0; 45 | } 46 | 47 | References 48 | ---------- 49 | 50 | * Hildebrand, F.B (1987): Introduction to numerical analysis. 51 | Courier Dover Publications, 2. ed. 52 | */ 53 | 54 | #ifndef _TESSEROIDS_GLQ_H_ 55 | #define _TESSEROIDS_GLQ_H_ 56 | 57 | 58 | /** \var GLQ_MAXIT 59 | Max iterations of the root-finder algorithm */ 60 | const int GLQ_MAXIT = 1000; 61 | 62 | 63 | /** \var GLQ_MAXERROR 64 | Max error allowed for the root-finder algorithm */ 65 | const double GLQ_MAXERROR = 0.000000000000001; 66 | 67 | 68 | /** Store the nodes and weights needed for a GLQ integration */ 69 | typedef struct glq_struct 70 | { 71 | int order; /**< order of the quadrature, ie number of nodes */ 72 | double *nodes; /**< abscissas or discretization points of the quadrature */ 73 | double *weights; /**< weighting coefficients of the quadrature */ 74 | double *nodes_unscaled; /**< nodes in [-1,1] interval */ 75 | } GLQ; 76 | 77 | 78 | /** Make a new GLQ structure and set all the parameters needed 79 | 80 | WARNING: Don't forget to free the memory malloced by this function using 81 | glq_free()! 82 | 83 | Prints error and warning messages using the logging.h module. 84 | 85 | @param order order of the quadrature, ie number of nodes 86 | @param lower lower integration limit 87 | @param upper upper integration limit 88 | 89 | @return GLQ data structure with the nodes and weights calculated. NULL if there 90 | was an error with allocation. 91 | */ 92 | GLQ * glq_new(int order, double lower, double upper); 93 | 94 | 95 | /** Free the memory allocated to make a GLQ structure 96 | 97 | @param glq pointer to the allocated memory 98 | */ 99 | void glq_free(GLQ *glq); 100 | 101 | 102 | /** Put the GLQ nodes to the integration limits IN PLACE. 103 | 104 | Will replace the values of glq.nodes with ones in the specified integration 105 | limits. 106 | 107 | In case the GLQ structure was created with glq_new(), the integration limits can 108 | be reset using this function. 109 | 110 | @param lower lower integration limit 111 | @param upper upper integration limit 112 | @param glq pointer to a GLQ structure created with glq_new() and with all 113 | necessary memory allocated 114 | 115 | @return Return code: 116 | - 0: if everything went OK 117 | - 1: if invalid order 118 | - 2: if NULL pointer for nodes or nodes_unscaled 119 | */ 120 | int glq_set_limits(double lower, double upper, GLQ *glq); 121 | 122 | 123 | /** Calculates the GLQ nodes using glq_next_root. 124 | 125 | Nodes will be in the [-1,1] interval. To convert them to the integration limits 126 | use glq_scale_nodes 127 | 128 | @param order order of the quadrature, ie how many nodes. Must be >= 2. 129 | @param nodes pre-allocated array to return the nodes. 130 | 131 | @return Return code: 132 | - 0: if everything went OK 133 | - 1: if invalid order 134 | - 2: if NULL pointer for nodes 135 | - 3: if number of maximum iterations was reached when calculating the root. 136 | This usually means that the desired accuracy was not achieved. Default 137 | desired accuracy is GLQ_MAXERROR. Default maximum iterations is 138 | GLQ_MAXIT. 139 | */ 140 | int glq_nodes(int order, double *nodes); 141 | 142 | 143 | /** Calculate the next Legendre polynomial root given the previous root found. 144 | 145 | Uses the root-finder algorithm of: 146 | 147 | Barrera-Figueroa, V., Sosa-Pedroza, J. and López-Bonilla, J., 2006, 148 | "Multiple root finder algorithm for Legendre and Chebyshev polynomials via 149 | Newton's method", 2006, Annales mathematicae et Informaticae, 33, pp 3-13 150 | 151 | @param initial initial estimate of the next root. I recommend the use of 152 | \f$ \cos\left(\pi\frac{(N - i - 0.25)}{N + 0.5}\right) \f$, 153 | where \f$ i \f$ is the index of the desired root 154 | @param root_index index of the desired root, starting from 0 155 | @param order order of the Legendre polynomial, ie number of roots. 156 | @param roots array with the roots found so far. Will return the next root in 157 | roots[root_index], so make sure to malloc enough space. 158 | 159 | @return Return code: 160 | - 0: if everything went OK 161 | - 1: if order is not valid 162 | - 2: if root_index is not valid (negative) 163 | - 3: if number of maximum iterations was reached when calculating the root. 164 | This usually means that the desired accuracy was not achieved. Default 165 | desired accuracy is GLQ_MAXERROR. Default maximum iterations is 166 | GLQ_MAXIT. 167 | */ 168 | int glq_next_root(double initial, int root_index, int order, 169 | double *roots); 170 | 171 | 172 | /** Calculates the weighting coefficients for the GLQ integration. 173 | 174 | @param order order of the quadrature, ie number of nodes and weights. 175 | @param nodes array containing the GLQ nodes calculated by glq_nodes. 176 | IMPORTANT: needs the nodes in [-1,1] interval! Scaled nodes 177 | will result in wrong weights! 178 | @param weights pre-allocated array to return the weights 179 | 180 | @return Return code: 181 | - 0: if everything went OK 182 | - 1: if order is not valid 183 | - 2: if nodes is a NULL pointer 184 | - 3: if weights is a NULL pointer 185 | */ 186 | int glq_weights(int order, double *nodes, double *weights); 187 | 188 | 189 | 190 | /* Make a new GLQ structure and set all the parameters needed */ 191 | GLQ * glq_new(int order, double lower, double upper) 192 | { 193 | GLQ *glq; 194 | int rc; 195 | 196 | glq = (GLQ *)malloc(sizeof(GLQ)); 197 | if (glq == NULL) 198 | { 199 | return NULL; 200 | } 201 | glq->order = order; 202 | glq->nodes = (double *)malloc(sizeof(double)*order); 203 | if (glq->nodes == NULL) 204 | { 205 | free(glq); 206 | return NULL; 207 | } 208 | glq->nodes_unscaled = (double *)malloc(sizeof(double)*order); 209 | if (glq->nodes_unscaled == NULL) 210 | { 211 | free(glq); 212 | free(glq->nodes); 213 | return NULL; 214 | } 215 | glq->weights = (double *)malloc(sizeof(double)*order); 216 | if (glq->weights == NULL) 217 | { 218 | free(glq); 219 | free(glq->nodes); 220 | free(glq->nodes_unscaled); 221 | return NULL; 222 | } 223 | rc = glq_nodes(order, glq->nodes_unscaled); 224 | if (rc != 0 && rc != 3) 225 | { 226 | switch (rc) 227 | { 228 | case 1: 229 | log_error("glq_nodes invalid GLQ order %d. Should be >= 2.", 230 | order); 231 | break; 232 | case 2: 233 | log_error("glq_nodes NULL pointer for nodes"); 234 | break; 235 | default: 236 | log_error("glq_nodes unknown error code %g", rc); 237 | break; 238 | } 239 | glq_free(glq); 240 | return NULL; 241 | } 242 | else if (rc == 3) 243 | { 244 | log_warning("glq_nodes max iterations reached in root finder"); 245 | log_warning("nodes might not have desired accuracy %g", GLQ_MAXERROR); 246 | } 247 | rc = glq_weights(order, glq->nodes_unscaled, glq->weights); 248 | if (rc != 0) 249 | { 250 | switch (rc) 251 | { 252 | case 1: 253 | log_error("glq_weights invalid GLQ order %d. Should be >= 2.", 254 | order); 255 | break; 256 | case 2: 257 | log_error("glq_weights NULL pointer for nodes"); 258 | break; 259 | case 3: 260 | log_error("glq_weights NULL pointer for weights"); 261 | break; 262 | default: 263 | log_error("glq_weights unknown error code %d\n", rc); 264 | break; 265 | } 266 | glq_free(glq); 267 | return NULL; 268 | } 269 | if (glq_set_limits(lower, upper, glq) != 0) 270 | { 271 | glq_free(glq); 272 | return NULL; 273 | } 274 | return glq; 275 | } 276 | 277 | 278 | /* Free the memory allocated to make a GLQ structure */ 279 | void glq_free(GLQ *glq) 280 | { 281 | free(glq->nodes); 282 | free(glq->nodes_unscaled); 283 | free(glq->weights); 284 | free(glq); 285 | } 286 | 287 | 288 | /* Calculates the GLQ nodes using glq_next_root. */ 289 | int glq_nodes(int order, double *nodes) 290 | { 291 | register int i; 292 | int rc = 0; 293 | double initial; 294 | 295 | if (order < 2) 296 | { 297 | return 1; 298 | } 299 | if (nodes == NULL) 300 | { 301 | return 2; 302 | } 303 | for (i = 0; i < order; i++) 304 | { 305 | initial = cos(PI*(order - i - 0.25) / (order + 0.5)); 306 | if (glq_next_root(initial, i, order, nodes) == 3) 307 | { 308 | rc = 3; 309 | } 310 | } 311 | return rc; 312 | } 313 | 314 | 315 | /* Put the GLQ nodes to the integration limits IN PLACE. */ 316 | int glq_set_limits(double lower, double upper, GLQ *glq) 317 | { 318 | /* Only calculate once to optimize the code */ 319 | double tmpplus = 0.5*(upper + lower), tmpminus = 0.5*(upper - lower); 320 | register int i; 321 | 322 | if (glq->order < 2) 323 | { 324 | return 1; 325 | } 326 | if (glq->nodes == NULL) 327 | { 328 | return 2; 329 | } 330 | if (glq->nodes_unscaled == NULL) 331 | { 332 | return 2; 333 | } 334 | for (i = 0; i < glq->order; i++) 335 | { 336 | glq->nodes[i] = tmpminus * glq->nodes_unscaled[i] + tmpplus; 337 | } 338 | return 0; 339 | } 340 | 341 | 342 | /* Calculate the next Legendre polynomial root given the previous root found. */ 343 | int glq_next_root(double initial, int root_index, int order, double *roots) 344 | { 345 | double x1, x0, pn, pn_2, pn_1, pn_line, sum; 346 | int it = 0; 347 | register int n; 348 | 349 | if (order < 2) 350 | { 351 | return 1; 352 | } 353 | if (root_index < 0 || root_index >= order) 354 | { 355 | return 2; 356 | } 357 | x1 = initial; 358 | do 359 | { 360 | x0 = x1; 361 | 362 | /* Calculate Pn(x0) */ 363 | /* Starting from P0(x) and P1(x), */ 364 | /* find the others using the recursive relation: */ 365 | /* Pn(x)=(2n-1)xPn_1(x)/n - (n-1)Pn_2(x)/n */ 366 | pn_1 = 1.; /* This is Po(x) */ 367 | pn = x0; /* and this P1(x) */ 368 | for (n = 2; n <= order; n++) 369 | { 370 | pn_2 = pn_1; 371 | pn_1 = pn; 372 | pn = (((2 * n - 1)*x0*pn_1) - ((n - 1)*pn_2)) / n; 373 | } 374 | /* Now calculate Pn'(x0) using another recursive relation: */ 375 | /* Pn'(x)=n(xPn(x)-Pn_1(x))/(x*x-1) */ 376 | pn_line = order * (x0*pn - pn_1) / (x0*x0 - 1); 377 | /* Sum the roots found so far */ 378 | for (n = 0, sum = 0; n < root_index; n++) 379 | { 380 | sum += 1. / (x0 - roots[n]); 381 | } 382 | /* Update the estimate for the root */ 383 | x1 = x0 - (double)pn / (pn_line - pn * sum); 384 | 385 | /** Compute the absolute value of x */ 386 | #define GLQ_ABS(x) ((x) < 0 ? -1*(x) : (x)) 387 | } while (GLQ_ABS(x1 - x0) > GLQ_MAXERROR && ++it <= GLQ_MAXIT); 388 | #undef GLQ_ABS 389 | 390 | roots[root_index] = x1; 391 | 392 | /* Tell the user if stagnation occurred */ 393 | if (it > GLQ_MAXIT) 394 | { 395 | return 3; 396 | } 397 | return 0; 398 | } 399 | 400 | 401 | /* Calculates the weighting coefficients for the GLQ integration. */ 402 | int glq_weights(int order, double *nodes, double *weights) 403 | { 404 | register int i, n; 405 | double xi, pn, pn_2, pn_1, pn_line; 406 | 407 | if (order < 2) 408 | { 409 | return 1; 410 | } 411 | if (nodes == NULL) 412 | { 413 | return 2; 414 | } 415 | if (weights == NULL) 416 | { 417 | return 3; 418 | } 419 | for (i = 0; i < order; i++) { 420 | 421 | xi = nodes[i]; 422 | 423 | /* Find Pn'(xi) with the recursive relation to find Pn and Pn-1: */ 424 | /* Pn(x)=(2n-1)xPn_1(x)/n - (n-1)Pn_2(x)/n */ 425 | /* Then use: Pn'(x)=n(xPn(x)-Pn_1(x))/(x*x-1) */ 426 | 427 | /* Find Pn and Pn-1 stating from P0 and P1 */ 428 | pn_1 = 1; /* This is Po(x) */ 429 | pn = xi; /* and this P1(x) */ 430 | for (n = 2; n <= order; n++) 431 | { 432 | pn_2 = pn_1; 433 | pn_1 = pn; 434 | pn = ((2 * n - 1)*xi*pn_1 - (n - 1)*pn_2) / n; 435 | } 436 | pn_line = order * (xi*pn - pn_1) / (xi*xi - 1.); 437 | /* ith weight is: wi = 2/(1 - xi^2)(Pn'(xi)^2) */ 438 | weights[i] = 2. / ((1 - xi * xi)*pn_line*pn_line); 439 | } 440 | return 0; 441 | } 442 | 443 | #endif 444 | -------------------------------------------------------------------------------- /source/Para_inv_open12.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | #define RECL 200 7 | #define MAXINBUFF RECL+14 8 | #define MAXREAD MAXINBUFF-2 9 | #define PATH MAXREAD 10 | 11 | 12 | class Para_inv_open 13 | { 14 | public: 15 | Para_inv_open(char * str_open); 16 | Para_inv_open(char args[13][MAXREAD], int argc); 17 | 18 | 19 | int Print_Log(char * fileLog); 20 | 21 | // 2022-5-26 12:30:25 This first version can only invert deltaT 22 | // The next updation would include the three components 23 | // and other quantities like Ta and deltaT_2 24 | int paraInvOrNot[6]; 25 | 26 | char fpobs_data[256]; 27 | 28 | char fmesh_data[256]; 29 | 30 | double alpha[4]; 31 | 32 | // Using GCV to determine the optimal regularinzation parameter or not 33 | int withCalGCVcurve; 34 | 35 | // altitude for depth weighting calculation, upward positive 36 | double z0_deepw_real; 37 | // type of depth weighting function, 1 for general, 2 for sensitivity based. 38 | int para_deepweight_type; 39 | double beta; 40 | double para_new; 41 | 42 | double refsus,minsus,maxsus,orisus; 43 | 44 | // para for spatial weighting functions 45 | int withspatsmooth; 46 | char fmodelsmoothfun_data[256]; 47 | 48 | int withnormweigt; 49 | char fnormweighfun_data[256]; 50 | 51 | int withrefmodel; 52 | int withorimodel; 53 | int withminmodel; 54 | int withmaxmodel; 55 | 56 | // using which method for susceptibility bound constraints 57 | // its value must be the below values! 58 | // 1. general or compulsury constraint! 59 | // 2. logarithmic barrier method (LBM, e.g., Li and Oldenburg, 2003) 60 | // 3. logarithmic transform method (e.g., Barbosa et al., 1999) 61 | int whichBoundConstrainMthd; 62 | 63 | 64 | 65 | char frefmodel[256]; 66 | char forimodel[256]; 67 | char fminmodel[256]; 68 | char fmaxmodel[256]; 69 | 70 | // 71 | int withLengthScale; 72 | int withDipAngles; 73 | 74 | char flengthscale[256]; 75 | char fdipangles[256]; 76 | 77 | int err_flag; // recording the errors 78 | 79 | ~Para_inv_open(); 80 | }; 81 | 82 | 83 | Para_inv_open::Para_inv_open(char * str_open) 84 | { 85 | FILE* fpIn = fopen(str_open, "rt"); 86 | 87 | err_flag = 0; 88 | char temp_str[256]; 89 | 90 | paraInvOrNot[0] = 1; 91 | paraInvOrNot[1] = 0; 92 | paraInvOrNot[2] = 0; 93 | paraInvOrNot[3] = 0; 94 | paraInvOrNot[4] = 0; 95 | paraInvOrNot[5] = 0; 96 | 97 | 98 | int num_invert_data = 0; 99 | fscanf(fpIn,"%s\n",temp_str); 100 | fscanf(fpIn,"%s\n",fpobs_data); 101 | cout<<"The total-field magnetic anomaly for inversion is ** "< 2 | #include "logger.h" 3 | #include "geometry.h" 4 | #include "glq.h" 5 | #include "constants.h" 6 | /* 7 | Functions that calculate the gravitational potential and its first and second 8 | derivatives for the tesseroid. 9 | 10 | The gravity gradients can be calculated using the general formula of 11 | Grombein et al. (2010). 12 | The integrals are solved using the Gauss-Legendre Quadrature rule 13 | (Asgharzadeh et al., 2007). 14 | 15 | The derivatives of the potential are made with respect to the local coordinate 16 | system x->North, y->East, z->Up (away from center of the Earth). 17 | 18 | To maintain the standard convention, only for component gz the z axis is 19 | inverted, so a positive density results in positive gz. 20 | 21 | Example 22 | ------- 23 | 24 | To calculate the gzz component due to a tesseroid on a regular grid: 25 | 26 | #include 27 | #include "glq.h"r 28 | #include "constants.h" 29 | #include "grav_tess.h" 30 | 31 | int main() 32 | { 33 | TESSEROID tess = {1000, 44, 46, -1, 1, MEAN_EARTH_RADIUS - 100000, 34 | MEAN_EARTH_RADIUS}; 35 | GLQ *glqlon, *glqlat, *glqr; 36 | double lon, lat, r = MEAN_EARTH_RADIUS + 1500000, res; 37 | int order = 8; 38 | 39 | glqlon = glq_new(order, tess.w, tess.e); 40 | glqlat = glq_new(order, tess.s, tess.n); 41 | glqr = glq_new(order, tess.r1, tess.r2); 42 | 43 | for(lat = 20; lat <= 70; lat += 0.5) 44 | { 45 | for(lon = -25; lon <= 25; lon += 0.5) 46 | { 47 | res = tess_gzz(tess, lon, lat, r, *glqlon, *glqlat, *glqr); 48 | printf("%g %g %g\n", lon, lat, res); 49 | } 50 | } 51 | 52 | glq_free(glqlon); 53 | glq_free(glqlat); 54 | glq_free(glqr); 55 | 56 | return 0; 57 | } 58 | 59 | References 60 | ---------- 61 | 62 | Asgharzadeh, M.F., von Frese, R.R.B., Kim, H.R., Leftwich, T.E. & Kim, J.W. 63 | (2007): Spherical prism gravity effects by Gauss-Legendre quadrature integration. 64 | Geophysical Journal International, 169, 1-11. 65 | 66 | Grombein, T.; Seitz, K.; Heck, B. (2010): Untersuchungen zur effizienten 67 | Berechnung topographischer Effekte auf den Gradiententensor am Fallbeispiel der 68 | Satellitengradiometriemission GOCE. 69 | KIT Scientific Reports 7547, ISBN 978-3-86644-510-9, KIT Scientific Publishing, 70 | Karlsruhe, Germany. 71 | */ 72 | 73 | #ifndef _TESSEROIDS_GRAV_TESS_H_ 74 | #define _TESSEROIDS_GRAV_TESS_H_ 75 | 76 | 77 | /* Needed for definition of TESSEROID */ 78 | #include "geometry.h" 79 | /* Needed for definition of GLQ */ 80 | #include "glq.h" 81 | 82 | 83 | /* Calculates the field of a tesseroid model at a given point. */ 84 | double calc_tess_model(TESSEROID *model, int size, double lonp, double latp, double rp, GLQ *glq_lon, GLQ *glq_lat, GLQ *glq_r, double (*field)(TESSEROID, double, double, double, GLQ, GLQ, GLQ)) 85 | { 86 | double res; 87 | int tess; 88 | 89 | res = 0; 90 | for(tess = 0; tess < size; tess++) 91 | { 92 | if(lonp >= model[tess].w && lonp <= model[tess].e && 93 | latp >= model[tess].s && latp <= model[tess].n && 94 | rp >= model[tess].r1 && rp <= model[tess].r2) 95 | { 96 | log_warning("Point (%g %g %g) is on tesseroid %d: %g %g %g %g %g %g %g. Can't guarantee accuracy.", 97 | lonp, latp, rp - MEAN_EARTH_RADIUS, tess, 98 | model[tess].w, model[tess].e, model[tess].s, 99 | model[tess].n, model[tess].r2 - MEAN_EARTH_RADIUS, 100 | model[tess].r1 - MEAN_EARTH_RADIUS, 101 | model[tess].density); 102 | } 103 | glq_set_limits(model[tess].w, model[tess].e, glq_lon); 104 | glq_set_limits(model[tess].s, model[tess].n, glq_lat); 105 | glq_set_limits(model[tess].r1, model[tess].r2, glq_r); 106 | res += field(model[tess], lonp, latp, rp, *glq_lon, *glq_lat, *glq_r); 107 | } 108 | return res; 109 | } 110 | 111 | 112 | /* Adaptatively calculate the field of a tesseroid model at a given point */ 113 | // 2018-4-12 11:52:39 可以自适应的剖分 Tesseroid 114 | double calc_tess_model_adapt(TESSEROID *model, int size, double lonp, double latp, double rp, GLQ *glq_lon, GLQ *glq_lat, GLQ *glq_r, double (*field)(TESSEROID, double, double, double, GLQ, GLQ, GLQ), double ratio) 115 | { 116 | double res, dist, lont, latt, rt, d2r = PI/180.; 117 | int tess; 118 | TESSEROID split[8]; 119 | 120 | res = 0; 121 | for(tess = 0; tess < size; tess++) 122 | { 123 | rt = model[tess].r2; 124 | lont = 0.5*(model[tess].w + model[tess].e); 125 | latt = 0.5*(model[tess].s + model[tess].n); 126 | dist = sqrt(rp*rp + rt*rt - 2*rp*rt*(sin(d2r*latp)*sin(d2r*latt) + 127 | cos(d2r*latp)*cos(d2r*latt)*cos(d2r*(lonp - lont)))); 128 | 129 | /* Would get stuck in infinite loop if dist = 0 and get wrong results if 130 | inside de tesseroid. Still do the calculation but warn user that it's 131 | probably wrong. */ 132 | if(lonp >= model[tess].w && lonp <= model[tess].e && 133 | latp >= model[tess].s && latp <= model[tess].n && 134 | rp >= model[tess].r1 && rp <= model[tess].r2) 135 | { 136 | log_warning("Point (%g %g %g) is on top of tesseroid %d: %g %g %g %g %g %g %g. Can't guarantee accuracy.", 137 | lonp, latp, rp - MEAN_EARTH_RADIUS, tess, 138 | model[tess].w, model[tess].e, model[tess].s, 139 | model[tess].n, model[tess].r2 - MEAN_EARTH_RADIUS, 140 | model[tess].r1 - MEAN_EARTH_RADIUS, 141 | model[tess].density); 142 | glq_set_limits(model[tess].w, model[tess].e, glq_lon); 143 | glq_set_limits(model[tess].s, model[tess].n, glq_lat); 144 | glq_set_limits(model[tess].r1, model[tess].r2, glq_r); 145 | res += field(model[tess], lonp, latp, rp, *glq_lon, *glq_lat, 146 | *glq_r); 147 | } 148 | /* Check if the computation point is at an acceptable distance. If not 149 | split the tesseroid using the given ratio */ 150 | else if( 151 | dist < ratio*MEAN_EARTH_RADIUS*d2r*(model[tess].e - model[tess].w) || 152 | dist < ratio*MEAN_EARTH_RADIUS*d2r*(model[tess].n - model[tess].s) || 153 | dist < ratio*(model[tess].r2 - model[tess].r1)) 154 | { 155 | log_debug("Splitting tesseroid %d (%g %g %g %g %g %g %g) at point (%g %g %g) using ratio %g", 156 | tess, model[tess].w, model[tess].e, model[tess].s, 157 | model[tess].n, model[tess].r2 - MEAN_EARTH_RADIUS, 158 | model[tess].r1 - MEAN_EARTH_RADIUS, model[tess].density, 159 | lonp, latp, rp - MEAN_EARTH_RADIUS, ratio); 160 | /* Do it recursively until ratio*size is smaller than distance */ 161 | split_tess(model[tess], split); 162 | res += calc_tess_model_adapt(split, 8, lonp, latp, rp, glq_lon, 163 | glq_lat, glq_r, field, ratio); 164 | } 165 | else 166 | { 167 | glq_set_limits(model[tess].w, model[tess].e, glq_lon); 168 | glq_set_limits(model[tess].s, model[tess].n, glq_lat); 169 | glq_set_limits(model[tess].r1, model[tess].r2, glq_r); 170 | res += field(model[tess], lonp, latp, rp, *glq_lon, *glq_lat, 171 | *glq_r); 172 | } 173 | } 174 | return res; 175 | } 176 | 177 | 178 | double tess_gxx(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, 179 | GLQ glq_lat, GLQ glq_r) 180 | { 181 | double d2r = PI/180., l_sqr, kphi, coslatp, coslatc, sinlatp, sinlatc, 182 | coslon, rc, kappa, res; 183 | register int i, j, k; 184 | 185 | coslatp = cos(d2r*latp); 186 | sinlatp = sin(d2r*latp); 187 | 188 | res = 0; 189 | 190 | for(k = 0; k < glq_lon.order; k++) 191 | { 192 | for(j = 0; j < glq_lat.order; j++) 193 | { 194 | for(i = 0; i < glq_r.order; i++) 195 | { 196 | rc = glq_r.nodes[i]; 197 | sinlatc = sin(d2r*glq_lat.nodes[j]); 198 | coslatc = cos(d2r*glq_lat.nodes[j]); 199 | coslon = cos(d2r*(lonp - glq_lon.nodes[k])); 200 | 201 | l_sqr = rp*rp + rc*rc - 2*rp*rc*(sinlatp*sinlatc + 202 | coslatp*coslatc*coslon); 203 | 204 | kphi = coslatp*sinlatc - sinlatp*coslatc*coslon; 205 | 206 | kappa = rc*rc*coslatc; 207 | 208 | res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]* 209 | kappa*(3*rc*kphi*rc*kphi - l_sqr)/pow(l_sqr, 2.5); 210 | } 211 | } 212 | } 213 | 214 | res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)* 215 | (tess.r2 - tess.r1)*0.125; 216 | 217 | return res; 218 | } 219 | 220 | 221 | /* Calculates gxy caused by a tesseroid. */ 222 | double tess_gxy(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, 223 | GLQ glq_lat, GLQ glq_r) 224 | { 225 | double d2r = PI/180., l_sqr, kphi, coslatp, coslatc, sinlatp, sinlatc, 226 | coslon, sinlon, rc, kappa, deltax, deltay, res; 227 | register int i, j, k; 228 | 229 | coslatp = cos(d2r*latp); 230 | sinlatp = sin(d2r*latp); 231 | 232 | res = 0; 233 | 234 | for(k = 0; k < glq_lon.order; k++) 235 | { 236 | for(j = 0; j < glq_lat.order; j++) 237 | { 238 | for(i = 0; i < glq_r.order; i++) 239 | { 240 | rc = glq_r.nodes[i]; 241 | sinlatc = sin(d2r*glq_lat.nodes[j]); 242 | coslatc = cos(d2r*glq_lat.nodes[j]); 243 | coslon = cos(d2r*(lonp - glq_lon.nodes[k])); 244 | sinlon = sin(d2r*(glq_lon.nodes[k] - lonp)); 245 | 246 | l_sqr = rp*rp + rc*rc - 2*rp*rc*(sinlatp*sinlatc + 247 | coslatp*coslatc*coslon); 248 | 249 | kphi = coslatp*sinlatc - sinlatp*coslatc*coslon; 250 | 251 | kappa = rc*rc*coslatc; 252 | 253 | deltax = rc*kphi; 254 | 255 | deltay = rc*coslatc*sinlon; 256 | 257 | res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]* 258 | kappa*(3*deltax*deltay)/pow(l_sqr, 2.5); 259 | } 260 | } 261 | } 262 | 263 | res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)* 264 | (tess.r2 - tess.r1)*0.125; 265 | 266 | return res; 267 | } 268 | 269 | 270 | /* Calculates gxz caused by a tesseroid. */ 271 | double tess_gxz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, 272 | GLQ glq_lat, GLQ glq_r) 273 | { 274 | double d2r = PI/180., l_sqr, kphi, coslatp, coslatc, sinlatp, sinlatc, 275 | coslon, cospsi, rc, kappa, deltax, deltaz, res; 276 | register int i, j, k; 277 | 278 | coslatp = cos(d2r*latp); 279 | sinlatp = sin(d2r*latp); 280 | 281 | res = 0; 282 | 283 | for(k = 0; k < glq_lon.order; k++) 284 | { 285 | for(j = 0; j < glq_lat.order; j++) 286 | { 287 | for(i = 0; i < glq_r.order; i++) 288 | { 289 | rc = glq_r.nodes[i]; 290 | sinlatc = sin(d2r*glq_lat.nodes[j]); 291 | coslatc = cos(d2r*glq_lat.nodes[j]); 292 | coslon = cos(d2r*(lonp - glq_lon.nodes[k])); 293 | 294 | cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon; 295 | 296 | l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi; 297 | 298 | kphi = coslatp*sinlatc - sinlatp*coslatc*coslon; 299 | 300 | kappa = rc*rc*coslatc; 301 | 302 | deltax = rc*kphi; 303 | 304 | deltaz = rc*cospsi - rp; 305 | 306 | res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]* 307 | kappa*(3*deltax*deltaz)/pow(l_sqr, 2.5); 308 | } 309 | } 310 | } 311 | 312 | res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)* 313 | (tess.r2 - tess.r1)*0.125; 314 | 315 | return res; 316 | } 317 | 318 | 319 | /* Calculates gyy caused by a tesseroid. */ 320 | double tess_gyy(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, 321 | GLQ glq_lat, GLQ glq_r) 322 | { 323 | double d2r = PI/180., l_sqr, coslatp, coslatc, sinlatp, sinlatc, 324 | coslon, sinlon, rc, kappa, deltay, res; 325 | register int i, j, k; 326 | 327 | coslatp = cos(d2r*latp); 328 | sinlatp = sin(d2r*latp); 329 | 330 | res = 0; 331 | 332 | for(k = 0; k < glq_lon.order; k++) 333 | { 334 | for(j = 0; j < glq_lat.order; j++) 335 | { 336 | for(i = 0; i < glq_r.order; i++) 337 | { 338 | rc = glq_r.nodes[i]; 339 | sinlatc = sin(d2r*glq_lat.nodes[j]); 340 | coslatc = cos(d2r*glq_lat.nodes[j]); 341 | coslon = cos(d2r*(lonp - glq_lon.nodes[k])); 342 | sinlon = sin(d2r*(glq_lon.nodes[k] - lonp)); 343 | 344 | l_sqr = rp*rp + rc*rc - 2*rp*rc*(sinlatp*sinlatc + 345 | coslatp*coslatc*coslon); 346 | 347 | kappa = rc*rc*coslatc; 348 | 349 | deltay = rc*coslatc*sinlon; 350 | 351 | res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]* 352 | kappa*(3*deltay*deltay - l_sqr)/pow(l_sqr, 2.5); 353 | } 354 | } 355 | } 356 | 357 | res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)* 358 | (tess.r2 - tess.r1)*0.125; 359 | 360 | return res; 361 | } 362 | 363 | 364 | /* Calculates gyz caused by a tesseroid. */ 365 | double tess_gyz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, 366 | GLQ glq_lat, GLQ glq_r) 367 | { 368 | double d2r = PI/180., l_sqr, coslatp, coslatc, sinlatp, sinlatc, 369 | coslon, sinlon, cospsi, rc, kappa, deltay, deltaz, res; 370 | register int i, j, k; 371 | 372 | coslatp = cos(d2r*latp); 373 | sinlatp = sin(d2r*latp); 374 | 375 | res = 0; 376 | 377 | for(k = 0; k < glq_lon.order; k++) 378 | { 379 | for(j = 0; j < glq_lat.order; j++) 380 | { 381 | for(i = 0; i < glq_r.order; i++) 382 | { 383 | rc = glq_r.nodes[i]; 384 | sinlatc = sin(d2r*glq_lat.nodes[j]); 385 | coslatc = cos(d2r*glq_lat.nodes[j]); 386 | coslon = cos(d2r*(lonp - glq_lon.nodes[k])); 387 | sinlon = sin(d2r*(glq_lon.nodes[k] - lonp)); 388 | 389 | cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon; 390 | 391 | l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi; 392 | 393 | kappa = rc*rc*coslatc; 394 | 395 | deltay = rc*coslatc*sinlon; 396 | 397 | deltaz = rc*cospsi - rp; 398 | 399 | res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]* 400 | kappa*(3*deltay*deltaz)/pow(l_sqr, 2.5); 401 | } 402 | } 403 | } 404 | 405 | res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)* 406 | (tess.r2 - tess.r1)*0.125; 407 | 408 | return res; 409 | } 410 | 411 | 412 | /* Calculates gzz caused by a tesseroid. */ 413 | double tess_gzz(TESSEROID tess, double lonp, double latp, double rp, GLQ glq_lon, 414 | GLQ glq_lat, GLQ glq_r) 415 | { 416 | double d2r = PI/180., l_sqr, coslatp, coslatc, sinlatp, sinlatc, 417 | coslon, cospsi, rc, kappa, deltaz, res; 418 | register int i, j, k; 419 | 420 | coslatp = cos(d2r*latp); 421 | sinlatp = sin(d2r*latp); 422 | 423 | res = 0; 424 | 425 | for(k = 0; k < glq_lon.order; k++) 426 | { 427 | for(j = 0; j < glq_lat.order; j++) 428 | { 429 | for(i = 0; i < glq_r.order; i++) 430 | { 431 | rc = glq_r.nodes[i]; 432 | sinlatc = sin(d2r*glq_lat.nodes[j]); 433 | coslatc = cos(d2r*glq_lat.nodes[j]); 434 | coslon = cos(d2r*(lonp - glq_lon.nodes[k])); 435 | 436 | cospsi = sinlatp*sinlatc + coslatp*coslatc*coslon; 437 | 438 | l_sqr = rp*rp + rc*rc - 2*rp*rc*cospsi; 439 | 440 | kappa = rc*rc*coslatc; 441 | 442 | deltaz = rc*cospsi - rp; 443 | 444 | res += glq_lon.weights[k]*glq_lat.weights[j]*glq_r.weights[i]* 445 | kappa*(3*deltaz*deltaz - l_sqr)/pow(l_sqr, 2.5); 446 | } 447 | } 448 | } 449 | 450 | res *= SI2EOTVOS*G*tess.density*d2r*(tess.e - tess.w)*d2r*(tess.n - tess.s)* 451 | (tess.r2 - tess.r1)*0.125; 452 | 453 | return res; 454 | } 455 | 456 | 457 | #endif 458 | 459 | 460 | -------------------------------------------------------------------------------- /source/Basic_inv_Prepare12.h: -------------------------------------------------------------------------------- 1 | #include "Basic_function_general.h" 2 | #include "logger.h" 3 | #include "glq.h" 4 | #include "constants.h" 5 | #include "geometry.h" 6 | #include "parsers.h" 7 | #include "linalg.h" 8 | #include "grav_tess.h" 9 | #include "obs_position.h" 10 | #include "Basic_Function_inv12.h" 11 | 12 | #define max(x,y) ( x>y?x:y ) 13 | #define min(x,y) ( xwithspatsmooth != 0){ 35 | FILE * fpModelsmoothfun = fopen(para->fmodelsmoothfun_data,"rt"); 36 | if(fpModelsmoothfun == NULL) 37 | { 38 | printf("\nSorry!\nFailed to open the fpModelsmoothfun file"); 39 | printf( ".\n"); 40 | err_num_tmp++; 41 | } 42 | i=0ULL; 43 | while(!feof(fpModelsmoothfun)) 44 | { 45 | fscanf(fpModelsmoothfun, "%lf %lf %d %lf %d %lf %d\n",&smooth0,&smooth1,&smooth4,&smooth2,&smooth5,&smooth3,&smooth6); 46 | modelsmoothfun_s[i] = smooth0; 47 | modelsmoothfun_x[i] = smooth1; 48 | modelsmoothfun_xdiffdrct[i] = smooth4; 49 | modelsmoothfun_y[i] = smooth2; 50 | modelsmoothfun_ydiffdrct[i] = smooth5; 51 | modelsmoothfun_z[i] = smooth3; 52 | modelsmoothfun_zdiffdrct[i] = smooth6; 53 | i++; 54 | } 55 | fclose(fpModelsmoothfun); 56 | } 57 | else{ 58 | for(i = 0ULL;iwithnormweigt == 1){ 74 | FILE * fpNormweighfun = fopen(para->fnormweighfun_data,"rt"); 75 | if(fpNormweighfun == NULL) 76 | { 77 | printf("\nSorry!\nFailed to open the fpNormweighfun file"); 78 | printf( ".\n"); 79 | err_num_tmp++; 80 | } 81 | i=0ULL; 82 | while(!feof(fpNormweighfun)) 83 | { 84 | fscanf(fpNormweighfun, "%lf %lf %lf %lf %lf %lf %lf %lf\n",&norms1,&norme1,&normm1,&normm2,&normm3,&normm4,&normm5,&normm6); 85 | p1[i] = 2; 86 | epsilon1[i] = 0.0001; 87 | p2[i] = norms1; 88 | epsilon2[i] = norme1; 89 | px2[i] = normm1; 90 | epsilonx2[i] = normm2; 91 | py2[i] = normm3; 92 | epsilony2[i] = normm4; 93 | pz2[i] = normm5; 94 | epsilonz2[i] = normm6; 95 | 96 | i++; 97 | } 98 | fclose(fpNormweighfun); 99 | } 100 | else{ 101 | for(i = 0ULL;iwithrefmodel == 1){ 119 | FILE * fprefmodel = fopen(para->frefmodel,"rt"); 120 | if(fprefmodel == NULL) 121 | { 122 | printf("\nSorry!\nFailed to open the fprefmodel file"); 123 | printf( ".\n"); 124 | err_num_tmp++; 125 | } 126 | i=0ULL; 127 | while(!feof(fprefmodel)) 128 | { 129 | fscanf(fprefmodel, "%lf\n",&refmdl1); 130 | m_ref_n[i] = refmdl1; 131 | i++; 132 | } 133 | fclose(fprefmodel); 134 | } 135 | else{ 136 | #pragma omp parallel for shared(N_mod,m_ref_n) private(i) 137 | for (i=0ULL;irefsus; 139 | } 140 | 141 | if(para->withorimodel == 1){ 142 | FILE * fporimodel = fopen(para->forimodel,"rt"); 143 | if(fporimodel == NULL) 144 | { 145 | printf("\nSorry!\nFailed to open the fporimodel file"); 146 | printf( ".\n"); 147 | err_num_tmp++; 148 | } 149 | i=0ULL; 150 | while(!feof(fporimodel)) 151 | { 152 | fscanf(fporimodel, "%lf\n",&orimdl1); 153 | m_0_n[i] = orimdl1; 154 | i++; 155 | } 156 | fclose(fporimodel); 157 | } 158 | else{ 159 | #pragma omp parallel for shared(N_mod,m_0_n) private(i) 160 | for (i=0ULL;iorisus; 162 | } 163 | 164 | if(para->withminmodel == 1){ 165 | FILE * fpminmodel = fopen(para->fminmodel,"rt"); 166 | if(fpminmodel == NULL) 167 | { 168 | printf("\nSorry!\nFailed to open the fpminmodel file"); 169 | printf( ".\n"); 170 | err_num_tmp++; 171 | } 172 | i=0ULL; 173 | while(!feof(fpminmodel)) 174 | { 175 | fscanf(fpminmodel, "%lf\n",&minmdl1); 176 | m_min_n[i] = minmdl1; 177 | i++; 178 | } 179 | fclose(fpminmodel); 180 | } 181 | else{ 182 | #pragma omp parallel for shared(N_mod,m_min_n) private(i) 183 | for (i=0ULL;iminsus; 185 | } 186 | 187 | if(para->withmaxmodel == 1){ 188 | FILE * fpmaxmodel = fopen(para->fmaxmodel,"rt"); 189 | if(fpmaxmodel == NULL) 190 | { 191 | printf("\nSorry!\nFailed to open the fpmaxmodel file"); 192 | printf( ".\n"); 193 | err_num_tmp++; 194 | } 195 | i=0ULL; 196 | while(!feof(fpmaxmodel)) 197 | { 198 | fscanf(fpmaxmodel, "%lf\n",&maxmdl1); 199 | m_max_n[i] = maxmdl1; 200 | i++; 201 | } 202 | fclose(fpmaxmodel); 203 | } 204 | else{ 205 | #pragma omp parallel for shared(N_mod,m_max_n) private(i) 206 | for (i=0ULL;imaxsus; 208 | } 209 | 210 | // reading the custom length scales 211 | double alphas1, alphax1, alphay1, alphaz1; 212 | if(para->withLengthScale == 1) { 213 | FILE * fpmixLengthscale = fopen(para->flengthscale,"rt"); 214 | if(fpmixLengthscale == NULL) 215 | { 216 | printf("\nSorry!\nFailed to open the fpmixLengthscale file"); 217 | printf( ".\n"); 218 | err_num_tmp++; 219 | } 220 | i=0ULL; 221 | while(!feof(fpmixLengthscale)) 222 | { 223 | fscanf(fpmixLengthscale, "%lf %lf %lf %lf\n",&alphas1,&alphax1,&alphay1,&alphaz1); 224 | m_alpha_s[i] = alphas1; 225 | m_alpha_x[i] = alphax1; 226 | m_alpha_y[i] = alphay1; 227 | m_alpha_z[i] = alphaz1; 228 | i++; 229 | } 230 | fclose(fpmixLengthscale); 231 | } 232 | else{ 233 | #pragma omp parallel for shared(N_mod,m_alpha_s,m_alpha_x,m_alpha_y,m_alpha_z) private(i) 234 | for (i=0ULL;ialpha[0]; 236 | m_alpha_x[i] = para->alpha[1]; 237 | m_alpha_y[i] = para->alpha[2]; 238 | m_alpha_z[i] = para->alpha[3]; 239 | } 240 | } 241 | 242 | 243 | // reading the custom dipping information 244 | double angle_phi1, angle_theta1, angle_psi1; 245 | if(para->withDipAngles == 1) { 246 | FILE * fpdipinfofile = fopen(para->fdipangles,"rt"); 247 | if(fpdipinfofile == NULL) 248 | { 249 | printf("\nSorry!\nFailed to open the fpdipinfofile file"); 250 | printf( ".\n"); 251 | err_num_tmp++; 252 | } 253 | i=0ULL; 254 | while(!feof(fpdipinfofile)) 255 | { 256 | fscanf(fpdipinfofile, "%lf %lf %lf\n",&angle_phi1,&angle_theta1,&angle_psi1); 257 | m_angle_phi[i] = angle_phi1; 258 | m_angle_theta[i] = angle_theta1; 259 | m_angle_psi[i] = angle_psi1; 260 | i++; 261 | } 262 | fclose(fpdipinfofile); 263 | } 264 | else{ 265 | #pragma omp parallel for shared(N_mod,m_angle_phi,m_angle_theta,m_angle_psi) private(i) 266 | for (i=0ULL;i= 60) 318 | break; 319 | 320 | if(j == i) 321 | continue; 322 | 323 | center_lon_j = (model[j].w + model[j].e)/2; 324 | center_lat_j = (model[j].s + model[j].n)/2; 325 | center_depth_j = (model[j].top + model[j].bot)/2; 326 | 327 | if ( fabs(center_lon_j - center_lon) < 1.8*tmp_spacing_lon ){ 328 | if ( fabs(center_lat_j - center_lat) < 1.8*tmp_spacing_lat ) { 329 | if( fabs(center_depth_j - center_depth) < 1.8*tmp_spacing_depth ){ 330 | tmp_index_60[total_num_tmp] = j; 331 | tmp_distance_60[total_num_tmp] = sqrt((center_lon_j - center_lon)*(center_lon_j - center_lon)*100000*100000 332 | + (center_lat_j - center_lat)*(center_lat_j - center_lat)*100000*100000 333 | + (center_depth_j - center_depth)*(center_depth_j - center_depth)); 334 | total_num_tmp++; 335 | 336 | } 337 | } 338 | } 339 | } 340 | 341 | int j_tmp; 342 | // the index along Longitude or in the South-North direction 343 | tmp_tmp_min = 10000000000; 344 | tmp_tmp_min_index = -9999; 345 | if(modelsmoothfun_xdiffdrct[i] == 1){ 346 | for (j_tmp = 0; j_tmp < total_num_tmp; j_tmp++){ 347 | center_lat_j = (model[tmp_index_60[j_tmp]].s + model[tmp_index_60[j_tmp]].n)/2; 348 | if (center_lat_j < (center_lat-tmp_spacing_lat/2)){ 349 | if (tmp_distance_60[j_tmp] < tmp_tmp_min){ 350 | tmp_tmp_min = tmp_distance_60[j_tmp]; 351 | tmp_tmp_min_index = tmp_index_60[j_tmp]; 352 | } 353 | } 354 | } 355 | if((tmp_tmp_min/100000) < 1.2*tmp_spacing_lat){ 356 | index_lat[i] = tmp_tmp_min_index; 357 | } 358 | } 359 | else{ 360 | for (j_tmp = 0; j_tmp < total_num_tmp; j_tmp++){ 361 | center_lat_j = (model[tmp_index_60[j_tmp]].s + model[tmp_index_60[j_tmp]].n)/2; 362 | if (center_lat_j > (center_lat+tmp_spacing_lat/2)){ 363 | if (tmp_distance_60[j_tmp] < tmp_tmp_min){ 364 | tmp_tmp_min = tmp_distance_60[j_tmp]; 365 | tmp_tmp_min_index = tmp_index_60[j_tmp]; 366 | } 367 | } 368 | } 369 | if((tmp_tmp_min/100000) < 1.2*tmp_spacing_lat){ 370 | index_lat[i] = tmp_tmp_min_index; 371 | } 372 | 373 | } 374 | 375 | // the index along Latitude or in the West-East direction 376 | tmp_tmp_min = 10000000000; 377 | tmp_tmp_min_index = -9999; 378 | if(modelsmoothfun_ydiffdrct[i] == 1){ 379 | for (j_tmp = 0; j_tmp < total_num_tmp; j_tmp++){ 380 | center_lon_j = (model[tmp_index_60[j_tmp]].w + model[tmp_index_60[j_tmp]].e)/2; 381 | if (center_lon_j < (center_lon-tmp_spacing_lon/2)){ 382 | if (tmp_distance_60[j_tmp] < tmp_tmp_min){ 383 | tmp_tmp_min = tmp_distance_60[j_tmp]; 384 | tmp_tmp_min_index = tmp_index_60[j_tmp]; 385 | } 386 | } 387 | } 388 | if((tmp_tmp_min/100000) < 1.2*tmp_spacing_lon){ 389 | index_lon[i] = tmp_tmp_min_index; 390 | } 391 | } 392 | else{ 393 | for (j_tmp = 0; j_tmp < total_num_tmp; j_tmp++){ 394 | center_lon_j = (model[tmp_index_60[j_tmp]].w + model[tmp_index_60[j_tmp]].e)/2; 395 | if (center_lon_j > (center_lon+tmp_spacing_lon/2)){ 396 | if (tmp_distance_60[j_tmp] < tmp_tmp_min){ 397 | tmp_tmp_min = tmp_distance_60[j_tmp]; 398 | tmp_tmp_min_index = tmp_index_60[j_tmp]; 399 | } 400 | } 401 | } 402 | if((tmp_tmp_min/100000) < 1.2*tmp_spacing_lon){ 403 | index_lon[i] = tmp_tmp_min_index; 404 | } 405 | } 406 | 407 | // the index towards geocenter in radial direction 408 | tmp_tmp_min = 10000000000; 409 | tmp_tmp_min_index = -9999; 410 | if(modelsmoothfun_zdiffdrct[i] == 1){ 411 | for (j_tmp = 0; j_tmp < total_num_tmp; j_tmp++){ 412 | center_depth_j = (model[tmp_index_60[j_tmp]].top + model[tmp_index_60[j_tmp]].bot)/2; 413 | if (center_depth_j > (center_depth+tmp_spacing_depth/2)){ 414 | if (tmp_distance_60[j_tmp] < tmp_tmp_min){ 415 | tmp_tmp_min = tmp_distance_60[j_tmp]; 416 | tmp_tmp_min_index = tmp_index_60[j_tmp]; 417 | } 418 | } 419 | } 420 | if( tmp_tmp_min < 1.2*tmp_spacing_depth ){ 421 | index_depth[i] = tmp_tmp_min_index; 422 | } 423 | } 424 | else{ 425 | for (j_tmp = 0; j_tmp < total_num_tmp; j_tmp++){ 426 | center_depth_j = (model[tmp_index_60[j_tmp]].top + model[tmp_index_60[j_tmp]].bot)/2; 427 | if (center_depth_j < (center_depth-tmp_spacing_depth/2)){ 428 | if (tmp_distance_60[j_tmp] < tmp_tmp_min){ 429 | tmp_tmp_min = tmp_distance_60[j_tmp]; 430 | tmp_tmp_min_index = tmp_index_60[j_tmp]; 431 | } 432 | } 433 | } 434 | if( tmp_tmp_min < 1.2*tmp_spacing_depth ){ 435 | index_depth[i] = tmp_tmp_min_index; 436 | } 437 | } 438 | } 439 | } -------------------------------------------------------------------------------- /source/Basic_Function12.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "getopt_cmdline.h" 11 | 12 | #include "Para_inv_Variable12.h" 13 | #include "Functions_InvGrad_BC_lbm_12.h" 14 | #include "Functions_InvGrad_BC_barbosa3_12.h" 15 | #include "Functions_InvGrad_BC_compulsory2_12.h" 16 | 17 | using namespace std; 18 | 19 | // create a log file of which name is the time when inversion started 20 | void BuildFileFolderandFile(char * fileLog) 21 | { 22 | time_t timep; 23 | struct tm *p; 24 | time(&timep); 25 | p = localtime(&timep); // getting the local time 26 | int year = 1900 + p->tm_year; 27 | int month = p->tm_mon + 1; 28 | int day = p->tm_mday; 29 | int hour = p->tm_hour; 30 | int minute = p->tm_min; 31 | int second = p->tm_sec; 32 | 33 | 34 | char str_year[8]; 35 | char str_month[8]; 36 | char str_day[8]; 37 | char str_hour[8]; 38 | char str_minute[8]; 39 | char str_second[8]; 40 | 41 | 42 | memset(str_year, 0, sizeof(str_year)); 43 | sprintf(str_year, "%d", year); 44 | 45 | memset(str_month, 0, sizeof(str_month)); 46 | if (month < 10) 47 | sprintf(str_month, "%d%d", 0, month); 48 | else 49 | sprintf(str_month, "%d", month); 50 | 51 | memset(str_day, 0, sizeof(str_day)); 52 | if (day < 10) 53 | sprintf(str_day, "%d%d", 0, day); 54 | else 55 | sprintf(str_day, "%d", day); 56 | 57 | memset(str_hour, 0, sizeof(str_hour)); 58 | if (hour < 10) 59 | sprintf(str_hour, "%d%d", 0, hour); 60 | else 61 | sprintf(str_hour, "%d", hour); 62 | 63 | memset(str_minute, 0, sizeof(str_minute)); 64 | if (minute < 10) 65 | sprintf(str_minute, "%d%d", 0, minute); 66 | else 67 | sprintf(str_minute, "%d", minute); 68 | 69 | memset(str_second, 0, sizeof(str_second)); 70 | if (second < 10) 71 | sprintf(str_second, "%d%d", 0, second); 72 | else 73 | sprintf(str_second, "%d", second); 74 | 75 | memset(fileLog, 0, sizeof(fileLog)); 76 | strcpy(fileLog, str_year); 77 | strcat(fileLog, str_month); 78 | strcat(fileLog, str_day); 79 | 80 | strcat(fileLog, "_"); 81 | strcat(fileLog, str_hour); 82 | strcat(fileLog, "_"); 83 | strcat(fileLog, str_minute); 84 | strcat(fileLog, "_"); 85 | strcat(fileLog, str_second); 86 | strcat(fileLog, "_InvLog.dat"); 87 | 88 | FILE * fRstLog; 89 | fRstLog = fopen(fileLog, "a"); 90 | fprintf(fRstLog, "The Inversion Starts at %d-%s-%s %s:%s:%s\n\n\n", year, str_month, str_day, str_hour, str_minute, str_second); 91 | fclose(fRstLog); 92 | } 93 | 94 | 95 | void save_invrslt_predata_Lcrv(TESSEROID *model, OBSMAGPOS *obs_pos_mag, int N_data, int N_mod, 96 | double para_new,double * m_1_n,int * paraInvOrNot, 97 | double * deltaT_pre,double * deltaT_preHax,double * deltaT_preHay, 98 | double * deltaT_preZa,double * deltaT_preTa, 99 | double * deltaT_pre_2, 100 | double * phi_result, char * fileLog) 101 | { 102 | 103 | int i,j,k,l; 104 | 105 | char fileresult[256]; 106 | memset(fileresult, 0, sizeof(fileresult)); 107 | sprintf(fileresult,"%s_sus_result.dat",fileLog); 108 | 109 | 110 | ofstream ftemp1; 111 | ftemp1.open(fileresult); 112 | for (j=0; jPrint_Log(fileLog); 194 | 195 | clock_t start,finish; 196 | start = clock(); 197 | int i,j,k,l; 198 | int N_data = ParaVariable->N_data; 199 | int N_mod = ParaVariable->N_mod; 200 | 201 | double phi_result[4]; 202 | double * deltaT_pre = new double [N_data]; 203 | 204 | double * deltaT_preHax = new double [N_data]; 205 | double * deltaT_preHay = new double [N_data]; 206 | double * deltaT_preZa = new double [N_data]; 207 | double * deltaT_preTa = new double [N_data]; 208 | 209 | double * deltaT_pre_2 = new double [N_data]; 210 | 211 | double * m_0_n1 = new double [N_mod]; 212 | double * m_1_n = new double [N_mod]; 213 | 214 | double para_new; 215 | 216 | 217 | #pragma omp parallel for shared(m_0_n1) private(i) 218 | for(i=0;im_0_n[i]; 220 | } 221 | 222 | double miu = pow(10,paraOpen->para_new); 223 | if(paraOpen->whichBoundConstrainMthd == 1){ 224 | para_new = InversionMagSus_compulsory_noneffsto(ParaVariable->model,ParaVariable->obs_pos_mag,N_data,N_mod, 225 | paraOpen->beta,miu,ParaVariable->obs_deltaT,ParaVariable->obs_deltaTerr, 226 | ParaVariable->obs_deltaTHax,ParaVariable->obs_deltaTerrHax,ParaVariable->obs_deltaTHay,ParaVariable->obs_deltaTerrHay, 227 | ParaVariable->obs_deltaTZa,ParaVariable->obs_deltaTerrZa,ParaVariable->obs_deltaTTa,ParaVariable->obs_deltaTerrTa, 228 | ParaVariable->obs_deltaT_2,ParaVariable->obs_deltaTerr_2, 229 | ParaVariable->geomag_ref_x,ParaVariable->geomag_ref_y,ParaVariable->geomag_ref_z, 230 | paraOpen->paraInvOrNot, 231 | ParaVariable->modelsmoothfun_s,ParaVariable->modelsmoothfun_x,ParaVariable->modelsmoothfun_y,ParaVariable->modelsmoothfun_z, 232 | ParaVariable->modelsmoothfun_xdiffdrct,ParaVariable->modelsmoothfun_ydiffdrct,ParaVariable->modelsmoothfun_zdiffdrct, 233 | ParaVariable->G_THax,ParaVariable->G_THay,ParaVariable->G_TZa, 234 | ParaVariable->p1,ParaVariable->p2,ParaVariable->px2,ParaVariable->py2,ParaVariable->pz2,ParaVariable->epsilon1,ParaVariable->epsilon2, 235 | ParaVariable->epsilonx2,ParaVariable->epsilony2,ParaVariable->epsilonz2, 236 | paraOpen->alpha,ParaVariable->m_ref_n,ParaVariable->m_min_n,ParaVariable->m_max_n,m_0_n1,m_1_n,phi_result,fileLog, 237 | paraOpen->withCalGCVcurve,paraOpen->para_deepweight_type,paraOpen->z0_deepw_real, 238 | ParaVariable->m_alpha_s, ParaVariable->m_alpha_x, ParaVariable->m_alpha_y, ParaVariable->m_alpha_z, 239 | ParaVariable->m_angle_phi, ParaVariable->m_angle_theta, ParaVariable->m_angle_psi, 240 | ParaVariable->index_lon, ParaVariable->index_lat, ParaVariable->index_depth, 241 | ParaVariable->N_data, ParaVariable->N_mod); 242 | } 243 | else if(paraOpen->whichBoundConstrainMthd == 2){ 244 | para_new = InversionMagSus_lbm_noneffsto(ParaVariable->model,ParaVariable->obs_pos_mag,N_data,N_mod, 245 | paraOpen->beta,miu,ParaVariable->obs_deltaT,ParaVariable->obs_deltaTerr, 246 | ParaVariable->obs_deltaTHax,ParaVariable->obs_deltaTerrHax,ParaVariable->obs_deltaTHay,ParaVariable->obs_deltaTerrHay, 247 | ParaVariable->obs_deltaTZa,ParaVariable->obs_deltaTerrZa,ParaVariable->obs_deltaTTa,ParaVariable->obs_deltaTerrTa, 248 | ParaVariable->obs_deltaT_2,ParaVariable->obs_deltaTerr_2, 249 | ParaVariable->geomag_ref_x,ParaVariable->geomag_ref_y,ParaVariable->geomag_ref_z, 250 | paraOpen->paraInvOrNot, 251 | ParaVariable->modelsmoothfun_s,ParaVariable->modelsmoothfun_x,ParaVariable->modelsmoothfun_y,ParaVariable->modelsmoothfun_z, 252 | ParaVariable->modelsmoothfun_xdiffdrct,ParaVariable->modelsmoothfun_ydiffdrct,ParaVariable->modelsmoothfun_zdiffdrct, 253 | ParaVariable->G_THax,ParaVariable->G_THay,ParaVariable->G_TZa, 254 | ParaVariable->p1,ParaVariable->p2,ParaVariable->px2,ParaVariable->py2,ParaVariable->pz2,ParaVariable->epsilon1,ParaVariable->epsilon2, 255 | ParaVariable->epsilonx2,ParaVariable->epsilony2,ParaVariable->epsilonz2, 256 | paraOpen->alpha,ParaVariable->m_ref_n,ParaVariable->m_min_n,ParaVariable->m_max_n,m_0_n1,m_1_n,phi_result,fileLog, 257 | paraOpen->withCalGCVcurve,paraOpen->para_deepweight_type,paraOpen->z0_deepw_real, 258 | ParaVariable->m_alpha_s,ParaVariable->m_alpha_x,ParaVariable->m_alpha_y,ParaVariable->m_alpha_z, 259 | ParaVariable->m_angle_phi,ParaVariable->m_angle_theta,ParaVariable->m_angle_psi, 260 | ParaVariable->index_lon, ParaVariable->index_lat, ParaVariable->index_depth, 261 | ParaVariable->N_data, ParaVariable->N_mod); 262 | } 263 | else if(paraOpen->whichBoundConstrainMthd == 3){ 264 | para_new = InversionMagSus_Barbosa_noneffsto(ParaVariable->model,ParaVariable->obs_pos_mag,N_data,N_mod, 265 | paraOpen->beta,miu,ParaVariable->obs_deltaT,ParaVariable->obs_deltaTerr, 266 | ParaVariable->obs_deltaTHax,ParaVariable->obs_deltaTerrHax,ParaVariable->obs_deltaTHay,ParaVariable->obs_deltaTerrHay, 267 | ParaVariable->obs_deltaTZa,ParaVariable->obs_deltaTerrZa,ParaVariable->obs_deltaTTa,ParaVariable->obs_deltaTerrTa, 268 | ParaVariable->obs_deltaT_2,ParaVariable->obs_deltaTerr_2, 269 | ParaVariable->geomag_ref_x,ParaVariable->geomag_ref_y,ParaVariable->geomag_ref_z, 270 | paraOpen->paraInvOrNot, 271 | ParaVariable->modelsmoothfun_s,ParaVariable->modelsmoothfun_x,ParaVariable->modelsmoothfun_y,ParaVariable->modelsmoothfun_z, 272 | ParaVariable->modelsmoothfun_xdiffdrct,ParaVariable->modelsmoothfun_ydiffdrct,ParaVariable->modelsmoothfun_zdiffdrct, 273 | ParaVariable->G_THax,ParaVariable->G_THay,ParaVariable->G_TZa, 274 | ParaVariable->p1,ParaVariable->p2,ParaVariable->px2,ParaVariable->py2,ParaVariable->pz2,ParaVariable->epsilon1,ParaVariable->epsilon2, 275 | ParaVariable->epsilonx2,ParaVariable->epsilony2,ParaVariable->epsilonz2, 276 | paraOpen->alpha,ParaVariable->m_ref_n,ParaVariable->m_min_n,ParaVariable->m_max_n,m_0_n1,m_1_n,phi_result,fileLog, 277 | paraOpen->withCalGCVcurve,paraOpen->para_deepweight_type,paraOpen->z0_deepw_real, 278 | ParaVariable->m_alpha_s, ParaVariable->m_alpha_x, ParaVariable->m_alpha_y, ParaVariable->m_alpha_z, 279 | ParaVariable->m_angle_phi, ParaVariable->m_angle_theta, ParaVariable->m_angle_psi, 280 | ParaVariable->index_lon, ParaVariable->index_lat, ParaVariable->index_depth, 281 | ParaVariable->N_data, ParaVariable->N_mod); 282 | } 283 | else{ 284 | cout<G_THax,ParaVariable->N_mod,m_1_n, 1, 0.0, deltaT_preHax, 1); 294 | cblas_dgemv(CblasRowMajor,CblasNoTrans,N_data,N_mod,1.0,ParaVariable->G_THay,ParaVariable->N_mod,m_1_n, 1, 0.0, deltaT_preHay, 1); 295 | cblas_dgemv(CblasRowMajor,CblasNoTrans,N_data,N_mod,1.0,ParaVariable->G_TZa,ParaVariable->N_mod,m_1_n, 1, 0.0, deltaT_preZa, 1); 296 | 297 | double cosIsinA, cosIcosA, sinI; 298 | double total_Bxyz; 299 | 300 | #pragma omp parallel for shared(N_data,deltaT_preHax,deltaT_preHay,deltaT_preZa,deltaT_preTa) private(i) 301 | for(i=0;igeomag_ref_x[i]*ParaVariable->geomag_ref_x[i] 304 | + ParaVariable->geomag_ref_y[i]*ParaVariable->geomag_ref_y[i] 305 | + ParaVariable->geomag_ref_z[i]*ParaVariable->geomag_ref_z[i]); 306 | cosIcosA = ParaVariable->geomag_ref_x[i] / total_Bxyz; 307 | cosIsinA = ParaVariable->geomag_ref_y[i] / total_Bxyz; 308 | sinI = ParaVariable->geomag_ref_z[i] / total_Bxyz; 309 | deltaT_pre[i] = deltaT_preHax[i]*cosIcosA + deltaT_preHay[i]*cosIsinA + deltaT_preZa[i]*sinI; 310 | } 311 | 312 | save_invrslt_predata_Lcrv(ParaVariable->model,ParaVariable->obs_pos_mag,N_data, N_mod, 313 | para_new,m_1_n,paraOpen->paraInvOrNot, 314 | deltaT_pre,deltaT_preHax,deltaT_preHay,deltaT_preZa,deltaT_preTa, 315 | deltaT_pre_2, 316 | phi_result,fileLog); 317 | 318 | finish = clock(); 319 | cout << "The present inversion totally cost : " << (double)(finish - start) / CLOCKS_PER_SEC << "seconds" << endl; 320 | FILE * fRstLog1; 321 | fRstLog1 = fopen(fileLog, "a"); 322 | 323 | fprintf(fRstLog1, "************************** "); 324 | fprintf(fRstLog1, "************************** \n\n"); 325 | 326 | fprintf(fRstLog1, "************************** "); 327 | fprintf(fRstLog1, "************************** \n\n"); 328 | 329 | fprintf(fRstLog1, "The present inversion totally cost : %lf seconds\n\n", (double)(finish - start) / CLOCKS_PER_SEC); 330 | fclose(fRstLog1); 331 | 332 | 333 | delete[] deltaT_pre; 334 | delete[] deltaT_pre_2; 335 | 336 | delete[] deltaT_preHax; 337 | delete[] deltaT_preHay; 338 | delete[] deltaT_preZa; 339 | delete[] deltaT_preTa; 340 | 341 | delete[] m_0_n1; 342 | delete[] m_1_n; 343 | return; 344 | } 345 | 346 | 347 | void ForwardModel_using_InvsSen(int N_data, int N_mod, TESSEROID *model, OBSMAGPOS *obs_pos, 348 | double * G_Hax, double * G_Hay, double * G_Za) 349 | { 350 | int i,j; 351 | double * mag = new double[N_mod]; 352 | for (i = 0; i < N_mod; i++) { 353 | mag[i] = model[i].suscept; 354 | } 355 | double * Hax = new double [N_data]; 356 | double * Hay = new double [N_data]; 357 | double * Za = new double [N_data]; 358 | double * deltaT = new double [N_data]; 359 | double * Ta = new double [N_data]; 360 | double * deltaT_2 = new double [N_data]; 361 | 362 | cblas_dgemv(CblasRowMajor, CblasNoTrans, N_data, N_mod, 1.0, G_Hax, N_mod, mag, 1, 0.0, Hax, 1); 363 | cblas_dgemv(CblasRowMajor, CblasNoTrans, N_data, N_mod, 1.0, G_Hay, N_mod, mag, 1, 0.0, Hay, 1); 364 | cblas_dgemv(CblasRowMajor, CblasNoTrans, N_data, N_mod, 1.0, G_Za, N_mod, mag, 1, 0.0, Za, 1); 365 | 366 | FILE * fpOut = fopen("result_deltaT_ALL_prediction.dat","w"); 367 | 368 | for(i=0; ifmesh_data); 143 | 144 | FILE *modelfile = NULL; 145 | modelfile = fopen(paraOpen->fmesh_data, "r"); 146 | 147 | model = read_mag_tess_model(modelfile, &N_mod); 148 | fclose(modelfile); 149 | if (model == NULL){ 150 | err_num++; 151 | cout<fmesh_data<<" !"<fpobs_data); 163 | 164 | FILE *obsposfile = NULL; 165 | obsposfile = fopen(paraOpen->fpobs_data, "r"); 166 | obs_pos_mag = read_mag_pos_position_magdata_err(obsposfile, &N_data); 167 | fclose(obsposfile); 168 | if (obs_pos_mag == NULL){ 169 | err_num++; 170 | cout<fpobs_data<<" !"< 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "mkl.h" 13 | 14 | #define eps1 0.00000000000000001 15 | #define random(x) (rand()%x) 16 | double Txyz_weight[3] = {1,1,1}; 17 | using namespace std; 18 | 19 | // quickly save a double vector for debugging 20 | void SaveFile_double (char * tempfilename, int num, double * result) 21 | { 22 | ofstream ftemp; 23 | ftemp.open(tempfilename); 24 | 25 | for(int i=0;i=50) 857 | u_pbb[i] = 1*Wd[i]; 858 | else 859 | u_pbb[i] = -1*Wd[i]; 860 | } 861 | 862 | 863 | double * temp_dn1 = new double[N_mod]; 864 | #pragma omp parallel for shared(N_mod, temp_dn1) private(i) 865 | for(i=0;itemp_gcv[2][1] && temp_gcv[1][1]>temp_gcv[2][1] && 1302 | temp_gcv[3][1]>temp_gcv[2][1] && temp_gcv[4][1]>temp_gcv[2][1] && temp_max > 0.5) 1303 | && sum_temp <= 20){ 1304 | temp_gcv[0][0] = temp_gcv[1][0]; 1305 | temp_gcv[0][1] = temp_gcv[1][1]; 1306 | temp_gcv[1][0] = temp_gcv[2][0]; 1307 | temp_gcv[1][1] = temp_gcv[2][1]; 1308 | temp_gcv[2][0] = temp_gcv[3][0]; 1309 | temp_gcv[2][1] = temp_gcv[3][1]; 1310 | temp_gcv[3][0] = temp_gcv[4][0]; 1311 | temp_gcv[3][1] = temp_gcv[4][1]; 1312 | 1313 | para = pow(10,temp_gcv[3][0]-2); 1314 | result_temp = cal_RegulPara_GCV_nonlinar_noneffsto(para, N_data,N_mod, G_T,Wd,obs_deltaT, 1315 | Ws,Wx, columns_x, rowIndex_x,Wy, columns_y, rowIndex_y,Wz, columns_z, rowIndex_z, 1316 | alpha,Rs,Rx,Ry,Rz,Rd,m_0_n,m_ref_n,m_alpha_s, m_alpha_x,m_alpha_y, m_alpha_z, 1317 | tran_r11,tran_r12,tran_r13,tran_r21,tran_r22,tran_r23,tran_r31,tran_r32,tran_r33); 1318 | resultfileGCV<= 20) 1333 | interuptOrnot = 1; 1334 | 1335 | double miu; 1336 | if(interuptOrnot == 0){ 1337 | double i_temp; 1338 | for(i_temp=temp_gcv[4][0]+0.5;i_temp= 60 && theta <= 120 && theta2 < 256){ 1446 | min_para = regpara[i]; 1447 | break; 1448 | } 1449 | } 1450 | 1451 | cout<<"The optimal regularization parameter is 10 ^ "<