diff --git a/.gitattributes b/.gitattributes index 69e400e494cf50de55f77b250d4bd1d7b6accbf6..1c65e282edbd35be2ee64a2a94967c420a0df675 100644 --- a/.gitattributes +++ b/.gitattributes @@ -186,10 +186,11 @@ CEP/Calibration/ExpIon/CMakeLists.txt -text CEP/Calibration/ExpIon/src/CMakeLists.txt -text CEP/Calibration/ExpIon/src/__init__.py -text CEP/Calibration/ExpIon/src/acalc.py -text +CEP/Calibration/ExpIon/src/baselinefitting.cc -text +CEP/Calibration/ExpIon/src/baselinefitting.py -text CEP/Calibration/ExpIon/src/calibrate-ion -text CEP/Calibration/ExpIon/src/client.py -text CEP/Calibration/ExpIon/src/error.py -text -CEP/Calibration/ExpIon/src/fitting.cc -text CEP/Calibration/ExpIon/src/format.py -text CEP/Calibration/ExpIon/src/io.py -text CEP/Calibration/ExpIon/src/ionosphere.py -text diff --git a/CEP/Calibration/ExpIon/src/CMakeLists.txt b/CEP/Calibration/ExpIon/src/CMakeLists.txt index 8f8090bc197c5ec79be66f4ffa606551ef800019..109a238bcc7224acb4e3620424011d8ac88aac9c 100644 --- a/CEP/Calibration/ExpIon/src/CMakeLists.txt +++ b/CEP/Calibration/ExpIon/src/CMakeLists.txt @@ -2,6 +2,20 @@ include(PythonInstall) +install(PROGRAMS calibrate-ion readms-part.sh readms-part.py parmdbwriter.py DESTINATION bin) + +lofar_add_library(_baselinefitting MODULE baselinefitting.cc) + +set_target_properties(_baselinefitting PROPERTIES + PREFIX "" + LIBRARY_OUTPUT_DIRECTORY ${PYTHON_BUILD_DIR}/lofar/expion) + +# This is a quick-and-dirty fix to install the Python binding module in the +# right place. It will now be installed twice, because lofar_add_library() +# will install it in $prefix/$libdir +install(TARGETS _baselinefitting + DESTINATION ${PYTHON_INSTALL_DIR}/lofar/expion) + # Python modules. python_install( __init__.py @@ -15,19 +29,7 @@ python_install( mpfit.py readms.py parmdbmain.py + baselinefitting.py repairGlobaldb.py DESTINATION lofar/expion) -install(PROGRAMS calibrate-ion readms-part.sh readms-part.py parmdbwriter.py DESTINATION bin) - -lofar_add_library(fitting MODULE fitting.cc) - -set_target_properties(fitting PROPERTIES - PREFIX "") -# LIBRARY_OUTPUT_DIRECTORY ${PYTHON_BUILD_DIR}/lofar/expion) - -# This is a quick-and-dirty fix to install the Python binding module in the -# right place. It will now be installed twice, because lofar_add_library() -# will install it in $prefix/$libdir -install(TARGETS fitting - DESTINATION ${PYTHON_INSTALL_DIR}/lofar/expion) diff --git a/CEP/Calibration/ExpIon/src/fitting.cc b/CEP/Calibration/ExpIon/src/baselinefitting.cc similarity index 72% rename from CEP/Calibration/ExpIon/src/fitting.cc rename to CEP/Calibration/ExpIon/src/baselinefitting.cc index 679d8800b4ecef2d3fbcd4218e9d8ae9488baf40..fc6dede8b5c41e7dcd8f2b761acdf454b5f4761a 100644 --- a/CEP/Calibration/ExpIon/src/fitting.cc +++ b/CEP/Calibration/ExpIon/src/baselinefitting.cc @@ -23,7 +23,7 @@ #include <lofar_config.h> #include <Common/OpenMP.h> -// #include <omp.h> + #include <casa/Containers/ValueHolder.h> #include <casa/Containers/Record.h> #include <casa/Utilities/CountedPtr.h> @@ -46,47 +46,71 @@ namespace LOFAR namespace ExpIon { -ValueHolder fit(const ValueHolder &phases_vh, const ValueHolder &A_vh, const ValueHolder &init_vh = ValueHolder(), const ValueHolder &flags_vh = ValueHolder()) +ValueHolder fit(const ValueHolder &phases_vh, const ValueHolder &A_vh, const ValueHolder &init_vh, + const ValueHolder &flags_vh, const ValueHolder &constant_parm_vh ) { + // Arrays are passed as ValueHolder + // They are Array is extracted by the asArray<Type> methods + // They pointer to the actual data is obtained by the Array.data() method. + + // Get the phases Array<Float> phases = phases_vh.asArrayFloat(); Float *phases_data = phases.data(); - Array<Bool> flags; - Bool noflags = flags_vh.isNull(); + + // Get the flags + Array<Bool> flags(flags_vh.asArrayBool()); + Bool noflags = (flags.ndim() == 0); + Bool *flags_data; if (!noflags) { - flags = flags_vh.asArrayBool(); + flags_data = flags.data(); } - Bool *flags_data = flags.data(); + + IPosition s = phases.shape(); + int N_station = s[0]; + int N_freq = s[1]; + + // Get the matrix with basis functions Array<Float> A = A_vh.asArrayFloat(); Float *A_data = A.data(); - IPosition s = phases.shape(); + IPosition s1 = A.shape(); - int N_station = s[0]; - int N_freq = s[1]; int N_coeff = s1[0]; int N_parm = N_station * N_coeff; Float sol[N_parm]; - int N_thread = OpenMP::maxThreads(); - LSQFit lnl[N_thread]; - lnl[0] = LSQFit(N_parm); - lnl[0].setMaxIter(10000); - uInt nr = 0; - - if (!init_vh.isNull()) + Array<Float> init(init_vh.asArrayFloat()); + if (init.ndim() == 0) { - Array<Float> init = init_vh.asArrayFloat(); - for(int i = 0; i < N_parm; i++) sol[i] = init.data()[i]; + for(int i = 0; i < N_parm; i++) sol[i] = 0.0; } else { - for(int i = 0; i < N_parm; i++) sol[i] = 0.0; + for(int i = 0; i < N_parm; i++) sol[i] = init.data()[i]; } - int iter = 0; - while (!lnl[0].isReady()) + + // Get the flags indicating which parameters are constant_parm + // i.e. are not a free parameter in the minimization problem + Array<Bool> constant_parm(constant_parm_vh.asArrayBool()); + Bool no_constant_parm = (constant_parm.ndim() == 0); + Bool *constant_parm_data; + if (!no_constant_parm) { - for(int i = 1; i<N_thread; i++) { + constant_parm_data = constant_parm.data(); + } + + Float cEq[N_parm]; + for(int i=0; i<N_parm; ++i) cEq[i] = 0.0; + + int N_thread = OpenMP::maxThreads(); + LSQFit lnl[N_thread]; + + uInt nr = 0; + + for (int iter = 0; iter<1000; iter++) + { + for(int i = 0; i<N_thread; i++) { lnl[i] = LSQFit(N_parm); } #pragma omp parallel @@ -112,13 +136,10 @@ ValueHolder fit(const ValueHolder &phases_vh, const ValueHolder &A_vh, const Val Float phase_ij_obs = phases_data_k_i - phases_data_k[j]; Float phase_ij_model = 0.0; - int idx_i = i*N_coeff; - int idx_j = j*N_coeff; - for (int l = 0; l<N_coeff; l++) { Float coeff = A_data_k[l]; - phase_ij_model += (sol[idx_i + l] - sol[idx_j + l]) * coeff ; + phase_ij_model += (sol[i + l*N_station] - sol[j + l*N_station]) * coeff ; } Float sin_dphase, cos_dphase; sincosf(phase_ij_obs - phase_ij_model, &sin_dphase, &cos_dphase); @@ -137,8 +158,8 @@ ValueHolder fit(const ValueHolder &phases_vh, const ValueHolder &A_vh, const Val derivatives_re[N_coeff + l] = -a; derivatives_im[l] = b; derivatives_im[N_coeff + l] = -b; - idx[l] = idx_i+l; - idx[N_coeff + l] = idx_j+l; + idx[l] = i+l*N_station; + idx[N_coeff + l] = j+l*N_station; } lnl[threadNum].makeNorm(uInt(2*N_coeff), (uInt*) idx, (Float*) derivatives_re, Float(1.0), residual_re); lnl[threadNum].makeNorm(uInt(2*N_coeff), (uInt*) idx, (Float*) derivatives_im, Float(1.0), residual_im); @@ -146,44 +167,53 @@ ValueHolder fit(const ValueHolder &phases_vh, const ValueHolder &A_vh, const Val } } } -// #pragma omp sections -// { -// { lnl[0].merge(lnl[1]); } -// #pragma omp section -// { lnl[2].merge(lnl[3]); } -// } } -// lnl[0].merge(lnl[2]); for(int i = 1; i<N_thread; i++) { lnl[0].merge(lnl[i]); } + + Float eq[2]; + eq[0] = 1.0; + eq[1] = -1.0; + uInt idx[2]; + + if ((!no_constant_parm) ) + { + for (int i = 0; i<N_parm; i++) + { + if (constant_parm_data[i]) + { + cEq[i] = 1.0; + lnl[0].addConstraint( (Float*) cEq, 0.0); + cEq[i] = 0.0; + } + } + } + if (!lnl[0].solveLoop(nr, sol, True)) { cout << "Error in loop: " << nr << endl; break; } - iter++; + if (lnl[0].isReady()) + { + break; + } } - cout << iter << endl; - Array<Float> solutions(IPosition(2, N_coeff, N_station ), sol); + Array<Float> solutions(IPosition(2, N_station, N_coeff), sol); ValueHolder result(solutions); return result; }; -ValueHolder fit2(const ValueHolder &phases_vh, const ValueHolder &A_vh) -{ - return fit(phases_vh, A_vh); -} - } // namespace ExpIon } // namespace LOFAR -BOOST_PYTHON_MODULE(fitting) +BOOST_PYTHON_MODULE(_baselinefitting) { casa::pyrap::register_convert_excp(); casa::pyrap::register_convert_basicdata(); @@ -191,5 +221,4 @@ BOOST_PYTHON_MODULE(fitting) casa::pyrap::register_convert_casa_record(); def("fit", LOFAR::ExpIon::fit); - def("fit", LOFAR::ExpIon::fit2); } diff --git a/CEP/Calibration/ExpIon/src/baselinefitting.py b/CEP/Calibration/ExpIon/src/baselinefitting.py new file mode 100644 index 0000000000000000000000000000000000000000..4708eea126511836feeeec40920344c173cebd05 --- /dev/null +++ b/CEP/Calibration/ExpIon/src/baselinefitting.py @@ -0,0 +1,35 @@ +"""Fit basefunctions to phases using all baselines + +Application: Clock-TEC separation + + +The phase can be described by a linear model + +.. math:: + phases = A p + +where the columns of matrix A contain the basefunctions and p are the parameters + +The same equation holds for the phases of multiple stations +The dimension of phases is then N_freq x N_station and +the dimension of p is N_freq x N_param + +The cost function that will be minimized is + +.. math:: + \\sum_{i=1}^{N_{station}-1}\\sum_{j=0}^{i-1} \\sum_{k=0}^{N_{freq}} \\| \\exp(\imath(\\Delta phase_{ijk} - \\Delta modelphase_{ijk})) \\|^2 +where +.. math:: + \\Delta phase_{ijk} = + \\Delta modelphase_{ijk} = + + + +""" + + +import _baselinefitting + +def fit(phases, A, p_0 = None, flags = None, constant_parms = None): + """see module description for detailed info""" + return _baselinefitting.fit(phases, A, p_0, flags, constant_parms) \ No newline at end of file