diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2cdafcb7053b27ffb7f460129a9ecb919f1a2888..18649ede698c6695a8dfe7342fe74da469a99d94 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -154,7 +154,7 @@ building_stage: - cat /etc/os-release - cd build - echo "Configuring with default compilers (MAGMA disabled)..." - - ./configure --without-magma --without-cublas --disable-offload --enable-refinement + - ./configure --without-magma --without-cublas --disable-offload --enable-refinement --enable-shared - make wipe - echo "Building the default configuration..." - make -j @@ -174,7 +174,7 @@ sanity_stage: - building_stage artifacts: paths: - - build/testing/valgrind.log + - build/testing/valgrind_*.log exclude: - ".git*" - ".git/**/*" @@ -185,11 +185,26 @@ sanity_stage: - hostname - echo $CI_COMMIT_SHA - echo $CI_COMMIT_BRANCH - - cd build/testing - - echo "Running memory sanity check" + - cd build/libnptm + - export LD_LIBRARY_PATH="$LD_LIBRARY_PATH;$PWD" + - cd ../testing + - echo "Running memory sanity check for ParticleDescriptor" - chmod +x test_ParticleDescriptor - - valgrind --leak-check=full --log-file=valgrind.log ./test_ParticleDescriptor - - grep "no leaks are possible" valgrind.log + - valgrind --leak-check=full --log-file=valgrind_Particle.log ./test_ParticleDescriptor + - grep "0 errors from 0 contexts" valgrind_Particle.log + - echo "Running memory sanity check for output classes" + - chmod +x test_cluster_outputs + - valgrind --leak-check=full --log-file=valgrind_cluster.log ./test_cluster_outputs + - grep "0 errors from 0 contexts" valgrind_cluster.log + - rm -rf c_OCLU_24 + - chmod +x test_inclusion_outputs + - valgrind --leak-check=full --log-file=valgrind_inclusion.log ./test_inclusion_outputs + - grep "0 errors from 0 contexts" valgrind_inclusion.log + - rm -rf c_OINCLU + - chmod +x test_sphere_outputs + - valgrind --leak-check=full --log-file=valgrind_sphere.log ./test_sphere_outputs + - grep "0 errors from 0 contexts" valgrind_sphere.log + - rm -rf c_OSPH running_stage: stage: run @@ -215,10 +230,12 @@ running_stage: - hostname - echo $CI_COMMIT_SHA - echo $CI_COMMIT_BRANCH - - cd build/sphere + - cd build/libnptm + - export LD_LIBRARY_PATH="$LD_LIBRARY_PATH;$PWD" + - cd ../sphere - echo "Running np_sphere" - chmod +x np_sphere - - ./np_sphere + - OMP_NUM_THREADS=1 ./np_sphere - cd ../cluster - echo "Running np_cluster" - chmod +x np_cluster @@ -240,7 +257,7 @@ testing_stage: - running_stage artifacts: paths: - - build/cluster/pycompare.html + - build/cluster/pycompare_*.html - build/inclusion/pycompare.html - build/sphere/pycompare.html exclude: @@ -253,7 +270,9 @@ testing_stage: - hostname - echo $CI_COMMIT_SHA - echo $CI_COMMIT_BRANCH - - cd build/sphere + - cd build/libnptm + - export LD_LIBRARY_PATH="$LD_LIBRARY_PATH;$PWD" + - cd ../sphere - export FFILE=../../test_data/sphere/OSPH - echo "Comparing output of SPHERE" - python3 ../../src/scripts/pycompare.py --no-progress --ffile $FFILE --cfile c_OSPH --html @@ -266,13 +285,37 @@ testing_stage: - cd ../cluster - echo "Comparing output of CLUSTER" - export FFILE=../../test_data/cluster/OCLU - - python3 ../../src/scripts/pycompare.py --no-progress --ffile $FFILE --cfile c_OCLU --html + - python3 ../../src/scripts/pycompare.py --no-progress --ffile $FFILE --cfile c_OCLU --html=pycompare_dev.html - echo "Testing cluster with 24 spheres" - OMP_NUM_THREADS=1 OMPI_ALLOW_RUN_AS_ROOT=1 OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1 mpirun -n 2 ./np_cluster ../../test_data/cluster/DEDFB_24 ../../test_data/cluster/DCLU_24 . - echo "Comparing output of CLUSTER with 24 spheres" - export FFILE=../../test_data/cluster/OCLU_24 - - python3 ../../src/scripts/pycompare.py --no-progress --ffile $FFILE --cfile c_OCLU --html + - python3 ../../src/scripts/pycompare.py --no-progress --ffile $FFILE --cfile c_OCLU --html=pycompare_24.html - echo "Checking consistency among legacy and HDF5 configuration files" - ../testing/test_TEDF ../../test_data/cluster/DEDFB_24 c_TEDF c_TEDF.hd5 - echo "Checking consistency among legacy and HDF5 TM files" - ../testing/test_TTMS c_TTMS c_TTMS.hd5 + - echo "Testing cluster with 48 spheres" + - OMP_NUM_THREADS=5 ./np_cluster ../../test_data/cluster/DEDFB_48 ../../test_data/cluster/DCLU_48 . + - echo "Comparing output of CLUSTER with 48 spheres" + - export FFILE=../../test_data/cluster/OCLU_48 + - python3 ../../src/scripts/pycompare.py --no-progress --ffile $FFILE --cfile c_OCLU --html=pycompare_48.html + - cd ../testing + - echo "Checking consistency of HDF5 cluster output" + - chmod u+x test_cluster_outputs + - ./test_cluster_outputs + - export FFILE=../../test_data/cluster/OCLU_24 + - python3 ../../src/scripts/pycompare.py --no-progress --ffile $FFILE --cfile c_OCLU_24 + - rm -rf c_OCLU_24 + - echo "Checking consistency of HDF5 incluson output" + - chmod u+x test_inclusion_outputs + - ./test_inclusion_outputs + - export FFILE=../../test_data/inclusion/OINCLU + - python3 ../../src/scripts/pycompare.py --no-progress --ffile $FFILE --cfile c_OINCLU + - rm -rf c_OINCLU + - chmod u+x test_sphere_outputs + - ./test_sphere_outputs + - export FFILE=../../test_data/sphere/OSPH + - python3 ../../src/scripts/pycompare.py --no-progress --ffile $FFILE --cfile c_OSPH + - rm -rf c_OSPH + \ No newline at end of file diff --git a/README.md b/README.md index 88a2a929a0d03e0c122d92e7f7b8dbdcc4ce8f06..c92092892c2af54f6c7176a50a137d0044f60883 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Distributing the code and its sources is possible under the terms of the GNU GPL - Saija et al. 2001, ApJ, 559, 993, DOI:10.1086/322350 - Borghese, Denti, Saija 2007, Scattering from Model Nonspherical Particles (ISBN 978-3-540-37413-8), DOI:10.1007/978-3-540-37414-5 -*NOTE:* The building process requires a working installation of a C++ and a FORTRAN compiler. Many solutions are available, but the recommended option is the *GNU Compiler Collection* `gcc` with the addition of `g++` and `gfortran`. The parallel code implementation further requires the use of parallel compilers complying with the MPI standard (*OpenMPI*, *MPICH*). +*NOTE:* The building process requires a working installation of a C++ and a FORTRAN compiler. Many solutions are available, but the recommended option is the *GNU Compiler Collection* `gcc` with the addition of `g++` and `gfortran`. Single-workstation multi-threaded parallelism is supported through _OpenMP_, while the multi-node code implementation further requires the use of parallel compilers complying with the _MPI_ standard (_OpenMPI_, _MPICH_). # Acknowledgments diff --git a/build/Makefile b/build/Makefile index d8b6bf192b8b392e1d2a8c1f0240530ef74e9605..5ae144d03206c40cfbf01114f487808653b49d8d 100644 --- a/build/Makefile +++ b/build/Makefile @@ -14,21 +14,29 @@ else NPTM_LIB=libnptm/libnptm.a CXXFLAGSLIB=-static endif # LIBMODE -NP_LIBNPTM_SRCS=../src/libnptm/algebraic.cpp ../src/libnptm/clu_subs.cpp ../src/libnptm/Commons.cpp ../src/libnptm/Configuration.cpp ../src/libnptm/cublas_calls.cpp ../src/libnptm/file_io.cpp ../src/libnptm/inclu_subs.cpp ../src/libnptm/logging.cpp ../src/libnptm/lapack_calls.cpp ../src/libnptm/magma_calls.cpp ../src/libnptm/Parsers.cpp ../src/libnptm/sph_subs.cpp ../src/libnptm/tfrfme.cpp ../src/libnptm/tra_subs.cpp ../src/libnptm/TransitionMatrix.cpp ../src/libnptm/utils.cpp -NP_LIBNPTM_OBJS=../src/libnptm/algebraic.o ../src/libnptm/clu_subs.o ../src/libnptm/Commons.o ../src/libnptm/Configuration.o ../src/libnptm/cublas_calls.o ../src/libnptm/file_io.o ../src/libnptm/inclu_subs.o ../src/libnptm/logging.o ../src/libnptm/lapack_calls.o ../src/libnptm/magma_calls.o ../src/libnptm/Parsers.o ../src/libnptm/sph_subs.o ../src/libnptm/tfrfme.o ../src/libnptm/tra_subs.o ../src/libnptm/TransitionMatrix.o ../src/libnptm/utils.o +NP_DOC_SRCS=../doc/src/config.dox +NP_LIBNPTM_SRCS=../src/libnptm/algebraic.cpp ../src/libnptm/clu_subs.cpp ../src/libnptm/Commons.cpp ../src/libnptm/Configuration.cpp ../src/libnptm/cublas_calls.cpp ../src/libnptm/file_io.cpp ../src/libnptm/inclu_subs.cpp ../src/libnptm/logging.cpp ../src/libnptm/lapack_calls.cpp ../src/libnptm/magma_calls.cpp ../src/libnptm/outputs.cpp ../src/libnptm/Parsers.cpp ../src/libnptm/sph_subs.cpp ../src/libnptm/tfrfme.cpp ../src/libnptm/tra_subs.cpp ../src/libnptm/TransitionMatrix.cpp ../src/libnptm/utils.cpp +NP_LIBNPTM_OBJS=../src/libnptm/algebraic.o ../src/libnptm/clu_subs.o ../src/libnptm/Commons.o ../src/libnptm/Configuration.o ../src/libnptm/cublas_calls.o ../src/libnptm/file_io.o ../src/libnptm/inclu_subs.o ../src/libnptm/logging.o ../src/libnptm/lapack_calls.o ../src/libnptm/magma_calls.o ../src/libnptm/outputs.o ../src/libnptm/Parsers.o ../src/libnptm/sph_subs.o ../src/libnptm/tfrfme.o ../src/libnptm/tra_subs.o ../src/libnptm/TransitionMatrix.o ../src/libnptm/utils.o +NP_CLUSTER_SRCS=../src/cluster/np_cluster.cpp ../src/cluster/cluster.cpp NP_CLUSTER_OBJS=../src/cluster/np_cluster.o ../src/cluster/cluster.o NP_CLUSTER_BINS=cluster/np_cluster +NP_INCLUSION_SRCS=../src/inclusion/np_inclusion.cpp ../src/inclusion/inclusion.cpp NP_INCLUSION_OBJS=../src/inclusion/np_inclusion.o ../src/inclusion/inclusion.o NP_INCLUSION_BINS=inclusion/np_inclusion +NP_SPHERE_SRCS=../src/sphere/np_sphere.cpp ../src/sphere/sphere.cpp NP_SPHERE_OBJS=../src/sphere/np_sphere.o ../src/sphere/sphere.o NP_SPHERE_BINS=sphere/np_sphere +NP_TRAPPING_SRCS=../src/trapping/np_trapping.cpp ../src/trapping/cfrfme.cpp ../src/trapping/clffft.cpp NP_TRAPPING_OBJS=../src/trapping/np_trapping.o ../src/trapping/cfrfme.o ../src/trapping/clffft.o NP_TRAPPING_BINS=trapping/np_trapping -NP_TESTING_OBJS=../src/testing/test_ParticleDescriptor.o ../src/testing/test_TEDF.o ../src/testing/test_TTMS.o -NP_TESTING_BINS=testing/test_ParticleDescriptor testing/test_TEDF testing/test_TTMS +NP_TESTING_OBJS=../src/testing/test_cluster_outputs.o ../src/testing/test_inclusion_outputs.o ../src/testing/test_sphere_outputs.o ../src/testing/test_ParticleDescriptor.o ../src/testing/test_TEDF.o ../src/testing/test_TTMS.o +NP_TESTING_BINS=testing/test_cluster_outputs testing/test_inclusion_outputs testing/test_sphere_outputs testing/test_ParticleDescriptor testing/test_TEDF testing/test_TTMS all: $(NPTM_LIB) $(FORTRAN_BINS) $(NP_CLUSTER_BINS) $(NP_INCLUSION_BINS) $(NP_SPHERE_BINS) $(NP_TRAPPING_BINS) $(NP_TESTING_BINS) +docs: $(NP_LIBNPTM_SRCS) $(NP_CLUSTER_SRCS) $(NP_DOC_SRCS) $(NP_INCLUSION_SRCS) $(NP_SPHERE_SRCS) $(NP_TRAPPING_SRCS) + cd ../doc/src; doxygen config.dox + libnptm/libnptm.a: $(NP_LIBNPTM_OBJS) $(AR) $(ARFLAGS) $@ $(NP_LIBNPTM_OBJS) @@ -75,6 +83,15 @@ trapping/np_trapping: $(NPTM_LIB) $(NP_TRAPPING_OBJS) testing/test_ParticleDescriptor: $(NPTM_LIB) ../src/testing/test_ParticleDescriptor.o $(CXX) $(CXXFLAGS) ../src/testing/test_ParticleDescriptor.o -o $@ $(CXXLDFLAGS) +testing/test_cluster_outputs: $(NPTM_LIB) ../src/testing/test_cluster_outputs.o + $(CXX) $(CXXFLAGS) ../src/testing/test_cluster_outputs.o -o $@ $(CXXLDFLAGS) + +testing/test_inclusion_outputs: $(NPTM_LIB) ../src/testing/test_inclusion_outputs.o + $(CXX) $(CXXFLAGS) ../src/testing/test_inclusion_outputs.o -o $@ $(CXXLDFLAGS) + +testing/test_sphere_outputs: $(NPTM_LIB) ../src/testing/test_sphere_outputs.o + $(CXX) $(CXXFLAGS) ../src/testing/test_sphere_outputs.o -o $@ $(CXXLDFLAGS) + testing/test_TEDF: $(NPTM_LIB) ../src/testing/test_TEDF.o $(CXX) $(CXXFLAGS) ../src/testing/test_TEDF.o -o $@ $(CXXLDFLAGS) @@ -146,3 +163,4 @@ clean: wipe: rm -rf $(FORTRAN_OBJS) $(NP_LIBNPTM_OBJS) $(NP_CLUSTER_OBJS) $(NP_INCLUSION_OBJS) $(NP_SPHERE_OBJS) $(NP_TRAPPING_OBJS) $(NP_TESTING_OBJS) rm -rf $(FORTRAN_BINS) libnptm/libnptm.a libnptm/libnptm.so $(NP_CLUSTER_BINS) $(NP_INCLUSION_BINS) $(NP_SPHERE_BINS) $(NP_TRAPPING_BINS) $(NP_TESTING_BINS) + rm -rf ../doc/build diff --git a/src/cluster/cluster.cpp b/src/cluster/cluster.cpp index 59604b689e25be4adede1e18c19502d7d1c553bb..3b50640f5c4ab253c5a40e8b8b0d1217cdaf4f32 100644 --- a/src/cluster/cluster.cpp +++ b/src/cluster/cluster.cpp @@ -39,17 +39,10 @@ #include <nvtx3/nvToolsExt.h> #endif -//#define USE_CUBLAS 1 #ifdef USE_CUBLAS #include <cuda_runtime.h> #endif -//#ifdef USE_MAGMA -//#include <cuda_runtime.h> -//#endif -// define by hand for a first test -//#define USE_REFINEMENT 1 - #ifndef INCLUDE_TYPES_H_ #include "../include/types.h" #endif @@ -98,19 +91,42 @@ #include "../include/utils.h" #endif -using namespace std; +#ifndef INCLUDE_OUTPUTS_H_ +#include "../include/outputs.h" +#endif -// I would like to put it all in a struct, but then I'd have to write a constructor for it, due to members defined as references, creating a worse nightmare than the one I'd like to simplify... +#ifndef INCLUDE_ITERATION_DATA_H_ +#include "../include/IterationData.h" +#endif -int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConfiguration *gconf, ScatteringAngles *sa, ClusterIterationData *cid, VirtualAsciiFile *output, const string& output_path, VirtualBinaryFile *vtppoanp); +using namespace std; -/*! \brief C++ implementation of CLU +/*! \brief Main calculation loop. * - * \param config_file: `string` Name of the configuration file. - * \param data_file: `string` Name of the input data file. - * \param output_path: `string` Directory to write the output files in. + * The solution of the scattering problem for different wavelengths is an + * embarrasingly parallel task. This function, therefore, collects all the + * operations that can be independently executed by different processes, + * after the configuration stage and the first calculation loop have been + * executed. + * + * \param jxi488: `int` Wavelength loop index. + * \param sconf: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` object. + * \param gconf: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` object. + * \param sa: `ScatteringAngles *` Pointer to a `ScatteringAngles` object. + * \param cid: `ClusterIterationData *` Pointer to a `ClusterIterationData` object. + * \param oi: `ClusterOutputInfo *` Pointer to a `ClusterOutputInfo` object. + * \param output_path: `const string &` Path to the output directory. + * \param vtppoanp: `VirtualBinaryFile *` Pointer to a `VirtualBinaryFile` object. */ +int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConfiguration *gconf, ScatteringAngles *sa, ClusterIterationData *cid, ClusterOutputInfo *oi, const string& output_path, VirtualBinaryFile *vtppoanp); +/*! \brief C++ implementation of CLU + * + * \param config_file: `const string &` Name of the configuration file. + * \param data_file: `const string &` Name of the input data file. + * \param output_path: `const string &` Name of the directory to write the output files in. + * \param mpidata: `const mixMPI *` Pointer to a mixMPI data structure. + */ void cluster(const string& config_file, const string& data_file, const string& output_path, const mixMPI *mpidata) { chrono::time_point<chrono::high_resolution_clock> t_start = chrono::high_resolution_clock::now(); chrono::duration<double> elapsed; @@ -212,14 +228,11 @@ void cluster(const string& config_file, const string& data_file, const string& o int nsph = gconf->number_of_spheres; // Sanity check on number of sphere consistency, should always be verified if (s_nsph == nsph) { - // Shortcuts to variables stored in configuration objects ScatteringAngles *p_scattering_angles = new ScatteringAngles(gconf); double wp = sconf->wp; - // Open empty virtual ascii file for output - VirtualAsciiFile *p_output = new VirtualAsciiFile(); - // for the time being, this is ok. When we can, add some logic in the sprintf calls that checks if a longer buffer would be needed, and in case expand it - // in any case, replace all sprintf() with snprintf(), to avoid in any case writing more than the available buffer size - char virtual_line[256]; + // ClusterOutputInfo : Thread 0 of MPI process 0 allocates the memory to + // store all the results. + ClusterOutputInfo *p_output = new ClusterOutputInfo(sconf, gconf, mpidata); // Create and initialise pristine cid for MPI proc 0 and thread 0 ClusterIterationData *cid = new ClusterIterationData(gconf, sconf, mpidata, device_count); const int ndi = cid->c1->nsph * cid->c1->nlim; @@ -227,73 +240,10 @@ void cluster(const string& config_file, const string& data_file, const string& o logger->log("INFO: Size of matrices to invert: " + to_string((int64_t)ndit) + " x " + to_string((int64_t)ndit) +".\n"); time_logger->log("INFO: Size of matrices to invert: " + to_string((int64_t)ndit) + " x " + to_string((int64_t)ndit) +".\n"); - //========================== - // Write a block of info to the ascii output file - //========================== - sprintf(virtual_line, " READ(IR,*)NSPH,LI,LE,MXNDM,INPOL,NPNT,NPNTTS,IAVM,ISAM\n"); - p_output->append_line(virtual_line); -#ifdef USE_ILP64 - sprintf(virtual_line, " %5d%5d%5d%5ld%5d%5d%5d%5d%5d\n", - nsph, cid->c1->li, cid->c1->le, gconf->mxndm, gconf->in_pol, gconf->npnt, - gconf->npntts, gconf->iavm, gconf->isam - ); -#else - sprintf(virtual_line, " %5d%5d%5d%5d%5d%5d%5d%5d%5d\n", - nsph, cid->c1->li, cid->c1->le, gconf->mxndm, gconf->in_pol, gconf->npnt, - gconf->npntts, gconf->iavm, gconf->isam - ); -#endif // USE_ILP64 - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(IR,*)RXX(I),RYY(I),RZZ(I)\n"); - p_output->append_line(virtual_line); - for (int ri = 0; ri < nsph; ri++) { - sprintf(virtual_line, "%17.8lE%17.8lE%17.8lE\n", - gconf->get_sph_x(ri), gconf->get_sph_y(ri), gconf->get_sph_z(ri) - ); - p_output->append_line(virtual_line); - } - sprintf(virtual_line, " READ(IR,*)TH,THSTP,THLST,THS,THSSTP,THSLST\n"); - p_output->append_line(virtual_line); - sprintf( - virtual_line, " %10.3lE%10.3lE%10.3lE%10.3lE%10.3lE%10.3lE\n", - p_scattering_angles->th, p_scattering_angles->thstp, - p_scattering_angles->thlst, p_scattering_angles->ths, - p_scattering_angles->thsstp, p_scattering_angles->thslst - ); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(IR,*)PH,PHSTP,PHLST,PHS,PHSSTP,PHSLST\n"); - p_output->append_line(virtual_line); - sprintf( - virtual_line, " %10.3lE%10.3lE%10.3lE%10.3lE%10.3lE%10.3lE\n", - p_scattering_angles->ph, p_scattering_angles->phstp, - p_scattering_angles->phlst, p_scattering_angles->phs, - p_scattering_angles->phsstp, p_scattering_angles->phslst - ); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(IR,*)JWTM\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " %5d\n", gconf->jwtm); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)NSPHT\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)(IOG(I),I=1,NSPH)\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)EXDC,WP,XIP,IDFC,NXI\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)(XIV(I),I=1,NXI)\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)NSHL(I),ROS(I)\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)(RCF(I,NS),NS=1,NSH)\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " \n"); - p_output->append_line(virtual_line); str(sconf, cid->c1); thdps(cid->c1->lm, cid->zpv); double exdc = sconf->exdc; double exri = sqrt(exdc); - sprintf(virtual_line, " REFR. INDEX OF EXTERNAL MEDIUM=%15.7lE\n", exri); - p_output->append_line(virtual_line); // Create empty virtual binary file VirtualBinaryFile *vtppoanp = new VirtualBinaryFile(); @@ -329,10 +279,7 @@ void cluster(const string& config_file, const string& data_file, const string& o vtppoanp->append_line(VirtualBinaryLine(nphs)); if (sconf->idfc < 0) { cid->vk = cid->xip * cid->wn; - sprintf(virtual_line, " VK=%15.7lE, XI IS SCALE FACTOR FOR LENGTHS\n", cid->vk); - p_output->append_line(virtual_line); - sprintf(virtual_line, " \n"); - p_output->append_line(virtual_line); + p_output->vec_vk[0] = cid->vk; } // do the first iteration on jxi488 separately, since it seems to be different from the others @@ -349,8 +296,8 @@ void cluster(const string& config_file, const string& data_file, const string& o #pragma omp single { jer = cluster_jxi488_cycle(jxi488, sconf, gconf, p_scattering_angles, cid, p_output, output_path, vtppoanp); - } - } + } // OMP sinlge + } // OMP parallel #ifdef USE_NVTX nvtxRangePop(); #endif @@ -383,8 +330,6 @@ void cluster(const string& config_file, const string& data_file, const string& o //================================================== // do the first outputs here, so that I open here the new files, afterwards I only append //================================================== - p_output->write_to_disk(output_path + "/c_OCLU"); - delete p_output; vtppoanp->write_to_disk(output_path + "/c_TPPOAN"); delete vtppoanp; @@ -404,7 +349,7 @@ void cluster(const string& config_file, const string& data_file, const string& o int myMPIstride = ompnumthreads; int myMPIblock = ompnumthreads; // Define here shared arrays of virtual ascii and binary files, so that thread 0 will be able to access them all later - VirtualAsciiFile **p_outarray = NULL; + ClusterOutputInfo **p_outarray = NULL; VirtualBinaryFile **vtppoanarray = NULL; #ifdef USE_NVTX @@ -427,7 +372,7 @@ void cluster(const string& config_file, const string& data_file, const string& o if (myompthread == 0) { // Initialise some shared variables only on thread 0 - p_outarray = new VirtualAsciiFile*[ompnumthreads]; + p_outarray = new ClusterOutputInfo*[ompnumthreads]; vtppoanarray = new VirtualBinaryFile*[ompnumthreads]; myMPIblock = ompnumthreads; myMPIstride = myMPIblock; @@ -456,11 +401,14 @@ void cluster(const string& config_file, const string& data_file, const string& o // To test parallelism, I will now start feeding this function with "clean" copies of the parameters, so that they will not be changed by previous iterations, and each one will behave as the first one. Define all (empty) variables here, so they have the correct scope, then they get different definitions depending on thread number ClusterIterationData *cid_2 = NULL; - VirtualAsciiFile *p_output_2 = NULL; + ClusterOutputInfo *p_output_2 = NULL; VirtualBinaryFile *vtppoanp_2 = NULL; // for threads other than the 0, create distinct copies of all relevant data, while for thread 0 just define new references / pointers to the original ones if (myompthread == 0) { cid_2 = cid; + // OMP thread 0 of MPI process 0 holds the pointer to the full output structure + p_output_2 = p_output; + p_outarray[0] = p_output_2; } else { // this is not thread 0, so do create fresh copies of all local variables cid_2 = new ClusterIterationData(*cid); @@ -468,6 +416,7 @@ void cluster(const string& config_file, const string& data_file, const string& o // make sure all threads align here: I don't want the following loop to accidentally start for thread 0, possibly modifying some variables before they are copied by all other threads if (myompthread==0) { logger->log("Syncing OpenMP threads and starting the loop on wavelengths\n"); + // Thread 0 of process 0 has already allocated all necessary output memory } #pragma omp barrier // ok, now I can actually start the parallel calculations @@ -476,16 +425,24 @@ void cluster(const string& config_file, const string& data_file, const string& o #pragma omp barrier int myjxi488 = ixi488+myompthread; // each thread opens new virtual files and stores their pointers in the shared array - p_output_2 = new VirtualAsciiFile(); vtppoanp_2 = new VirtualBinaryFile(); // each thread puts a copy of the pointers to its virtual files in the shared arrays - p_outarray[myompthread] = p_output_2; vtppoanarray[myompthread] = vtppoanp_2; #pragma omp barrier // each MPI process handles a number of contiguous scales corresponding to its number of OMP threads at this omp level of parallelism if (myjxi488 <= cid_2->number_of_scales) { + if (myompthread > 0) { + // UPDATE: non-0 threads need to allocate memory for one scale at a time. + p_output_2 = new ClusterOutputInfo(sconf, gconf, mpidata, myjxi488, 1); + p_outarray[myompthread] = p_output_2; + } int jer = cluster_jxi488_cycle(myjxi488, sconf, gconf, p_scattering_angles, cid_2, p_output_2, output_path, vtppoanp_2); + } else { + if (myompthread > 0) { + // If there is no input for this thread, set output pointer to NULL. + p_outarray[myompthread] = NULL; + } } #pragma omp barrier @@ -496,8 +453,11 @@ void cluster(const string& config_file, const string& data_file, const string& o // threads different from 0 append their virtual files to the one of thread 0, and delete them if (myompthread == 0) { for (int ti=1; ti<ompnumthreads; ti++) { - p_outarray[0]->append(*(p_outarray[ti])); - delete p_outarray[ti]; + if (p_outarray[ti] != NULL) { + p_outarray[0]->insert(*(p_outarray[ti])); + delete p_outarray[ti]; + p_outarray[ti] = NULL; + } vtppoanarray[0]->append(*(vtppoanarray[ti])); delete vtppoanarray[ti]; } @@ -508,8 +468,8 @@ void cluster(const string& config_file, const string& data_file, const string& o //============================================== if (myompthread == 0) { // thread 0 writes its virtual files, now including contributions from all threads, to disk, and deletes them - p_outarray[0]->append_to_disk(output_path + "/c_OCLU"); - delete p_outarray[0]; + // p_outarray[0]->append_to_disk(output_path + "/c_OCLU"); + // delete p_outarray[0]; vtppoanarray[0]->append_to_disk(output_path + "/c_TPPOAN"); delete vtppoanarray[0]; @@ -517,11 +477,14 @@ void cluster(const string& config_file, const string& data_file, const string& o if (mpidata->mpirunning) { // only go through this if MPI has been actually used for (int rr=1; rr<mpidata->nprocs; rr++) { + // get the data from process rr by receiving it in total memory structure + p_outarray[0]->mpireceive(mpidata, rr); // get the data from process rr, creating a new virtual ascii file - VirtualAsciiFile *p_output = new VirtualAsciiFile(mpidata, rr); + // VirtualAsciiFile *p_output = new VirtualAsciiFile(mpidata, rr); // append to disk and delete virtual ascii file - p_output->append_to_disk(output_path + "/c_OCLU"); - delete p_output; + // p_output->append_to_disk(output_path + "/c_OCLU"); + // delete p_output; + // get the data from process rr, creating a new virtual binary file VirtualBinaryFile *vtppoanp = new VirtualBinaryFile(mpidata, rr); // append to disk and delete virtual binary file @@ -555,12 +518,15 @@ void cluster(const string& config_file, const string& data_file, const string& o delete cid_2; } delete p_scattering_angles; - } + p_output->write(output_path + "/c_OCLU.hd5", "HDF5"); + p_output->write(output_path + "/c_OCLU", "LEGACY"); + delete p_output; + } // closes s_nsph == nsph check else { // NSPH mismatch between geometry and scatterer configurations. throw UnrecognizedConfigurationException( - "Inconsistent geometry and scatterer configurations." - ); + "Inconsistent geometry and scatterer configurations." + ); } delete sconf; @@ -577,7 +543,7 @@ void cluster(const string& config_file, const string& data_file, const string& o time_logger->log(message); fclose(timing_file); delete time_logger; - } // end instructions block of MPI process 0 + } // end of instruction block for MPI process 0 //=============================== // instruction block for MPI processes different from 0 @@ -593,7 +559,7 @@ void cluster(const string& config_file, const string& data_file, const string& o // Create this variable and initialise it with a default here, so that it is defined anyway, with or without OpenMP support enabled int ompnumthreads = 1; - VirtualAsciiFile **p_outarray = NULL; + ClusterOutputInfo **p_outarray = NULL; VirtualBinaryFile **vtppoanarray = NULL; int myjxi488startoffset; int myMPIstride = ompnumthreads; @@ -616,13 +582,13 @@ void cluster(const string& config_file, const string& data_file, const string& o // receive myMPIstride sent by MPI process 0 to all processes MPI_Bcast(&myMPIstride, 1, MPI_INT, 0, MPI_COMM_WORLD); // allocate virtual files for each thread - p_outarray = new VirtualAsciiFile*[ompnumthreads]; + p_outarray = new ClusterOutputInfo*[ompnumthreads]; vtppoanarray = new VirtualBinaryFile*[ompnumthreads]; } #pragma omp barrier // To test parallelism, I will now start feeding this function with "clean" copies of the parameters, so that they will not be changed by previous iterations, and each one will behave as the first one. Define all (empty) variables here, so they have the correct scope, then they get different definitions depending on thread number ClusterIterationData *cid_2 = NULL; - VirtualAsciiFile *p_output_2 = NULL; + ClusterOutputInfo *p_output_2 = NULL; VirtualBinaryFile *vtppoanp_2 = NULL; // PLACEHOLDER // for threads other than the 0, create distinct copies of all relevant data, while for thread 0 just define new references / pointers to the original ones @@ -640,25 +606,41 @@ void cluster(const string& config_file, const string& data_file, const string& o #pragma omp barrier int myjxi488 = ixi488 + myjxi488startoffset + myompthread; // each thread opens new virtual files and stores their pointers in the shared array - p_output_2 = new VirtualAsciiFile(); vtppoanp_2 = new VirtualBinaryFile(); // each thread puts a copy of the pointers to its virtual files in the shared arrays - p_outarray[myompthread] = p_output_2; vtppoanarray[myompthread] = vtppoanp_2; #pragma omp barrier if (myompthread==0) logger->log("Syncing OpenMP threads and starting the loop on wavelengths\n"); // ok, now I can actually start the parallel calculations // each MPI process handles a number of contiguous scales corresponding to its number of OMP threads at this omp level of parallelism if (myjxi488 <= cid_2->number_of_scales) { + if (myompthread > 0) { + // UPDATE: non-0 threads need to allocate memory for one scale at a time. + p_output_2 = new ClusterOutputInfo(sconf, gconf, mpidata, myjxi488, 1); + p_outarray[myompthread] = p_output_2; + } else { + // Thread 0 of non-zero MPI processes needs to allocate memory for the + // output of all threads. + p_output_2 = new ClusterOutputInfo(sconf, gconf, mpidata, myjxi488, ompnumthreads); + p_outarray[0] = p_output_2; + } int jer = cluster_jxi488_cycle(myjxi488, sconf, gconf, p_scattering_angles, cid_2, p_output_2, output_path, vtppoanp_2); - } // close the OMP parallel for loop + } else { + if (myompthread > 0) { + // If there is no input for this thread, set the output pointer to NULL. + p_outarray[myompthread] = NULL; + } + } #pragma omp barrier // threads different from 0 append their virtual files to the one of thread 0, and delete them if (myompthread == 0) { for (int ti=1; ti<ompnumthreads; ti++) { - p_outarray[0]->append(*(p_outarray[ti])); - delete p_outarray[ti]; + if (p_outarray[ti] != NULL) { + p_outarray[0]->insert(*(p_outarray[ti])); + delete p_outarray[ti]; + p_outarray[ti] = NULL; + } vtppoanarray[0]->append(*(vtppoanarray[ti])); delete vtppoanarray[ti]; } @@ -673,9 +655,9 @@ void cluster(const string& config_file, const string& data_file, const string& o int test = MPI_Barrier(MPI_COMM_WORLD); } } - } // close strided loop running on MPI processes + } // ixi488: close strided loop running on MPI processes - // Clean memory + // Clean memory #pragma omp barrier if (myompthread == 0) { delete[] p_outarray; @@ -698,9 +680,10 @@ void cluster(const string& config_file, const string& data_file, const string& o #endif } -int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConfiguration *gconf, ScatteringAngles *sa, ClusterIterationData *cid, VirtualAsciiFile *output, const string& output_path, VirtualBinaryFile *vtppoanp) +int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConfiguration *gconf, ScatteringAngles *sa, ClusterIterationData *cid, ClusterOutputInfo *output, const string& output_path, VirtualBinaryFile *vtppoanp) { int nxi = sconf->number_of_scales; + const dcomplex cc0 = 0.0 + I * 0.0; char virtual_line[256]; string message = "INFO: running scale iteration " + to_string(jxi488) + " of " + to_string(nxi) + ".\n"; Logger *logger = new Logger(LOG_DEBG); @@ -721,17 +704,19 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf int inpol = gconf->in_pol; int npnt = gconf->npnt; int npntts = gconf->npntts; - int isam = gconf->iavm; + int isam = gconf->isam; int jwtm = gconf->jwtm; np_int ndit = 2 * nsph * cid->c1->nlim; int isq, ibf; int last_configuration; + int num_configs = sconf->configurations; + int ndirs = sa->nkks; + int oindex = -1; + int jindex = jxi488 - output->first_xi + 1; #ifdef USE_NVTX nvtxRangePush("Prepare matrix calculation"); #endif - sprintf(virtual_line, "========== JXI =%3d ====================\n", jxi488); - output->append_line(virtual_line); double xi = sconf->get_scale(jxi488 - 1); double exdc = sconf->exdc; double exri = sqrt(exdc); @@ -740,18 +725,20 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf if (idfc >= 0) { cid->vk = xi * cid->wn; vkarg = cid->vk; - sprintf(virtual_line, " VK=%15.7lE, XI=%15.7lE\n", cid->vk, xi); - output->append_line(virtual_line); + output->vec_vk[jindex - 1] = cid->vk; + output->vec_xi[jindex - 1] = xi; } else { vkarg = xi * cid->vk; cid->sqsfi = 1.0 / (xi * xi); - sprintf(virtual_line, " XI=%15.7lE\n", xi); - output->append_line(virtual_line); + output->vec_vk[jindex - 1] = cid->vk; + output->vec_xi[jindex - 1] = xi; } hjv(exri, vkarg, jer, lcalc, cid->arg, cid->c1); if (jer != 0) { - sprintf(virtual_line, " STOP IN HJV\n"); - output->append_line(virtual_line); + output->vec_ier[jindex - 1] = 1; + output->vec_jxi[jindex - 1] = -jxi488; + logger->log("Error in HJV for scale " + to_string(jxi488) + "!", LOG_ERRO); + delete logger; return jer; // break; // rewrite this to go to the end of the function, to free locally allocated variables and return jer } @@ -782,13 +769,14 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf cid->c1, jer, lcalc, cid->arg, last_configuration ); if (jer != 0) { - sprintf(virtual_line, " STOP IN DME\n"); - output->append_line(virtual_line); + output->vec_ier[jindex - 1] = 2; + output->vec_jxi[jindex - 1] = -jxi488; return jer; //break; } } if (jer != 0) { + output->vec_jxi[jindex - 1] = -jxi488; return jer; //break; } @@ -906,14 +894,6 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf TransitionMatrix::write_binary(ttms_name, nlemt, lm, cid->vk, exri, cid->c1->am0m); } } - // label 156: continue from here - if (inpol == 0) { - sprintf(virtual_line, " LIN\n"); - output->append_line(virtual_line); - } else { // label 158 - sprintf(virtual_line, " CIRC\n"); - output->append_line(virtual_line); - } // label 160 double cs0 = 0.25 * cid->vk * cid->vk * cid->vk / acos(0.0); double csch = 0.0, qschu = 0.0, pschu = 0.0, s0mag = 0.0; @@ -922,69 +902,59 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf double sqk = cid->vk * cid->vk * exdc; aps(cid->zpv, cid->c1->li, nsph, cid->c1, sqk, cid->gaps); rabas(inpol, cid->c1->li, nsph, cid->c1, cid->tqse, cid->tqspe, cid->tqss, cid->tqsps); - if (cid->c1->li != cid->c1->le) { - sprintf(virtual_line, " SPHERES; LMX=LI\n"); - output->append_line(virtual_line); - } last_configuration = 0; for (int i170 = 1; i170 <= nsph; i170++) { if (cid->c1->iog[i170 - 1] >= i170) { int i = i170 - 1; last_configuration++; + oindex = (jindex - 1) * num_configs + last_configuration - 1; double albeds = cid->c1->sscs[i] / cid->c1->sexs[i]; cid->c1->sqscs[i] *= cid->sqsfi; cid->c1->sqabs[i] *= cid->sqsfi; cid->c1->sqexs[i] *= cid->sqsfi; - sprintf(virtual_line, " SPHERE %2d\n", i170); - output->append_line(virtual_line); if (cid->c1->nshl[last_configuration - 1] != 1) { - sprintf(virtual_line, " SIZE=%15.7lE\n", cid->c1->vsz[i]); - output->append_line(virtual_line); + output->vec_sphere_ref_indices[oindex] = cc0; + output->vec_sphere_sizes[oindex] = cid->c1->vsz[i]; } else { // label 162 - sprintf(virtual_line, " SIZE=%15.7lE, REFRACTIVE INDEX=%15.7lE%15.7lE\n", cid->c1->vsz[i], real(cid->c1->vkt[i]), imag(cid->c1->vkt[i])); - output->append_line(virtual_line); + output->vec_sphere_ref_indices[oindex] = cid->c1->vkt[i]; + output->vec_sphere_sizes[oindex] = cid->c1->vsz[i]; } // label 164 - sprintf(virtual_line, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n"); - output->append_line(virtual_line); - sprintf(virtual_line, " %14.7lE%15.7lE%15.7lE%15.7lE\n", cid->c1->sscs[i], cid->c1->sabs[i], cid->c1->sexs[i], albeds); - output->append_line(virtual_line); - sprintf(virtual_line, " ---- SCS/GS -- ABS/GS -- EXS/GS ---\n"); - output->append_line(virtual_line); - sprintf(virtual_line, " %14.7lE%15.7lE%15.7lE\n", cid->c1->sqscs[i], cid->c1->sqabs[i], cid->c1->sqexs[i]); - output->append_line(virtual_line); - sprintf(virtual_line, " FSAS=%15.7lE%15.7lE\n", real(cid->c1->fsas[i]), imag(cid->c1->fsas[i])); - output->append_line(virtual_line); - double alamb = 2.0 * 3.141592653589793 / cid->vk; - sprintf(virtual_line, "INSERTION: CS_SPHERE %15.7lE%15.7lE%15.7lE%15.7lE\n", alamb, cid->c1->sscs[i], cid->c1->sabs[i], cid->c1->sexs[i]); - output->append_line(virtual_line); + output->vec_sphere_scs[oindex] = cid->c1->sscs[i]; + output->vec_sphere_abs[oindex] = cid->c1->sabs[i]; + output->vec_sphere_exs[oindex] = cid->c1->sexs[i]; + output->vec_sphere_albs[oindex] = albeds; + output->vec_sphere_sqscs[oindex] = cid->c1->sqscs[i]; + output->vec_sphere_sqabs[oindex] = cid->c1->sqabs[i]; + output->vec_sphere_sqexs[oindex] = cid->c1->sqexs[i]; + output->vec_fsas[oindex] = cid->c1->fsas[i]; csch = 2.0 * cid->vk * cid->sqsfi / cid->c1->gcsv[i]; s0 = cid->c1->fsas[i] * exri; qschu = imag(s0) * csch; pschu = real(s0) * csch; s0mag = cabs(s0) * cs0; - sprintf(virtual_line, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", qschu, pschu, s0mag); - output->append_line(virtual_line); + output->vec_qschus[oindex] = qschu; + output->vec_pschus[oindex] = pschu; + output->vec_s0mags[oindex] = s0mag; double rapr = cid->c1->sexs[i] - cid->gaps[i]; double cosav = cid->gaps[i] / cid->c1->sscs[i]; - sprintf(virtual_line, " COSAV=%15.7lE, RAPRS=%15.7lE\n", cosav, rapr); - output->append_line(virtual_line); - sprintf(virtual_line, " IPO= 1, TQEk=%15.7lE, TQSk=%15.7lE\n", cid->tqse[0][i], cid->tqss[0][i]); - output->append_line(virtual_line); - sprintf(virtual_line, " IPO= 2, TQEk=%15.7lE, TQSk=%15.7lE\n", cid->tqse[1][i], cid->tqss[1][i]); - output->append_line(virtual_line); + output->vec_cosavs[oindex] = cosav; + output->vec_raprs[oindex] = rapr; + output->vec_tqek1[oindex] = cid->tqse[0][i]; + output->vec_tqsk1[oindex] = cid->tqss[0][i]; + output->vec_tqek2[oindex] = cid->tqse[1][i]; + output->vec_tqsk2[oindex] = cid->tqss[1][i]; } } // i170 loop - sprintf(virtual_line, " FSAT=%15.7lE%15.7lE\n", real(cid->c1->tfsas), imag(cid->c1->tfsas)); - output->append_line(virtual_line); + output->vec_fsat[jindex - 1] = cid->c1->tfsas; csch = 2.0 * cid->vk * cid->sqsfi / cid->c1->gcs; s0 = cid->c1->tfsas * exri; qschu = imag(s0) * csch; pschu = real(s0) * csch; s0mag = cabs(s0) * cs0; - sprintf(virtual_line, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", qschu, pschu, s0mag); - output->append_line(virtual_line); - // tppoan.write(reinterpret_cast<char *>(&(cid->vk)), sizeof(double)); + output->vec_qschut[jindex - 1] = qschu; + output->vec_pschut[jindex - 1] = pschu; + output->vec_s0magt[jindex - 1] = s0mag; vtppoanp->append_line(VirtualBinaryLine(cid->vk)); pcrsm0(cid->vk, exri, inpol, cid->c1); apcra(cid->zpv, cid->c1->le, cid->c1->am0m, inpol, sqk, cid->gapm, cid->gappm); @@ -1000,6 +970,7 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf nvtxRangePush("Angle loop"); #endif double th = sa->th; + int done_dirs = 0; for (int jth486 = 1; jth486 <= sa->nth; jth486++) { // OpenMP portable? double ph = sa->ph; double cost = 0.0, sint = 0.0, cosp = 0.0, sinp = 0.0; @@ -1086,15 +1057,10 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf jw = 1; } // label 196 - // tppoan.write(reinterpret_cast<char *>(&th), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(th)); - // tppoan.write(reinterpret_cast<char *>(&ph), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(ph)); - // tppoan.write(reinterpret_cast<char *>(&ths), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(ths)); - // tppoan.write(reinterpret_cast<char *>(&phs), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(phs)); - // tppoan.write(reinterpret_cast<char *>(&(cid->scan)), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(cid->scan)); if (jaw != 0) { jaw = 0; @@ -1103,45 +1069,33 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { double value = cid->cext[i][j]; - // tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(value)); } } for (int i = 0; i < 2; i++) { double value = cid->c1->scscm[i]; - // tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(value)); value = real(cid->c1->scscpm[i]); - // tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(value)); value = imag(cid->c1->scscpm[i]); - // tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(value)); value = cid->c1->ecscm[i]; - // tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(value)); value = real(cid->c1->ecscpm[i]); - // tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(value)); value = imag(cid->c1->ecscpm[i]); - // tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(value)); } for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { double value = cid->gapm[i][j]; - // tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(value)); value = real(cid->gappm[i][j]); - // tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(value)); value = imag(cid->gappm[i][j]); - // tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); vtppoanp->append_line(VirtualBinaryLine(value)); } } - sprintf(virtual_line, " CLUSTER (ENSEMBLE AVERAGE, MODE%2d)\n", iavm); - output->append_line(virtual_line); int jlr = 2; for (int ilr210 = 1; ilr210 <= 2; ilr210++) { int ipol = (ilr210 % 2 == 0) ? 1 : -1; @@ -1164,148 +1118,123 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf double s0magm = cabs(s0m) * cs0; double rfinrm = real(cid->c1->fsacm[ilr210 - 1][ilr210 - 1]) / real(cid->c1->tfsas); double extcrm = imag(cid->c1->fsacm[ilr210 - 1][ilr210 - 1]) / imag(cid->c1->tfsas); - if (inpol == 0) { - sprintf(virtual_line, " LIN %2d\n", ipol); - output->append_line(virtual_line); - } else { // label 206 - sprintf(virtual_line, " CIRC %2d\n", ipol); - output->append_line(virtual_line); - } + // if (inpol == 0) { + // sprintf(virtual_line, " LIN %2d\n", ipol); + // output->append_line(virtual_line); + // } else { // label 206 + // sprintf(virtual_line, " CIRC %2d\n", ipol); + // output->append_line(virtual_line); + // } // label 208 - sprintf(virtual_line, " ----- SCC ----- ABC ----- EXC ----- ALBEDC --\n"); - output->append_line(virtual_line); - sprintf(virtual_line, " %14.7lE%15.7lE%15.7lE%15.7lE\n", scasm, abssm, extsm, albdm); - output->append_line(virtual_line); - sprintf(virtual_line, " --- SCC/TGS - ABC/TGS - EXC/TGS ---\n"); - output->append_line(virtual_line); - sprintf(virtual_line, " %14.7lE%15.7lE%15.7lE\n", qscam, qabsm, qextm); - output->append_line(virtual_line); - sprintf(virtual_line, " ---- SCCRT --- ABCRT --- EXCRT ----\n"); - output->append_line(virtual_line); - sprintf(virtual_line, " %14.7lE%15.7lE%15.7lE\n", scarm, absrm, extrm); - output->append_line(virtual_line); - sprintf( - virtual_line, " FSAC(%1d,%1d)=%15.7lE%15.7lE FSAC(%1d,%1d)=%15.7lE%15.7lE\n", - ilr210, ilr210, real(cid->c1->fsacm[ilr210 - 1][ilr210 - 1]), - imag(cid->c1->fsacm[ilr210 - 1][ilr210 - 1]), jlr, ilr210, - real(cid->c1->fsacm[jlr - 1][ilr210 - 1]), imag(cid->c1->fsacm[jlr - 1][ilr210 - 1]) - ); - output->append_line(virtual_line); - sprintf( - virtual_line, " RE(FSAC(%1d,%1d))/RE(TFSAS)=%15.7lE, IM(FSAC(%1d,%1d))/IM(TFSAS)=%15.7lE\n", - ilr210, ilr210, rfinrm, ilr210, ilr210, extcrm - ); - output->append_line(virtual_line); - sprintf(virtual_line, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", qschum, pschum, s0magm); - output->append_line(virtual_line); + if (ipol == -1) { + output->vec_scc1[jindex - 1] = scasm; + output->vec_abc1[jindex - 1] = abssm; + output->vec_exc1[jindex - 1] = extsm; + output->vec_albedc1[jindex - 1] = albdm; + output->vec_qscamc1[jindex - 1] = qscam; + output->vec_qabsmc1[jindex - 1] = qabsm; + output->vec_qextmc1[jindex - 1] = qextm; + output->vec_sccrt1[jindex - 1] = scarm; + output->vec_abcrt1[jindex - 1] = absrm; + output->vec_excrt1[jindex - 1] = extrm; + // Following values are written after FSAC + output->vec_qschuc1[jindex - 1] = qschum; + output->vec_pschuc1[jindex - 1] = pschum; + output->vec_s0magc1[jindex - 1] = s0magm; + } else if (ipol == 1) { + output->vec_scc2[jindex - 1] = scasm; + output->vec_abc2[jindex - 1] = abssm; + output->vec_exc2[jindex - 1] = extsm; + output->vec_albedc2[jindex - 1] = albdm; + output->vec_qscamc2[jindex - 1] = qscam; + output->vec_qabsmc2[jindex - 1] = qabsm; + output->vec_qextmc2[jindex - 1] = qextm; + output->vec_sccrt2[jindex - 1] = scarm; + output->vec_abcrt2[jindex - 1] = absrm; + output->vec_excrt2[jindex - 1] = extrm; + // Following values are written after FSAC + output->vec_qschuc2[jindex - 1] = qschum; + output->vec_pschuc2[jindex - 1] = pschum; + output->vec_s0magc2[jindex - 1] = s0magm; + } // ipol polarization switch + if (ilr210 == 1 && jlr == 2) { + output->vec_fsac11[jindex - 1] = cid->c1->fsacm[0][0]; + output->vec_fsac21[jindex - 1] = cid->c1->fsacm[1][0]; + } else if (ilr210 == 2 && jlr == 1) { + output->vec_fsac22[jindex - 1] = cid->c1->fsacm[1][1]; + output->vec_fsac12[jindex - 1] = cid->c1->fsacm[0][1]; + } double rapr = cid->c1->ecscm[ilr210 - 1] - cid->gapm[2][ilr210 - 1]; double cosav = cid->gapm[2][ilr210 - 1] / cid->c1->scscm[ilr210 - 1]; double fz = rapr; - sprintf(virtual_line, " COSAV=%15.7lE, RAPRS=%15.7lE\n", cosav, rapr); - output->append_line(virtual_line); - sprintf(virtual_line, " Fk=%15.7lE\n", fz); - output->append_line(virtual_line); - double alamb = 2.0 * 3.141592653589793 / cid->vk; if (ilr210 == 1) { - sprintf(virtual_line, "INSERTION: CSM_CLUSTER %15.7lE%15.7lE%15.7lE%15.7lE\n", alamb, scasm, abssm, extsm); - output->append_line(virtual_line); + output->vec_cosavc1[jindex - 1] = cosav; + output->vec_raprc1[jindex - 1] = rapr; + output->vec_fkc1[jindex - 1] = fz; + } else if (ilr210 == 2) { + output->vec_cosavc2[jindex - 1] = cosav; + output->vec_raprc2[jindex - 1] = rapr; + output->vec_fkc2[jindex - 1] = fz; } } // ilr210 loop - double rmbrif = (real(cid->c1->fsacm[0][0]) - real(cid->c1->fsacm[1][1])) / real(cid->c1->fsacm[0][0]); - double rmdchr = (imag(cid->c1->fsacm[0][0]) - imag(cid->c1->fsacm[1][1])) / imag(cid->c1->fsacm[0][0]); - sprintf(virtual_line, " (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))=%15.7lE\n", rmbrif); - output->append_line(virtual_line); - sprintf(virtual_line, " (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))=%15.7lE\n", rmdchr); - output->append_line(virtual_line); } // label 212 - sprintf(virtual_line, "********** JTH =%3d, JPH =%3d, JTHS =%3d, JPHS =%3d ********************\n", jth486, jph484, jths, jphs); - output->append_line(virtual_line); - sprintf(virtual_line, " TIDG=%10.3lE, PIDG=%10.3lE, TSDG=%10.3lE, PSDG=%10.3lE\n", th, ph, ths, phs); - output->append_line(virtual_line); - sprintf(virtual_line, " SCAND=%10.3lE\n", cid->scan); - output->append_line(virtual_line); - sprintf(virtual_line, " CFMP=%15.7lE, SFMP=%15.7lE\n", cid->cfmp, cid->sfmp); - output->append_line(virtual_line); - sprintf(virtual_line, " CFSP=%15.7lE, SFSP=%15.7lE\n", cid->cfsp, cid->sfsp); - output->append_line(virtual_line); + output->vec_dir_scand[done_dirs] = cid->scan; + output->vec_dir_cfmp[done_dirs] = cid->cfmp; + output->vec_dir_sfmp[done_dirs] = cid->sfmp; + output->vec_dir_cfsp[done_dirs] = cid->cfsp; + output->vec_dir_sfsp[done_dirs] = cid->sfsp; if (isam >= 0) { - sprintf(virtual_line, " UNI=(%12.5lE,%12.5lE,%12.5lE)\n", cid->un[0], cid->un[1], cid->un[2]); - output->append_line(virtual_line); - sprintf(virtual_line, " UNS=(%12.5lE,%12.5lE,%12.5lE)\n", cid->uns[0], cid->uns[1], cid->uns[2]); - output->append_line(virtual_line); + output->vec_dir_un[3 * done_dirs] = cid->un[0]; + output->vec_dir_un[3 * done_dirs + 1] = cid->un[1]; + output->vec_dir_un[3 * done_dirs + 2] = cid->un[2]; + output->vec_dir_uns[3 * done_dirs] = cid->uns[0]; + output->vec_dir_uns[3 * done_dirs + 1] = cid->uns[1]; + output->vec_dir_uns[3 * done_dirs + 2] = cid->uns[2]; } else { // label 214 - sprintf(virtual_line, " UN=(%12.5lE,%12.5lE,%12.5lE)\n\n", cid->un[0], cid->un[1], cid->un[2]); - output->append_line(virtual_line); - } - // label 220 - if (inpol == 0) { - sprintf(virtual_line, " LIN\n"); - output->append_line(virtual_line); - } else { // label 222 - sprintf(virtual_line, " CIRC\n"); - output->append_line(virtual_line); + output->vec_dir_un[3 * done_dirs] = cid->un[0]; + output->vec_dir_un[3 * done_dirs + 1] = cid->un[1]; + output->vec_dir_un[3 * done_dirs + 2] = cid->un[2]; + output->vec_dir_uns[3 * done_dirs] = 0.0; + output->vec_dir_uns[3 * done_dirs + 1] = 0.0; + output->vec_dir_uns[3 * done_dirs + 2] = 0.0; } // label 224 scr2(cid->vk, vkarg, exri, cid->duk, cid->c1); - if (cid->c1->li != cid->c1->le) { - sprintf(virtual_line, " SPHERES; LMX=MIN0(LI,LE)\n"); - output->append_line(virtual_line); - } + last_configuration = 0; for (int i226 = 1; i226 <= nsph; i226++) { if (cid->c1->iog[i226 - 1] >= i226) { - sprintf(virtual_line, " SPHERE %2d\n", i226); - output->append_line(virtual_line); - sprintf( - virtual_line, " SAS(1,1)=%15.7lE%15.7lE, SAS(2,1)=%15.7lE%15.7lE\n", - real(cid->c1->sas[i226 - 1][0][0]), imag(cid->c1->sas[i226 - 1][0][0]), - real(cid->c1->sas[i226 - 1][1][0]), imag(cid->c1->sas[i226 - 1][1][0]) - ); - output->append_line(virtual_line); - sprintf( - virtual_line, " SAS(1,2)=%15.7lE%15.7lE, SAS(2,2)=%15.7lE%15.7lE\n", - real(cid->c1->sas[i226 - 1][0][1]), imag(cid->c1->sas[i226 - 1][0][1]), - real(cid->c1->sas[i226 - 1][1][1]), imag(cid->c1->sas[i226 - 1][1][1]) - ); - output->append_line(virtual_line); + oindex = (jindex - 1) * num_configs * ndirs + num_configs * done_dirs + last_configuration; + last_configuration++; + output->vec_dir_sas11[oindex] = cid->c1->sas[i226 - 1][0][0]; + output->vec_dir_sas21[oindex] = cid->c1->sas[i226 - 1][1][0]; + output->vec_dir_sas12[oindex] = cid->c1->sas[i226 - 1][0][1]; + output->vec_dir_sas22[oindex] = cid->c1->sas[i226 - 1][1][1]; for (int j225 = 0; j225 < 16; j225++) { cid->c1->vint[j225] = cid->c1->vints[i226 - 1][j225]; } // j225 loop mmulc(cid->c1->vint, cid->cmullr, cid->cmul); - sprintf(virtual_line, " MULS\n"); - output->append_line(virtual_line); for (int i1 = 0; i1 < 4; i1++) { - sprintf( - virtual_line, " %15.7lE%15.7lE%15.7lE%15.7lE\n", - cid->cmul[i1][0], cid->cmul[i1][1], cid->cmul[i1][2], cid->cmul[i1][3] - ); - output->append_line(virtual_line); + oindex = 16 * (jindex - 1) * num_configs * ndirs + 16 * num_configs * done_dirs + 16 * (last_configuration - 1) + 4 * i1; + output->vec_dir_muls[oindex] = cid->cmul[i1][0]; + output->vec_dir_muls[oindex + 1] = cid->cmul[i1][1]; + output->vec_dir_muls[oindex + 2] = cid->cmul[i1][2]; + output->vec_dir_muls[oindex + 3] = cid->cmul[i1][3]; } // i1 loop - sprintf(virtual_line, " MULSLR\n"); - output->append_line(virtual_line); for (int i1 = 0; i1 < 4; i1++) { - sprintf( - virtual_line, " %15.7lE%15.7lE%15.7lE%15.7lE\n", - cid->cmullr[i1][0], cid->cmullr[i1][1], cid->cmullr[i1][2], cid->cmullr[i1][3] - ); - output->append_line(virtual_line); + oindex = 16 * (jindex - 1) * num_configs * ndirs + 16 * num_configs * done_dirs + 16 * (last_configuration - 1) + 4 * i1; + output->vec_dir_mulslr[oindex] = cid->cmullr[i1][0]; + output->vec_dir_mulslr[oindex + 1] = cid->cmullr[i1][1]; + output->vec_dir_mulslr[oindex + 2] = cid->cmullr[i1][2]; + output->vec_dir_mulslr[oindex + 3] = cid->cmullr[i1][3]; } // i1 loop } } // i226 loop - sprintf( - virtual_line, " SAT(1,1)=%15.7lE%15.7lE, SAT(2,1)=%15.7lE%15.7lE\n", - real(cid->c1->tsas[0][0]), imag(cid->c1->tsas[0][0]), - real(cid->c1->tsas[1][0]), imag(cid->c1->tsas[1][0]) - ); - output->append_line(virtual_line); - sprintf( - virtual_line, " SAT(1,2)=%15.7lE%15.7lE, SAT(2,2)=%15.7lE%15.7lE\n", - real(cid->c1->tsas[0][1]), imag(cid->c1->tsas[0][1]), - real(cid->c1->tsas[1][1]), imag(cid->c1->tsas[1][1]) - ); - output->append_line(virtual_line); - sprintf(virtual_line, " CLUSTER\n"); - output->append_line(virtual_line); + oindex = (jindex - 1) * ndirs + done_dirs; + output->vec_dir_sat11[oindex] = cid->c1->tsas[0][0]; + output->vec_dir_sat21[oindex] = cid->c1->tsas[1][0]; + output->vec_dir_sat12[oindex] = cid->c1->tsas[0][1]; + output->vec_dir_sat22[oindex] = cid->c1->tsas[1][1]; pcros(cid->vk, exri, cid->c1); mextc(cid->vk, exri, cid->c1->fsac, cid->cextlr, cid->cext); mmulc(cid->c1->vint, cid->cmullr, cid->cmul); @@ -1428,64 +1357,44 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf s0mag = cabs(s0) * cs0; double refinr = real(cid->c1->fsac[ilr290 - 1][ilr290 - 1]) / real(cid->c1->tfsas); double extcor = imag(cid->c1->fsac[ilr290 - 1][ilr290 - 1]) / imag(cid->c1->tfsas); - if (inpol == 0) { - sprintf(virtual_line, " LIN %2d\n", ipol); - output->append_line(virtual_line); - } else { // label 273 - sprintf(virtual_line, " CIRC %2d\n", ipol); - output->append_line(virtual_line); - } - // label 275 - sprintf(virtual_line, " ----- SCC ----- ABC ----- EXC ----- ALBEDC --\n"); - output->append_line(virtual_line); - sprintf( - virtual_line, " %14.7lE%15.7lE%15.7lE%15.7lE\n", - scasec, abssec, extsec, albedc - ); - output->append_line(virtual_line); - sprintf(virtual_line, " --- SCC/TGS - ABC/TGS - EXC/TGS ---\n"); - output->append_line(virtual_line); - sprintf( - virtual_line, " %14.7lE%15.7lE%15.7lE\n", - qsca, qabs, qext - ); - output->append_line(virtual_line); - sprintf(virtual_line, " ---- SCCRT --- ABCRT --- EXCRT ----\n"); - output->append_line(virtual_line); - sprintf( - virtual_line, " %14.7lE%15.7lE%15.7lE\n", - scarat, absrat, extrat - ); - output->append_line(virtual_line); - sprintf( - virtual_line, " FSAC(%1d,%1d)=%15.7lE%15.7lE FSAC(%1d,%1d)=%15.7lE%15.7lE\n", - ilr290, ilr290, real(cid->c1->fsac[ilr290 - 1][ilr290 - 1]), imag(cid->c1->fsac[ilr290 - 1][ilr290 - 1]), - jlr, ilr290, real(cid->c1->fsac[jlr - 1][ilr290 - 1]), imag(cid->c1->fsac[jlr - 1][ilr290 - 1]) - ); - output->append_line(virtual_line); - sprintf( - virtual_line, " SAC(%1d,%1d)=%15.7lE%15.7lE SAC(%1d,%1d)=%15.7lE%15.7lE\n", - ilr290, ilr290, real(cid->c1->sac[ilr290 - 1][ilr290 - 1]), imag(cid->c1->sac[ilr290 - 1][ilr290 - 1]), - jlr, ilr290, real(cid->c1->sac[jlr - 1][ilr290 - 1]), imag(cid->c1->sac[jlr - 1][ilr290 - 1]) - ); - output->append_line(virtual_line); - sprintf( - virtual_line, " RE(FSAC(%1d,%1d))/RE(TFSAS)=%15.7lE, IM(FSAC(%1d,%1d))/IM(TFSAS)=%15.7lE\n", - ilr290, ilr290, refinr, ilr290, ilr290, extcor - ); - output->append_line(virtual_line); - sprintf( - virtual_line, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", - qschu, pschu, s0mag - ); - output->append_line(virtual_line); - double alamb = 2.0 * 3.141592653589793 / cid->vk; - if (ilr290 == 1) { - sprintf(virtual_line, "INSERTION: CS1_CLUSTER %13.5le%10.3le%10.3le%15.7le%15.7le%15.7le\n", alamb, th, ths, scasec, abssec, extsec); - } else if (ilr290 == 2) { - sprintf(virtual_line, "INSERTION: CS2_CLUSTER %13.5le%10.3le%10.3le%15.7le%15.7le%15.7le\n", alamb, th, ths, scasec, abssec, extsec); + // oindex remains unchanged + if (ipol == -1) { + output->vec_dir_scc1[oindex] = scasec; + output->vec_dir_abc1[oindex] = abssec; + output->vec_dir_exc1[oindex] = extsec; + output->vec_dir_albedc1[oindex] = albedc; + output->vec_dir_qscc1[oindex] = qsca; + output->vec_dir_qabc1[oindex] = qabs; + output->vec_dir_qexc1[oindex] = qext; + output->vec_dir_sccrt1[oindex] = scarat; + output->vec_dir_abcrt1[oindex] = absrat; + output->vec_dir_excrt1[oindex] = extrat; + output->vec_dir_fsac11[oindex] = cid->c1->fsac[0][0]; + output->vec_dir_fsac21[oindex] = cid->c1->fsac[1][0]; + output->vec_dir_sac11[oindex] = cid->c1->sac[0][0]; + output->vec_dir_sac21[oindex] = cid->c1->sac[1][0]; + output->vec_dir_qschuc1[oindex] = qschu; + output->vec_dir_pschuc1[oindex] = pschu; + output->vec_dir_s0magc1[oindex] = s0mag; + } else if (ipol == 1) { + output->vec_dir_scc2[oindex] = scasec; + output->vec_dir_abc2[oindex] = abssec; + output->vec_dir_exc2[oindex] = extsec; + output->vec_dir_albedc2[oindex] = albedc; + output->vec_dir_qscc2[oindex] = qsca; + output->vec_dir_qabc2[oindex] = qabs; + output->vec_dir_qexc2[oindex] = qext; + output->vec_dir_sccrt2[oindex] = scarat; + output->vec_dir_abcrt2[oindex] = absrat; + output->vec_dir_excrt2[oindex] = extrat; + output->vec_dir_fsac22[oindex] = cid->c1->fsac[1][1]; + output->vec_dir_fsac12[oindex] = cid->c1->fsac[0][1]; + output->vec_dir_sac22[oindex] = cid->c1->sac[1][1]; + output->vec_dir_sac12[oindex] = cid->c1->sac[0][1]; + output->vec_dir_qschuc2[oindex] = qschu; + output->vec_dir_pschuc2[oindex] = pschu; + output->vec_dir_s0magc2[oindex] = s0mag; } - output->append_line(virtual_line); bool goto190 = isam >= 0 && (jths > 1 || jphs > 1); if (!goto190) { cid->gapv[0] = cid->gap[0][ilr290 - 1]; @@ -1495,12 +1404,25 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf double scatts = cid->c1->scsc[ilr290 - 1]; double rapr, cosav, fp, fn, fk, fx, fy, fz; rftr(cid->u, cid->up, cid->un, cid->gapv, extins, scatts, rapr, cosav, fp, fn, fk, fx, fy, fz); - sprintf(virtual_line, " COSAV=%15.7lE, RAPRS=%15.7lE\n", cosav, rapr); - output->append_line(virtual_line); - sprintf(virtual_line, " Fl=%15.7lE, Fr=%15.7lE, Fk=%15.7lE\n", fp, fn, fk); - output->append_line(virtual_line); - sprintf(virtual_line, " Fx=%15.7lE, Fy=%15.7lE, Fz=%15.7lE\n", fx, fy, fz); - output->append_line(virtual_line); + if (ipol == -1) { + output->vec_dir_cosavc1[oindex] = cosav; + output->vec_dir_raprc1[oindex] = rapr; + output->vec_dir_flc1[oindex] = fp; + output->vec_dir_frc1[oindex] = fn; + output->vec_dir_fkc1[oindex] = fk; + output->vec_dir_fxc1[oindex] = fx; + output->vec_dir_fyc1[oindex] = fy; + output->vec_dir_fzc1[oindex] = fz; + } else if (ipol == 1) { + output->vec_dir_cosavc2[oindex] = cosav; + output->vec_dir_raprc2[oindex] = rapr; + output->vec_dir_flc2[oindex] = fp; + output->vec_dir_frc2[oindex] = fn; + output->vec_dir_fkc2[oindex] = fk; + output->vec_dir_fxc2[oindex] = fx; + output->vec_dir_fyc2[oindex] = fy; + output->vec_dir_fzc2[oindex] = fz; + } cid->tqev[0] = cid->tqce[ilr290 - 1][0]; cid->tqev[1] = cid->tqce[ilr290 - 1][1]; cid->tqev[2] = cid->tqce[ilr290 - 1][2]; @@ -1509,45 +1431,48 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf cid->tqsv[2] = cid->tqcs[ilr290 - 1][2]; double tep, ten, tek, tsp, tsn, tsk; tqr(cid->u, cid->up, cid->un, cid->tqev, cid->tqsv, tep, ten, tek, tsp, tsn, tsk); - sprintf(virtual_line, " TQEl=%15.7lE, TQEr=%15.7lE, TQEk=%15.7lE\n", tep, ten, tek); - output->append_line(virtual_line); - sprintf(virtual_line, " TQSl=%15.7lE, TQSr=%15.7lE, TQSk=%15.7lE\n", tsp, tsn, tsk); - output->append_line(virtual_line); - sprintf( - virtual_line, " TQEx=%15.7lE, TQEy=%15.7lE, TQEz=%15.7lE\n", - cid->tqce[ilr290 - 1][0], cid->tqce[ilr290 - 1][1], cid->tqce[ilr290 - 1][2] - ); - output->append_line(virtual_line); - sprintf( - virtual_line, " TQSx=%15.7lE, TQSy=%15.7lE, TQSz=%15.7lE\n", - cid->tqcs[ilr290 - 1][0], cid->tqcs[ilr290 - 1][1], cid->tqcs[ilr290 - 1][2] - ); - output->append_line(virtual_line); + if (ipol == -1) { + output->vec_dir_tqelc1[oindex] = tep; + output->vec_dir_tqerc1[oindex] = ten; + output->vec_dir_tqekc1[oindex] = tek; + output->vec_dir_tqslc1[oindex] = tsp; + output->vec_dir_tqsrc1[oindex] = tsn; + output->vec_dir_tqskc1[oindex] = tsk; + output->vec_dir_tqexc1[oindex] = cid->tqce[0][0]; + output->vec_dir_tqeyc1[oindex] = cid->tqce[0][1]; + output->vec_dir_tqezc1[oindex] = cid->tqce[0][2]; + output->vec_dir_tqsxc1[oindex] = cid->tqcs[0][0]; + output->vec_dir_tqsyc1[oindex] = cid->tqcs[0][1]; + output->vec_dir_tqszc1[oindex] = cid->tqcs[0][2]; + } else if (ipol == 1) { + output->vec_dir_tqelc2[oindex] = tep; + output->vec_dir_tqerc2[oindex] = ten; + output->vec_dir_tqekc2[oindex] = tek; + output->vec_dir_tqslc2[oindex] = tsp; + output->vec_dir_tqsrc2[oindex] = tsn; + output->vec_dir_tqskc2[oindex] = tsk; + output->vec_dir_tqexc2[oindex] = cid->tqce[1][0]; + output->vec_dir_tqeyc2[oindex] = cid->tqce[1][1]; + output->vec_dir_tqezc2[oindex] = cid->tqce[1][2]; + output->vec_dir_tqsxc2[oindex] = cid->tqcs[1][0]; + output->vec_dir_tqsyc2[oindex] = cid->tqcs[1][1]; + output->vec_dir_tqszc2[oindex] = cid->tqcs[1][2]; + } } } //ilr290 loop - double rbirif = (real(cid->c1->fsac[0][0]) - real(cid->c1->fsac[1][1])) / real(cid->c1->fsac[0][0]); - double rdichr = (imag(cid->c1->fsac[0][0]) - imag(cid->c1->fsac[1][1])) / imag(cid->c1->fsac[0][0]); - sprintf(virtual_line, " (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))=%15.7lE\n", rbirif); - output->append_line(virtual_line); - sprintf(virtual_line, " (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))=%15.7lE\n", rdichr); - output->append_line(virtual_line); - sprintf(virtual_line, " MULC\n"); - output->append_line(virtual_line); for (int i = 0; i < 4; i++) { - sprintf( - virtual_line, " %15.7lE%15.7lE%15.7lE%15.7lE\n", - cid->cmul[i][0], cid->cmul[i][1], cid->cmul[i][2], cid->cmul[i][3] - ); - output->append_line(virtual_line); + oindex = 16 * (jindex - 1) * ndirs + 16 * done_dirs + 4 * i; + output->vec_dir_mulc[oindex] = cid->cmul[i][0]; + output->vec_dir_mulc[oindex + 1] = cid->cmul[i][1]; + output->vec_dir_mulc[oindex + 2] = cid->cmul[i][2]; + output->vec_dir_mulc[oindex + 3] = cid->cmul[i][3]; } - sprintf(virtual_line, " MULCLR\n"); - output->append_line(virtual_line); for (int i = 0; i < 4; i++) { - sprintf( - virtual_line, " %15.7lE%15.7lE%15.7lE%15.7lE\n", - cid->cmullr[i][0], cid->cmullr[i][1], cid->cmullr[i][2], cid->cmullr[i][3] - ); - output->append_line(virtual_line); + oindex = 16 * (jindex - 1) * ndirs + 16 * done_dirs + 4 * i; + output->vec_dir_mulclr[oindex] = cid->cmullr[i][0]; + output->vec_dir_mulclr[oindex + 1] = cid->cmullr[i][1]; + output->vec_dir_mulclr[oindex + 2] = cid->cmullr[i][2]; + output->vec_dir_mulclr[oindex + 3] = cid->cmullr[i][3]; } if (iavm != 0) { mmulc(cid->c1->vintm, cid->cmullr, cid->cmul); @@ -1568,37 +1493,25 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf vtppoanp->append_line(VirtualBinaryLine(value)); } } - sprintf(virtual_line, " CLUSTER (ENSEMBLE AVERAGE, MODE%2d)\n", iavm); - output->append_line(virtual_line); - if (inpol == 0) { - sprintf(virtual_line, " LIN\n"); - output->append_line(virtual_line); - } else { // label 316 - sprintf(virtual_line, " CIRC\n"); - output->append_line(virtual_line); - } // label 318 - sprintf(virtual_line, " MULC\n"); - output->append_line(virtual_line); for (int i = 0; i < 4; i++) { - sprintf( - virtual_line, " %15.7lE%15.7lE%15.7lE%15.7lE\n", - cid->cmul[i][0], cid->cmul[i][1], cid->cmul[i][2], cid->cmul[i][3] - ); - output->append_line(virtual_line); + oindex = 16 * (jindex - 1) + 4 * i; // if IAVM fails, try adding directions + output->vec_dir_mulc[oindex] = cid->cmul[i][0]; + output->vec_dir_mulc[oindex + 1] = cid->cmul[i][1]; + output->vec_dir_mulc[oindex + 2] = cid->cmul[i][2]; + output->vec_dir_mulc[oindex + 3] = cid->cmul[i][3]; } - sprintf(virtual_line, " MULCLR\n"); - output->append_line(virtual_line); for (int i = 0; i < 4; i++) { - sprintf( - virtual_line, " %15.7lE%15.7lE%15.7lE%15.7lE\n", - cid->cmullr[i][0], cid->cmullr[i][1], cid->cmullr[i][2], cid->cmullr[i][3] - ); - output->append_line(virtual_line); + oindex = 16 * (jindex - 1) + 4 * i; // if IAVM fails, try adding directions + output->vec_dir_mulclr[oindex] = cid->cmullr[i][0]; + output->vec_dir_mulclr[oindex + 1] = cid->cmullr[i][1]; + output->vec_dir_mulclr[oindex + 2] = cid->cmullr[i][2]; + output->vec_dir_mulclr[oindex + 3] = cid->cmullr[i][3]; } } // label 420, continues jphs loop if (isam < 1) phs += sa->phsstp; + done_dirs++; } // jphs loop, labeled 480 if (isam <= 1) thsl += sa->thsstp; } // jths loop, labeled 482 @@ -1609,6 +1522,7 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf #ifdef USE_NVTX nvtxRangePop(); #endif + if (jer == 0) output->vec_jxi[jindex - 1] = jxi488; interval_end = chrono::high_resolution_clock::now(); elapsed = interval_end - interval_start; message = "INFO: angle loop for scale " + to_string(jxi488) + " took " + to_string(elapsed.count()) + "s.\n"; @@ -1620,3 +1534,536 @@ int cluster_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConf return jer; } + +// >>> IMPLEMENTATION OF ClusterIterationData CLASS <<< +ClusterIterationData::ClusterIterationData(GeometryConfiguration *gconf, ScattererConfiguration *sconf, const mixMPI *mpidata, const int device_count) { + c1 = new ParticleDescriptorCluster(gconf, sconf); + const int ndi = c1->nsph * c1->nlim; + const np_int ndit = 2 * ndi; + gaps = new double[c1->nsph](); + tqev = new double[3](); + tqsv = new double[3](); + tqse = new double*[2]; + tqspe = new dcomplex*[2]; + tqss = new double*[2]; + tqsps = new dcomplex*[2]; + tqce = new double*[2]; + tqcpe = new dcomplex*[2]; + tqcs = new double*[2]; + tqcps = new dcomplex*[2]; + for (int ti = 0; ti < 2; ti++) { + tqse[ti] = new double[c1->nsph](); + tqspe[ti] = new dcomplex[c1->nsph](); + tqss[ti] = new double[c1->nsph](); + tqsps[ti] = new dcomplex[c1->nsph](); + tqce[ti] = new double[3](); + tqcpe[ti] = new dcomplex[3](); + tqcs[ti] = new double[3](); + tqcps[ti] = new dcomplex[3](); + } + gapv = new double[3](); + gapp = new dcomplex*[3]; + gappm = new dcomplex*[3]; + gap = new double*[3]; + gapm = new double*[3]; + for (int gi = 0; gi < 3; gi++) { + gapp[gi] = new dcomplex[2](); + gappm[gi] = new dcomplex[2](); + gap[gi] = new double[2](); + gapm[gi] = new double[2](); + } + u = new double[3](); + us = new double[3](); + un = new double[3](); + uns = new double[3](); + up = new double[3](); + ups = new double[3](); + unmp = new double[3](); + unsmp = new double[3](); + upmp = new double[3](); + upsmp = new double[3](); + argi = new double[1](); + args = new double[1](); + duk = new double[3](); + cextlr = new double*[4]; + cext = new double*[4]; + cmullr = new double*[4];; + cmul = new double*[4]; + for (int ci = 0; ci < 4; ci++) { + cextlr[ci] = new double[4](); + cext[ci] = new double[4](); + cmullr[ci] = new double[4](); + cmul[ci] = new double[4](); + } + zpv = new double***[c1->lm]; + for (int zi = 0; zi < c1->lm; zi++) { + zpv[zi] = new double**[3]; + for (int zj = 0; zj < 3; zj++) { + zpv[zi][zj] = new double*[2]; + for (int zk = 0; zk < 2; zk++) { + zpv[zi][zj][zk] = new double[2](); + } + } + } + am_vector = new dcomplex[ndit * ndit](); + am = new dcomplex*[ndit]; + for (int ai = 0; ai < ndit; ai++) { + am[ai] = (am_vector + ai * ndit); + } + + arg = 0.0 + 0.0 * I; + // These are suspect initializations + scan = 0.0; + cfmp = 0.0; + sfmp = 0.0; + cfsp = 0.0; + sfsp = 0.0; + // End of suspect initializations + wn = sconf->wp / 3.0e8; + xip = sconf->xip; + sqsfi = 1.0; + vk = 0.0; + number_of_scales = sconf->number_of_scales; + xiblock = (int) ceil(((double) (sconf->number_of_scales-1))/((double) mpidata->nprocs)); + lastxi = ((mpidata->rank+1) * xiblock)+1; + firstxi = lastxi-xiblock+1; + if (lastxi > sconf->number_of_scales) lastxi = sconf->number_of_scales; + +#ifdef USE_MAGMA + proc_device = mpidata->rank % device_count; +#else + proc_device = 0; +#endif + + // In the first iteration, if refinement is enabled, determine the number of refinement iterations required to arrive at the target accuracy (if achievable in a reasonable number of iterations) + refinemode = 2; + // maxrefiters and accuracygoal should be configurable and preferably set somewhere else + maxrefiters = 20; + accuracygoal = 1e-6; +} + +ClusterIterationData::ClusterIterationData(const ClusterIterationData& rhs) { + c1 = new ParticleDescriptorCluster(reinterpret_cast<ParticleDescriptorCluster &>(*(rhs.c1))); + const int ndi = c1->nsph * c1->nlim; + const np_int ndit = 2 * ndi; + gaps = new double[c1->nsph](); + for (int gi = 0; gi < c1->nsph; gi++) gaps[gi] = rhs.gaps[gi]; + tqev = new double[3](); + tqsv = new double[3](); + for (int ti = 0; ti < 3; ti++) { + tqev[ti] = rhs.tqev[ti]; + tqsv[ti] = rhs.tqsv[ti]; + } + tqse = new double*[2]; + tqspe = new dcomplex*[2]; + tqss = new double*[2]; + tqsps = new dcomplex*[2]; + tqce = new double*[2]; + tqcpe = new dcomplex*[2]; + tqcs = new double*[2]; + tqcps = new dcomplex*[2]; + for (int ti = 0; ti < 2; ti++) { + tqse[ti] = new double[c1->nsph](); + tqspe[ti] = new dcomplex[c1->nsph](); + tqss[ti] = new double[c1->nsph](); + tqsps[ti] = new dcomplex[c1->nsph](); + for (int tj = 0; tj < c1->nsph; tj++) { + tqse[ti][tj] = rhs.tqse[ti][tj]; + tqspe[ti][tj] = rhs.tqspe[ti][tj]; + tqss[ti][tj] = rhs.tqss[ti][tj]; + tqsps[ti][tj] = rhs.tqsps[ti][tj]; + } + tqce[ti] = new double[3](); + tqcpe[ti] = new dcomplex[3](); + tqcs[ti] = new double[3](); + tqcps[ti] = new dcomplex[3](); + for (int tj = 0; tj < 3; tj++) { + tqce[ti][tj] = rhs.tqce[ti][tj]; + tqcpe[ti][tj] = rhs.tqcpe[ti][tj]; + tqcs[ti][tj] = rhs.tqcs[ti][tj]; + tqcps[ti][tj] = rhs.tqcps[ti][tj]; + } + } + gapv = new double[3](); + gapp = new dcomplex*[3]; + gappm = new dcomplex*[3]; + gap = new double*[3]; + gapm = new double*[3]; + for (int gi = 0; gi < 3; gi++) { + gapv[gi] = rhs.gapv[gi]; + gapp[gi] = new dcomplex[2](); + gappm[gi] = new dcomplex[2](); + gap[gi] = new double[2](); + gapm[gi] = new double[2](); + for (int gj = 0; gj < 2; gj++) { + gapp[gi][gj] = rhs.gapp[gi][gj]; + gappm[gi][gj] = rhs.gappm[gi][gj]; + gap[gi][gj] = rhs.gap[gi][gj]; + gapm[gi][gj] = rhs.gapm[gi][gj]; + } + } + u = new double[3](); + us = new double[3](); + un = new double[3](); + uns = new double[3](); + up = new double[3](); + ups = new double[3](); + unmp = new double[3](); + unsmp = new double[3](); + upmp = new double[3](); + upsmp = new double[3](); + duk = new double[3](); + for (int ui = 0; ui < 3; ui++) { + u[ui] = rhs.u[ui]; + us[ui] = rhs.us[ui]; + un[ui] = rhs.un[ui]; + uns[ui] = rhs.uns[ui]; + up[ui] = rhs.up[ui]; + ups[ui] = rhs.ups[ui]; + unmp[ui] = rhs.unmp[ui]; + unsmp[ui] = rhs.unsmp[ui]; + upmp[ui] = rhs.upmp[ui]; + upsmp[ui] = rhs.upsmp[ui]; + duk[ui] = rhs.duk[ui]; + } + argi = new double[1](); + args = new double[1](); + argi[0] = rhs.argi[0]; + args[0] = rhs.args[0]; + cextlr = new double*[4]; + cext = new double*[4]; + cmullr = new double*[4];; + cmul = new double*[4]; + for (int ci = 0; ci < 4; ci++) { + cextlr[ci] = new double[4](); + cext[ci] = new double[4](); + cmullr[ci] = new double[4](); + cmul[ci] = new double[4](); + for (int cj = 0; cj < 4; cj++) { + cextlr[ci][cj] = rhs.cextlr[ci][cj]; + cext[ci][cj] = rhs.cext[ci][cj]; + cmullr[ci][cj] = rhs.cmullr[ci][cj]; + cmul[ci][cj] = rhs.cmul[ci][cj]; + } + } + zpv = new double***[c1->lm]; + for (int zi = 0; zi < c1->lm; zi++) { + zpv[zi] = new double**[3]; + for (int zj = 0; zj < 3; zj++) { + zpv[zi][zj] = new double*[2]; + for (int zk = 0; zk < 2; zk++) { + zpv[zi][zj][zk] = new double[2](); + zpv[zi][zj][zk][0] = rhs.zpv[zi][zj][zk][0]; + zpv[zi][zj][zk][1] = rhs.zpv[zi][zj][zk][1]; + } + } + } + am_vector = new dcomplex[ndit * ndit](); + for (np_int ai = 0; ai < ndit * ndit; ai++) am_vector[ai] = rhs.am_vector[ai]; + am = new dcomplex*[ndit]; + for (np_int ai = 0; ai < ndit; ai++) { + am[ai] = (am_vector + ai * ndit); + } + + arg = rhs.arg; + // These are suspect initializations + scan = rhs.scan; + cfmp = rhs.cfmp; + sfmp = rhs.sfmp; + cfsp = rhs.cfsp; + sfsp = rhs.sfsp; + // End of suspect initializations + wn = rhs.wn; + xip = rhs.xip; + sqsfi = rhs.sqsfi; + vk = rhs.vk; + firstxi = rhs.firstxi; + lastxi = rhs.lastxi; + xiblock = rhs.xiblock; + number_of_scales = rhs.number_of_scales; + + proc_device = rhs.proc_device; + refinemode = rhs.refinemode; + maxrefiters = rhs.maxrefiters; + accuracygoal = rhs.accuracygoal; +} + +#ifdef MPI_VERSION +ClusterIterationData::ClusterIterationData(const mixMPI *mpidata, const int device_count) { + c1 = new ParticleDescriptorCluster(mpidata); + const int ndi = c1->nsph * c1->nlim; + const np_int ndit = 2 * ndi; + gaps = new double[c1->nsph](); + MPI_Bcast(gaps, c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + tqev = new double[3](); + tqsv = new double[3](); + MPI_Bcast(tqev, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqsv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + tqse = new double*[2]; + tqspe = new dcomplex*[2]; + tqss = new double*[2]; + tqsps = new dcomplex*[2]; + tqce = new double*[2]; + tqcpe = new dcomplex*[2]; + tqcs = new double*[2]; + tqcps = new dcomplex*[2]; + for (int ti = 0; ti < 2; ti++) { + tqse[ti] = new double[c1->nsph](); + tqspe[ti] = new dcomplex[c1->nsph](); + tqss[ti] = new double[c1->nsph](); + tqsps[ti] = new dcomplex[c1->nsph](); + MPI_Bcast(tqse[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqspe[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(tqss[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqsps[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + tqce[ti] = new double[3](); + tqcpe[ti] = new dcomplex[3](); + tqcs[ti] = new double[3](); + tqcps[ti] = new dcomplex[3](); + MPI_Bcast(tqce[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcpe[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcs[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcps[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + } + gapv = new double[3](); + gapp = new dcomplex*[3]; + gappm = new dcomplex*[3]; + gap = new double*[3]; + gapm = new double*[3]; + MPI_Bcast(gapv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + for (int gi = 0; gi < 3; gi++) { + gapp[gi] = new dcomplex[2](); + gappm[gi] = new dcomplex[2](); + gap[gi] = new double[2](); + gapm[gi] = new double[2](); + MPI_Bcast(gapp[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(gappm[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(gap[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(gapm[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } + u = new double[3](); + us = new double[3](); + un = new double[3](); + uns = new double[3](); + up = new double[3](); + ups = new double[3](); + unmp = new double[3](); + unsmp = new double[3](); + upmp = new double[3](); + upsmp = new double[3](); + duk = new double[3](); + MPI_Bcast(u, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(us, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(un, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(uns, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(up, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(ups, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(duk, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + argi = new double[1](); + args = new double[1](); + MPI_Bcast(argi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(args, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + cextlr = new double*[4]; + cext = new double*[4]; + cmullr = new double*[4];; + cmul = new double*[4]; + for (int ci = 0; ci < 4; ci++) { + cextlr[ci] = new double[4](); + cext[ci] = new double[4](); + cmullr[ci] = new double[4](); + cmul[ci] = new double[4](); + MPI_Bcast(cextlr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cext[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cmullr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cmul[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } + zpv = new double***[c1->lm]; + for (int zi = 0; zi < c1->lm; zi++) { + zpv[zi] = new double**[3]; + for (int zj = 0; zj < 3; zj++) { + zpv[zi][zj] = new double*[2]; + for (int zk = 0; zk < 2; zk++) { + zpv[zi][zj][zk] = new double[2](); + MPI_Bcast(zpv[zi][zj][zk], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } + } + } + am_vector = new dcomplex[ndit * ndit](); + am = new dcomplex*[ndit]; + for (np_int ai = 0; ai < ndit; ai++) { + am[ai] = (am_vector + ai * ndit); + MPI_Bcast(am[ai], ndit, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + } + MPI_Bcast(&arg, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(&scan, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&wn, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xip, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sqsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&vk, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xiblock, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&number_of_scales, 1, MPI_INT, 0, MPI_COMM_WORLD); + lastxi = ((mpidata->rank+1) * xiblock)+1; + firstxi = lastxi-xiblock+1; + if (lastxi > number_of_scales) lastxi = number_of_scales; + +#ifdef USE_MAGMA + proc_device = mpidata->rank % device_count; +#else + proc_device = 0; +#endif + MPI_Bcast(&refinemode, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&maxrefiters, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&accuracygoal, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); +} + +void ClusterIterationData::mpibcast(const mixMPI *mpidata) { + c1->mpibcast(mpidata); + const int ndi = c1->nsph * c1->nlim; + const np_int ndit = 2 * ndi; + MPI_Bcast(gaps, c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqev, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqsv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + for (int ti = 0; ti < 2; ti++) { + MPI_Bcast(tqse[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqspe[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(tqss[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqsps[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(tqce[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcpe[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcs[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcps[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + } + MPI_Bcast(gapv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + for (int gi = 0; gi < 3; gi++) { + MPI_Bcast(gapp[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(gappm[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(gap[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(gapm[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } + MPI_Bcast(u, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(us, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(un, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(uns, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(up, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(ups, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(duk, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(argi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(args, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + for (int ci = 0; ci < 4; ci++) { + MPI_Bcast(cextlr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cext[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cmullr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cmul[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } + for (int zi = 0; zi < c1->lm; zi++) { + for (int zj = 0; zj < 3; zj++) { + for (int zk = 0; zk < 2; zk++) { + MPI_Bcast(zpv[zi][zj][zk], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } + } + } + // since MPI expects an int argument for the number of elements to transfer in one go, transfer am one row at a time + for (int ai = 0; ai < ndit; ai++) { + MPI_Bcast(am[ai], ndit, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + } + MPI_Bcast(&arg, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(&scan, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&wn, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xip, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sqsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&vk, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xiblock, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&number_of_scales, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&refinemode, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&maxrefiters, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&accuracygoal, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); +} +#endif + +ClusterIterationData::~ClusterIterationData() { + const int nsph = c1->nsph; + delete[] am_vector; + delete[] am; + for (int zi = c1->lm - 1; zi > -1; zi--) { + for (int zj = 2; zj > -1; zj--) { + delete[] zpv[zi][zj][1]; + delete[] zpv[zi][zj][0]; + delete[] zpv[zi][zj]; + } + delete[] zpv[zi]; + } + delete[] zpv; + delete c1; + delete[] gaps; + for (int ti = 1; ti > -1; ti--) { + delete[] tqse[ti]; + delete[] tqss[ti]; + delete[] tqspe[ti]; + delete[] tqsps[ti]; + delete[] tqce[ti]; + delete[] tqcpe[ti]; + delete[] tqcs[ti]; + delete[] tqcps[ti]; + } + delete[] tqse; + delete[] tqss; + delete[] tqspe; + delete[] tqsps; + delete[] tqce; + delete[] tqcpe; + delete[] tqcs; + delete[] tqcps; + delete[] tqev; + delete[] tqsv; + for (int gi = 2; gi > -1; gi--) { + delete[] gapp[gi]; + delete[] gappm[gi]; + delete[] gap[gi]; + delete[] gapm[gi]; + } + delete[] gapp; + delete[] gappm; + delete[] gap; + delete[] gapm; + delete[] gapv; + delete[] u; + delete[] us; + delete[] un; + delete[] uns; + delete[] up; + delete[] ups; + delete[] unmp; + delete[] unsmp; + delete[] upmp; + delete[] upsmp; + delete[] argi; + delete[] args; + delete[] duk; + for (int ci = 3; ci > -1; ci--) { + delete[] cextlr[ci]; + delete[] cext[ci]; + delete[] cmullr[ci]; + delete[] cmul[ci]; + } + delete[] cextlr; + delete[] cext; + delete[] cmullr; + delete[] cmul; +} +// >>> END OF ClusterIterationData CLASS IMPLEMENTATION <<< diff --git a/src/cluster/np_cluster.cpp b/src/cluster/np_cluster.cpp index a6cfc15cbb5f1492af2a4f18cf738f5795fe937f..7beb785cf6003945889b2d9263bbf2fa23934942 100644 --- a/src/cluster/np_cluster.cpp +++ b/src/cluster/np_cluster.cpp @@ -35,6 +35,12 @@ #include <cstdio> #include <string> +#ifdef USE_MPI +#ifndef MPI_VERSION +#include <mpi.h> +#endif +#endif + #ifndef INCLUDE_TYPES_H_ #include "../include/types.h" #endif @@ -64,26 +70,27 @@ extern void cluster(const string& config_file, const string& data_file, const st * \return result: `int` An exit code passed to the OS (0 for succesful execution). */ int main(int argc, char **argv) { + int ierr = 0; #ifdef MPI_VERSION - int ierr = MPI_Init(&argc, &argv); - // create and initialise class with essential MPI data - mixMPI *mpidata = new mixMPI(MPI_COMM_WORLD); + ierr = MPI_Init(&argc, &argv); + // create and initialise class with essential MPI data + mixMPI *mpidata = new mixMPI(MPI_COMM_WORLD); #else - // create a the class with dummy data if we are not using MPI at all - mixMPI *mpidata = new mixMPI(); + // create a the class with dummy data if we are not using MPI at all + mixMPI *mpidata = new mixMPI(); #endif - string config_file = "../../test_data/cluster/DEDFB"; - string data_file = "../../test_data/cluster/DCLU"; - string output_path = "."; - if (argc == 4) { - config_file = string(argv[1]); - data_file = string(argv[2]); - output_path = string(argv[3]); - } - cluster(config_file, data_file, output_path, mpidata); + string config_file = "../../test_data/cluster/DEDFB"; + string data_file = "../../test_data/cluster/DCLU"; + string output_path = "."; + if (argc == 4) { + config_file = string(argv[1]); + data_file = string(argv[2]); + output_path = string(argv[3]); + } + cluster(config_file, data_file, output_path, mpidata); #ifdef MPI_VERSION - MPI_Finalize(); + MPI_Finalize(); #endif - delete mpidata; - return 0; + delete mpidata; + return ierr; } diff --git a/src/include/Commons.h b/src/include/Commons.h index 88958c8d8ff15b9b45f38b5f2f3d717c276f22d8..cce0a6537d1f4854619b10d1b01fd99ea867e071 100644 --- a/src/include/Commons.h +++ b/src/include/Commons.h @@ -33,10 +33,6 @@ #ifndef INCLUDE_COMMONS_H_ #define INCLUDE_COMMONS_H_ -#ifdef USE_MPI -#include <mpi.h> -#endif - class ParticleDescriptor; /*! \brief Structure with essential MPI data. @@ -69,100 +65,6 @@ public: ~mixMPI(); }; -/*! \brief A data structure representing the information used for a single scale - * of the CLUSTER case. - */ -class ClusterIterationData { -public: - //! \brief Pointer to a ParticleDescriptor structure. - ParticleDescriptor *c1; - //! \brief Vector of geometric asymmetry factors. - double *gaps; - double **tqse; - dcomplex **tqspe; - double **tqss; - dcomplex **tqsps; - double ****zpv; - double **gapm; - dcomplex **gappm; - double *argi; - double *args; - double **gap; - dcomplex **gapp; - double **tqce; - dcomplex **tqcpe; - double **tqcs; - dcomplex **tqcps; - double *duk; - double **cextlr; - double **cext; - double **cmullr; - double **cmul; - double *gapv; - double *tqev; - double *tqsv; - double *u; - double *us; - double *un; - double *uns; - double *up; - double *ups; - double *unmp; - double *unsmp; - double *upmp; - double *upsmp; - //! \brief Scattering angle. - double scan; - double cfmp; - double sfmp; - double cfsp; - double sfsp; - double qsfi; - double sqsfi; - dcomplex *am_vector; - dcomplex **am; - dcomplex arg; - //! \brief Vacuum magnitude of wave vector. - double vk; - //! \brief Wave number. - double wn; - double xip; - int number_of_scales; - int xiblock; - int firstxi; - int lastxi; - //! \brief ID of the GPU used by one MPI process. - int proc_device; - //! \brief Refinement mode selction flag. - int refinemode; - //! \brief Maximum number of refinement iterations. - int maxrefiters; - //! \brief Required accuracy level. - double accuracygoal; - - ClusterIterationData(GeometryConfiguration *gconf, ScattererConfiguration *sconf, const mixMPI *mpidata, const int device_count); - - ClusterIterationData(const ClusterIterationData& rhs); - -#ifdef MPI_VERSION - ClusterIterationData(const mixMPI *mpidata, const int device_count); - - /*! \brief Broadcast over MPI the ClusterIterationData instance from MPI process 0 to all others. - * - * When using MPI, the initial ClusterIterationData instance created by MPI process 0 - * needs to be replicated on all other processes. This function sends it using - * MPI broadcast calls. The MPI broadcast calls in this function must match those - * in the constructor using the mixMPI pointer. - * - * \param mpidata: `mixMPI *` Pointer to the mpi structure used to do the MPI broadcast. - */ - void mpibcast(const mixMPI *mpidata); -#endif - - ~ClusterIterationData(); - -}; - /*! \brief Basic data structure describing the particle model and its interaction with fields. * * This class forms a base of the data structure collections that are used by the @@ -322,10 +224,12 @@ public: dcomplex *dlri; //! \brief Vector of dielectric constants. dcomplex *dc0; - //! \brief TBD + //! \brief Vector of complex refractive indices. dcomplex *vkt; //! \brief Vector of sizes in units of 2*PI/LAMBDA double *vsz; + //! \brief Total geometric cross-section. + double gcs; // >>> END OF SECTION COMMON TO ALL DESCRIPTOR TYPES <<< // // >>> NEEDED BY SPHERE AND CLUSTER <<< // @@ -352,23 +256,23 @@ public: // >>> END OF SECTION NEEDED BY SPHERE AND CLUSTER <<< // // >>> NEEDED BY CLUSTER <<< - // \brief Vector of field intensity components. + //! \brief Vector of field intensity components. dcomplex *vintt; - //! \brief Total forward scattering amplitude. + //! \brief Total forward scattering amplitude of the spheres. dcomplex tfsas; - //! \brief Total scattering amplitude. + //! \brief Total scattering amplitude of the spheres. dcomplex **tsas; - //! \brief Total scattering cross-section. + //! \brief Sphere scattering cross-section. double scs; - //! \brief Total extinction cross-section. + //! \brief Sphere extinction cross-section. double ecs; - //! \brief Total absorption cross-section. + //! \brief Sphere absorption cross-section. double acs; //! \brief TBD. dcomplex **gis; //! \brief TBD. dcomplex **gls; - //! \brief TBD. + //! \brief Mean scattering amplitude components. dcomplex **sam; // >>> END OF SECTION NEEDED BY CLUSTER <<< // @@ -403,8 +307,6 @@ public: const int& ndit = _ndit; //! \brief Read-only view of NDM. const int& ndm = _ndm; - //! \brief Total geometric cross-section. - double gcs; //! \brief TBD dcomplex *vh; diff --git a/src/include/Configuration.h b/src/include/Configuration.h index f51e8529c18a95e1e6969543b51f0dda41daaf22..81477ab6b223ef61f158137702a3a4c5753ed3e4 100644 --- a/src/include/Configuration.h +++ b/src/include/Configuration.h @@ -67,17 +67,17 @@ protected: int _le; //! \brief Maximum dimension of allocated matrix allowance (deprecated). np_int _mxndm; - //! \brief QUESTION: definition? + //! \brief Flag for intensity. int _iavm; //! \brief Incident field polarization status (0 - linear, 1 - circular). int _in_pol; - //! \brief Number of transition points. QUESTION: correct? + //! \brief Number of points for transition layer integration. int _npnt; - //! \brief Transition smoothness. QUESTION: correct? + //! \brief Number of points for non-transition layer integration. int _npntts; //! \brief Type of meridional plane definition. int _isam; - //! \brief Transition matrix layer ID. QUESTION: correct? + //! \brief Scale index of the T-matrix output. int _jwtm; //! \brief Incident field initial azimuth. double _in_theta_start; @@ -121,17 +121,17 @@ public: const int& le = _le; //! \brief Read only view on maximum dimension of allocated matrix allowance (deprecated). const np_int& mxndm = _mxndm; - //! \brief QUESTION: definition? + //! \brief Read only view on the intensity mode flag. const int& iavm = _iavm; //! \brief Read only view on incident field polarization status (0 - linear, 1 - circular). const int& in_pol = _in_pol; - //! \brief Read only view on number of transition points. QUESTION: correct? + //! \brief Read only view on number of points for transition layer integration. const int& npnt = _npnt; - //! \brief Read only view on transition smoothness. QUESTION: correct? + //! \brief Read only view on number of points for non-transition layer integration. const int& npntts = _npntts; //! \brief Read only view on type of meridional plane definition. const int& isam = _isam; - //! \brief Read only view on transition matrix layer ID. QUESTION: correct? + //! \brief Read only view on scale index for T-matrix output. const int& jwtm = _jwtm; //! \brief Read only view on incident field initial azimuth. const double& in_theta_start = _in_theta_start; @@ -157,14 +157,6 @@ public: const double& sc_phi_step = _sc_phi_step; //! \brief Read only view on scattered field final elevation. const double& sc_phi_end = _sc_phi_end; - /* - //! \brief Read only view on vector of spherical components X coordinates. - const double *sph_x = _sph_x; - //! \brief Read only view on vector of spherical components Y coordinates. - const double *sph_y = _sph_y; - //! \brief Read only view on vector of spherical components Z coordinates. - const double *sph_z = _sph_z; - */ /*! \brief Build a scattering geometry configuration structure. * @@ -394,6 +386,7 @@ public: * memory structures. * * \param nsph: `int` The number of spheres in the simulation. + * \param configs: `int` Number of spherical monometer configuration types. * \param scale_vector: `double*` The radiation-particle scale vector. * \param nxi: `int` The number of radiation-particle scalings. * \param variable_name: `string` The name of the radiation-particle scaling type. @@ -524,22 +517,6 @@ public: */ int get_nshl(int index) { return _nshl_vec[index]; } - /* - /*! \brief Get the value of a parameter by name. - * - * The proper way to access read-only parameters from outside a class is to define - * public methods that return their values. For configuration operations, whose - * optimization is not critical, it is possible to define a single function that - * returns simple scalar values called by name. Access to more complicated data - * structures, on the other hand, require specialized methods which avoid the - * burden of searching the necessary value across the whole array every time. - * - * \param param_name: `string` Name of the parameter to be retrieved. - * \return value: `double` Value of the requested parameter. - - double get_param(const std::string& param_name); - */ - /*! \brief Get the radius of a sphere by its index. * * This is a specialized function to get the radius of a sphere through its @@ -555,7 +532,8 @@ public: * This is a specialized function to access a scale (generally a wavelength), * through its index. * - * \param index: `int` Index of the scale to be retrieved. + * \param row: `int` Row index of the element to be retrieved. + * \param column: `int` Column index of the element to be retrieved. * \return scale: `double` The desired scale. */ double get_rcf(int row, int column) { return _rcf[row][column]; } diff --git a/src/include/IterationData.h b/src/include/IterationData.h new file mode 100644 index 0000000000000000000000000000000000000000..8b8dca9e98afeda9201b92a7b10c1478f747046f --- /dev/null +++ b/src/include/IterationData.h @@ -0,0 +1,493 @@ +/* Copyright (C) 2024 INAF - Osservatorio Astronomico di Cagliari + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + A copy of the GNU General Public License is distributed along with + this program in the COPYING file. If not, see: <https://www.gnu.org/licenses/>. + */ + +/*! \file IterationData.h + * + * \brief Multi-process communication data structures. + * + */ + +#ifndef INCLUDE_ITERATION_DATA_H_ +#define INCLUDE_ITERATION_DATA_H_ + +// >>> DEFINITION OF ClusterIterationData CLASS <<< +/*! \brief A data structure representing the information used for a single scale + * of the CLUSTER case. + */ +class ClusterIterationData { +public: + //! \brief Pointer to a ParticleDescriptor structure. + ParticleDescriptor *c1; + //! \brief Vector of geometric asymmetry factors. + double *gaps; + //! \brief Components of extinction contribution to radiation torque on a single sphere along k. + double **tqse; + //! \brief Components of polarized extinction contribution to radiation torque on a single sphere along k. + dcomplex **tqspe; + //! \brief Components of scattering contribution to radiation torque on a single sphere along k. + double **tqss; + //! \brief Components of polarized scattering contribution to radiation torque on a single sphere along k. + dcomplex **tqsps; + //! \brief L-dependent coefficients of the geometric asymmetry parameter. + double ****zpv; + //! \brief Mean geometric asymmetry parameters. + double **gapm; + //! \brief Mean geometric asymmetry parameters referred to polarization plane. + dcomplex **gappm; + //! \brief Imaginary part of the harmonic functions argument. + double *argi; + //! \brief Argument of the harmonic functions referred to the scattering plane. + double *args; + //! \brief Geometric asymmetry parameters. + double **gap; + //! \brief Geometric asymmetry parameters referred to polarization plane. + dcomplex **gapp; + //! \brief Components of extinction contribution to radiation torque on the cluster along k. + double **tqce; + //! \brief Components of extinction contribution to radiation torque on the cluster along k referred to polarization plane. + dcomplex **tqcpe; + //! \brief Components of scattering contribution to radiation torque on the cluster along k. + double **tqcs; + //! \brief Components of scattering contribution to radiation torque on the cluster along k referred to polarization plane. + dcomplex **tqcps; + //! \brief Variation of unitary radiation vector. QUESTION: correct? + double *duk; + //! \brief Cluster extinction cross-section components referred to scattering plane. + double **cextlr; + //! \brief Cluster extinction cross-section components referred to meridional plane. + double **cext; + //! \brief Cluster Mueller Transformation Matrix components referred to scattering plane. + double **cmullr; + //! \brief Cluster Mueller Transformation Matrix components referred to meridional plane. + double **cmul; + //! \brief Geometric asymmetry parameter components. + double *gapv; + //! \brief Radiation extinction torque components. + double *tqev; + //! \brief Radiation scattering torque components. + double *tqsv; + //! \brief Incident unitary vector components. + double *u; + //! \brief Scattered unitary vector components. + double *us; + //! \brief Normal unitary vector components. + double *un; + //! \brief Normal scattered unitary vector components. + double *uns; + //! \brief Incident unitary vector components on polarization plane. + double *up; + //! \brief Scattered unitary vector components on polarization plane. + double *ups; + //! \brief Mean unitary vector components normal to polarization plane. + double *unmp; + //! \brief Mean scattered unitary vector components normal to polarization plane. + double *unsmp; + //! \brief Mean incident unitary vector components on polarization plane. + double *upmp; + //! \brief Mean scattered unitary vector components on polarization plane. + double *upsmp; + //! \brief Scattering angle. + double scan; + //! \brief Control parameter on incidence direction referred to meridional plane. + double cfmp; + //! \brief Control parameter on scattering direction referred to meridional plane. + double sfmp; + //! \brief Control parameter on incidence direction referred to scattering plane. + double cfsp; + //! \brief Control parameter on scattering direction referred to scattering plane. + double sfsp; + //! \brief SQSFI = XI^-2 + double sqsfi; + //! \brief Vectorized scattering coefficient matrix. + dcomplex *am_vector; + //! \brief Scattering coefficient matrix. + dcomplex **am; + //! \brief Argument of harmonic functions. QUESTION: correct? + dcomplex arg; + //! \brief Vacuum magnitude of wave vector. + double vk; + //! \brief Wave number. + double wn; + //! \brief Normalization scale. QUESTION: correct? + double xip; + //! \brief Number of scales (wavelengths) to be computed. + int number_of_scales; + //! \brief Size of the block of scales handled by the current process. + int xiblock; + //! \brief Index of the first scale handled by the current process. + int firstxi; + //! \brief Index of the last scale handled by the current process. + int lastxi; + //! \brief ID of the GPU used by one MPI process. + int proc_device; + //! \brief Refinement mode selction flag. + int refinemode; + //! \brief Maximum number of refinement iterations. + int maxrefiters; + //! \brief Required accuracy level. + double accuracygoal; + + /*! \brief `ClusterIterationData` default instance constructor. + * + * \param gconf: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` object. + * \param sconf: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` object. + * \param mpidata: `mixMPI *` Pointer to a `mixMPI` object. + * \param device_count: `const int` Number of offload devices available on the system. + */ + ClusterIterationData(GeometryConfiguration *gconf, ScattererConfiguration *sconf, const mixMPI *mpidata, const int device_count); + + /*! \brief `ClusterIterationData` copy constructor. + * + * \param rhs: `const ClusterIterationData &` Reference to the `ClusterIterationData` object to be copied. + */ + ClusterIterationData(const ClusterIterationData& rhs); + +#ifdef MPI_VERSION + /*! \brief `ClusterIterationData` MPI constructor. + * + * \param mpidata: `const mixMPI *` Pointer to a `mixMPI` instance. + * \param device_count: `const int` Number of offload devices available on the system. + */ + ClusterIterationData(const mixMPI *mpidata, const int device_count); + + /*! \brief Broadcast over MPI the ClusterIterationData instance from MPI process 0 to all others. + * + * When using MPI, the initial ClusterIterationData instance created by MPI process 0 + * needs to be replicated on all other processes. This function sends it using + * MPI broadcast calls. The MPI broadcast calls in this function must match those + * in the constructor using the mixMPI pointer. + * + * \param mpidata: `mixMPI *` Pointer to the mpi structure used to do the MPI broadcast. + */ + void mpibcast(const mixMPI *mpidata); +#endif // MPI_VERSION + + /*! \brief `ClusterIterationData` instance destroyer. + */ + ~ClusterIterationData(); +}; +// >>> END OF ClusterIterationData CLASS DEFINITION <<< + +// >>> DEFINITION OF InclusionIterationData CLASS <<< +/*! \brief A data structure representing the information used for a single scale + * of the INCLUSION case. + */ +class InclusionIterationData { +protected: + //! \brief Vectorized geometric asymmetry parameter components. + double *vec_zpv; + +public: + //! \brief External layer index. + int nimd; + //! \brief External layer radius. + double extr; + + //! \brief Pointer to a ParticleDescriptor structure. + ParticleDescriptor *c1; + //! \brief Vector of geometric asymmetry factors. + double *gaps; + //! \brief Components of extinction contribution to radiation torque on a single sphere along k. + double **tqse; + //! \brief Components of polarized extinction contribution to radiation torque on a single sphere along k. + dcomplex **tqspe; + //! \brief Components of scattering contribution to radiation torque on a single sphere along k. + double **tqss; + //! \brief Components of polarized scattering contribution to radiation torque on a single sphere along k. + dcomplex **tqsps; + //! \brief L-dependent coefficients of the geometric asymmetry parameter. + double ****zpv; + //! \brief Mean geometric asymmetry parameters. + double **gapm; + //! \brief Mean geometric asymmetry parameters referred to polarization plane. + dcomplex **gappm; + //! \brief Imaginary part of the harmonic functions argument. + double *argi; + //! \brief Argument of the harmonic functions referred to the scattering plane. + double *args; + //! \brief Geometric asymmetry parameters. + double **gap; + //! \brief Geometric asymmetry parameters referred to polarization plane. + dcomplex **gapp; + //! \brief Components of extinction contribution to radiation torque on the cluster along k. + double **tqce; + //! \brief Components of extinction contribution to radiation torque on the cluster along k referred to polarization plane. + dcomplex **tqcpe; + //! \brief Components of scattering contribution to radiation torque on the cluster along k. + double **tqcs; + //! \brief Components of scattering contribution to radiation torque on the cluster along k referred to polarization plane. + dcomplex **tqcps; + //! \brief Variation of unitary radiation vector. QUESTION: correct? + double *duk; + //! \brief Cluster extinction cross-section components referred to scattering plane. + double **cextlr; + //! \brief Cluster extinction cross-section components referred to meridional plane. + double **cext; + //! \brief Cluster Mueller Transformation Matrix components referred to scattering plane. + double **cmullr; + //! \brief Cluster Mueller Transformation Matrix components referred to meridional plane. + double **cmul; + //! \brief Geometric asymmetry parameter components. + double *gapv; + //! \brief Radiation extinction torque components. + double *tqev; + //! \brief Radiation scattering torque components. + double *tqsv; + //! \brief Incident unitary vector components. + double *u; + //! \brief Scattered unitary vector components. + double *us; + //! \brief Normal unitary vector components. + double *un; + //! \brief Normal scattered unitary vector components. + double *uns; + //! \brief Incident unitary vector components on polarization plane. + double *up; + //! \brief Scattered unitary vector components on polarization plane. + double *ups; + //! \brief Mean unitary vector components normal to polarization plane. + double *unmp; + //! \brief Mean scattered unitary vector components normal to polarization plane. + double *unsmp; + //! \brief Mean incident unitary vector components on polarization plane. + double *upmp; + //! \brief Mean scattered unitary vector components on polarization plane. + double *upsmp; + //! \brief Scattering angle. + double scan; + //! \brief Control parameter on incidence direction referred to meridional plane. + double cfmp; + //! \brief Control parameter on scattering direction referred to meridional plane. + double sfmp; + //! \brief Control parameter on incidence direction referred to scattering plane. + double cfsp; + //! \brief Control parameter on scattering direction referred to scattering plane. + double sfsp; + //! \brief SQSFI = XI^-2 + double sqsfi; + //! \brief Vectorized scattering coefficient matrix. + dcomplex *am_vector; + //! \brief Scattering coefficient matrix. + dcomplex **am; + //! \brief Argument of harmonic functions. QUESTION: correct? + dcomplex arg; + //! \brief Vacuum magnitude of wave vector. + double vk; + //! \brief Wave number. + double wn; + //! \brief Normalization scale. QUESTION: correct? + double xip; + //! \brief Number of scales (wavelengths) to be computed. + int number_of_scales; + //! \brief Size of the block of scales handled by the current process. + int xiblock; + //! \brief Index of the first scale handled by the current process. + int firstxi; + //! \brief Index of the last scale handled by the current process. + int lastxi; + //! \brief ID of the GPU used by one MPI process. + int proc_device; + //! \brief Refinement mode selction flag. + int refinemode; + //! \brief Maximum number of refinement iterations. + int maxrefiters; + //! \brief Required accuracy level. + double accuracygoal; + + /*! \brief `InclusionIterationData` default instance constructor. + * + * \param gconf: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` object. + * \param sconf: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` object. + * \param mpidata: `mixMPI *` Pointer to a `mixMPI` object. + * \param device_count: `const int` Number of offload devices available on the system. + */ + InclusionIterationData(GeometryConfiguration *gconf, ScattererConfiguration *sconf, const mixMPI *mpidata, const int device_count); + + /*! \brief `InclusionIterationData` copy constructor. + * + * \param rhs: `const InclusionIterationData &` Reference to the `InclusionIterationData` object to be copied. + */ + InclusionIterationData(const InclusionIterationData& rhs); + +#ifdef MPI_VERSION + /*! \brief `InclusionIterationData` MPI constructor. + * + * \param mpidata: `const mixMPI *` Pointer to a `mixMPI` instance. + * \param device_count: `const int` Number of offload devices available on the system. + */ + InclusionIterationData(const mixMPI *mpidata, const int device_count); + + /*! \brief Broadcast over MPI the InclusionIterationData instance from MPI process 0 to all others. + * + * When using MPI, the initial InclusionIterationData instance created by MPI process 0 + * needs to be replicated on all other processes. This function sends it using + * MPI broadcast calls. The MPI broadcast calls in this function must match those + * in the constructor using the mixMPI pointer. + * + * \param mpidata: `mixMPI *` Pointer to the mpi structure used to do the MPI broadcast. + */ + void mpibcast(const mixMPI *mpidata); +#endif + + /*! \brief `InclusionIterationData` instance destroyer. + */ + ~InclusionIterationData(); +}; +// >>> END OF InclusionIterationData CLASS DEFINITION <<< // + +// >>> DEFINITION OF SphereIterationData CLASS <<< +/*! \brief A data structure representing the information used for a single scale + * of the SPHERE case. + */ +class SphereIterationData { +protected: + //! \brief Number of spheres + int _nsph; + //! \brief Maximum field expansion order. + int _lm; + //! \brief Vector of Mueller matrix components. + double *vec_cmul; + //! \brief Vector of Mueller matrix components referred to meridional plane. + double *vec_cmullr; + //! Vectorized TQSPE. + dcomplex *vec_tqspe; + //! Vectorized TQSPS. + dcomplex *vec_tqsps; + //! Vectorized TQSE. + double *vec_tqse; + //! Vectorized TQSS. + double *vec_tqss; + //! Vectorized ZPV. + double *vec_zpv; + +public: + //! \brief Vacuum magnitude of wave vector. + double vk; + //! \brief Wave number. + double wn; + //! \brief Normalization scale. QUESTION: correct? + double xip; + //! \brief Number of scales (wavelengths) to be computed. + int number_of_scales; + //! \brief Size of the block of scales handled by the current process. + int xiblock; + //! \brief Index of the first scale handled by the current process. + int firstxi; + //! \brief Index of the last scale handled by the current process. + int lastxi; + //! \brief Argument of harmonic functions. + dcomplex arg; + //! \brief S0 = FSAS / (4 PI K^3). + dcomplex s0; + //! \brief Total forward scattering amplitude of the spheres. + dcomplex tfsas; + //! \brief Pointer to a sphere particle descriptor. + ParticleDescriptor *c1; + //! \brief Imaginary part of `arg`. + double *argi; + //! \brief `arg` squared. + double *args; + //! \brief Scattering angle. + double scan; + //! \brief Control parameter on incidence direction referred to meridional plane. + double cfmp; + //! \brief Control parameter on scattering direction referred to meridional plane. + double sfmp; + //! \brief Control parameter on incidence direction referred to scattering plane. + double cfsp; + //! \brief Control parameter on scattering direction referred to scattering plane. + double sfsp; + //! \brief Geometry asymmetry parameter for spheres. + double *gaps; + //! \brief Variation of unitary wave vector. + double *duk; + //! \brief Incidence direction unitary vector. + double *u; + //! \brief Scattering direction unitary vector. + double *us; + //! \brief Normal direction unitary vector. + double *un; + //! \brief Scattering normal direction unitary vector. + double *uns; + //! \brief Polarization direction unitary vector. + double *up; + //! \brief Scattered polarization direction unitary vector. + double *ups; + //! \brief Polarization direction unitary vector referred to meridional plane. + double *upmp; + //! \brief Scattered polarization direction unitary vector referred to meridional plane. + double *upsmp; + //! \brief Normal direction unitary vector referred to meridional plane. + double *unmp; + //! \brief Scattering normal direction unitary vector referred to meridional plane. + double *unsmp; + //! \brief Mueller matrix components. + double **cmul; + //! \brief Mueller matrix components referred to meridional plane. + double **cmullr; + //! \brief Polarization-dependent extinction contribution to torque for each sphere. + dcomplex **tqspe; + //! \brief Polarization-dependent scattering contribution to torque for each sphere. + dcomplex **tqsps; + //! \brief Extinction contribution to torque for each sphere. + double **tqse; + //! \brief Scattering contribution to torque for each sphere. + double **tqss; + //! \brief Scattering coefficients tensor. + double ****zpv; + + /*! \brief `SphereIterationData` default instance constructor. + * + * \param gconf: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` object. + * \param sconf: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` object. + * \param mpidata: `mixMPI *` Pointer to a `mixMPI` object. + * \param device_count: `const int` Number of offload devices available on the system. + */ + SphereIterationData(GeometryConfiguration *gconf, ScattererConfiguration *sconf, const mixMPI *mpidata, const int device_count); + + /*! \brief `SphereIterationData` copy constructor. + * + * \param rhs: `const SphereIterationData &` Reference to the object to be copied. + */ + SphereIterationData(const SphereIterationData& rhs); + +#ifdef MPI_VERSION + /*! \brief `SphereIterationData` MPI constructor. + * + * \param mpidata: `const mixMPI *` Pointer to a `mixMPI` instance. + * \param device_count: `const int` Number of offload devices available on the system. + */ + SphereIterationData(const mixMPI *mpidata, const int device_count); + + /*! \brief Broadcast over MPI the `SphereIterationData` instance from MPI process 0 to all others. + * + * When using MPI, the initial InclusionIterationData instance created by + * MPI process 0 needs to be replicated on all other processes. This + * function sends it using MPI broadcast calls. The MPI broadcast calls in + * this function must match those in the constructor using the mixMPI pointer. + * + * \param mpidata: `mixMPI *` Pointer to `mixMPI` instance. + */ + int mpibcast(const mixMPI *mpidata); +#endif // MPI_VERSION + + /*! \brief `SphereIterationData` instance destroyer. + */ + ~SphereIterationData(); +}; +// >>> END OF SphereIterationData CLASS DEFINITION <<< + +#endif // INCLUDE_ITERATION_DATA_H_ diff --git a/src/include/algebraic.h b/src/include/algebraic.h index 508cf0a31d258afb1c44287a1cf91d4d514a4491..c59dbae2c43a452313970d1e3cca215b407cc55a 100644 --- a/src/include/algebraic.h +++ b/src/include/algebraic.h @@ -36,8 +36,12 @@ using namespace std; * \param mat: `complex double **` The matrix to be inverted (must be a square matrix). * \param size: `np_int` The size of the matrix (i.e. the number of its rows or columns). * \param ier: `int &` Reference to an integer variable for returning a result flag. - * \param max_size: `np_int` The maximum expected size (required by some call-backs, - * optional, defaults to 0). + * \param maxrefiters: `int &` Reference to the maximum number of refinement iterations. + * \param accuracygoal: `double &` Reference to the requested accuracy level. + * \param refinemode: `int` Flag for refinement mode selection. + * \param output_path: `const string &` Path where the output needs to be placed. + * \param jxi488: `int` Index of the current wavelength calculation. + * \param max_size: `np_int` The maximum expected size (required by some call-backs, optional, defaults to 0). * \param target_device: `int` ID of target GPU, if available (defaults to 0). */ void invert_matrix(dcomplex **mat, np_int size, int &ier, int &maxrefiters, double &accuracygoal, int refinemode, const string& output_path, int jxi488, np_int max_size=0, int target_device=0); diff --git a/src/include/clu_subs.h b/src/include/clu_subs.h index 32994085c4dfc5e3a4cf2ccaf0cb1dffab3b7d2e..9c5feffe260086c5b8a42fa7608a5bb82585f35a 100644 --- a/src/include/clu_subs.h +++ b/src/include/clu_subs.h @@ -127,10 +127,11 @@ void crsm1(double vk, double exri, ParticleDescriptor *c1); * \param l2: `int` * \param m2: `int` * \param c1: `ParticleDescriptor *` + * \param rac3j: `dcomplex *` */ dcomplex ghit_d( int ihi, int ipamo, int nbl, int l1, int m1, int l2, int m2, - ParticleDescriptor *c1 + ParticleDescriptor *c1, double *rac3j ); /*! \brief Compute the transfer vector from N2 to N1. diff --git a/src/include/cublas_calls.h b/src/include/cublas_calls.h index e71b7558cd2b8720f6950187e6e5691e8c60cc76..3d379fdef70ae6bbef2e27d28c1c4496296e8552 100644 --- a/src/include/cublas_calls.h +++ b/src/include/cublas_calls.h @@ -42,7 +42,8 @@ void cublas_zinvert(dcomplex **mat, np_int n, int device_id); * \param mat: Matrix of complex. The matrix to be inverted. * \param n: `np_int` The number of rows and columns of the [n x n] matrix. * \param maxrefiters: `int` Maximum number of refinement iterations to apply. - * \param accuracygoal: `double` Accuracy to achieve in iterative refinement, defined as the module of the maximum difference between the identity matrix and the matrix product of the (approximate) inverse times the original matrix. On return, it contains the actually achieved accuracy + * \param accuracygoal: `double &` Accuracy to achieve in iterative refinement, defined as the module of the maximum difference between the identity matrix and the matrix product of the (approximate) inverse times the original matrix. On return, it contains the actually achieved accuracy. + * \param refinemode: `int` Flag to choose the refinement mode. * \param device_id: `int` ID of the device for matrix inversion offloading. */ void cublas_zinvert_and_refine(dcomplex **mat, np_int n, int &maxrefiters, double &accuracygoal, int refinemode, int device_id); diff --git a/src/include/file_io.h b/src/include/file_io.h index df475bf7a0c7a2f1dac5f07cfb9d60c71ed363ba..250acd331289d8ae3b086fe1dd82725752696154 100644 --- a/src/include/file_io.h +++ b/src/include/file_io.h @@ -228,7 +228,6 @@ public: * \param rhs: `const VirtualAsciiFile&` The refence to the VirtualAsciiFile to be inserted. * \param start: `int32_t` The first line to be inserted (optional, default is 0). * \param end: `int32_t` The last line to be inserted (optional, default is 0 to read all). - * \param line: `const string&` Reference to a string representing the line. * \return result: `int` A result code (0 if successful). */ int insert(int32_t position, VirtualAsciiFile& rhs, int32_t start = 0, int32_t end = 0); @@ -275,18 +274,37 @@ public: //! \brief Read only view of `_data_size`. const size_t & data_size = _data_size; - /*! \brief VirtualBinaryLine instance constructor. + /*! \brief VirtualBinaryLine instance constructor for `int` data. * - * \param mydata: `int, double, long, float, complex, or dcomplex`piece of data to put in the line. + * \param mydata: `int` The piece of data to put in the line. */ VirtualBinaryLine(int mydata); + + /*! \brief VirtualBinaryLine instance constructor for `long` data. + * + * \param mydata: `long` The piece of data to put in the line. + */ VirtualBinaryLine(long mydata); + + /*! \brief VirtualBinaryLine instance constructor for single-precision floating point data. + * + * \param mydata: `float` The piece of data to put in the line. + */ VirtualBinaryLine(float mydata); + + /*! \brief VirtualBinaryLine instance constructor for double-precision floating point data. + * + * \param mydata: `double` The piece of data to put in the line. + */ VirtualBinaryLine(double mydata); - // VirtualBinaryLine(complex mydata); + + /*! \brief VirtualBinaryLine instance constructor for `dcomplex` data. + * + * \param mydata: `dcomplex` The piece of data to put in the line. + */ VirtualBinaryLine(dcomplex mydata); - /*! \brief VirtualBinaryLine copy constructor. + /*! \brief VirtualBinaryLine copy constructor. * * \param rhs: `const VirtualBinaryLine&` Reference to a VirtualBinaryLine instance. */ @@ -367,23 +385,6 @@ public: */ int append_to_disk(const std::string& file_name); - // /*! \brief Insert another VirtualBinaryFile at a given position. - // * - // * This function inserts a target VirtualBinaryFile in the current one at the given - // * position. Optionally, a range of lines to be inserted can be specified, otherwise - // * the full content of the target file is inserted. This function DOES NOT increase - // * the size of the inner storage and it can only be used if the inner storage has - // * already been adjusted to contain the insertion target. - // * - // * \param position: `int32_t` The position at which the other file is inserted in this one. - // * \param rhs: `const VirtualBinaryFile&` The refence to the VirtualBinaryFile to be inserted. - // * \param start: `int32_t` The first line to be inserted (optional, default is 0). - // * \param end: `int32_t` The last line to be inserted (optional, default is 0 to read all). - // * \param line: `const string&` Reference to a string representing the line. - // * \return result: `int` A result code (0 if successful). - // */ - // int insert(int32_t position, VirtualBinaryFile& rhs, int32_t start = 0, int32_t end = 0); - /*! \brief Get the number of lines in the current instance. * * \return size: `int32_t` The number of lines in the VirtualBinaryFile instance. diff --git a/src/include/inclu_subs.h b/src/include/inclu_subs.h index d8696d96103ffaccd76cd1ab5efdd36ee7856f4a..64e5a1f3da5d11fc060f709b60ac50d4d2055554 100644 --- a/src/include/inclu_subs.h +++ b/src/include/inclu_subs.h @@ -56,7 +56,6 @@ void incms(dcomplex **am, double enti, ParticleDescriptor *c1); /*! \brief C++ porting of INDME. * - * \param li: `int` Maximum internal field expansion order. * \param i: `int` 1-based sphere configuration index. * \param npnt: `int` TBD. * \param npntts: `int` TBD. diff --git a/src/include/lapack_calls.h b/src/include/lapack_calls.h index fa24aac5d44d651a0f3283619a6e613e78f51d58..45a18733b3432697dd46bc3f763df74a0129a3a1 100644 --- a/src/include/lapack_calls.h +++ b/src/include/lapack_calls.h @@ -43,7 +43,8 @@ void zinvert(dcomplex **mat, np_int n, int &jer); * \param n: `np_int` The number of rows and columns of the [n x n] matrix. * \param jer: `int &` Reference to an integer return flag. * \param maxrefiters: `int` Maximum number of refinement iterations. - * \param accuracygoal: `double` Accuracy to achieve in iterative refinement, defined as the module of the maximum difference between the identity matrix and the matrix product of the (approximate) inverse times the original matrix. On return, it contains the actually achieved accuracy + * \param accuracygoal: `double &` Accuracy to achieve in iterative refinement, defined as the module of the maximum difference between the identity matrix and the matrix product of the (approximate) inverse times the original matrix. On return, it contains the actually achieved accuracy. + * \param refinemode: `int` Flag to control the refinement mode. */ void zinvert_and_refine(dcomplex **mat, np_int n, int &jer, int &maxrefiters, double &accuracygoal, int refinemode); diff --git a/src/include/logging.h b/src/include/logging.h index e58522a1ceddb3137228e02ae7385e57b45e98d0..f5fc061535419a63e2498744b376177e2cbbcada 100644 --- a/src/include/logging.h +++ b/src/include/logging.h @@ -65,13 +65,13 @@ class Logger { * \param threshold: `int` Threshold of the messages to be included in log. Can * be `LOG_DEBG` (log everything), `LOG_INFO` (give detailed information), * `LOG_WARN` (log odd looking effects), or `LOG_ERRO` (print error messages, - * `always active). The default behaviour is `LOG_WARN`. + * always active). The default behaviour is `LOG_WARN`. * \param logging_output: `FILE *` Pointer to an open output file for common messages * (optional, default is `stdout`). * \param error_output: `FILE *` Pointer to an open output file for error messages * (optional, default is `stderr`). */ - Logger(int threshold, FILE *logging_output=stdout, FILE *error_output=stderr); + Logger(int threshold, FILE *logging_output = stdout, FILE *error_output = stderr); /*! \brief Logger instance destroyer. */ diff --git a/src/include/magma_calls.h b/src/include/magma_calls.h index 1e1ccff65a5db4d5125b7387d8ae230e32438015..679b07f37c70b0cc88036f0af4e4cca9163ada78 100644 --- a/src/include/magma_calls.h +++ b/src/include/magma_calls.h @@ -56,22 +56,30 @@ void magma_zinvert1(dcomplex * &inva, np_int n, int &jer, int device_id); * \param n: `np_int` The number of rows and columns of the [n x n] matrix. * \param jer: `int &` Reference to an integer return flag. * \param maxrefiters: `int` Maximum number of refinement iterations to apply. - * \param accuracygoal: `double` Accuracy to achieve in iterative refinement, defined as the module of the maximum difference between the identity matrix and the matrix product of the (approximate) inverse times the original matrix. On return, it contains the actually achieved accuracy + * \param accuracygoal: `double &` Accuracy to achieve in iterative refinement, defined as the module of the maximum difference between the identity matrix and the matrix product of the (approximate) inverse times the original matrix. On return, it contains the actually achieved accuracy. + * \param refinemode: `int` Flag to control the refinement mode. * \param device_id: `int` ID of the device for matrix inversion offloading. + * \param output_path: `const string &` Path where the output needs to be placed. + * \param jxi488: `int` Index of the current wavelength calculation. */ void magma_zinvert_and_refine(dcomplex **mat, np_int n, int &jer, int &maxrefiters, double &accuracygoal, int refinemode, int device_id, const string& output_path, int jxi488); -/*! \brief apply iterative refinement of the solution of a matrix inversion +/*! \brief Apply iterative refinement of the solution of a matrix inversion. * - * iteratively compute and apply a correction to the inverse inva of the complex matrix aorig, for a maximum number of maxiters times, or until achieving a maximum residual better than accuracygoal + * Iteratively compute and apply a correction to the inverse `inva` of the complex + * matrix `aorig`, for a maximum number of `maxiters` times, or until achieving a + * maximum residual better than `accuracygoal`. * * \param aorig: pointer to the first element of the matrix of complex to be inverted. * \param inva: pointer to the first element of inverse. * \param n: `np_int` The number of rows and columns of the [n x n] matrices. * \param jer: `int &` Reference to an integer return flag. * \param maxrefiters: `int` Maximum number of refinement iterations to apply. - * \param accuracygoal: `double` Accuracy to achieve in iterative refinement, defined as the module of the maximum difference between the identity matrix and the matrix product of the (approximate) inverse times the original matrix. On return, it contains the actually achieved accuracy + * \param accuracygoal: `double` Accuracy to achieve in iterative refinement, defined as the module of the maximum difference between the identity matrix and the matrix product of the (approximate) inverse times the original matrix. On return, it contains the actually achieved accuracy. + * \param refinemode: `int` Flag for refinement mode selection. * \param device_id: `int` ID of the device for matrix inversion offloading. + * \param output_path: `const string &` Path where the output needs to be placed. + * \param jxi488: `int` Index of the current wavelength calculation. */ void magma_refine(dcomplex *aorig, dcomplex *inva, np_int n, int &jer, int &maxrefiters, double &accuracygoal, int refinemode, int device_id, const string& output_path, int jxi488); diff --git a/src/include/outputs.h b/src/include/outputs.h new file mode 100644 index 0000000000000000000000000000000000000000..abea6a6f891c1e318c7c7c244f196cc469a38b48 --- /dev/null +++ b/src/include/outputs.h @@ -0,0 +1,1243 @@ +/* Copyright (C) 2024 INAF - Osservatorio Astronomico di Cagliari + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + A copy of the GNU General Public License is distributed along with + this program in the COPYING file. If not, see: <https://www.gnu.org/licenses/>. + */ + +/*! \file outputs.h + * + * \brief Definition of the output format system. + */ +#ifndef INCLUDE_OUTPUTS_H_ +#define INCLUDE_OUTPUTS_H_ + +// >>> OUTPUT FOR CLUSTER <<< +/*! \brief Class to collect output information for scattering from clusters. + * + * The results of the calculation can be saved in different formats. + * It is therefore convenient to have a proper memory structure that + * allows for storing the results and flushing them in any of the + * permitted formats with just one operation. The purpose of the + * `ClusterOutputInfo` class is to provide a wrapper for the output + * of the cluster scattering solver. + */ +class ClusterOutputInfo { +protected: + //! \brief Number of incident azimuth calculations. + int _num_theta; + //! \brief Number of scattered azimuth calculations. + int _num_thetas; + //! \brief Number of incident elevation calculations. + int _num_phi; + //! \brief Number of scattered elevation calculations. + int _num_phis; + //! \brief ID of the first computed wavelength + int _first_xi; + + /*! \brief Write the output to a HDF5 file. + * + * \param file_name: `const string &` Path to the output to be written. + * \return result: `int` Exit code (0 if successful). + */ + int write_hdf5(const std::string &file_name); + + /*! \brief Write the output to a legacy text file. + * + * This function takes care of writing the output using the legacy + * formatted ASCII structure. If the output file does not exist, it + * is created. If it exists, the new content overwritten. + * + * \param output: `const string &` Path to the output to be written. + * \return result: `int` Exit code (0 if successful). + */ + int write_legacy(const std::string &output); + +public: + //! \brief Read-only view on the ID of the first scale + const int &first_xi = _first_xi; + //! \brief Number of spheres in the aggregate. + int nsph; + //! \brief Maximum internal field expansion order. + int li; + //! \brief Maximum external field expansion order. + int le; + //! \brief Maximum field expansion order. + int lm; + //! \brief Maximum coefficient matrix dimension. + np_int mxndm; + //! \brief Incident polarization flag. + int inpol; + //! \brief Number of points for transition layer integration. + int npnt; + //! \brief Number of points for non-transition layer integration. + int npntts; + //! \brief Flag for intensity. + int iavm; + //! \brief Flag for reference to meridional plane. + int isam; + //! \brief Flag for dielectric function definition. + int idfc; + //! \brief Vector of spherical components X Cartesian coordinates. + double *vec_x_coords; + //! \brief Vector of spherical components Y Cartesian coordinates. + double *vec_y_coords; + //! \brief Vector of spherical components Z Cartesian coordinates. + double *vec_z_coords; + //! \brief First incident radiation azimuth angle. + double th; + //! \brief Incident radiation azimuth angle step. + double thstp; + //! \brief Last incident radiation azimuth angle. + double thlst; + //! \brief First scattered radiation azimuth angle. + double ths; + //! \brief Scattered radiation azimuth angle step. + double thsstp; + //! \brief Last scattered radiation azimuth angle. + double thslst; + //! \brief First incident radiation elevation angle. + double ph; + //! \brief Incident radiation elevation angle step. + double phstp; + //! \brief Last incident radiation elevation angle. + double phlst; + //! \brief First scattered radiation elevation angle. + double phs; + //! \brief Scattered radiation elevation angle step. + double phsstp; + //! \brief Last scattered radiation elevation angle. + double phslst; + //! \brief Number of directions to be explicitly solved. + int ndirs; + //! \brief Refractive index of external medium. + double exri; + //! \brief Number of scales (wavelengths) + int nxi; + //! \brief Number of scales handled by the current process. + int xi_block_size; + //! \brief Index of the wavelength for T-matrix output. + int jwtm; + //! \brief Vector of scale (wavelength) indices. + int *vec_jxi; + //! \brief Vector of error severities (0 - success, 1 - HJV, 2 - DME). + short *vec_ier; + //! \brief Vector of vacuum wave numbers. + double *vec_vk; + //! \brief Vector of computed scales. + double *vec_xi; + //! \brief Number of sphere configurations. + int configurations; + //! \brief Vector of sphere sizes (all configurations for every scale). + double *vec_sphere_sizes; + //! \brief Vector of sphere refractive indices (all configurations for every scale). + dcomplex *vec_sphere_ref_indices; + //! \brief Vector of sphere scattering cross-sections (all configurations for every scale). + double *vec_sphere_scs; + //! \brief Vector of sphere absorption cross-sections (all configurations for every scale). + double *vec_sphere_abs; + //! \brief Vector of sphere extinction cross-sections (all configurations for every scale). + double *vec_sphere_exs; + //! \brief Vector of sphere albedos (all configurations for every scale). + double *vec_sphere_albs; + //! \brief Vector of sphere scattering cross-section to geometric section ratios (all configurations for every scale). + double *vec_sphere_sqscs; + //! \brief Vector of sphere absorption cross-sections to geometric section ratios (all configurations for every scale). + double *vec_sphere_sqabs; + //! \brief Vector of sphere extinction cross-sections to geometric section ratios (all configurations for every scale). + double *vec_sphere_sqexs; + //! \brief Vector of sphere forward scattering amplitudes (all configurations for every scale). + dcomplex *vec_fsas; + //! \brief Vector of QSCHU = 4 pi IMAG(FSAS) / TOTAL_GEOM_SECTION (all configurations for every scale). + double *vec_qschus; + //! \brief Vector of PSCHU = 4 pi REAL(FSAS) / TOTAL_GEOM_SECTION (all configurations for every scale). + double *vec_pschus; + //! \brief Vector of S0MAG = ABS(FSAS) / (4 pi k^3) (all configurations for every scale). + double *vec_s0mags; + //! \brief Vector of sphere asymmetry parameters (all configurations for every scale). + double *vec_cosavs; + //! \brief Vector of sphere radiation pressure forces (all configurations for every scale). + double *vec_raprs; + //! \brief Vector of extinction contributions to radiation torques along k for parallel linear polarization (all configurations for every scale). + double *vec_tqek1; + //! \brief Vector of scattering contributions to radiation torques along k for parallel linear polarization (all configurations for every scale). + double *vec_tqsk1; + //! \brief Vector of extinction contributions to radiation torques along k for perpendicular linear polarization (all configurations for every scale). + double *vec_tqek2; + //! \brief Vector of scattering contributions to radiation torques along k for perpendicular linear polarization (all configurations for every scale). + double *vec_tqsk2; + //! \brief Vector of total forward scattering amplitudes (one for each scale). + dcomplex *vec_fsat; + //! \brief Vector of total QSCHU (one for each scale). + double *vec_qschut; + //! \brief Vector of total PSCHU (one for each scale). + double *vec_pschut; + //! \brief Vector of total S0MAG (one for each scale). + double *vec_s0magt; + //! \brief Total geometric section. + double tgs; + //! \brief Vector of cluster scattering cross-sections (parallel polarization). + double *vec_scc1; + //! \brief Vector of cluster scattering cross-sections (perpendicular polarization). + double *vec_scc2; + //! \brief Vector of cluster absorption cross-sections (parallel polarization). + double *vec_abc1; + //! \brief Vector of cluster absorption cross-sections (perpendicular polarization). + double *vec_abc2; + //! \brief Vector of cluster extinction cross-sections (parallel polarization). + double *vec_exc1; + //! \brief Vector of cluster extinction cross-sections (perpendicular polarization). + double *vec_exc2; + //! \brief Vector of cluster albedos (parallel polarization). + double *vec_albedc1; + //! \brief Vector of cluster albedos (perpendicular polarization). + double *vec_albedc2; + //! \brief Vector of cluster scattering to geometric cross-section ratios (parallel polarization). + double *vec_qscamc1; + //! \brief Vector of cluster scattering to geometric cross-section ratios (perpendicular polarization). + double *vec_qscamc2; + //! \brief Vector of cluster absorption to geometric cross-section ratios (parallel polarization). + double *vec_qabsmc1; + //! \brief Vector of cluster absorption to geometric cross-section ratios (perpendicular polarization). + double *vec_qabsmc2; + //! \brief Vector of cluster extinction to geometric cross-section ratios (parallel polarization). + double *vec_qextmc1; + //! \brief Vector of cluster extinction to geometric cross-section ratios (perpendicular polarization). + double *vec_qextmc2; + //! \brief Vector of cluster-to-sum-of-spheres scattering cross-section ratios (parallel polarization). + double *vec_sccrt1; + //! \brief Vector of cluster-to-sum-of-spheres scattering cross-section ratios (parallel polarization). + double *vec_sccrt2; + //! \brief Vector of cluster-to-sum-of-spheres absorption cross-section ratios (parallel polarization). + double *vec_abcrt1; + //! \brief Vector of cluster-to-sum-of-spheres absorption cross-section ratios (perpendicular polarization). + double *vec_abcrt2; + //! \brief Vector of cluster-to-sum-of-spheres extinction cross-section ratios (parallel polarization). + double *vec_excrt1; + //! \brief Vector of cluster-to-sum-of-spheres extinction cross-section ratios (perpendicular polarization). + double *vec_excrt2; + //! \brief Vector of forward scattering amplitudes for polarization parallel to incidence (one per scale). + dcomplex *vec_fsac11; + //! \brief Vector of forward scattering amplitudes for polarization perpendicular to incidence (one per scale). + dcomplex *vec_fsac21; + //! \brief Vector of forward scattering amplitudes for polarization parallel to incidence (one per scale). + dcomplex *vec_fsac22; + //! \brief Vector of forward scattering amplitudes for polarization perpendicular to incidence (one per scale). + dcomplex *vec_fsac12; + //! \brief Vector of cluster QSCHU (parallel polarization). + double *vec_qschuc1; + //! \brief Vector of cluster QSCHU (perpendicular polarization). + double *vec_qschuc2; + //! \brief Vector of cluster PSCHU (parallel polarization). + double *vec_pschuc1; + //! \brief Vector of cluster PSCHU (perpendicular polarization). + double *vec_pschuc2; + //! \brief Vector of cluster S0MAG (parallel polarization). + double *vec_s0magc1; + //! \brief Vector of cluster S0MAG (perpendicular polarization). + double *vec_s0magc2; + //! \brief Vector of cluster asymmetry parameters (parallel polarization). + double *vec_cosavc1; + //! \brief Vector of cluster asymmetry parameters (perpendicular polarization). + double *vec_cosavc2; + //! \brief Vector of cluster radiation pressure forces (parallel polarization). + double *vec_raprc1; + //! \brief Vector of cluster radiation pressure forces (perpendicular polarization). + double *vec_raprc2; + //! \brief Vector of optical forces along incidence direction [N] (parallel polarization). + double *vec_fkc1; + //! \brief Vector of optical forces along incidence direction [N] (perpendicular polarization). + double *vec_fkc2; + //! \brief Vector of incidence azimuth directions (one per incidence azimuth). + double *vec_dir_tidg; + //! \brief Vector of incidence elevation directions (one per incidence elevation). + double *vec_dir_pidg; + //! \brief Vector of scattering azimuth directions (one per scattering azimuth). + double *vec_dir_tsdg; + //! \brief Vector of scattering elevation directions (one per scattering elevation). + double *vec_dir_psdg; + //! \brief Vector of scattering angles (one per direction). + double *vec_dir_scand; + //! \brief Control parameter for incidence plane referred to meridional plane (one per direction). + double *vec_dir_cfmp; + //! \brief Control parameter for scattering plane referred to meridional plane (one per direction). + double *vec_dir_sfmp; + //! \brief Control parameter for incidence plane referred to scattering plane (one per direction). + double *vec_dir_cfsp; + //! \brief Control parameter for scattering plane referred to scattering plane (one per direction). + double *vec_dir_sfsp; + //! \brief Components of the unitary vector perpendicular to incidence plane (three per direction). + double *vec_dir_un; + //! \brief Components of the unitary vector perpendicular to scattering plane (three per direction). + double *vec_dir_uns; + //! \brief Vector of sphere differential scattering amplitude with polarization parallel to parallel incidence field. + dcomplex *vec_dir_sas11; + //! \brief Vector of sphere differential scattering amplitude with polarization perpendicular to the parallel incidence field. + dcomplex *vec_dir_sas21; + //! \brief Vector of sphere differential scattering amplitude with polarization perpendicular to perpendicular incidence field. + dcomplex *vec_dir_sas12; + //! \brief Vector of sphere differential scattering amplitude with polarization parallel the perpendicular incidence field. + dcomplex *vec_dir_sas22; + //! \brief Vector of sphere Mueller transormation matrices referred to meridional plane. + double *vec_dir_muls; + //! \brief Vector of sphere Mueller transormation matrices referred to scattering plane. + double *vec_dir_mulslr; + //! \brief Vector of sphere total differential scattering amplitude with polarization parallel to parallel incidence field. + dcomplex *vec_dir_sat11; + //! \brief Vector of sphere total differential scattering amplitude with polarization perpendicular to the parallel incidence field. + dcomplex *vec_dir_sat21; + //! \brief Vector of sphere total differential scattering amplitude with polarization perpendicular to perpendicular incidence field. + dcomplex *vec_dir_sat12; + //! \brief Vector of sphere total differential scattering amplitude with polarization parallel the perpendicular incidence field. + dcomplex *vec_dir_sat22; + //! \brief Vector of cluster differential scattering cross-sections (parallel polarization). + double *vec_dir_scc1; + //! \brief Vector of cluster differential scattering cross-sections (perpendicular polarization). + double *vec_dir_scc2; + //! \brief Vector of cluster differential absorption cross-sections (parallel polarization). + double *vec_dir_abc1; + //! \brief Vector of cluster differential absorption cross-sections (perpendicular polarization). + double *vec_dir_abc2; + //! \brief Vector of cluster differential extinction cross-sections (parallel polarization). + double *vec_dir_exc1; + //! \brief Vector of cluster differential extinction cross-sections (perpendicular polarization). + double *vec_dir_exc2; + //! \brief Vector of cluster differential albedos (parallel polarization). + double *vec_dir_albedc1; + //! \brief Vector of cluster differential albedos (perpendicular polarization). + double *vec_dir_albedc2; + //! \brief Vector of differential scattering to geometric cross-section ratios (parallel polarization). + double *vec_dir_qscc1; + //! \brief Vector of differential scattering to geometric cross-section ratios (perpendicular polarization). + double *vec_dir_qscc2; + //! \brief Vector of differential absorption to geometric cross-section ratios (parallel polarization). + double *vec_dir_qabc1; + //! \brief Vector of differential absorption to geometric cross-section ratios (perpendicular polarization). + double *vec_dir_qabc2; + //! \brief Vector of differential extinction to geometric cross-section ratios (parallel polarization). + double *vec_dir_qexc1; + //! \brief Vector of differential extinction to geometric cross-section ratios (perpendicular polarization). + double *vec_dir_qexc2; + //! \brief Vector of differential cluster-to-total scattering cross-section ratios (parallel polarization). + double *vec_dir_sccrt1; + //! \brief Vector of differential cluster-to-total scattering cross-section ratios (perpendicular polarization). + double *vec_dir_sccrt2; + //! \brief Vector of differential cluster-to-total absorption cross-section ratios (parallel polarization). + double *vec_dir_abcrt1; + //! \brief Vector of differential cluster-to-total absorption cross-section ratios (perpendicular polarization). + double *vec_dir_abcrt2; + //! \brief Vector of differential cluster-to-total extinction cross-section ratios (parallel polarization). + double *vec_dir_excrt1; + //! \brief Vector of differential cluster-to-total extinction cross-section ratios (perpendicular polarization). + double *vec_dir_excrt2; + //! \brief Vector of differential cluster forward scattering amplitude with polarization parallel to parallel incidence field (one per direction and scale). + dcomplex *vec_dir_fsac11; + //! \brief Vector of differential cluster forward scattering amplitude with polarization perpendicular to the parallel incidence field (one per direction and scale). + dcomplex *vec_dir_fsac21; + //! \brief Vector of differential cluster forward scattering amplitude with polarization perpendicular to perpendicular incidence field (one per direction and scale). + dcomplex *vec_dir_fsac12; + //! \brief Vector of differential cluster forward scattering amplitude with polarization parallel the perpendicular incidence field (one per direction and scale). + dcomplex *vec_dir_fsac22; + //! \brief Vector of differential cluster scattering amplitude with polarization parallel to parallel incidence field (one per direction and scale). + dcomplex *vec_dir_sac11; + //! \brief Vector of differential cluster scattering amplitude with polarization perpendicular to the parallel incidence field (one per direction and scale). + dcomplex *vec_dir_sac21; + //! \brief Vector of differential cluster scattering amplitude with polarization perpendicular to perpendicular incidence field (one per direction and scale). + dcomplex *vec_dir_sac12; + //! \brief Vector of differential cluster scattering amplitude with polarization parallel the perpendicular incidence field (one per direction and scale). + dcomplex *vec_dir_sac22; + //! \brief Vector of differential cluster QSCHU (parallel polarization). + double *vec_dir_qschuc1; + //! \brief Vector of differential cluster QSCHU (perpendicular polarization). + double *vec_dir_qschuc2; + //! \brief Vector of differential cluster PSCHU (parallel polarization). + double *vec_dir_pschuc1; + //! \brief Vector of differential cluster PSCHU (perpendicular polarization). + double *vec_dir_pschuc2; + //! \brief Vector of cluster differential S0MAG (parallel polarization). + double *vec_dir_s0magc1; + //! \brief Vector of cluster differential S0MAG (perpendicular polarization). + double *vec_dir_s0magc2; + //! \brief Vector of differential cluster asymmetry parameters (parallel polarization). + double *vec_dir_cosavc1; + //! \brief Vector of differential cluster asymmetry parameters (perpendicular polarization). + double *vec_dir_cosavc2; + //! \brief Vector of differential cluster radiation pressure forces (1). + double *vec_dir_raprc1; + //! \brief Vector of differential cluster radiation pressure forces (1). + double *vec_dir_raprc2; + //! \brief Vector of differential radiation pressure force components along the polarization direction (parallel polarization). + double *vec_dir_flc1; + //! \brief Vector of differential radiation pressure force components along the polarization direction (perpendicular polarization). + double *vec_dir_flc2; + //! \brief Vector of differential radiation pressure force components perpendicular to the polarization direction (parallel polarization). + double *vec_dir_frc1; + //! \brief Vector of differential radiation pressure force components perpendicular to the polarization direction (perpendicular polarization). + double *vec_dir_frc2; + //! \brief Vector of differential radiation pressure force components along the incidence direction (parallel polarization). + double *vec_dir_fkc1; + //! \brief Vector of differential radiation pressure force components along the incidence direction (perpendicular polarization). + double *vec_dir_fkc2; + //! \brief Vector of differential radiation pressure force components along the X axis (parallel polarization). + double *vec_dir_fxc1; + //! \brief Vector of differential radiation pressure force components along the X axis (perpendicular polarization). + double *vec_dir_fxc2; + //! \brief Vector of differential radiation pressure force components along the Y axis (parallel polarization). + double *vec_dir_fyc1; + //! \brief Vector of differential radiation pressure force components along the Y axis (perpendicular polarization). + double *vec_dir_fyc2; + //! \brief Vector of differential radiation pressure force components along the Z axis (parallel polarization). + double *vec_dir_fzc1; + //! \brief Vector of differential radiation pressure force components along the Z axis (perpendicular polarization). + double *vec_dir_fzc2; + //! \brief Vector of differential extinction contribution to radiation torque components along the polarization direction (parallel polarization). + double *vec_dir_tqelc1; + //! \brief Vector of differential extinction contribution to radiation torque components along the polarization direction (perpendicular polarization). + double *vec_dir_tqelc2; + //! \brief Vector of differential extinction contribution to radiation torque components perpendicular to the polarization direction (parallel polarization). + double *vec_dir_tqerc1; + //! \brief Vector of differential extinction contribution to radiation torque components perpendicular to the polarization direction (perpendicular polarization). + double *vec_dir_tqerc2; + //! \brief Vector of differential extinction contribution to radiation torque components along the incidence direction (parallel polarization). + double *vec_dir_tqekc1; + //! \brief Vector of differential extinction contribution to radiation torque components along the incidence direction (perpendicular polarization). + double *vec_dir_tqekc2; + //! \brief Vector of differential extinction contribution to radiation torque components along the X axis (parallel polarization). + double *vec_dir_tqexc1; + //! \brief Vector of differential extinction contribution to radiation torque components along the X axis (perpendicular polarization). + double *vec_dir_tqexc2; + //! \brief Vector of differential extinction contribution to radiation torque components along the Y axis (parallel polarization). + double *vec_dir_tqeyc1; + //! \brief Vector of differential extinction contribution to radiation torque components along the Y axis (perpendicular polarization). + double *vec_dir_tqeyc2; + //! \brief Vector of differential extinction contribution to radiation torque components along the Z axis (parallel polarization). + double *vec_dir_tqezc1; + //! \brief Vector of differential extinction contribution to radiation torque components along the Z axis (perpendicular polarization). + double *vec_dir_tqezc2; + //! \brief Vector of differential scattering contribution to radiation torque components along the polarization direction (parallel polarization). + double *vec_dir_tqslc1; + //! \brief Vector of differential scattering contribution to radiation torque components along the polarization direction (perpendicular polarization). + double *vec_dir_tqslc2; + //! \brief Vector of differential scattering contribution to radiation torque components perpendicular to the polarization direction (parallel polarization). + double *vec_dir_tqsrc1; + //! \brief Vector of differential scattering contribution to radiation torque components perpendicular to the polarization direction (perpendicular polarization). + double *vec_dir_tqsrc2; + //! \brief Vector of differential scattering contribution to radiation torque components along the incidence direction (parallel polarization). + double *vec_dir_tqskc1; + //! \brief Vector of differential scattering contribution to radiation torque components along the incidence direction (perpendicular polarization). + double *vec_dir_tqskc2; + //! \brief Vector of differential scattering contribution to radiation torque components along X axis (parallel polarization). + double *vec_dir_tqsxc1; + //! \brief Vector of differential scattering contribution to radiation torque components along X axis (perpendicular polarization). + double *vec_dir_tqsxc2; + //! \brief Vector of differential scattering contribution to radiation torque components along Y axis (parallel polarization). + double *vec_dir_tqsyc1; + //! \brief Vector of differential scattering contribution to radiation torque components along Y axis (perpendicular polarization). + double *vec_dir_tqsyc2; + //! \brief Vector of differential scattering contribution to radiation torque components along Z axis (parallel polarization). + double *vec_dir_tqszc1; + //! \brief Vector of differential scattering contribution to radiation torque components along Z axis (perpendicular polarization). + double *vec_dir_tqszc2; + //! \brief Vector of cluster Mueller transormation matrices referred to meridional plane (16 per direction per scale). + double *vec_dir_mulc; + //! \brief Vector of cluster Mueller transormation matrices referred to scattering plane (16 per direction per scale). + double *vec_dir_mulclr; + + /*! \brief `ClusterOutputInfo` default instance constructor. + * + * \param sc: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` instance. + * \param gc: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` instance. + * \param mpidata: `const mixMPI*` Pointer to a mixMPI instance. + * \param first_xi: `int` Index of the first scale in output (optional, default is 1). + * \param xi_length: `int` Number of scales tobe included in output (optional, default is 0, meaning all). + */ + ClusterOutputInfo( + ScattererConfiguration *sc, GeometryConfiguration *gc, + const mixMPI *mpidata, int first_xi = 1, int xi_length = 0 + ); + + /*! \brief `ClusterOutputInfo` constructor from HDF5 input. + * + * \param hdf5_name: `const string &` Path to the HDF5 file to be read. + */ + ClusterOutputInfo(const std::string &hdf5_name); + + /*! \brief `ClusterOutputInfo` instance destroyer. + */ + ~ClusterOutputInfo(); + + /*! \brief Estimate the size of the structure that would be built for given input. + * + * \param sc: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` instance. + * \param gc: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` instance. + * \param first_xi: `int` Index of the first scale in output (optional, default is 1). + * \param xi_length: `int` Number of scales tobe included in output (optional, default is all). + * \return size: `long` Estimated instance size in bytes. + */ + static long compute_size( + ScattererConfiguration *sc, GeometryConfiguration *gc, + int first_xi = 1, int xi_length = 0 + ); + + /*! \brief Get the size of a `ClusterOutputInfo` instance in bytes. + * + * \return size: `long` Estimated instance size in bytes. + */ + long compute_size(); + + /*! \brief Insert in the current output data the data of another block. + * + * \param rhs: `const ClusterOutputInfo &` Reference to the source data block. + * \return result: `int` Exit code (0 if successful). + */ + int insert(const ClusterOutputInfo &rhs); + + /*! \brief Write the output to a file. + * + * \param output: `const string &` Path to the output to be written. + * \param format: `const string &` Output format (one of LEGACY or HDF5). + * \return result: `int` Exit code (0 if successful). + */ + int write(const std::string &output, const std::string &format); + +#ifdef MPI_VERSION + /*! \brief Receive output data from worker processes. + * + * This function is invoked by the MPI rank-0 process to fetch the + * output data produced by higher rank processes. When calling this + * function, process 0 halts until a valid data chunk is transmitted + * by the queried process. + * + * \param mpidata: `const mixMPI*` Pointer to a `mixMPI` instance. + * \param pid: `int` Rank of the process that is transmitting data. + * \return result: `int` An exit code (0 for success). + */ + int mpireceive(const mixMPI* mpidata, int pid); + + /*! \brief Send output data to process 0. + * + * This function is invoked by non-zero ranked MPI processes when + * they are ready to send back the output data. When a process meets + * this function call, it halts until MPI process 0 asks for the + * data transmission. + * + * \param mpidata: `const mixMPI*` Pointer to a `mixMPI` instance. + * \param pid: `int` Rank of the process that is transmitting data. + * \return result: `int` An exit code (0 for success). + */ + int mpisend(const mixMPI *mpidata); +#endif // MPI_VERSION +}; +// >>> END OF OUTPUT FOR CLUSTER <<< + +// >>> OUTPUT FOR INCLUSION <<< +/*! \brief Class to collect output information for scattering from particle with inclusions. + * + * The results of the calculation can be saved in different formats. + * It is therefore convenient to have a proper memory structure that + * allows for storing the results and flushing them in any of the + * permitted formats with just one operation. The purpose of the + * `InclusionOutputInfo` class is to provide a wrapper for the output + * of the particle with inclusions scattering solver. + */ +class InclusionOutputInfo { +protected: + //! \brief Number of incident azimuth calculations. + int _num_theta; + //! \brief Number of scattered azimuth calculations. + int _num_thetas; + //! \brief Number of incident elevation calculations. + int _num_phi; + //! \brief Number of scattered elevation calculations. + int _num_phis; + //! \brief ID of the first computed wavelength + int _first_xi; + + /*! \brief Write the output to a HDF5 file. + * + * \param file_name: `const string &` Path to the output to be written. + * \return result: `int` Exit code (0 if successful). + */ + int write_hdf5(const std::string &file_name); + + /*! \brief Write the output to a legacy text file. + * + * This function takes care of writing the output using the legacy + * formatted ASCII structure. If the output file does not exist, it + * is created. If it exists, the new content is overwritten. + * + * \param output: `const string &` Path to the output to be written. + * \return result: `int` Exit code (0 if successful). + */ + int write_legacy(const std::string &output); + +public: + //! \brief Read-only view on the ID of the first scale + const int &first_xi = _first_xi; + //! \brief Number of spheres in the aggregate. + int nsph; + //! \brief Maximum internal field expansion order. + int li; + //! \brief Maximum external field expansion order. + int le; + //! \brief Maximum field expansion order. + int lm; + //! \brief Maximum coefficient matrix dimension. + np_int mxndm; + //! \brief Incident polarization flag. + int inpol; + //! \brief Number of points for transition layer integration. + int npnt; + //! \brief Number of points for non-transition layer integration. + int npntts; + //! \brief Flag for intensity. + int iavm; + //! \brief Flag for reference to meridional plane. + int isam; + //! \brief Flag for dielectric function definition. + int idfc; + //! \brief Vector of spherical components X Cartesian coordinates. + double *vec_x_coords; + //! \brief Vector of spherical components Y Cartesian coordinates. + double *vec_y_coords; + //! \brief Vector of spherical components Z Cartesian coordinates. + double *vec_z_coords; + //! \brief First incident radiation azimuth angle. + double th; + //! \brief Incident radiation azimuth angle step. + double thstp; + //! \brief Last incident radiation azimuth angle. + double thlst; + //! \brief First scattered radiation azimuth angle. + double ths; + //! \brief Scattered radiation azimuth angle step. + double thsstp; + //! \brief Last scattered radiation azimuth angle. + double thslst; + //! \brief First incident radiation elevation angle. + double ph; + //! \brief Incident radiation elevation angle step. + double phstp; + //! \brief Last incident radiation elevation angle. + double phlst; + //! \brief First scattered radiation elevation angle. + double phs; + //! \brief Scattered radiation elevation angle step. + double phsstp; + //! \brief Last scattered radiation elevation angle. + double phslst; + //! \brief Number of directions to be explicitly solved. + int ndirs; + //! \brief Refractive index of external medium. + double exri; + //! \brief Number of scales (wavelengths) + int nxi; + //! \brief Number of scales handled by the current process. + int xi_block_size; + //! \brief Index of the wavelength for T-matrix output. + int jwtm; + //! \brief Vector of scale (wavelength) indices. + int *vec_jxi; + //! \brief Vector of error severities (0 - success, 1 - INDME, 2 - OSPV). + short *vec_ier; + //! \brief Vector of vacuum wave numbers. + double *vec_vk; + //! \brief Vector of computed scales. + double *vec_xi; + //! \brief Number of sphere configurations. + int configurations; + //! \brief Vector of sphere sizes (all configurations for every scale). + double *vec_sphere_sizes; + //! \brief Vector of sphere refractive indices (all configurations for every scale). + dcomplex *vec_sphere_ref_indices; + //! \brief Vector of particle scattering cross-sections (parallel polarization). + double *vec_scs1; + //! \brief Vector of particle scattering cross-sections (perpendicular polarization). + double *vec_scs2; + //! \brief Vector of particle absorption cross-sections (parallel polarization). + double *vec_abs1; + //! \brief Vector of particle absorption cross-sections (perpendicular polarization). + double *vec_abs2; + //! \brief Vector of particle extinction cross-sections (parallel polarization). + double *vec_exs1; + //! \brief Vector of particle extinction cross-sections (perpendicular polarization). + double *vec_exs2; + //! \brief Vector of particle albedos (parallel polarization). + double *vec_albeds1; + //! \brief Vector of particle albedos (perpendicular polarization). + double *vec_albeds2; + //! \brief Vector of particle scattering-to-geometric cross-sections (parallel polarization). + double *vec_scsrt1; + //! \brief Vector of particle scattering-to-geometric cross-sections (perpendicular polarization). + double *vec_scsrt2; + //! \brief Vector of particle absorption-to-geometric cross-sections (parallel polarization). + double *vec_absrt1; + //! \brief Vector of particle absorption-to-geometric cross-sections (perpendicular polarization). + double *vec_absrt2; + //! \brief Vector of particle extinction-to-geometric cross-sections (parallel polarization). + double *vec_exsrt1; + //! \brief Vector of particle extinction-to-geometric cross-sections (perpendicular polarization). + double *vec_exsrt2; + //! \brief Vector of particle QSCHU (parallel polarization). + double *vec_qschu1; + //! \brief Vector of particle QSCHU (perpendicular polarization). + double *vec_qschu2; + //! \brief Vector of particle PSCHU (parallel polarization). + double *vec_pschu1; + //! \brief Vector of particle PSCHU (perpendicular polarization). + double *vec_pschu2; + //! \brief Vector of particle S0MAG (parallel polarization). + double *vec_s0mag1; + //! \brief Vector of particle S0MAG (perpendicular polarization). + double *vec_s0mag2; + //! \brief Vector of particle average asymmetry parameter (parallel polarization). + double *vec_cosav1; + //! \brief Vector of particle average asymmetry parameter (perpendicular polarization). + double *vec_cosav2; + //! \brief Vector of particle average radiation pressure force (N - parallel polarization). + double *vec_raprs1; + //! \brief Vector of particle average radiation pressure force (N - perpendicular polarization). + double *vec_raprs2; + //! \brief Vector of particle average radiation force along incidence direction (N - parallel polarization). + double *vec_fk1; + //! \brief Vector of particle average radiation force along incidence direction (N - perpendicular polarization). + double *vec_fk2; + //! \brief Vector of forward scattering amplitudes for polarization parallel to incidence (one per scale). + dcomplex *vec_fsas11; + //! \brief Vector of forward scattering amplitudes for polarization perpendicular to incidence (one per scale). + dcomplex *vec_fsas21; + //! \brief Vector of forward scattering amplitudes for polarization parallel to incidence (one per scale). + dcomplex *vec_fsas22; + //! \brief Vector of forward scattering amplitudes for polarization perpendicular to incidence (one per scale). + dcomplex *vec_fsas12; + //! \brief Vector of incidence azimuth directions (one per incidence azimuth). + double *vec_dir_tidg; + //! \brief Vector of incidence elevation directions (one per incidence elevation). + double *vec_dir_pidg; + //! \brief Vector of scattering azimuth directions (one per scattering azimuth). + double *vec_dir_tsdg; + //! \brief Vector of scattering elevation directions (one per scattering elevation). + double *vec_dir_psdg; + //! \brief Vector of scattering angles (one per direction). + double *vec_dir_scand; + //! \brief Control parameter for incidence plane referred to meridional plane (one per direction). + double *vec_dir_cfmp; + //! \brief Control parameter for scattering plane referred to meridional plane (one per direction). + double *vec_dir_sfmp; + //! \brief Control parameter for incidence plane referred to scattering plane (one per direction). + double *vec_dir_cfsp; + //! \brief Control parameter for scattering plane referred to scattering plane (one per direction). + double *vec_dir_sfsp; + //! \brief Components of the unitary vector perpendicular to incidence plane (three per direction). + double *vec_dir_un; + //! \brief Components of the unitary vector perpendicular to scattering plane (three per direction). + double *vec_dir_uns; + //! \brief Vector of particle differential scattering cross-sections (parallel polarization). + double *vec_dir_scs1; + //! \brief Vector of particle differential scattering cross-sections (perpendicular polarization). + double *vec_dir_scs2; + //! \brief Vector of particle differential absorption cross-sections (parallel polarization). + double *vec_dir_abs1; + //! \brief Vector of particle differential absorption cross-sections (perpendicular polarization). + double *vec_dir_abs2; + //! \brief Vector of particle differential extinction cross-sections (parallel polarization). + double *vec_dir_exs1; + //! \brief Vector of particle differential extinction cross-sections (perpendicular polarization). + double *vec_dir_exs2; + //! \brief Vector of particle differential albedos (parallel polarization). + double *vec_dir_albeds1; + //! \brief Vector of particle differential albedos (perpendicular polarization). + double *vec_dir_albeds2; + //! \brief Vector of particle differential scattering-to-geometric cross-sections (parallel polarization). + double *vec_dir_scsrt1; + //! \brief Vector of particle differential scattering-to-geometric cross-sections (perpendicular polarization). + double *vec_dir_scsrt2; + //! \brief Vector of particle differential absorption-to-geometric cross-sections (parallel polarization). + double *vec_dir_absrt1; + //! \brief Vector of particle differential absorption-to-geometric cross-sections (perpendicular polarization). + double *vec_dir_absrt2; + //! \brief Vector of particle differential extinction-to-geometric cross-sections (parallel polarization). + double *vec_dir_exsrt1; + //! \brief Vector of particle differential extinction-to-geometric cross-sections (perpendicular polarization). + double *vec_dir_exsrt2; + //! \brief Vector of particle differential forward scattering amplitude with polarization parallel to parallel incidence field. + dcomplex *vec_dir_fsas11; + //! \brief Vector of particle differential forward scattering amplitude with polarization perpendicular to the parallel incidence field. + dcomplex *vec_dir_fsas21; + //! \brief Vector of particle differential forward scattering amplitude with polarization perpendicular to perpendicular incidence field. + dcomplex *vec_dir_fsas12; + //! \brief Vector of particle differential forward scattering amplitude with polarization parallel the perpendicular incidence field. + dcomplex *vec_dir_fsas22; + //! \brief Vector of particle differential scattering amplitude with polarization parallel to parallel incidence field. + dcomplex *vec_dir_sas11; + //! \brief Vector of particle differential scattering amplitude with polarization perpendicular to the parallel incidence field. + dcomplex *vec_dir_sas21; + //! \brief Vector of particle differential scattering amplitude with polarization perpendicular to perpendicular incidence field. + dcomplex *vec_dir_sas12; + //! \brief Vector of particle differential scattering amplitude with polarization parallel the perpendicular incidence field. + dcomplex *vec_dir_sas22; + //! \brief Vector of differential particle QSCHU (parallel polarization). + double *vec_dir_qschu1; + //! \brief Vector of differential particle QSCHU (perpendicular polarization). + double *vec_dir_qschu2; + //! \brief Vector of differential particle PSCHU (parallel polarization). + double *vec_dir_pschu1; + //! \brief Vector of differential particle PSCHU (perpendicular polarization). + double *vec_dir_pschu2; + //! \brief Vector of particle differential S0MAG (parallel polarization). + double *vec_dir_s0mag1; + //! \brief Vector of particle differential S0MAG (perpendicular polarization). + double *vec_dir_s0mag2; + //! \brief Vector of differential particle asymmetry parameters (parallel polarization). + double *vec_dir_cosav1; + //! \brief Vector of differential particle asymmetry parameters (perpendicular polarization). + double *vec_dir_cosav2; + //! \brief Vector of differential particle radiation pressure forces (1). + double *vec_dir_rapr1; + //! \brief Vector of differential particle radiation pressure forces (1). + double *vec_dir_rapr2; + //! \brief Vector of differential radiation pressure force components along the polarization direction (parallel polarization). + double *vec_dir_fl1; + //! \brief Vector of differential radiation pressure force components along the polarization direction (perpendicular polarization). + double *vec_dir_fl2; + //! \brief Vector of differential radiation pressure force components perpendicular to the polarization direction (parallel polarization). + double *vec_dir_fr1; + //! \brief Vector of differential radiation pressure force components perpendicular to the polarization direction (perpendicular polarization). + double *vec_dir_fr2; + //! \brief Vector of differential radiation pressure force components along the incidence direction (parallel polarization). + double *vec_dir_fk1; + //! \brief Vector of differential radiation pressure force components along the incidence direction (perpendicular polarization). + double *vec_dir_fk2; + //! \brief Vector of differential radiation pressure force components along the X axis (parallel polarization). + double *vec_dir_fx1; + //! \brief Vector of differential radiation pressure force components along the X axis (perpendicular polarization). + double *vec_dir_fx2; + //! \brief Vector of differential radiation pressure force components along the Y axis (parallel polarization). + double *vec_dir_fy1; + //! \brief Vector of differential radiation pressure force components along the Y axis (perpendicular polarization). + double *vec_dir_fy2; + //! \brief Vector of differential radiation pressure force components along the Z axis (parallel polarization). + double *vec_dir_fz1; + //! \brief Vector of differential radiation pressure force components along the Z axis (perpendicular polarization). + double *vec_dir_fz2; + //! \brief Vector of differential extinction contribution to radiation torque components along the polarization direction (parallel polarization). + double *vec_dir_tqel1; + //! \brief Vector of differential extinction contribution to radiation torque components along the polarization direction (perpendicular polarization). + double *vec_dir_tqel2; + //! \brief Vector of differential extinction contribution to radiation torque components perpendicular to the polarization direction (parallel polarization). + double *vec_dir_tqer1; + //! \brief Vector of differential extinction contribution to radiation torque components perpendicular to the polarization direction (perpendicular polarization). + double *vec_dir_tqer2; + //! \brief Vector of differential extinction contribution to radiation torque components along the incidence direction (parallel polarization). + double *vec_dir_tqek1; + //! \brief Vector of differential extinction contribution to radiation torque components along the incidence direction (perpendicular polarization). + double *vec_dir_tqek2; + //! \brief Vector of differential extinction contribution to radiation torque components along the X axis (parallel polarization). + double *vec_dir_tqex1; + //! \brief Vector of differential extinction contribution to radiation torque components along the X axis (perpendicular polarization). + double *vec_dir_tqex2; + //! \brief Vector of differential extinction contribution to radiation torque components along the Y axis (parallel polarization). + double *vec_dir_tqey1; + //! \brief Vector of differential extinction contribution to radiation torque components along the Y axis (perpendicular polarization). + double *vec_dir_tqey2; + //! \brief Vector of differential extinction contribution to radiation torque components along the Z axis (parallel polarization). + double *vec_dir_tqez1; + //! \brief Vector of differential extinction contribution to radiation torque components along the Z axis (perpendicular polarization). + double *vec_dir_tqez2; + //! \brief Vector of differential scattering contribution to radiation torque components along the polarization direction (parallel polarization). + double *vec_dir_tqsl1; + //! \brief Vector of differential scattering contribution to radiation torque components along the polarization direction (perpendicular polarization). + double *vec_dir_tqsl2; + //! \brief Vector of differential scattering contribution to radiation torque components perpendicular to the polarization direction (parallel polarization). + double *vec_dir_tqsr1; + //! \brief Vector of differential scattering contribution to radiation torque components perpendicular to the polarization direction (perpendicular polarization). + double *vec_dir_tqsr2; + //! \brief Vector of differential scattering contribution to radiation torque components along the incidence direction (parallel polarization). + double *vec_dir_tqsk1; + //! \brief Vector of differential scattering contribution to radiation torque components along the incidence direction (perpendicular polarization). + double *vec_dir_tqsk2; + //! \brief Vector of differential scattering contribution to radiation torque components along X axis (parallel polarization). + double *vec_dir_tqsx1; + //! \brief Vector of differential scattering contribution to radiation torque components along X axis (perpendicular polarization). + double *vec_dir_tqsx2; + //! \brief Vector of differential scattering contribution to radiation torque components along Y axis (parallel polarization). + double *vec_dir_tqsy1; + //! \brief Vector of differential scattering contribution to radiation torque components along Y axis (perpendicular polarization). + double *vec_dir_tqsy2; + //! \brief Vector of differential scattering contribution to radiation torque components along Z axis (parallel polarization). + double *vec_dir_tqsz1; + //! \brief Vector of differential scattering contribution to radiation torque components along Z axis (perpendicular polarization). + double *vec_dir_tqsz2; + //! \brief Vector of cluster Mueller transormation matrices referred to meridional plane (16 per direction per scale). + double *vec_dir_mull; + //! \brief Vector of cluster Mueller transormation matrices referred to scattering plane (16 per direction per scale). + double *vec_dir_mulllr; + + /*! \brief `InclusionOutputInfo` default instance constructor. + * + * \param sc: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` instance. + * \param gc: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` instance. + * \param mpidata: `const mixMPI*` Pointer to a mixMPI instance. + * \param first_xi: `int` Index of the first scale in output (optional, default is 1). + * \param xi_length: `int` Number of scales tobe included in output (optional, default is 0, meaning all). + */ + InclusionOutputInfo( + ScattererConfiguration *sc, GeometryConfiguration *gc, + const mixMPI *mpidata, int first_xi = 1, int xi_length = 0 + ); + + /*! \brief `InclusionOutputInfo` constructor from HDF5 input. + * + * \param hdf5_name: `const string &` Path to the HDF5 file to be read. + */ + InclusionOutputInfo(const std::string &hdf5_name); + + /*! \brief `InclusionOutputInfo` instance destroyer. + */ + ~InclusionOutputInfo(); + + /*! \brief Estimate the size of the structure that would be built for given input. + * + * \param sc: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` instance. + * \param gc: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` instance. + * \param first_xi: `int` Index of the first scale in output (optional, default is 1). + * \param xi_length: `int` Number of scales tobe included in output (optional, default is all). + * \return size: `long` Estimated instance size in bytes. + */ + static long compute_size( + ScattererConfiguration *sc, GeometryConfiguration *gc, + int first_xi = 1, int xi_length = 0 + ); + + /*! \brief Get the size of a `ClusterOutputInfo` instance in bytes. + * + * \return size: `long` Estimated instance size in bytes. + */ + long compute_size(); + + /*! \brief Insert in the current output data the data of another block. + * + * \param rhs: `const InclusionOutputInfo &` Reference to the source data block. + * \return result: `int` Exit code (0 if successful). + */ + int insert(const InclusionOutputInfo &rhs); + + /*! \brief Write the output to a file. + * + * \param output: `const string &` Path to the output to be written. + * \param format: `const string &` Output format (one of LEGACY or HDF5). + * \return result: `int` Exit code (0 if successful). + */ + int write(const std::string &output, const std::string &format); + +#ifdef MPI_VERSION + /*! \brief Receive output data from worker processes. + * + * This function is invoked by the MPI rank-0 process to fetch the + * output data produced by higher rank processes. When calling this + * function, process 0 halts until a valid data chunk is transmitted + * by the queried process. + * + * \param mpidata: `const mixMPI*` Pointer to a `mixMPI` instance. + * \param pid: `int` Rank of the process that is transmitting data. + * \return result: `int` An exit code (0 for success). + */ + int mpireceive(const mixMPI* mpidata, int pid); + + /*! \brief Send output data to process 0. + * + * This function is invoked by non-zero ranked MPI processes when + * they are ready to send back the output data. When a process meets + * this function call, it halts until MPI process 0 asks for the + * data transmission. + * + * \param mpidata: `const mixMPI*` Pointer to a `mixMPI` instance. + * \param pid: `int` Rank of the process that is transmitting data. + * \return result: `int` An exit code (0 for success). + */ + int mpisend(const mixMPI *mpidata); +#endif // MPI_VERSION +}; +// >>> END OF OUTPUT FOR INCLUSION <<< + +// >>> OUTPUT FOR SPHERE <<< +class SphereOutputInfo { +protected: + //! \brief Number of incident azimuth calculations. + int _num_theta; + //! \brief Number of scattered azimuth calculations. + int _num_thetas; + //! \brief Number of incident elevation calculations. + int _num_phi; + //! \brief Number of scattered elevation calculations. + int _num_phis; + //! \brief ID of the first computed wavelength + int _first_xi; + + /*! \brief Write the output to a HDF5 file. + * + * \param file_name: `const string &` Path to the output to be written. + * \return result: `int` Exit code (0 if successful). + */ + int write_hdf5(const std::string &file_name); + + /*! \brief Write the output to a legacy text file. + * + * This function takes care of writing the output using the legacy + * formatted ASCII structure. If the output file does not exist, it + * is created. If it exists, the new content is overwritten. + * + * \param output: `const string &` Path to the output to be written. + * \return result: `int` Exit code (0 if successful). + */ + int write_legacy(const std::string &output); + +public: + //! \brief Read-only view on the ID of the first scale + const int &first_xi = _first_xi; + //! \brief Number of spheres. + int nsph; + //! \brief Maximum field expansion order. + int lm; + //! \brief Incident polarization flag. + int inpol; + //! \brief Number of points for transition layer integration. + int npnt; + //! \brief Number of points for non-transition layer integration. + int npntts; + //! \brief Flag for reference to meridional plane. + int isam; + //! \brief Flag for dielectric function definition. + int idfc; + //! \brief First incident radiation azimuth angle. + double th; + //! \brief Incident radiation azimuth angle step. + double thstp; + //! \brief Last incident radiation azimuth angle. + double thlst; + //! \brief First scattered radiation azimuth angle. + double ths; + //! \brief Scattered radiation azimuth angle step. + double thsstp; + //! \brief Last scattered radiation azimuth angle. + double thslst; + //! \brief First incident radiation elevation angle. + double ph; + //! \brief Incident radiation elevation angle step. + double phstp; + //! \brief Last incident radiation elevation angle. + double phlst; + //! \brief First scattered radiation elevation angle. + double phs; + //! \brief Scattered radiation elevation angle step. + double phsstp; + //! \brief Last scattered radiation elevation angle. + double phslst; + //! \brief Number of directions to be explicitly solved. + int ndirs; + //! \brief Refractive index of external medium. + double exri; + //! \brief Number of scales (wavelengths) + int nxi; + //! \brief Number of scales handled by the current process. + int xi_block_size; + //! \brief Index of the wavelength for T-matrix output. + int jwtm; + //! \brief Number of sphere types. + int configurations; + //! \brief Highest expansion order achieved in calculations. + int lcalc; + //! \brief Harmonic functions argument. + dcomplex arg; + //! \brief Vector of scale (wavelength) indices. + int *vec_jxi; + //! \brief Vector of error severities (0 - success, 1 - DME). + short *vec_ier; + //! \brief Vector of vacuum wave numbers. + double *vec_vk; + //! \brief Vector of computed scales. + double *vec_xi; + //! \brief Vector of sphere sizes (one for every configuration and scale). + double *vec_sphere_sizes; + //! \brief Vector of sphere refractive indices (one for every configuration and scale). + dcomplex *vec_sphere_ref_indices; + //! \brief Vector of sphere scattering cross-sections. + double *vec_scs; + //! \brief Vector of sphere absorption cross-sections. + double *vec_abs; + //! \brief Vector of sphere extinction cross-sections. + double *vec_exs; + //! \brief Vector of sphere albedos. + double *vec_albeds; + //! \brief Vector of sphere scattering-to-geometric cross-sections. + double *vec_scsrt; + //! \brief Vector of sphere absorption-to-geometric cross-sections. + double *vec_absrt; + //! \brief Vector of sphere extinction-to-geometric cross-sections. + double *vec_exsrt; + //! \brief Vector of sphere forward scattering amplitudes. + dcomplex *vec_fsas; + //! \brief Vector of sphere QSCHU. + double *vec_qschu; + //! \brief Vector of sphere PSCHU. + double *vec_pschu; + //! \brief Vector of sphere S0MAG. + double *vec_s0mag; + //! \brief Vector of sphere average asymmetry parameter. + double *vec_cosav; + //! \brief Vector of sphere average radiation pressure force (N). + double *vec_raprs; + //! \brief Vector of sphere average extinction torque along incidence direction (parallel polarization). + double *vec_tqek1; + //! \brief Vector of sphere average extinction torque along incidence direction (perpendicular polarization). + double *vec_tqek2; + //! \brief Vector of sphere average scattering torque along incidence direction (parallel polarization). + double *vec_tqsk1; + //! \brief Vector of sphere average scattering torque along incidence direction (perpendicular polarization). + double *vec_tqsk2; + //| \brief Vector of total forward scattering amplitudes. + dcomplex *vec_fsat; + //! \brief Vector of total QSCHU. + double *vec_qschut; + //! \brief Vector of total PSCHU. + double *vec_pschut; + //! \brief Vector of total S0MAG. + double *vec_s0magt; + //! \brief Vector of incidence azimuth directions (one per incidence azimuth). + double *vec_dir_tidg; + //! \brief Vector of incidence elevation directions (one per incidence elevation). + double *vec_dir_pidg; + //! \brief Vector of scattering azimuth directions (one per scattering azimuth). + double *vec_dir_tsdg; + //! \brief Vector of scattering elevation directions (one per scattering elevation). + double *vec_dir_psdg; + //! \brief Vector of scattering angles (one per direction). + double *vec_dir_scand; + //! \brief Control parameter for incidence plane referred to meridional plane (one per direction). + double *vec_dir_cfmp; + //! \brief Control parameter for scattering plane referred to meridional plane (one per direction). + double *vec_dir_sfmp; + //! \brief Control parameter for incidence plane referred to scattering plane (one per direction). + double *vec_dir_cfsp; + //! \brief Control parameter for scattering plane referred to scattering plane (one per direction). + double *vec_dir_sfsp; + //! \brief Components of the unitary vector perpendicular to incidence plane (three per direction). + double *vec_dir_un; + //! \brief Components of the unitary vector perpendicular to scattering plane (three per direction). + double *vec_dir_uns; + //! \brief Vector of sphere differential scattering amplitude with polarization parallel to parallel incidence field. + dcomplex *vec_dir_sas11; + //! \brief Vector of sphere differential scattering amplitude with polarization perpendicular to the parallel incidence field. + dcomplex *vec_dir_sas21; + //! \brief Vector of sphere differential scattering amplitude with polarization perpendicular to perpendicular incidence field. + dcomplex *vec_dir_sas12; + //! \brief Vector of sphere differential scattering amplitude with polarization parallel the perpendicular incidence field. + dcomplex *vec_dir_sas22; + //! \brief Vector of differential radiation pressure force components along the X axis. + double *vec_dir_fx; + //! \brief Vector of differential radiation pressure force components along the Y axis. + double *vec_dir_fy; + //! \brief Vector of differential radiation pressure force components along the Z axis. + double *vec_dir_fz; + //! \brief Vector of sphere Mueller transormation matrices referred to meridional plane. + double *vec_dir_muls; + //! \brief Vector of sphere Mueller transormation matrices referred to scattering plane. + double *vec_dir_mulslr; + + /*! \brief `SphereOutputInfo` default instance constructor. + * + * \param sc: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` instance. + * \param gc: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` instance. + * \param mpidata: `const mixMPI*` Pointer to a mixMPI instance. + * \param first_xi: `int` Index of the first scale in output (optional, default is 1). + * \param xi_length: `int` Number of scales tobe included in output (optional, default is 0, meaning all). + */ + SphereOutputInfo( + ScattererConfiguration *sc, GeometryConfiguration *gc, + const mixMPI *mpidata, int first_xi = 1, int xi_length = 0 + ); + + /*! \brief `SphereOutputInfo` constructor from HDF5 input. + * + * \param hdf5_name: `const string &` Path to the HDF5 file to be read. + */ + SphereOutputInfo(const std::string &hdf5_name); + + /*! \brief `InclusionOutputInfo` instance destroyer. + */ + ~SphereOutputInfo(); + + /*! \brief Estimate the size of the structure that would be built for given input. + * + * \param sc: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` instance. + * \param gc: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` instance. + * \param first_xi: `int` Index of the first scale in output (optional, default is 1). + * \param xi_length: `int` Number of scales tobe included in output (optional, default is all). + * \return size: `long` Estimated instance size in bytes. + */ + static long compute_size( + ScattererConfiguration *sc, GeometryConfiguration *gc, + int first_xi = 1, int xi_length = 0 + ); + + /*! \brief Get the size of a `ClusterOutputInfo` instance in bytes. + * + * \return size: `long` Estimated instance size in bytes. + */ + long compute_size(); + + /*! \brief Insert in the current output data the data of another block. + * + * \param rhs: `const SphereOutputInfo &` Reference to the source data block. + * \return result: `int` Exit code (0 if successful). + */ + int insert(const SphereOutputInfo &rhs); + + /*! \brief Write the output to a file. + * + * \param output: `const string &` Path to the output to be written. + * \param format: `const string &` Output format (one of LEGACY or HDF5). + * \return result: `int` Exit code (0 if successful). + */ + int write(const std::string &output, const std::string &format); + +#ifdef MPI_VERSION + /*! \brief Receive output data from worker processes. + * + * This function is invoked by the MPI rank-0 process to fetch the + * output data produced by higher rank processes. When calling this + * function, process 0 halts until a valid data chunk is transmitted + * by the queried process. + * + * \param mpidata: `const mixMPI*` Pointer to a `mixMPI` instance. + * \param pid: `int` Rank of the process that is transmitting data. + * \return result: `int` An exit code (0 for success). + */ + int mpireceive(const mixMPI *mpidata, int pid); + + /*! \brief Send output data to process 0. + * + * This function is invoked by non-zero ranked MPI processes when + * they are ready to send back the output data. When a process meets + * this function call, it halts until MPI process 0 asks for the + * data transmission. + * + * \param mpidata: `const mixMPI*` Pointer to a `mixMPI` instance. + * \param pid: `int` Rank of the process that is transmitting data. + * \return result: `int` An exit code (0 for success). + */ + int mpisend(const mixMPI *mpidata); +#endif // MPI_VERSION +}; +// >>> END OF OUTPUT FOR SPHERE <<< + +#endif // INCLUDE_OUTPUTS_H_ diff --git a/src/include/sph_subs.h b/src/include/sph_subs.h index d4d9bc7bf03fabd198674c3abe96c95c7f1d2dd9..1bac56f53536c89c113255e661ab1733c4396d20 100644 --- a/src/include/sph_subs.h +++ b/src/include/sph_subs.h @@ -70,14 +70,7 @@ void cbf(int n, dcomplex z, int &nm, dcomplex *csj); */ double cg1(int lmpml, int mu, int l, int m); -/*! \brief Conjugate of a double precision complex number - * - * \param z: `complex double` The input complex number. - * \return result: `complex double` The conjugate of the input number. - */ -// dcomplex dconjg(dcomplex z); - -/*! \brief Comute the continuous variation of the refractive index and of its radial derivative. +/*! \brief Compute the continuous variation of the refractive index and of its radial derivative. * * This function implements the continuous variation of the refractive index and of its radial * derivative through the materials that constitute the sphere and its surrounding medium. See @@ -88,7 +81,7 @@ double cg1(int lmpml, int mu, int l, int m); * \param i: `int` * \param ic: `int` * \param vk: `double` - * \param c1: `ParticleDescriptor *` Pointer to `ParticleDescriptor` data structure. + * \param c1: `ParticleDescriptor *` Pointer to a `ParticleDescriptor` data structure. */ void diel(int npntmo, int ns, int i, int ic, double vk, ParticleDescriptor *c1); diff --git a/src/include/types.h b/src/include/types.h index 453514b4d89762c779e7f6fb2ba05888244e465a..ba73e2a1edee19c6a8b66090a55adef6fb566e47 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -24,6 +24,7 @@ #include <complex.h> +//! \brief Short-cut to C-style double precision complex type. typedef __complex__ double dcomplex; #ifdef USE_MKL @@ -52,16 +53,20 @@ typedef __complex__ double dcomplex; #ifndef np_int #ifdef lapack_int +//! \brief Alias of the default integer type. #define np_int lapack_int #else #ifdef USE_ILP64 +//! \brief Alias of the default integer type. #define np_int int64_t #else +//! \brief Alias of the default integer type. #define np_int int32_t #endif // USE_ILP64 #endif // lapack_int #endif // np_int +//! \brief Macro to compute the conjugate of a complex number. #define dconjg(z) ( (__real__ (z) - I * (__imag__ (z))) ) /*! \brief Get the imaginary part of double precision complex number. diff --git a/src/inclusion/inclusion.cpp b/src/inclusion/inclusion.cpp index fb9fab4949122238159ef5bc32ffe30b6e8e1d26..86c73b469a07f4a89e9fac7b3420a62bc1119339 100644 --- a/src/inclusion/inclusion.cpp +++ b/src/inclusion/inclusion.cpp @@ -24,17 +24,21 @@ #include <fstream> #include <hdf5.h> #include <string> + #ifdef _OPENMP #include <omp.h> #endif + #ifdef USE_MPI #ifndef MPI_VERSION #include <mpi.h> #endif #endif + #ifdef USE_NVTX #include <nvtx3/nvToolsExt.h> #endif + #ifdef USE_MAGMA #include <cuda_runtime.h> #endif @@ -91,1479 +95,831 @@ #include "../include/utils.h" #endif -using namespace std; - -// >>> InclusionIterationData header <<< // -/*! \brief A data structure representing the information used for a single scale - * of the INCLUSION case. - */ -class InclusionIterationData { -protected: - double *vec_zpv; - -public: - int nimd; - double extr; - - //! \brief Pointer to a ParticleDescriptor structure. - ParticleDescriptor *c1; - //! \brief Vector of geometric asymmetry factors. - double *gaps; - double **tqse; - dcomplex **tqspe; - double **tqss; - dcomplex **tqsps; - double ****zpv; - double **gapm; - dcomplex **gappm; - double *argi; - double *args; - double **gap; - dcomplex **gapp; - double **tqce; - dcomplex **tqcpe; - double **tqcs; - dcomplex **tqcps; - double *duk; - double **cextlr; - double **cext; - double **cmullr; - double **cmul; - double *gapv; - double *tqev; - double *tqsv; - double *u; - double *us; - double *un; - double *uns; - double *up; - double *ups; - double *unmp; - double *unsmp; - double *upmp; - double *upsmp; - //! \brief Scattering angle. - double scan; - double cfmp; - double sfmp; - double cfsp; - double sfsp; - double qsfi; - double sqsfi; - dcomplex *am_vector; - dcomplex **am; - dcomplex arg; - //! \brief Vacuum magnitude of wave vector. - double vk; - //! \brief Wave number. - double wn; - double xip; - int number_of_scales; - int xiblock; - int firstxi; - int lastxi; - //! \brief ID of the GPU used by one MPI process. - int proc_device; - //! \brief Refinement mode selction flag. - int refinemode; - //! \brief Maximum number of refinement iterations. - int maxrefiters; - //! \brief Required accuracy level. - double accuracygoal; - - InclusionIterationData(GeometryConfiguration *gconf, ScattererConfiguration *sconf, const mixMPI *mpidata, const int device_count); - - InclusionIterationData(const InclusionIterationData& rhs); - -#ifdef MPI_VERSION - InclusionIterationData(const mixMPI *mpidata, const int device_count); - - /*! \brief Broadcast over MPI the InclusionIterationData instance from MPI process 0 to all others. - * - * When using MPI, the initial InclusionIterationData instance created by MPI process 0 - * needs to be replicated on all other processes. This function sends it using - * MPI broadcast calls. The MPI broadcast calls in this function must match those - * in the constructor using the mixMPI pointer. - * - * \param mpidata: `mixMPI *` Pointer to the mpi structure used to do the MPI broadcast. - */ - void mpibcast(const mixMPI *mpidata); +#ifndef INCLUDE_OUTPUTS_H_ +#include "../include/outputs.h" #endif - ~InclusionIterationData(); +#ifndef INCLUDE_ITERATION_DATA_H_ +#include "../include/IterationData.h" +#endif -}; +using namespace std; -// >>> End of InclusionIterationData header <<< // +/*! \brief Main calculation loop. + * + * The solution of the scattering problem for different wavelengths is an + * embarrasingly parallel task. This function, therefore, collects all the + * operations that can be independently executed by different processes, + * after the configuration stage and the first calculation loop have been + * executed. + * + * \param jxi488: `int` Wavelength loop index. + * \param sconf: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` object. + * \param gconf: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` object. + * \param sa: `ScatteringAngles *` Pointer to a `ScatteringAngles` object. + * \param cid: `InclusionIterationData *` Pointer to an `InclusionIterationData` object. + * \param oi: `InclusionOutputInfo *` Pointer to an `InclusionOutputInfo` object. + * \param output_path: `const string &` Path to the output directory. + * \param vtppoanp: `VirtualBinaryFile *` Pointer to a `VirtualBinaryFile` object. + */ +int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConfiguration *gconf, ScatteringAngles *sa, InclusionIterationData *cid, InclusionOutputInfo *output, const string& output_path, VirtualBinaryFile *vtppoanp); -// >>> InclusionIterationData implementation <<< // -InclusionIterationData::InclusionIterationData(GeometryConfiguration *gconf, ScattererConfiguration *sconf, const mixMPI *mpidata, const int device_count) { - c1 = new ParticleDescriptorInclusion(gconf, sconf); - const int ndi = c1->nsph * c1->nlim; - const np_int ndit = 2 * ndi; - gaps = new double[c1->nsph](); - tqev = new double[3](); - tqsv = new double[3](); - tqse = new double*[2]; - tqspe = new dcomplex*[2]; - tqss = new double*[2]; - tqsps = new dcomplex*[2]; - tqce = new double*[2]; - tqcpe = new dcomplex*[2]; - tqcs = new double*[2]; - tqcps = new dcomplex*[2]; - for (int ti = 0; ti < 2; ti++) { - tqse[ti] = new double[c1->nsph](); - tqspe[ti] = new dcomplex[c1->nsph](); - tqss[ti] = new double[c1->nsph](); - tqsps[ti] = new dcomplex[c1->nsph](); - tqce[ti] = new double[3](); - tqcpe[ti] = new dcomplex[3](); - tqcs[ti] = new double[3](); - tqcps[ti] = new dcomplex[3](); - } - gapv = new double[3](); - gapp = new dcomplex*[3]; - gappm = new dcomplex*[3]; - gap = new double*[3]; - gapm = new double*[3]; - for (int gi = 0; gi < 3; gi++) { - gapp[gi] = new dcomplex[2](); - gappm[gi] = new dcomplex[2](); - gap[gi] = new double[2](); - gapm[gi] = new double[2](); - } - u = new double[3](); - us = new double[3](); - un = new double[3](); - uns = new double[3](); - up = new double[3](); - ups = new double[3](); - unmp = new double[3](); - unsmp = new double[3](); - upmp = new double[3](); - upsmp = new double[3](); - argi = new double[1](); - args = new double[1](); - duk = new double[3](); - cextlr = new double*[4]; - cext = new double*[4]; - cmullr = new double*[4];; - cmul = new double*[4]; - for (int ci = 0; ci < 4; ci++) { - cextlr[ci] = new double[4](); - cext[ci] = new double[4](); - cmullr[ci] = new double[4](); - cmul[ci] = new double[4](); +/*! \brief C++ implementation of INCLU + * + * \param config_file: `string` Name of the configuration file. + * \param data_file: `string` Name of the input data file. + * \param output_path: `string` Directory to write the output files in. + * \param mpidata: `mixMPI *` Pointer to an instance of MPI data settings. + */ +void inclusion(const string& config_file, const string& data_file, const string& output_path, const mixMPI *mpidata) { + chrono::time_point<chrono::high_resolution_clock> t_start = chrono::high_resolution_clock::now(); + chrono::duration<double> elapsed; + string message; + string timing_name; + FILE *timing_file; + Logger *time_logger; + if (mpidata->rank == 0) { + timing_name = output_path + "/c_timing_mpi"+ to_string(mpidata->rank) +".log"; + timing_file = fopen(timing_name.c_str(), "w"); + time_logger = new Logger(LOG_DEBG, timing_file); } - vec_zpv = new double[c1->lm * 12](); - zpv = new double***[c1->lm]; - for (int zi = 0; zi < c1->lm; zi++) { - zpv[zi] = new double**[12]; - for (int zj = 0; zj < 3; zj++) { - zpv[zi][zj] = new double*[4]; - zpv[zi][zj][0] = vec_zpv + (zi * 12) + (zj * 4); - zpv[zi][zj][1] = vec_zpv + (zi * 12) + (zj * 4) + 2; + Logger *logger = new Logger(LOG_DEBG); + int device_count = 0; + //=========== + // Initialise MAGMA + //=========== +#ifdef USE_MAGMA + const magma_int_t d_array_max_size = 32; // TEMPORARY: can become configurable parameter + magma_device_t *device_array = new magma_device_t[d_array_max_size]; + magma_int_t num_devices; + magma_getdevices(device_array, d_array_max_size, &num_devices); + device_count = (int)num_devices; + delete[] device_array; + message = "DEBUG: Proc-" + to_string(mpidata->rank) + " found " + to_string(device_count) + " GPU "; + if (device_count > 1) message += "devices.\n"; + else message += "device.\n"; + logger->log(message, LOG_DEBG); + logger->log("INFO: Process " + to_string(mpidata->rank) + " initializes MAGMA.\n"); + magma_int_t magma_result = magma_init(); + if (magma_result != MAGMA_SUCCESS) { + logger->err("ERROR: Process " + to_string(mpidata->rank) + " failed to initilize MAGMA.\n"); + logger->err("PROC-" + to_string(mpidata->rank) + ": MAGMA error code " + to_string(magma_result) + "\n"); + if (mpidata->rank == 0) { + fclose(timing_file); + delete time_logger; } + delete logger; + return; } - am_vector = new dcomplex[c1->ndm * c1->ndm](); - am = new dcomplex*[c1->ndm]; - for (int ai = 0; ai < c1->ndm; ai++) { - am[ai] = (am_vector + ai * c1->ndm); - } +#endif // end MAGMA initialisation - arg = 0.0 + 0.0 * I; - // These are suspect initializations - scan = 0.0; - cfmp = 0.0; - sfmp = 0.0; - cfsp = 0.0; - sfsp = 0.0; - qsfi = 0.0; - // End of suspect initializations - wn = sconf->wp / 3.0e8; - xip = sconf->xip; - sqsfi = 1.0; - vk = 0.0; - number_of_scales = sconf->number_of_scales; - xiblock = (int) ceil(((double) (sconf->number_of_scales-1))/((double) mpidata->nprocs)); - lastxi = ((mpidata->rank+1) * xiblock)+1; - firstxi = lastxi-xiblock+1; - if (lastxi > sconf->number_of_scales) lastxi = sconf->number_of_scales; + //=========================== + // the following only happens on MPI process 0 + //=========================== + if (mpidata->rank == 0) { +#ifdef USE_NVTX + nvtxRangePush("Set up"); +#endif + //======================= + // Initialise sconf from configuration file + //======================= + logger->log("INFO: making legacy configuration...", LOG_INFO); + ScattererConfiguration *sconf = NULL; + try { + sconf = ScattererConfiguration::from_dedfb(config_file); + } catch(const OpenConfigurationFileException &ex) { + logger->err("\nERROR: failed to open scatterer configuration file.\n"); + string message = "FILE: " + string(ex.what()) + "\n"; + logger->err(message); + fclose(timing_file); + delete time_logger; + delete logger; + return; + } + sconf->write_formatted(output_path + "/c_OEDFB"); + sconf->write_binary(output_path + "/c_TEDF"); + sconf->write_binary(output_path + "/c_TEDF.hd5", "HDF5"); + // end scatterer initialisation - nimd = c1->nshl[0] + 1; - c1->rc[0][nimd - 1] = c1->ros[0] * sconf->get_rcf(0, nimd - 1); - extr = c1->rc[0][nimd - 1]; - const double pig = acos(0.0) * 2.0; - c1->gcs = pig * extr * extr; - + //======================== + // Initialise gconf from configuration files + //======================== + GeometryConfiguration *gconf = NULL; + try { + gconf = GeometryConfiguration::from_legacy(data_file); + } catch (const OpenConfigurationFileException &ex) { + logger->err("\nERROR: failed to open geometry configuration file.\n"); + string message = "FILE: " + string(ex.what()) + "\n"; + logger->err(message); + if (sconf) delete sconf; + fclose(timing_file); + delete time_logger; + delete logger; + return; + } + logger->log(" done.\n", LOG_INFO); + //end gconf initialisation + +#ifdef USE_NVTX + nvtxRangePop(); +#endif + int s_nsph = sconf->number_of_spheres; + int nsph = gconf->number_of_spheres; + // Sanity check on number of sphere consistency, should always be verified + if (s_nsph == nsph) { + // Shortcuts to variables stored in configuration objects + ScatteringAngles *p_scattering_angles = new ScatteringAngles(gconf); + double wp = sconf->wp; + // Open empty virtual ascii file for output + InclusionOutputInfo *p_output = new InclusionOutputInfo(sconf, gconf, mpidata); + InclusionIterationData *cid = new InclusionIterationData(gconf, sconf, mpidata, device_count); + const np_int ndi = cid->c1->nsph * cid->c1->nlim; + const np_int ndit = 2 * ndi; + logger->log("INFO: Size of matrices to invert: " + to_string((int64_t)cid->c1->ndm) + " x " + to_string((int64_t)cid->c1->ndm) +".\n"); + time_logger->log("INFO: Size of matrices to invert: " + to_string((int64_t)cid->c1->ndm) + " x " + to_string((int64_t)cid->c1->ndm) +".\n"); + + instr(sconf, cid->c1); + thdps(cid->c1->lm, cid->zpv); + double exdc = sconf->exdc; + double exri = sqrt(exdc); + + // Create an empty bynary file + VirtualBinaryFile *vtppoanp = new VirtualBinaryFile(); + string tppoan_name = output_path + "/c_TPPOAN"; #ifdef USE_MAGMA - proc_device = mpidata->rank % device_count; + logger->log("INFO: using MAGMA calls.\n", LOG_INFO); +#elif defined USE_LAPACK + logger->log("INFO: using LAPACK calls.\n", LOG_INFO); #else - proc_device = 0; + logger->log("INFO: using fall-back lucin() calls.\n", LOG_INFO); #endif + int iavm = gconf->iavm; + int isam = gconf->isam; + int inpol = gconf->in_pol; + int nxi = sconf->number_of_scales; + int nth = p_scattering_angles->nth; + int nths = p_scattering_angles->nths; + int nph = p_scattering_angles->nph; + int nphs = p_scattering_angles->nphs; + + //======================== + // write a block of info to virtual binary file + //======================== + vtppoanp->append_line(VirtualBinaryLine(iavm)); + vtppoanp->append_line(VirtualBinaryLine(isam)); + vtppoanp->append_line(VirtualBinaryLine(inpol)); + vtppoanp->append_line(VirtualBinaryLine(nxi)); + vtppoanp->append_line(VirtualBinaryLine(nth)); + vtppoanp->append_line(VirtualBinaryLine(nph)); + vtppoanp->append_line(VirtualBinaryLine(nths)); + vtppoanp->append_line(VirtualBinaryLine(nphs)); + if (sconf->idfc < 0) { + cid->vk = cid->xip * cid->wn; + p_output->vec_vk[0] = cid->vk; + } + + // do the first iteration on jxi488 separately, since it seems to be different from the others + int jxi488 = 1; + int initialmaxrefiters = cid->maxrefiters; + + chrono::time_point<chrono::high_resolution_clock> start_iter_1 = chrono::high_resolution_clock::now(); +#ifdef USE_NVTX + nvtxRangePush("First iteration"); +#endif + // use these pragmas, which should have no effect on parallelism, just to push OMP nested levels at the same level also in the first wavelength iteration + int jer = 0; +#pragma omp parallel + { +#pragma omp single + { + jer = inclusion_jxi488_cycle(jxi488, sconf, gconf, p_scattering_angles, cid, p_output, output_path, vtppoanp); + } + } +#ifdef USE_NVTX + nvtxRangePop(); +#endif + chrono::time_point<chrono::high_resolution_clock> end_iter_1 = chrono::high_resolution_clock::now(); + elapsed = start_iter_1 - t_start; + string message = "INFO: Calculation setup took " + to_string(elapsed.count()) + "s.\n"; + logger->log(message); + time_logger->log(message); + elapsed = end_iter_1 - start_iter_1; + message = "INFO: First iteration took " + to_string(elapsed.count()) + "s.\n"; + logger->log(message); + time_logger->log(message); + /* for the next iterations, just always do maxiter iterations, assuming the accuracy is good enough */ + cid->refinemode = 0; + /* add an extra iteration for margin, if this does not exceed initialmaxrefiters */ + // if (cid->maxrefiters < initialmaxrefiters) cid->maxrefiters++; + if (jer != 0) { + // First loop failed. Halt the calculation. + fclose(timing_file); + delete time_logger; + delete p_output; + delete p_scattering_angles; + delete cid; + delete logger; + delete sconf; + delete gconf; + return; + } - // In the first iteration, if refinement is enabled, determine the number of refinement iterations required to arrive at the target accuracy (if achievable in a reasonable number of iterations) - refinemode = 2; - // maxrefiters and accuracygoal should be configurable and preferably set somewhere else - maxrefiters = 20; - accuracygoal = 1e-6; -} - -InclusionIterationData::InclusionIterationData(const InclusionIterationData& rhs) { - c1 = new ParticleDescriptorInclusion(reinterpret_cast<ParticleDescriptorInclusion &>(*(rhs.c1))); - const int ndi = c1->nsph * c1->nlim; - const np_int ndit = 2 * ndi; - gaps = new double[c1->nsph](); - for (int gi = 0; gi < c1->nsph; gi++) gaps[gi] = rhs.gaps[gi]; - tqev = new double[3](); - tqsv = new double[3](); - for (int ti = 0; ti < 3; ti++) { - tqev[ti] = rhs.tqev[ti]; - tqsv[ti] = rhs.tqsv[ti]; - } - tqse = new double*[2]; - tqspe = new dcomplex*[2]; - tqss = new double*[2]; - tqsps = new dcomplex*[2]; - tqce = new double*[2]; - tqcpe = new dcomplex*[2]; - tqcs = new double*[2]; - tqcps = new dcomplex*[2]; - for (int ti = 0; ti < 2; ti++) { - tqse[ti] = new double[c1->nsph](); - tqspe[ti] = new dcomplex[c1->nsph](); - tqss[ti] = new double[c1->nsph](); - tqsps[ti] = new dcomplex[c1->nsph](); - for (int tj = 0; tj < c1->nsph; tj++) { - tqse[ti][tj] = rhs.tqse[ti][tj]; - tqspe[ti][tj] = rhs.tqspe[ti][tj]; - tqss[ti][tj] = rhs.tqss[ti][tj]; - tqsps[ti][tj] = rhs.tqsps[ti][tj]; - } - tqce[ti] = new double[3](); - tqcpe[ti] = new dcomplex[3](); - tqcs[ti] = new double[3](); - tqcps[ti] = new dcomplex[3](); - for (int tj = 0; tj < 3; tj++) { - tqce[ti][tj] = rhs.tqce[ti][tj]; - tqcpe[ti][tj] = rhs.tqcpe[ti][tj]; - tqcs[ti][tj] = rhs.tqcs[ti][tj]; - tqcps[ti][tj] = rhs.tqcps[ti][tj]; - } - } - gapv = new double[3](); - gapp = new dcomplex*[3]; - gappm = new dcomplex*[3]; - gap = new double*[3]; - gapm = new double*[3]; - for (int gi = 0; gi < 3; gi++) { - gapv[gi] = rhs.gapv[gi]; - gapp[gi] = new dcomplex[2](); - gappm[gi] = new dcomplex[2](); - gap[gi] = new double[2](); - gapm[gi] = new double[2](); - for (int gj = 0; gj < 2; gj++) { - gapp[gi][gj] = rhs.gapp[gi][gj]; - gappm[gi][gj] = rhs.gappm[gi][gj]; - gap[gi][gj] = rhs.gap[gi][gj]; - gapm[gi][gj] = rhs.gapm[gi][gj]; - } - } - u = new double[3](); - us = new double[3](); - un = new double[3](); - uns = new double[3](); - up = new double[3](); - ups = new double[3](); - unmp = new double[3](); - unsmp = new double[3](); - upmp = new double[3](); - upsmp = new double[3](); - duk = new double[3](); - for (int ui = 0; ui < 3; ui++) { - u[ui] = rhs.u[ui]; - us[ui] = rhs.us[ui]; - un[ui] = rhs.un[ui]; - uns[ui] = rhs.uns[ui]; - up[ui] = rhs.up[ui]; - ups[ui] = rhs.ups[ui]; - unmp[ui] = rhs.unmp[ui]; - unsmp[ui] = rhs.unsmp[ui]; - upmp[ui] = rhs.upmp[ui]; - upsmp[ui] = rhs.upsmp[ui]; - duk[ui] = rhs.duk[ui]; - } - argi = new double[1](); - args = new double[1](); - argi[0] = rhs.argi[0]; - args[0] = rhs.args[0]; - cextlr = new double*[4]; - cext = new double*[4]; - cmullr = new double*[4];; - cmul = new double*[4]; - for (int ci = 0; ci < 4; ci++) { - cextlr[ci] = new double[4](); - cext[ci] = new double[4](); - cmullr[ci] = new double[4](); - cmul[ci] = new double[4](); - for (int cj = 0; cj < 4; cj++) { - cextlr[ci][cj] = rhs.cextlr[ci][cj]; - cext[ci][cj] = rhs.cext[ci][cj]; - cmullr[ci][cj] = rhs.cmullr[ci][cj]; - cmul[ci][cj] = rhs.cmul[ci][cj]; - } - } - vec_zpv = new double[c1->lm * 12]; - zpv = new double***[c1->lm]; - for (int zi = 0; zi < c1->lm; zi++) { - zpv[zi] = new double **[12]; - for (int zj = 0; zj < 3; zj++) { - zpv[zi][zj] = new double*[4]; - zpv[zi][zj][0] = vec_zpv + (zi * 12) + (zj * 4); - zpv[zi][zj][1] = vec_zpv + (zi * 12) + (zj * 4) + 2; - zpv[zi][zj][0][0] = rhs.zpv[zi][zj][0][0]; - zpv[zi][zj][0][1] = rhs.zpv[zi][zj][0][1]; - zpv[zi][zj][1][0] = rhs.zpv[zi][zj][1][0]; - zpv[zi][zj][1][1] = rhs.zpv[zi][zj][1][1]; - } - } - am_vector = new dcomplex[c1->ndm * c1->ndm]; - for (int ai = 0; ai < c1->ndm * c1->ndm; ai++) am_vector[ai] = rhs.am_vector[ai]; - am = new dcomplex*[c1->ndm]; - for (int ai = 0; ai < c1->ndm; ai++) { - am[ai] = (am_vector + ai * c1->ndm); - } - - arg = rhs.arg; - // These are suspect initializations - scan = rhs.scan; - cfmp = rhs.cfmp; - sfmp = rhs.sfmp; - cfsp = rhs.cfsp; - sfsp = rhs.sfsp; - qsfi = rhs.qsfi; - // End of suspect initializations - wn = rhs.wn; - xip = rhs.xip; - sqsfi = rhs.sqsfi; - vk = rhs.vk; - firstxi = rhs.firstxi; - lastxi = rhs.lastxi; - xiblock = rhs.xiblock; - number_of_scales = rhs.number_of_scales; - - nimd = rhs.nimd; - extr = rhs.extr; - - proc_device = rhs.proc_device; - refinemode = rhs.refinemode; - maxrefiters = rhs.maxrefiters; - accuracygoal = rhs.accuracygoal; -} + //================================================== + // do the first outputs here, so that I open here the new files, afterwards I only append + //================================================== + vtppoanp->write_to_disk(output_path + "/c_TPPOAN"); + delete vtppoanp; + + // here go the calls that send data to be duplicated on other MPI processes from process 0 to others, using MPI broadcasts, but only if MPI is actually used +#ifdef MPI_VERSION + if (mpidata->mpirunning) { + gconf->mpibcast(mpidata); + sconf->mpibcast(mpidata); + cid->mpibcast(mpidata); + p_scattering_angles->mpibcast(mpidata); + } +#endif + // Create this variable and initialise it with a default here, so that it is defined anyway, with or without OpenMP support enabled + int ompnumthreads = 1; + // this is for MPI process 0 (or even if we are not using MPI at all) + int myjxi488startoffset = 0; + int myMPIstride = ompnumthreads; + int myMPIblock = ompnumthreads; + // Define here shared arrays of virtual ascii and binary files, so that thread 0 will be able to access them all later + InclusionOutputInfo **p_outarray = NULL; + VirtualBinaryFile **vtppoanarray = NULL; + +#ifdef USE_NVTX + nvtxRangePush("Parallel loop"); +#endif + + //=========================================== + // open the OpenMP parallel context, so each thread can initialise its stuff + //=========================================== +#pragma omp parallel + { + // Create and initialise this variable here, so that if OpenMP is enabled it is local to the thread, and if OpenMP is not enabled it has a well-defiled value anyway + int myompthread = 0; + +#ifdef _OPENMP + // If OpenMP is enabled, give actual values to myompthread and ompnumthreads, and open thread-local output files + myompthread = omp_get_thread_num(); + if (myompthread == 0) ompnumthreads = omp_get_num_threads(); +#endif + + if (myompthread == 0) { + // Initialise some shared variables only on thread 0 + p_outarray = new InclusionOutputInfo*[ompnumthreads]; + vtppoanarray = new VirtualBinaryFile*[ompnumthreads]; + myMPIblock = ompnumthreads; + myMPIstride = myMPIblock; + } #ifdef MPI_VERSION -InclusionIterationData::InclusionIterationData(const mixMPI *mpidata, const int device_count) { - c1 = new ParticleDescriptorInclusion(mpidata); - const int ndi = c1->nsph * c1->nlim; - const np_int ndit = 2 * ndi; - gaps = new double[c1->nsph](); - MPI_Bcast(gaps, c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - tqev = new double[3](); - tqsv = new double[3](); - MPI_Bcast(tqev, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqsv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - tqse = new double*[2]; - tqspe = new dcomplex*[2]; - tqss = new double*[2]; - tqsps = new dcomplex*[2]; - tqce = new double*[2]; - tqcpe = new dcomplex*[2]; - tqcs = new double*[2]; - tqcps = new dcomplex*[2]; - for (int ti = 0; ti < 2; ti++) { - tqse[ti] = new double[c1->nsph](); - tqspe[ti] = new dcomplex[c1->nsph](); - tqss[ti] = new double[c1->nsph](); - tqsps[ti] = new dcomplex[c1->nsph](); - MPI_Bcast(tqse[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqspe[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(tqss[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqsps[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - tqce[ti] = new double[3](); - tqcpe[ti] = new dcomplex[3](); - tqcs[ti] = new double[3](); - tqcps[ti] = new dcomplex[3](); - MPI_Bcast(tqce[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcpe[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcs[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcps[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - } - gapv = new double[3](); - gapp = new dcomplex*[3]; - gappm = new dcomplex*[3]; - gap = new double*[3]; - gapm = new double*[3]; - MPI_Bcast(gapv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - for (int gi = 0; gi < 3; gi++) { - gapp[gi] = new dcomplex[2](); - gappm[gi] = new dcomplex[2](); - gap[gi] = new double[2](); - gapm[gi] = new double[2](); - MPI_Bcast(gapp[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(gappm[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(gap[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(gapm[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); - } - u = new double[3](); - us = new double[3](); - un = new double[3](); - uns = new double[3](); - up = new double[3](); - ups = new double[3](); - unmp = new double[3](); - unsmp = new double[3](); - upmp = new double[3](); - upsmp = new double[3](); - duk = new double[3](); - MPI_Bcast(u, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(us, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(un, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(uns, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(up, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(ups, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(unmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(unsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(upmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(upsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(duk, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - argi = new double[1](); - args = new double[1](); - MPI_Bcast(argi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(args, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - cextlr = new double*[4]; - cext = new double*[4]; - cmullr = new double*[4];; - cmul = new double*[4]; - for (int ci = 0; ci < 4; ci++) { - cextlr[ci] = new double[4](); - cext[ci] = new double[4](); - cmullr[ci] = new double[4](); - cmul[ci] = new double[4](); - MPI_Bcast(cextlr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cext[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cmullr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cmul[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - } - vec_zpv = new double[c1->lm * 12]; - MPI_Bcast(vec_zpv, c1->lm * 12, MPI_DOUBLE, 0, MPI_COMM_WORLD); - zpv = new double***[c1->lm]; - for (int zi = 0; zi < c1->lm; zi++) { - zpv[zi] = new double **[12]; - for (int zj = 0; zj < 3; zj++) { - zpv[zi][zj] = new double*[4]; - zpv[zi][zj][0] = vec_zpv + (zi * 12) + (zj * 4); - zpv[zi][zj][1] = vec_zpv + (zi * 12) + (zj * 4) + 2; + if (myompthread == 0) { + if (mpidata->mpirunning) { + // only go through this if MPI has been actually used + for (int rr=1; rr<mpidata->nprocs; rr++) { + // individually send their respective starting points to other MPI processes: they start immediately after the frequencies computed by previous processes so far + int remotejxi488startoffset = myMPIstride; + MPI_Send(&remotejxi488startoffset, 1, MPI_INT, rr, 3, MPI_COMM_WORLD); + int remoteMPIblock; + MPI_Recv(&remoteMPIblock, 1, MPI_INT, rr, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + // update myMPIstride to include the ones due to MPI process rr + myMPIstride += remoteMPIblock; + } + // now I know the total myMPIstride, I can send it to all processes + MPI_Bcast(&myMPIstride, 1, MPI_INT, 0, MPI_COMM_WORLD); + } + } +#endif + // add an omp barrier to make sure that the global variables defined by thread 0 are known to all threads below this +#pragma omp barrier + + // To test parallelism, I will now start feeding this function with "clean" copies of the parameters, so that they will not be changed by previous iterations, and each one will behave as the first one. Define all (empty) variables here, so they have the correct scope, then they get different definitions depending on thread number + InclusionIterationData *cid_2 = NULL; + InclusionOutputInfo *p_output_2 = NULL; + VirtualBinaryFile *vtppoanp_2 = NULL; + // for threads other than the 0, create distinct copies of all relevant data, while for thread 0 just define new references / pointers to the original ones + if (myompthread == 0) { + cid_2 = cid; + // OMP thread 0 of MPI process 0 holds the pointer to the full output structure + p_output_2 = p_output; + p_outarray[0] = p_output_2; + } else { + // this is not thread 0, so do create fresh copies of all local variables + cid_2 = new InclusionIterationData(*cid); + } + // make sure all threads align here: I don't want the following loop to accidentally start for thread 0, possibly modifying some variables before they are copied by all other threads + if (myompthread==0) { + logger->log("Syncing OpenMP threads and starting the loop on wavelengths\n"); + } +#pragma omp barrier + // ok, now I can actually start the parallel calculations + for (int ixi488=2; ixi488<=cid_2->number_of_scales; ixi488 +=myMPIstride) { + // the parallel loop over MPI processes covers a different set of indices for each thread +#pragma omp barrier + int myjxi488 = ixi488+myompthread; + // each thread opens new virtual files and stores their pointers in the shared array + vtppoanp_2 = new VirtualBinaryFile(); + // each thread puts a copy of the pointers to its virtual files in the shared arrays + vtppoanarray[myompthread] = vtppoanp_2; +#pragma omp barrier + + // each MPI process handles a number of contiguous scales corresponding to its number of OMP threads at this omp level of parallelism + if (myjxi488 <= cid_2->number_of_scales) { + if (myompthread > 0) { + // UPDATE: non-0 threads need to allocate memory for one scale at a time. + p_output_2 = new InclusionOutputInfo(sconf, gconf, mpidata, myjxi488, 1); + p_outarray[myompthread] = p_output_2; + } + int jer = inclusion_jxi488_cycle(myjxi488, sconf, gconf, p_scattering_angles, cid_2, p_output_2, output_path, vtppoanp_2); + } else { + if (myompthread > 0) { + // If there is no input for this thread, set output pointer to NULL. + p_outarray[myompthread] = NULL; + } + } +#pragma omp barrier + +#ifdef USE_NVTX + nvtxRangePush("Output concatenation"); +#endif +#pragma omp barrier + // threads different from 0 append their virtual files to the one of thread 0, and delete them + if (myompthread == 0) { + for (int ti=1; ti<ompnumthreads; ti++) { + if (p_outarray[ti] != NULL) { + p_outarray[0]->insert(*(p_outarray[ti])); + delete p_outarray[ti]; + p_outarray[ti] = NULL; + } + vtppoanarray[0]->append(*(vtppoanarray[ti])); + delete vtppoanarray[ti]; + } + } +#pragma omp barrier + //============================================== + // Collect all virtual files on thread 0 of MPI process 0, and append them to disk + //============================================== + if (myompthread == 0) { + // thread 0 writes its virtual files, now including contributions from all threads, to disk, and deletes them + // p_outarray[0]->append_to_disk(output_path + "/c_OINCLU"); + // delete p_outarray[0]; + vtppoanarray[0]->append_to_disk(output_path + "/c_TPPOAN"); + delete vtppoanarray[0]; + +#ifdef MPI_VERSION + if (mpidata->mpirunning) { + // only go through this if MPI has been actually used + for (int rr=1; rr<mpidata->nprocs; rr++) { + // get the data from process rr by receiving it in total memory structure + p_outarray[0]->mpireceive(mpidata, rr); + // get the data from process rr, creating a new virtual ascii file + // VirtualAsciiFile *p_output = new VirtualAsciiFile(mpidata, rr); + // append to disk and delete virtual ascii file + // p_output->append_to_disk(output_path + "/c_OINCLU"); + // delete p_output; + + // get the data from process rr, creating a new virtual binary file + VirtualBinaryFile *vtppoanp = new VirtualBinaryFile(mpidata, rr); + // append to disk and delete virtual binary file + vtppoanp->append_to_disk(output_path + "/c_TPPOAN"); + delete vtppoanp; + int test = MPI_Barrier(MPI_COMM_WORLD); + } + } +#endif + } + // end block writing to disk +#ifdef USE_NVTX + nvtxRangePop(); +#endif +#pragma omp barrier + + } // close strided loop running on MPI processes, ixi488 loop + // delete the shared arrays I used to make available to thread 0 the virtual files of other threads +#pragma omp barrier + if (myompthread == 0) { + delete[] p_outarray; + delete[] vtppoanarray; + } + { + string message = "INFO: Closing thread-local output files of thread " + to_string(myompthread) + " and syncing threads.\n"; + logger->log(message); + } +#ifdef USE_NVTX + nvtxRangePop(); +#endif + delete cid_2; + } + delete p_scattering_angles; + p_output->write(output_path + "/c_OINCLU.hd5", "HDF5"); + p_output->write(output_path + "/c_OINCLU", "LEGACY"); + delete p_output; + } // closes s_nsph == nsph check + + else { // Sphere number inconsistency error. + throw UnrecognizedConfigurationException( + "Inconsistent geometry and scatterer configurations." + ); } - } - am_vector = new dcomplex[c1->ndm * c1->ndm]; - am = new dcomplex*[c1->ndm]; - for (int ai = 0; ai < c1->ndm; ai++) { - am[ai] = (am_vector + ai * c1->ndm); - MPI_Bcast(am[ai], c1->ndm, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - } - MPI_Bcast(&arg, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(&scan, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&cfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&cfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&qsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&wn, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&xip, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sqsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&vk, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&xiblock, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&number_of_scales, 1, MPI_INT, 0, MPI_COMM_WORLD); - lastxi = ((mpidata->rank+1) * xiblock)+1; - firstxi = lastxi-xiblock+1; - if (lastxi > number_of_scales) lastxi = number_of_scales; - MPI_Bcast(&nimd, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&extr, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - + delete sconf; + delete gconf; #ifdef USE_MAGMA - proc_device = mpidata->rank % device_count; -#else - proc_device = 0; + logger->log("INFO: Process " + to_string(mpidata->rank) + " finalizes MAGMA.\n"); + magma_finalize(); #endif - MPI_Bcast(&refinemode, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&maxrefiters, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&accuracygoal, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); -} - -void InclusionIterationData::mpibcast(const mixMPI *mpidata) { - c1->mpibcast(mpidata); - const int ndi = c1->nsph * c1->nlim; - const np_int ndit = 2 * ndi; - MPI_Bcast(gaps, c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqev, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqsv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - for (int ti = 0; ti < 2; ti++) { - MPI_Bcast(tqse[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqspe[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(tqss[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqsps[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(tqce[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcpe[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcs[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcps[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - } - MPI_Bcast(gapv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - for (int gi = 0; gi < 3; gi++) { - MPI_Bcast(gapp[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(gappm[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(gap[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(gapm[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); - } - MPI_Bcast(u, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(us, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(un, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(uns, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(up, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(ups, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(unmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(unsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(upmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(upsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(duk, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(argi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(args, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - for (int ci = 0; ci < 4; ci++) { - MPI_Bcast(cextlr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cext[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cmullr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cmul[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - } - MPI_Bcast(vec_zpv, c1->lm * 12, MPI_DOUBLE, 0, MPI_COMM_WORLD); - // since MPI expects an int argument for the number of elements to transfer in one go, transfer am one row at a time - for (int ai = 0; ai < c1->ndm; ai++) { - MPI_Bcast(am[ai], c1->ndm, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - } - MPI_Bcast(&arg, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(&scan, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&cfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&cfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&qsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&wn, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&xip, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sqsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&vk, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&xiblock, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&number_of_scales, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&nimd, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&extr, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&refinemode, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&maxrefiters, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&accuracygoal, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); -} + chrono::time_point<chrono::high_resolution_clock> t_end = chrono::high_resolution_clock::now(); + elapsed = t_end - t_start; + string message = "INFO: Calculation lasted " + to_string(elapsed.count()) + "s.\n"; + logger->log(message); + logger->log("Finished: output written to " + output_path + "/c_OINCLU\n"); + time_logger->log(message); + fclose(timing_file); + delete time_logger; + } // end instructions block of MPI process 0 + + //=============================== + // instruction block for MPI processes different from 0 + //=============================== +#ifdef MPI_VERSION + else { + // here go the code for MPI processes other than 0 + // copy gconf, sconf, cid and p_scattering_angles from MPI process 0 + GeometryConfiguration *gconf = new GeometryConfiguration(mpidata); + ScattererConfiguration *sconf = new ScattererConfiguration(mpidata); + InclusionIterationData *cid = new InclusionIterationData(mpidata, device_count); + ScatteringAngles *p_scattering_angles = new ScatteringAngles(mpidata); + + // Create this variable and initialise it with a default here, so that it is defined anyway, with or without OpenMP support enabled + int ompnumthreads = 1; + InclusionOutputInfo **p_outarray = NULL; + VirtualBinaryFile **vtppoanarray = NULL; + int myjxi488startoffset; + int myMPIstride = ompnumthreads; + int myMPIblock = ompnumthreads; + +#pragma omp parallel + { + // Create and initialise this variable here, so that if OpenMP is enabled it is local to the thread, and if OpenMP is not enabled it has a well-defiled value anyway + int myompthread = 0; +#ifdef _OPENMP + // If OpenMP is enabled, give actual values to myompthread and ompnumthreads, and open thread-local output files + myompthread = omp_get_thread_num(); + if (myompthread == 0) ompnumthreads = omp_get_num_threads(); #endif + if (myompthread == 0) { + // receive the start parameter from MPI process 0 + MPI_Recv(&myjxi488startoffset, 1, MPI_INT, 0, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + // send my number of omp threads to process 0 + MPI_Send(&ompnumthreads, 1, MPI_INT, 0, 3, MPI_COMM_WORLD); + // receive myMPIstride sent by MPI process 0 to all processes + MPI_Bcast(&myMPIstride, 1, MPI_INT, 0, MPI_COMM_WORLD); + // allocate virtual files for each thread + p_outarray = new InclusionOutputInfo*[ompnumthreads]; + vtppoanarray = new VirtualBinaryFile*[ompnumthreads]; + } +#pragma omp barrier + // To test parallelism, I will now start feeding this function with "clean" copies of the parameters, so that they will not be changed by previous iterations, and each one will behave as the first one. Define all (empty) variables here, so they have the correct scope, then they get different definitions depending on thread number + InclusionIterationData *cid_2 = NULL; + InclusionOutputInfo *p_output_2 = NULL; + VirtualBinaryFile *vtppoanp_2 = NULL; + // PLACEHOLDER + // for threads other than the 0, create distinct copies of all relevant data, while for thread 0 just define new references / pointers to the original ones + if (myompthread == 0) { + cid_2 = cid; + } else { + // this is not thread 0, so do create fresh copies of all local variables + cid_2 = new InclusionIterationData(*cid); + } + // make sure all threads align here: I don't want the following loop to accidentally start for thread 0, possibly modifying some variables before they are copied by all other threads +#pragma omp barrier + // ok, now I can actually start the parallel calculations + for (int ixi488=2; ixi488<=cid_2->number_of_scales; ixi488 +=myMPIstride) { + // the parallel loop over MPI processes covers a different set of indices for each thread +#pragma omp barrier + int myjxi488 = ixi488 + myjxi488startoffset + myompthread; + // each thread opens new virtual files and stores their pointers in the shared array + vtppoanp_2 = new VirtualBinaryFile(); + // each thread puts a copy of the pointers to its virtual files in the shared arrays + vtppoanarray[myompthread] = vtppoanp_2; +#pragma omp barrier + if (myompthread==0) logger->log("Syncing OpenMP threads and starting the loop on wavelengths\n"); + // ok, now I can actually start the parallel calculations + // each MPI process handles a number of contiguous scales corresponding to its number of OMP threads at this omp level of parallelism + if (myjxi488 <= cid_2->number_of_scales) { + if (myompthread > 0) { + // UPDATE: non-0 threads need to allocate memory for one scale at a time. + p_output_2 = new InclusionOutputInfo(sconf, gconf, mpidata, myjxi488, 1); + p_outarray[myompthread] = p_output_2; + } else { + // Thread 0 of non-zero MPI processes needs to allocate memory for the + // output of all threads. + p_output_2 = new InclusionOutputInfo(sconf, gconf, mpidata, myjxi488, ompnumthreads); + p_outarray[0] = p_output_2; + } + int jer = inclusion_jxi488_cycle(myjxi488, sconf, gconf, p_scattering_angles, cid_2, p_output_2, output_path, vtppoanp_2); + } else { + if (myompthread > 0) { + // If there is no input for this thread, set the output pointer to NULL. + p_outarray[myompthread] = NULL; + } + } -InclusionIterationData::~InclusionIterationData() { - const int nsph = c1->nsph; - delete[] am_vector; - delete[] am; - for (int zi = 0; zi < c1->lm; zi++) { - for (int zj = 0; zj < 3; zj++) { - delete[] zpv[zi][zj]; - } - delete[] zpv[zi]; - } - delete[] zpv; - delete[] vec_zpv; - delete c1; - delete[] gaps; - for (int ti = 1; ti > -1; ti--) { - delete[] tqse[ti]; - delete[] tqss[ti]; - delete[] tqspe[ti]; - delete[] tqsps[ti]; - delete[] tqce[ti]; - delete[] tqcpe[ti]; - delete[] tqcs[ti]; - delete[] tqcps[ti]; - } - delete[] tqse; - delete[] tqss; - delete[] tqspe; - delete[] tqsps; - delete[] tqce; - delete[] tqcpe; - delete[] tqcs; - delete[] tqcps; - delete[] tqev; - delete[] tqsv; - for (int gi = 2; gi > -1; gi--) { - delete[] gapp[gi]; - delete[] gappm[gi]; - delete[] gap[gi]; - delete[] gapm[gi]; - } - delete[] gapp; - delete[] gappm; - delete[] gap; - delete[] gapm; - delete[] gapv; - delete[] u; - delete[] us; - delete[] un; - delete[] uns; - delete[] up; - delete[] ups; - delete[] unmp; - delete[] unsmp; - delete[] upmp; - delete[] upsmp; - delete[] argi; - delete[] args; - delete[] duk; - for (int ci = 3; ci > -1; ci--) { - delete[] cextlr[ci]; - delete[] cext[ci]; - delete[] cmullr[ci]; - delete[] cmul[ci]; +#pragma omp barrier + // threads different from 0 append their virtual files to the one of thread 0, and delete them + if (myompthread == 0) { + for (int ti=1; ti<ompnumthreads; ti++) { + if (p_outarray[ti] != NULL) { + p_outarray[0]->insert(*(p_outarray[ti])); + delete p_outarray[ti]; + p_outarray[ti] = NULL; + } + vtppoanarray[0]->append(*(vtppoanarray[ti])); + delete vtppoanarray[ti]; + } + // thread 0 sends the collected virtualfiles to thread 0 of MPI process 0, then deletes them + for (int rr=1; rr<mpidata->nprocs; rr++) { + if (rr == mpidata->rank) { + p_outarray[0]->mpisend(mpidata); + delete p_outarray[0]; + vtppoanarray[0]->mpisend(mpidata); + delete vtppoanarray[0]; + } + int test = MPI_Barrier(MPI_COMM_WORLD); + } + } + } // close strided loop running on MPI processes + + // Clean memory +#pragma omp barrier + if (myompthread == 0) { + delete[] p_outarray; + delete[] vtppoanarray; + } + delete cid_2; + + } // close pragma omp parallel + delete p_scattering_angles; + delete sconf; + delete gconf; +#endif +#ifdef USE_MAGMA + logger->log("INFO: Process " + to_string(mpidata->rank) + " finalizes MAGMA.\n"); + magma_finalize(); +#endif + delete logger; +#ifdef MPI_VERSION } - delete[] cextlr; - delete[] cext; - delete[] cmullr; - delete[] cmul; +#endif } -// >>> End of InclusionIterationData implementation <<< // - -int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConfiguration *gconf, ScatteringAngles *sa, InclusionIterationData *cid, VirtualAsciiFile *output, const string& output_path, VirtualBinaryFile *vtppoanp); - -/*! \brief C++ implementation of INCLU - * - * \param config_file: `string` Name of the configuration file. - * \param data_file: `string` Name of the input data file. - * \param output_path: `string` Directory to write the output files in. - * \param mpidata: `mixMPI *` Pointer to an instance of MPI data settings. - */ -void inclusion(const string& config_file, const string& data_file, const string& output_path, const mixMPI *mpidata) { - chrono::time_point<chrono::high_resolution_clock> t_start = chrono::high_resolution_clock::now(); - chrono::duration<double> elapsed; - string message; - string timing_name; - FILE *timing_file; - Logger *time_logger; - if (mpidata->rank == 0) { - timing_name = output_path + "/c_timing_mpi"+ to_string(mpidata->rank) +".log"; - timing_file = fopen(timing_name.c_str(), "w"); - time_logger = new Logger(LOG_DEBG, timing_file); - } + +int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConfiguration *gconf, ScatteringAngles *sa, InclusionIterationData *cid, InclusionOutputInfo *output, const string& output_path, VirtualBinaryFile *vtppoanp) { + const dcomplex cc0 = 0.0 + I * 0.0; + int nxi = sconf->number_of_scales; + char virtual_line[256]; + string message = "INFO: running scale iteration " + to_string(jxi488) + " of " + to_string(nxi) + ".\n"; Logger *logger = new Logger(LOG_DEBG); - int device_count = 0; - //=========== - // Initialise MAGMA - //=========== -#ifdef USE_MAGMA - const magma_int_t d_array_max_size = 32; // TEMPORARY: can become configurable parameter - magma_device_t *device_array = new magma_device_t[d_array_max_size]; - magma_int_t num_devices; - magma_getdevices(device_array, d_array_max_size, &num_devices); - device_count = (int)num_devices; - delete[] device_array; - message = "DEBUG: Proc-" + to_string(mpidata->rank) + " found " + to_string(device_count) + " GPU "; - if (device_count > 1) message += "devices.\n"; - else message += "device.\n"; - logger->log(message, LOG_DEBG); - logger->log("INFO: Process " + to_string(mpidata->rank) + " initializes MAGMA.\n"); - magma_int_t magma_result = magma_init(); - if (magma_result != MAGMA_SUCCESS) { - logger->err("ERROR: Process " + to_string(mpidata->rank) + " failed to initilize MAGMA.\n"); - logger->err("PROC-" + to_string(mpidata->rank) + ": MAGMA error code " + to_string(magma_result) + "\n"); - if (mpidata->rank == 0) { - fclose(timing_file); - delete time_logger; - } - delete logger; - return; - } -#endif // end MAGMA initialisation - - //=========================== - // the following only happens on MPI process 0 - //=========================== - if (mpidata->rank == 0) { -#ifdef USE_NVTX - nvtxRangePush("Set up"); -#endif - //======================= - // Initialise sconf from configuration file - //======================= - logger->log("INFO: making legacy configuration...", LOG_INFO); - ScattererConfiguration *sconf = NULL; - try { - sconf = ScattererConfiguration::from_dedfb(config_file); - } catch(const OpenConfigurationFileException &ex) { - logger->err("\nERROR: failed to open scatterer configuration file.\n"); - string message = "FILE: " + string(ex.what()) + "\n"; - logger->err(message); - fclose(timing_file); - delete time_logger; - delete logger; - return; - } - sconf->write_formatted(output_path + "/c_OEDFB"); - sconf->write_binary(output_path + "/c_TEDF"); - sconf->write_binary(output_path + "/c_TEDF.hd5", "HDF5"); - // end scatterer initialisation - - //======================== - // Initialise gconf from configuration files - //======================== - GeometryConfiguration *gconf = NULL; - try { - gconf = GeometryConfiguration::from_legacy(data_file); - } catch (const OpenConfigurationFileException &ex) { - logger->err("\nERROR: failed to open geometry configuration file.\n"); - string message = "FILE: " + string(ex.what()) + "\n"; - logger->err(message); - if (sconf) delete sconf; - fclose(timing_file); - delete time_logger; - delete logger; - return; - } - logger->log(" done.\n", LOG_INFO); - //end gconf initialisation + logger->log(message); + chrono::duration<double> elapsed; + chrono::time_point<chrono::high_resolution_clock> interval_start, interval_end; + int jer = 0; + int lcalc = 0; + int jaw = 1; + int li = cid->c1->li; + int le = cid->c1->le; + int lm = cid->c1->lm; + int nsph = cid->c1->nsph; + np_int mxndm = gconf->mxndm; + int iavm = gconf->iavm; + int inpol = gconf->in_pol; + int npnt = cid->c1->npnt; + int npntts = cid->c1->npntts; + int isam = gconf->iavm; + int jwtm = gconf->jwtm; + np_int ndit = cid->c1->ndit; + int isq, ibf; + int last_configuration; + dcomplex ent, entn; + double enti; + int num_configs = sconf->configurations; + int ndirs = sa->nkks; + int oindex = -1; + int jindex = jxi488 - output->first_xi + 1; #ifdef USE_NVTX - nvtxRangePop(); + nvtxRangePush("Prepare matrix calculation"); #endif - int s_nsph = sconf->number_of_spheres; - int nsph = gconf->number_of_spheres; - // Sanity check on number of sphere consistency, should always be verified - if (s_nsph == nsph) { - // Shortcuts to variables stored in configuration objects - ScatteringAngles *p_scattering_angles = new ScatteringAngles(gconf); - double wp = sconf->wp; - // Open empty virtual ascii file for output - VirtualAsciiFile *p_output = new VirtualAsciiFile(); - char virtual_line[256]; - InclusionIterationData *cid = new InclusionIterationData(gconf, sconf, mpidata, device_count); - const np_int ndi = cid->c1->nsph * cid->c1->nlim; - const np_int ndit = 2 * ndi; - logger->log("INFO: Size of matrices to invert: " + to_string((int64_t)cid->c1->ndm) + " x " + to_string((int64_t)cid->c1->ndm) +".\n"); - time_logger->log("INFO: Size of matrices to invert: " + to_string((int64_t)cid->c1->ndm) + " x " + to_string((int64_t)cid->c1->ndm) +".\n"); - - //========================== - // Write a block of info to the ascii output file - //========================== - sprintf(virtual_line, " READ(IR,*)NSPH,LI,LE,MXNDM,INPOL,NPNT,NPNTTS,IAVM,ISAM\n"); - p_output->append_line(virtual_line); -#ifdef USE_ILP64 - sprintf(virtual_line, " %5d%5d%5d%5ld%5d%5d%5d%5d%5d\n", - nsph, cid->c1->li, cid->c1->le, gconf->mxndm, gconf->in_pol, gconf->npnt, - gconf->npntts, gconf->iavm, gconf->iavm - ); -#else - sprintf(virtual_line, " %5d%5d%5d%5d%5d%5d%5d%5d%5d\n", - nsph, cid->c1->li, cid->c1->le, gconf->mxndm, gconf->in_pol, gconf->npnt, - gconf->npntts, gconf->iavm, gconf->iavm - ); -#endif // USE_ILP64 - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(IR,*)RXX(I),RYY(I),RZZ(I)\n"); - p_output->append_line(virtual_line); - for (int ri = 0; ri < nsph; ri++) { - sprintf(virtual_line, "%17.8lE%17.8lE%17.8lE\n", - gconf->get_sph_x(ri), gconf->get_sph_y(ri), gconf->get_sph_z(ri) - ); - p_output->append_line(virtual_line); + double xi = sconf->get_scale(jxi488 - 1); + double exdc = sconf->exdc; + double exri = sqrt(exdc); + int idfc = (int)sconf->idfc; + double vkarg = 0.0; + if (idfc >= 0) { + cid->vk = xi * cid->wn; + vkarg = cid->vk; + output->vec_vk[jindex - 1] = cid->vk; + output->vec_xi[jindex - 1] = xi; + // goes to 120 + } else { // label 119 + vkarg = xi * cid->vk; + cid->sqsfi = 1.0 / (xi * xi); + output->vec_vk[jindex - 1] = cid->vk; + output->vec_xi[jindex - 1] = xi; + } + // label 120 + double sze = vkarg * cid->extr; + last_configuration = 0; + for (int i133 = 1; i133 <= cid->c1->nsph; i133++) { + int iogi = cid->c1->iog[i133 - 1]; + if (iogi != i133) { + for (int l123 = 1; l123 <= cid->c1->li; l123++) { + cid->c1->rmi[l123 - 1][i133 - 1] = cid->c1->rmi[l123 - 1][iogi - 1]; + cid->c1->rei[l123 - 1][i133 - 1] = cid->c1->rei[l123 - 1][iogi - 1]; + } // l123 loop + } else { // label 125 + last_configuration++; + int nsh = cid->c1->nshl[last_configuration - 1]; + int ici = (nsh + 1) / 2; + if (i133 == 1) ici++; + if (idfc == 0) { + for (int ic = 0; ic < ici; ic++) + cid->c1->dc0[ic] = sconf->get_dielectric_constant(ic, i133 - 1, jxi488 - 1); + // goes to 129 + } else { // label 127 + if (jxi488 == 1) { + for (int ic = 0; ic < ici; ic++) { + cid->c1->dc0[ic] = sconf->get_dielectric_constant(ic, i133 - 1, 0); + } + } } - sprintf(virtual_line, " READ(IR,*)TH,THSTP,THLST,THS,THSSTP,THSLST\n"); - p_output->append_line(virtual_line); - sprintf( - virtual_line, " %10.3lE%10.3lE%10.3lE%10.3lE%10.3lE%10.3lE\n", - p_scattering_angles->th, p_scattering_angles->thstp, - p_scattering_angles->thlst, p_scattering_angles->ths, - p_scattering_angles->thsstp, p_scattering_angles->thslst - ); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(IR,*)PH,PHSTP,PHLST,PHS,PHSSTP,PHSLST\n"); - p_output->append_line(virtual_line); - sprintf( - virtual_line, " %10.3lE%10.3lE%10.3lE%10.3lE%10.3lE%10.3lE\n", - p_scattering_angles->ph, p_scattering_angles->phstp, - p_scattering_angles->phlst, p_scattering_angles->phs, - p_scattering_angles->phsstp, p_scattering_angles->phslst - ); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(IR,*)JWTM\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " %5d\n", gconf->jwtm); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)NSPHT\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)(IOG(I),I=1,NSPH)\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)EXDC,WP,XIP,IDFC,NXI\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)(XIV(I),I=1,NXI)\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)NSHL(I),ROS(I)\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " READ(ITIN)(RCF(I,NS),NS=1,NSH)\n"); - p_output->append_line(virtual_line); - sprintf(virtual_line, " \n"); - p_output->append_line(virtual_line); - instr(sconf, cid->c1); - thdps(cid->c1->lm, cid->zpv); - double exdc = sconf->exdc; - double exri = sqrt(exdc); - sprintf(virtual_line, " REFR. INDEX OF EXTERNAL MEDIUM=%15.7lE\n", exri); - p_output->append_line(virtual_line); - - // Create an empty bynary file - VirtualBinaryFile *vtppoanp = new VirtualBinaryFile(); - string tppoan_name = output_path + "/c_TPPOAN"; -#ifdef USE_MAGMA - logger->log("INFO: using MAGMA calls.\n", LOG_INFO); -#elif defined USE_LAPACK - logger->log("INFO: using LAPACK calls.\n", LOG_INFO); -#else - logger->log("INFO: using fall-back lucin() calls.\n", LOG_INFO); -#endif - int iavm = gconf->iavm; - int isam = gconf->isam; - int inpol = gconf->in_pol; - int nxi = sconf->number_of_scales; - int nth = p_scattering_angles->nth; - int nths = p_scattering_angles->nths; - int nph = p_scattering_angles->nph; - int nphs = p_scattering_angles->nphs; - - //======================== - // write a block of info to virtual binary file - //======================== - vtppoanp->append_line(VirtualBinaryLine(iavm)); - vtppoanp->append_line(VirtualBinaryLine(isam)); - vtppoanp->append_line(VirtualBinaryLine(inpol)); - vtppoanp->append_line(VirtualBinaryLine(nxi)); - vtppoanp->append_line(VirtualBinaryLine(nth)); - vtppoanp->append_line(VirtualBinaryLine(nph)); - vtppoanp->append_line(VirtualBinaryLine(nths)); - vtppoanp->append_line(VirtualBinaryLine(nphs)); - if (sconf->idfc < 0) { - cid->vk = cid->xip * cid->wn; - sprintf(virtual_line, " VK=%15.7lE, XI IS SCALE FACTOR FOR LENGTHS\n", cid->vk); - p_output->append_line(virtual_line); - sprintf(virtual_line, " \n"); - p_output->append_line(virtual_line); + // label 129 + if (i133 == 1) { + ent = cid->c1->dc0[ici - 1]; + enti = imag(ent); + entn = csqrt(ent); + // goes to 131 + } else { // label 130 + if (nsh % 2 == 0) cid->c1->dc0[ici] = ent; } - - // do the first iteration on jxi488 separately, since it seems to be different from the others - int jxi488 = 1; - int initialmaxrefiters = cid->maxrefiters; - - chrono::time_point<chrono::high_resolution_clock> start_iter_1 = chrono::high_resolution_clock::now(); + indme(i133, npnt, npntts, vkarg, ent, enti, entn, jer, lcalc, cid->arg, cid->c1); + if (jer != 0) { + output->vec_ier[jindex - 1] = 1; + output->vec_jxi[jindex - 1] = -jxi488; + message = "ERROR: indme failed with error code " + to_string(jer) + ".\n"; + logger->log(message, LOG_ERRO); + delete logger; + return jer; + //break; + } + } + } // i133 loop + ospv(cid->c1, vkarg, sze, exri, entn, enti, jer, lcalc, cid->arg); + if (jer != 0) { + output->vec_ier[jindex - 1] = 2; + output->vec_jxi[jindex - 1] = -jxi488; + message = "ERROR: ospv failed with error code " + to_string(jer) + ".\n"; + logger->log(message, LOG_ERRO); + delete logger; + return jer; + // break; + } // i133 loop #ifdef USE_NVTX - nvtxRangePush("First iteration"); + nvtxRangePop(); #endif - // use these pragmas, which should have no effect on parallelism, just to push OMP nested levels at the same level also in the first wavelength iteration - int jer = 0; -#pragma omp parallel - { -#pragma omp single - { - jer = inclusion_jxi488_cycle(jxi488, sconf, gconf, p_scattering_angles, cid, p_output, output_path, vtppoanp); - } - } + interval_start = chrono::high_resolution_clock::now(); #ifdef USE_NVTX - nvtxRangePop(); + nvtxRangePush("Calculate inverted matrix"); #endif - chrono::time_point<chrono::high_resolution_clock> end_iter_1 = chrono::high_resolution_clock::now(); - elapsed = start_iter_1 - t_start; - string message = "INFO: Calculation setup took " + to_string(elapsed.count()) + "s.\n"; - logger->log(message); - time_logger->log(message); - elapsed = end_iter_1 - start_iter_1; - message = "INFO: First iteration took " + to_string(elapsed.count()) + "s.\n"; - logger->log(message); - time_logger->log(message); - /* for the next iterations, just always do maxiter iterations, assuming the accuracy is good enough */ - cid->refinemode = 0; - /* add an extra iteration for margin, if this does not exceed initialmaxrefiters */ - // if (cid->maxrefiters < initialmaxrefiters) cid->maxrefiters++; - if (jer != 0) { - // First loop failed. Halt the calculation. - fclose(timing_file); - delete time_logger; - delete p_output; - delete p_scattering_angles; - delete cid; - delete logger; - delete sconf; - delete gconf; - return; - } - - //================================================== - // do the first outputs here, so that I open here the new files, afterwards I only append - //================================================== - p_output->write_to_disk(output_path + "/c_OINCLU"); - delete p_output; - vtppoanp->write_to_disk(output_path + "/c_TPPOAN"); - delete vtppoanp; - - // here go the calls that send data to be duplicated on other MPI processes from process 0 to others, using MPI broadcasts, but only if MPI is actually used -#ifdef MPI_VERSION - if (mpidata->mpirunning) { - gconf->mpibcast(mpidata); - sconf->mpibcast(mpidata); - cid->mpibcast(mpidata); - p_scattering_angles->mpibcast(mpidata); - } -#endif - // Create this variable and initialise it with a default here, so that it is defined anyway, with or without OpenMP support enabled - int ompnumthreads = 1; - // this is for MPI process 0 (or even if we are not using MPI at all) - int myjxi488startoffset = 0; - int myMPIstride = ompnumthreads; - int myMPIblock = ompnumthreads; - // Define here shared arrays of virtual ascii and binary files, so that thread 0 will be able to access them all later - VirtualAsciiFile **p_outarray = NULL; - VirtualBinaryFile **vtppoanarray = NULL; - -#ifdef USE_NVTX - nvtxRangePush("Parallel loop"); -#endif - - //=========================================== - // open the OpenMP parallel context, so each thread can initialise its stuff - //=========================================== -#pragma omp parallel - { - // Create and initialise this variable here, so that if OpenMP is enabled it is local to the thread, and if OpenMP is not enabled it has a well-defiled value anyway - int myompthread = 0; - -#ifdef _OPENMP - // If OpenMP is enabled, give actual values to myompthread and ompnumthreads, and open thread-local output files - myompthread = omp_get_thread_num(); - if (myompthread == 0) ompnumthreads = omp_get_num_threads(); +#ifdef DEBUG_AM + /* now, before cms, output am to p_outam0 */ + VirtualAsciiFile *outam0 = new VirtualAsciiFile(); + string outam0_name = output_path + "/c_AM0_JXI" + to_string(jxi488) + ".txt"; + sprintf(virtual_line, " AM matrix before CMS\n"); + outam0->append_line(virtual_line); + sprintf(virtual_line, " I1+1 I2+1 Real Imag\n"); + outam0->append_line(virtual_line); + write_dcomplex_matrix(outam0, cid->am, cid->c1->ndm, cid->c1->ndm); + outam0->write_to_disk(outam0_name); + delete outam0; #endif - - if (myompthread == 0) { - // Initialise some shared variables only on thread 0 - p_outarray = new VirtualAsciiFile*[ompnumthreads]; - vtppoanarray = new VirtualBinaryFile*[ompnumthreads]; - myMPIblock = ompnumthreads; - myMPIstride = myMPIblock; - } - -#ifdef MPI_VERSION - if (myompthread == 0) { - if (mpidata->mpirunning) { - // only go through this if MPI has been actually used - for (int rr=1; rr<mpidata->nprocs; rr++) { - // individually send their respective starting points to other MPI processes: they start immediately after the frequencies computed by previous processes so far - int remotejxi488startoffset = myMPIstride; - MPI_Send(&remotejxi488startoffset, 1, MPI_INT, rr, 3, MPI_COMM_WORLD); - int remoteMPIblock; - MPI_Recv(&remoteMPIblock, 1, MPI_INT, rr, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - // update myMPIstride to include the ones due to MPI process rr - myMPIstride += remoteMPIblock; - } - // now I know the total myMPIstride, I can send it to all processes - MPI_Bcast(&myMPIstride, 1, MPI_INT, 0, MPI_COMM_WORLD); - } - } + incms(cid->am, enti, cid->c1); +#ifdef DEBUG_AM + VirtualAsciiFile *outam1 = new VirtualAsciiFile(); + string outam1_name = output_path + "/c_AM1_JXI" + to_string(jxi488) + ".txt"; + sprintf(virtual_line, " AM matrix after CMS before LUCIN\n"); + outam1->append_line(virtual_line); + sprintf(virtual_line, " I1+1 I2+1 Real Imag\n"); + outam1->append_line(virtual_line); + write_dcomplex_matrix(outam1, cid->am, cid->c1->ndm, cid->c1->ndm, " %5d %5d (%17.8lE,%17.8lE)\n", 1); + outam1->write_to_disk(outam1_name); + delete outam1; #endif - // add an omp barrier to make sure that the global variables defined by thread 0 are known to all threads below this -#pragma omp barrier - - // To test parallelism, I will now start feeding this function with "clean" copies of the parameters, so that they will not be changed by previous iterations, and each one will behave as the first one. Define all (empty) variables here, so they have the correct scope, then they get different definitions depending on thread number - InclusionIterationData *cid_2 = NULL; - VirtualAsciiFile *p_output_2 = NULL; - VirtualBinaryFile *vtppoanp_2 = NULL; - // for threads other than the 0, create distinct copies of all relevant data, while for thread 0 just define new references / pointers to the original ones - if (myompthread == 0) { - cid_2 = cid; - } else { - // this is not thread 0, so do create fresh copies of all local variables - cid_2 = new InclusionIterationData(*cid); - } - // make sure all threads align here: I don't want the following loop to accidentally start for thread 0, possibly modifying some variables before they are copied by all other threads - if (myompthread==0) { - logger->log("Syncing OpenMP threads and starting the loop on wavelengths\n"); - } -#pragma omp barrier - // ok, now I can actually start the parallel calculations - for (int ixi488=2; ixi488<=cid_2->number_of_scales; ixi488 +=myMPIstride) { - // the parallel loop over MPI processes covers a different set of indices for each thread -#pragma omp barrier - int myjxi488 = ixi488+myompthread; - // each thread opens new virtual files and stores their pointers in the shared array - p_output_2 = new VirtualAsciiFile(); - vtppoanp_2 = new VirtualBinaryFile(); - // each thread puts a copy of the pointers to its virtual files in the shared arrays - p_outarray[myompthread] = p_output_2; - vtppoanarray[myompthread] = vtppoanp_2; -#pragma omp barrier - - // each MPI process handles a number of contiguous scales corresponding to its number of OMP threads at this omp level of parallelism - if (myjxi488 <= cid_2->number_of_scales) { - int jer = inclusion_jxi488_cycle(myjxi488, sconf, gconf, p_scattering_angles, cid_2, p_output_2, output_path, vtppoanp_2); - } -#pragma omp barrier - #ifdef USE_NVTX - nvtxRangePush("Output concatenation"); -#endif -#pragma omp barrier - // threads different from 0 append their virtual files to the one of thread 0, and delete them - if (myompthread == 0) { - for (int ti=1; ti<ompnumthreads; ti++) { - p_outarray[0]->append(*(p_outarray[ti])); - delete p_outarray[ti]; - vtppoanarray[0]->append(*(vtppoanarray[ti])); - delete vtppoanarray[ti]; - } - } -#pragma omp barrier - //============================================== - // Collect all virtual files on thread 0 of MPI process 0, and append them to disk - //============================================== - if (myompthread == 0) { - // thread 0 writes its virtual files, now including contributions from all threads, to disk, and deletes them - p_outarray[0]->append_to_disk(output_path + "/c_OINCLU"); - delete p_outarray[0]; - vtppoanarray[0]->append_to_disk(output_path + "/c_TPPOAN"); - delete vtppoanarray[0]; - -#ifdef MPI_VERSION - if (mpidata->mpirunning) { - // only go through this if MPI has been actually used - for (int rr=1; rr<mpidata->nprocs; rr++) { - // get the data from process rr, creating a new virtual ascii file - VirtualAsciiFile *p_output = new VirtualAsciiFile(mpidata, rr); - // append to disk and delete virtual ascii file - p_output->append_to_disk(output_path + "/c_OINCLU"); - delete p_output; - // get the data from process rr, creating a new virtual binary file - VirtualBinaryFile *vtppoanp = new VirtualBinaryFile(mpidata, rr); - // append to disk and delete virtual binary file - vtppoanp->append_to_disk(output_path + "/c_TPPOAN"); - delete vtppoanp; - int test = MPI_Barrier(MPI_COMM_WORLD); - } - } + nvtxRangePop(); #endif - } - // end block writing to disk + interval_end = chrono::high_resolution_clock::now(); + elapsed = interval_end - interval_start; + message = "INFO: matrix calculation for scale " + to_string(jxi488) + " took " + to_string(elapsed.count()) + "s.\n"; + logger->log(message); + interval_start = chrono::high_resolution_clock::now(); #ifdef USE_NVTX - nvtxRangePop(); + nvtxRangePush("Invert the matrix"); #endif -#pragma omp barrier - - } // close strided loop running on MPI processes, ixi488 loop - // delete the shared arrays I used to make available to thread 0 the virtual files of other threads -#pragma omp barrier - if (myompthread == 0) { - delete[] p_outarray; - delete[] vtppoanarray; - } - { - string message = "INFO: Closing thread-local output files of thread " + to_string(myompthread) + " and syncing threads.\n"; - logger->log(message); - } + // we the accuracygoal in, get the actual accuracy back out + double actualaccuracy = cid->accuracygoal; + invert_matrix(cid->am, cid->c1->ndm, jer, cid->maxrefiters, actualaccuracy, cid->refinemode, output_path, jxi488, mxndm, cid->proc_device); + // in principle, we should check whether the returned actualaccuracy is indeed lower than the accuracygoal, and do something about it if not +#ifdef USE_REFINEMENT + if (cid->refinemode==2) { + message = "INFO: calibration obtained accuracy " + to_string(actualaccuracy) + " (" + to_string(cid->accuracygoal) + " requested) in " + to_string(cid->maxrefiters) + " refinement iterations\n"; + logger->log(message); + if (actualaccuracy > 1e-2) { + printf("Accuracy worse than 0.01, stopping"); + exit(1); + } + } +#endif // USE_REFINEMENT #ifdef USE_NVTX - nvtxRangePop(); + nvtxRangePop(); #endif - delete cid_2; - } - delete p_scattering_angles; - } - - else { // Sphere number inconsistency error. - throw UnrecognizedConfigurationException( - "Inconsistent geometry and scatterer configurations." - ); - } - - delete sconf; - delete gconf; -#ifdef USE_MAGMA - logger->log("INFO: Process " + to_string(mpidata->rank) + " finalizes MAGMA.\n"); - magma_finalize(); + interval_end = chrono::high_resolution_clock::now(); + elapsed = interval_end - interval_start; + message = "INFO: matrix inversion for scale " + to_string(jxi488) + " took " + to_string(elapsed.count()) + "s.\n"; + logger->log(message); + if (jer != 0) { + message = "ERROR: matrix inversion ended with error code " + to_string(jer) + ".\n"; + logger->err(message); + delete logger; + return jer; + // break; // jxi488 loop: goes to memory clean + } + interval_start = chrono::high_resolution_clock::now(); +#ifdef USE_NVTX + nvtxRangePush("Average calculation"); #endif - chrono::time_point<chrono::high_resolution_clock> t_end = chrono::high_resolution_clock::now(); - elapsed = t_end - t_start; - string message = "INFO: Calculation lasted " + to_string(elapsed.count()) + "s.\n"; - logger->log(message); - logger->log("Finished: output written to " + output_path + "/c_OINCLU\n"); - time_logger->log(message); - fclose(timing_file); - delete time_logger; - } // end instructions block of MPI process 0 - - //=============================== - // instruction block for MPI processes different from 0 - //=============================== -#ifdef MPI_VERSION - else { - // here go the code for MPI processes other than 0 - // copy gconf, sconf, cid and p_scattering_angles from MPI process 0 - GeometryConfiguration *gconf = new GeometryConfiguration(mpidata); - ScattererConfiguration *sconf = new ScattererConfiguration(mpidata); - InclusionIterationData *cid = new InclusionIterationData(mpidata, device_count); - ScatteringAngles *p_scattering_angles = new ScatteringAngles(mpidata); - - // Create this variable and initialise it with a default here, so that it is defined anyway, with or without OpenMP support enabled - int ompnumthreads = 1; - VirtualAsciiFile **p_outarray = NULL; - VirtualBinaryFile **vtppoanarray = NULL; - int myjxi488startoffset; - int myMPIstride = ompnumthreads; - int myMPIblock = ompnumthreads; - -#pragma omp parallel - { - // Create and initialise this variable here, so that if OpenMP is enabled it is local to the thread, and if OpenMP is not enabled it has a well-defiled value anyway - int myompthread = 0; -#ifdef _OPENMP - // If OpenMP is enabled, give actual values to myompthread and ompnumthreads, and open thread-local output files - myompthread = omp_get_thread_num(); - if (myompthread == 0) ompnumthreads = omp_get_num_threads(); -#endif - if (myompthread == 0) { - // receive the start parameter from MPI process 0 - MPI_Recv(&myjxi488startoffset, 1, MPI_INT, 0, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - // send my number of omp threads to process 0 - MPI_Send(&ompnumthreads, 1, MPI_INT, 0, 3, MPI_COMM_WORLD); - // receive myMPIstride sent by MPI process 0 to all processes - MPI_Bcast(&myMPIstride, 1, MPI_INT, 0, MPI_COMM_WORLD); - // allocate virtual files for each thread - p_outarray = new VirtualAsciiFile*[ompnumthreads]; - vtppoanarray = new VirtualBinaryFile*[ompnumthreads]; - } -#pragma omp barrier - // To test parallelism, I will now start feeding this function with "clean" copies of the parameters, so that they will not be changed by previous iterations, and each one will behave as the first one. Define all (empty) variables here, so they have the correct scope, then they get different definitions depending on thread number - InclusionIterationData *cid_2 = NULL; - VirtualAsciiFile *p_output_2 = NULL; - VirtualBinaryFile *vtppoanp_2 = NULL; - // PLACEHOLDER - // for threads other than the 0, create distinct copies of all relevant data, while for thread 0 just define new references / pointers to the original ones - if (myompthread == 0) { - cid_2 = cid; - } else { - // this is not thread 0, so do create fresh copies of all local variables - cid_2 = new InclusionIterationData(*cid); - } - // make sure all threads align here: I don't want the following loop to accidentally start for thread 0, possibly modifying some variables before they are copied by all other threads -#pragma omp barrier - // ok, now I can actually start the parallel calculations - for (int ixi488=2; ixi488<=cid_2->number_of_scales; ixi488 +=myMPIstride) { - // the parallel loop over MPI processes covers a different set of indices for each thread -#pragma omp barrier - int myjxi488 = ixi488 + myjxi488startoffset + myompthread; - // each thread opens new virtual files and stores their pointers in the shared array - p_output_2 = new VirtualAsciiFile(); - vtppoanp_2 = new VirtualBinaryFile(); - // each thread puts a copy of the pointers to its virtual files in the shared arrays - p_outarray[myompthread] = p_output_2; - vtppoanarray[myompthread] = vtppoanp_2; -#pragma omp barrier - if (myompthread==0) logger->log("Syncing OpenMP threads and starting the loop on wavelengths\n"); - // ok, now I can actually start the parallel calculations - // each MPI process handles a number of contiguous scales corresponding to its number of OMP threads at this omp level of parallelism - if (myjxi488 <= cid_2->number_of_scales) { - int jer = inclusion_jxi488_cycle(myjxi488, sconf, gconf, p_scattering_angles, cid_2, p_output_2, output_path, vtppoanp_2); - } // close the OMP parallel for loop - -#pragma omp barrier - // threads different from 0 append their virtual files to the one of thread 0, and delete them - if (myompthread == 0) { - for (int ti=1; ti<ompnumthreads; ti++) { - p_outarray[0]->append(*(p_outarray[ti])); - delete p_outarray[ti]; - vtppoanarray[0]->append(*(vtppoanarray[ti])); - delete vtppoanarray[ti]; - } - // thread 0 sends the collected virtualfiles to thread 0 of MPI process 0, then deletes them - for (int rr=1; rr<mpidata->nprocs; rr++) { - if (rr == mpidata->rank) { - p_outarray[0]->mpisend(mpidata); - delete p_outarray[0]; - vtppoanarray[0]->mpisend(mpidata); - delete vtppoanarray[0]; - } - int test = MPI_Barrier(MPI_COMM_WORLD); - } - } - } // close strided loop running on MPI processes - - // Clean memory -#pragma omp barrier - if (myompthread == 0) { - delete[] p_outarray; - delete[] vtppoanarray; - } - delete cid_2; - - } // close pragma omp parallel - delete p_scattering_angles; - delete sconf; - delete gconf; -#endif -#ifdef USE_MAGMA - logger->log("INFO: Process " + to_string(mpidata->rank) + " finalizes MAGMA.\n"); - magma_finalize(); -#endif - delete logger; -#ifdef MPI_VERSION - } -#endif -} - -int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryConfiguration *gconf, ScatteringAngles *sa, InclusionIterationData *cid, VirtualAsciiFile *output, const string& output_path, VirtualBinaryFile *vtppoanp) { - int nxi = sconf->number_of_scales; - char virtual_line[256]; - string message = "INFO: running scale iteration " + to_string(jxi488) + " of " + to_string(nxi) + ".\n"; - Logger *logger = new Logger(LOG_DEBG); - logger->log(message); - chrono::duration<double> elapsed; - chrono::time_point<chrono::high_resolution_clock> interval_start, interval_end; - int jer = 0; - int lcalc = 0; - int jaw = 1; - int li = cid->c1->li; - int le = cid->c1->le; - int lm = cid->c1->lm; - int nsph = cid->c1->nsph; - np_int mxndm = gconf->mxndm; - int iavm = gconf->iavm; - int inpol = gconf->in_pol; - int npnt = cid->c1->npnt; - int npntts = cid->c1->npntts; - int isam = gconf->iavm; - int jwtm = gconf->jwtm; - np_int ndit = cid->c1->ndit; - int isq, ibf; - int last_configuration; - dcomplex ent, entn; - double enti; - -#ifdef USE_NVTX - nvtxRangePush("Prepare matrix calculation"); + exma(cid->am, cid->c1); +#ifdef DEBUG_AM + VirtualAsciiFile *outam3 = new VirtualAsciiFile(); + string outam3_name = output_path + "/c_AM3_JXI" + to_string(jxi488) + ".txt"; + sprintf(virtual_line, " AM matrix after EXMA\n"); + outam3->append_line(virtual_line); + sprintf(virtual_line, " I1+1 I2+1 Real Imag\n"); + outam3->append_line(virtual_line); + write_dcomplex_matrix(outam3, cid->am, cid->c1->ndm, cid->c1->ndm); + outam3->write_to_disk(outam3_name); + delete outam3; #endif - sprintf(virtual_line, "========== JXI =%3d ====================\n", jxi488); - output->append_line(virtual_line); - double xi = sconf->get_scale(jxi488 - 1); - double exdc = sconf->exdc; - double exri = sqrt(exdc); - int idfc = (int)sconf->idfc; - double vkarg = 0.0; if (idfc >= 0) { - cid->vk = xi * cid->wn; - vkarg = cid->vk; - sprintf(virtual_line, " VK=%15.7lE, XI=%15.7lE\n", cid->vk, xi); - output->append_line(virtual_line); - // goes to 120 - } else { // label 119 - vkarg = xi * cid->vk; - cid->sqsfi = 1.0 / (xi * xi); - sprintf(virtual_line, " XI=%15.7lE\n", xi); - output->append_line(virtual_line); + if (jxi488 == jwtm) { + int nlemt = 2 * cid->c1->nlem; + string ttms_name = output_path + "/c_TTMS.hd5"; + TransitionMatrix::write_binary(ttms_name, nlemt, lm, cid->vk, exri, cid->c1->am0m, "HDF5"); + ttms_name = output_path + "/c_TTMS"; + TransitionMatrix::write_binary(ttms_name, nlemt, lm, cid->vk, exri, cid->c1->am0m); + } } - // label 120 - double sze = vkarg * cid->extr; + // label 156: continue from here last_configuration = 0; - for (int i133 = 1; i133 <= cid->c1->nsph; i133++) { - int iogi = cid->c1->iog[i133 - 1]; - if (iogi != i133) { - for (int l123 = 1; l123 <= cid->c1->li; l123++) { - cid->c1->rmi[l123 - 1][i133 - 1] = cid->c1->rmi[l123 - 1][iogi - 1]; - cid->c1->rei[l123 - 1][i133 - 1] = cid->c1->rei[l123 - 1][iogi - 1]; - } // l123 loop - } else { // label 125 + for (int i168 = 1; i168 <= nsph; i168++) { + if (cid->c1->iog[i168 - 1] >= i168) { + int i = i168 - 1; last_configuration++; - int nsh = cid->c1->nshl[last_configuration - 1]; - int ici = (nsh + 1) / 2; - if (i133 == 1) ici++; - if (idfc == 0) { - for (int ic = 0; ic < ici; ic++) - cid->c1->dc0[ic] = sconf->get_dielectric_constant(ic, i133 - 1, jxi488 - 1); - // goes to 129 - } else { // label 127 - if (jxi488 == 1) { - for (int ic = 0; ic < ici; ic++) { - cid->c1->dc0[ic] = sconf->get_dielectric_constant(ic, i133 - 1, 0); - } - } - } - // label 129 - if (i133 == 1) { - ent = cid->c1->dc0[ici - 1]; - enti = imag(ent); - entn = csqrt(ent); - // goes to 131 - } else { // label 130 - if (nsh % 2 == 0) cid->c1->dc0[ici] = ent; - } - indme(i133, npnt, npntts, vkarg, ent, enti, entn, jer, lcalc, cid->arg, cid->c1); - if (jer != 0) { - sprintf(virtual_line, " STOP IN INDME\n"); - output->append_line(virtual_line); - message = "ERROR: indme failed with error code " + to_string(jer) + ".\n"; - logger->log(message, LOG_ERRO); - delete logger; - return jer; - //break; + oindex = (jindex - 1) * (num_configs + 1) + last_configuration - 1; + if (cid->c1->nshl[i168 - 1] != 1) { + output->vec_sphere_ref_indices[oindex] = cc0; + output->vec_sphere_sizes[oindex] = cid->c1->vsz[i]; + } else { + output->vec_sphere_ref_indices[oindex] = cid->c1->vkt[i]; + output->vec_sphere_sizes[oindex] = cid->c1->vsz[i]; } - } - } // i133 loop - ospv(cid->c1, vkarg, sze, exri, entn, enti, jer, lcalc, cid->arg); - if (jer != 0) { - sprintf(virtual_line, " STOP IN OSPV\n"); - output->append_line(virtual_line); - message = "ERROR: ospv failed with error code " + to_string(jer) + ".\n"; - logger->log(message, LOG_ERRO); - delete logger; - return jer; - // break; - } // i133 loop + } + } // i168 loop + oindex = (jindex - 1) * (num_configs + 1) + num_configs; + output->vec_sphere_sizes[oindex] = sze; + output->vec_sphere_ref_indices[oindex] = entn; + // label 160 + double cs0 = 0.25 * cid->vk * cid->vk * cid->vk / acos(0.0); + double csch = 2.0 * cid->vk * cid->sqsfi / cid->c1->gcs; + double sqk = cid->vk * cid->vk * exdc; + vtppoanp->append_line(VirtualBinaryLine(cid->vk)); + pcrsm0(cid->vk, exri, inpol, cid->c1); + apcra(cid->zpv, cid->c1->le, cid->c1->am0m, inpol, sqk, cid->gapm, cid->gappm); #ifdef USE_NVTX nvtxRangePop(); #endif + interval_end = chrono::high_resolution_clock::now(); + elapsed = interval_end - interval_start; + message = "INFO: average calculation for scale " + to_string(jxi488) + " took " + to_string(elapsed.count()) + "s.\n"; + logger->log(message); interval_start = chrono::high_resolution_clock::now(); #ifdef USE_NVTX - nvtxRangePush("Calculate inverted matrix"); -#endif -#ifdef DEBUG_AM - /* now, before cms, output am to p_outam0 */ - VirtualAsciiFile *outam0 = new VirtualAsciiFile(); - string outam0_name = output_path + "/c_AM0_JXI" + to_string(jxi488) + ".txt"; - sprintf(virtual_line, " AM matrix before CMS\n"); - outam0->append_line(virtual_line); - sprintf(virtual_line, " I1+1 I2+1 Real Imag\n"); - outam0->append_line(virtual_line); - write_dcomplex_matrix(outam0, cid->am, cid->c1->ndm, cid->c1->ndm); - outam0->write_to_disk(outam0_name); - delete outam0; -#endif - incms(cid->am, enti, cid->c1); -#ifdef DEBUG_AM - VirtualAsciiFile *outam1 = new VirtualAsciiFile(); - string outam1_name = output_path + "/c_AM1_JXI" + to_string(jxi488) + ".txt"; - sprintf(virtual_line, " AM matrix after CMS before LUCIN\n"); - outam1->append_line(virtual_line); - sprintf(virtual_line, " I1+1 I2+1 Real Imag\n"); - outam1->append_line(virtual_line); - write_dcomplex_matrix(outam1, cid->am, cid->c1->ndm, cid->c1->ndm, " %5d %5d (%17.8lE,%17.8lE)\n", 1); - outam1->write_to_disk(outam1_name); - delete outam1; -#endif -#ifdef USE_NVTX - nvtxRangePop(); -#endif - interval_end = chrono::high_resolution_clock::now(); - elapsed = interval_end - interval_start; - message = "INFO: matrix calculation for scale " + to_string(jxi488) + " took " + to_string(elapsed.count()) + "s.\n"; - logger->log(message); - interval_start = chrono::high_resolution_clock::now(); -#ifdef USE_NVTX - nvtxRangePush("Invert the matrix"); -#endif - // we the accuracygoal in, get the actual accuracy back out - double actualaccuracy = cid->accuracygoal; - invert_matrix(cid->am, cid->c1->ndm, jer, cid->maxrefiters, actualaccuracy, cid->refinemode, output_path, jxi488, mxndm, cid->proc_device); - // in principle, we should check whether the returned actualaccuracy is indeed lower than the accuracygoal, and do something about it if not -#ifdef USE_REFINEMENT - if (cid->refinemode==2) { - message = "INFO: calibration obtained accuracy " + to_string(actualaccuracy) + " (" + to_string(cid->accuracygoal) + " requested) in " + to_string(cid->maxrefiters) + " refinement iterations\n"; - logger->log(message); - if (actualaccuracy > 1e-2) { - printf("Accuracy worse than 0.01, stopping"); - exit(1); - } - } -#endif // USE_REFINEMENT -#ifdef USE_NVTX - nvtxRangePop(); -#endif - interval_end = chrono::high_resolution_clock::now(); - elapsed = interval_end - interval_start; - message = "INFO: matrix inversion for scale " + to_string(jxi488) + " took " + to_string(elapsed.count()) + "s.\n"; - logger->log(message); - if (jer != 0) { - message = "ERROR: matrix inversion ended with error code " + to_string(jer) + ".\n"; - logger->err(message); - delete logger; - return jer; - // break; // jxi488 loop: goes to memory clean - } - interval_start = chrono::high_resolution_clock::now(); -#ifdef USE_NVTX - nvtxRangePush("Average calculation"); -#endif - exma(cid->am, cid->c1); -#ifdef DEBUG_AM - VirtualAsciiFile *outam3 = new VirtualAsciiFile(); - string outam3_name = output_path + "/c_AM3_JXI" + to_string(jxi488) + ".txt"; - sprintf(virtual_line, " AM matrix after EXMA\n"); - outam3->append_line(virtual_line); - sprintf(virtual_line, " I1+1 I2+1 Real Imag\n"); - outam3->append_line(virtual_line); - write_dcomplex_matrix(outam3, cid->am, cid->c1->ndm, cid->c1->ndm); - outam3->write_to_disk(outam3_name); - delete outam3; -#endif - if (idfc >= 0) { - if (jxi488 == jwtm) { - int nlemt = 2 * cid->c1->nlem; - string ttms_name = output_path + "/c_TTMS.hd5"; - TransitionMatrix::write_binary(ttms_name, nlemt, lm, cid->vk, exri, cid->c1->am0m, "HDF5"); - ttms_name = output_path + "/c_TTMS"; - TransitionMatrix::write_binary(ttms_name, nlemt, lm, cid->vk, exri, cid->c1->am0m); - } - } - // label 156: continue from here - for (int i168 = 1; i168 <= nsph; i168++) { - if (cid->c1->iog[i168 - 1] >= i168) { - if (cid->c1->nshl[i168 - 1] != 1) { - sprintf(virtual_line, " SPHERE N.%2d: SIZE=%15.7lE\n", i168, cid->c1->vsz[i168 - 1]); - output->append_line(virtual_line); - } else { - sprintf(virtual_line, " SPHERE N.%2d: SIZE=%15.7lE, REFRACTIVE INDEX=%15.7lE%15.7lE\n", i168, cid->c1->vsz[i168 - 1], real(cid->c1->vkt[i168 - 1]), imag(cid->c1->vkt[i168 - 1])); - output->append_line(virtual_line); - } - } - } // i168 loop - sprintf(virtual_line, " EXT. SPHERE: SIZE=%15.7lE, REFRACTIVE INDEX=%15.7lE%15.7lE\n", sze, real(entn), imag(entn)); - output->append_line(virtual_line); - // label 160 - double cs0 = 0.25 * cid->vk * cid->vk * cid->vk / acos(0.0); - double csch = 2.0 * cid->vk * cid->sqsfi / cid->c1->gcs; - double sqk = cid->vk * cid->vk * exdc; - vtppoanp->append_line(VirtualBinaryLine(cid->vk)); - pcrsm0(cid->vk, exri, inpol, cid->c1); - apcra(cid->zpv, cid->c1->le, cid->c1->am0m, inpol, sqk, cid->gapm, cid->gappm); -#ifdef USE_NVTX - nvtxRangePop(); -#endif - interval_end = chrono::high_resolution_clock::now(); - elapsed = interval_end - interval_start; - message = "INFO: average calculation for scale " + to_string(jxi488) + " took " + to_string(elapsed.count()) + "s.\n"; - logger->log(message); - interval_start = chrono::high_resolution_clock::now(); -#ifdef USE_NVTX - nvtxRangePush("Angle loop"); + nvtxRangePush("Angle loop"); #endif double th = sa->th; + int done_dirs = 0; for (int jth486 = 1; jth486 <= sa->nth; jth486++) { // OpenMP portable? double ph = sa->ph; double cost = 0.0, sint = 0.0, cosp = 0.0, sinp = 0.0; @@ -1689,8 +1045,6 @@ int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryCo vtppoanp->append_line(VirtualBinaryLine(value)); } } - sprintf(virtual_line, " ENSEMBLE AVERAGE, MODE%2d\n", iavm); - output->append_line(virtual_line); int jlr = 2; for (int ilr210 = 1; ilr210 <= 2; ilr210++) { int ipol = (ilr210 % 2 == 0) ? 1 : -1; @@ -1706,68 +1060,72 @@ int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryCo double qschum = imag(s0m) * csch; double pschum = real(s0m) * csch; double s0magm = cabs(s0m) * cs0; - if (inpol == 0) { - sprintf(virtual_line, " LIN %2d\n", ipol); - output->append_line(virtual_line); - } else { // label 206 - sprintf(virtual_line, " CIRC %2d\n", ipol); - output->append_line(virtual_line); - } + // if (inpol == 0) { + // sprintf(virtual_line, " LIN %2d\n", ipol); + // output->append_line(virtual_line); + // } else { // label 206 + // sprintf(virtual_line, " CIRC %2d\n", ipol); + // output->append_line(virtual_line); + // } // label 208 - sprintf(virtual_line, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n"); - output->append_line(virtual_line); - sprintf(virtual_line, " %14.7lE%15.7lE%15.7lE%15.7lE\n", scasm, abssm, extsm, albdm); - output->append_line(virtual_line); - double alamb = 2.0 * 3.141592653589793238 / cid->vk; - sprintf(virtual_line, "INSERTION: SCASECM %5d%15.7E%15.7E%15.7E%15.7E\n", ipol, alamb, scasm, abssm, extsm); - output->append_line(virtual_line); - sprintf(virtual_line, " ---- SCS/GS -- ABC/GS -- EXS/GS ---\n"); - output->append_line(virtual_line); - sprintf(virtual_line, " %14.7lE%15.7lE%15.7lE\n", qscam, qabsm, qextm); - output->append_line(virtual_line); - sprintf( - virtual_line, " FSAS(%1d,%1d)=%15.7lE%15.7lE FSAS(%1d,%1d)=%15.7lE%15.7lE\n", - ilr210, ilr210, real(cid->c1->fsacm[ilr210 - 1][ilr210 - 1]), - imag(cid->c1->fsacm[ilr210 - 1][ilr210 - 1]), jlr, ilr210, - real(cid->c1->fsacm[jlr - 1][ilr210 - 1]), imag(cid->c1->fsacm[jlr - 1][ilr210 - 1]) - ); - output->append_line(virtual_line); - sprintf(virtual_line, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", qschum, pschum, s0magm); - output->append_line(virtual_line); double rapr = cid->c1->ecscm[ilr210 - 1] - cid->gapm[2][ilr210 - 1]; double cosav = cid->gapm[2][ilr210 - 1] / cid->c1->scscm[ilr210 - 1]; double fz = rapr; - sprintf(virtual_line, " COSAV=%15.7lE, RAPRS=%15.7lE\n", cosav, rapr); - output->append_line(virtual_line); - sprintf(virtual_line, " Fk=%15.7lE\n", fz); - output->append_line(virtual_line); + if (ipol == -1) { + output->vec_scs1[jindex - 1] = scasm; + output->vec_abs1[jindex - 1] = abssm; + output->vec_exs1[jindex - 1] = extsm; + output->vec_albeds1[jindex - 1] = albdm; + output->vec_scsrt1[jindex - 1] = qscam; + output->vec_absrt1[jindex - 1] = qabsm; + output->vec_exsrt1[jindex - 1] = qextm; + output->vec_fsas11[jindex - 1] = cid->c1->fsacm[0][0]; + output->vec_fsas21[jindex - 1] = cid->c1->fsacm[1][0]; + output->vec_qschu1[jindex -1] = qschum; + output->vec_pschu1[jindex -1] = pschum; + output->vec_s0mag1[jindex -1] = s0magm; + output->vec_cosav1[jindex -1] = cosav; + output->vec_raprs1[jindex -1] = rapr; + output->vec_fk1[jindex -1] = fz; + } else if (ipol == 1) { + output->vec_scs2[jindex - 1] = scasm; + output->vec_abs2[jindex - 1] = abssm; + output->vec_exs2[jindex - 1] = extsm; + output->vec_albeds2[jindex - 1] = albdm; + output->vec_scsrt2[jindex - 1] = qscam; + output->vec_absrt2[jindex - 1] = qabsm; + output->vec_exsrt2[jindex - 1] = qextm; + output->vec_fsas22[jindex - 1] = cid->c1->fsacm[1][1]; + output->vec_fsas12[jindex - 1] = cid->c1->fsacm[0][1]; + output->vec_qschu2[jindex -1] = qschum; + output->vec_pschu2[jindex -1] = pschum; + output->vec_s0mag2[jindex -1] = s0magm; + output->vec_cosav2[jindex -1] = cosav; + output->vec_raprs2[jindex -1] = rapr; + output->vec_fk2[jindex -1] = fz; + } } // ilr210 loop - double rmbrif = (real(cid->c1->fsacm[0][0]) - real(cid->c1->fsacm[1][1])) / real(cid->c1->fsacm[0][0]); - double rmdchr = (imag(cid->c1->fsacm[0][0]) - imag(cid->c1->fsacm[1][1])) / imag(cid->c1->fsacm[0][0]); - sprintf(virtual_line, " (RE(FSAS(1,1))-RE(FSAS(2,2)))/RE(FSAS(1,1))=%15.7lE\n", rmbrif); - output->append_line(virtual_line); - sprintf(virtual_line, " (IM(FSAS(1,1))-IM(FSAS(2,2)))/IM(FSAS(1,1))=%15.7lE\n", rmdchr); - output->append_line(virtual_line); } // label 212 - sprintf(virtual_line, "********** JTH =%3d, JPH =%3d, JTHS =%3d, JPHS =%3d ********************\n", jth486, jph484, jths, jphs); - output->append_line(virtual_line); - sprintf(virtual_line, " TIDG=%10.3lE, PIDG=%10.3lE, TSDG=%10.3lE, PSDG=%10.3lE\n", th, ph, ths, phs); - output->append_line(virtual_line); - sprintf(virtual_line, " SCAND=%10.3lE\n", cid->scan); - output->append_line(virtual_line); - sprintf(virtual_line, " CFMP=%15.7lE, SFMP=%15.7lE\n", cid->cfmp, cid->sfmp); - output->append_line(virtual_line); - sprintf(virtual_line, " CFSP=%15.7lE, SFSP=%15.7lE\n", cid->cfsp, cid->sfsp); - output->append_line(virtual_line); + output->vec_dir_scand[done_dirs] = cid->scan; + output->vec_dir_cfmp[done_dirs] = cid->cfmp; + output->vec_dir_sfmp[done_dirs] = cid->sfmp; + output->vec_dir_cfsp[done_dirs] = cid->cfsp; + output->vec_dir_sfsp[done_dirs] = cid->sfsp; if (isam >= 0) { - sprintf(virtual_line, " UNI=(%12.5lE,%12.5lE,%12.5lE)\n", cid->un[0], cid->un[1], cid->un[2]); - output->append_line(virtual_line); - sprintf(virtual_line, " UNS=(%12.5lE,%12.5lE,%12.5lE)\n", cid->uns[0], cid->uns[1], cid->uns[2]); - output->append_line(virtual_line); + output->vec_dir_un[3 * done_dirs] = cid->un[0]; + output->vec_dir_un[3 * done_dirs + 1] = cid->un[1]; + output->vec_dir_un[3 * done_dirs + 2] = cid->un[2]; + output->vec_dir_uns[3 * done_dirs] = cid->uns[0]; + output->vec_dir_uns[3 * done_dirs + 1] = cid->uns[1]; + output->vec_dir_uns[3 * done_dirs + 2] = cid->uns[2]; } else { // label 214 - sprintf(virtual_line, " UN=(%12.5lE,%12.5lE,%12.5lE)\n\n", cid->un[0], cid->un[1], cid->un[2]); - output->append_line(virtual_line); + output->vec_dir_un[3 * done_dirs] = cid->un[0]; + output->vec_dir_un[3 * done_dirs + 1] = cid->un[1]; + output->vec_dir_un[3 * done_dirs + 2] = cid->un[2]; + output->vec_dir_uns[3 * done_dirs] = 0.0; + output->vec_dir_uns[3 * done_dirs + 1] = 0.0; + output->vec_dir_uns[3 * done_dirs + 2] = 0.0; } // label 220 pcros(cid->vk, exri, cid->c1); @@ -1848,8 +1206,7 @@ int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryCo vtppoanp->append_line(VirtualBinaryLine(value)); } } - sprintf(virtual_line, " SINGLE SCATTERER\n"); - output->append_line(virtual_line); + oindex = (jindex - 1) * ndirs + done_dirs; int jlr = 2; for (int ilr290 = 1; ilr290 <= 2; ilr290++) { int ipol = (ilr290 % 2 == 0) ? 1 : -1; @@ -1865,53 +1222,38 @@ int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryCo double qschu = imag(s0) * csch; double pschu = real(s0) * csch; double s0mag = cabs(s0) * cs0; - if (inpol == 0) { - sprintf(virtual_line, " LIN %2d\n", ipol); - output->append_line(virtual_line); - } else { // label 273 - sprintf(virtual_line, " CIRC %2d\n", ipol); - output->append_line(virtual_line); - } // label 275 - sprintf(virtual_line, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n"); - output->append_line(virtual_line); - sprintf( - virtual_line, " %14.7lE%15.7lE%15.7lE%15.7lE\n", - scasec, abssec, extsec, albedc - ); - output->append_line(virtual_line); - double alam = 2.0 * 3.141592653589793238 / cid->vk; - sprintf(virtual_line, "INSERTION: SCASEC %5d%14.7lE%14.7lE%14.7lE%14.7lE\n", ipol, alam, scasec, abssec, extsec); - sprintf(virtual_line, " ---- SCS/GS -- ABS/GS -- EXS/GS ---\n"); - output->append_line(virtual_line); - sprintf( - virtual_line, " %14.7lE%15.7lE%15.7lE\n", - qsca, qabs, qext - ); - output->append_line(virtual_line); - sprintf( - virtual_line, - " FSAS(%1d,%1d)=%15.7lE%15.7lE FSAS(%1d,%1d)=%15.7lE%15.7lE\n", - ilr290, ilr290, real(cid->c1->fsac[ilr290 - 1][ilr290 - 1]), - imag(cid->c1->fsac[ilr290 - 1][ilr290 - 1]), jlr, ilr290, - real(cid->c1->fsac[jlr - 1][ilr290 - 1]), - imag(cid->c1->fsac[jlr - 1][ilr290 - 1]) - ); - output->append_line(virtual_line); - sprintf( - virtual_line, - " SAS(%1d,%1d)=%15.7lE%15.7lE SAS(%1d,%1d)=%15.7lE%15.7lE\n", - ilr290, ilr290, real(cid->c1->sac[ilr290 - 1][ilr290 - 1]), - imag(cid->c1->sac[ilr290 - 1][ilr290 - 1]), jlr, ilr290, - real(cid->c1->sac[jlr - 1][ilr290 - 1]), - imag(cid->c1->sac[jlr - 1][ilr290 - 1]) - ); - output->append_line(virtual_line); - sprintf( - virtual_line, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", - qschu, pschu, s0mag - ); - output->append_line(virtual_line); + if (ipol == -1) { + output->vec_dir_scs1[oindex] = scasec; + output->vec_dir_abs1[oindex] = abssec; + output->vec_dir_exs1[oindex] = extsec; + output->vec_dir_albeds1[oindex] = albedc; + output->vec_dir_scsrt1[oindex] = qsca; + output->vec_dir_absrt1[oindex] = qabs; + output->vec_dir_exsrt1[oindex] = qext; + output->vec_dir_fsas11[oindex] = cid->c1->fsac[0][0]; + output->vec_dir_fsas21[oindex] = cid->c1->fsac[1][0]; + output->vec_dir_sas11[oindex] = cid->c1->sac[0][0]; + output->vec_dir_sas21[oindex] = cid->c1->sac[1][0]; + output->vec_dir_qschu1[oindex] = qschu; + output->vec_dir_pschu1[oindex] = pschu; + output->vec_dir_s0mag1[oindex] = s0mag; + } else if (ipol == 1) { + output->vec_dir_scs2[oindex] = scasec; + output->vec_dir_abs2[oindex] = abssec; + output->vec_dir_exs2[oindex] = extsec; + output->vec_dir_albeds2[oindex] = albedc; + output->vec_dir_scsrt2[oindex] = qsca; + output->vec_dir_absrt2[oindex] = qabs; + output->vec_dir_exsrt2[oindex] = qext; + output->vec_dir_fsas22[oindex] = cid->c1->fsac[1][1]; + output->vec_dir_fsas12[oindex] = cid->c1->fsac[0][1]; + output->vec_dir_sas22[oindex] = cid->c1->sac[1][1]; + output->vec_dir_sas12[oindex] = cid->c1->sac[0][1]; + output->vec_dir_qschu2[oindex] = qschu; + output->vec_dir_pschu2[oindex] = pschu; + output->vec_dir_s0mag2[oindex] = s0mag; + } bool goto290 = isam >= 0 && (jths > 1 || jphs > 1); if (!goto290) { cid->gapv[0] = cid->gap[0][ilr290 - 1]; @@ -1921,12 +1263,25 @@ int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryCo double scatts = cid->c1->scsc[ilr290 - 1]; double rapr, cosav, fp, fn, fk, fx, fy, fz; rftr(cid->u, cid->up, cid->un, cid->gapv, extins, scatts, rapr, cosav, fp, fn, fk, fx, fy, fz); - sprintf(virtual_line, " COSAV=%15.7lE, RAPRS=%15.7lE\n", cosav, rapr); - output->append_line(virtual_line); - sprintf(virtual_line, " Fl=%15.7lE, Fr=%15.7lE, Fk=%15.7lE\n", fp, fn, fk); - output->append_line(virtual_line); - sprintf(virtual_line, " Fx=%15.7lE, Fy=%15.7lE, Fz=%15.7lE\n", fx, fy, fz); - output->append_line(virtual_line); + if (ipol == -1) { + output->vec_dir_cosav1[oindex] = cosav; + output->vec_dir_rapr1[oindex] = rapr; + output->vec_dir_fl1[oindex] = fp; + output->vec_dir_fr1[oindex] = fn; + output->vec_dir_fk1[oindex] = fk; + output->vec_dir_fx1[oindex] = fx; + output->vec_dir_fy1[oindex] = fy; + output->vec_dir_fz1[oindex] = fz; + } else if (ipol == 1) { + output->vec_dir_cosav2[oindex] = cosav; + output->vec_dir_rapr2[oindex] = rapr; + output->vec_dir_fl2[oindex] = fp; + output->vec_dir_fr2[oindex] = fn; + output->vec_dir_fk2[oindex] = fk; + output->vec_dir_fx2[oindex] = fx; + output->vec_dir_fy2[oindex] = fy; + output->vec_dir_fz2[oindex] = fz; + } cid->tqev[0] = cid->tqce[ilr290 - 1][0]; cid->tqev[1] = cid->tqce[ilr290 - 1][1]; cid->tqev[2] = cid->tqce[ilr290 - 1][2]; @@ -1935,45 +1290,48 @@ int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryCo cid->tqsv[2] = cid->tqcs[ilr290 - 1][2]; double tep, ten, tek, tsp, tsn, tsk; tqr(cid->u, cid->up, cid->un, cid->tqev, cid->tqsv, tep, ten, tek, tsp, tsn, tsk); - sprintf(virtual_line, " TQEl=%15.7lE, TQEr=%15.7lE, TQEk=%15.7lE\n", tep, ten, tek); - output->append_line(virtual_line); - sprintf(virtual_line, " TQSl=%15.7lE, TQSr=%15.7lE, TQSk=%15.7lE\n", tsp, tsn, tsk); - output->append_line(virtual_line); - sprintf( - virtual_line, " TQEx=%15.7lE, TQEy=%15.7lE, TQEz=%15.7lE\n", - cid->tqce[ilr290 - 1][0], cid->tqce[ilr290 - 1][1], cid->tqce[ilr290 - 1][2] - ); - output->append_line(virtual_line); - sprintf( - virtual_line, " TQSx=%15.7lE, TQSy=%15.7lE, TQSz=%15.7lE\n", - cid->tqcs[ilr290 - 1][0], cid->tqcs[ilr290 - 1][1], cid->tqcs[ilr290 - 1][2] - ); - output->append_line(virtual_line); + if (ipol == -1) { + output->vec_dir_tqel1[oindex] = tep; + output->vec_dir_tqer1[oindex] = ten; + output->vec_dir_tqek1[oindex] = tek; + output->vec_dir_tqsl1[oindex] = tsp; + output->vec_dir_tqsr1[oindex] = tsn; + output->vec_dir_tqsk1[oindex] = tsk; + output->vec_dir_tqex1[oindex] = cid->tqce[0][0]; + output->vec_dir_tqey1[oindex] = cid->tqce[0][1]; + output->vec_dir_tqez1[oindex] = cid->tqce[0][2]; + output->vec_dir_tqsx1[oindex] = cid->tqcs[0][0]; + output->vec_dir_tqsy1[oindex] = cid->tqcs[0][1]; + output->vec_dir_tqsz1[oindex] = cid->tqcs[0][2]; + } else if (ipol == 1) { + output->vec_dir_tqel2[oindex] = tep; + output->vec_dir_tqer2[oindex] = ten; + output->vec_dir_tqek2[oindex] = tek; + output->vec_dir_tqsl2[oindex] = tsp; + output->vec_dir_tqsr2[oindex] = tsn; + output->vec_dir_tqsk2[oindex] = tsk; + output->vec_dir_tqex2[oindex] = cid->tqce[1][0]; + output->vec_dir_tqey2[oindex] = cid->tqce[1][1]; + output->vec_dir_tqez2[oindex] = cid->tqce[1][2]; + output->vec_dir_tqsx2[oindex] = cid->tqcs[1][0]; + output->vec_dir_tqsy2[oindex] = cid->tqcs[1][1]; + output->vec_dir_tqsz2[oindex] = cid->tqcs[1][2]; + } } } //ilr290 loop - double rbirif = (real(cid->c1->fsac[0][0]) - real(cid->c1->fsac[1][1])) / real(cid->c1->fsac[0][0]); - double rdichr = (imag(cid->c1->fsac[0][0]) - imag(cid->c1->fsac[1][1])) / imag(cid->c1->fsac[0][0]); - sprintf(virtual_line, " (RE(FSAS(1,1))-RE(FSAS(2,2)))/RE(FSAS(1,1))=%15.7lE\n", rbirif); - output->append_line(virtual_line); - sprintf(virtual_line, " (IM(FSAS(1,1))-IM(FSAS(2,2)))/IM(FSAS(1,1))=%15.7lE\n", rdichr); - output->append_line(virtual_line); - sprintf(virtual_line, " MULL\n"); - output->append_line(virtual_line); for (int i = 0; i < 4; i++) { - sprintf( - virtual_line, " %15.7lE%15.7lE%15.7lE%15.7lE\n", - cid->cmul[i][0], cid->cmul[i][1], cid->cmul[i][2], cid->cmul[i][3] - ); - output->append_line(virtual_line); + oindex = 16 * (jindex - 1) * ndirs + 16 * done_dirs + 4 * i; + output->vec_dir_mull[oindex] = cid->cmul[i][0]; + output->vec_dir_mull[oindex + 1] = cid->cmul[i][1]; + output->vec_dir_mull[oindex + 2] = cid->cmul[i][2]; + output->vec_dir_mull[oindex + 3] = cid->cmul[i][3]; } - sprintf(virtual_line, " MULLLR\n"); - output->append_line(virtual_line); for (int i = 0; i < 4; i++) { - sprintf( - virtual_line, " %15.7lE%15.7lE%15.7lE%15.7lE\n", - cid->cmullr[i][0], cid->cmullr[i][1], cid->cmullr[i][2], cid->cmullr[i][3] - ); - output->append_line(virtual_line); + oindex = 16 * (jindex - 1) * ndirs + 16 * done_dirs + 4 * i; + output->vec_dir_mulllr[oindex] = cid->cmullr[i][0]; + output->vec_dir_mulllr[oindex + 1] = cid->cmullr[i][1]; + output->vec_dir_mulllr[oindex + 2] = cid->cmullr[i][2]; + output->vec_dir_mulllr[oindex + 3] = cid->cmullr[i][3]; } if (iavm != 0) { mmulc(cid->c1->vintm, cid->cmullr, cid->cmul); @@ -1991,37 +1349,25 @@ int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryCo vtppoanp->append_line(VirtualBinaryLine(value)); } } - sprintf(virtual_line, " CLUSTER (ENSEMBLE AVERAGE, MODE%2d)\n", iavm); - output->append_line(virtual_line); - if (inpol == 0) { - sprintf(virtual_line, " LIN\n"); - output->append_line(virtual_line); - } else { // label 316 - sprintf(virtual_line, " CIRC\n"); - output->append_line(virtual_line); - } // label 318 - sprintf(virtual_line, " MULC\n"); - output->append_line(virtual_line); for (int i = 0; i < 4; i++) { - sprintf( - virtual_line, " %15.7lE%15.7lE%15.7lE%15.7lE\n", - cid->cmul[i][0], cid->cmul[i][1], cid->cmul[i][2], cid->cmul[i][3] - ); - output->append_line(virtual_line); + oindex = 16 * (jindex - 1) + 4 * i; // if IAVM fails, try adding directions + output->vec_dir_mull[oindex] = cid->cmul[i][0]; + output->vec_dir_mull[oindex + 1] = cid->cmul[i][1]; + output->vec_dir_mull[oindex + 2] = cid->cmul[i][2]; + output->vec_dir_mull[oindex + 3] = cid->cmul[i][3]; } - sprintf(virtual_line, " MULCLR\n"); - output->append_line(virtual_line); for (int i = 0; i < 4; i++) { - sprintf( - virtual_line, " %15.7lE%15.7lE%15.7lE%15.7lE\n", - cid->cmullr[i][0], cid->cmullr[i][1], cid->cmullr[i][2], cid->cmullr[i][3] - ); - output->append_line(virtual_line); + oindex = 16 * (jindex - 1) + 4 * i; // if IAVM fails, try adding directions + output->vec_dir_mulllr[oindex] = cid->cmul[i][0]; + output->vec_dir_mulllr[oindex + 1] = cid->cmullr[i][1]; + output->vec_dir_mulllr[oindex + 2] = cid->cmullr[i][2]; + output->vec_dir_mulllr[oindex + 3] = cid->cmullr[i][3]; } } // label 420, continues jphs loop if (isam < 1) phs += sa->phsstp; + done_dirs++; } // jphs loop, labeled 480 if (isam <= 1) thsl += sa->thsstp; } // jths loop, labeled 482 @@ -2032,14 +1378,557 @@ int inclusion_jxi488_cycle(int jxi488, ScattererConfiguration *sconf, GeometryCo #ifdef USE_NVTX nvtxRangePop(); #endif + if (jer == 0) output->vec_jxi[jindex - 1] = jxi488; interval_end = chrono::high_resolution_clock::now(); elapsed = interval_end - interval_start; message = "INFO: angle loop for scale " + to_string(jxi488) + " took " + to_string(elapsed.count()) + "s.\n"; logger->log(message); - logger->log("INFO: finished scale iteration " + to_string(jxi488) + " of " + to_string(nxi) + ".\n"); + logger->log("INFO: finished scale iteration " + to_string(jxi488) + " of " + to_string(nxi) + ".\n"); + + delete logger; + + return jer; +} + +// >>> IMPLEMENTATION OF InclusionIterationData CLASS <<< // +InclusionIterationData::InclusionIterationData(GeometryConfiguration *gconf, ScattererConfiguration *sconf, const mixMPI *mpidata, const int device_count) { + c1 = new ParticleDescriptorInclusion(gconf, sconf); + const int ndi = c1->nsph * c1->nlim; + const np_int ndit = 2 * ndi; + gaps = new double[c1->nsph](); + tqev = new double[3](); + tqsv = new double[3](); + tqse = new double*[2]; + tqspe = new dcomplex*[2]; + tqss = new double*[2]; + tqsps = new dcomplex*[2]; + tqce = new double*[2]; + tqcpe = new dcomplex*[2]; + tqcs = new double*[2]; + tqcps = new dcomplex*[2]; + for (int ti = 0; ti < 2; ti++) { + tqse[ti] = new double[c1->nsph](); + tqspe[ti] = new dcomplex[c1->nsph](); + tqss[ti] = new double[c1->nsph](); + tqsps[ti] = new dcomplex[c1->nsph](); + tqce[ti] = new double[3](); + tqcpe[ti] = new dcomplex[3](); + tqcs[ti] = new double[3](); + tqcps[ti] = new dcomplex[3](); + } + gapv = new double[3](); + gapp = new dcomplex*[3]; + gappm = new dcomplex*[3]; + gap = new double*[3]; + gapm = new double*[3]; + for (int gi = 0; gi < 3; gi++) { + gapp[gi] = new dcomplex[2](); + gappm[gi] = new dcomplex[2](); + gap[gi] = new double[2](); + gapm[gi] = new double[2](); + } + u = new double[3](); + us = new double[3](); + un = new double[3](); + uns = new double[3](); + up = new double[3](); + ups = new double[3](); + unmp = new double[3](); + unsmp = new double[3](); + upmp = new double[3](); + upsmp = new double[3](); + argi = new double[1](); + args = new double[1](); + duk = new double[3](); + cextlr = new double*[4]; + cext = new double*[4]; + cmullr = new double*[4];; + cmul = new double*[4]; + for (int ci = 0; ci < 4; ci++) { + cextlr[ci] = new double[4](); + cext[ci] = new double[4](); + cmullr[ci] = new double[4](); + cmul[ci] = new double[4](); + } + vec_zpv = new double[c1->lm * 12](); + zpv = new double***[c1->lm]; + for (int zi = 0; zi < c1->lm; zi++) { + zpv[zi] = new double**[12]; + for (int zj = 0; zj < 3; zj++) { + zpv[zi][zj] = new double*[4]; + zpv[zi][zj][0] = vec_zpv + (zi * 12) + (zj * 4); + zpv[zi][zj][1] = vec_zpv + (zi * 12) + (zj * 4) + 2; + } + } + am_vector = new dcomplex[c1->ndm * c1->ndm](); + am = new dcomplex*[c1->ndm]; + for (int ai = 0; ai < c1->ndm; ai++) { + am[ai] = (am_vector + ai * c1->ndm); + } + + arg = 0.0 + 0.0 * I; + // These are suspect initializations + scan = 0.0; + cfmp = 0.0; + sfmp = 0.0; + cfsp = 0.0; + sfsp = 0.0; + // End of suspect initializations + wn = sconf->wp / 3.0e8; + xip = sconf->xip; + sqsfi = 1.0; + vk = 0.0; + number_of_scales = sconf->number_of_scales; + xiblock = (int) ceil(((double) (sconf->number_of_scales-1))/((double) mpidata->nprocs)); + lastxi = ((mpidata->rank+1) * xiblock)+1; + firstxi = lastxi-xiblock+1; + if (lastxi > sconf->number_of_scales) lastxi = sconf->number_of_scales; + + nimd = c1->nshl[0] + 1; + c1->rc[0][nimd - 1] = c1->ros[0] * sconf->get_rcf(0, nimd - 1); + extr = c1->rc[0][nimd - 1]; + const double pig = acos(0.0) * 2.0; + c1->gcs = pig * extr * extr; + +#ifdef USE_MAGMA + proc_device = mpidata->rank % device_count; +#else + proc_device = 0; +#endif + + // In the first iteration, if refinement is enabled, determine the number of refinement iterations required to arrive at the target accuracy (if achievable in a reasonable number of iterations) + refinemode = 2; + // maxrefiters and accuracygoal should be configurable and preferably set somewhere else + maxrefiters = 20; + accuracygoal = 1e-6; +} + +InclusionIterationData::InclusionIterationData(const InclusionIterationData& rhs) { + c1 = new ParticleDescriptorInclusion(reinterpret_cast<ParticleDescriptorInclusion &>(*(rhs.c1))); + const int ndi = c1->nsph * c1->nlim; + const np_int ndit = 2 * ndi; + gaps = new double[c1->nsph](); + for (int gi = 0; gi < c1->nsph; gi++) gaps[gi] = rhs.gaps[gi]; + tqev = new double[3](); + tqsv = new double[3](); + for (int ti = 0; ti < 3; ti++) { + tqev[ti] = rhs.tqev[ti]; + tqsv[ti] = rhs.tqsv[ti]; + } + tqse = new double*[2]; + tqspe = new dcomplex*[2]; + tqss = new double*[2]; + tqsps = new dcomplex*[2]; + tqce = new double*[2]; + tqcpe = new dcomplex*[2]; + tqcs = new double*[2]; + tqcps = new dcomplex*[2]; + for (int ti = 0; ti < 2; ti++) { + tqse[ti] = new double[c1->nsph](); + tqspe[ti] = new dcomplex[c1->nsph](); + tqss[ti] = new double[c1->nsph](); + tqsps[ti] = new dcomplex[c1->nsph](); + for (int tj = 0; tj < c1->nsph; tj++) { + tqse[ti][tj] = rhs.tqse[ti][tj]; + tqspe[ti][tj] = rhs.tqspe[ti][tj]; + tqss[ti][tj] = rhs.tqss[ti][tj]; + tqsps[ti][tj] = rhs.tqsps[ti][tj]; + } + tqce[ti] = new double[3](); + tqcpe[ti] = new dcomplex[3](); + tqcs[ti] = new double[3](); + tqcps[ti] = new dcomplex[3](); + for (int tj = 0; tj < 3; tj++) { + tqce[ti][tj] = rhs.tqce[ti][tj]; + tqcpe[ti][tj] = rhs.tqcpe[ti][tj]; + tqcs[ti][tj] = rhs.tqcs[ti][tj]; + tqcps[ti][tj] = rhs.tqcps[ti][tj]; + } + } + gapv = new double[3](); + gapp = new dcomplex*[3]; + gappm = new dcomplex*[3]; + gap = new double*[3]; + gapm = new double*[3]; + for (int gi = 0; gi < 3; gi++) { + gapv[gi] = rhs.gapv[gi]; + gapp[gi] = new dcomplex[2](); + gappm[gi] = new dcomplex[2](); + gap[gi] = new double[2](); + gapm[gi] = new double[2](); + for (int gj = 0; gj < 2; gj++) { + gapp[gi][gj] = rhs.gapp[gi][gj]; + gappm[gi][gj] = rhs.gappm[gi][gj]; + gap[gi][gj] = rhs.gap[gi][gj]; + gapm[gi][gj] = rhs.gapm[gi][gj]; + } + } + u = new double[3](); + us = new double[3](); + un = new double[3](); + uns = new double[3](); + up = new double[3](); + ups = new double[3](); + unmp = new double[3](); + unsmp = new double[3](); + upmp = new double[3](); + upsmp = new double[3](); + duk = new double[3](); + for (int ui = 0; ui < 3; ui++) { + u[ui] = rhs.u[ui]; + us[ui] = rhs.us[ui]; + un[ui] = rhs.un[ui]; + uns[ui] = rhs.uns[ui]; + up[ui] = rhs.up[ui]; + ups[ui] = rhs.ups[ui]; + unmp[ui] = rhs.unmp[ui]; + unsmp[ui] = rhs.unsmp[ui]; + upmp[ui] = rhs.upmp[ui]; + upsmp[ui] = rhs.upsmp[ui]; + duk[ui] = rhs.duk[ui]; + } + argi = new double[1](); + args = new double[1](); + argi[0] = rhs.argi[0]; + args[0] = rhs.args[0]; + cextlr = new double*[4]; + cext = new double*[4]; + cmullr = new double*[4];; + cmul = new double*[4]; + for (int ci = 0; ci < 4; ci++) { + cextlr[ci] = new double[4](); + cext[ci] = new double[4](); + cmullr[ci] = new double[4](); + cmul[ci] = new double[4](); + for (int cj = 0; cj < 4; cj++) { + cextlr[ci][cj] = rhs.cextlr[ci][cj]; + cext[ci][cj] = rhs.cext[ci][cj]; + cmullr[ci][cj] = rhs.cmullr[ci][cj]; + cmul[ci][cj] = rhs.cmul[ci][cj]; + } + } + vec_zpv = new double[c1->lm * 12]; + zpv = new double***[c1->lm]; + for (int zi = 0; zi < c1->lm; zi++) { + zpv[zi] = new double **[12]; + for (int zj = 0; zj < 3; zj++) { + zpv[zi][zj] = new double*[4]; + zpv[zi][zj][0] = vec_zpv + (zi * 12) + (zj * 4); + zpv[zi][zj][1] = vec_zpv + (zi * 12) + (zj * 4) + 2; + zpv[zi][zj][0][0] = rhs.zpv[zi][zj][0][0]; + zpv[zi][zj][0][1] = rhs.zpv[zi][zj][0][1]; + zpv[zi][zj][1][0] = rhs.zpv[zi][zj][1][0]; + zpv[zi][zj][1][1] = rhs.zpv[zi][zj][1][1]; + } + } + am_vector = new dcomplex[c1->ndm * c1->ndm]; + for (int ai = 0; ai < c1->ndm * c1->ndm; ai++) am_vector[ai] = rhs.am_vector[ai]; + am = new dcomplex*[c1->ndm]; + for (int ai = 0; ai < c1->ndm; ai++) { + am[ai] = (am_vector + ai * c1->ndm); + } + + arg = rhs.arg; + // These are suspect initializations + scan = rhs.scan; + cfmp = rhs.cfmp; + sfmp = rhs.sfmp; + cfsp = rhs.cfsp; + sfsp = rhs.sfsp; + // End of suspect initializations + wn = rhs.wn; + xip = rhs.xip; + sqsfi = rhs.sqsfi; + vk = rhs.vk; + firstxi = rhs.firstxi; + lastxi = rhs.lastxi; + xiblock = rhs.xiblock; + number_of_scales = rhs.number_of_scales; + + nimd = rhs.nimd; + extr = rhs.extr; + + proc_device = rhs.proc_device; + refinemode = rhs.refinemode; + maxrefiters = rhs.maxrefiters; + accuracygoal = rhs.accuracygoal; +} + +#ifdef MPI_VERSION +InclusionIterationData::InclusionIterationData(const mixMPI *mpidata, const int device_count) { + c1 = new ParticleDescriptorInclusion(mpidata); + const int ndi = c1->nsph * c1->nlim; + const np_int ndit = 2 * ndi; + gaps = new double[c1->nsph](); + MPI_Bcast(gaps, c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + tqev = new double[3](); + tqsv = new double[3](); + MPI_Bcast(tqev, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqsv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + tqse = new double*[2]; + tqspe = new dcomplex*[2]; + tqss = new double*[2]; + tqsps = new dcomplex*[2]; + tqce = new double*[2]; + tqcpe = new dcomplex*[2]; + tqcs = new double*[2]; + tqcps = new dcomplex*[2]; + for (int ti = 0; ti < 2; ti++) { + tqse[ti] = new double[c1->nsph](); + tqspe[ti] = new dcomplex[c1->nsph](); + tqss[ti] = new double[c1->nsph](); + tqsps[ti] = new dcomplex[c1->nsph](); + MPI_Bcast(tqse[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqspe[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(tqss[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqsps[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + tqce[ti] = new double[3](); + tqcpe[ti] = new dcomplex[3](); + tqcs[ti] = new double[3](); + tqcps[ti] = new dcomplex[3](); + MPI_Bcast(tqce[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcpe[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcs[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcps[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + } + gapv = new double[3](); + gapp = new dcomplex*[3]; + gappm = new dcomplex*[3]; + gap = new double*[3]; + gapm = new double*[3]; + MPI_Bcast(gapv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + for (int gi = 0; gi < 3; gi++) { + gapp[gi] = new dcomplex[2](); + gappm[gi] = new dcomplex[2](); + gap[gi] = new double[2](); + gapm[gi] = new double[2](); + MPI_Bcast(gapp[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(gappm[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(gap[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(gapm[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } + u = new double[3](); + us = new double[3](); + un = new double[3](); + uns = new double[3](); + up = new double[3](); + ups = new double[3](); + unmp = new double[3](); + unsmp = new double[3](); + upmp = new double[3](); + upsmp = new double[3](); + duk = new double[3](); + MPI_Bcast(u, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(us, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(un, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(uns, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(up, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(ups, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(duk, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + argi = new double[1](); + args = new double[1](); + MPI_Bcast(argi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(args, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + cextlr = new double*[4]; + cext = new double*[4]; + cmullr = new double*[4];; + cmul = new double*[4]; + for (int ci = 0; ci < 4; ci++) { + cextlr[ci] = new double[4](); + cext[ci] = new double[4](); + cmullr[ci] = new double[4](); + cmul[ci] = new double[4](); + MPI_Bcast(cextlr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cext[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cmullr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cmul[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } + vec_zpv = new double[c1->lm * 12]; + MPI_Bcast(vec_zpv, c1->lm * 12, MPI_DOUBLE, 0, MPI_COMM_WORLD); + zpv = new double***[c1->lm]; + for (int zi = 0; zi < c1->lm; zi++) { + zpv[zi] = new double **[12]; + for (int zj = 0; zj < 3; zj++) { + zpv[zi][zj] = new double*[4]; + zpv[zi][zj][0] = vec_zpv + (zi * 12) + (zj * 4); + zpv[zi][zj][1] = vec_zpv + (zi * 12) + (zj * 4) + 2; + } + } + am_vector = new dcomplex[c1->ndm * c1->ndm]; + am = new dcomplex*[c1->ndm]; + for (int ai = 0; ai < c1->ndm; ai++) { + am[ai] = (am_vector + ai * c1->ndm); + MPI_Bcast(am[ai], c1->ndm, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + } + MPI_Bcast(&arg, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(&scan, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&wn, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xip, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sqsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&vk, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xiblock, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&number_of_scales, 1, MPI_INT, 0, MPI_COMM_WORLD); + lastxi = ((mpidata->rank+1) * xiblock)+1; + firstxi = lastxi-xiblock+1; + if (lastxi > number_of_scales) lastxi = number_of_scales; + + MPI_Bcast(&nimd, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&extr, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + +#ifdef USE_MAGMA + proc_device = mpidata->rank % device_count; +#else + proc_device = 0; +#endif + MPI_Bcast(&refinemode, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&maxrefiters, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&accuracygoal, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); +} - delete logger; +void InclusionIterationData::mpibcast(const mixMPI *mpidata) { + c1->mpibcast(mpidata); + const int ndi = c1->nsph * c1->nlim; + const np_int ndit = 2 * ndi; + MPI_Bcast(gaps, c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqev, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqsv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + for (int ti = 0; ti < 2; ti++) { + MPI_Bcast(tqse[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqspe[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(tqss[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqsps[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(tqce[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcpe[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcs[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(tqcps[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + } + MPI_Bcast(gapv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + for (int gi = 0; gi < 3; gi++) { + MPI_Bcast(gapp[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(gappm[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(gap[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(gapm[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } + MPI_Bcast(u, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(us, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(un, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(uns, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(up, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(ups, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(duk, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(argi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(args, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + for (int ci = 0; ci < 4; ci++) { + MPI_Bcast(cextlr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cext[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cmullr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(cmul[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } + MPI_Bcast(vec_zpv, c1->lm * 12, MPI_DOUBLE, 0, MPI_COMM_WORLD); + // since MPI expects an int argument for the number of elements to transfer in one go, transfer am one row at a time + for (int ai = 0; ai < c1->ndm; ai++) { + MPI_Bcast(am[ai], c1->ndm, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + } + MPI_Bcast(&arg, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(&scan, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&wn, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xip, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sqsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&vk, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xiblock, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&number_of_scales, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&nimd, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&extr, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&refinemode, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&maxrefiters, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&accuracygoal, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); +} +#endif - return jer; +InclusionIterationData::~InclusionIterationData() { + const int nsph = c1->nsph; + delete[] am_vector; + delete[] am; + for (int zi = 0; zi < c1->lm; zi++) { + for (int zj = 0; zj < 3; zj++) { + delete[] zpv[zi][zj]; + } + delete[] zpv[zi]; + } + delete[] zpv; + delete[] vec_zpv; + delete c1; + delete[] gaps; + for (int ti = 1; ti > -1; ti--) { + delete[] tqse[ti]; + delete[] tqss[ti]; + delete[] tqspe[ti]; + delete[] tqsps[ti]; + delete[] tqce[ti]; + delete[] tqcpe[ti]; + delete[] tqcs[ti]; + delete[] tqcps[ti]; + } + delete[] tqse; + delete[] tqss; + delete[] tqspe; + delete[] tqsps; + delete[] tqce; + delete[] tqcpe; + delete[] tqcs; + delete[] tqcps; + delete[] tqev; + delete[] tqsv; + for (int gi = 2; gi > -1; gi--) { + delete[] gapp[gi]; + delete[] gappm[gi]; + delete[] gap[gi]; + delete[] gapm[gi]; + } + delete[] gapp; + delete[] gappm; + delete[] gap; + delete[] gapm; + delete[] gapv; + delete[] u; + delete[] us; + delete[] un; + delete[] uns; + delete[] up; + delete[] ups; + delete[] unmp; + delete[] unsmp; + delete[] upmp; + delete[] upsmp; + delete[] argi; + delete[] args; + delete[] duk; + for (int ci = 3; ci > -1; ci--) { + delete[] cextlr[ci]; + delete[] cext[ci]; + delete[] cmullr[ci]; + delete[] cmul[ci]; + } + delete[] cextlr; + delete[] cext; + delete[] cmullr; + delete[] cmul; } +// >>> END OF InclusionIterationData CLASS IMPLEMENTATION <<< diff --git a/src/libnptm/Commons.cpp b/src/libnptm/Commons.cpp index 126ca007bacfdb2acbafaf3c1d2e32855b0a5da9..cfdec141721873bb3ecddaaa80614fefa6a87959 100644 --- a/src/libnptm/Commons.cpp +++ b/src/libnptm/Commons.cpp @@ -18,6 +18,12 @@ * * \brief Implementation of the common data structures. */ +#include <cstring> + +#ifdef USE_MPI +#include <mpi.h> +#endif + #ifndef INCLUDE_TYPES_H_ #include "../include/types.h" #endif @@ -30,12 +36,6 @@ #include "../include/Commons.h" #endif -#include <cstring> - -#ifdef USE_MPI -#include <mpi.h> -#endif - mixMPI::mixMPI() { mpirunning = 0; rank = 0; @@ -61,541 +61,6 @@ mixMPI::mixMPI(const mixMPI& rhs) { mixMPI::~mixMPI() { } -ClusterIterationData::ClusterIterationData(GeometryConfiguration *gconf, ScattererConfiguration *sconf, const mixMPI *mpidata, const int device_count) { - c1 = new ParticleDescriptorCluster(gconf, sconf); - const int ndi = c1->nsph * c1->nlim; - const np_int ndit = 2 * ndi; - gaps = new double[c1->nsph](); - tqev = new double[3](); - tqsv = new double[3](); - tqse = new double*[2]; - tqspe = new dcomplex*[2]; - tqss = new double*[2]; - tqsps = new dcomplex*[2]; - tqce = new double*[2]; - tqcpe = new dcomplex*[2]; - tqcs = new double*[2]; - tqcps = new dcomplex*[2]; - for (int ti = 0; ti < 2; ti++) { - tqse[ti] = new double[c1->nsph](); - tqspe[ti] = new dcomplex[c1->nsph](); - tqss[ti] = new double[c1->nsph](); - tqsps[ti] = new dcomplex[c1->nsph](); - tqce[ti] = new double[3](); - tqcpe[ti] = new dcomplex[3](); - tqcs[ti] = new double[3](); - tqcps[ti] = new dcomplex[3](); - } - gapv = new double[3](); - gapp = new dcomplex*[3]; - gappm = new dcomplex*[3]; - gap = new double*[3]; - gapm = new double*[3]; - for (int gi = 0; gi < 3; gi++) { - gapp[gi] = new dcomplex[2](); - gappm[gi] = new dcomplex[2](); - gap[gi] = new double[2](); - gapm[gi] = new double[2](); - } - u = new double[3](); - us = new double[3](); - un = new double[3](); - uns = new double[3](); - up = new double[3](); - ups = new double[3](); - unmp = new double[3](); - unsmp = new double[3](); - upmp = new double[3](); - upsmp = new double[3](); - argi = new double[1](); - args = new double[1](); - duk = new double[3](); - cextlr = new double*[4]; - cext = new double*[4]; - cmullr = new double*[4];; - cmul = new double*[4]; - for (int ci = 0; ci < 4; ci++) { - cextlr[ci] = new double[4](); - cext[ci] = new double[4](); - cmullr[ci] = new double[4](); - cmul[ci] = new double[4](); - } - zpv = new double***[c1->lm]; - for (int zi = 0; zi < c1->lm; zi++) { - zpv[zi] = new double**[3]; - for (int zj = 0; zj < 3; zj++) { - zpv[zi][zj] = new double*[2]; - for (int zk = 0; zk < 2; zk++) { - zpv[zi][zj][zk] = new double[2](); - } - } - } - am_vector = new dcomplex[ndit * ndit](); - am = new dcomplex*[ndit]; - for (int ai = 0; ai < ndit; ai++) { - am[ai] = (am_vector + ai * ndit); - } - - arg = 0.0 + 0.0 * I; - // These are suspect initializations - scan = 0.0; - cfmp = 0.0; - sfmp = 0.0; - cfsp = 0.0; - sfsp = 0.0; - qsfi = 0.0; - // End of suspect initializations - wn = sconf->wp / 3.0e8; - xip = sconf->xip; - sqsfi = 1.0; - vk = 0.0; - number_of_scales = sconf->number_of_scales; - xiblock = (int) ceil(((double) (sconf->number_of_scales-1))/((double) mpidata->nprocs)); - lastxi = ((mpidata->rank+1) * xiblock)+1; - firstxi = lastxi-xiblock+1; - if (lastxi > sconf->number_of_scales) lastxi = sconf->number_of_scales; - -#ifdef USE_MAGMA - proc_device = mpidata->rank % device_count; -#else - proc_device = 0; -#endif - - // In the first iteration, if refinement is enabled, determine the number of refinement iterations required to arrive at the target accuracy (if achievable in a reasonable number of iterations) - refinemode = 2; - // maxrefiters and accuracygoal should be configurable and preferably set somewhere else - maxrefiters = 20; - accuracygoal = 1e-6; -} - -ClusterIterationData::ClusterIterationData(const ClusterIterationData& rhs) { - c1 = new ParticleDescriptorCluster(reinterpret_cast<ParticleDescriptorCluster &>(*(rhs.c1))); - const int ndi = c1->nsph * c1->nlim; - const np_int ndit = 2 * ndi; - gaps = new double[c1->nsph](); - for (int gi = 0; gi < c1->nsph; gi++) gaps[gi] = rhs.gaps[gi]; - tqev = new double[3](); - tqsv = new double[3](); - for (int ti = 0; ti < 3; ti++) { - tqev[ti] = rhs.tqev[ti]; - tqsv[ti] = rhs.tqsv[ti]; - } - tqse = new double*[2]; - tqspe = new dcomplex*[2]; - tqss = new double*[2]; - tqsps = new dcomplex*[2]; - tqce = new double*[2]; - tqcpe = new dcomplex*[2]; - tqcs = new double*[2]; - tqcps = new dcomplex*[2]; - for (int ti = 0; ti < 2; ti++) { - tqse[ti] = new double[c1->nsph](); - tqspe[ti] = new dcomplex[c1->nsph](); - tqss[ti] = new double[c1->nsph](); - tqsps[ti] = new dcomplex[c1->nsph](); - for (int tj = 0; tj < c1->nsph; tj++) { - tqse[ti][tj] = rhs.tqse[ti][tj]; - tqspe[ti][tj] = rhs.tqspe[ti][tj]; - tqss[ti][tj] = rhs.tqss[ti][tj]; - tqsps[ti][tj] = rhs.tqsps[ti][tj]; - } - tqce[ti] = new double[3](); - tqcpe[ti] = new dcomplex[3](); - tqcs[ti] = new double[3](); - tqcps[ti] = new dcomplex[3](); - for (int tj = 0; tj < 3; tj++) { - tqce[ti][tj] = rhs.tqce[ti][tj]; - tqcpe[ti][tj] = rhs.tqcpe[ti][tj]; - tqcs[ti][tj] = rhs.tqcs[ti][tj]; - tqcps[ti][tj] = rhs.tqcps[ti][tj]; - } - } - gapv = new double[3](); - gapp = new dcomplex*[3]; - gappm = new dcomplex*[3]; - gap = new double*[3]; - gapm = new double*[3]; - for (int gi = 0; gi < 3; gi++) { - gapv[gi] = rhs.gapv[gi]; - gapp[gi] = new dcomplex[2](); - gappm[gi] = new dcomplex[2](); - gap[gi] = new double[2](); - gapm[gi] = new double[2](); - for (int gj = 0; gj < 2; gj++) { - gapp[gi][gj] = rhs.gapp[gi][gj]; - gappm[gi][gj] = rhs.gappm[gi][gj]; - gap[gi][gj] = rhs.gap[gi][gj]; - gapm[gi][gj] = rhs.gapm[gi][gj]; - } - } - u = new double[3](); - us = new double[3](); - un = new double[3](); - uns = new double[3](); - up = new double[3](); - ups = new double[3](); - unmp = new double[3](); - unsmp = new double[3](); - upmp = new double[3](); - upsmp = new double[3](); - duk = new double[3](); - for (int ui = 0; ui < 3; ui++) { - u[ui] = rhs.u[ui]; - us[ui] = rhs.us[ui]; - un[ui] = rhs.un[ui]; - uns[ui] = rhs.uns[ui]; - up[ui] = rhs.up[ui]; - ups[ui] = rhs.ups[ui]; - unmp[ui] = rhs.unmp[ui]; - unsmp[ui] = rhs.unsmp[ui]; - upmp[ui] = rhs.upmp[ui]; - upsmp[ui] = rhs.upsmp[ui]; - duk[ui] = rhs.duk[ui]; - } - argi = new double[1](); - args = new double[1](); - argi[0] = rhs.argi[0]; - args[0] = rhs.args[0]; - cextlr = new double*[4]; - cext = new double*[4]; - cmullr = new double*[4];; - cmul = new double*[4]; - for (int ci = 0; ci < 4; ci++) { - cextlr[ci] = new double[4](); - cext[ci] = new double[4](); - cmullr[ci] = new double[4](); - cmul[ci] = new double[4](); - for (int cj = 0; cj < 4; cj++) { - cextlr[ci][cj] = rhs.cextlr[ci][cj]; - cext[ci][cj] = rhs.cext[ci][cj]; - cmullr[ci][cj] = rhs.cmullr[ci][cj]; - cmul[ci][cj] = rhs.cmul[ci][cj]; - } - } - zpv = new double***[c1->lm]; - for (int zi = 0; zi < c1->lm; zi++) { - zpv[zi] = new double**[3]; - for (int zj = 0; zj < 3; zj++) { - zpv[zi][zj] = new double*[2]; - for (int zk = 0; zk < 2; zk++) { - zpv[zi][zj][zk] = new double[2](); - zpv[zi][zj][zk][0] = rhs.zpv[zi][zj][zk][0]; - zpv[zi][zj][zk][1] = rhs.zpv[zi][zj][zk][1]; - } - } - } - am_vector = new dcomplex[ndit * ndit](); - for (np_int ai = 0; ai < ndit * ndit; ai++) am_vector[ai] = rhs.am_vector[ai]; - am = new dcomplex*[ndit]; - for (np_int ai = 0; ai < ndit; ai++) { - am[ai] = (am_vector + ai * ndit); - } - - arg = rhs.arg; - // These are suspect initializations - scan = rhs.scan; - cfmp = rhs.cfmp; - sfmp = rhs.sfmp; - cfsp = rhs.cfsp; - sfsp = rhs.sfsp; - qsfi = rhs.qsfi; - // End of suspect initializations - wn = rhs.wn; - xip = rhs.xip; - sqsfi = rhs.sqsfi; - vk = rhs.vk; - firstxi = rhs.firstxi; - lastxi = rhs.lastxi; - xiblock = rhs.xiblock; - number_of_scales = rhs.number_of_scales; - - proc_device = rhs.proc_device; - refinemode = rhs.refinemode; - maxrefiters = rhs.maxrefiters; - accuracygoal = rhs.accuracygoal; -} - -#ifdef MPI_VERSION -ClusterIterationData::ClusterIterationData(const mixMPI *mpidata, const int device_count) { - c1 = new ParticleDescriptorCluster(mpidata); - const int ndi = c1->nsph * c1->nlim; - const np_int ndit = 2 * ndi; - gaps = new double[c1->nsph](); - MPI_Bcast(gaps, c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - tqev = new double[3](); - tqsv = new double[3](); - MPI_Bcast(tqev, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqsv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - tqse = new double*[2]; - tqspe = new dcomplex*[2]; - tqss = new double*[2]; - tqsps = new dcomplex*[2]; - tqce = new double*[2]; - tqcpe = new dcomplex*[2]; - tqcs = new double*[2]; - tqcps = new dcomplex*[2]; - for (int ti = 0; ti < 2; ti++) { - tqse[ti] = new double[c1->nsph](); - tqspe[ti] = new dcomplex[c1->nsph](); - tqss[ti] = new double[c1->nsph](); - tqsps[ti] = new dcomplex[c1->nsph](); - MPI_Bcast(tqse[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqspe[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(tqss[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqsps[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - tqce[ti] = new double[3](); - tqcpe[ti] = new dcomplex[3](); - tqcs[ti] = new double[3](); - tqcps[ti] = new dcomplex[3](); - MPI_Bcast(tqce[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcpe[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcs[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcps[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - } - gapv = new double[3](); - gapp = new dcomplex*[3]; - gappm = new dcomplex*[3]; - gap = new double*[3]; - gapm = new double*[3]; - MPI_Bcast(gapv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - for (int gi = 0; gi < 3; gi++) { - gapp[gi] = new dcomplex[2](); - gappm[gi] = new dcomplex[2](); - gap[gi] = new double[2](); - gapm[gi] = new double[2](); - MPI_Bcast(gapp[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(gappm[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(gap[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(gapm[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); - } - u = new double[3](); - us = new double[3](); - un = new double[3](); - uns = new double[3](); - up = new double[3](); - ups = new double[3](); - unmp = new double[3](); - unsmp = new double[3](); - upmp = new double[3](); - upsmp = new double[3](); - duk = new double[3](); - MPI_Bcast(u, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(us, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(un, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(uns, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(up, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(ups, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(unmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(unsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(upmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(upsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(duk, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - argi = new double[1](); - args = new double[1](); - MPI_Bcast(argi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(args, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - cextlr = new double*[4]; - cext = new double*[4]; - cmullr = new double*[4];; - cmul = new double*[4]; - for (int ci = 0; ci < 4; ci++) { - cextlr[ci] = new double[4](); - cext[ci] = new double[4](); - cmullr[ci] = new double[4](); - cmul[ci] = new double[4](); - MPI_Bcast(cextlr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cext[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cmullr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cmul[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - } - zpv = new double***[c1->lm]; - for (int zi = 0; zi < c1->lm; zi++) { - zpv[zi] = new double**[3]; - for (int zj = 0; zj < 3; zj++) { - zpv[zi][zj] = new double*[2]; - for (int zk = 0; zk < 2; zk++) { - zpv[zi][zj][zk] = new double[2](); - MPI_Bcast(zpv[zi][zj][zk], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); - } - } - } - am_vector = new dcomplex[ndit * ndit](); - am = new dcomplex*[ndit]; - for (np_int ai = 0; ai < ndit; ai++) { - am[ai] = (am_vector + ai * ndit); - MPI_Bcast(am[ai], ndit, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - } - MPI_Bcast(&arg, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(&scan, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&cfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&cfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&qsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&wn, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&xip, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sqsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&vk, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&xiblock, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&number_of_scales, 1, MPI_INT, 0, MPI_COMM_WORLD); - lastxi = ((mpidata->rank+1) * xiblock)+1; - firstxi = lastxi-xiblock+1; - if (lastxi > number_of_scales) lastxi = number_of_scales; - -#ifdef USE_MAGMA - proc_device = mpidata->rank % device_count; -#else - proc_device = 0; -#endif - MPI_Bcast(&refinemode, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&maxrefiters, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&accuracygoal, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); -} - -void ClusterIterationData::mpibcast(const mixMPI *mpidata) { - c1->mpibcast(mpidata); - const int ndi = c1->nsph * c1->nlim; - const np_int ndit = 2 * ndi; - MPI_Bcast(gaps, c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqev, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqsv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - for (int ti = 0; ti < 2; ti++) { - MPI_Bcast(tqse[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqspe[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(tqss[ti], c1->nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqsps[ti], c1->nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(tqce[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcpe[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcs[ti], 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(tqcps[ti], 3, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - } - MPI_Bcast(gapv, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - for (int gi = 0; gi < 3; gi++) { - MPI_Bcast(gapp[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(gappm[gi], 2, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(gap[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(gapm[gi], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); - } - MPI_Bcast(u, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(us, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(un, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(uns, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(up, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(ups, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(unmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(unsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(upmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(upsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(duk, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(argi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(args, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - for (int ci = 0; ci < 4; ci++) { - MPI_Bcast(cextlr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cext[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cmullr[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(cmul[ci], 4, MPI_DOUBLE, 0, MPI_COMM_WORLD); - } - for (int zi = 0; zi < c1->lm; zi++) { - for (int zj = 0; zj < 3; zj++) { - for (int zk = 0; zk < 2; zk++) { - MPI_Bcast(zpv[zi][zj][zk], 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); - } - } - } - // since MPI expects an int argument for the number of elements to transfer in one go, transfer am one row at a time - for (int ai = 0; ai < ndit; ai++) { - MPI_Bcast(am[ai], ndit, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - } - MPI_Bcast(&arg, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); - MPI_Bcast(&scan, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&cfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&cfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&qsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&wn, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&xip, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&sqsfi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&vk, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&xiblock, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&number_of_scales, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&refinemode, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&maxrefiters, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast(&accuracygoal, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); -} -#endif - -ClusterIterationData::~ClusterIterationData() { - const int nsph = c1->nsph; - delete[] am_vector; - delete[] am; - for (int zi = c1->lm - 1; zi > -1; zi--) { - for (int zj = 2; zj > -1; zj--) { - delete[] zpv[zi][zj][1]; - delete[] zpv[zi][zj][0]; - delete[] zpv[zi][zj]; - } - delete[] zpv[zi]; - } - delete[] zpv; - delete c1; - delete[] gaps; - for (int ti = 1; ti > -1; ti--) { - delete[] tqse[ti]; - delete[] tqss[ti]; - delete[] tqspe[ti]; - delete[] tqsps[ti]; - delete[] tqce[ti]; - delete[] tqcpe[ti]; - delete[] tqcs[ti]; - delete[] tqcps[ti]; - } - delete[] tqse; - delete[] tqss; - delete[] tqspe; - delete[] tqsps; - delete[] tqce; - delete[] tqcpe; - delete[] tqcs; - delete[] tqcps; - delete[] tqev; - delete[] tqsv; - for (int gi = 2; gi > -1; gi--) { - delete[] gapp[gi]; - delete[] gappm[gi]; - delete[] gap[gi]; - delete[] gapm[gi]; - } - delete[] gapp; - delete[] gappm; - delete[] gap; - delete[] gapm; - delete[] gapv; - delete[] u; - delete[] us; - delete[] un; - delete[] uns; - delete[] up; - delete[] ups; - delete[] unmp; - delete[] unsmp; - delete[] upmp; - delete[] upsmp; - delete[] argi; - delete[] args; - delete[] duk; - for (int ci = 3; ci > -1; ci--) { - delete[] cextlr[ci]; - delete[] cext[ci]; - delete[] cmullr[ci]; - delete[] cmul[ci]; - } - delete[] cextlr; - delete[] cext; - delete[] cmullr; - delete[] cmul; -} - // >>> ParticleDescriptor class implementation. <<< // ParticleDescriptor::ParticleDescriptor(GeometryConfiguration *gconf, ScattererConfiguration *sconf) { _class_type = BASE_TYPE; @@ -1367,7 +832,8 @@ ParticleDescriptorCluster::ParticleDescriptorCluster(const ParticleDescriptorClu ecscm[ci] = rhs.ecscm[ci]; } v3j0 = new double[_nv3j]; - for (int vj = 0; vj < _nv3j; vj++) v3j0[vj] = rhs.v3j0[_nv3j]; + // for (int vj = 0; vj < _nv3j; vj++) v3j0[vj] = rhs.v3j0[_nv3j]; REPORT: AAAAH! ORRORE E DISGUSTO! + for (int vj = 0; vj < _nv3j; vj++) v3j0[vj] = rhs.v3j0[vj]; ind3j = new int*[_lm + 1]; for (int ii = 0; ii <= _lm; ii++) ind3j[ii] = vec_ind3j + (_lm * ii); rac3j = new double[_lmtpo]; diff --git a/src/libnptm/Configuration.cpp b/src/libnptm/Configuration.cpp index fe21233dc421748e69f40c12d1955a86b4979e4e..fe78967c8e6a18705b076d266cd29fe4686c8f69 100644 --- a/src/libnptm/Configuration.cpp +++ b/src/libnptm/Configuration.cpp @@ -222,13 +222,18 @@ GeometryConfiguration* GeometryConfiguration::from_legacy(const std::string& fil throw ex; } int _nsph = 0, _lm = 0, _in_pol = 0, _npnt = 0, _npntts = 0, _isam = 0; - int _li = 0, _le = 0, _iavm = 0; + int _li = 0, _le = 0, _iavm = 0, num_params = 0; np_int _mxndm = 0; regex re = regex("-?[0-9]+"); + str_target = file_lines[last_read_line]; + while(regex_search(str_target, m, re)) { + str_target = m.suffix().str(); + num_params++; + } str_target = file_lines[last_read_line++]; regex_search(str_target, m, re); _nsph = stoi(m.str()); - if (_nsph == 1) { + if (num_params == 6) { for (int ri = 0; ri < 5; ri++) { str_target = m.suffix().str(); regex_search(str_target, m, re); @@ -238,7 +243,7 @@ GeometryConfiguration* GeometryConfiguration::from_legacy(const std::string& fil if (ri == 3) _npntts = stoi(m.str()); if (ri == 4) _isam = stoi(m.str()); } - } else { + } else if (num_params == 9) { for (int ri = 0; ri < 8; ri++) { str_target = m.suffix().str(); regex_search(str_target, m, re); @@ -251,6 +256,9 @@ GeometryConfiguration* GeometryConfiguration::from_legacy(const std::string& fil if (ri == 6) _iavm = stoi(m.str()); if (ri == 7) _isam = stoi(m.str()); } + } else { + OpenConfigurationFileException ex("ERROR: " + file_name + " is not a recognized input file."); + throw ex; } double *x, *y, *z; x = new double[_nsph]; @@ -312,15 +320,14 @@ GeometryConfiguration* GeometryConfiguration::from_legacy(const std::string& fil regex_search(str_target, m, re); fjwtm = stoi(m.str()); GeometryConfiguration *conf = new GeometryConfiguration( - _nsph, _lm, _in_pol, _npnt, _npntts, _isam, - _li, _le, _mxndm, _iavm, - x, y, z, - in_th_start, in_th_step, in_th_end, - sc_th_start, sc_th_step, sc_th_end, - in_ph_start, in_ph_step, in_ph_end, - sc_ph_start, sc_ph_step, sc_ph_end, - fjwtm - ); + _nsph, _lm, _in_pol, _npnt, _npntts, _isam, + _li, _le, _mxndm, _iavm, x, y, z, + in_th_start, in_th_step, in_th_end, + sc_th_start, sc_th_step, sc_th_end, + in_ph_start, in_ph_step, in_ph_end, + sc_ph_start, sc_ph_step, sc_ph_end, + fjwtm + ); delete[] file_lines; return conf; } @@ -951,22 +958,10 @@ ScattererConfiguration* ScattererConfiguration::from_legacy(const std::string& f input.close(); ScattererConfiguration *conf = new ScattererConfiguration( - _nsph, - configurations, - _xi_vec, - _nxi, - "XIV", - _iog_vec, - _ros_vec, - _nshl_vec, - _rcf_vec, - _idfc, - _dc0m, - (_ies == 1), - _exdc, - _wp, - _xip - ); + _nsph, configurations, _xi_vec, _nxi, "XIV", _iog_vec, _ros_vec, + _nshl_vec, _rcf_vec, _idfc, _dc0m, (_ies == 1), _exdc, _wp, _xip + ); + delete[] _xi_vec; return conf; } diff --git a/src/libnptm/algebraic.cpp b/src/libnptm/algebraic.cpp index e0363e2133e233b8af0f622f8536f987485b5a60..33158f0c0dec340389d8fb61ca34823b13ddb73f 100644 --- a/src/libnptm/algebraic.cpp +++ b/src/libnptm/algebraic.cpp @@ -57,7 +57,7 @@ using namespace std; #endif // >>> FALL-BACK FUNCTIONS DECLARATION <<< // -extern void lucin(dcomplex **mat, np_int max_size, np_int size, int &ier); +extern void lucin(dcomplex **am, const np_int nddmst, np_int n, int &ier); // >>> END OF FALL-BACK FUNCTIONS <<< // using namespace std; diff --git a/src/libnptm/file_io.cpp b/src/libnptm/file_io.cpp index 28efaba4ab2c8da59cc1678441ce2192db90dc26..376a546560600ab2c1a55b3b10a926c444933ed5 100644 --- a/src/libnptm/file_io.cpp +++ b/src/libnptm/file_io.cpp @@ -94,7 +94,7 @@ HDFFile* HDFFile::from_schema( herr_t status; string *rec_types = schema.get_record_types(); string *rec_names = schema.get_record_names(); - string known_types[] = {"INT32", "FLOAT64", "COMPLEX128"}; + string known_types[] = {"INT32", "FLOAT64", "COMPLEX128", "INT64", "INT16"}; int rec_num = schema.get_record_number(); regex re; smatch m; @@ -113,8 +113,10 @@ HDFFile* HDFFile::from_schema( if (type_index == 1) data_type = H5Tcopy(H5T_NATIVE_INT); else if (type_index == 2) data_type = H5Tcopy(H5T_NATIVE_DOUBLE); else if (type_index == 3) data_type = H5Tcopy(H5T_NATIVE_DOUBLE); + else if (type_index == 4) data_type = H5Tcopy(H5T_NATIVE_LONG); + else if (type_index == 5) data_type = H5Tcopy(H5T_NATIVE_SHORT); } - if (type_index == 3) break; + if (type_index == 5) break; } if (found_type) { re = regex("[0-9]+"); @@ -161,7 +163,7 @@ herr_t HDFFile::read( hid_t mem_space_id, hid_t file_space_id, hid_t dapl_id, hid_t dxpl_id ) { - string known_types[] = {"INT32", "FLOAT64"}; + string known_types[] = {"INT32", "FLOAT64", "COMPLEX128", "INT64", "INT16"}; regex re; smatch m; bool found_type = false; @@ -169,7 +171,7 @@ herr_t HDFFile::read( while (!found_type) { re = regex(known_types[type_index++]); found_type = regex_search(data_type, m, re); - if (type_index == 2) break; + if (type_index == 5) break; } if (found_type) { hid_t dataset_id = H5Dopen2(file_id, dataset_name.c_str(), dapl_id); @@ -179,6 +181,12 @@ herr_t HDFFile::read( mem_type_id = H5T_NATIVE_INT; break; case 2: mem_type_id = H5T_NATIVE_DOUBLE; break; + case 3: + mem_type_id = H5T_NATIVE_DOUBLE; break; + case 4: + mem_type_id = H5T_NATIVE_LONG; break; + case 5: + mem_type_id = H5T_NATIVE_SHORT; break; default: throw UnrecognizedParameterException("unrecognized data type \"" + data_type + "\""); } @@ -200,7 +208,7 @@ herr_t HDFFile::write( hid_t mem_space_id, hid_t file_space_id, hid_t dapl_id, hid_t dxpl_id ) { - string known_types[] = {"INT32", "FLOAT64", "COMPLEX128"}; + string known_types[] = {"INT32", "FLOAT64", "COMPLEX128", "INT64", "INT16"}; regex re; smatch m; bool found_type = false; @@ -208,7 +216,7 @@ herr_t HDFFile::write( while (!found_type) { re = regex(known_types[type_index++]); found_type = regex_search(data_type, m, re); - if (type_index == 3) break; + if (type_index == 5) break; } if (found_type) { hid_t dataset_id = H5Dopen2(file_id, dataset_name.c_str(), dapl_id); @@ -220,6 +228,10 @@ herr_t HDFFile::write( mem_type_id = H5T_NATIVE_DOUBLE; break; case 3: mem_type_id = H5T_NATIVE_DOUBLE; break; + case 4: + mem_type_id = H5T_NATIVE_LONG; break; + case 5: + mem_type_id = H5T_NATIVE_SHORT; break; default: throw UnrecognizedParameterException("unrecognized data type \"" + data_type + "\""); } diff --git a/src/libnptm/outputs.cpp b/src/libnptm/outputs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36abbc3b2a5aad669a10e872a74e68c576061c5d --- /dev/null +++ b/src/libnptm/outputs.cpp @@ -0,0 +1,5902 @@ +/* Copyright (C) 2024 INAF - Osservatorio Astronomico di Cagliari + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + A copy of the GNU General Public License is distributed along with + this program in the COPYING file. If not, see: <https://www.gnu.org/licenses/>. + */ + +/*! \file outputs.cpp + * + * \brief Implementation of the code output format system. + */ +#include <cstdio> +#include <exception> +#include <string> +#include <cstring> +#include <hdf5.h> + +#ifdef USE_MPI +#ifndef MPI_VERSION +#include <mpi.h> +#endif +#endif + +#ifndef INCLUDE_ERRORS_H_ +#include "../include/errors.h" +#endif + +#ifndef INCLUDE_LIST_H_ +#include "../include/List.h" +#endif + +#ifndef INCLUDE_TYPES_H_ +#include "../include/types.h" +#endif + +#ifndef INCLUDE_CONFIGURATION_H_ +#include "../include/Configuration.h" +#endif + +#ifndef INCLUDE_FILE_IO_H_ +#include "../include/file_io.h" +#endif + +#ifndef INCLUDE_OUTPUTS_H_ +#include "../include/outputs.h" +#endif + +using namespace std; + +// >>> ClusterOutputInfo CLASS IMPLEMENTATION <<< +ClusterOutputInfo::ClusterOutputInfo( + ScattererConfiguration *sc, GeometryConfiguration *gc, + const mixMPI *mpidata, int first_xi, int xi_length +) { + nsph = gc->number_of_spheres; + li = gc->li; + le = gc->le; + lm = gc->l_max; + mxndm = gc->mxndm; + inpol = gc->in_pol; + npnt = gc->npnt; + npntts = gc->npntts; + iavm = gc->iavm; + isam = gc->isam; + jwtm = gc->jwtm; + // Get spherical constituent coordinates + vec_x_coords = new double[nsph]; + vec_y_coords = new double[nsph]; + vec_z_coords = new double[nsph]; + for (int nsi = 0; nsi < nsph; nsi++) { + vec_x_coords[nsi] = gc->get_sph_x(nsi); + vec_y_coords[nsi] = gc->get_sph_y(nsi); + vec_z_coords[nsi] = gc->get_sph_z(nsi); + } + // Get directional information + th = gc->in_theta_start; + thstp = gc->in_theta_step; + thlst = gc->in_theta_end; + ths = gc->sc_theta_start; + thsstp = gc->sc_theta_step; + thslst = gc->sc_theta_end; + _num_theta = (thstp == 0.0) ? 1 : 1 + int((thlst - th) / thstp); + _num_thetas = (thsstp == 0.0) ? 1 : 1 + int((thslst - ths) / thsstp); + ph = gc->in_phi_start; + phstp = gc->in_phi_step; + phlst = gc->in_phi_end; + phs = gc->sc_phi_start; + phsstp = gc->sc_phi_step; + phslst = gc->sc_phi_end; + _num_phi = (phstp == 0.0) ? 1 : 1 + int((phlst - ph) / phstp); + _num_phis = (phsstp == 0.0) ? 1 : 1 + int((phslst - phs) / phsstp); + ndirs = _num_theta * _num_thetas * _num_phi * _num_phis; + // Get scattering problem configuration + double exdc = sc->exdc; + exri = sqrt(exdc); + idfc = sc->idfc; + nxi = sc->number_of_scales; + _first_xi = first_xi; + xi_block_size = (xi_length == 0) ? nxi - (_first_xi - 1) : xi_length; + vec_jxi = new int[xi_block_size](); + vec_ier = new short[xi_block_size](); + vec_vk = new double[xi_block_size](); + vec_xi = new double[xi_block_size](); + configurations = sc->configurations; + vec_sphere_sizes = new double[xi_block_size * configurations](); + vec_sphere_ref_indices = new dcomplex[xi_block_size * configurations](); + vec_sphere_scs = new double[xi_block_size * configurations](); + vec_sphere_abs = new double[xi_block_size * configurations](); + vec_sphere_exs = new double[xi_block_size * configurations](); + vec_sphere_albs = new double[xi_block_size * configurations](); + vec_sphere_sqscs = new double[xi_block_size * configurations](); + vec_sphere_sqabs = new double[xi_block_size * configurations](); + vec_sphere_sqexs = new double[xi_block_size * configurations](); + vec_fsas = new dcomplex[xi_block_size * configurations](); + vec_qschus = new double[xi_block_size * configurations](); + vec_pschus = new double[xi_block_size * configurations](); + vec_s0mags = new double[xi_block_size * configurations](); + vec_cosavs = new double[xi_block_size * configurations](); + vec_raprs = new double[xi_block_size * configurations](); + vec_tqek1 = new double[xi_block_size * configurations](); + vec_tqsk1 = new double[xi_block_size * configurations](); + vec_tqek2 = new double[xi_block_size * configurations](); + vec_tqsk2 = new double[xi_block_size * configurations](); + vec_fsat = new dcomplex[xi_block_size](); + vec_qschut = new double[xi_block_size](); + vec_pschut = new double[xi_block_size](); + vec_s0magt = new double[xi_block_size](); + tgs = 0.0; + vec_scc1 = new double[xi_block_size](); + vec_scc2 = new double[xi_block_size](); + vec_abc1 = new double[xi_block_size](); + vec_abc2 = new double[xi_block_size](); + vec_exc1 = new double[xi_block_size](); + vec_exc2 = new double[xi_block_size](); + vec_albedc1 = new double[xi_block_size](); + vec_albedc2 = new double[xi_block_size](); + vec_qscamc1 = new double[xi_block_size](); + vec_qscamc2 = new double[xi_block_size](); + vec_qabsmc1 = new double[xi_block_size](); + vec_qabsmc2 = new double[xi_block_size](); + vec_qextmc1 = new double[xi_block_size](); + vec_qextmc2 = new double[xi_block_size](); + vec_sccrt1 = new double[xi_block_size](); + vec_sccrt2 = new double[xi_block_size](); + vec_abcrt1 = new double[xi_block_size](); + vec_abcrt2 = new double[xi_block_size](); + vec_excrt1 = new double[xi_block_size](); + vec_excrt2 = new double[xi_block_size](); + vec_fsac11 = new dcomplex[xi_block_size](); + vec_fsac21 = new dcomplex[xi_block_size](); + vec_fsac22 = new dcomplex[xi_block_size](); + vec_fsac12 = new dcomplex[xi_block_size](); + vec_qschuc1 = new double[xi_block_size](); + vec_qschuc2 = new double[xi_block_size](); + vec_pschuc1 = new double[xi_block_size](); + vec_pschuc2 = new double[xi_block_size](); + vec_s0magc1 = new double[xi_block_size](); + vec_s0magc2 = new double[xi_block_size](); + vec_cosavc1 = new double[xi_block_size](); + vec_cosavc2 = new double[xi_block_size](); + vec_raprc1 = new double[xi_block_size](); + vec_raprc2 = new double[xi_block_size](); + vec_fkc1 = new double[xi_block_size](); + vec_fkc2 = new double[xi_block_size](); + vec_dir_tidg = new double[_num_theta]; + vec_dir_pidg = new double[_num_phi]; + vec_dir_tsdg = new double[_num_thetas]; + vec_dir_psdg = new double[_num_phis]; + // Initialize directions (they are scale-independent) + double cti = th, cpi = ph, cts = ths, cps = phs; + for (int di = 0; di < _num_theta; di++) { + vec_dir_tidg[di] = cti; + cti += thstp; + } + for (int di = 0; di < _num_thetas; di++) { + vec_dir_tsdg[di] = cts; + cts += thsstp; + } + for (int di = 0; di < _num_phi; di++) { + vec_dir_pidg[di] = cpi; + cpi += phstp; + } + for (int di = 0; di < _num_phis; di++) { + vec_dir_psdg[di] = cps; + cps += phsstp; + } + vec_dir_scand = new double[ndirs](); + vec_dir_cfmp = new double[ndirs](); + vec_dir_sfmp = new double[ndirs](); + vec_dir_cfsp = new double[ndirs](); + vec_dir_sfsp = new double[ndirs](); + vec_dir_un = new double[3 * ndirs](); + vec_dir_uns = new double[3 * ndirs](); + vec_dir_sas11 = new dcomplex[ndirs * configurations * xi_block_size](); + vec_dir_sas21 = new dcomplex[ndirs * configurations * xi_block_size](); + vec_dir_sas12 = new dcomplex[ndirs * configurations * xi_block_size](); + vec_dir_sas22 = new dcomplex[ndirs * configurations * xi_block_size](); + vec_dir_muls = new double[16 * ndirs * configurations * xi_block_size](); + vec_dir_mulslr = new double[16 * ndirs * configurations * xi_block_size](); + vec_dir_sat11 = new dcomplex[ndirs * xi_block_size](); + vec_dir_sat21 = new dcomplex[ndirs * xi_block_size](); + vec_dir_sat12 = new dcomplex[ndirs * xi_block_size](); + vec_dir_sat22 = new dcomplex[ndirs * xi_block_size](); + vec_dir_scc1 = new double[ndirs * xi_block_size](); + vec_dir_scc2 = new double[ndirs * xi_block_size](); + vec_dir_abc1 = new double[ndirs * xi_block_size](); + vec_dir_abc2 = new double[ndirs * xi_block_size](); + vec_dir_exc1 = new double[ndirs * xi_block_size](); + vec_dir_exc2 = new double[ndirs * xi_block_size](); + vec_dir_albedc1 = new double[ndirs * xi_block_size](); + vec_dir_albedc2 = new double[ndirs * xi_block_size](); + vec_dir_qscc1 = new double[ndirs * xi_block_size](); + vec_dir_qscc2 = new double[ndirs * xi_block_size](); + vec_dir_qabc1 = new double[ndirs * xi_block_size](); + vec_dir_qabc2 = new double[ndirs * xi_block_size](); + vec_dir_qexc1 = new double[ndirs * xi_block_size](); + vec_dir_qexc2 = new double[ndirs * xi_block_size](); + vec_dir_sccrt1 = new double[ndirs * xi_block_size](); + vec_dir_sccrt2 = new double[ndirs * xi_block_size](); + vec_dir_abcrt1 = new double[ndirs * xi_block_size](); + vec_dir_abcrt2 = new double[ndirs * xi_block_size](); + vec_dir_excrt1 = new double[ndirs * xi_block_size](); + vec_dir_excrt2 = new double[ndirs * xi_block_size](); + vec_dir_fsac11 = new dcomplex[ndirs * xi_block_size](); + vec_dir_fsac21 = new dcomplex[ndirs * xi_block_size](); + vec_dir_fsac12 = new dcomplex[ndirs * xi_block_size](); + vec_dir_fsac22 = new dcomplex[ndirs * xi_block_size](); + vec_dir_sac11 = new dcomplex[ndirs * xi_block_size](); + vec_dir_sac21 = new dcomplex[ndirs * xi_block_size](); + vec_dir_sac12 = new dcomplex[ndirs * xi_block_size](); + vec_dir_sac22 = new dcomplex[ndirs * xi_block_size](); + vec_dir_qschuc1 = new double[ndirs * xi_block_size](); + vec_dir_qschuc2 = new double[ndirs * xi_block_size](); + vec_dir_pschuc1 = new double[ndirs * xi_block_size](); + vec_dir_pschuc2 = new double[ndirs * xi_block_size](); + vec_dir_s0magc1 = new double[ndirs * xi_block_size](); + vec_dir_s0magc2 = new double[ndirs * xi_block_size](); + vec_dir_cosavc1 = new double[ndirs * xi_block_size](); + vec_dir_cosavc2 = new double[ndirs * xi_block_size](); + vec_dir_raprc1 = new double[ndirs * xi_block_size](); + vec_dir_raprc2 = new double[ndirs * xi_block_size](); + vec_dir_flc1 = new double[ndirs * xi_block_size](); + vec_dir_flc2 = new double[ndirs * xi_block_size](); + vec_dir_frc1 = new double[ndirs * xi_block_size](); + vec_dir_frc2 = new double[ndirs * xi_block_size](); + vec_dir_fkc1 = new double[ndirs * xi_block_size](); + vec_dir_fkc2 = new double[ndirs * xi_block_size](); + vec_dir_fxc1 = new double[ndirs * xi_block_size](); + vec_dir_fxc2 = new double[ndirs * xi_block_size](); + vec_dir_fyc1 = new double[ndirs * xi_block_size](); + vec_dir_fyc2 = new double[ndirs * xi_block_size](); + vec_dir_fzc1 = new double[ndirs * xi_block_size](); + vec_dir_fzc2 = new double[ndirs * xi_block_size](); + vec_dir_tqelc1 = new double[ndirs * xi_block_size](); + vec_dir_tqelc2 = new double[ndirs * xi_block_size](); + vec_dir_tqerc1 = new double[ndirs * xi_block_size](); + vec_dir_tqerc2 = new double[ndirs * xi_block_size](); + vec_dir_tqekc1 = new double[ndirs * xi_block_size](); + vec_dir_tqekc2 = new double[ndirs * xi_block_size](); + vec_dir_tqexc1 = new double[ndirs * xi_block_size](); + vec_dir_tqexc2 = new double[ndirs * xi_block_size](); + vec_dir_tqeyc1 = new double[ndirs * xi_block_size](); + vec_dir_tqeyc2 = new double[ndirs * xi_block_size](); + vec_dir_tqezc1 = new double[ndirs * xi_block_size](); + vec_dir_tqezc2 = new double[ndirs * xi_block_size](); + vec_dir_tqslc1 = new double[ndirs * xi_block_size](); + vec_dir_tqslc2 = new double[ndirs * xi_block_size](); + vec_dir_tqsrc1 = new double[ndirs * xi_block_size](); + vec_dir_tqsrc2 = new double[ndirs * xi_block_size](); + vec_dir_tqskc1 = new double[ndirs * xi_block_size](); + vec_dir_tqskc2 = new double[ndirs * xi_block_size](); + vec_dir_tqsxc1 = new double[ndirs * xi_block_size](); + vec_dir_tqsxc2 = new double[ndirs * xi_block_size](); + vec_dir_tqsyc1 = new double[ndirs * xi_block_size](); + vec_dir_tqsyc2 = new double[ndirs * xi_block_size](); + vec_dir_tqszc1 = new double[ndirs * xi_block_size](); + vec_dir_tqszc2 = new double[ndirs * xi_block_size](); + vec_dir_mulc = new double[16 * ndirs * xi_block_size](); + vec_dir_mulclr = new double[16 * ndirs * xi_block_size](); +} + +ClusterOutputInfo::ClusterOutputInfo(const std::string &hdf5_name) { + unsigned int flags = H5F_ACC_RDONLY; + HDFFile *hdf_file = new HDFFile(hdf5_name, flags); + herr_t status = hdf_file->get_status(); + string str_name, str_type; + if (status == 0) { + status = hdf_file->read("NSPH", "INT32_(1)", &nsph); + status = hdf_file->read("LI", "INT32_(1)", &li); + status = hdf_file->read("LE", "INT32_(1)", &le); + status = hdf_file->read("LM", "INT32_(1)", &lm); + long tmp; + status = hdf_file->read("MXNDM", "INT64_(1)", &tmp); + mxndm = (np_int)tmp; + status = hdf_file->read("INPOL", "INT32_(1)", &inpol); + status = hdf_file->read("NPNT", "INT32_(1)", &npnt); + status = hdf_file->read("NPNTTS", "INT32_(1)", &npntts); + status = hdf_file->read("IAVM", "INT32_(1)", &iavm); + status = hdf_file->read("ISAM", "INT32_(1)", &isam); + status = hdf_file->read("JWTM", "INT32_(1)", &jwtm); + str_type = "FLOAT64_(" + to_string(nsph) + ")"; + vec_x_coords = new double[nsph]; + vec_y_coords = new double[nsph]; + vec_z_coords = new double[nsph]; + status = hdf_file->read("VEC_SPH_X", str_type, vec_x_coords); + status = hdf_file->read("VEC_SPH_Y", str_type, vec_y_coords); + status = hdf_file->read("VEC_SPH_Z", str_type, vec_z_coords); + status = hdf_file->read("TH_START", "FLOAT64_(1)", &th); + status = hdf_file->read("TH_STEP", "FLOAT64_(1)", &thstp); + status = hdf_file->read("TH_END", "FLOAT64_(1)", &thlst); + _num_theta = (thstp == 0.0) ? 1 : 1 + int((thlst - th) / thstp); + status = hdf_file->read("THS_START", "FLOAT64_(1)", &ths); + status = hdf_file->read("THS_STEP", "FLOAT64_(1)", &thsstp); + status = hdf_file->read("THS_END", "FLOAT64_(1)", &thslst); + _num_thetas = (thsstp == 0.0) ? 1 : 1 + int((thslst - ths) / thsstp); + status = hdf_file->read("PH_START", "FLOAT64_(1)", &ph); + status = hdf_file->read("PH_STEP", "FLOAT64_(1)", &phstp); + status = hdf_file->read("PH_END", "FLOAT64_(1)", &phlst); + _num_phi = (phstp == 0.0) ? 1 : 1 + int((phlst - ph) / phstp); + status = hdf_file->read("PHS_START", "FLOAT64_(1)", &phs); + status = hdf_file->read("PHS_STEP", "FLOAT64_(1)", &phsstp); + status = hdf_file->read("PHS_END", "FLOAT64_(1)", &phslst); + _num_phis = (phsstp == 0.0) ? 1 : 1 + int((phslst - phs) / phsstp); + ndirs = _num_theta * _num_thetas * _num_phi * _num_phis; + status = hdf_file->read("EXRI", "FLOAT64_(1)", &exri); + status = hdf_file->read("IDFC", "INT32_(1)", &idfc); + status = hdf_file->read("XI1", "INT32_(1)", &_first_xi); + status = hdf_file->read("NXI", "INT32_(1)", &xi_block_size); + nxi = (_first_xi == 1) ? xi_block_size : xi_block_size + _first_xi; + str_type = "INT32_(" + to_string(xi_block_size) + ")"; + vec_jxi = new int[xi_block_size]; + status = hdf_file->read("VEC_JXI", str_type, vec_jxi); + str_type = "INT16_(" + to_string(xi_block_size) + ")"; + vec_ier = new short[xi_block_size]; + status = hdf_file->read("VEC_IER", str_type, vec_ier); + str_type = "FLOAT64_(" + to_string(xi_block_size) + ")"; + vec_vk = new double[xi_block_size]; + status = hdf_file->read("VEC_VK", str_type, vec_vk); + vec_xi = new double[xi_block_size]; + status = hdf_file->read("VEC_VK", str_type, vec_xi); + status = hdf_file->read("NCONF", "INT32_(1)", &configurations); + str_type = "FLOAT64_(" + to_string(xi_block_size * configurations) + ")"; + vec_sphere_sizes = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_SPH_SIZES", str_type, vec_sphere_sizes); + str_type = "FLOAT64_(" + to_string(2 * xi_block_size * configurations) + ")"; + vec_sphere_ref_indices = new dcomplex[xi_block_size * configurations]; + status = hdf_file->read("VEC_SPH_REFRI", str_type, vec_sphere_ref_indices); + str_type = "FLOAT64_(" + to_string(xi_block_size * configurations) + ")"; + vec_sphere_scs = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_SPH_SCS", str_type, vec_sphere_scs); + vec_sphere_abs = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_SPH_ABS", str_type, vec_sphere_abs); + vec_sphere_exs = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_SPH_EXS", str_type, vec_sphere_exs); + vec_sphere_albs = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_SPH_ALBS", str_type, vec_sphere_albs); + vec_sphere_sqscs = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_SPH_SQSCS", str_type, vec_sphere_sqscs); + vec_sphere_sqabs = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_SPH_SQABS", str_type, vec_sphere_sqabs); + vec_sphere_sqexs = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_SPH_SQEXS", str_type, vec_sphere_sqexs); + str_type = "FLOAT64_(" + to_string(2 * xi_block_size * configurations) + ")"; + vec_fsas = new dcomplex[xi_block_size * configurations]; + status = hdf_file->read("VEC_FSAS", str_type, vec_fsas); + str_type = "FLOAT64_(" + to_string(xi_block_size * configurations) + ")"; + vec_qschus = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_QSCHUS", str_type, vec_qschus); + vec_pschus = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_PSCHUS", str_type, vec_pschus); + vec_s0mags = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_S0MAGS", str_type, vec_s0mags); + vec_cosavs = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_COSAVS", str_type, vec_cosavs); + vec_raprs = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_RAPRS", str_type, vec_raprs); + vec_tqek1 = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_TQEK1", str_type, vec_tqek1); + vec_tqsk1 = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_TQSK1", str_type, vec_tqsk1); + vec_tqek2 = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_TQEK2", str_type, vec_tqek2); + vec_tqsk2 = new double[xi_block_size * configurations]; + status = hdf_file->read("VEC_TQSK2", str_type, vec_tqsk2); + str_type = "FLOAT64_(" + to_string(2 * xi_block_size) + ")"; + vec_fsat = new dcomplex[xi_block_size]; + status = hdf_file->read("VEC_FSAT", str_type, vec_fsat); + str_type = "FLOAT64_(" + to_string(xi_block_size) + ")"; + vec_qschut = new double[xi_block_size]; + status = hdf_file->read("VEC_QSCHUT", str_type, vec_qschut); + vec_pschut = new double[xi_block_size]; + status = hdf_file->read("VEC_PSCHUT", str_type, vec_pschut); + vec_s0magt = new double[xi_block_size]; + status = hdf_file->read("VEC_S0MAGT", str_type, vec_s0magt); + vec_scc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_SCC1", str_type, vec_scc1); + vec_scc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_SCC2", str_type, vec_scc2); + vec_abc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_ABC1", str_type, vec_abc1); + vec_abc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_ABC2", str_type, vec_abc2); + vec_exc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_EXC1", str_type, vec_exc1); + vec_exc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_EXC2", str_type, vec_exc2); + vec_albedc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_ALBEDC1", str_type, vec_albedc1); + vec_albedc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_ALBEDC2", str_type, vec_albedc2); + vec_qscamc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_QSCAMC1", str_type, vec_qscamc1); + vec_qscamc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_QSCAMC2", str_type, vec_qscamc2); + vec_qabsmc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_QABSMC1", str_type, vec_qabsmc1); + vec_qabsmc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_QABSMC2", str_type, vec_qabsmc2); + vec_qextmc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_QEXTMC1", str_type, vec_qextmc1); + vec_qextmc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_QEXTMC2", str_type, vec_qextmc2); + vec_sccrt1 = new double[xi_block_size]; + status = hdf_file->read("VEC_SCCRT1", str_type, vec_sccrt1); + vec_sccrt2 = new double[xi_block_size]; + status = hdf_file->read("VEC_SCCRT2", str_type, vec_sccrt2); + vec_abcrt1 = new double[xi_block_size]; + status = hdf_file->read("VEC_ABCRT1", str_type, vec_abcrt1); + vec_abcrt2 = new double[xi_block_size]; + status = hdf_file->read("VEC_ABCRT2", str_type, vec_abcrt2); + vec_excrt1 = new double[xi_block_size]; + status = hdf_file->read("VEC_EXCRT1", str_type, vec_excrt1); + vec_excrt2 = new double[xi_block_size]; + status = hdf_file->read("VEC_EXCRT2", str_type, vec_excrt2); + str_type = "FLOAT64_(" + to_string(2 * xi_block_size) + ")"; + vec_fsac11 = new dcomplex[xi_block_size]; + status = hdf_file->read("VEC_FSAC11", str_type, vec_fsac11); + vec_fsac21 = new dcomplex[xi_block_size]; + status = hdf_file->read("VEC_FSAC21", str_type, vec_fsac21); + vec_fsac22 = new dcomplex[xi_block_size]; + status = hdf_file->read("VEC_FSAC22", str_type, vec_fsac22); + vec_fsac12 = new dcomplex[xi_block_size]; + status = hdf_file->read("VEC_FSAC12", str_type, vec_fsac12); + str_type = "FLOAT64_(" + to_string(xi_block_size) + ")"; + vec_qschuc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_QSCHUC1", str_type, vec_qschuc1); + vec_qschuc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_QSCHUC2", str_type, vec_qschuc2); + vec_pschuc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_PSCHUC1", str_type, vec_pschuc1); + vec_pschuc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_PSCHUC2", str_type, vec_pschuc2); + vec_s0magc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_S0MAGC1", str_type, vec_s0magc1); + vec_s0magc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_S0MAGC2", str_type, vec_s0magc2); + vec_cosavc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_COSAVC1", str_type, vec_cosavc1); + vec_cosavc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_COSAVC2", str_type, vec_cosavc2); + vec_raprc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_RAPRC1", str_type, vec_raprc1); + vec_raprc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_RAPRC2", str_type, vec_raprc2); + vec_fkc1 = new double[xi_block_size]; + status = hdf_file->read("VEC_FKC1", str_type, vec_fkc1); + vec_fkc2 = new double[xi_block_size]; + status = hdf_file->read("VEC_FKC2", str_type, vec_fkc2); + // Initialize directions (they are scale-independent) + vec_dir_tidg = new double[_num_theta]; + vec_dir_pidg = new double[_num_phi]; + vec_dir_tsdg = new double[_num_thetas]; + vec_dir_psdg = new double[_num_phis]; + double cti = th, cpi = ph, cts = ths, cps = phs; + for (int di = 0; di < _num_theta; di++) { + vec_dir_tidg[di] = cti; + cti += thstp; + } + for (int di = 0; di < _num_thetas; di++) { + vec_dir_tsdg[di] = cts; + cts += thsstp; + } + for (int di = 0; di < _num_phi; di++) { + vec_dir_pidg[di] = cpi; + cpi += phstp; + } + for (int di = 0; di < _num_phis; di++) { + vec_dir_psdg[di] = cps; + cps += phsstp; + } + str_type = "FLOAT64_(" + to_string(ndirs) + ")"; + vec_dir_scand = new double[ndirs]; + status = hdf_file->read("VEC_DIR_SCAN", str_type, vec_dir_scand); + vec_dir_cfmp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_CFMP", str_type, vec_dir_cfmp); + vec_dir_cfsp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_CFSP", str_type, vec_dir_cfsp); + vec_dir_sfmp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_SFMP", str_type, vec_dir_sfmp); + vec_dir_sfsp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_SFSP", str_type, vec_dir_sfsp); + str_type = "FLOAT64_(" + to_string(3 * ndirs) + ")"; + vec_dir_un = new double[3 * ndirs]; + status = hdf_file->read("VEC_DIR_UN", str_type, vec_dir_un); + vec_dir_uns = new double[3 * ndirs]; + status = hdf_file->read("VEC_DIR_UNS", str_type, vec_dir_uns); + str_type = "FLOAT64_(" + to_string(2 * ndirs * configurations * xi_block_size) + ")"; + vec_dir_sas11 = new dcomplex[ndirs * configurations * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS11", str_type, vec_dir_sas11); + vec_dir_sas21 = new dcomplex[ndirs * configurations * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS21", str_type, vec_dir_sas21); + vec_dir_sas12 = new dcomplex[ndirs * configurations * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS12", str_type, vec_dir_sas12); + vec_dir_sas22 = new dcomplex[ndirs * configurations * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS22", str_type, vec_dir_sas22); + str_type = "FLOAT64_(" + to_string(16 * ndirs * configurations * xi_block_size) + ")"; + vec_dir_muls = new double[16 * ndirs *configurations * xi_block_size]; + status = hdf_file->read("VEC_DIR_MULS", str_type, vec_dir_muls); + vec_dir_mulslr = new double[16 * ndirs *configurations * xi_block_size]; + status = hdf_file->read("VEC_DIR_MULSLR", str_type, vec_dir_mulslr); + str_type = "FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"; + vec_dir_sat11 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAT11", str_type, vec_dir_sat11); + vec_dir_sat21 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAT21", str_type, vec_dir_sat21); + vec_dir_sat12 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAT12", str_type, vec_dir_sat12); + vec_dir_sat22 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAT22", str_type, vec_dir_sat22); + str_type = "FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"; + vec_dir_scc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SCC1", str_type, vec_dir_scc1); + vec_dir_scc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SCC2", str_type, vec_dir_scc2); + vec_dir_abc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ABC1", str_type, vec_dir_abc1); + vec_dir_abc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ABC2", str_type, vec_dir_abc2); + vec_dir_exc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_EXC1", str_type, vec_dir_exc1); + vec_dir_exc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_EXC2", str_type, vec_dir_exc2); + vec_dir_albedc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ALBEDC1", str_type, vec_dir_albedc1); + vec_dir_albedc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ALBEDC2", str_type, vec_dir_albedc2); + vec_dir_qscc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_QSCC1", str_type, vec_dir_qscc1); + vec_dir_qscc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_QSCC2", str_type, vec_dir_qscc2); + vec_dir_qabc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_QABC1", str_type, vec_dir_qabc1); + vec_dir_qabc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_QABC2", str_type, vec_dir_qabc2); + vec_dir_qexc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_QEXC1", str_type, vec_dir_qexc1); + vec_dir_qexc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_QEXC2", str_type, vec_dir_qexc2); + vec_dir_sccrt1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SCCRT1", str_type, vec_dir_sccrt1); + vec_dir_sccrt2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SCCRT2", str_type, vec_dir_sccrt2); + vec_dir_abcrt1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ABCRT1", str_type, vec_dir_abcrt1); + vec_dir_abcrt2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ABCRT2", str_type, vec_dir_abcrt2); + vec_dir_excrt1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_EXCRT1", str_type, vec_dir_excrt1); + vec_dir_excrt2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_EXCRT2", str_type, vec_dir_excrt2); + str_type = "FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"; + vec_dir_fsac11 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FSAC11", str_type, vec_dir_fsac11); + vec_dir_fsac21 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FSAC21", str_type, vec_dir_fsac21); + vec_dir_fsac12 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FSAC12", str_type, vec_dir_fsac12); + vec_dir_fsac22 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FSAC22", str_type, vec_dir_fsac22); + vec_dir_sac11 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAC11", str_type, vec_dir_sac11); + vec_dir_sac21 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAC21", str_type, vec_dir_sac21); + vec_dir_sac12 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAC12", str_type, vec_dir_sac12); + vec_dir_sac22 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAC22", str_type, vec_dir_sac22); + str_type = "FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"; + vec_dir_qschuc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_QSCHUC1", str_type, vec_dir_qschuc1); + vec_dir_qschuc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_QSCHUC2", str_type, vec_dir_qschuc2); + vec_dir_pschuc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_PSCHUC1", str_type, vec_dir_pschuc1); + vec_dir_pschuc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_PSCHUC2", str_type, vec_dir_pschuc2); + vec_dir_s0magc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_S0MAGC1", str_type, vec_dir_s0magc1); + vec_dir_s0magc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_S0MAGC2", str_type, vec_dir_s0magc2); + vec_dir_cosavc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_COSAVC1", str_type, vec_dir_cosavc1); + vec_dir_cosavc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_COSAVC2", str_type, vec_dir_cosavc2); + vec_dir_raprc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_RAPRC1", str_type, vec_dir_raprc1); + vec_dir_raprc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_RAPRC2", str_type, vec_dir_raprc2); + vec_dir_flc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FLC1", str_type, vec_dir_flc1); + vec_dir_flc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FLC2", str_type, vec_dir_flc2); + vec_dir_frc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FRC1", str_type, vec_dir_frc1); + vec_dir_frc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FRC2", str_type, vec_dir_frc2); + vec_dir_fkc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FKC1", str_type, vec_dir_fkc1); + vec_dir_fkc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FKC2", str_type, vec_dir_fkc2); + vec_dir_fxc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FXC1", str_type, vec_dir_fxc1); + vec_dir_fxc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FXC2", str_type, vec_dir_fxc2); + vec_dir_fyc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FYC1", str_type, vec_dir_fyc1); + vec_dir_fyc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FYC2", str_type, vec_dir_fyc2); + vec_dir_fzc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FZC1", str_type, vec_dir_fzc1); + vec_dir_fzc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FZC2", str_type, vec_dir_fzc2); + vec_dir_tqelc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQELC1", str_type, vec_dir_tqelc1); + vec_dir_tqelc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQELC2", str_type, vec_dir_tqelc2); + vec_dir_tqerc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQERC1", str_type, vec_dir_tqerc1); + vec_dir_tqerc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQERC2", str_type, vec_dir_tqerc2); + vec_dir_tqekc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEKC1", str_type, vec_dir_tqekc1); + vec_dir_tqekc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEKC2", str_type, vec_dir_tqekc2); + vec_dir_tqexc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEXC1", str_type, vec_dir_tqexc1); + vec_dir_tqexc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEXC2", str_type, vec_dir_tqexc2); + vec_dir_tqeyc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEYC1", str_type, vec_dir_tqeyc1); + vec_dir_tqeyc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEYC2", str_type, vec_dir_tqeyc2); + vec_dir_tqezc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEZC1", str_type, vec_dir_tqezc1); + vec_dir_tqezc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEZC2", str_type, vec_dir_tqezc2); + vec_dir_tqslc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSLC1", str_type, vec_dir_tqslc1); + vec_dir_tqslc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSLC2", str_type, vec_dir_tqslc2); + vec_dir_tqsrc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSRC1", str_type, vec_dir_tqsrc1); + vec_dir_tqsrc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSRC2", str_type, vec_dir_tqsrc2); + vec_dir_tqskc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSKC1", str_type, vec_dir_tqskc1); + vec_dir_tqskc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSKC2", str_type, vec_dir_tqskc2); + vec_dir_tqsxc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSXC1", str_type, vec_dir_tqsxc1); + vec_dir_tqsxc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSXC2", str_type, vec_dir_tqsxc2); + vec_dir_tqsyc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSYC1", str_type, vec_dir_tqsyc1); + vec_dir_tqsyc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSYC2", str_type, vec_dir_tqsyc2); + vec_dir_tqszc1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSZC1", str_type, vec_dir_tqszc1); + vec_dir_tqszc2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSZC2", str_type, vec_dir_tqszc2); + str_type = "FLOAT64_(" + to_string(16 * ndirs * xi_block_size) + ")"; + vec_dir_mulc = new double[16 * ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_MULC", str_type, vec_dir_mulc); + vec_dir_mulclr = new double[16 * ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_MULCLR", str_type, vec_dir_mulclr); + status = hdf_file->close(); + delete hdf_file; + } else { + if (hdf_file != NULL) delete hdf_file; + UnrecognizedFormatException ex("Error: " + hdf5_name + " not recognized as a valid HDF5 file!"); + throw ex; + } +} + +ClusterOutputInfo::~ClusterOutputInfo() { + delete[] vec_x_coords; + delete[] vec_y_coords; + delete[] vec_z_coords; + delete[] vec_jxi; + delete[] vec_ier; + delete[] vec_vk; + delete[] vec_xi; + delete[] vec_sphere_sizes; + delete[] vec_sphere_ref_indices; + delete[] vec_sphere_scs; + delete[] vec_sphere_abs; + delete[] vec_sphere_exs; + delete[] vec_sphere_albs; + delete[] vec_sphere_sqscs; + delete[] vec_sphere_sqabs; + delete[] vec_sphere_sqexs; + delete[] vec_fsas; + delete[] vec_qschus; + delete[] vec_pschus; + delete[] vec_s0mags; + delete[] vec_cosavs; + delete[] vec_raprs; + delete[] vec_tqek1; + delete[] vec_tqsk1; + delete[] vec_tqek2; + delete[] vec_tqsk2; + delete[] vec_fsat; + delete[] vec_qschut; + delete[] vec_pschut; + delete[] vec_s0magt; + delete[] vec_scc1; + delete[] vec_scc2; + delete[] vec_abc1; + delete[] vec_abc2; + delete[] vec_exc1; + delete[] vec_exc2; + delete[] vec_albedc1; + delete[] vec_albedc2; + delete[] vec_sccrt1; + delete[] vec_sccrt2; + delete[] vec_abcrt1; + delete[] vec_abcrt2; + delete[] vec_excrt1; + delete[] vec_excrt2; + delete[] vec_fsac11; + delete[] vec_fsac21; + delete[] vec_fsac22; + delete[] vec_fsac12; + delete[] vec_qschuc1; + delete[] vec_qschuc2; + delete[] vec_pschuc1; + delete[] vec_pschuc2; + delete[] vec_s0magc1; + delete[] vec_s0magc2; + delete[] vec_cosavc1; + delete[] vec_cosavc2; + delete[] vec_raprc1; + delete[] vec_raprc2; + delete[] vec_fkc1; + delete[] vec_fkc2; + delete[] vec_dir_tidg; + delete[] vec_dir_pidg; + delete[] vec_dir_tsdg; + delete[] vec_dir_psdg; + delete[] vec_dir_scand; + delete[] vec_dir_cfmp; + delete[] vec_dir_sfmp; + delete[] vec_dir_cfsp; + delete[] vec_dir_sfsp; + delete[] vec_dir_un; + delete[] vec_dir_uns; + delete[] vec_dir_sas11; + delete[] vec_dir_sas21; + delete[] vec_dir_sas12; + delete[] vec_dir_sas22; + delete[] vec_dir_muls; + delete[] vec_dir_mulslr; + delete[] vec_dir_sat11; + delete[] vec_dir_sat21; + delete[] vec_dir_sat12; + delete[] vec_dir_sat22; + delete[] vec_dir_scc1; + delete[] vec_dir_scc2; + delete[] vec_dir_abc1; + delete[] vec_dir_abc2; + delete[] vec_dir_exc1; + delete[] vec_dir_exc2; + delete[] vec_dir_albedc1; + delete[] vec_dir_albedc2; + delete[] vec_dir_qscc1; + delete[] vec_dir_qscc2; + delete[] vec_dir_qabc1; + delete[] vec_dir_qabc2; + delete[] vec_dir_qexc1; + delete[] vec_dir_qexc2; + delete[] vec_qscamc1; + delete[] vec_qscamc2; + delete[] vec_qabsmc1; + delete[] vec_qabsmc2; + delete[] vec_qextmc1; + delete[] vec_qextmc2; + delete[] vec_dir_sccrt1; + delete[] vec_dir_sccrt2; + delete[] vec_dir_abcrt1; + delete[] vec_dir_abcrt2; + delete[] vec_dir_excrt1; + delete[] vec_dir_excrt2; + delete[] vec_dir_fsac11; + delete[] vec_dir_fsac21; + delete[] vec_dir_fsac12; + delete[] vec_dir_fsac22; + delete[] vec_dir_sac11; + delete[] vec_dir_sac21; + delete[] vec_dir_sac12; + delete[] vec_dir_sac22; + delete[] vec_dir_qschuc1; + delete[] vec_dir_qschuc2; + delete[] vec_dir_pschuc1; + delete[] vec_dir_pschuc2; + delete[] vec_dir_s0magc1; + delete[] vec_dir_s0magc2; + delete[] vec_dir_cosavc1; + delete[] vec_dir_cosavc2; + delete[] vec_dir_raprc1; + delete[] vec_dir_raprc2; + delete[] vec_dir_flc1; + delete[] vec_dir_flc2; + delete[] vec_dir_frc1; + delete[] vec_dir_frc2; + delete[] vec_dir_fkc1; + delete[] vec_dir_fkc2; + delete[] vec_dir_fxc1; + delete[] vec_dir_fxc2; + delete[] vec_dir_fyc1; + delete[] vec_dir_fyc2; + delete[] vec_dir_fzc1; + delete[] vec_dir_fzc2; + delete[] vec_dir_tqelc1; + delete[] vec_dir_tqelc2; + delete[] vec_dir_tqerc1; + delete[] vec_dir_tqerc2; + delete[] vec_dir_tqekc1; + delete[] vec_dir_tqekc2; + delete[] vec_dir_tqexc1; + delete[] vec_dir_tqexc2; + delete[] vec_dir_tqeyc1; + delete[] vec_dir_tqeyc2; + delete[] vec_dir_tqezc1; + delete[] vec_dir_tqezc2; + delete[] vec_dir_tqslc1; + delete[] vec_dir_tqslc2; + delete[] vec_dir_tqsrc1; + delete[] vec_dir_tqsrc2; + delete[] vec_dir_tqskc1; + delete[] vec_dir_tqskc2; + delete[] vec_dir_tqsxc1; + delete[] vec_dir_tqsxc2; + delete[] vec_dir_tqsyc1; + delete[] vec_dir_tqsyc2; + delete[] vec_dir_tqszc1; + delete[] vec_dir_tqszc2; + delete[] vec_dir_mulc; + delete[] vec_dir_mulclr; +} + +long ClusterOutputInfo::compute_size( + ScattererConfiguration *sc, GeometryConfiguration *gc, + int first_xi, int xi_length +) { + long result = sizeof(np_int); + result += 21 * sizeof(int); + result += 14 * sizeof(double); + result += 121 * sizeof(long); + int _nsph = gc->number_of_spheres; + double _th = gc->in_theta_start; + double _thstp = gc->in_theta_step; + double _thlst = gc->in_theta_end; + double _ths = gc->sc_theta_start; + double _thsstp = gc->sc_theta_step; + double _thslst = gc->sc_theta_end; + int num_theta = 1 + int((_thlst - _th) / _thstp); + int num_thetas = 1 + int((_thslst - _ths) / _thsstp); + double _ph = gc->in_phi_start; + double _phstp = gc->in_phi_step; + double _phlst = gc->in_phi_end; + double _phs = gc->sc_phi_start; + double _phsstp = gc->sc_phi_step; + double _phslst = gc->sc_phi_end; + int num_phi = 1 + int((_phlst - _ph) / _phstp); + int num_phis = 1 + int((_phslst - _phs) / _phsstp); + int _ndirs = num_theta * num_thetas * num_phi * num_phis; + int _nxi = sc->number_of_scales; + int _xi_block_size = (xi_length == 0) ? _nxi : xi_length; + int _configurations = sc->configurations; + result += 3 * _nsph * sizeof(double); // sphere coordinate vectors + result += _xi_block_size * sizeof(int); // scale index vector + result += _xi_block_size * sizeof(short); // error code vector + result += 2 * _xi_block_size * sizeof(double); // scale vectors + result += _xi_block_size * _configurations * sizeof(dcomplex); // refraction indices vector + result += 5 * _xi_block_size * _configurations * sizeof(double); // sphere sizes, albedos and cross-sections + result += 3 * _xi_block_size * _configurations * sizeof(double); // cross-section to geometric section ratios + result += _xi_block_size * _configurations * sizeof(dcomplex); // fsas vector + result += 9 * _xi_block_size * _configurations * sizeof(double); // up to tqsk2 vector + result += _xi_block_size * sizeof(dcomplex); // fsat vector + result += 3 * _xi_block_size * sizeof(double); // up to s0magt vector + result += 20 * _xi_block_size * sizeof(double); // up to excrtt vector + result += 4 * _xi_block_size * sizeof(dcomplex); // up to fsac12 vector + result += 12 * _xi_block_size * sizeof(double); // up to fkc vector + result += num_theta * sizeof(double); // vec_dir_tidg; + result += num_thetas * sizeof(double); // vec_dir_tsdg; + result += num_phi * sizeof(double); // vec_dir_pidg; + result += num_phis * sizeof(double); // vec_dir_psdg; + result += 11 * _ndirs * sizeof(double); // up to dir_uns vector + result += 4 * _ndirs * _configurations * _xi_block_size * sizeof(dcomplex); // up to dir_sas22 vector + result += 32 * _ndirs * _configurations * _xi_block_size * sizeof(double); // up to dir_mulslr vector + result += 4 * _ndirs * _xi_block_size * sizeof(dcomplex); // up to dir_sat22 vector + result += 20 * _ndirs * _xi_block_size * sizeof(double); // up to dir_excrt vector + result += 8 * _ndirs * _xi_block_size * sizeof(dcomplex); // up to dir_sac22 vector + result += 80 * _ndirs * _xi_block_size * sizeof(double); // up to dir_mulclr vector + + return result; +} + +long ClusterOutputInfo::compute_size() { + long result = sizeof(np_int); + result += 21 * sizeof(int); + result += 14 * sizeof(double); + result += 121 * sizeof(long); + result += 3 * nsph * sizeof(double); // sphere coordinate vectors + result += xi_block_size * sizeof(int); // scale index vector + result += xi_block_size * sizeof(short); // error code vector + result += 2 * xi_block_size * sizeof(double); // scale vectors + result += xi_block_size * configurations * sizeof(dcomplex); // refraction indices vector + result += 5 * xi_block_size * configurations * sizeof(double); // sphere sizes, albedos and cross-sections + result += 3 * xi_block_size * configurations * sizeof(double); // cross-sections to geometric section ratios + result += configurations * sizeof(double); // sphere geometric sections + result += xi_block_size * configurations * sizeof(dcomplex); // fsas vector + result += 9 * xi_block_size * configurations * sizeof(double); // up to tqsk2 vector + result += xi_block_size * sizeof(dcomplex); // fsat vector + result += 3 * xi_block_size * sizeof(double); // up to s0magt vector + result += 20 * xi_block_size * sizeof(double); // up to excrtt vector + result += 4 * xi_block_size * sizeof(dcomplex); // up to fsac12 vector + result += 12 * xi_block_size * sizeof(double); // up to fkc vector + result += _num_theta * sizeof(double); // vec_dir_tidg; + result += _num_thetas * sizeof(double); // vec_dir_tsdg; + result += _num_phi * sizeof(double); // vec_dir_pidg; + result += _num_phis * sizeof(double); // vec_dir_psdg; + result += 11 * ndirs * sizeof(double); // up to dir_uns vector + result += 4 * ndirs * configurations * xi_block_size * sizeof(dcomplex); // up to dir_sas22 vector + result += 32 * ndirs * configurations * xi_block_size * sizeof(double); // up to dir_mulslr vector + result += 4 * ndirs * xi_block_size * sizeof(dcomplex); // up to dir_sat22 vector + result += 20 * ndirs * xi_block_size * sizeof(double); // up to dir_excrt vector + result += 8 * ndirs * xi_block_size * sizeof(dcomplex); // up to dir_sac22 vector + result += 80 * ndirs * xi_block_size * sizeof(double); // up to dir_mulclr vector + return result; +} + +int ClusterOutputInfo::insert(const ClusterOutputInfo &rhs) { + int result = 0; + result += (rhs.nsph == nsph) ? 0 : 1; + result += (rhs.inpol == inpol) ? 0 : 1; + result += (rhs.iavm == iavm) ? 0 : 1; + result += (rhs.isam == isam) ? 0 : 1; + result += (rhs._num_theta == _num_theta) ? 0 : 1; + result += (rhs._num_thetas == _num_thetas) ? 0 : 1; + result += (rhs._num_phi == _num_phi) ? 0 : 1; + result += (rhs._num_phis == _num_phis) ? 0 : 1; + result += (rhs.ndirs == ndirs) ? 0 : 1; + result += (rhs.exri == exri) ? 0 : 1; + result += (rhs.idfc == idfc) ? 0 : 1; + result += (rhs.configurations == configurations) ? 0 : 1; + if (result == 0) { + int offset, chunk_size, xi1; + xi1 = rhs._first_xi; + // Insert vectors whose size depends on wavelengths + offset = xi1 - _first_xi; + chunk_size = rhs.xi_block_size; + memcpy(vec_jxi + offset, rhs.vec_jxi, chunk_size * sizeof(int)); + memcpy(vec_ier + offset, rhs.vec_ier, chunk_size * sizeof(short)); + memcpy(vec_vk + offset, rhs.vec_vk, chunk_size * sizeof(double)); + memcpy(vec_xi + offset, rhs.vec_xi, chunk_size * sizeof(double)); + memcpy(vec_fsat + offset, rhs.vec_fsat, chunk_size * sizeof(dcomplex)); + memcpy(vec_qschut + offset, rhs.vec_qschut, chunk_size * sizeof(double)); + memcpy(vec_pschut + offset, rhs.vec_pschut, chunk_size * sizeof(double)); + memcpy(vec_s0magt + offset, rhs.vec_s0magt, chunk_size * sizeof(double)); + memcpy(vec_scc1 + offset, rhs.vec_scc1, chunk_size * sizeof(double)); + memcpy(vec_scc2 + offset, rhs.vec_scc2, chunk_size * sizeof(double)); + memcpy(vec_abc1 + offset, rhs.vec_abc1, chunk_size * sizeof(double)); + memcpy(vec_abc2 + offset, rhs.vec_abc2, chunk_size * sizeof(double)); + memcpy(vec_exc1 + offset, rhs.vec_exc1, chunk_size * sizeof(double)); + memcpy(vec_exc2 + offset, rhs.vec_exc2, chunk_size * sizeof(double)); + memcpy(vec_albedc1 + offset, rhs.vec_albedc1, chunk_size * sizeof(double)); + memcpy(vec_albedc2 + offset, rhs.vec_albedc2, chunk_size * sizeof(double)); + memcpy(vec_qscamc1 + offset, rhs.vec_qscamc1, chunk_size * sizeof(double)); + memcpy(vec_qscamc2 + offset, rhs.vec_qscamc2, chunk_size * sizeof(double)); + memcpy(vec_qabsmc1 + offset, rhs.vec_qabsmc1, chunk_size * sizeof(double)); + memcpy(vec_qabsmc2 + offset, rhs.vec_qabsmc2, chunk_size * sizeof(double)); + memcpy(vec_qextmc1 + offset, rhs.vec_qextmc1, chunk_size * sizeof(double)); + memcpy(vec_qextmc2 + offset, rhs.vec_qextmc2, chunk_size * sizeof(double)); + memcpy(vec_sccrt1 + offset, rhs.vec_sccrt1, chunk_size * sizeof(double)); + memcpy(vec_sccrt2 + offset, rhs.vec_sccrt2, chunk_size * sizeof(double)); + memcpy(vec_abcrt1 + offset, rhs.vec_abcrt1, chunk_size * sizeof(double)); + memcpy(vec_abcrt2 + offset, rhs.vec_abcrt2, chunk_size * sizeof(double)); + memcpy(vec_excrt1 + offset, rhs.vec_excrt1, chunk_size * sizeof(double)); + memcpy(vec_excrt2 + offset, rhs.vec_excrt2, chunk_size * sizeof(double)); + memcpy(vec_fsac11 + offset, rhs.vec_fsac11, chunk_size * sizeof(dcomplex)); + memcpy(vec_fsac21 + offset, rhs.vec_fsac21, chunk_size * sizeof(dcomplex)); + memcpy(vec_fsac22 + offset, rhs.vec_fsac22, chunk_size * sizeof(dcomplex)); + memcpy(vec_fsac12 + offset, rhs.vec_fsac12, chunk_size * sizeof(dcomplex)); + memcpy(vec_qschuc1 + offset, rhs.vec_qschuc1, chunk_size * sizeof(double)); + memcpy(vec_qschuc2 + offset, rhs.vec_qschuc2, chunk_size * sizeof(double)); + memcpy(vec_pschuc1 + offset, rhs.vec_pschuc1, chunk_size * sizeof(double)); + memcpy(vec_pschuc2 + offset, rhs.vec_pschuc2, chunk_size * sizeof(double)); + memcpy(vec_s0magc1 + offset, rhs.vec_s0magc1, chunk_size * sizeof(double)); + memcpy(vec_s0magc2 + offset, rhs.vec_s0magc2, chunk_size * sizeof(double)); + memcpy(vec_cosavc1 + offset, rhs.vec_cosavc1, chunk_size * sizeof(double)); + memcpy(vec_cosavc2 + offset, rhs.vec_cosavc2, chunk_size * sizeof(double)); + memcpy(vec_raprc1 + offset, rhs.vec_raprc1, chunk_size * sizeof(double)); + memcpy(vec_raprc2 + offset, rhs.vec_raprc2, chunk_size * sizeof(double)); + memcpy(vec_fkc1 + offset, rhs.vec_fkc1, chunk_size * sizeof(double)); + memcpy(vec_fkc2 + offset, rhs.vec_fkc2, chunk_size * sizeof(double)); + // Insert vectors of multiple configuration values per scale + offset = (xi1 - _first_xi) * configurations; + chunk_size = rhs.xi_block_size * configurations; + memcpy(vec_sphere_sizes + offset, rhs.vec_sphere_sizes, chunk_size * sizeof(double)); + memcpy(vec_sphere_ref_indices + offset, rhs.vec_sphere_ref_indices, chunk_size * sizeof(dcomplex)); + memcpy(vec_sphere_scs + offset, rhs.vec_sphere_scs, chunk_size * sizeof(double)); + memcpy(vec_sphere_abs + offset, rhs.vec_sphere_abs, chunk_size * sizeof(double)); + memcpy(vec_sphere_exs + offset, rhs.vec_sphere_exs, chunk_size * sizeof(double)); + memcpy(vec_sphere_albs + offset, rhs.vec_sphere_albs, chunk_size * sizeof(double)); + memcpy(vec_sphere_sqscs + offset, rhs.vec_sphere_sqscs, chunk_size * sizeof(double)); + memcpy(vec_sphere_sqabs + offset, rhs.vec_sphere_sqabs, chunk_size * sizeof(double)); + memcpy(vec_sphere_sqexs + offset, rhs.vec_sphere_sqexs, chunk_size * sizeof(double)); + memcpy(vec_fsas + offset, rhs.vec_fsas, chunk_size * sizeof(dcomplex)); + memcpy(vec_qschus + offset, rhs.vec_qschus, chunk_size * sizeof(double)); + memcpy(vec_pschus + offset, rhs.vec_pschus, chunk_size * sizeof(double)); + memcpy(vec_s0mags + offset, rhs.vec_s0mags, chunk_size * sizeof(double)); + memcpy(vec_cosavs + offset, rhs.vec_cosavs, chunk_size * sizeof(double)); + memcpy(vec_raprs + offset, rhs.vec_raprs, chunk_size * sizeof(double)); + memcpy(vec_tqek1 + offset, rhs.vec_tqek1, chunk_size * sizeof(double)); + memcpy(vec_tqsk1 + offset, rhs.vec_tqsk1, chunk_size * sizeof(double)); + memcpy(vec_tqek2 + offset, rhs.vec_tqek2, chunk_size * sizeof(double)); + memcpy(vec_tqsk2 + offset, rhs.vec_tqsk2, chunk_size * sizeof(double)); + // Insert vectors of multiple directions per configuration + offset = (xi1 - _first_xi) * configurations * ndirs; + chunk_size = rhs.xi_block_size * configurations * ndirs; + memcpy(vec_dir_sas11 + offset, rhs.vec_dir_sas11, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sas21 + offset, rhs.vec_dir_sas21, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sas12 + offset, rhs.vec_dir_sas12, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sas22 + offset, rhs.vec_dir_sas22, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_muls + 16 * offset, rhs.vec_dir_muls, 16 * chunk_size * sizeof(double)); + memcpy(vec_dir_mulslr + 16 * offset, rhs.vec_dir_mulslr, 16 * chunk_size * sizeof(double)); + // Insert vectors whose sizes depend on wavelengths and directions + offset = (xi1 - _first_xi) * ndirs; + chunk_size = rhs.xi_block_size * ndirs; + memcpy(vec_dir_sat11 + offset, rhs.vec_dir_sat11, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sat21 + offset, rhs.vec_dir_sat21, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sat12 + offset, rhs.vec_dir_sat12, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sat22 + offset, rhs.vec_dir_sat22, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_scc1 + offset, rhs.vec_dir_scc1, chunk_size * sizeof(double)); + memcpy(vec_dir_scc2 + offset, rhs.vec_dir_scc2, chunk_size * sizeof(double)); + memcpy(vec_dir_abc1 + offset, rhs.vec_dir_abc1, chunk_size * sizeof(double)); + memcpy(vec_dir_abc2 + offset, rhs.vec_dir_abc2, chunk_size * sizeof(double)); + memcpy(vec_dir_exc1 + offset, rhs.vec_dir_exc1, chunk_size * sizeof(double)); + memcpy(vec_dir_exc2 + offset, rhs.vec_dir_exc2, chunk_size * sizeof(double)); + memcpy(vec_dir_albedc1 + offset, rhs.vec_dir_albedc1, chunk_size * sizeof(double)); + memcpy(vec_dir_albedc2 + offset, rhs.vec_dir_albedc2, chunk_size * sizeof(double)); + memcpy(vec_dir_qscc1 + offset, rhs.vec_dir_qscc1, chunk_size * sizeof(double)); + memcpy(vec_dir_qscc2 + offset, rhs.vec_dir_qscc2, chunk_size * sizeof(double)); + memcpy(vec_dir_qabc1 + offset, rhs.vec_dir_qabc1, chunk_size * sizeof(double)); + memcpy(vec_dir_qabc2 + offset, rhs.vec_dir_qabc2, chunk_size * sizeof(double)); + memcpy(vec_dir_qexc1 + offset, rhs.vec_dir_qexc1, chunk_size * sizeof(double)); + memcpy(vec_dir_qexc2 + offset, rhs.vec_dir_qexc2, chunk_size * sizeof(double)); + memcpy(vec_dir_sccrt1 + offset, rhs.vec_dir_sccrt1, chunk_size * sizeof(double)); + memcpy(vec_dir_sccrt2 + offset, rhs.vec_dir_sccrt2, chunk_size * sizeof(double)); + memcpy(vec_dir_abcrt1 + offset, rhs.vec_dir_abcrt1, chunk_size * sizeof(double)); + memcpy(vec_dir_abcrt2 + offset, rhs.vec_dir_abcrt2, chunk_size * sizeof(double)); + memcpy(vec_dir_excrt1 + offset, rhs.vec_dir_excrt1, chunk_size * sizeof(double)); + memcpy(vec_dir_excrt2 + offset, rhs.vec_dir_excrt2, chunk_size * sizeof(double)); + memcpy(vec_dir_fsac11 + offset, rhs.vec_dir_fsac11, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_fsac21 + offset, rhs.vec_dir_fsac21, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_fsac12 + offset, rhs.vec_dir_fsac12, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_fsac22 + offset, rhs.vec_dir_fsac22, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sac11 + offset, rhs.vec_dir_sac11, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sac21 + offset, rhs.vec_dir_sac21, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sac12 + offset, rhs.vec_dir_sac12, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sac22 + offset, rhs.vec_dir_sac22, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_qschuc1 + offset, rhs.vec_dir_qschuc1, chunk_size * sizeof(double)); + memcpy(vec_dir_qschuc2 + offset, rhs.vec_dir_qschuc2, chunk_size * sizeof(double)); + memcpy(vec_dir_pschuc1 + offset, rhs.vec_dir_pschuc1, chunk_size * sizeof(double)); + memcpy(vec_dir_pschuc2 + offset, rhs.vec_dir_pschuc2, chunk_size * sizeof(double)); + memcpy(vec_dir_s0magc1 + offset, rhs.vec_dir_s0magc1, chunk_size * sizeof(double)); + memcpy(vec_dir_s0magc2 + offset, rhs.vec_dir_s0magc2, chunk_size * sizeof(double)); + memcpy(vec_dir_cosavc1 + offset, rhs.vec_dir_cosavc1, chunk_size * sizeof(double)); + memcpy(vec_dir_cosavc2 + offset, rhs.vec_dir_cosavc2, chunk_size * sizeof(double)); + memcpy(vec_dir_raprc1 + offset, rhs.vec_dir_raprc1, chunk_size * sizeof(double)); + memcpy(vec_dir_raprc2 + offset, rhs.vec_dir_raprc2, chunk_size * sizeof(double)); + memcpy(vec_dir_flc1 + offset, rhs.vec_dir_flc1, chunk_size * sizeof(double)); + memcpy(vec_dir_flc2 + offset, rhs.vec_dir_flc2, chunk_size * sizeof(double)); + memcpy(vec_dir_frc1 + offset, rhs.vec_dir_frc1, chunk_size * sizeof(double)); + memcpy(vec_dir_frc2 + offset, rhs.vec_dir_frc2, chunk_size * sizeof(double)); + memcpy(vec_dir_fkc1 + offset, rhs.vec_dir_fkc1, chunk_size * sizeof(double)); + memcpy(vec_dir_fkc2 + offset, rhs.vec_dir_fkc2, chunk_size * sizeof(double)); + memcpy(vec_dir_fxc1 + offset, rhs.vec_dir_fxc1, chunk_size * sizeof(double)); + memcpy(vec_dir_fxc2 + offset, rhs.vec_dir_fxc2, chunk_size * sizeof(double)); + memcpy(vec_dir_fyc1 + offset, rhs.vec_dir_fyc1, chunk_size * sizeof(double)); + memcpy(vec_dir_fyc2 + offset, rhs.vec_dir_fyc2, chunk_size * sizeof(double)); + memcpy(vec_dir_fzc1 + offset, rhs.vec_dir_fzc1, chunk_size * sizeof(double)); + memcpy(vec_dir_fzc2 + offset, rhs.vec_dir_fzc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqelc1 + offset, rhs.vec_dir_tqelc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqelc2 + offset, rhs.vec_dir_tqelc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqerc1 + offset, rhs.vec_dir_tqerc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqerc2 + offset, rhs.vec_dir_tqerc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqekc1 + offset, rhs.vec_dir_tqekc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqekc2 + offset, rhs.vec_dir_tqekc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqexc1 + offset, rhs.vec_dir_tqexc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqexc2 + offset, rhs.vec_dir_tqexc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqeyc1 + offset, rhs.vec_dir_tqeyc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqeyc2 + offset, rhs.vec_dir_tqeyc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqezc1 + offset, rhs.vec_dir_tqezc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqezc2 + offset, rhs.vec_dir_tqezc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqslc1 + offset, rhs.vec_dir_tqslc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqslc2 + offset, rhs.vec_dir_tqslc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsrc1 + offset, rhs.vec_dir_tqsrc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsrc2 + offset, rhs.vec_dir_tqsrc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqskc1 + offset, rhs.vec_dir_tqskc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqskc2 + offset, rhs.vec_dir_tqskc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsxc1 + offset, rhs.vec_dir_tqsxc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsxc2 + offset, rhs.vec_dir_tqsxc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsyc1 + offset, rhs.vec_dir_tqsyc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsyc2 + offset, rhs.vec_dir_tqsyc2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqszc1 + offset, rhs.vec_dir_tqszc1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqszc2 + offset, rhs.vec_dir_tqszc2, chunk_size * sizeof(double)); + memcpy(vec_dir_mulc + 16 * offset, rhs.vec_dir_mulc, 16 * chunk_size * sizeof(double)); + memcpy(vec_dir_mulclr + 16 * offset, rhs.vec_dir_mulclr, 16 * chunk_size * sizeof(double)); + } + return result; +} + +int ClusterOutputInfo::write(const std::string &output, const std::string &format) { + int result = 0; + if (format.compare("LEGACY") == 0) { + result = write_legacy(output); + } else if (format.compare("HDF5") == 0) { + result = write_hdf5(output); + } else { + string message = "Unknown format mode: \"" + format + "\""; + throw UnrecognizedConfigurationException(message); + } + return result; +} + +int ClusterOutputInfo::write_hdf5(const std::string &file_name) { + List<string> *rec_name_list = new List<string>(1); + List<string> *rec_type_list = new List<string>(1); + List<void *> *rec_ptr_list = new List<void *>(1); + string str_type, str_name; + rec_name_list->set(0, "NSPH"); + rec_type_list->set(0, "INT32_(1)"); + rec_ptr_list->set(0, &nsph); + rec_name_list->append("LI"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&li); + rec_name_list->append("LE"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&le); + rec_name_list->append("LM"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&lm); + rec_name_list->append("MXNDM"); + rec_type_list->append("INT64_(1)"); + rec_ptr_list->append(&mxndm); + rec_name_list->append("INPOL"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&inpol); + rec_name_list->append("NPNT"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&npnt); + rec_name_list->append("NPNTTS"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&npntts); + rec_name_list->append("IAVM"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&iavm); + rec_name_list->append("ISAM"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&isam); + rec_name_list->append("JWTM"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&jwtm); + rec_name_list->append("VEC_SPH_X"); + rec_type_list->append("FLOAT64_(" + to_string(nsph) + ")"); + rec_ptr_list->append(vec_x_coords); + rec_name_list->append("VEC_SPH_Y"); + rec_type_list->append("FLOAT64_(" + to_string(nsph) + ")"); + rec_ptr_list->append(vec_y_coords); + rec_name_list->append("VEC_SPH_Z"); + rec_type_list->append("FLOAT64_(" + to_string(nsph) + ")"); + rec_ptr_list->append(vec_z_coords); + rec_name_list->append("TH_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&th); + rec_name_list->append("TH_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thstp); + rec_name_list->append("TH_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thlst); + rec_name_list->append("THS_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&ths); + rec_name_list->append("THS_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thsstp); + rec_name_list->append("THS_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thslst); + rec_name_list->append("PH_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&ph); + rec_name_list->append("PH_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phstp); + rec_name_list->append("PH_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phlst); + rec_name_list->append("PHS_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phs); + rec_name_list->append("PHS_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phsstp); + rec_name_list->append("PHS_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phslst); + rec_name_list->append("EXRI"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&exri); + rec_name_list->append("IDFC"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&idfc); + rec_name_list->append("XI1"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&_first_xi); + rec_name_list->append("NXI"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&xi_block_size); + rec_name_list->append("VEC_JXI"); + rec_type_list->append("INT32_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_jxi); + rec_name_list->append("VEC_IER"); + rec_type_list->append("INT16_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_ier); + rec_name_list->append("VEC_VK"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_vk); + rec_name_list->append("VEC_XI"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_xi); + rec_name_list->append("NCONF"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&configurations); + rec_name_list->append("VEC_SPH_SIZES"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_sphere_sizes); + rec_name_list->append("VEC_SPH_REFRI"); + rec_type_list->append("FLOAT64_(" + to_string(2 * xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_sphere_ref_indices); + rec_name_list->append("VEC_SPH_SCS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_sphere_scs); + rec_name_list->append("VEC_SPH_ABS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_sphere_abs); + rec_name_list->append("VEC_SPH_EXS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_sphere_exs); + rec_name_list->append("VEC_SPH_ALBS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_sphere_albs); + rec_name_list->append("VEC_SPH_SQSCS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_sphere_sqscs); + rec_name_list->append("VEC_SPH_SQABS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_sphere_sqabs); + rec_name_list->append("VEC_SPH_SQEXS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_sphere_sqexs); + rec_name_list->append("VEC_FSAS"); + rec_type_list->append("FLOAT64_(" + to_string(2 * xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_fsas); + rec_name_list->append("VEC_QSCHUS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_qschus); + rec_name_list->append("VEC_PSCHUS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_pschus); + rec_name_list->append("VEC_S0MAGS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_s0mags); + rec_name_list->append("VEC_COSAVS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_cosavs); + rec_name_list->append("VEC_RAPRS"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_raprs); + rec_name_list->append("VEC_TQEK1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_tqek1); + rec_name_list->append("VEC_TQSK1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_tqsk1); + rec_name_list->append("VEC_TQEK2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_tqek2); + rec_name_list->append("VEC_TQSK2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * configurations) + ")"); + rec_ptr_list->append(vec_tqsk2); + rec_name_list->append("VEC_FSAT"); + rec_type_list->append("FLOAT64_(" + to_string(2 * xi_block_size) + ")"); + rec_ptr_list->append(vec_fsat); + rec_name_list->append("VEC_QSCHUT"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_qschut); + rec_name_list->append("VEC_PSCHUT"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_pschut); + rec_name_list->append("VEC_S0MAGT"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_s0magt); + rec_name_list->append("VEC_SCC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_scc1); + rec_name_list->append("VEC_SCC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_scc2); + rec_name_list->append("VEC_ABC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_abc1); + rec_name_list->append("VEC_ABC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_abc2); + rec_name_list->append("VEC_EXC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_exc1); + rec_name_list->append("VEC_EXC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_exc2); + rec_name_list->append("VEC_ALBEDC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_albedc1); + rec_name_list->append("VEC_ALBEDC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_albedc2); + rec_name_list->append("VEC_QSCAMC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_qscamc1); + rec_name_list->append("VEC_QSCAMC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_qscamc2); + rec_name_list->append("VEC_QABSMC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_qabsmc1); + rec_name_list->append("VEC_QABSMC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_qabsmc2); + rec_name_list->append("VEC_QEXTMC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_qextmc1); + rec_name_list->append("VEC_QEXTMC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_qextmc2); + rec_name_list->append("VEC_SCCRT1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_sccrt1); + rec_name_list->append("VEC_SCCRT2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_sccrt2); + rec_name_list->append("VEC_ABCRT1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_abcrt1); + rec_name_list->append("VEC_ABCRT2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_abcrt2); + rec_name_list->append("VEC_EXCRT1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_excrt1); + rec_name_list->append("VEC_EXCRT2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_excrt2); + rec_name_list->append("VEC_FSAC11"); + rec_type_list->append("FLOAT64_(" + to_string(2 * xi_block_size) + ")"); + rec_ptr_list->append(vec_fsac11); + rec_name_list->append("VEC_FSAC21"); + rec_type_list->append("FLOAT64_(" + to_string(2 * xi_block_size) + ")"); + rec_ptr_list->append(vec_fsac21); + rec_name_list->append("VEC_FSAC22"); + rec_type_list->append("FLOAT64_(" + to_string(2 * xi_block_size) + ")"); + rec_ptr_list->append(vec_fsac22); + rec_name_list->append("VEC_FSAC12"); + rec_type_list->append("FLOAT64_(" + to_string(2 * xi_block_size) + ")"); + rec_ptr_list->append(vec_fsac12); + rec_name_list->append("VEC_QSCHUC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_qschuc1); + rec_name_list->append("VEC_QSCHUC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_qschuc2); + rec_name_list->append("VEC_PSCHUC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_pschuc1); + rec_name_list->append("VEC_PSCHUC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_pschuc2); + rec_name_list->append("VEC_S0MAGC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_s0magc1); + rec_name_list->append("VEC_S0MAGC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_s0magc2); + rec_name_list->append("VEC_COSAVC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_cosavc1); + rec_name_list->append("VEC_COSAVC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_cosavc2); + rec_name_list->append("VEC_RAPRC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_raprc1); + rec_name_list->append("VEC_RAPRC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_raprc2); + rec_name_list->append("VEC_FKC1"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_fkc1); + rec_name_list->append("VEC_FKC2"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_fkc2); + rec_name_list->append("VEC_DIR_SCAN"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs) + ")"); + rec_ptr_list->append(vec_dir_scand); + rec_name_list->append("VEC_DIR_CFMP"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs) + ")"); + rec_ptr_list->append(vec_dir_cfmp); + rec_name_list->append("VEC_DIR_SFMP"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs) + ")"); + rec_ptr_list->append(vec_dir_sfmp); + rec_name_list->append("VEC_DIR_CFSP"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs) + ")"); + rec_ptr_list->append(vec_dir_cfsp); + rec_name_list->append("VEC_DIR_SFSP"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs) + ")"); + rec_ptr_list->append(vec_dir_sfsp); + rec_name_list->append("VEC_DIR_UN"); + rec_type_list->append("FLOAT64_(" + to_string(3 * ndirs) + ")"); + rec_ptr_list->append(vec_dir_un); + rec_name_list->append("VEC_DIR_UNS"); + rec_type_list->append("FLOAT64_(" + to_string(3 * ndirs) + ")"); + rec_ptr_list->append(vec_dir_uns); + rec_name_list->append("VEC_DIR_SAS11"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * configurations * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sas11); + rec_name_list->append("VEC_DIR_SAS21"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * configurations * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sas21); + rec_name_list->append("VEC_DIR_SAS12"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * configurations * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sas12); + rec_name_list->append("VEC_DIR_SAS22"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * configurations * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sas22); + rec_name_list->append("VEC_DIR_MULS"); + rec_type_list->append("FLOAT64_(" + to_string(16 * ndirs * configurations * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_muls); + rec_name_list->append("VEC_DIR_MULSLR"); + rec_type_list->append("FLOAT64_(" + to_string(16 * ndirs * configurations * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_mulslr); + rec_name_list->append("VEC_DIR_SAT11"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sat11); + rec_name_list->append("VEC_DIR_SAT21"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sat21); + rec_name_list->append("VEC_DIR_SAT12"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sat12); + rec_name_list->append("VEC_DIR_SAT22"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sat22); + rec_name_list->append("VEC_DIR_SCC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_scc1); + rec_name_list->append("VEC_DIR_SCC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_scc2); + rec_name_list->append("VEC_DIR_ABC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_abc1); + rec_name_list->append("VEC_DIR_ABC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_abc2); + rec_name_list->append("VEC_DIR_EXC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_exc1); + rec_name_list->append("VEC_DIR_EXC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_exc2); + rec_name_list->append("VEC_DIR_ALBEDC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_albedc1); + rec_name_list->append("VEC_DIR_ALBEDC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_albedc2); + rec_name_list->append("VEC_DIR_QSCC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_qscc1); + rec_name_list->append("VEC_DIR_QSCC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_qscc2); + rec_name_list->append("VEC_DIR_QABC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_qabc1); + rec_name_list->append("VEC_DIR_QABC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_qabc2); + rec_name_list->append("VEC_DIR_QEXC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_qexc1); + rec_name_list->append("VEC_DIR_QEXC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_qexc2); + rec_name_list->append("VEC_DIR_SCCRT1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sccrt1); + rec_name_list->append("VEC_DIR_SCCRT2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sccrt2); + rec_name_list->append("VEC_DIR_ABCRT1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_abcrt1); + rec_name_list->append("VEC_DIR_ABCRT2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_abcrt2); + rec_name_list->append("VEC_DIR_EXCRT1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_excrt1); + rec_name_list->append("VEC_DIR_EXCRT2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_excrt2); + rec_name_list->append("VEC_DIR_FSAC11"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fsac11); + rec_name_list->append("VEC_DIR_FSAC21"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fsac21); + rec_name_list->append("VEC_DIR_FSAC12"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fsac12); + rec_name_list->append("VEC_DIR_FSAC22"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fsac22); + rec_name_list->append("VEC_DIR_SAC11"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sac11); + rec_name_list->append("VEC_DIR_SAC21"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sac21); + rec_name_list->append("VEC_DIR_SAC12"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sac12); + rec_name_list->append("VEC_DIR_SAC22"); + rec_type_list->append("FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_sac22); + rec_name_list->append("VEC_DIR_QSCHUC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_qschuc1); + rec_name_list->append("VEC_DIR_QSCHUC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_qschuc2); + rec_name_list->append("VEC_DIR_PSCHUC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_pschuc1); + rec_name_list->append("VEC_DIR_PSCHUC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_pschuc2); + rec_name_list->append("VEC_DIR_S0MAGC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_s0magc1); + rec_name_list->append("VEC_DIR_S0MAGC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_s0magc2); + rec_name_list->append("VEC_DIR_COSAVC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_cosavc1); + rec_name_list->append("VEC_DIR_COSAVC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_cosavc2); + rec_name_list->append("VEC_DIR_RAPRC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_raprc1); + rec_name_list->append("VEC_DIR_RAPRC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_raprc2); + rec_name_list->append("VEC_DIR_FLC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_flc1); + rec_name_list->append("VEC_DIR_FLC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_flc2); + rec_name_list->append("VEC_DIR_FRC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_frc1); + rec_name_list->append("VEC_DIR_FRC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_frc2); + rec_name_list->append("VEC_DIR_FKC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fkc1); + rec_name_list->append("VEC_DIR_FKC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fkc2); + rec_name_list->append("VEC_DIR_FXC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fxc1); + rec_name_list->append("VEC_DIR_FXC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fxc2); + rec_name_list->append("VEC_DIR_FYC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fyc1); + rec_name_list->append("VEC_DIR_FYC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fyc2); + rec_name_list->append("VEC_DIR_FZC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fzc1); + rec_name_list->append("VEC_DIR_FZC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_fzc2); + rec_name_list->append("VEC_DIR_TQELC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqelc1); + rec_name_list->append("VEC_DIR_TQELC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqelc2); + rec_name_list->append("VEC_DIR_TQERC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqerc1); + rec_name_list->append("VEC_DIR_TQERC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqerc2); + rec_name_list->append("VEC_DIR_TQEKC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqekc1); + rec_name_list->append("VEC_DIR_TQEKC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqekc2); + rec_name_list->append("VEC_DIR_TQEXC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqexc1); + rec_name_list->append("VEC_DIR_TQEXC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqexc2); + rec_name_list->append("VEC_DIR_TQEYC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqeyc1); + rec_name_list->append("VEC_DIR_TQEYC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqeyc2); + rec_name_list->append("VEC_DIR_TQEZC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqezc1); + rec_name_list->append("VEC_DIR_TQEZC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqezc2); + rec_name_list->append("VEC_DIR_TQSLC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqslc1); + rec_name_list->append("VEC_DIR_TQSLC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqslc2); + rec_name_list->append("VEC_DIR_TQSRC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqsrc1); + rec_name_list->append("VEC_DIR_TQSRC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqsrc2); + rec_name_list->append("VEC_DIR_TQSKC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqskc1); + rec_name_list->append("VEC_DIR_TQSKC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqskc2); + rec_name_list->append("VEC_DIR_TQSXC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqsxc1); + rec_name_list->append("VEC_DIR_TQSXC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqsxc2); + rec_name_list->append("VEC_DIR_TQSYC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqsyc1); + rec_name_list->append("VEC_DIR_TQSYC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqsyc2); + rec_name_list->append("VEC_DIR_TQSZC1"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqszc1); + rec_name_list->append("VEC_DIR_TQSZC2"); + rec_type_list->append("FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_tqszc2); + rec_name_list->append("VEC_DIR_MULC"); + rec_type_list->append("FLOAT64_(" + to_string(16 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_mulc); + rec_name_list->append("VEC_DIR_MULCLR"); + rec_type_list->append("FLOAT64_(" + to_string(16 * ndirs * xi_block_size) + ")"); + rec_ptr_list->append(vec_dir_mulclr); + + // Convert the lists to arrays and write them to HDF5 + string *rec_names = rec_name_list->to_array(); + string *rec_types = rec_type_list->to_array(); + void **rec_pointers = rec_ptr_list->to_array(); + const int rec_num = rec_name_list->length(); + FileSchema *schema = new FileSchema(rec_num, rec_types, rec_names); + HDFFile *hdf_file = HDFFile::from_schema(*schema, file_name, H5F_ACC_TRUNC); + for (int ri = 0; ri < rec_num; ri++) + hdf_file->write(rec_names[ri], rec_types[ri], rec_pointers[ri]); + hdf_file->close(); + + // Clean memory + delete rec_name_list; + delete rec_type_list; + delete rec_ptr_list; + delete[] rec_names; + delete[] rec_types; + delete[] rec_pointers; + delete schema; + delete hdf_file; + return 0; +} + +int ClusterOutputInfo::write_legacy(const std::string &output) { + const dcomplex cc0 = 0.0 + I * 0.0; + int result = 0; + FILE *p_outfile = fopen(output.c_str(), "w"); + if (p_outfile != NULL) { + if (vec_jxi[0] == 1) { + // Write the preamble of c_OCLU. + fprintf(p_outfile, " READ(IR,*)NSPH,LI,LE,MXNDM,INPOL,NPNT,NPNTTS,IAVM,ISAM\n"); +#ifdef USE_ILP64 + fprintf( + p_outfile, " %5d%5d%5d%5ld%5d%5d%5d%5d%5d\n", + nsph, li, le, mxndm, inpol, npnt, npntts, iavm, isam + ); +#else + fprintf( + p_outfile, " %5d%5d%5d%5d%5d%5d%5d%5d%5d\n", + nsph, li, le, mxndm, inpol, npnt, npntts, iavm, isam + ); +#endif // USE_ILP64 + fprintf(p_outfile, " READ(IR,*)RXX(I),RYY(I),RZZ(I)\n"); + for (int ri = 0; ri < nsph; ri++) { + fprintf( + p_outfile, "%17.8lE%17.8lE%17.8lE\n", + vec_x_coords[ri], vec_y_coords[ri], vec_z_coords[ri] + ); + } + fprintf(p_outfile, " READ(IR,*)TH,THSTP,THLST,THS,THSSTP,THSLST\n"); + fprintf( + p_outfile, " %10.3lE%10.3lE%10.3lE%10.3lE%10.3lE%10.3lE\n", + th, thstp, thlst, ths, thsstp, thslst + ); + fprintf(p_outfile, " READ(IR,*)PH,PHSTP,PHLST,PHS,PHSSTP,PHSLST\n"); + fprintf( + p_outfile, " %10.3lE%10.3lE%10.3lE%10.3lE%10.3lE%10.3lE\n", + ph, phstp, phlst, phs, phsstp, phslst + ); + fprintf(p_outfile, " READ(IR,*)JWTM\n"); + fprintf(p_outfile, " %5d\n", jwtm); + fprintf(p_outfile, " READ(ITIN)NSPHT\n"); + fprintf(p_outfile, " READ(ITIN)(IOG(I),I=1,NSPH)\n"); + fprintf(p_outfile, " READ(ITIN)EXDC,WP,XIP,IDFC,NXI\n"); + fprintf(p_outfile, " READ(ITIN)(XIV(I),I=1,NXI)\n"); + fprintf(p_outfile, " READ(ITIN)NSHL(I),ROS(I)\n"); + fprintf(p_outfile, " READ(ITIN)(RCF(I,NS),NS=1,NSH)\n \n"); + fprintf(p_outfile, " REFR. INDEX OF EXTERNAL MEDIUM=%15.7lE\n", exri); + if (idfc < 0) { + fprintf(p_outfile, " VK=%15.7lE, XI IS SCALE FACTOR FOR LENGTHS\n \n", vec_vk[0]); + } + } + // Write the wavelength loop data. + for (int jxi = 0; jxi < xi_block_size; jxi++) { + fprintf(p_outfile, "========== JXI =%3d ====================\n", vec_jxi[jxi]); + if (idfc >= 0) { + fprintf(p_outfile, " VK=%15.7lE, XI=%15.7lE\n", vec_vk[jxi], vec_xi[jxi]); + } else { + fprintf(p_outfile, " XI=%15.7lE\n", vec_xi[jxi]); + } + if (vec_ier[jxi] == 1) { + fprintf(p_outfile, " STOP IN HJV\n"); + result = 1; + break; // jxi loop + } + if (vec_ier[jxi] == 2) { + fprintf(p_outfile, " STOP IN DME\n"); + result = 2; + break; // jxi loop + } + double alamb = 2.0 * 3.141592653589793 / vec_vk[jxi]; + if (inpol == 0) + fprintf(p_outfile, " LIN\n"); + else + fprintf(p_outfile, " CIRC\n"); + if (li != le) + fprintf(p_outfile, " SPHERES; LMX=LI\n"); + for (int si = 0; si < configurations; si++) { + fprintf(p_outfile, " SPHERE %2d\n", si + 1); + if (vec_sphere_ref_indices[jxi * configurations + si] == cc0) + fprintf(p_outfile, " SIZE=%15.7lE\n", vec_sphere_sizes[jxi * configurations + si]); + else + fprintf( + p_outfile, " SIZE=%15.7lE, REFRACTIVE INDEX=%15.7lE%15.7lE\n", + vec_sphere_sizes[jxi * configurations + si], + real(vec_sphere_ref_indices[jxi * configurations + si]), + imag(vec_sphere_ref_indices[jxi * configurations + si]) + ); + fprintf(p_outfile, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE%15.7lE\n", + vec_sphere_scs[jxi * configurations + si], + vec_sphere_abs[jxi * configurations + si], + vec_sphere_exs[jxi * configurations + si], + vec_sphere_albs[jxi * configurations + si] + ); + fprintf(p_outfile, " ---- SCS/GS -- ABS/GS -- EXS/GS ---\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_sphere_sqscs[jxi * configurations + si], + vec_sphere_sqabs[jxi * configurations + si], + vec_sphere_sqexs[jxi * configurations + si] + ); + fprintf( + p_outfile, " FSAS=%15.7lE%15.7lE\n", + real(vec_fsas[jxi * configurations + si]), + imag(vec_fsas[jxi * configurations + si]) + ); + fprintf( + p_outfile, "INSERTION: CS_SPHERE %15.7lE%15.7lE%15.7lE%15.7lE\n", + alamb, vec_sphere_scs[jxi * configurations + si], + vec_sphere_abs[jxi * configurations + si], + vec_sphere_exs[jxi * configurations + si] + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_qschus[jxi * configurations + si], + vec_pschus[jxi * configurations + si], + vec_s0mags[jxi * configurations + si] + ); + fprintf( + p_outfile, " COSAV=%15.7lE, RAPRS=%15.7lE\n", + vec_cosavs[jxi * configurations + si], + vec_raprs[jxi * configurations + si] + ); + fprintf( + p_outfile, " IPO= 1, TQEk=%15.7lE, TQSk=%15.7lE\n", + vec_tqek1[jxi * configurations + si], + vec_tqsk1[jxi * configurations + si] + ); + fprintf( + p_outfile, " IPO= 2, TQEk=%15.7lE, TQSk=%15.7lE\n", + vec_tqek2[jxi * configurations + si], + vec_tqsk2[jxi * configurations + si] + ); + } // si configuration loop + fprintf( + p_outfile, " FSAT=%15.7lE%15.7lE\n", + real(vec_fsat[jxi]), imag(vec_fsat[jxi]) + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_qschut[jxi], vec_pschut[jxi], vec_s0magt[jxi] + ); + fprintf(p_outfile, " CLUSTER (ENSEMBLE AVERAGE, MODE%2d)\n", iavm); + // Parallel polarization cluster average section + if (inpol == 0) + fprintf(p_outfile, " LIN -1\n"); + else + fprintf(p_outfile, " CIRC -1\n"); + fprintf(p_outfile, " ----- SCC ----- ABC ----- EXC ----- ALBEDC --\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE%15.7lE\n", + vec_scc1[jxi], vec_abc1[jxi], vec_exc1[jxi], vec_albedc1[jxi] + ); + fprintf(p_outfile, " --- SCC/TGS - ABC/TGS - EXC/TGS ---\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_qscamc1[jxi], vec_qabsmc1[jxi], vec_qextmc1[jxi] + ); + fprintf(p_outfile, " ---- SCCRT --- ABCRT --- EXCRT ----\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_sccrt1[jxi], vec_abcrt1[jxi], vec_excrt1[jxi] + ); + fprintf( + p_outfile, " FSAC(1,1)=%15.7lE%15.7lE FSAC(2,1)=%15.7lE%15.7lE\n", + real(vec_fsac11[jxi]), imag(vec_fsac11[jxi]), + real(vec_fsac21[jxi]), imag(vec_fsac21[jxi]) + ); + fprintf( + p_outfile, " RE(FSAC(1,1))/RE(TFSAS)=%15.7lE, IM(FSAC(1,1))/IM(TFSAS)=%15.7lE\n", + real(vec_fsac11[jxi]) / real(vec_fsat[jxi]), + imag(vec_fsac11[jxi]) / imag(vec_fsat[jxi]) + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_qschuc1[jxi], vec_pschuc1[jxi], vec_s0magc1[jxi] + ); + fprintf( + p_outfile, " COSAV=%15.7lE, RAPRS=%15.7lE\n", + vec_cosavc1[jxi], vec_raprc1[jxi] + ); + fprintf(p_outfile, " Fk=%15.7lE\n", vec_fkc1[jxi]); + fprintf( + p_outfile, "INSERTION: CSM_CLUSTER %15.7lE%15.7lE%15.7lE%15.7lE\n", + alamb, vec_scc1[jxi], vec_abc1[jxi], vec_exc1[jxi] + ); + // Perpendicular polarization cluster average section + if (inpol == 0) + fprintf(p_outfile, " LIN 1\n"); + else + fprintf(p_outfile, " CIRC 1\n"); + fprintf(p_outfile, " ----- SCC ----- ABC ----- EXC ----- ALBEDC --\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE%15.7lE\n", + vec_scc2[jxi], vec_abc2[jxi], vec_exc2[jxi], vec_albedc2[jxi] + ); + fprintf(p_outfile, " --- SCC/TGS - ABC/TGS - EXC/TGS ---\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_qscamc2[jxi], vec_qabsmc2[jxi], vec_qextmc2[jxi] + ); + fprintf(p_outfile, " ---- SCCRT --- ABCRT --- EXCRT ----\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_sccrt2[jxi], vec_abcrt2[jxi], vec_excrt2[jxi] + ); + fprintf( + p_outfile, " FSAC(2,2)=%15.7lE%15.7lE FSAC(1,2)=%15.7lE%15.7lE\n", + real(vec_fsac22[jxi]), imag(vec_fsac22[jxi]), + real(vec_fsac12[jxi]), imag(vec_fsac12[jxi]) + ); + fprintf( + p_outfile, " RE(FSAC(2,2))/RE(TFSAS)=%15.7lE, IM(FSAC(2,2))/IM(TFSAS)=%15.7lE\n", + real(vec_fsac22[jxi]) / real(vec_fsat[jxi]), + imag(vec_fsac22[jxi]) / imag(vec_fsat[jxi]) + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_qschuc2[jxi], vec_pschuc2[jxi], vec_s0magc2[jxi] + ); + fprintf( + p_outfile, " COSAV=%15.7lE, RAPRS=%15.7lE\n", + vec_cosavc2[jxi], vec_raprc2[jxi] + ); + fprintf(p_outfile, " Fk=%15.7lE\n", vec_fkc2[jxi]); + + fprintf( + p_outfile, " (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))=%15.7lE\n", + (real(vec_fsac11[jxi]) - real(vec_fsac22[jxi])) / real(vec_fsac11[jxi]) + ); + fprintf( + p_outfile, " (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))=%15.7lE\n", + (imag(vec_fsac11[jxi]) - imag(vec_fsac22[jxi])) / imag(vec_fsac11[jxi]) + ); + // Differential directional loop + // Loop sorting (outer to inner) is: + // THETA_INC - PHI_INC - THETA_SCAT - PHI_SCAT + int dir_index = 0; + for (int jth = 0; jth < _num_theta; jth++) { + for (int jph = 0; jph < _num_phi; jph++) { + for (int jths = 0; jths < _num_thetas; jths++) { + for (int jphs = 0; jphs < _num_phis; jphs++) { + fprintf( + p_outfile, "********** JTH =%3d, JPH =%3d, JTHS =%3d, JPHS =%3d ********************\n", + jth + 1, jph + 1, jths + 1, jphs + 1 + ); + fprintf( + p_outfile, " TIDG=%10.3lE, PIDG=%10.3lE, TSDG=%10.3lE, PSDG=%10.3lE\n", + th + jth * thstp, ph + jph * phstp, + ths + jths * thsstp, phs + jphs * phsstp + ); + fprintf(p_outfile, " SCAND=%10.3lE\n", vec_dir_scand[dir_index]); + fprintf( + p_outfile, " CFMP=%15.7lE, SFMP=%15.7lE\n", + vec_dir_cfmp[dir_index], vec_dir_sfmp[dir_index] + ); + fprintf( + p_outfile, " CFSP=%15.7lE, SFSP=%15.7lE\n", + vec_dir_cfsp[dir_index], vec_dir_sfsp[dir_index] + ); + if (isam >= 0) { + fprintf( + p_outfile, " UNI=(%12.5lE,%12.5lE,%12.5lE)\n", + vec_dir_un[3 * dir_index], vec_dir_un[3 * dir_index + 1], vec_dir_un[3 * dir_index + 2] + ); + fprintf( + p_outfile, " UNS=(%12.5lE,%12.5lE,%12.5lE)\n", + vec_dir_uns[3 * dir_index], vec_dir_uns[3 * dir_index + 1], vec_dir_uns[3 * dir_index + 2] + ); + } else + fprintf( + p_outfile, " UN=(%12.5lE,%12.5lE,%12.5lE)\n\n", + vec_dir_un[3 * dir_index], vec_dir_un[3 * dir_index + 1], vec_dir_un[3 * dir_index + 2] + ); + if (inpol == 0) + fprintf(p_outfile, " LIN\n"); + else + fprintf(p_outfile, " CIRC\n"); + if (li != le) fprintf(p_outfile, " SPHERES; LMX=MIN0(LI,LE)\n"); + for (int si = 0; si < configurations; si++) { + int sas_dir_index = jxi * configurations * ndirs + configurations * dir_index + si; + fprintf(p_outfile, " SPHERE %2d\n", si + 1); + fprintf( + p_outfile, " SAS(1,1)=%15.7lE%15.7lE, SAS(2,1)=%15.7lE%15.7lE\n", + real(vec_dir_sas11[sas_dir_index]), + imag(vec_dir_sas11[sas_dir_index]), + real(vec_dir_sas21[sas_dir_index]), + imag(vec_dir_sas21[sas_dir_index]) + ); + fprintf( + p_outfile, " SAS(1,2)=%15.7lE%15.7lE, SAS(2,2)=%15.7lE%15.7lE\n", + real(vec_dir_sas12[sas_dir_index]), + imag(vec_dir_sas12[sas_dir_index]), + real(vec_dir_sas22[sas_dir_index]), + imag(vec_dir_sas22[sas_dir_index]) + ); + fprintf(p_outfile, " MULS\n"); + for (int i1 = 0; i1 < 4; i1++) { + int muls_dir_index = 16 * jxi * ndirs * configurations + 16 * configurations * dir_index + 16 * si + 4 * i1; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_muls[muls_dir_index], + vec_dir_muls[muls_dir_index + 1], + vec_dir_muls[muls_dir_index + 2], + vec_dir_muls[muls_dir_index + 3] + ); + } // i1 loop + fprintf(p_outfile, " MULSLR\n"); + for (int i1 = 0; i1 < 4; i1++) { + int muls_dir_index = 16 * jxi * ndirs * configurations + 16 * configurations * dir_index + 16 * si + 4 * i1; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_mulslr[muls_dir_index], + vec_dir_mulslr[muls_dir_index + 1], + vec_dir_mulslr[muls_dir_index + 2], + vec_dir_mulslr[muls_dir_index + 3] + ); + } // i1 loop + } // si loop + int sat_dir_index = jxi * ndirs + dir_index; + fprintf( + p_outfile, " SAT(1,1)=%15.7lE%15.7lE, SAT(2,1)=%15.7lE%15.7lE\n", + real(vec_dir_sat11[sat_dir_index]), + imag(vec_dir_sat11[sat_dir_index]), + real(vec_dir_sat21[sat_dir_index]), + imag(vec_dir_sat21[sat_dir_index]) + ); + fprintf( + p_outfile, " SAT(1,2)=%15.7lE%15.7lE, SAT(2,2)=%15.7lE%15.7lE\n", + real(vec_dir_sat12[sat_dir_index]), + imag(vec_dir_sat12[sat_dir_index]), + real(vec_dir_sat22[sat_dir_index]), + imag(vec_dir_sat22[sat_dir_index]) + ); + bool goto190 = isam >= 0 && (jths > 0 || jphs > 0); + fprintf(p_outfile, " CLUSTER\n"); + // Parallel polarization cluster section + if (inpol == 0) + fprintf(p_outfile, " LIN -1\n"); + else + fprintf(p_outfile, " CIRC -1\n"); + + fprintf(p_outfile, " ----- SCC ----- ABC ----- EXC ----- ALBEDC --\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_scc1[sat_dir_index], vec_dir_abc1[sat_dir_index], + vec_dir_exc1[sat_dir_index], vec_dir_albedc1[sat_dir_index] + ); + fprintf(p_outfile, " --- SCC/TGS - ABC/TGS - EXC/TGS ---\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_dir_qscc1[sat_dir_index], + vec_dir_qabc1[sat_dir_index], + vec_dir_qexc1[sat_dir_index] + ); + fprintf(p_outfile, " ---- SCCRT --- ABCRT --- EXCRT ----\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_dir_sccrt1[sat_dir_index], + vec_dir_abcrt1[sat_dir_index], + vec_dir_excrt1[sat_dir_index] + ); + fprintf( + p_outfile, " FSAC(1,1)=%15.7lE%15.7lE FSAC(2,1)=%15.7lE%15.7lE\n", + real(vec_dir_fsac11[sat_dir_index]), + imag(vec_dir_fsac11[sat_dir_index]), + real(vec_dir_fsac21[sat_dir_index]), + imag(vec_dir_fsac21[sat_dir_index]) + ); + fprintf( + p_outfile, " SAC(1,1)=%15.7lE%15.7lE SAC(2,1)=%15.7lE%15.7lE\n", + real(vec_dir_sac11[sat_dir_index]), + imag(vec_dir_sac11[sat_dir_index]), + real(vec_dir_sac21[sat_dir_index]), + imag(vec_dir_sac21[sat_dir_index]) + ); + fprintf( + p_outfile, " RE(FSAC(1,1))/RE(TFSAS)=%15.7lE, IM(FSAC(1,1))/IM(TFSAS)=%15.7lE\n", + real(vec_dir_fsac11[sat_dir_index]) / real(vec_fsat[jxi]), + imag(vec_dir_fsac11[sat_dir_index]) / imag(vec_fsat[jxi]) + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_dir_qschuc1[sat_dir_index], + vec_dir_pschuc1[sat_dir_index], + vec_dir_s0magc1[sat_dir_index] + ); + fprintf( + p_outfile, "INSERTION: CS1_CLUSTER %13.5le%10.3le%10.3le%15.7le%15.7le%15.7le\n", + alamb, th + jth * thstp, ths + jths * thsstp, + vec_dir_scc1[sat_dir_index], + vec_dir_abc1[sat_dir_index], + vec_dir_exc1[sat_dir_index] + ); + if (!goto190) { + fprintf( + p_outfile, " COSAV=%15.7lE, RAPRS=%15.7lE\n", + vec_dir_cosavc1[sat_dir_index], + vec_dir_raprc1[sat_dir_index] + ); + fprintf( + p_outfile, " Fl=%15.7lE, Fr=%15.7lE, Fk=%15.7lE\n", + vec_dir_flc1[sat_dir_index], + vec_dir_frc1[sat_dir_index], + vec_dir_fkc1[sat_dir_index] + ); + fprintf( + p_outfile, " Fx=%15.7lE, Fy=%15.7lE, Fz=%15.7lE\n", + vec_dir_fxc1[sat_dir_index], + vec_dir_fyc1[sat_dir_index], + vec_dir_fzc1[sat_dir_index] + ); + fprintf( + p_outfile, " TQEl=%15.7lE, TQEr=%15.7lE, TQEk=%15.7lE\n", + vec_dir_tqelc1[sat_dir_index], + vec_dir_tqerc1[sat_dir_index], + vec_dir_tqekc1[sat_dir_index] + ); + fprintf( + p_outfile, " TQSl=%15.7lE, TQSr=%15.7lE, TQSk=%15.7lE\n", + vec_dir_tqslc1[sat_dir_index], + vec_dir_tqsrc1[sat_dir_index], + vec_dir_tqskc1[sat_dir_index] + ); + fprintf( + p_outfile, " TQEx=%15.7lE, TQEy=%15.7lE, TQEz=%15.7lE\n", + vec_dir_tqexc1[sat_dir_index], + vec_dir_tqeyc1[sat_dir_index], + vec_dir_tqezc1[sat_dir_index] + ); + fprintf( + p_outfile, " TQSx=%15.7lE, TQSy=%15.7lE, TQSz=%15.7lE\n", + vec_dir_tqsxc1[sat_dir_index], + vec_dir_tqsyc1[sat_dir_index], + vec_dir_tqszc1[sat_dir_index] + ); + } // end goto190 switch + // Perpendicular polarization cluster section + if (inpol == 0) + fprintf(p_outfile, " LIN 1\n"); + else + fprintf(p_outfile, " CIRC 1\n"); + + fprintf(p_outfile, " ----- SCC ----- ABC ----- EXC ----- ALBEDC --\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_scc2[sat_dir_index], vec_dir_abc2[sat_dir_index], + vec_dir_exc2[sat_dir_index], vec_dir_albedc2[sat_dir_index] + ); + fprintf(p_outfile, " --- SCC/TGS - ABC/TGS - EXC/TGS ---\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_dir_qscc2[sat_dir_index], + vec_dir_qabc2[sat_dir_index], + vec_dir_qexc2[sat_dir_index] + ); + fprintf(p_outfile, " ---- SCCRT --- ABCRT --- EXCRT ----\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_dir_sccrt2[sat_dir_index], + vec_dir_abcrt2[sat_dir_index], + vec_dir_excrt2[sat_dir_index] + ); + fprintf( + p_outfile, " FSAC(2,2)=%15.7lE%15.7lE FSAC(1,2)=%15.7lE%15.7lE\n", + real(vec_dir_fsac22[sat_dir_index]), + imag(vec_dir_fsac22[sat_dir_index]), + real(vec_dir_fsac12[sat_dir_index]), + imag(vec_dir_fsac12[sat_dir_index]) + ); + fprintf( + p_outfile, " SAC(2,2)=%15.7lE%15.7lE SAC(1,2)=%15.7lE%15.7lE\n", + real(vec_dir_sac22[sat_dir_index]), + imag(vec_dir_sac22[sat_dir_index]), + real(vec_dir_sac12[sat_dir_index]), + imag(vec_dir_sac12[sat_dir_index]) + ); + fprintf( + p_outfile, " RE(FSAC(2,2))/RE(TFSAS)=%15.7lE, IM(FSAC(2,2))/IM(TFSAS)=%15.7lE\n", + real(vec_dir_fsac22[sat_dir_index]) / real(vec_fsat[jxi]), + imag(vec_dir_fsac22[sat_dir_index]) / imag(vec_fsat[jxi]) + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_dir_qschuc2[sat_dir_index], + vec_dir_pschuc2[sat_dir_index], + vec_dir_s0magc2[sat_dir_index] + ); + fprintf( + p_outfile, "INSERTION: CS2_CLUSTER %13.5le%10.3le%10.3le%15.7le%15.7le%15.7le\n", + alamb, th + jth * thstp, ths + jths * thsstp, + vec_dir_scc2[sat_dir_index], + vec_dir_abc2[sat_dir_index], + vec_dir_exc2[sat_dir_index] + ); + if (!goto190) { + fprintf( + p_outfile, " COSAV=%15.7lE, RAPRS=%15.7lE\n", + vec_dir_cosavc2[sat_dir_index], + vec_dir_raprc2[sat_dir_index] + ); + fprintf( + p_outfile, " Fl=%15.7lE, Fr=%15.7lE, Fk=%15.7lE\n", + vec_dir_flc2[sat_dir_index], + vec_dir_frc2[sat_dir_index], + vec_dir_fkc2[sat_dir_index] + ); + fprintf( + p_outfile, " Fx=%15.7lE, Fy=%15.7lE, Fz=%15.7lE\n", + vec_dir_fxc2[sat_dir_index], + vec_dir_fyc2[sat_dir_index], + vec_dir_fzc2[sat_dir_index] + ); + fprintf( + p_outfile, " TQEl=%15.7lE, TQEr=%15.7lE, TQEk=%15.7lE\n", + vec_dir_tqelc2[sat_dir_index], + vec_dir_tqerc2[sat_dir_index], + vec_dir_tqekc2[sat_dir_index] + ); + fprintf( + p_outfile, " TQSl=%15.7lE, TQSr=%15.7lE, TQSk=%15.7lE\n", + vec_dir_tqslc2[sat_dir_index], + vec_dir_tqsrc2[sat_dir_index], + vec_dir_tqskc2[sat_dir_index] + ); + fprintf( + p_outfile, " TQEx=%15.7lE, TQEy=%15.7lE, TQEz=%15.7lE\n", + vec_dir_tqexc2[sat_dir_index], + vec_dir_tqeyc2[sat_dir_index], + vec_dir_tqezc2[sat_dir_index] + ); + fprintf( + p_outfile, " TQSx=%15.7lE, TQSy=%15.7lE, TQSz=%15.7lE\n", + vec_dir_tqsxc2[sat_dir_index], + vec_dir_tqsyc2[sat_dir_index], + vec_dir_tqszc2[sat_dir_index] + ); + } // end goto190 switch + fprintf( + p_outfile, " (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))=%15.7lE\n", + (real(vec_dir_fsac11[sat_dir_index]) - real(vec_dir_fsac22[sat_dir_index])) / real(vec_dir_fsac11[sat_dir_index]) + ); + fprintf( + p_outfile, " (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))=%15.7lE\n", + (imag(vec_dir_fsac11[sat_dir_index]) - imag(vec_dir_fsac22[sat_dir_index])) / imag(vec_dir_fsac11[sat_dir_index]) + ); + fprintf(p_outfile, " MULC\n"); + for (int i = 0; i < 4; i++) { + int mulc_dir_index = 16 * jxi * ndirs + 16 * dir_index + 4 * i; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_mulc[mulc_dir_index], + vec_dir_mulc[mulc_dir_index + 1], + vec_dir_mulc[mulc_dir_index + 2], + vec_dir_mulc[mulc_dir_index + 3] + ); + } // i mulc loop + fprintf(p_outfile, " MULCLR\n"); + for (int i = 0; i < 4; i++) { + int mulc_dir_index = 16 * jxi * ndirs + 16 * dir_index + 4 * i; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_mulclr[mulc_dir_index], + vec_dir_mulclr[mulc_dir_index + 1], + vec_dir_mulclr[mulc_dir_index + 2], + vec_dir_mulclr[mulc_dir_index + 3] + ); + } // i mulclr loop + if (iavm != 0) { + fprintf(p_outfile, " CLUSTER (ENSEMBLE AVERAGE, MODE%2d)\n", iavm); + if (inpol == 0) + fprintf(p_outfile, " LIN\n"); + else + fprintf(p_outfile, " CIRC\n"); + fprintf(p_outfile, " MULC\n"); + for (int i = 0; i < 4; i++) { + int mulc_dir_index = 16 * jxi + 4 * i; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_mulc[mulc_dir_index], + vec_dir_mulc[mulc_dir_index + 1], + vec_dir_mulc[mulc_dir_index + 2], + vec_dir_mulc[mulc_dir_index + 3] + ); + } // i mulc loop + fprintf(p_outfile, " MULCLR\n"); + for (int i = 0; i < 4; i++) { + int mulc_dir_index = 16 * jxi + 4 * i; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_mulclr[mulc_dir_index], + vec_dir_mulclr[mulc_dir_index + 1], + vec_dir_mulclr[mulc_dir_index + 2], + vec_dir_mulclr[mulc_dir_index + 3] + ); + } + } // end of if (iavm != 0) switch + dir_index++; + } // jphs loop + } // jths loop + } // jph loop + } // jth loop + } // jxi wavelength loop + fclose(p_outfile); + } else { + result = -1; + } + return result; +} + +#ifdef MPI_VERSION +int ClusterOutputInfo::mpireceive(const mixMPI *mpidata, int pid) { + int result = 0; + int chk_nsph, chk_inpol, chk_iavm, chk_isam, chk_num_theta, chk_num_thetas; + int chk_num_phi, chk_num_phis, chk_ndirs, chk_idfc, chk_configs; + double chk_exri; + MPI_Recv(&chk_nsph, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_inpol, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_iavm, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_isam, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_theta, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_thetas, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_phi, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_phis, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_ndirs, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_exri, 1, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_idfc, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_configs, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + result += (chk_nsph == nsph) ? 0 : 1; + result += (chk_inpol == inpol) ? 0 : 1; + result += (chk_iavm == iavm) ? 0 : 1; + result += (chk_isam == isam) ? 0 : 1; + result += (chk_num_theta == _num_theta) ? 0 : 1; + result += (chk_num_thetas == _num_thetas) ? 0 : 1; + result += (chk_num_phi == _num_phi) ? 0 : 1; + result += (chk_num_phis == _num_phis) ? 0 : 1; + result += (chk_ndirs == ndirs) ? 0 : 1; + result += (chk_exri == exri) ? 0 : 1; + result += (chk_idfc == idfc) ? 0 : 1; + result += (chk_configs == configurations) ? 0 : 1; + if (result == 0) { + int xi1, offset, chunk_size; + MPI_Send(&result, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD); + MPI_Recv(&xi1, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chunk_size, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + // Receive vectors of single values per scale + offset = xi1 - _first_xi; + MPI_Recv(vec_jxi + offset, chunk_size, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_ier + offset, chunk_size, MPI_SHORT, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_vk + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_xi + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fsat + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qschut + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_pschut + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_s0magt + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_scc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_scc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_abc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_abc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_exc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_exc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_albedc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_albedc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qscamc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qscamc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qabsmc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qabsmc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qextmc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qextmc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sccrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sccrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_abcrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_abcrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_excrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_excrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fsac11 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fsac21 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fsac22 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fsac12 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qschuc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qschuc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_pschuc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_pschuc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_s0magc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_s0magc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_cosavc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_cosavc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_raprc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_raprc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fkc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fkc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + // Receive vectors of multiple configuration values per scale + MPI_Recv(&chunk_size, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + offset = (xi1 - _first_xi) * configurations; + MPI_Recv(vec_sphere_sizes + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sphere_ref_indices + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sphere_scs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sphere_abs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sphere_exs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sphere_albs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sphere_sqscs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sphere_sqabs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sphere_sqexs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fsas + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qschus + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_pschus + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_s0mags + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_cosavs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_raprs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_tqek1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_tqsk1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_tqek2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_tqsk2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + // Receive vectors whose sizes depend on directions and configurations. + MPI_Recv(&chunk_size, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + offset = (xi1 - _first_xi) * ndirs * configurations; + MPI_Recv(vec_dir_sas11 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sas21 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sas12 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sas22 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_muls + 16 * offset, 16 * chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_mulslr + 16 * offset, 16 * chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + // Receive vectors whose sizes depend on directions and scales. + MPI_Recv(&chunk_size, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + offset = (xi1 - _first_xi) * ndirs; + MPI_Recv(vec_dir_sat11 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sat21 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sat12 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sat22 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_scc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_scc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_abc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_abc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_exc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_exc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_albedc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_albedc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_qscc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_qscc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_qabc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_qabc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_qexc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_qexc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sccrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sccrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_abcrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_abcrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_excrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_excrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fsac11 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fsac21 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fsac12 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fsac22 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sac11 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sac21 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sac12 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sac22 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_qschuc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_qschuc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_pschuc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_pschuc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_s0magc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_s0magc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_cosavc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_cosavc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_raprc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_raprc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_flc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_flc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_frc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_frc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fkc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fkc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fxc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fxc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fyc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fyc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fzc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fzc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqelc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqelc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqerc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqerc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqekc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqekc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqexc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqexc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqeyc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqeyc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqezc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqezc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqslc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqslc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsrc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsrc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqskc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqskc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsxc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsxc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsyc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsyc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqszc1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqszc2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_mulc + 16 * offset, 16 * chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_mulclr + 16 * offset, 16 * chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + } else { + MPI_Send(&result, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD); + } + return result; +} + + +int ClusterOutputInfo::mpisend(const mixMPI *mpidata) { + int result = 0; + int chunk_size; + // Send output metadata for configuration cross-check + MPI_Send(&nsph, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&inpol, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&iavm, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&isam, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_theta, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_thetas, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_phi, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_phis, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&ndirs, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&exri, 1, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(&idfc, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&configurations, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + // Wait for process 0 to cross-check the configuration + MPI_Recv(&result, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + if (result == 0) { + // Process 0 confirmed the consistency of configuration. Send the data. + // Send vectors of single values per scale + MPI_Send(&_first_xi, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&xi_block_size, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_jxi, xi_block_size, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_ier, xi_block_size, MPI_SHORT, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_vk, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_xi, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fsat, xi_block_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qschut, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_pschut, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_s0magt, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_scc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_scc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_abc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_abc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_exc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_exc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_albedc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_albedc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qscamc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qscamc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qabsmc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qabsmc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qextmc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qextmc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sccrt1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sccrt2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_abcrt1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_abcrt2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_excrt1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_excrt2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fsac11, xi_block_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fsac21, xi_block_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fsac22, xi_block_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fsac12, xi_block_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qschuc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qschuc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_pschuc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_pschuc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_s0magc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_s0magc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_cosavc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_cosavc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_raprc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_raprc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fkc1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fkc2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + + // Send vectors of multiple configuration values per scale + chunk_size = xi_block_size * configurations; + MPI_Send(&chunk_size, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_sizes, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_ref_indices, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_scs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_abs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_exs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_albs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_sqscs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_sqabs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_sqexs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fsas, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qschus, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_pschus, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_s0mags, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_cosavs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_raprs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_tqek1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_tqsk1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_tqek2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_tqsk2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + + // Send vectors whose sizes depend on directions and configurations. + chunk_size = ndirs * configurations * xi_block_size; + MPI_Send(&chunk_size, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas11, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas21, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas12, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas22, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_muls, 16 * chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_mulslr, 16 * chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + + // Send vectors whose sizes depend on directions and scales. + chunk_size = xi_block_size * ndirs; + MPI_Send(&chunk_size, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sat11, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sat21, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sat12, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sat22, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_scc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_scc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_abc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_abc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_exc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_exc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_albedc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_albedc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_qscc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_qscc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_qabc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_qabc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_qexc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_qexc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sccrt1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sccrt2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_abcrt1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_abcrt2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_excrt1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_excrt2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fsac11, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fsac21, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fsac12, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fsac22, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sac11, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sac21, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sac12, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sac22, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_qschuc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_qschuc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_pschuc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_pschuc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_s0magc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_s0magc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_cosavc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_cosavc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_raprc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_raprc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_flc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_flc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_frc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_frc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fkc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fkc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fxc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fxc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fyc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fyc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fzc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fzc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqelc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqelc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqerc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqerc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqekc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqekc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqexc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqexc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqeyc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqeyc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqezc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqezc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqslc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqslc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsrc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsrc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqskc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqskc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsxc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsxc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsyc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsyc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqszc1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqszc2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_mulc, 16 * chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_mulclr, 16 * chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + } + return result; +} +#endif //MPI_VERSION +// >>> END OF ClusterOutputInfo CLASS IMPLEMENTATION <<< + +// >>> InclusionOutputInfo CLASS IMPLEMENTATION <<< +InclusionOutputInfo::InclusionOutputInfo( + ScattererConfiguration *sc, GeometryConfiguration *gc, + const mixMPI *mpidata, int first_xi, int xi_length +) { + nsph = gc->number_of_spheres; + li = gc->li; + le = gc->le; + lm = gc->l_max; + mxndm = gc->mxndm; + inpol = gc->in_pol; + npnt = gc->npnt; + npntts = gc->npntts; + iavm = gc->iavm; + isam = gc->isam; + jwtm = gc->jwtm; + // Get spherical constituent coordinates + vec_x_coords = new double[nsph]; + vec_y_coords = new double[nsph]; + vec_z_coords = new double[nsph]; + for (int nsi = 0; nsi < nsph; nsi++) { + vec_x_coords[nsi] = gc->get_sph_x(nsi); + vec_y_coords[nsi] = gc->get_sph_y(nsi); + vec_z_coords[nsi] = gc->get_sph_z(nsi); + } + // Get directional information + th = gc->in_theta_start; + thstp = gc->in_theta_step; + thlst = gc->in_theta_end; + ths = gc->sc_theta_start; + thsstp = gc->sc_theta_step; + thslst = gc->sc_theta_end; + _num_theta = (thstp == 0.0) ? 1 : 1 + int((thlst - th) / thstp); + _num_thetas = (thsstp == 0.0) ? 1 : 1 + int((thslst - ths) / thsstp); + ph = gc->in_phi_start; + phstp = gc->in_phi_step; + phlst = gc->in_phi_end; + phs = gc->sc_phi_start; + phsstp = gc->sc_phi_step; + phslst = gc->sc_phi_end; + _num_phi = (phstp == 0.0) ? 1 : 1 + int((phlst - ph) / phstp); + _num_phis = (phsstp == 0.0) ? 1 : 1 + int((phslst - phs) / phsstp); + ndirs = _num_theta * _num_thetas * _num_phi * _num_phis; + // Get scattering problem configuration + double exdc = sc->exdc; + exri = sqrt(exdc); + idfc = sc->idfc; + nxi = sc->number_of_scales; + _first_xi = first_xi; + xi_block_size = (xi_length == 0) ? nxi - (_first_xi - 1) : xi_length; + vec_jxi = new int[xi_block_size](); + vec_ier = new short[xi_block_size](); + vec_vk = new double[xi_block_size](); + vec_xi = new double[xi_block_size](); + configurations = sc->configurations; + vec_sphere_sizes = new double[xi_block_size * (configurations + 1)](); + vec_sphere_ref_indices = new dcomplex[xi_block_size * (configurations + 1)](); + vec_scs1 = new double[xi_block_size](); + vec_scs2 = new double[xi_block_size](); + vec_abs1 = new double[xi_block_size](); + vec_abs2 = new double[xi_block_size](); + vec_exs1 = new double[xi_block_size](); + vec_exs2 = new double[xi_block_size](); + vec_albeds1 = new double[xi_block_size](); + vec_albeds2 = new double[xi_block_size](); + vec_scsrt1 = new double[xi_block_size](); + vec_scsrt2 = new double[xi_block_size](); + vec_absrt1 = new double[xi_block_size](); + vec_absrt2 = new double[xi_block_size](); + vec_exsrt1 = new double[xi_block_size](); + vec_exsrt2 = new double[xi_block_size](); + vec_qschu1 = new double[xi_block_size](); + vec_qschu2 = new double[xi_block_size](); + vec_pschu1 = new double[xi_block_size](); + vec_pschu2 = new double[xi_block_size](); + vec_s0mag1 = new double[xi_block_size](); + vec_s0mag2 = new double[xi_block_size](); + vec_cosav1 = new double[xi_block_size](); + vec_cosav2 = new double[xi_block_size](); + vec_raprs1 = new double[xi_block_size](); + vec_raprs2 = new double[xi_block_size](); + vec_fk1 = new double[xi_block_size](); + vec_fk2 = new double[xi_block_size](); + vec_fsas11 = new dcomplex[xi_block_size](); + vec_fsas21 = new dcomplex[xi_block_size](); + vec_fsas22 = new dcomplex[xi_block_size](); + vec_fsas12 = new dcomplex[xi_block_size](); + vec_dir_tidg = new double[_num_theta]; + vec_dir_pidg = new double[_num_phi]; + vec_dir_tsdg = new double[_num_thetas]; + vec_dir_psdg = new double[_num_phis]; + // Initialize directions (they are scale-independent) + double cti = th, cpi = ph, cts = ths, cps = phs; + for (int di = 0; di < _num_theta; di++) { + vec_dir_tidg[di] = cti; + cti += thstp; + } + for (int di = 0; di < _num_thetas; di++) { + vec_dir_tsdg[di] = cts; + cts += thsstp; + } + for (int di = 0; di < _num_phi; di++) { + vec_dir_pidg[di] = cpi; + cpi += phstp; + } + for (int di = 0; di < _num_phis; di++) { + vec_dir_psdg[di] = cps; + cps += phsstp; + } + vec_dir_scand = new double[ndirs](); + vec_dir_cfmp = new double[ndirs](); + vec_dir_sfmp = new double[ndirs](); + vec_dir_cfsp = new double[ndirs](); + vec_dir_sfsp = new double[ndirs](); + vec_dir_un = new double[3 * ndirs](); + vec_dir_uns = new double[3 * ndirs](); + vec_dir_scs1 = new double[ndirs * xi_block_size](); + vec_dir_scs2 = new double[ndirs * xi_block_size](); + vec_dir_abs1 = new double[ndirs * xi_block_size](); + vec_dir_abs2 = new double[ndirs * xi_block_size](); + vec_dir_exs1 = new double[ndirs * xi_block_size](); + vec_dir_exs2 = new double[ndirs * xi_block_size](); + vec_dir_albeds1 = new double[ndirs * xi_block_size](); + vec_dir_albeds2 = new double[ndirs * xi_block_size](); + vec_dir_scsrt1 = new double[ndirs * xi_block_size](); + vec_dir_scsrt2 = new double[ndirs * xi_block_size](); + vec_dir_absrt1 = new double[ndirs * xi_block_size](); + vec_dir_absrt2 = new double[ndirs * xi_block_size](); + vec_dir_exsrt1 = new double[ndirs * xi_block_size](); + vec_dir_exsrt2 = new double[ndirs * xi_block_size](); + vec_dir_fsas11 = new dcomplex[ndirs * xi_block_size](); + vec_dir_fsas21 = new dcomplex[ndirs * xi_block_size](); + vec_dir_fsas12 = new dcomplex[ndirs * xi_block_size](); + vec_dir_fsas22 = new dcomplex[ndirs * xi_block_size](); + vec_dir_sas11 = new dcomplex[ndirs * xi_block_size](); + vec_dir_sas21 = new dcomplex[ndirs * xi_block_size](); + vec_dir_sas12 = new dcomplex[ndirs * xi_block_size](); + vec_dir_sas22 = new dcomplex[ndirs * xi_block_size](); + vec_dir_qschu1 = new double[ndirs * xi_block_size](); + vec_dir_qschu2 = new double[ndirs * xi_block_size](); + vec_dir_pschu1 = new double[ndirs * xi_block_size](); + vec_dir_pschu2 = new double[ndirs * xi_block_size](); + vec_dir_s0mag1 = new double[ndirs * xi_block_size](); + vec_dir_s0mag2 = new double[ndirs * xi_block_size](); + vec_dir_cosav1 = new double[ndirs * xi_block_size](); + vec_dir_cosav2 = new double[ndirs * xi_block_size](); + vec_dir_rapr1 = new double[ndirs * xi_block_size](); + vec_dir_rapr2 = new double[ndirs * xi_block_size](); + vec_dir_fl1 = new double[ndirs * xi_block_size](); + vec_dir_fl2 = new double[ndirs * xi_block_size](); + vec_dir_fr1 = new double[ndirs * xi_block_size](); + vec_dir_fr2 = new double[ndirs * xi_block_size](); + vec_dir_fk1 = new double[ndirs * xi_block_size](); + vec_dir_fk2 = new double[ndirs * xi_block_size](); + vec_dir_fx1 = new double[ndirs * xi_block_size](); + vec_dir_fx2 = new double[ndirs * xi_block_size](); + vec_dir_fy1 = new double[ndirs * xi_block_size](); + vec_dir_fy2 = new double[ndirs * xi_block_size](); + vec_dir_fz1 = new double[ndirs * xi_block_size](); + vec_dir_fz2 = new double[ndirs * xi_block_size](); + vec_dir_tqel1 = new double[ndirs * xi_block_size](); + vec_dir_tqel2 = new double[ndirs * xi_block_size](); + vec_dir_tqer1 = new double[ndirs * xi_block_size](); + vec_dir_tqer2 = new double[ndirs * xi_block_size](); + vec_dir_tqek1 = new double[ndirs * xi_block_size](); + vec_dir_tqek2 = new double[ndirs * xi_block_size](); + vec_dir_tqex1 = new double[ndirs * xi_block_size](); + vec_dir_tqex2 = new double[ndirs * xi_block_size](); + vec_dir_tqey1 = new double[ndirs * xi_block_size](); + vec_dir_tqey2 = new double[ndirs * xi_block_size](); + vec_dir_tqez1 = new double[ndirs * xi_block_size](); + vec_dir_tqez2 = new double[ndirs * xi_block_size](); + vec_dir_tqsl1 = new double[ndirs * xi_block_size](); + vec_dir_tqsl2 = new double[ndirs * xi_block_size](); + vec_dir_tqsr1 = new double[ndirs * xi_block_size](); + vec_dir_tqsr2 = new double[ndirs * xi_block_size](); + vec_dir_tqsk1 = new double[ndirs * xi_block_size](); + vec_dir_tqsk2 = new double[ndirs * xi_block_size](); + vec_dir_tqsx1 = new double[ndirs * xi_block_size](); + vec_dir_tqsx2 = new double[ndirs * xi_block_size](); + vec_dir_tqsy1 = new double[ndirs * xi_block_size](); + vec_dir_tqsy2 = new double[ndirs * xi_block_size](); + vec_dir_tqsz1 = new double[ndirs * xi_block_size](); + vec_dir_tqsz2 = new double[ndirs * xi_block_size](); + vec_dir_mull = new double[16 * ndirs * xi_block_size](); + vec_dir_mulllr = new double[16 * ndirs * xi_block_size](); +} + +InclusionOutputInfo::InclusionOutputInfo(const std::string &hdf5_name) { + unsigned int flags = H5F_ACC_RDONLY; + HDFFile *hdf_file = new HDFFile(hdf5_name, flags); + herr_t status = hdf_file->get_status(); + string str_name, str_type; + if (status == 0) { + status = hdf_file->read("NSPH", "INT32_(1)", &nsph); + status = hdf_file->read("LI", "INT32_(1)", &li); + status = hdf_file->read("LE", "INT32_(1)", &le); + status = hdf_file->read("LM", "INT32_(1)", &lm); + long tmp; + status = hdf_file->read("MXNDM", "INT64_(1)", &tmp); + mxndm = (np_int)tmp; + status = hdf_file->read("INPOL", "INT32_(1)", &inpol); + status = hdf_file->read("NPNT", "INT32_(1)", &npnt); + status = hdf_file->read("NPNTTS", "INT32_(1)", &npntts); + status = hdf_file->read("IAVM", "INT32_(1)", &iavm); + status = hdf_file->read("ISAM", "INT32_(1)", &isam); + status = hdf_file->read("JWTM", "INT32_(1)", &jwtm); + str_type = "FLOAT64_(" + to_string(nsph) + ")"; + vec_x_coords = new double[nsph]; + vec_y_coords = new double[nsph]; + vec_z_coords = new double[nsph]; + status = hdf_file->read("VEC_SPH_X", str_type, vec_x_coords); + status = hdf_file->read("VEC_SPH_Y", str_type, vec_y_coords); + status = hdf_file->read("VEC_SPH_Z", str_type, vec_z_coords); + status = hdf_file->read("TH_START", "FLOAT64_(1)", &th); + status = hdf_file->read("TH_STEP", "FLOAT64_(1)", &thstp); + status = hdf_file->read("TH_END", "FLOAT64_(1)", &thlst); + _num_theta = (thstp == 0.0) ? 1 : 1 + int((thlst - th) / thstp); + status = hdf_file->read("THS_START", "FLOAT64_(1)", &ths); + status = hdf_file->read("THS_STEP", "FLOAT64_(1)", &thsstp); + status = hdf_file->read("THS_END", "FLOAT64_(1)", &thslst); + _num_thetas = (thsstp == 0.0) ? 1 : 1 + int((thslst - ths) / thsstp); + status = hdf_file->read("PH_START", "FLOAT64_(1)", &ph); + status = hdf_file->read("PH_STEP", "FLOAT64_(1)", &phstp); + status = hdf_file->read("PH_END", "FLOAT64_(1)", &phlst); + _num_phi = (phstp == 0.0) ? 1 : 1 + int((phlst - ph) / phstp); + status = hdf_file->read("PHS_START", "FLOAT64_(1)", &phs); + status = hdf_file->read("PHS_STEP", "FLOAT64_(1)", &phsstp); + status = hdf_file->read("PHS_END", "FLOAT64_(1)", &phslst); + _num_phis = (phsstp == 0.0) ? 1 : 1 + int((phslst - phs) / phsstp); + ndirs = _num_theta * _num_thetas * _num_phi * _num_phis; + status = hdf_file->read("EXRI", "FLOAT64_(1)", &exri); + status = hdf_file->read("IDFC", "INT32_(1)", &idfc); + status = hdf_file->read("XI1", "INT32_(1)", &_first_xi); + status = hdf_file->read("NXI", "INT32_(1)", &xi_block_size); + nxi = (_first_xi == 1) ? xi_block_size : xi_block_size + _first_xi; + str_type = "INT32_(" + to_string(xi_block_size) + ")"; + vec_jxi = new int[xi_block_size]; + status = hdf_file->read("VEC_JXI", str_type, vec_jxi); + str_type = "INT16_(" + to_string(xi_block_size) + ")"; + vec_ier = new short[xi_block_size]; + status = hdf_file->read("VEC_IER", str_type, vec_ier); + str_type = "FLOAT64_(" + to_string(xi_block_size) + ")"; + vec_vk = new double[xi_block_size]; + status = hdf_file->read("VEC_VK", str_type, vec_vk); + vec_xi = new double[xi_block_size]; + status = hdf_file->read("VEC_VK", str_type, vec_xi); + status = hdf_file->read("NCONF", "INT32_(1)", &configurations); + str_type = "FLOAT64_(" + to_string(xi_block_size * (configurations + 1)) + ")"; + vec_sphere_sizes = new double[xi_block_size * (configurations + 1)]; + status = hdf_file->read("VEC_SPH_SIZES", str_type, vec_sphere_sizes); + str_type = "FLOAT64_(" + to_string(2 * xi_block_size * (configurations + 1)) + ")"; + vec_sphere_ref_indices = new dcomplex[xi_block_size * (configurations + 1)]; + status = hdf_file->read("VEC_SPH_REFRI", str_type, vec_sphere_ref_indices); + str_type = "FLOAT64_(" + to_string(xi_block_size) + ")"; + vec_scs1 = new double[xi_block_size]; + status = hdf_file->read("VEC_SCS1", str_type, vec_scs1); + vec_scs2 = new double[xi_block_size]; + status = hdf_file->read("VEC_SCS2", str_type, vec_scs2); + vec_abs1 = new double[xi_block_size]; + status = hdf_file->read("VEC_ABS1", str_type, vec_abs1); + vec_abs2 = new double[xi_block_size]; + status = hdf_file->read("VEC_ABS2", str_type, vec_abs2); + vec_exs1 = new double[xi_block_size]; + status = hdf_file->read("VEC_EXS1", str_type, vec_exs1); + vec_exs2 = new double[xi_block_size]; + status = hdf_file->read("VEC_EXS2", str_type, vec_exs2); + vec_albeds1 = new double[xi_block_size]; + status = hdf_file->read("VEC_ALBEDS1", str_type, vec_albeds1); + vec_albeds2 = new double[xi_block_size]; + status = hdf_file->read("VEC_ALBEDS2", str_type, vec_albeds2); + vec_scsrt1 = new double[xi_block_size]; + status = hdf_file->read("VEC_SCSRT1", str_type, vec_scsrt1); + vec_scsrt2 = new double[xi_block_size]; + status = hdf_file->read("VEC_SCSRT2", str_type, vec_scsrt2); + vec_absrt1 = new double[xi_block_size]; + status = hdf_file->read("VEC_ABSRT1", str_type, vec_absrt1); + vec_absrt2 = new double[xi_block_size]; + status = hdf_file->read("VEC_ABSRT2", str_type, vec_absrt2); + vec_exsrt1 = new double[xi_block_size]; + status = hdf_file->read("VEC_EXSRT1", str_type, vec_exsrt1); + vec_exsrt2 = new double[xi_block_size]; + status = hdf_file->read("VEC_EXSRT2", str_type, vec_exsrt2); + vec_qschu1 = new double[xi_block_size]; + status = hdf_file->read("VEC_QSCHU1", str_type, vec_qschu1); + vec_qschu2 = new double[xi_block_size]; + status = hdf_file->read("VEC_QSCHU2", str_type, vec_qschu2); + vec_pschu1 = new double[xi_block_size]; + status = hdf_file->read("VEC_PSCHU1", str_type, vec_pschu1); + vec_pschu2 = new double[xi_block_size]; + status = hdf_file->read("VEC_PSCHU2", str_type, vec_pschu2); + vec_s0mag1 = new double[xi_block_size]; + status = hdf_file->read("VEC_S0MAG1", str_type, vec_s0mag1); + vec_s0mag2 = new double[xi_block_size]; + status = hdf_file->read("VEC_S0MAG2", str_type, vec_s0mag2); + vec_cosav1 = new double[xi_block_size]; + status = hdf_file->read("VEC_COSAV1", str_type, vec_cosav1); + vec_cosav2 = new double[xi_block_size]; + status = hdf_file->read("VEC_COSAV2", str_type, vec_cosav2); + vec_raprs1 = new double[xi_block_size]; + status = hdf_file->read("VEC_RAPRS1", str_type, vec_raprs1); + vec_raprs2 = new double[xi_block_size]; + status = hdf_file->read("VEC_RAPRS2", str_type, vec_raprs2); + vec_fk1 = new double[xi_block_size]; + status = hdf_file->read("VEC_FK1", str_type, vec_fk1); + vec_fk2 = new double[xi_block_size]; + status = hdf_file->read("VEC_FK2", str_type, vec_fk2); + str_type = "FLOAT64_(" + to_string(2 * xi_block_size) + ")"; + vec_fsas11 = new dcomplex[xi_block_size]; + status = hdf_file->read("VEC_FSAS11", str_type, vec_fsas11); + vec_fsas21 = new dcomplex[xi_block_size]; + status = hdf_file->read("VEC_FSAS21", str_type, vec_fsas21); + vec_fsas22 = new dcomplex[xi_block_size]; + status = hdf_file->read("VEC_FSAS22", str_type, vec_fsas22); + vec_fsas12 = new dcomplex[xi_block_size]; + status = hdf_file->read("VEC_FSAS12", str_type, vec_fsas12); + // Initialize directions (they are scale-independent) + vec_dir_tidg = new double[_num_theta]; + vec_dir_tsdg = new double[_num_thetas]; + vec_dir_pidg = new double[_num_phi]; + vec_dir_psdg = new double[_num_phis]; + double cti = th, cpi = ph, cts = ths, cps = phs; + for (int di = 0; di < _num_theta; di++) { + vec_dir_tidg[di] = cti; + cti += thstp; + } + for (int di = 0; di < _num_thetas; di++) { + vec_dir_tsdg[di] = cts; + cts += thsstp; + } + for (int di = 0; di < _num_phi; di++) { + vec_dir_pidg[di] = cpi; + cpi += phstp; + } + for (int di = 0; di < _num_phis; di++) { + vec_dir_psdg[di] = cps; + cps += phsstp; + } + str_type = "FLOAT64_(" + to_string(ndirs) + ")"; + vec_dir_scand = new double[ndirs]; + status = hdf_file->read("VEC_DIR_SCAND", str_type, vec_dir_scand); + vec_dir_cfmp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_CFMP", str_type, vec_dir_cfmp); + vec_dir_sfmp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_SFMP", str_type, vec_dir_sfmp); + vec_dir_cfsp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_CFSP", str_type, vec_dir_cfsp); + vec_dir_sfsp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_SFSP", str_type, vec_dir_sfsp); + str_type = "FLOAT64_(" + to_string(3 * ndirs) + ")"; + vec_dir_un = new double[3 * ndirs]; + status = hdf_file->read("VEC_DIR_UN", str_type, vec_dir_un); + vec_dir_uns = new double[3 * ndirs]; + status = hdf_file->read("VEC_DIR_UNS", str_type, vec_dir_uns); + str_type = "FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"; + vec_dir_scs1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SCS1", str_type, vec_dir_scs1); + vec_dir_scs2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SCS2", str_type, vec_dir_scs2); + vec_dir_abs1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ABS1", str_type, vec_dir_abs1); + vec_dir_abs2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ABS2", str_type, vec_dir_abs2); + vec_dir_exs1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_EXS1", str_type, vec_dir_exs1); + vec_dir_exs2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_EXS2", str_type, vec_dir_exs2); + vec_dir_albeds1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ALBEDS1", str_type, vec_dir_albeds1); + vec_dir_albeds2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ALBEDS2", str_type, vec_dir_albeds2); + vec_dir_scsrt1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SCSRT1", str_type, vec_dir_scsrt1); + vec_dir_scsrt2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SCSRT2", str_type, vec_dir_scsrt2); + vec_dir_absrt1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ABSRT1", str_type, vec_dir_absrt1); + vec_dir_absrt2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_ABSRT2", str_type, vec_dir_absrt2); + vec_dir_exsrt1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_EXSRT1", str_type, vec_dir_exsrt1); + vec_dir_exsrt2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_EXSRT2", str_type, vec_dir_exsrt2); + str_type = "FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"; + vec_dir_fsas11 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FSAS11", str_type, vec_dir_fsas11); + vec_dir_fsas21 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FSAS21", str_type, vec_dir_fsas21); + vec_dir_fsas12 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FSAS12", str_type, vec_dir_fsas12); + vec_dir_fsas22 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FSAS22", str_type, vec_dir_fsas22); + vec_dir_sas11 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS11", str_type, vec_dir_sas11); + vec_dir_sas21 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS21", str_type, vec_dir_sas21); + vec_dir_sas12 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS12", str_type, vec_dir_sas12); + vec_dir_sas22 = new dcomplex[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS22", str_type, vec_dir_sas22); + str_type = "FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"; + vec_dir_qschu1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_QSCHU1", str_type, vec_dir_qschu1); + vec_dir_qschu2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_QSCHU2", str_type, vec_dir_qschu2); + vec_dir_pschu1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_PSCHU1", str_type, vec_dir_pschu1); + vec_dir_pschu2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_PSCHU2", str_type, vec_dir_pschu2); + vec_dir_s0mag1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_S0MAG1", str_type, vec_dir_s0mag1); + vec_dir_s0mag2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_S0MAG2", str_type, vec_dir_s0mag2); + vec_dir_cosav1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_COSAV1", str_type, vec_dir_cosav1); + vec_dir_cosav2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_COSAV2", str_type, vec_dir_cosav2); + vec_dir_rapr1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_RAPR1", str_type, vec_dir_rapr1); + vec_dir_rapr2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_RAPR2", str_type, vec_dir_rapr2); + vec_dir_fl1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FL1", str_type, vec_dir_fl1); + vec_dir_fl2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FL2", str_type, vec_dir_fl2); + vec_dir_fr1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FR1", str_type, vec_dir_fr1); + vec_dir_fr2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FR2", str_type, vec_dir_fr2); + vec_dir_fk1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FK1", str_type, vec_dir_fk1); + vec_dir_fk2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FK2", str_type, vec_dir_fk2); + vec_dir_fx1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FX1", str_type, vec_dir_fx1); + vec_dir_fx2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FX2", str_type, vec_dir_fx2); + vec_dir_fy1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FY1", str_type, vec_dir_fy1); + vec_dir_fy2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FY2", str_type, vec_dir_fy2); + vec_dir_fz1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FZ1", str_type, vec_dir_fz1); + vec_dir_fz2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_FZ2", str_type, vec_dir_fz2); + vec_dir_tqel1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEL1", str_type, vec_dir_tqel1); + vec_dir_tqel2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEL2", str_type, vec_dir_tqel2); + vec_dir_tqer1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQER1", str_type, vec_dir_tqer1); + vec_dir_tqer2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQER2", str_type, vec_dir_tqer2); + vec_dir_tqek1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEK1", str_type, vec_dir_tqek1); + vec_dir_tqek2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEK2", str_type, vec_dir_tqek2); + vec_dir_tqex1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEX1", str_type, vec_dir_tqex1); + vec_dir_tqex2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEX2", str_type, vec_dir_tqex2); + vec_dir_tqey1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEY1", str_type, vec_dir_tqey1); + vec_dir_tqey2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEY2", str_type, vec_dir_tqey2); + vec_dir_tqez1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEZ1", str_type, vec_dir_tqez1); + vec_dir_tqez2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQEZ2", str_type, vec_dir_tqez2); + vec_dir_tqsl1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSL1", str_type, vec_dir_tqsl1); + vec_dir_tqsl2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSL2", str_type, vec_dir_tqsl2); + vec_dir_tqsr1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSR1", str_type, vec_dir_tqsr1); + vec_dir_tqsr2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSR2", str_type, vec_dir_tqsr2); + vec_dir_tqsk1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSK1", str_type, vec_dir_tqsk1); + vec_dir_tqsk2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSK2", str_type, vec_dir_tqsk2); + vec_dir_tqsx1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSX1", str_type, vec_dir_tqsx1); + vec_dir_tqsx2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSX2", str_type, vec_dir_tqsx2); + vec_dir_tqsy1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSY1", str_type, vec_dir_tqsy1); + vec_dir_tqsy2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSY2", str_type, vec_dir_tqsy2); + vec_dir_tqsz1 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSZ1", str_type, vec_dir_tqsz1); + vec_dir_tqsz2 = new double[ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_TQSZ2", str_type, vec_dir_tqsz2); + str_type = "FLOAT64_(" + to_string(16 * ndirs * xi_block_size) + ")"; + vec_dir_mull = new double[16 * ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_MULL", str_type, vec_dir_mull); + vec_dir_mulllr = new double[16 * ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_MULLLR", str_type, vec_dir_mulllr); + status = hdf_file->close(); + delete hdf_file; + } else { + if (hdf_file != NULL) delete hdf_file; + UnrecognizedFormatException ex("Error: " + hdf5_name + " not recognized as a valid HDF5 file!"); + throw ex; + } +} + +InclusionOutputInfo::~InclusionOutputInfo() { + delete[] vec_x_coords; + delete[] vec_y_coords; + delete[] vec_z_coords; + delete[] vec_jxi; + delete[] vec_ier; + delete[] vec_vk; + delete[] vec_xi; + delete[] vec_sphere_sizes; + delete[] vec_sphere_ref_indices; + delete[] vec_scs1; + delete[] vec_scs2; + delete[] vec_abs1; + delete[] vec_abs2; + delete[] vec_exs1; + delete[] vec_exs2; + delete[] vec_albeds1; + delete[] vec_albeds2; + delete[] vec_scsrt1; + delete[] vec_scsrt2; + delete[] vec_absrt1; + delete[] vec_absrt2; + delete[] vec_exsrt1; + delete[] vec_exsrt2; + delete[] vec_qschu1; + delete[] vec_qschu2; + delete[] vec_pschu1; + delete[] vec_pschu2; + delete[] vec_s0mag1; + delete[] vec_s0mag2; + delete[] vec_cosav1; + delete[] vec_cosav2; + delete[] vec_raprs1; + delete[] vec_raprs2; + delete[] vec_fk1; + delete[] vec_fk2; + delete[] vec_fsas11; + delete[] vec_fsas21; + delete[] vec_fsas22; + delete[] vec_fsas12; + delete[] vec_dir_tidg; + delete[] vec_dir_pidg; + delete[] vec_dir_tsdg; + delete[] vec_dir_psdg; + delete[] vec_dir_scand; + delete[] vec_dir_cfmp; + delete[] vec_dir_sfmp; + delete[] vec_dir_cfsp; + delete[] vec_dir_sfsp; + delete[] vec_dir_un; + delete[] vec_dir_uns; + delete[] vec_dir_scs1; + delete[] vec_dir_scs2; + delete[] vec_dir_abs1; + delete[] vec_dir_abs2; + delete[] vec_dir_exs1; + delete[] vec_dir_exs2; + delete[] vec_dir_albeds1; + delete[] vec_dir_albeds2; + delete[] vec_dir_scsrt1; + delete[] vec_dir_scsrt2; + delete[] vec_dir_absrt1; + delete[] vec_dir_absrt2; + delete[] vec_dir_exsrt1; + delete[] vec_dir_exsrt2; + delete[] vec_dir_fsas11; + delete[] vec_dir_fsas21; + delete[] vec_dir_fsas12; + delete[] vec_dir_fsas22; + delete[] vec_dir_sas11; + delete[] vec_dir_sas21; + delete[] vec_dir_sas12; + delete[] vec_dir_sas22; + delete[] vec_dir_qschu1; + delete[] vec_dir_qschu2; + delete[] vec_dir_pschu1; + delete[] vec_dir_pschu2; + delete[] vec_dir_s0mag1; + delete[] vec_dir_s0mag2; + delete[] vec_dir_cosav1; + delete[] vec_dir_cosav2; + delete[] vec_dir_rapr1; + delete[] vec_dir_rapr2; + delete[] vec_dir_fl1; + delete[] vec_dir_fl2; + delete[] vec_dir_fr1; + delete[] vec_dir_fr2; + delete[] vec_dir_fk1; + delete[] vec_dir_fk2; + delete[] vec_dir_fx1; + delete[] vec_dir_fx2; + delete[] vec_dir_fy1; + delete[] vec_dir_fy2; + delete[] vec_dir_fz1; + delete[] vec_dir_fz2; + delete[] vec_dir_tqel1; + delete[] vec_dir_tqel2; + delete[] vec_dir_tqer1; + delete[] vec_dir_tqer2; + delete[] vec_dir_tqek1; + delete[] vec_dir_tqek2; + delete[] vec_dir_tqex1; + delete[] vec_dir_tqex2; + delete[] vec_dir_tqey1; + delete[] vec_dir_tqey2; + delete[] vec_dir_tqez1; + delete[] vec_dir_tqez2; + delete[] vec_dir_tqsl1; + delete[] vec_dir_tqsl2; + delete[] vec_dir_tqsr1; + delete[] vec_dir_tqsr2; + delete[] vec_dir_tqsk1; + delete[] vec_dir_tqsk2; + delete[] vec_dir_tqsx1; + delete[] vec_dir_tqsx2; + delete[] vec_dir_tqsy1; + delete[] vec_dir_tqsy2; + delete[] vec_dir_tqsz1; + delete[] vec_dir_tqsz2; + delete[] vec_dir_mull; + delete[] vec_dir_mulllr; +} + +long InclusionOutputInfo::compute_size() { + long result = sizeof(np_int); + result += 21 * sizeof(int); + result += 13 * sizeof(double); + result += 120 * sizeof(long); // vector pointers + result += xi_block_size * (sizeof(int) + sizeof(short)); // vec_jxi, vec_ier + result += 3 * nsph * sizeof(double); // coordinate vectors + result += 29 * xi_block_size * sizeof(double); // wavelength dependent real values + result += 5 * xi_block_size * sizeof(dcomplex); // wavelength dependent complex values + result += 15 * ndirs * sizeof(double); // values depending only on directions + result += 92 * ndirs * xi_block_size * sizeof(double); // values depending on directions and wavelengths + result += 8 * ndirs * xi_block_size * sizeof(dcomplex); // values depending on directions and wavelengths + return result; +} + +long InclusionOutputInfo::compute_size( + ScattererConfiguration *sc, GeometryConfiguration *gc, + int first_xi, int xi_length +) { + long result = sizeof(np_int); + result += 21 * sizeof(int); + result += 13 * sizeof(double); + result += 120 * sizeof(long); // vector pointers + int _nsph = gc->number_of_spheres; + double _th = gc->in_theta_start; + double _thstp = gc->in_theta_step; + double _thlst = gc->in_theta_end; + double _ths = gc->sc_theta_start; + double _thsstp = gc->sc_theta_step; + double _thslst = gc->sc_theta_end; + int num_theta = 1 + int((_thlst - _th) / _thstp); + int num_thetas = 1 + int((_thslst - _ths) / _thsstp); + double _ph = gc->in_phi_start; + double _phstp = gc->in_phi_step; + double _phlst = gc->in_phi_end; + double _phs = gc->sc_phi_start; + double _phsstp = gc->sc_phi_step; + double _phslst = gc->sc_phi_end; + int num_phi = 1 + int((_phlst - _ph) / _phstp); + int num_phis = 1 + int((_phslst - _phs) / _phsstp); + int _ndirs = num_theta * num_thetas * num_phi * num_phis; + int _nxi = sc->number_of_scales; + int _xi_block_size = (xi_length == 0) ? _nxi : xi_length; + int _configurations = sc->configurations; + result += _xi_block_size * (sizeof(int) + sizeof(short)); // vec_jxi, vec_ier + result += 3 * _nsph * sizeof(double); // coordinate vectors + result += 29 * _xi_block_size * sizeof(double); // wavelength dependent real values + result += 5 * _xi_block_size * sizeof(dcomplex); // wavelength dependent complex values + result += 15 * _ndirs * sizeof(double); // values depending only on directions + result += 92 * _ndirs * _xi_block_size * sizeof(double); // values depending on directions and wavelengths + result += 8 * _ndirs * _xi_block_size * sizeof(dcomplex); // values depending on directions and wavelengths + return result; +} + +int InclusionOutputInfo::insert(const InclusionOutputInfo &rhs) { + int result = 0; + result += (rhs.nsph == nsph) ? 0 : 1; + result += (rhs.inpol == inpol) ? 0 : 1; + result += (rhs.iavm == iavm) ? 0 : 1; + result += (rhs.isam == isam) ? 0 : 1; + result += (rhs._num_theta == _num_theta) ? 0 : 1; + result += (rhs._num_thetas == _num_thetas) ? 0 : 1; + result += (rhs._num_phi == _num_phi) ? 0 : 1; + result += (rhs._num_phis == _num_phis) ? 0 : 1; + result += (rhs.ndirs == ndirs) ? 0 : 1; + result += (rhs.exri == exri) ? 0 : 1; + result += (rhs.idfc == idfc) ? 0 : 1; + result += (rhs.configurations == configurations) ? 0 : 1; + if (result == 0) { + int offset, chunk_size, xi1; + xi1 = rhs._first_xi; + // Insert vectors whose size depends on wavelengths + offset = xi1 - _first_xi; + chunk_size = rhs.xi_block_size; + memcpy(vec_jxi + offset, rhs.vec_jxi, chunk_size * sizeof(int)); + memcpy(vec_ier + offset, rhs.vec_ier, chunk_size * sizeof(short)); + memcpy(vec_vk + offset, rhs.vec_vk, chunk_size * sizeof(double)); + memcpy(vec_xi + offset, rhs.vec_xi, chunk_size * sizeof(double)); + memcpy(vec_scs1 + offset, rhs.vec_scs1, chunk_size * sizeof(double)); + memcpy(vec_scs2 + offset, rhs.vec_scs2, chunk_size * sizeof(double)); + memcpy(vec_abs1 + offset, rhs.vec_abs1, chunk_size * sizeof(double)); + memcpy(vec_abs2 + offset, rhs.vec_abs2, chunk_size * sizeof(double)); + memcpy(vec_exs1 + offset, rhs.vec_exs1, chunk_size * sizeof(double)); + memcpy(vec_exs2 + offset, rhs.vec_exs2, chunk_size * sizeof(double)); + memcpy(vec_albeds1 + offset, rhs.vec_albeds1, chunk_size * sizeof(double)); + memcpy(vec_albeds2 + offset, rhs.vec_albeds2, chunk_size * sizeof(double)); + memcpy(vec_scsrt1 + offset, rhs.vec_scsrt1, chunk_size * sizeof(double)); + memcpy(vec_scsrt2 + offset, rhs.vec_scsrt2, chunk_size * sizeof(double)); + memcpy(vec_absrt1 + offset, rhs.vec_absrt1, chunk_size * sizeof(double)); + memcpy(vec_absrt2 + offset, rhs.vec_absrt2, chunk_size * sizeof(double)); + memcpy(vec_exsrt1 + offset, rhs.vec_exsrt1, chunk_size * sizeof(double)); + memcpy(vec_exsrt2 + offset, rhs.vec_exsrt2, chunk_size * sizeof(double)); + memcpy(vec_qschu1 + offset, rhs.vec_qschu1, chunk_size * sizeof(double)); + memcpy(vec_qschu2 + offset, rhs.vec_qschu2, chunk_size * sizeof(double)); + memcpy(vec_pschu1 + offset, rhs.vec_pschu1, chunk_size * sizeof(double)); + memcpy(vec_pschu2 + offset, rhs.vec_pschu2, chunk_size * sizeof(double)); + memcpy(vec_s0mag1 + offset, rhs.vec_s0mag1, chunk_size * sizeof(double)); + memcpy(vec_s0mag2 + offset, rhs.vec_s0mag2, chunk_size * sizeof(double)); + memcpy(vec_cosav1 + offset, rhs.vec_cosav1, chunk_size * sizeof(double)); + memcpy(vec_cosav2 + offset, rhs.vec_cosav2, chunk_size * sizeof(double)); + memcpy(vec_raprs1 + offset, rhs.vec_raprs1, chunk_size * sizeof(double)); + memcpy(vec_raprs2 + offset, rhs.vec_raprs2, chunk_size * sizeof(double)); + memcpy(vec_fk1 + offset, rhs.vec_fk1, chunk_size * sizeof(double)); + memcpy(vec_fk2 + offset, rhs.vec_fk2, chunk_size * sizeof(double)); + memcpy(vec_fsas11 + offset, rhs.vec_fsas11, chunk_size * sizeof(dcomplex)); + memcpy(vec_fsas21 + offset, rhs.vec_fsas21, chunk_size * sizeof(dcomplex)); + memcpy(vec_fsas22 + offset, rhs.vec_fsas22, chunk_size * sizeof(dcomplex)); + memcpy(vec_fsas12 + offset, rhs.vec_fsas12, chunk_size * sizeof(dcomplex)); + + // Insert vectors whose sizes depend on configurations + offset = (xi1 - _first_xi) * (configurations + 1); + chunk_size = rhs.xi_block_size * (configurations + 1); + memcpy(vec_sphere_sizes + offset, rhs.vec_sphere_sizes, chunk_size * sizeof(double)); + memcpy(vec_sphere_ref_indices + offset, rhs.vec_sphere_ref_indices, chunk_size * sizeof(dcomplex)); + + // Insert vectors whose sizes depend on directions and wavelengths + offset = (xi1 - _first_xi) * ndirs; + chunk_size = rhs.xi_block_size * ndirs; + memcpy(vec_dir_scs1 + offset, rhs.vec_dir_scs1, chunk_size * sizeof(double)); + memcpy(vec_dir_scs2 + offset, rhs.vec_dir_scs2, chunk_size * sizeof(double)); + memcpy(vec_dir_abs1 + offset, rhs.vec_dir_abs1, chunk_size * sizeof(double)); + memcpy(vec_dir_abs2 + offset, rhs.vec_dir_abs2, chunk_size * sizeof(double)); + memcpy(vec_dir_exs1 + offset, rhs.vec_dir_exs1, chunk_size * sizeof(double)); + memcpy(vec_dir_exs2 + offset, rhs.vec_dir_exs2, chunk_size * sizeof(double)); + memcpy(vec_dir_albeds1 + offset, rhs.vec_dir_albeds1, chunk_size * sizeof(double)); + memcpy(vec_dir_albeds2 + offset, rhs.vec_dir_albeds2, chunk_size * sizeof(double)); + memcpy(vec_dir_scsrt1 + offset, rhs.vec_dir_scsrt1, chunk_size * sizeof(double)); + memcpy(vec_dir_scsrt2 + offset, rhs.vec_dir_scsrt2, chunk_size * sizeof(double)); + memcpy(vec_dir_absrt1 + offset, rhs.vec_dir_absrt1, chunk_size * sizeof(double)); + memcpy(vec_dir_absrt2 + offset, rhs.vec_dir_absrt2, chunk_size * sizeof(double)); + memcpy(vec_dir_exsrt1 + offset, rhs.vec_dir_exsrt1, chunk_size * sizeof(double)); + memcpy(vec_dir_exsrt2 + offset, rhs.vec_dir_exsrt2, chunk_size * sizeof(double)); + memcpy(vec_dir_fsas11 + offset, rhs.vec_dir_fsas11, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_fsas21 + offset, rhs.vec_dir_fsas21, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_fsas12 + offset, rhs.vec_dir_fsas12, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_fsas22 + offset, rhs.vec_dir_fsas22, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sas11 + offset, rhs.vec_dir_sas11, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sas21 + offset, rhs.vec_dir_sas21, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sas12 + offset, rhs.vec_dir_sas12, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sas22 + offset, rhs.vec_dir_sas22, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_qschu1 + offset, rhs.vec_dir_qschu1, chunk_size * sizeof(double)); + memcpy(vec_dir_qschu2 + offset, rhs.vec_dir_qschu2, chunk_size * sizeof(double)); + memcpy(vec_dir_pschu1 + offset, rhs.vec_dir_pschu1, chunk_size * sizeof(double)); + memcpy(vec_dir_pschu2 + offset, rhs.vec_dir_pschu2, chunk_size * sizeof(double)); + memcpy(vec_dir_s0mag1 + offset, rhs.vec_dir_s0mag1, chunk_size * sizeof(double)); + memcpy(vec_dir_s0mag2 + offset, rhs.vec_dir_s0mag2, chunk_size * sizeof(double)); + memcpy(vec_dir_cosav1 + offset, rhs.vec_dir_cosav1, chunk_size * sizeof(double)); + memcpy(vec_dir_cosav2 + offset, rhs.vec_dir_cosav2, chunk_size * sizeof(double)); + memcpy(vec_dir_rapr1 + offset, rhs.vec_dir_rapr1, chunk_size * sizeof(double)); + memcpy(vec_dir_rapr2 + offset, rhs.vec_dir_rapr2, chunk_size * sizeof(double)); + memcpy(vec_dir_fl1 + offset, rhs.vec_dir_fl1, chunk_size * sizeof(double)); + memcpy(vec_dir_fl2 + offset, rhs.vec_dir_fl2, chunk_size * sizeof(double)); + memcpy(vec_dir_fr1 + offset, rhs.vec_dir_fr1, chunk_size * sizeof(double)); + memcpy(vec_dir_fr2 + offset, rhs.vec_dir_fr2, chunk_size * sizeof(double)); + memcpy(vec_dir_fk1 + offset, rhs.vec_dir_fk1, chunk_size * sizeof(double)); + memcpy(vec_dir_fk2 + offset, rhs.vec_dir_fk2, chunk_size * sizeof(double)); + memcpy(vec_dir_fx1 + offset, rhs.vec_dir_fx1, chunk_size * sizeof(double)); + memcpy(vec_dir_fx2 + offset, rhs.vec_dir_fx2, chunk_size * sizeof(double)); + memcpy(vec_dir_fy1 + offset, rhs.vec_dir_fy1, chunk_size * sizeof(double)); + memcpy(vec_dir_fy2 + offset, rhs.vec_dir_fy2, chunk_size * sizeof(double)); + memcpy(vec_dir_fz1 + offset, rhs.vec_dir_fz1, chunk_size * sizeof(double)); + memcpy(vec_dir_fz2 + offset, rhs.vec_dir_fz2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqel1 + offset, rhs.vec_dir_tqel1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqel2 + offset, rhs.vec_dir_tqel2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqer1 + offset, rhs.vec_dir_tqer1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqer2 + offset, rhs.vec_dir_tqer2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqek1 + offset, rhs.vec_dir_tqek1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqek2 + offset, rhs.vec_dir_tqek2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqex1 + offset, rhs.vec_dir_tqex1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqex2 + offset, rhs.vec_dir_tqex2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqey1 + offset, rhs.vec_dir_tqey1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqey2 + offset, rhs.vec_dir_tqey2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqez1 + offset, rhs.vec_dir_tqez1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqez2 + offset, rhs.vec_dir_tqez2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsl1 + offset, rhs.vec_dir_tqsl1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsl2 + offset, rhs.vec_dir_tqsl2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsr1 + offset, rhs.vec_dir_tqsr1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsr2 + offset, rhs.vec_dir_tqsr2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsk1 + offset, rhs.vec_dir_tqsk1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsk2 + offset, rhs.vec_dir_tqsk2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsx1 + offset, rhs.vec_dir_tqsx1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsx2 + offset, rhs.vec_dir_tqsx2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsy1 + offset, rhs.vec_dir_tqsy1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsy2 + offset, rhs.vec_dir_tqsy2, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsz1 + offset, rhs.vec_dir_tqsz1, chunk_size * sizeof(double)); + memcpy(vec_dir_tqsz2 + offset, rhs.vec_dir_tqsz2, chunk_size * sizeof(double)); + memcpy(vec_dir_mull + 16 * offset, rhs.vec_dir_mull, 16 * chunk_size * sizeof(double)); + memcpy(vec_dir_mulllr + 16 * offset, rhs.vec_dir_mulllr, 16 * chunk_size * sizeof(double)); + } + return result; +} + +int InclusionOutputInfo::write(const std::string &output, const std::string &format) { + int result = 0; + if (format.compare("LEGACY") == 0) { + result = write_legacy(output); + } else if (format.compare("HDF5") == 0) { + result = write_hdf5(output); + } else { + string message = "Unknown format mode: \"" + format + "\""; + throw UnrecognizedConfigurationException(message); + } + return result; +} + +int InclusionOutputInfo::write_hdf5(const std::string &file_name) { + List<string> *rec_name_list = new List<string>(1); + List<string> *rec_type_list = new List<string>(1); + List<void *> *rec_ptr_list = new List<void *>(1); + string str_type, str_name; + rec_name_list->set(0, "NSPH"); + rec_type_list->set(0, "INT32_(1)"); + rec_ptr_list->set(0, &nsph); + rec_name_list->append("LI"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&li); + rec_name_list->append("LE"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&le); + rec_name_list->append("LM"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&lm); + rec_name_list->append("MXNDM"); + rec_type_list->append("INT64_(1)"); + rec_ptr_list->append(&mxndm); + rec_name_list->append("INPOL"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&inpol); + rec_name_list->append("NPNT"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&npnt); + rec_name_list->append("NPNTTS"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&npntts); + rec_name_list->append("IAVM"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&iavm); + rec_name_list->append("ISAM"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&isam); + rec_name_list->append("JWTM"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&jwtm); + rec_name_list->append("VEC_SPH_X"); + rec_type_list->append("FLOAT64_(" + to_string(nsph) + ")"); + rec_ptr_list->append(vec_x_coords); + rec_name_list->append("VEC_SPH_Y"); + rec_type_list->append("FLOAT64_(" + to_string(nsph) + ")"); + rec_ptr_list->append(vec_y_coords); + rec_name_list->append("VEC_SPH_Z"); + rec_type_list->append("FLOAT64_(" + to_string(nsph) + ")"); + rec_ptr_list->append(vec_z_coords); + rec_name_list->append("TH_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&th); + rec_name_list->append("TH_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thstp); + rec_name_list->append("TH_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thlst); + rec_name_list->append("THS_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&ths); + rec_name_list->append("THS_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thsstp); + rec_name_list->append("THS_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thslst); + rec_name_list->append("PH_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&ph); + rec_name_list->append("PH_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phstp); + rec_name_list->append("PH_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phlst); + rec_name_list->append("PHS_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phs); + rec_name_list->append("PHS_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phsstp); + rec_name_list->append("PHS_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phslst); + rec_name_list->append("EXRI"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&exri); + rec_name_list->append("IDFC"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&idfc); + rec_name_list->append("XI1"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&_first_xi); + rec_name_list->append("NXI"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&xi_block_size); + rec_name_list->append("VEC_JXI"); + rec_type_list->append("INT32_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_jxi); + rec_name_list->append("VEC_IER"); + rec_type_list->append("INT16_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_ier); + rec_name_list->append("VEC_VK"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_vk); + rec_name_list->append("VEC_XI"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_xi); + rec_name_list->append("NCONF"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&configurations); + rec_name_list->append("VEC_SPH_SIZES"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size * (configurations + 1)) + ")"); + rec_ptr_list->append(vec_sphere_sizes); + rec_name_list->append("VEC_SPH_REFRI"); + rec_type_list->append("FLOAT64_(" + to_string(2 * xi_block_size * (configurations+ 1)) + ")"); + rec_ptr_list->append(vec_sphere_ref_indices); + str_type = "FLOAT64_(" + to_string(xi_block_size) + ")"; + rec_name_list->append("VEC_SCS1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_scs1); + rec_name_list->append("VEC_SCS2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_scs2); + rec_name_list->append("VEC_ABS1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_abs1); + rec_name_list->append("VEC_ABS2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_abs2); + rec_name_list->append("VEC_EXS1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_exs1); + rec_name_list->append("VEC_EXS2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_exs2); + rec_name_list->append("VEC_ALBEDS1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_albeds1); + rec_name_list->append("VEC_ALBEDS2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_albeds2); + rec_name_list->append("VEC_SCSRT1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_scsrt1); + rec_name_list->append("VEC_SCSRT2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_scsrt2); + rec_name_list->append("VEC_ABSRT1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_absrt1); + rec_name_list->append("VEC_ABSRT2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_absrt2); + rec_name_list->append("VEC_EXSRT1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_exsrt1); + rec_name_list->append("VEC_EXSRT2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_exsrt2); + rec_name_list->append("VEC_QSCHU1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_qschu1); + rec_name_list->append("VEC_QSCHU2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_qschu2); + rec_name_list->append("VEC_PSCHU1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_pschu1); + rec_name_list->append("VEC_PSCHU2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_pschu2); + rec_name_list->append("VEC_S0MAG1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_s0mag1); + rec_name_list->append("VEC_S0MAG2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_s0mag2); + rec_name_list->append("VEC_COSAV1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_cosav1); + rec_name_list->append("VEC_COSAV2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_cosav2); + rec_name_list->append("VEC_RAPRS1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_raprs1); + rec_name_list->append("VEC_RAPRS2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_raprs2); + rec_name_list->append("VEC_FK1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_fk1); + rec_name_list->append("VEC_FK2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_fk2); + str_type = "FLOAT64_(" + to_string(2 * xi_block_size) + ")"; + rec_name_list->append("VEC_FSAS11"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_fsas11); + rec_name_list->append("VEC_FSAS21"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_fsas21); + rec_name_list->append("VEC_FSAS12"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_fsas12); + rec_name_list->append("VEC_FSAS22"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_fsas22); + str_type = "FLOAT64_(" + to_string(ndirs) + ")"; + rec_name_list->append("VEC_DIR_SCAND"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_scand); + rec_name_list->append("VEC_DIR_CFMP"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_cfmp); + rec_name_list->append("VEC_DIR_CFSP"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_cfsp); + rec_name_list->append("VEC_DIR_SFMP"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sfmp); + rec_name_list->append("VEC_DIR_SFSP"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sfsp); + str_type = "FLOAT64_(" + to_string(3 * ndirs) + ")"; + rec_name_list->append("VEC_DIR_UN"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_un); + rec_name_list->append("VEC_DIR_UNS"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_uns); + str_type = "FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"; + rec_name_list->append("VEC_DIR_SCS1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_scs1); + rec_name_list->append("VEC_DIR_SCS2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_scs2); + rec_name_list->append("VEC_DIR_ABS1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_abs1); + rec_name_list->append("VEC_DIR_ABS2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_abs2); + rec_name_list->append("VEC_DIR_EXS1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_exs1); + rec_name_list->append("VEC_DIR_EXS2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_exs2); + rec_name_list->append("VEC_DIR_ALBEDS1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_albeds1); + rec_name_list->append("VEC_DIR_ALBEDS2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_albeds2); + rec_name_list->append("VEC_DIR_SCSRT1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_scsrt1); + rec_name_list->append("VEC_DIR_SCSRT2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_scsrt2); + rec_name_list->append("VEC_DIR_ABSRT1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_absrt1); + rec_name_list->append("VEC_DIR_ABSRT2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_absrt2); + rec_name_list->append("VEC_DIR_EXSRT1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_exsrt1); + rec_name_list->append("VEC_DIR_EXSRT2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_exsrt2); + str_type = "FLOAT64_(" + to_string(2 * ndirs * xi_block_size) + ")"; + rec_name_list->append("VEC_DIR_FSAS11"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fsas11); + rec_name_list->append("VEC_DIR_FSAS21"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fsas21); + rec_name_list->append("VEC_DIR_FSAS12"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fsas12); + rec_name_list->append("VEC_DIR_FSAS22"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fsas22); + rec_name_list->append("VEC_DIR_SAS11"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sas11); + rec_name_list->append("VEC_DIR_SAS21"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sas21); + rec_name_list->append("VEC_DIR_SAS12"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sas12); + rec_name_list->append("VEC_DIR_SAS22"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sas22); + str_type = "FLOAT64_(" + to_string(ndirs * xi_block_size) + ")"; + rec_name_list->append("VEC_DIR_QSCHU1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_qschu1); + rec_name_list->append("VEC_DIR_QSCHU2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_qschu2); + rec_name_list->append("VEC_DIR_PSCHU1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_pschu1); + rec_name_list->append("VEC_DIR_PSCHU2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_pschu2); + rec_name_list->append("VEC_DIR_S0MAG1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_s0mag1); + rec_name_list->append("VEC_DIR_S0MAG2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_s0mag2); + rec_name_list->append("VEC_DIR_COSAV1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_cosav1); + rec_name_list->append("VEC_DIR_COSAV2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_cosav2); + rec_name_list->append("VEC_DIR_RAPR1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_rapr1); + rec_name_list->append("VEC_DIR_RAPR2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_rapr2); + rec_name_list->append("VEC_DIR_FL1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fl1); + rec_name_list->append("VEC_DIR_FL2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fl2); + rec_name_list->append("VEC_DIR_FR1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fr1); + rec_name_list->append("VEC_DIR_FR2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fr2); + rec_name_list->append("VEC_DIR_FK1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fk1); + rec_name_list->append("VEC_DIR_FK2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fk2); + rec_name_list->append("VEC_DIR_FX1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fx1); + rec_name_list->append("VEC_DIR_FX2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fx2); + rec_name_list->append("VEC_DIR_FY1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fy1); + rec_name_list->append("VEC_DIR_FY2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fy2); + rec_name_list->append("VEC_DIR_FZ1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fz1); + rec_name_list->append("VEC_DIR_FZ2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fz2); + rec_name_list->append("VEC_DIR_TQEL1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqel1); + rec_name_list->append("VEC_DIR_TQEL2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqel2); + rec_name_list->append("VEC_DIR_TQER1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqer1); + rec_name_list->append("VEC_DIR_TQER2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqer2); + rec_name_list->append("VEC_DIR_TQEK1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqek1); + rec_name_list->append("VEC_DIR_TQEK2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqek2); + rec_name_list->append("VEC_DIR_TQEX1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqex1); + rec_name_list->append("VEC_DIR_TQEX2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqex2); + rec_name_list->append("VEC_DIR_TQEY1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqey1); + rec_name_list->append("VEC_DIR_TQEY2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqey2); + rec_name_list->append("VEC_DIR_TQEZ1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqez1); + rec_name_list->append("VEC_DIR_TQEZ2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqez2); + rec_name_list->append("VEC_DIR_TQSL1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsl1); + rec_name_list->append("VEC_DIR_TQSL2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsl2); + rec_name_list->append("VEC_DIR_TQSR1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsr1); + rec_name_list->append("VEC_DIR_TQSR2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsr2); + rec_name_list->append("VEC_DIR_TQSK1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsk1); + rec_name_list->append("VEC_DIR_TQSK2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsk2); + rec_name_list->append("VEC_DIR_TQSX1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsx1); + rec_name_list->append("VEC_DIR_TQSX2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsx2); + rec_name_list->append("VEC_DIR_TQSY1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsy1); + rec_name_list->append("VEC_DIR_TQSY2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsy2); + rec_name_list->append("VEC_DIR_TQSZ1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsz1); + rec_name_list->append("VEC_DIR_TQSZ2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_tqsz2); + str_type = "FLOAT64_(" + to_string(16 * ndirs * xi_block_size) + ")"; + rec_name_list->append("VEC_DIR_MULL"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_mull); + rec_name_list->append("VEC_DIR_MULLLR"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_mulllr); + + // Convert the lists to arrays and write them to HDF5 + string *rec_names = rec_name_list->to_array(); + string *rec_types = rec_type_list->to_array(); + void **rec_pointers = rec_ptr_list->to_array(); + const int rec_num = rec_name_list->length(); + FileSchema *schema = new FileSchema(rec_num, rec_types, rec_names); + HDFFile *hdf_file = HDFFile::from_schema(*schema, file_name, H5F_ACC_TRUNC); + for (int ri = 0; ri < rec_num; ri++) + hdf_file->write(rec_names[ri], rec_types[ri], rec_pointers[ri]); + hdf_file->close(); + + // Clean memory + delete rec_name_list; + delete rec_type_list; + delete rec_ptr_list; + delete[] rec_names; + delete[] rec_types; + delete[] rec_pointers; + delete schema; + delete hdf_file; + return 0; +} + +int InclusionOutputInfo::write_legacy(const std::string &output) { + const dcomplex cc0 = 0.0 + I * 0.0; + int result = 0; + FILE *p_outfile = fopen(output.c_str(), "w"); + if (p_outfile != NULL) { + if (vec_jxi[0] == 1) { + fprintf(p_outfile, " READ(IR,*)NSPH,LI,LE,MXNDM,INPOL,NPNT,NPNTTS,IAVM,ISAM\n"); +#ifdef USE_ILP64 + fprintf( + p_outfile, " %5d%5d%5d%5ld%5d%5d%5d%5d%5d\n", + nsph, li, le, mxndm, inpol, npnt, npntts, + iavm, iavm + ); +#else + fprintf( + p_outfile, " %5d%5d%5d%5d%5d%5d%5d%5d%5d\n", + nsph, li, le, mxndm, inpol, npnt, npntts, + iavm, iavm + ); +#endif // USE_ILP64 + fprintf(p_outfile, " READ(IR,*)RXX(I),RYY(I),RZZ(I)\n"); + for (int ri = 0; ri < nsph; ri++) { + fprintf( + p_outfile, "%17.8lE%17.8lE%17.8lE\n", + vec_x_coords[ri], vec_y_coords[ri], vec_z_coords[ri] + ); + } + fprintf(p_outfile, " READ(IR,*)TH,THSTP,THLST,THS,THSSTP,THSLST\n"); + fprintf( + p_outfile, " %10.3lE%10.3lE%10.3lE%10.3lE%10.3lE%10.3lE\n", + th, thstp, thlst, ths, thsstp, thslst + ); + fprintf(p_outfile, " READ(IR,*)PH,PHSTP,PHLST,PHS,PHSSTP,PHSLST\n"); + fprintf( + p_outfile, " %10.3lE%10.3lE%10.3lE%10.3lE%10.3lE%10.3lE\n", + ph, phstp, phlst, phs, phsstp, phslst + ); + fprintf(p_outfile, " READ(IR,*)JWTM\n"); + fprintf(p_outfile, " %5d\n", jwtm); + fprintf(p_outfile, " READ(ITIN)NSPHT\n"); + fprintf(p_outfile, " READ(ITIN)(IOG(I),I=1,NSPH)\n"); + fprintf(p_outfile, " READ(ITIN)EXDC,WP,XIP,IDFC,NXI\n"); + fprintf(p_outfile, " READ(ITIN)(XIV(I),I=1,NXI)\n"); + fprintf(p_outfile, " READ(ITIN)NSHL(I),ROS(I)\n"); + fprintf(p_outfile, " READ(ITIN)(RCF(I,NS),NS=1,NSH)\n \n"); + fprintf(p_outfile, " REFR. INDEX OF EXTERNAL MEDIUM=%15.7lE\n", exri); + if (idfc < 0) { + fprintf( p_outfile, " VK=%15.7lE, XI IS SCALE FACTOR FOR LENGTHS\n \n", vec_vk[0]); + } + // End preamble writing + } + // Wavelength loop + for (int jxi = 0; jxi < xi_block_size; jxi++) { + int done_dirs = 0; + double alamb = 2.0 * 3.141592653589793238 / vec_vk[jxi]; + fprintf(p_outfile, "========== JXI =%3d ====================\n", vec_jxi[jxi]); + if (idfc >= 0) { + fprintf(p_outfile, " VK=%15.7lE, XI=%15.7lE\n", vec_vk[jxi], vec_xi[jxi]); + } else { + fprintf(p_outfile, " XI=%15.7lE\n", vec_xi[jxi]); + } + if (vec_ier[jxi] == 1) { + fprintf(p_outfile, " STOP IN INDME\n"); + break; + } else if (vec_ier[jxi] == 2) { + fprintf(p_outfile, " STOP IN OSPV\n"); + break; + } + for (int i168 = 1; i168 <= configurations; i168++) { + int cindex = jxi * (configurations + 1) + i168 - 1; + if (vec_sphere_ref_indices[cindex] == cc0) { + fprintf(p_outfile, " SPHERE N.%2d: SIZE=%15.7lE\n", i168, vec_sphere_sizes[cindex]); + } else { + fprintf( + p_outfile, " SPHERE N.%2d: SIZE=%15.7lE, REFRACTIVE INDEX=%15.7lE%15.7lE\n", + i168, vec_sphere_sizes[cindex], real(vec_sphere_ref_indices[cindex]), + imag(vec_sphere_ref_indices[cindex]) + ); + } + } // i168 configuration loop + int cindex = jxi * (configurations + 1) + configurations; + fprintf( + p_outfile, " EXT. SPHERE: SIZE=%15.7lE, REFRACTIVE INDEX=%15.7lE%15.7lE\n", + vec_sphere_sizes[cindex], real(vec_sphere_ref_indices[cindex]), + imag(vec_sphere_ref_indices[cindex]) + ); + fprintf(p_outfile, " ENSEMBLE AVERAGE, MODE%2d\n", iavm); + if (inpol == 0) fprintf(p_outfile, " LIN -1\n"); + else fprintf(p_outfile, " CIRC -1\n"); + fprintf(p_outfile, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE%15.7lE\n", + vec_scs1[jxi], vec_abs1[jxi], vec_exs1[jxi], vec_albeds1[jxi] + ); + fprintf(p_outfile, "INSERTION: SCASECM %5d%15.7E%15.7E%15.7E%15.7E\n", + -1, alamb, vec_scs1[jxi], vec_abs1[jxi], vec_exs1[jxi] + ); + fprintf(p_outfile, " ---- SCS/GS -- ABC/GS -- EXS/GS ---\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_scsrt1[jxi], vec_absrt1[jxi], vec_exsrt1[jxi] + ); + fprintf( + p_outfile, " FSAS(1,1)=%15.7lE%15.7lE FSAS(2,1)=%15.7lE%15.7lE\n", + real(vec_fsas11[jxi]), imag(vec_fsas11[jxi]), + real(vec_fsas21[jxi]), imag(vec_fsas21[jxi]) + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_qschu1[jxi], vec_pschu1[jxi], vec_s0mag1[jxi] + ); + fprintf( + p_outfile, " COSAV=%15.7lE, RAPRS=%15.7lE\n", + vec_cosav1[jxi], vec_raprs1[jxi] + ); + fprintf(p_outfile, " Fk=%15.7lE\n", vec_fk1[jxi]); + if (inpol == 0) fprintf(p_outfile, " LIN 1\n"); + else fprintf(p_outfile, " CIRC 1\n"); + fprintf(p_outfile, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE%15.7lE\n", + vec_scs2[jxi], vec_abs2[jxi], vec_exs2[jxi], vec_albeds2[jxi] + ); + fprintf(p_outfile, "INSERTION: SCASECM %5d%15.7E%15.7E%15.7E%15.7E\n", + 1, alamb, vec_scs2[jxi], vec_abs2[jxi], vec_exs2[jxi] + ); + fprintf(p_outfile, " ---- SCS/GS -- ABC/GS -- EXS/GS ---\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_scsrt2[jxi], vec_absrt2[jxi], vec_exsrt2[jxi] + ); + fprintf( + p_outfile, " FSAS(2,2)=%15.7lE%15.7lE FSAS(1,2)=%15.7lE%15.7lE\n", + real(vec_fsas22[jxi]), imag(vec_fsas22[jxi]), + real(vec_fsas12[jxi]), imag(vec_fsas12[jxi]) + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_qschu2[jxi], vec_pschu2[jxi], vec_s0mag2[jxi] + ); + fprintf( + p_outfile, " COSAV=%15.7lE, RAPRS=%15.7lE\n", + vec_cosav2[jxi], vec_raprs2[jxi] + ); + fprintf(p_outfile, " Fk=%15.7lE\n", vec_fk2[jxi]); + fprintf( + p_outfile, " (RE(FSAS(1,1))-RE(FSAS(2,2)))/RE(FSAS(1,1))=%15.7lE\n", + (real(vec_fsas11[jxi]) - real(vec_fsas22[jxi])) / real(vec_fsas11[jxi]) + ); + fprintf( + p_outfile, " (IM(FSAS(1,1))-IM(FSAS(2,2)))/IM(FSAS(1,1))=%15.7lE\n", + (imag(vec_fsas11[jxi]) - imag(vec_fsas22[jxi])) / imag(vec_fsas11[jxi]) + ); + for (int jth = 0; jth < _num_theta; jth++) { + for (int jph = 0; jph < _num_phi; jph++) { + for (int jths = 0; jths < _num_thetas; jths++) { + for (int jphs = 0; jphs < _num_phis; jphs++) { + bool goto290 = isam >= 0 && (jths > 0 || jphs > 0); + int dir_index = ndirs * jxi + done_dirs; + fprintf( + p_outfile, "********** JTH =%3d, JPH =%3d, JTHS =%3d, JPHS =%3d ********************\n", + jth + 1, jph + 1, jths + 1, jphs +1 + ); + fprintf( + p_outfile, " TIDG=%10.3lE, PIDG=%10.3lE, TSDG=%10.3lE, PSDG=%10.3lE\n", + th + jth * thstp, ph + jph * phstp, ths + jths * thsstp, phs + jphs * phsstp + ); + fprintf(p_outfile, " SCAND=%10.3lE\n", vec_dir_scand[done_dirs]); + fprintf( + p_outfile, " CFMP=%15.7lE, SFMP=%15.7lE\n", + vec_dir_cfmp[done_dirs], vec_dir_sfmp[done_dirs] + ); + fprintf( + p_outfile, " CFSP=%15.7lE, SFSP=%15.7lE\n", + vec_dir_cfsp[done_dirs], vec_dir_sfsp[done_dirs] + ); + if (isam >= 0) { + fprintf( + p_outfile, " UNI=(%12.5lE,%12.5lE,%12.5lE)\n", + vec_dir_un[done_dirs], + vec_dir_un[done_dirs + 1], + vec_dir_un[done_dirs + 2] + ); + fprintf( + p_outfile, " UNS=(%12.5lE,%12.5lE,%12.5lE)\n", + vec_dir_uns[done_dirs], + vec_dir_uns[done_dirs + 1], + vec_dir_uns[done_dirs + 2] + ); + } else { // label 214 + fprintf( + p_outfile, " UN=(%12.5lE,%12.5lE,%12.5lE)\n\n", + vec_dir_un[done_dirs], + vec_dir_un[done_dirs + 1], + vec_dir_un[done_dirs + 2] + ); + } + fprintf(p_outfile, " SINGLE SCATTERER\n"); + if (inpol == 0) { + fprintf(p_outfile, " LIN -1\n"); + } else { + fprintf(p_outfile, " CIRC -1\n"); + } + // label 275 + fprintf(p_outfile, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_scs1[dir_index], + vec_dir_abs1[dir_index], + vec_dir_exs1[dir_index], + vec_dir_albeds1[dir_index] + ); + fprintf( + p_outfile, "INSERTION: SCASEC %5d%14.7lE%14.7lE%14.7lE%14.7lE\n", + -1, alamb, vec_dir_scs1[dir_index], vec_dir_abs1[dir_index], + vec_dir_exs1[dir_index] + ); + fprintf(p_outfile, " ---- SCS/GS -- ABS/GS -- EXS/GS ---\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_dir_scsrt1[dir_index], + vec_dir_absrt1[dir_index], + vec_dir_exsrt1[dir_index] + ); + fprintf( + p_outfile, " FSAS(1,1)=%15.7lE%15.7lE FSAS(2,1)=%15.7lE%15.7lE\n", + real(vec_dir_fsas11[dir_index]), imag(vec_dir_fsas11[dir_index]), + real(vec_dir_fsas21[dir_index]), imag(vec_dir_fsas21[dir_index]) + ); + fprintf( + p_outfile, " SAS(1,1)=%15.7lE%15.7lE SAS(2,1)=%15.7lE%15.7lE\n", + real(vec_dir_sas11[dir_index]), imag(vec_dir_sas11[dir_index]), + real(vec_dir_sas21[dir_index]), imag(vec_dir_sas21[dir_index]) + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_dir_qschu1[dir_index], + vec_dir_pschu1[dir_index], + vec_dir_s0mag1[dir_index] + ); + if (!goto290) { + fprintf( + p_outfile, " COSAV=%15.7lE, RAPRS=%15.7lE\n", + vec_dir_cosav1[dir_index], vec_dir_rapr1[dir_index] + ); + fprintf( + p_outfile, " Fl=%15.7lE, Fr=%15.7lE, Fk=%15.7lE\n", + vec_dir_fl1[dir_index], vec_dir_fr1[dir_index], + vec_dir_fk1[dir_index] + ); + fprintf( + p_outfile, " Fx=%15.7lE, Fy=%15.7lE, Fz=%15.7lE\n", + vec_dir_fx1[dir_index], vec_dir_fy1[dir_index], + vec_dir_fz1[dir_index] + ); + fprintf( + p_outfile, " TQEl=%15.7lE, TQEr=%15.7lE, TQEk=%15.7lE\n", + vec_dir_tqel1[dir_index], vec_dir_tqer1[dir_index], + vec_dir_tqek1[dir_index] + ); + fprintf( + p_outfile, " TQSl=%15.7lE, TQSr=%15.7lE, TQSk=%15.7lE\n", + vec_dir_tqsl1[dir_index], vec_dir_tqsr1[dir_index], + vec_dir_tqsk1[dir_index] + ); + fprintf( + p_outfile, " TQEx=%15.7lE, TQEy=%15.7lE, TQEz=%15.7lE\n", + vec_dir_tqex1[dir_index], vec_dir_tqey1[dir_index], + vec_dir_tqez1[dir_index] + ); + fprintf( + p_outfile, " TQSx=%15.7lE, TQSy=%15.7lE, TQSz=%15.7lE\n", + vec_dir_tqsx1[dir_index], vec_dir_tqsy1[dir_index], + vec_dir_tqsz1[dir_index] + ); + } // goto290 switch + if (inpol == 0) { + fprintf(p_outfile, " LIN 1\n"); + } else { + fprintf(p_outfile, " CIRC 1\n"); + } + // label 275 + fprintf(p_outfile, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_scs2[dir_index], + vec_dir_abs2[dir_index], + vec_dir_exs2[dir_index], + vec_dir_albeds2[dir_index] + ); + fprintf( + p_outfile, "INSERTION: SCASEC %5d%14.7lE%14.7lE%14.7lE%14.7lE\n", + 1, alamb, vec_dir_scs2[dir_index], vec_dir_abs2[dir_index], + vec_dir_exs2[dir_index] + ); + fprintf(p_outfile, " ---- SCS/GS -- ABS/GS -- EXS/GS ---\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_dir_scsrt2[dir_index], + vec_dir_absrt2[dir_index], + vec_dir_exsrt2[dir_index] + ); + fprintf( + p_outfile, " FSAS(2,2)=%15.7lE%15.7lE FSAS(1,2)=%15.7lE%15.7lE\n", + real(vec_dir_fsas22[dir_index]), imag(vec_dir_fsas22[dir_index]), + real(vec_dir_fsas12[dir_index]), imag(vec_dir_fsas12[dir_index]) + ); + fprintf( + p_outfile, " SAS(2,2)=%15.7lE%15.7lE SAS(1,2)=%15.7lE%15.7lE\n", + real(vec_dir_sas22[dir_index]), imag(vec_dir_sas22[dir_index]), + real(vec_dir_sas12[dir_index]), imag(vec_dir_sas12[dir_index]) + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_dir_qschu2[dir_index], + vec_dir_pschu2[dir_index], + vec_dir_s0mag2[dir_index] + ); + if (!goto290) { + fprintf( + p_outfile, " COSAV=%15.7lE, RAPRS=%15.7lE\n", + vec_dir_cosav2[dir_index], vec_dir_rapr2[dir_index] + ); + fprintf( + p_outfile, " Fl=%15.7lE, Fr=%15.7lE, Fk=%15.7lE\n", + vec_dir_fl2[dir_index], vec_dir_fr2[dir_index], + vec_dir_fk2[dir_index] + ); + fprintf( + p_outfile, " Fx=%15.7lE, Fy=%15.7lE, Fz=%15.7lE\n", + vec_dir_fx2[dir_index], vec_dir_fy2[dir_index], + vec_dir_fz2[dir_index] + ); + fprintf( + p_outfile, " TQEl=%15.7lE, TQEr=%15.7lE, TQEk=%15.7lE\n", + vec_dir_tqel2[dir_index], vec_dir_tqer2[dir_index], + vec_dir_tqek2[dir_index] + ); + fprintf( + p_outfile, " TQSl=%15.7lE, TQSr=%15.7lE, TQSk=%15.7lE\n", + vec_dir_tqsl2[dir_index], vec_dir_tqsr2[dir_index], + vec_dir_tqsk2[dir_index] + ); + fprintf( + p_outfile, " TQEx=%15.7lE, TQEy=%15.7lE, TQEz=%15.7lE\n", + vec_dir_tqex2[dir_index], vec_dir_tqey2[dir_index], + vec_dir_tqez2[dir_index] + ); + fprintf( + p_outfile, " TQSx=%15.7lE, TQSy=%15.7lE, TQSz=%15.7lE\n", + vec_dir_tqsx2[dir_index], vec_dir_tqsy2[dir_index], + vec_dir_tqsz2[dir_index] + ); + } // goto290 switch + fprintf( + p_outfile, " (RE(FSAS(1,1))-RE(FSAS(2,2)))/RE(FSAS(1,1))=%15.7lE\n", + (real(vec_dir_fsas11[dir_index]) - real(vec_dir_fsas22[dir_index])) / real(vec_dir_fsas11[dir_index]) + ); + fprintf( + p_outfile, " (IM(FSAS(1,1))-IM(FSAS(2,2)))/IM(FSAS(1,1))=%15.7lE\n", + (imag(vec_dir_fsas11[dir_index]) - imag(vec_dir_fsas22[dir_index])) / imag(vec_dir_fsas11[dir_index]) + ); + fprintf(p_outfile, " MULL\n"); + for (int i = 0; i < 4; i++) { + int mull_index = 16 * dir_index + 4 * i; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_mull[mull_index], + vec_dir_mull[mull_index + 1], + vec_dir_mull[mull_index + 2], + vec_dir_mull[mull_index + 3] + ); + } // i MULL loop + fprintf(p_outfile, " MULLLR\n"); + for (int i = 0; i < 4; i++) { + int mull_index = 16 * dir_index + 4 * i; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_mulllr[mull_index], + vec_dir_mulllr[mull_index + 1], + vec_dir_mulllr[mull_index + 2], + vec_dir_mulllr[mull_index + 3] + ); + } // i MULLR loop + if (iavm != 0) { + fprintf(p_outfile, " ENSEMBLE AVERAGE, MODE%2d\n", iavm); + if (inpol == 0) fprintf(p_outfile, " LIN\n"); + else fprintf(p_outfile, " CIRC\n"); + // label 318 + fprintf(p_outfile, " MULL\n"); + for (int i = 0; i < 4; i++) { + int mul_dir_index = 16 * dir_index + 4 * i; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_mull[mul_dir_index], + vec_dir_mull[mul_dir_index + 1], + vec_dir_mull[mul_dir_index + 2], + vec_dir_mull[mul_dir_index + 3] + ); + } // i MULL loop + fprintf(p_outfile, " MULLLR\n"); + for (int i = 0; i < 4; i++) { + int mul_dir_index = 16 * dir_index + 4 * i; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_mulllr[mul_dir_index], + vec_dir_mulllr[mul_dir_index + 1], + vec_dir_mulllr[mul_dir_index + 2], + vec_dir_mulllr[mul_dir_index + 3] + ); + } // i MULLR loop + } // iavm != 0 block + done_dirs++; + } // jphs loop + } // jths loop + } // jph loop + } // jth loop + } // jxi wavelength loop + fclose(p_outfile); + } else { + result = -1; + } + return result; +} + +#ifdef MPI_VERSION +int InclusionOutputInfo::mpireceive(const mixMPI* mpidata, int pid) { + int result = 0; + int chk_nsph, chk_inpol, chk_iavm, chk_isam, chk_num_theta, chk_num_thetas; + int chk_num_phi, chk_num_phis, chk_ndirs, chk_idfc, chk_configs; + double chk_exri; + MPI_Recv(&chk_nsph, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_inpol, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_iavm, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_isam, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_theta, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_thetas, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_phi, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_phis, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_ndirs, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_exri, 1, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_idfc, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_configs, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + result += (chk_nsph == nsph) ? 0 : 1; + result += (chk_inpol == inpol) ? 0 : 1; + result += (chk_iavm == iavm) ? 0 : 1; + result += (chk_isam == isam) ? 0 : 1; + result += (chk_num_theta == _num_theta) ? 0 : 1; + result += (chk_num_thetas == _num_thetas) ? 0 : 1; + result += (chk_num_phi == _num_phi) ? 0 : 1; + result += (chk_num_phis == _num_phis) ? 0 : 1; + result += (chk_ndirs == ndirs) ? 0 : 1; + result += (chk_exri == exri) ? 0 : 1; + result += (chk_idfc == idfc) ? 0 : 1; + result += (chk_configs == configurations) ? 0 : 1; + if (result == 0) { + int xi1, offset, chunk_size; + MPI_Send(&result, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD); + MPI_Recv(&xi1, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + // Receive vectors of single values per scale + MPI_Recv(&chunk_size, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + offset = xi1 - _first_xi; + MPI_Recv(vec_jxi + offset, chunk_size, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_ier + offset, chunk_size, MPI_SHORT, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_vk + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_xi + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_scs1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_scs2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_abs1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_abs2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_exs1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_exs2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_albeds1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_albeds2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_scsrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_scsrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_absrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_absrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_exsrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_exsrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qschu1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qschu2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_pschu1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_pschu2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_s0mag1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_s0mag2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_cosav1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_cosav2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_raprs1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_raprs2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fk1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fk2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fsas11 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fsas21 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fsas22 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fsas12 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + // Receive vectors whose sizes depend on configurations + MPI_Recv(&chunk_size, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + offset = (xi1 - _first_xi) * (configurations + 1); + MPI_Recv(vec_sphere_sizes + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sphere_ref_indices + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + // Receive vectors whose sizes depend on directions and wavelengths + MPI_Recv(&chunk_size, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + offset = (xi1 - _first_xi) * ndirs; + MPI_Recv(vec_dir_scs1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_scs2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_abs1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_abs2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_exs1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_exs2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_albeds1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_albeds2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_scsrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_scsrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_absrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_absrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_exsrt1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_exsrt2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fsas11 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fsas21 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fsas12 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fsas22 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sas11 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sas21 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sas12 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sas22 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_qschu1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_qschu2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_pschu1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_pschu2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_s0mag1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_s0mag2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_cosav1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_cosav2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_rapr1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_rapr2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + MPI_Recv(vec_dir_fl1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fl2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fr1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fr2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fk1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fk2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fx1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fx2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fy1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fy2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fz1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fz2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqel1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqel2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqer1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqer2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqek1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqek2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqex1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqex2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqey1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqey2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqez1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqez2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsl1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsl2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsr1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsr2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsk1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsk2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsx1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsx2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsy1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsy2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsz1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_tqsz2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_mull + 16 * offset, 16 * chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_mulllr + 16 * offset, 16 * chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + } else { + MPI_Send(&result, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD); + } + return result; +} + +int InclusionOutputInfo::mpisend(const mixMPI *mpidata) { + int result = 0; + int chunk_size; + // Send output metadata for configuration cross-check + MPI_Send(&nsph, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&inpol, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&iavm, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&isam, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_theta, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_thetas, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_phi, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_phis, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&ndirs, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&exri, 1, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(&idfc, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&configurations, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + // Wait for process 0 to cross-check the configuration + MPI_Recv(&result, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + if (result == 0) { + // Process 0 confirmed the consistency of configuration. Send the data. + // Send vectors of single values per scale + MPI_Send(&_first_xi, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&xi_block_size, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_jxi, xi_block_size, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_ier, xi_block_size, MPI_SHORT, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_vk, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_xi, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_scs1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_scs2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_abs1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_abs2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_exs1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_exs2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_albeds1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_albeds2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_scsrt1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_scsrt2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_absrt1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_absrt2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_exsrt1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_exsrt2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qschu1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qschu2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_pschu1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_pschu2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_s0mag1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_s0mag2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_cosav1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_cosav2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_raprs1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_raprs2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fk1, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fk2, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fsas11, xi_block_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fsas21, xi_block_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fsas22, xi_block_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fsas12, xi_block_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + + // Send vectors whose sizes depend on configurations + chunk_size = xi_block_size * (configurations + 1); + MPI_Send(&chunk_size, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_sizes, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_ref_indices, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + + // Send vectors whose sizes depend on directions and wavelengths + chunk_size = xi_block_size * ndirs; + MPI_Send(&chunk_size, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_scs1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_scs2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_abs1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_abs2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_exs1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_exs2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_albeds1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_albeds2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_scsrt1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_scsrt2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_absrt1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_absrt2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_exsrt1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_exsrt2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fsas11, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fsas21, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fsas12, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fsas22, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas11, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas21, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas12, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas22, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_qschu1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_qschu2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_pschu1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_pschu2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_s0mag1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_s0mag2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_cosav1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_cosav2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_rapr1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_rapr2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fl1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fl2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fr1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fr2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fk1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fk2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fx1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fx2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fy1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fy2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fz1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fz2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqel1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqel2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqer1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqer2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqek1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqek2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqex1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqex2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqey1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqey2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqez1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqez2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsl1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsl2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsr1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsr2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsk1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsk2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsx1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsx2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsy1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsy2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsz1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_tqsz2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_mull, 16 * chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_mulllr, 16 * chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + } + return result; +} +#endif // MPI_VERSION +// >>> END OF InclusionOutputInfo CLASS IMPLEMENTATION <<< + +// >>> SphereOutputInfo CLASS IMPLEMENTATION <<< +SphereOutputInfo::SphereOutputInfo( + ScattererConfiguration *sc, GeometryConfiguration *gc, + const mixMPI *mpidata, int first_xi, int xi_length +) { + _first_xi = first_xi; + nsph = gc->number_of_spheres; + lm = gc->l_max; + inpol = gc->in_pol; + npnt = gc->npnt; + npntts = gc->npntts; + isam = gc->isam; + idfc = sc->idfc; + th = gc->in_theta_start; + thstp = gc->in_theta_step; + thlst = gc->in_theta_end; + _num_theta = (thstp == 0.0) ? 1 : 1 + (int)((thlst - th) / thstp); + ths = gc->sc_theta_start; + thsstp = gc->sc_theta_step; + thslst = gc->sc_theta_end; + _num_thetas = (thsstp == 0.0) ? 1 : 1 + (int)((thslst - ths) / thsstp); + ph = gc->in_phi_start; + phstp = gc->in_phi_step; + phlst = gc->in_phi_end; + _num_phi = (phstp == 0.0) ? 1 : 1 + (int)((phlst - ph) / phstp); + phs = gc->sc_phi_start; + phsstp = gc->sc_phi_step; + phslst = gc->sc_phi_end; + _num_phis = (phsstp == 0.0) ? 1 : 1 + (int)((phslst - phs) / phsstp); + ndirs = _num_theta * _num_thetas * _num_phi * _num_phis; + configurations = sc->configurations; + double exdc = sc->exdc; + exri = sqrt(exdc); + nxi = sc->number_of_scales; + xi_block_size = (xi_length == 0) ? nxi : xi_length; + jwtm = gc->jwtm; + lcalc = 0; + arg = 0.0 + I * 0.0; + vec_jxi = new int[xi_block_size](); + vec_ier = new short[xi_block_size](); + vec_vk = new double[xi_block_size](); + vec_xi = new double[xi_block_size](); + vec_sphere_sizes = new double[configurations * xi_block_size](); + vec_sphere_ref_indices = new dcomplex[configurations * xi_block_size](); + vec_scs = new double[configurations * xi_block_size](); + vec_abs = new double[configurations * xi_block_size](); + vec_exs = new double[configurations * xi_block_size](); + vec_albeds = new double[configurations * xi_block_size](); + vec_scsrt = new double[configurations * xi_block_size](); + vec_absrt = new double[configurations * xi_block_size](); + vec_exsrt = new double[configurations * xi_block_size](); + vec_fsas = new dcomplex[configurations * xi_block_size](); + vec_qschu = new double[configurations * xi_block_size](); + vec_pschu = new double[configurations * xi_block_size](); + vec_s0mag = new double[configurations * xi_block_size](); + vec_cosav = new double[configurations * xi_block_size](); + vec_raprs = new double[configurations * xi_block_size](); + vec_tqek1 = new double[configurations * xi_block_size](); + vec_tqek2 = new double[configurations * xi_block_size](); + vec_tqsk1 = new double[configurations * xi_block_size](); + vec_tqsk2 = new double[configurations * xi_block_size](); + if (nsph == 1) { + vec_fsat = NULL; + vec_qschut = NULL; + vec_pschut = NULL; + vec_s0magt = NULL; + } else { + vec_fsat = new dcomplex[xi_block_size](); + vec_qschut = new double[xi_block_size](); + vec_pschut = new double[xi_block_size](); + vec_s0magt = new double[xi_block_size](); + } + // Initialize directions (they are scale-independent) + vec_dir_tidg = new double[_num_theta]; + vec_dir_pidg = new double[_num_phi]; + vec_dir_tsdg = new double[_num_thetas]; + vec_dir_psdg = new double[_num_phis]; + double cti = th, cpi = ph, cts = ths, cps = phs; + for (int di = 0; di < _num_theta; di++) { + vec_dir_tidg[di] = cti; + cti += thstp; + } + for (int di = 0; di < _num_thetas; di++) { + vec_dir_tsdg[di] = cts; + cts += thsstp; + } + for (int di = 0; di < _num_phi; di++) { + vec_dir_pidg[di] = cpi; + cpi += phstp; + } + for (int di = 0; di < _num_phis; di++) { + vec_dir_psdg[di] = cps; + cps += phsstp; + } + vec_dir_scand = new double[ndirs](); + vec_dir_cfmp = new double[ndirs](); + vec_dir_cfsp = new double[ndirs](); + vec_dir_sfmp = new double[ndirs](); + vec_dir_sfsp = new double[ndirs](); + vec_dir_un = new double[3 * ndirs](); + vec_dir_uns = new double[3 * ndirs](); + vec_dir_sas11 = new dcomplex[nsph * ndirs * xi_block_size](); + vec_dir_sas21 = new dcomplex[nsph * ndirs * xi_block_size](); + vec_dir_sas12 = new dcomplex[nsph * ndirs * xi_block_size](); + vec_dir_sas22 = new dcomplex[nsph * ndirs * xi_block_size](); + vec_dir_fx = new double[nsph * _num_theta * _num_phi * xi_block_size](); + vec_dir_fy = new double[nsph * _num_theta * _num_phi * xi_block_size](); + vec_dir_fz = new double[nsph * _num_theta * _num_phi * xi_block_size](); + vec_dir_muls = new double[16 * nsph * ndirs * xi_block_size](); + vec_dir_mulslr = new double[16 * nsph * ndirs * xi_block_size](); +} + +SphereOutputInfo::SphereOutputInfo(const std::string &hdf5_name) { + unsigned int flags = H5F_ACC_RDONLY; + HDFFile *hdf_file = new HDFFile(hdf5_name, flags); + herr_t status = hdf_file->get_status(); + string str_name, str_type; + if (status == 0) { + status = hdf_file->read("NSPH", "INT32_(1)", &nsph); + status = hdf_file->read("LM", "INT32_(1)", &lm); + status = hdf_file->read("INPOL", "INT32_(1)", &inpol); + status = hdf_file->read("NPNT", "INT32_(1)", &npnt); + status = hdf_file->read("NPNTTS", "INT32_(1)", &npntts); + status = hdf_file->read("ISAM", "INT32_(1)", &isam); + status = hdf_file->read("JWTM", "INT32_(1)", &jwtm); + status = hdf_file->read("TH_START", "FLOAT64_(1)", &th); + status = hdf_file->read("TH_STEP", "FLOAT64_(1)", &thstp); + status = hdf_file->read("TH_END", "FLOAT64_(1)", &thlst); + _num_theta = (thstp == 0.0) ? 1 : 1 + int((thlst - th) / thstp); + status = hdf_file->read("THS_START", "FLOAT64_(1)", &ths); + status = hdf_file->read("THS_STEP", "FLOAT64_(1)", &thsstp); + status = hdf_file->read("THS_END", "FLOAT64_(1)", &thslst); + _num_thetas = (thsstp == 0.0) ? 1 : 1 + int((thslst - ths) / thsstp); + status = hdf_file->read("PH_START", "FLOAT64_(1)", &ph); + status = hdf_file->read("PH_STEP", "FLOAT64_(1)", &phstp); + status = hdf_file->read("PH_END", "FLOAT64_(1)", &phlst); + _num_phi = (phstp == 0.0) ? 1 : 1 + int((phlst - ph) / phstp); + status = hdf_file->read("PHS_START", "FLOAT64_(1)", &phs); + status = hdf_file->read("PHS_STEP", "FLOAT64_(1)", &phsstp); + status = hdf_file->read("PHS_END", "FLOAT64_(1)", &phslst); + _num_phis = (phsstp == 0.0) ? 1 : 1 + int((phslst - phs) / phsstp); + ndirs = _num_theta * _num_thetas * _num_phi * _num_phis; + status = hdf_file->read("EXRI", "FLOAT64_(1)", &exri); + status = hdf_file->read("NUM_CONF", "INT32_(1)", &configurations); + status = hdf_file->read("IDFC", "INT32_(1)", &idfc); + status = hdf_file->read("XI1", "INT32_(1)", &_first_xi); + status = hdf_file->read("NXI", "INT32_(1)", &xi_block_size); + nxi = (_first_xi == 1) ? xi_block_size : xi_block_size + _first_xi; + lcalc = 0; + arg = 0.0 + I * 0.0; + str_type = "INT32_(" + to_string(xi_block_size) + ")"; + vec_jxi = new int[xi_block_size]; + status = hdf_file->read("VEC_JXI", str_type, vec_jxi); + str_type = "INT16_(" + to_string(xi_block_size) + ")"; + vec_ier = new short[xi_block_size]; + status = hdf_file->read("VEC_IER", str_type, vec_ier); + str_type = "FLOAT64_(" + to_string(xi_block_size) + ")"; + vec_vk = new double[xi_block_size]; + status = hdf_file->read("VEC_VK", str_type, vec_vk); + vec_xi = new double[xi_block_size]; + status = hdf_file->read("VEC_XI", str_type, vec_xi); + str_type = "FLOAT64_(" + to_string(configurations * xi_block_size) + ")"; + vec_sphere_sizes = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_SPH_SIZES", str_type, vec_sphere_sizes); + str_type = "FLOAT64_(" + to_string(2 * configurations * xi_block_size) + ")"; + vec_sphere_ref_indices = new dcomplex[configurations * xi_block_size]; + status = hdf_file->read("VEC_SPH_REFRI", str_type, vec_sphere_ref_indices); + str_type = "FLOAT64_(" + to_string(configurations * xi_block_size) + ")"; + vec_scs = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_SCS", str_type, vec_scs); + vec_abs = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_ABS", str_type, vec_abs); + vec_exs = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_EXS", str_type, vec_exs); + vec_albeds = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_ALBEDS", str_type, vec_albeds); + vec_scsrt = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_SCSRT", str_type, vec_scsrt); + vec_absrt = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_ABSRT", str_type, vec_absrt); + vec_exsrt = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_EXSRT", str_type, vec_exsrt); + str_type = "FLOAT64_(" + to_string(2 * configurations * xi_block_size) + ")"; + vec_fsas = new dcomplex[configurations * xi_block_size]; + status = hdf_file->read("VEC_FSAS", str_type, vec_fsas); + str_type = "FLOAT64_(" + to_string(configurations * xi_block_size) + ")"; + vec_qschu = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_QSCHU", str_type, vec_qschu); + vec_pschu = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_PSCHU", str_type, vec_pschu); + vec_s0mag = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_S0MAG", str_type, vec_s0mag); + vec_cosav = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_COSAV", str_type, vec_cosav); + vec_raprs = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_RAPRS", str_type, vec_raprs); + vec_tqek1 = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_TQEK1", str_type, vec_tqek1); + vec_tqek2 = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_TQEK2", str_type, vec_tqek2); + vec_tqsk1 = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_TQSK1", str_type, vec_tqsk1); + vec_tqsk2 = new double[configurations * xi_block_size]; + status = hdf_file->read("VEC_TQSK2", str_type, vec_tqsk2); + if (nsph != 1) { + str_type = "FLOAT64_(" + to_string(2 * xi_block_size) + ")"; + vec_fsat = new dcomplex[xi_block_size]; + status = hdf_file->read("VEC_FSAT", str_type, vec_fsat); + str_type = "FLOAT64_(" + to_string(xi_block_size) + ")"; + vec_qschut = new double[xi_block_size]; + status = hdf_file->read("VEC_QSCHUT", str_type, vec_qschut); + vec_pschut = new double[xi_block_size]; + status = hdf_file->read("VEC_PSCHUT", str_type, vec_pschut); + vec_s0magt = new double[xi_block_size]; + status = hdf_file->read("VEC_S0MAGT", str_type, vec_s0magt); + } else { + vec_fsat = NULL; + vec_qschut = NULL; + vec_pschut = NULL; + vec_s0magt = NULL; + } + // Initialize directions (they are scale-independent) + vec_dir_tidg = new double[_num_theta]; + vec_dir_tsdg = new double[_num_thetas]; + vec_dir_pidg = new double[_num_phi]; + vec_dir_psdg = new double[_num_phis]; + double cti = th, cpi = ph, cts = ths, cps = phs; + for (int di = 0; di < _num_theta; di++) { + vec_dir_tidg[di] = cti; + cti += thstp; + } + for (int di = 0; di < _num_thetas; di++) { + vec_dir_tsdg[di] = cts; + cts += thsstp; + } + for (int di = 0; di < _num_phi; di++) { + vec_dir_pidg[di] = cpi; + cpi += phstp; + } + for (int di = 0; di < _num_phis; di++) { + vec_dir_psdg[di] = cps; + cps += phsstp; + } + str_type = "FLOAT64_(" + to_string(ndirs) + ")"; + vec_dir_scand = new double[ndirs]; + status = hdf_file->read("VEC_DIR_SCAND", str_type, vec_dir_scand); + vec_dir_cfmp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_CFMP", str_type, vec_dir_cfmp); + vec_dir_sfmp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_SFMP", str_type, vec_dir_sfmp); + vec_dir_cfsp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_CFSP", str_type, vec_dir_cfsp); + vec_dir_sfsp = new double[ndirs]; + status = hdf_file->read("VEC_DIR_SFSP", str_type, vec_dir_sfsp); + str_type = "FLOAT64_(" + to_string(3 * ndirs) + ")"; + vec_dir_un = new double[3 * ndirs]; + status = hdf_file->read("VEC_DIR_UN", str_type, vec_dir_un); + vec_dir_uns = new double[3 * ndirs]; + status = hdf_file->read("VEC_DIR_UNS", str_type, vec_dir_uns); + str_type = "FLOAT64_(" + to_string(2 * nsph * ndirs * xi_block_size) + ")"; + vec_dir_sas11 = new dcomplex[nsph * ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS11", str_type, vec_dir_sas11); + vec_dir_sas21 = new dcomplex[nsph * ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS21", str_type, vec_dir_sas21); + vec_dir_sas12 = new dcomplex[nsph * ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS12", str_type, vec_dir_sas12); + vec_dir_sas22 = new dcomplex[nsph * ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_SAS22", str_type, vec_dir_sas22); + str_type = "FLOAT64_(" + to_string(nsph * _num_theta * _num_phi * xi_block_size) + ")"; + vec_dir_fx = new double[nsph * _num_theta * _num_phi * xi_block_size]; + status = hdf_file->read("VEC_DIR_FX", str_type, vec_dir_fx); + vec_dir_fy = new double[nsph * _num_theta * _num_phi * xi_block_size]; + status = hdf_file->read("VEC_DIR_FY", str_type, vec_dir_fy); + vec_dir_fz = new double[nsph * _num_theta * _num_phi * xi_block_size]; + status = hdf_file->read("VEC_DIR_FZ", str_type, vec_dir_fz); + str_type = "FLOAT64_(" + to_string(16 * nsph * ndirs * xi_block_size) + ")"; + vec_dir_muls = new double[16 * nsph * ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_MULS", str_type, vec_dir_muls); + vec_dir_mulslr = new double[16 * nsph * ndirs * xi_block_size]; + status = hdf_file->read("VEC_DIR_MULSLR", str_type, vec_dir_mulslr); + status = hdf_file->close(); + delete hdf_file; + } else { + if (hdf_file != NULL) delete hdf_file; + UnrecognizedFormatException ex("Error: " + hdf5_name + " not recognized as a valid HDF5 file!"); + throw ex; + } +} + +SphereOutputInfo::~SphereOutputInfo() { + delete[] vec_jxi; + delete[] vec_ier; + delete[] vec_vk; + delete[] vec_xi; + delete[] vec_sphere_sizes; + delete[] vec_sphere_ref_indices; + delete[] vec_scs; + delete[] vec_abs; + delete[] vec_exs; + delete[] vec_albeds; + delete[] vec_scsrt; + delete[] vec_absrt; + delete[] vec_exsrt; + delete[] vec_fsas; + delete[] vec_qschu; + delete[] vec_pschu; + delete[] vec_s0mag; + delete[] vec_cosav; + delete[] vec_raprs; + delete[] vec_tqek1; + delete[] vec_tqek2; + delete[] vec_tqsk1; + delete[] vec_tqsk2; + if (nsph != 1) { + delete[] vec_fsat; + delete[] vec_qschut; + delete[] vec_pschut; + delete[] vec_s0magt; + } + delete[] vec_dir_tidg; + delete[] vec_dir_pidg; + delete[] vec_dir_tsdg; + delete[] vec_dir_psdg; + delete[] vec_dir_scand; + delete[] vec_dir_cfmp; + delete[] vec_dir_cfsp; + delete[] vec_dir_sfmp; + delete[] vec_dir_sfsp; + delete[] vec_dir_un; + delete[] vec_dir_uns; + delete[] vec_dir_sas11; + delete[] vec_dir_sas21; + delete[] vec_dir_sas12; + delete[] vec_dir_sas22; + delete[] vec_dir_fx; + delete[] vec_dir_fy; + delete[] vec_dir_fz; + delete[] vec_dir_muls; + delete[] vec_dir_mulslr; +} + +long SphereOutputInfo::compute_size( + ScattererConfiguration *sc, GeometryConfiguration *gc, + int first_xi, int xi_length +) { + // Size of the configuration set + long result = 18 * sizeof(int); + result += 12 * sizeof(double); + result += 47 * sizeof(long); + result += sizeof(dcomplex); + // Get configuration parameters + int _nsph = gc->number_of_spheres; + double _th = gc->in_theta_start; + double _thstp = gc->in_theta_step; + double _thlst = gc->in_theta_end; + int num_theta = (_thstp == 0.0) ? 1 : 1 + (int)((_thlst - _th) / _thstp); + double _ths = gc->sc_theta_start; + double _thsstp = gc->sc_theta_step; + double _thslst = gc->sc_theta_end; + int num_thetas = (_thsstp == 0.0) ? 1 : 1 + (int)((_thslst - _ths) / _thsstp); + double _ph = gc->in_phi_start; + double _phstp = gc->in_phi_step; + double _phlst = gc->in_phi_end; + int num_phi = (_phstp == 0.0) ? 1 : 1 + (int)((_phlst - _ph) / _phstp); + double _phs = gc->sc_phi_start; + double _phsstp = gc->sc_phi_step; + double _phslst = gc->sc_phi_end; + int num_phis = (_phsstp == 0.0) ? 1 : 1 + (int)((_phslst - _phs) / _phsstp); + int _ndirs = num_theta * num_thetas * num_phi * num_phis; + int _nxi = sc->number_of_scales; + int _xi_block_size = (xi_length == 0) ? _nxi : xi_length; + int _nconf = sc->configurations; + // Size of the data set + result += _xi_block_size * (sizeof(short) + sizeof(int)); + result += 2 * _xi_block_size * sizeof(double); + result += 16 * _nconf * _xi_block_size * sizeof(double); + result += 2 * _nconf * _xi_block_size * sizeof(dcomplex); + result += (num_theta + num_thetas + num_phi + num_phis) * sizeof(double); + result += 11 * _ndirs * sizeof(double); + result += 4 * _nsph * _ndirs * _xi_block_size * sizeof(dcomplex); + result += 3 * _nsph * num_theta * num_phi * sizeof(double); + result += 32 * _nsph * _ndirs * _xi_block_size * sizeof(double); + if (_nsph != 1) { + result += _xi_block_size * sizeof(dcomplex); + result += 3 * _xi_block_size * sizeof(double); + } + return result; +} + +long SphereOutputInfo::compute_size() { + // Size of the configuration set + long result = 18 * sizeof(int); + result += 12 * sizeof(double); + result += 47 * sizeof(long); + result += sizeof(dcomplex); + // Size of the data set + result += xi_block_size * (sizeof(short) + sizeof(int)); + result += 2 * xi_block_size * sizeof(double); + result += 16 * configurations * xi_block_size * sizeof(double); + result += 2 * configurations * xi_block_size * sizeof(dcomplex); + result += (_num_theta + _num_thetas + _num_phi + _num_phis) * sizeof(double); + result += 11 * ndirs * sizeof(double); + result += 4 * nsph * ndirs * xi_block_size * sizeof(dcomplex); + result += 3 * nsph * _num_theta * _num_phi * sizeof(double); + result += 32 * nsph * ndirs * xi_block_size * sizeof(double); + if (nsph != 1) { + result += xi_block_size * sizeof(dcomplex); + result += 3 * xi_block_size * sizeof(double); + } + return result; +} + +int SphereOutputInfo::insert(const SphereOutputInfo &rhs) { + int result = 0; + result += (rhs.nsph == nsph) ? 0 : 1; + result += (rhs.inpol == inpol) ? 0 : 1; + result += (rhs.isam == isam) ? 0 : 1; + result += (rhs._num_theta == _num_theta) ? 0 : 1; + result += (rhs._num_thetas == _num_thetas) ? 0 : 1; + result += (rhs._num_phi == _num_phi) ? 0 : 1; + result += (rhs._num_phis == _num_phis) ? 0 : 1; + result += (rhs.ndirs == ndirs) ? 0 : 1; + result += (rhs.exri == exri) ? 0 : 1; + result += (rhs.idfc == idfc) ? 0 : 1; + result += (rhs.configurations == configurations) ? 0 : 1; + if (result == 0) { + int offset, chunk_size, xi1; + xi1 = rhs._first_xi; + // Insert vectors whose sizes depend on wavelengths + offset = xi1 - _first_xi; + chunk_size = rhs.xi_block_size; + memcpy(vec_jxi + offset, rhs.vec_jxi, chunk_size * sizeof(int)); + memcpy(vec_ier + offset, rhs.vec_ier, chunk_size * sizeof(short)); + memcpy(vec_vk + offset, rhs.vec_vk, chunk_size * sizeof(double)); + memcpy(vec_xi + offset, rhs.vec_xi, chunk_size * sizeof(double)); + if (nsph != 1) { + memcpy(vec_fsat + offset, rhs.vec_fsat, chunk_size * sizeof(dcomplex)); + memcpy(vec_qschut + offset, rhs.vec_qschut, chunk_size * sizeof(double)); + memcpy(vec_pschut + offset, rhs.vec_pschut, chunk_size * sizeof(double)); + memcpy(vec_s0magt + offset, rhs.vec_s0magt, chunk_size * sizeof(double)); + } + + // Insert vectors whose sizes depend on configurations and wavelengths + offset = (xi1 - _first_xi) * configurations; + chunk_size = rhs.xi_block_size * configurations; + memcpy(vec_sphere_sizes + offset, rhs.vec_sphere_sizes, chunk_size * sizeof(double)); + memcpy(vec_sphere_ref_indices + offset, rhs.vec_sphere_ref_indices, chunk_size * sizeof(dcomplex)); + memcpy(vec_scs + offset, rhs.vec_scs, chunk_size * sizeof(double)); + memcpy(vec_abs + offset, rhs.vec_abs, chunk_size * sizeof(double)); + memcpy(vec_exs + offset, rhs.vec_exs, chunk_size * sizeof(double)); + memcpy(vec_albeds + offset, rhs.vec_albeds, chunk_size * sizeof(double)); + memcpy(vec_scsrt + offset, rhs.vec_scsrt, chunk_size * sizeof(double)); + memcpy(vec_absrt + offset, rhs.vec_absrt, chunk_size * sizeof(double)); + memcpy(vec_exsrt + offset, rhs.vec_exsrt, chunk_size * sizeof(double)); + memcpy(vec_fsas + offset, rhs.vec_fsas, chunk_size * sizeof(dcomplex)); + memcpy(vec_qschu + offset, rhs.vec_qschu, chunk_size * sizeof(double)); + memcpy(vec_pschu + offset, rhs.vec_pschu, chunk_size * sizeof(double)); + memcpy(vec_s0mag + offset, rhs.vec_s0mag, chunk_size * sizeof(double)); + memcpy(vec_cosav + offset, rhs.vec_cosav, chunk_size * sizeof(double)); + memcpy(vec_raprs + offset, rhs.vec_raprs, chunk_size * sizeof(double)); + memcpy(vec_tqek1 + offset, rhs.vec_tqek1, chunk_size * sizeof(double)); + memcpy(vec_tqek2 + offset, rhs.vec_tqek2, chunk_size * sizeof(double)); + memcpy(vec_tqsk1 + offset, rhs.vec_tqsk1, chunk_size * sizeof(double)); + memcpy(vec_tqsk2 + offset, rhs.vec_tqsk2, chunk_size * sizeof(double)); + + // Insert vectors whose sizes depend on NSPH, directions and wavelengths + offset = (xi1 - _first_xi) * nsph * ndirs; + chunk_size = rhs.xi_block_size * nsph * ndirs; + memcpy(vec_dir_sas11 + offset, rhs.vec_dir_sas11, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sas21 + offset, rhs.vec_dir_sas21, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sas12 + offset, rhs.vec_dir_sas12, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_sas22 + offset, rhs.vec_dir_sas22, chunk_size * sizeof(dcomplex)); + memcpy(vec_dir_muls + 16 * offset, rhs.vec_dir_muls, 16 * chunk_size * sizeof(double)); + memcpy(vec_dir_mulslr + 16 * offset, rhs.vec_dir_mulslr, 16 * chunk_size * sizeof(double)); + + // Insert vectors whose sizes depend on NSPH, incidence directions and wavelengths + offset = (xi1 - _first_xi) * nsph * _num_theta * _num_phi; + chunk_size = rhs.xi_block_size * nsph * _num_theta * _num_phi; + memcpy(vec_dir_fx + offset, rhs.vec_dir_fx, chunk_size * sizeof(double)); + memcpy(vec_dir_fy + offset, rhs.vec_dir_fy, chunk_size * sizeof(double)); + memcpy(vec_dir_fz + offset, rhs.vec_dir_fz, chunk_size * sizeof(double)); + // TODO: fix the vector sizes in HDF5 writer and MPI communicators + } + return result; +} + +int SphereOutputInfo::write(const std::string &output, const std::string &format) { + int result = 0; + if (format.compare("LEGACY") == 0) { + result = write_legacy(output); + } else if (format.compare("HDF5") == 0) { + result = write_hdf5(output); + } else { + string message = "Unknown format mode: \"" + format + "\""; + throw UnrecognizedConfigurationException(message); + } + return result; +} + +int SphereOutputInfo::write_hdf5(const std::string &file_name) { + List<string> *rec_name_list = new List<string>(1); + List<string> *rec_type_list = new List<string>(1); + List<void *> *rec_ptr_list = new List<void *>(1); + string str_type, str_name; + rec_name_list->set(0, "NSPH"); + rec_type_list->set(0, "INT32_(1)"); + rec_ptr_list->set(0, &nsph); + rec_name_list->append("LM"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&lm); + rec_name_list->append("INPOL"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&inpol); + rec_name_list->append("NPNT"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&npnt); + rec_name_list->append("NPNTTS"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&npntts); + rec_name_list->append("ISAM"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&isam); + rec_name_list->append("JWTM"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&jwtm); + rec_name_list->append("TH_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&th); + rec_name_list->append("TH_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thstp); + rec_name_list->append("TH_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thlst); + rec_name_list->append("THS_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&ths); + rec_name_list->append("THS_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thsstp); + rec_name_list->append("THS_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&thslst); + rec_name_list->append("PH_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&ph); + rec_name_list->append("PH_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phstp); + rec_name_list->append("PH_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phlst); + rec_name_list->append("PHS_START"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phs); + rec_name_list->append("PHS_STEP"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phsstp); + rec_name_list->append("PHS_END"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&phslst); + rec_name_list->append("EXRI"); + rec_type_list->append("FLOAT64_(1)"); + rec_ptr_list->append(&exri); + rec_name_list->append("IDFC"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&idfc); + rec_name_list->append("NUM_CONF"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&configurations); + rec_name_list->append("XI1"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&_first_xi); + rec_name_list->append("NXI"); + rec_type_list->append("INT32_(1)"); + rec_ptr_list->append(&xi_block_size); + rec_name_list->append("VEC_JXI"); + rec_type_list->append("INT32_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_jxi); + rec_name_list->append("VEC_IER"); + rec_type_list->append("INT16_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_ier); + rec_name_list->append("VEC_VK"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_vk); + rec_name_list->append("VEC_XI"); + rec_type_list->append("FLOAT64_(" + to_string(xi_block_size) + ")"); + rec_ptr_list->append(vec_xi); + rec_name_list->append("VEC_SPH_SIZES"); + rec_type_list->append("FLOAT64_(" + to_string(configurations * xi_block_size) + ")"); + rec_ptr_list->append(vec_sphere_sizes); + rec_name_list->append("VEC_SPH_REFRI"); + rec_type_list->append("FLOAT64_(" + to_string(2 * configurations * xi_block_size) + ")"); + rec_ptr_list->append(vec_sphere_ref_indices); + str_type = "FLOAT64_(" + to_string(configurations * xi_block_size) + ")"; + rec_name_list->append("VEC_SCS"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_scs); + rec_name_list->append("VEC_ABS"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_abs); + rec_name_list->append("VEC_EXS"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_exs); + rec_name_list->append("VEC_ALBEDS"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_albeds); + rec_name_list->append("VEC_SCSRT"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_scsrt); + rec_name_list->append("VEC_ABSRT"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_absrt); + rec_name_list->append("VEC_EXSRT"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_exsrt); + str_type = "FLOAT64_(" + to_string(2 * configurations * xi_block_size) + ")"; + rec_name_list->append("VEC_FSAS"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_fsas); + str_type = "FLOAT64_(" + to_string(configurations * xi_block_size) + ")"; + rec_name_list->append("VEC_QSCHU"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_qschu); + rec_name_list->append("VEC_PSCHU"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_pschu); + rec_name_list->append("VEC_S0MAG"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_s0mag); + rec_name_list->append("VEC_COSAV"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_cosav); + rec_name_list->append("VEC_RAPRS"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_raprs); + rec_name_list->append("VEC_TQEK1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_tqek1); + rec_name_list->append("VEC_TQEK2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_tqek2); + rec_name_list->append("VEC_TQSK1"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_tqsk1); + rec_name_list->append("VEC_TQSK2"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_tqsk2); + if (nsph != 1) { + str_type = "FLOAT64_(" + to_string(2 * xi_block_size) + ")"; + rec_name_list->append("VEC_FSAT"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_fsat); + str_type = "FLOAT64_(" + to_string(xi_block_size) + ")"; + rec_name_list->append("VEC_QSCHUT"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_qschut); + rec_name_list->append("VEC_PSCHUT"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_pschut); + rec_name_list->append("VEC_S0MAGT"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_s0magt); + } + str_type = "FLOAT64_(" + to_string(ndirs) + ")"; + rec_name_list->append("VEC_DIR_SCAND"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_scand); + rec_name_list->append("VEC_DIR_CFMP"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_cfmp); + rec_name_list->append("VEC_DIR_CFSP"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_cfsp); + rec_name_list->append("VEC_DIR_SFMP"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sfmp); + rec_name_list->append("VEC_DIR_SFSP"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sfsp); + str_type = "FLOAT64_(" + to_string(3 * ndirs) + ")"; + rec_name_list->append("VEC_DIR_UN"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_un); + rec_name_list->append("VEC_DIR_UNS"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_uns); + str_type = "FLOAT64_(" + to_string(2 * nsph * ndirs * xi_block_size) + ")"; + rec_name_list->append("VEC_DIR_SAS11"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sas11); + rec_name_list->append("VEC_DIR_SAS21"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sas21); + rec_name_list->append("VEC_DIR_SAS12"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sas12); + rec_name_list->append("VEC_DIR_SAS22"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_sas22); + str_type = "FLOAT64_(" + to_string(nsph * _num_theta * _num_phi * xi_block_size) + ")"; + rec_name_list->append("VEC_DIR_FX"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fx); + rec_name_list->append("VEC_DIR_FY"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fy); + rec_name_list->append("VEC_DIR_FZ"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_fz); + str_type = "FLOAT64_(" + to_string(16 * nsph * ndirs * xi_block_size) + ")"; + rec_name_list->append("VEC_DIR_MULS"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_muls); + rec_name_list->append("VEC_DIR_MULSLR"); + rec_type_list->append(str_type); + rec_ptr_list->append(vec_dir_mulslr); + + // Convert the lists to arrays and write them to HDF5 + string *rec_names = rec_name_list->to_array(); + string *rec_types = rec_type_list->to_array(); + void **rec_pointers = rec_ptr_list->to_array(); + const int rec_num = rec_name_list->length(); + FileSchema *schema = new FileSchema(rec_num, rec_types, rec_names); + HDFFile *hdf_file = HDFFile::from_schema(*schema, file_name, H5F_ACC_TRUNC); + for (int ri = 0; ri < rec_num; ri++) + hdf_file->write(rec_names[ri], rec_types[ri], rec_pointers[ri]); + hdf_file->close(); + + // Clean memory + delete rec_name_list; + delete rec_type_list; + delete rec_ptr_list; + delete[] rec_names; + delete[] rec_types; + delete[] rec_pointers; + delete schema; + delete hdf_file; + return 0; +} + +int SphereOutputInfo::write_legacy(const std::string &file_name) { + const dcomplex cc0 = 0.0 + I * 0.0; + int result = 0; + int nks = _num_thetas * _num_phis; + FILE *p_outfile = fopen(file_name.c_str(), "w"); + if (p_outfile != NULL) { + if (vec_jxi[0] == 1) { + fprintf(p_outfile, " READ(IR,*)NSPH,LM,INPOL,NPNT,NPNTTS,ISAM\n"); + fprintf( + p_outfile, " %5d%5d%5d%5d%5d%5d\n", + nsph, lm, inpol, npnt, npntts, isam + ); + fprintf(p_outfile, " READ(IR,*)TH,THSTP,THLST,THS,THSSTP,THSLST\n"); + fprintf( + p_outfile, " %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE\n", + th, thstp, thlst, ths, thsstp, thslst + ); + fprintf(p_outfile, " READ(IR,*)PH,PHSTP,PHLST,PHS,PHSSTP,PHSLST\n"); + fprintf( + p_outfile, " %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE\n", + ph, phstp, phlst, phs, phsstp, phslst + ); + fprintf(p_outfile, " READ(IR,*)JWTM\n"); + fprintf(p_outfile, " %5d\n", jwtm); + fprintf(p_outfile, " READ(ITIN)NSPHT\n"); + fprintf(p_outfile, " READ(ITIN)(IOG(I),I=1,NSPH)\n"); + fprintf(p_outfile, " READ(ITIN)EXDC,WP,XIP,IDFC,NXI\n"); + fprintf(p_outfile, " READ(ITIN)(XIV(I),I=1,NXI)\n"); + fprintf(p_outfile, " READ(ITIN)NSHL(I),ROS(I)\n"); + fprintf(p_outfile, " READ(ITIN)(RCF(I,NS),NS=1,NSH)\n \n"); + fprintf(p_outfile, " REFR. INDEX OF EXTERNAL MEDIUM=%15.7lE\n", exri); + if (inpol == 0) fprintf(p_outfile, " LIN\n \n"); + else fprintf(p_outfile, " CIRC\n \n"); + if (idfc < 0) { + fprintf(p_outfile, " VK=%15.7lE, XI IS SCALE FACTOR FOR LENGTHS\n \n", vec_vk[0]); + } + } // End preamble writing + // Wavelength loop + for (int jxi = 0; jxi < xi_block_size; jxi++) { + int done_dirs = 0; + fprintf(p_outfile, "========== JXI =%3d ====================\n", jxi + 1); + if (idfc >= 0) { + fprintf(p_outfile, " VK=%15.7lE, XI=%15.7lE\n", vec_xi[jxi], vec_vk[jxi]); + } else { // IDFC < 0 + fprintf(p_outfile, " XI=%15.7lE\n", vec_xi[jxi]); + } + if (vec_ier[jxi] == 1) { + fprintf(p_outfile, " STOP IN DME\n"); + fprintf( + p_outfile, " AT %1d LCALC=%3d TOO SMALL WITH ARG=%15.7lE+i(%15.7lE)\n", + (int)vec_ier[jxi], lcalc, real(arg), imag(arg) + ); + } + for (int ci = 0; ci < configurations; ci++) { + int cindex = jxi * configurations + ci; + fprintf(p_outfile, " SPHERE %2d\n", ci + 1); + if (vec_sphere_ref_indices[cindex] == cc0) { + fprintf(p_outfile, " SIZE=%15.7lE\n", vec_sphere_sizes[cindex]); + } else { + fprintf( + p_outfile, " SIZE=%15.7lE, REFRACTIVE INDEX=%15.7lE%15.7lE\n", + vec_sphere_sizes[cindex], real(vec_sphere_ref_indices[cindex]), + imag(vec_sphere_ref_indices[cindex]) + ); + } + fprintf(p_outfile, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE%15.7lE\n", + vec_scs[cindex], vec_abs[cindex], vec_exs[cindex], vec_albeds[cindex] + ); + fprintf(p_outfile, " ---- SCS/GS -- ABS/GS -- EXS/GS ---\n"); + fprintf( + p_outfile, " %14.7lE%15.7lE%15.7lE\n", + vec_scsrt[cindex], vec_absrt[cindex], vec_exsrt[cindex] + ); + fprintf( + p_outfile, " FSAS=%15.7lE%15.7lE\n", + real(vec_fsas[cindex]), imag(vec_fsas[cindex]) + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_qschu[cindex], vec_pschu[cindex], vec_s0mag[cindex] + ); + fprintf( + p_outfile, " COSAV=%15.7lE, RAPRS=%15.7lE\n", + vec_cosav[cindex], vec_raprs[cindex] + ); + fprintf( + p_outfile, " IPO= 1, TQEk=%15.7lE, TQSk=%15.7lE\n", + vec_tqek1[cindex], vec_tqsk1[cindex] + ); + fprintf( + p_outfile, " IPO= 2, TQEk=%15.7lE, TQSk=%15.7lE\n", + vec_tqek2[cindex], vec_tqsk2[cindex] + ); + } // ci configuration loop + if (nsph != 1) { + fprintf( + p_outfile, " FSAT=(%15.7lE,%15.7lE)\n", + real(vec_fsat[jxi]), imag(vec_fsat[jxi]) + ); + fprintf( + p_outfile, " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", + vec_qschut[jxi], vec_pschut[jxi], vec_s0magt[jxi] + ); + } + for (int jth = 0; jth < _num_theta; jth++) { + for (int jph = 0; jph < _num_phi; jph++) { + for (int jths = 0; jths < _num_thetas; jths++) { + for (int jphs = 0; jphs < _num_phis; jphs++) { + int dir_index = ndirs * jxi + done_dirs; + bool goto190 = (nks == 1) && ((jxi > 0) || (jth > 0) || (jph > 0)); + fprintf( + p_outfile, "********** JTH =%3d, JPH =%3d, JTHS =%3d, JPHS =%3d ********************\n", + jth + 1, jph + 1, jths + 1, jphs + 1 + ); + fprintf( + p_outfile, " TIDG=%10.3lE, PIDG=%10.3lE, TSDG=%10.3lE, PSDG=%10.3lE\n", + th + jth * thstp, + ph + jph * phstp, + ths + jths * thsstp, + phs + jphs * phsstp + ); + fprintf(p_outfile, " SCAND=%10.3lE\n", vec_dir_scand[done_dirs]); + fprintf( + p_outfile, " CFMP=%15.7lE, SFMP=%15.7lE\n", + vec_dir_cfmp[done_dirs], vec_dir_sfmp[done_dirs] + ); + fprintf( + p_outfile, " CFSP=%15.7lE, SFSP=%15.7lE\n", + vec_dir_cfsp[done_dirs], vec_dir_sfsp[done_dirs] + ); + if (isam >= 0) { + fprintf( + p_outfile, " UNI=(%12.5lE,%12.5lE,%12.5lE)\n", + vec_dir_un[3 * done_dirs], + vec_dir_un[3 * done_dirs + 1], + vec_dir_un[3 * done_dirs + 2] + ); + fprintf( + p_outfile, " UNS=(%12.5lE,%12.5lE,%12.5lE)\n", + vec_dir_uns[3 * done_dirs], + vec_dir_uns[3 * done_dirs + 1], + vec_dir_uns[3 * done_dirs + 2] + ); + } else { + fprintf( + p_outfile, " UN=(%12.5lE,%12.5lE,%12.5lE)\n", + vec_dir_un[3 * done_dirs], + vec_dir_un[3 * done_dirs + 1], + vec_dir_un[3 * done_dirs + 2] + ); + } + for (int i = 0; i < nsph; i++) { + int cindex = jxi * nsph * ndirs + nsph * done_dirs + i; + fprintf(p_outfile, " SPHERE %2d\n", i + 1); + fprintf( + p_outfile, " SAS(1,1)=%15.7lE%15.7lE, SAS(2,1)=%15.7lE%15.7lE\n", + real(vec_dir_sas11[cindex]), + imag(vec_dir_sas11[cindex]), + real(vec_dir_sas21[cindex]), + imag(vec_dir_sas21[cindex]) + ); + fprintf( + p_outfile, " SAS(1,2)=%15.7lE%15.7lE, SAS(2,2)=%15.7lE%15.7lE\n", + real(vec_dir_sas12[cindex]), + imag(vec_dir_sas12[cindex]), + real(vec_dir_sas22[cindex]), + imag(vec_dir_sas22[cindex]) + ); + if (jths == 0 && jphs == 0) { + fprintf( + p_outfile, " Fx=%15.7lE, Fy=%15.7lE, Fz=%15.7lE\n", + vec_dir_fx[jxi * nsph * _num_theta * _num_phi + jth * nsph * _num_phi + jph * nsph + i], + vec_dir_fy[jxi * nsph * _num_theta * _num_phi + jth * nsph * _num_phi + jph * nsph + i], + vec_dir_fz[jxi * nsph * _num_theta * _num_phi + jth * nsph * _num_phi + jph * nsph + i] + ); + } + fprintf(p_outfile, " MULS\n"); + for (int j = 0; j < 4; j++) { + int muls_index = 16 * cindex + 4 * j; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_muls[muls_index], + vec_dir_muls[muls_index + 1], + vec_dir_muls[muls_index + 2], + vec_dir_muls[muls_index + 3] + ); + } // j muls loop + fprintf(p_outfile, " MULSLR\n"); + for (int j = 0; j < 4; j++) { + int muls_index = 16 * cindex + 4 * j; + fprintf( + p_outfile, " %15.7lE%15.7lE%15.7lE%15.7lE\n", + vec_dir_mulslr[muls_index], + vec_dir_mulslr[muls_index + 1], + vec_dir_mulslr[muls_index + 2], + vec_dir_mulslr[muls_index + 3] + ); + } // j mulslr loop + } // i sphere loop + done_dirs++; + } // jphs loop + } // jths loop + } // jph loop + } // jth loop + } // jxi wavelength loop + fclose(p_outfile); + } else { + result = -1; + } + return result; +} + +#ifdef MPI_VERSION +int SphereOutputInfo::mpireceive(const mixMPI *mpidata, int pid) { + int result = 0; + int chk_nsph, chk_inpol, chk_isam, chk_num_theta, chk_num_thetas; + int chk_num_phi, chk_num_phis, chk_ndirs, chk_idfc, chk_configs; + double chk_exri; + MPI_Recv(&chk_nsph, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_inpol, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_isam, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_theta, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_thetas, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_phi, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_num_phis, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_ndirs, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_exri, 1, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_idfc, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&chk_configs, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + result += (chk_nsph == nsph) ? 0 : 1; + result += (chk_inpol == inpol) ? 0 : 1; + result += (chk_isam == isam) ? 0 : 1; + result += (chk_num_theta == _num_theta) ? 0 : 1; + result += (chk_num_thetas == _num_thetas) ? 0 : 1; + result += (chk_num_phi == _num_phi) ? 0 : 1; + result += (chk_num_phis == _num_phis) ? 0 : 1; + result += (chk_ndirs == ndirs) ? 0 : 1; + result += (chk_exri == exri) ? 0 : 1; + result += (chk_idfc == idfc) ? 0 : 1; + result += (chk_configs == configurations) ? 0 : 1; + if (result == 0) { + int xi1, offset, chunk_size; + MPI_Send(&result, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD); + MPI_Recv(&xi1, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + // Receive vectors of single values per scale + MPI_Recv(&chunk_size, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + offset = xi1 - _first_xi; + MPI_Recv(vec_jxi + offset, chunk_size, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_ier + offset, chunk_size, MPI_SHORT, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_vk + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_xi + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + if (nsph != 1) { + MPI_Recv(vec_fsat + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qschut + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_pschut + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_s0magt + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + } + + // Receive vectors whose sizes depend on configurations and wavelengths + MPI_Recv(&chunk_size, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + offset = (xi1 - _first_xi) * configurations; + MPI_Recv(vec_sphere_sizes + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_sphere_ref_indices + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_scs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_abs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_exs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_albeds + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_scsrt + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_absrt + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_exsrt + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_fsas + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_qschu + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_pschu + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_s0mag + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_cosav + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_raprs + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_tqek1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_tqek2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_tqsk1 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_tqsk2 + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + // Receive vectors whose sizes depend on NSPH, directions and wavelengths + MPI_Recv(&chunk_size, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + offset = (xi1 - _first_xi) * nsph * ndirs; + MPI_Recv(vec_dir_sas11 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sas21 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sas12 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_sas22 + offset, chunk_size, MPI_C_DOUBLE_COMPLEX, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_muls + 16 * offset, 16 * chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_mulslr + 16 * offset, 16 * chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + // Receive vectors whose sizes depend on NSPH, incidence directions and wavelengths + MPI_Recv(&chunk_size, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + offset = (xi1 - _first_xi) * nsph * _num_theta * _num_phi; + MPI_Recv(vec_dir_fx + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fy + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(vec_dir_fz + offset, chunk_size, MPI_DOUBLE, pid, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + } else { + MPI_Send(&result, 1, MPI_INT32_T, pid, 10, MPI_COMM_WORLD); + } + return result; +} + +int SphereOutputInfo::mpisend(const mixMPI *mpidata) { + int result = 0; + int chunk_size; + // Send output metadata for configuration cross-check + MPI_Send(&nsph, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&inpol, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&isam, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_theta, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_thetas, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_phi, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&_num_phis, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&ndirs, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&exri, 1, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(&idfc, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&configurations, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + // Wait for process 0 to cross-check the configuration + MPI_Recv(&result, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + if (result == 0) { + // Process 0 confirmed the consistency of configuration. Send the data. + // Send vectors of single values per scale + MPI_Send(&_first_xi, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(&xi_block_size, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_jxi, xi_block_size, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_ier, xi_block_size, MPI_SHORT, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_vk, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_xi, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + if (nsph != 1) { + MPI_Send(vec_fsat, xi_block_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qschut, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_pschut, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_s0magt, xi_block_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + } + + // Send vectors whose sizes depend on configurations and scales + chunk_size = xi_block_size * configurations; + MPI_Send(&chunk_size, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_sizes, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_sphere_ref_indices, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_scs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_abs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_exs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_albeds, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_scsrt, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_absrt, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_exsrt, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_fsas, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_qschu, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_pschu, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_s0mag, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_cosav, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_raprs, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_tqek1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_tqek2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_tqsk1, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_tqsk2, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + + // Send vectors whose sizes depend on NSPH, directions and wavelengths + chunk_size = xi_block_size * nsph * ndirs; + MPI_Send(&chunk_size, 1, MPI_INT32_T, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas11, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas21, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas12, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_sas22, chunk_size, MPI_C_DOUBLE_COMPLEX, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_muls, 16 * chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_mulslr, 16 * chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + + // Send vectors whose sizes depend on NSPH, incidence directions and wavelengths + chunk_size = xi_block_size * nsph * _num_theta * _num_phi; + MPI_Send(vec_dir_fx, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fy, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + MPI_Send(vec_dir_fz, chunk_size, MPI_DOUBLE, 0, 10, MPI_COMM_WORLD); + } + return result; +} +#endif // MPI_VERSION +// >>> END OF SphereOutputInfo CLASS IMPLEMENTATION <<< diff --git a/src/scripts/pycompare.py b/src/scripts/pycompare.py index fe68f7338bd6721829dcbe4a1856b015fbef43f3..d8c7072f233e908517c2222c21a983ee8b460f63 100755 --- a/src/scripts/pycompare.py +++ b/src/scripts/pycompare.py @@ -141,7 +141,7 @@ def compare_files(config): print("ERROR: C++ file is shorter than FORTRAN file.") fortran_file.close() c_file.close() - mismatch_count['errors'] = line_count + mismatch_count['errors'] = line_count if line_count > 0 else 1 return mismatch_count f_lines[0] = fortran_file.readline() c_lines[0] = c_file.readline() diff --git a/src/scripts/pydynrange.py b/src/scripts/pydynrange.py index b9c74ca8bb5faf7f8c5f7ce3a29495ee7fc63ca4..491f68f80e83ac7542ce3b9eb873e1fbe813f6a2 100755 --- a/src/scripts/pydynrange.py +++ b/src/scripts/pydynrange.py @@ -37,27 +37,44 @@ from sys import argv, stdout # # \returns exit_code: `int` 0 on successful completion. class PlotData: - # \brief PlotData instance constructor. + ## \brief PlotData instance constructor. def __init__(self): + ## \brief Maximum real part value. self.max_real = -1.0 + ## \brief Maximum imaginary part value. self.max_imag = -1.0 + ## \brief Maximum absolute value. self.max_absl = -1.0 + ## \brief Minimum (most negative) real part value. self.min_real = 1.0 + ## \brief Minimum (most negative) imaginary part value. self.min_imag = 1.0 + ## \brief Smallest absolute value. self.sml_absl = 1.0 + ## \brief Smallest absolute real part value. self.sml_real = 1.0 + ## \brief Smallest absolute imaginary part value. self.sml_imag = 1.0 + ## \brief Histogram of absolute values. self.absl_hist = [0 for i in range(-99, 100)] + ## \brief Histogram of real values. self.real_hist = [0 for i in range(-99, 100)] + ## \brief Histogram of imaginary values. self.imag_hist = [0 for i in range(-99, 100)] + ## \brief Maximum real order of magnitude. self.max_real_mag = -100 + ## \brief Minimum real order of magnitude. self.min_real_mag = 100 + ## \brief Maximum imaginary order of magnitude. self.max_imag_mag = -100 + ## \brief Minimum imaginary order of magnitude. self.min_imag_mag = 100 + ## \brief Maximum absolute order of magnitude. self.max_absl_mag = -100 + ## \brief Minimum absolute order of magnitude. self.min_absl_mag = 100 - # \brief Print a text log of the dynamic range. + ## \brief Print a text log of the dynamic range. def log_dynamic_range(self): print(" MAX( ABS[AM] ) = %14.7e"%self.max_absl) print(" MIN( ABS[AM] ) = %14.7e"%self.sml_absl) @@ -69,7 +86,9 @@ class PlotData: print("MIN( ABS( IMAG[AM] ) ) = %14.7e"%self.sml_imag) return - # \brief Make histograms of dynamic range with matplotlib. + ## \brief Make histograms of dynamic range with matplotlib. + # + # \param config: `dict` Dictionary of configuration options. def plot_dynamic_range(self, config): import matplotlib.pyplot as plt import numpy as np diff --git a/src/sphere/np_sphere.cpp b/src/sphere/np_sphere.cpp index 8c369947763b15011ff243f00e57d39209064d78..e83f1edeedefdc422b30f89540fd1d0b8642ee93 100644 --- a/src/sphere/np_sphere.cpp +++ b/src/sphere/np_sphere.cpp @@ -34,6 +34,12 @@ #include <cstdio> #include <string> +#ifdef USE_MPI +#ifndef MPI_VERSION +#include <mpi.h> +#endif +#endif + #ifndef INCLUDE_TYPES_H_ #include "../include/types.h" #endif @@ -42,9 +48,13 @@ #include "../include/Configuration.h" #endif +#ifndef INCLUDE_COMMONS_H_ +#include "../include/Commons.h" +#endif + using namespace std; -extern void sphere(const string& config_file, const string& data_file, const string& output_path); +extern void sphere(const string& config_file, const string& data_file, const string& output_path, const mixMPI *mpidata); /*! \brief Main program entry point. * @@ -59,6 +69,15 @@ extern void sphere(const string& config_file, const string& data_file, const str * \return result: `int` An exit code passed to the OS (0 for succesful execution). */ int main(int argc, char **argv) { + int ierr = 0; +#ifdef MPI_VERSION + ierr = MPI_Init(&argc, &argv); + // create and initialise class with essential MPI data + mixMPI *mpidata = new mixMPI(MPI_COMM_WORLD); +#else + // create a the class with dummy data if we are not using MPI at all + mixMPI *mpidata = new mixMPI(); +#endif string config_file = "../../test_data/sphere/DEDFB"; string data_file = "../../test_data/sphere/DSPH"; string output_path = "."; @@ -67,6 +86,10 @@ int main(int argc, char **argv) { data_file = string(argv[2]); output_path = string(argv[3]); } - sphere(config_file, data_file, output_path); - return 0; + sphere(config_file, data_file, output_path, mpidata); +#ifdef MPI_VERSION + MPI_Finalize(); +#endif + delete mpidata; + return ierr; } diff --git a/src/sphere/sphere.cpp b/src/sphere/sphere.cpp index 9f8c661698188683e17ea41db885f12f1fd658b3..033e111cad90872665c1ccb4fb7e191f000bdd37 100644 --- a/src/sphere/sphere.cpp +++ b/src/sphere/sphere.cpp @@ -21,8 +21,19 @@ #include <cstdio> #include <exception> #include <fstream> +#include <hdf5.h> #include <string> +#ifdef _OPENMP +#include <omp.h> +#endif + +#ifdef USE_MPI +#ifndef MPI_VERSION +#include <mpi.h> +#endif +#endif + #ifndef INCLUDE_TYPES_H_ #include "../include/types.h" #endif @@ -51,642 +62,1160 @@ #include "../include/TransitionMatrix.h" #endif +#ifndef INCLUDE_LIST_H_ +#include "../include/List.h" +#endif + +#ifndef INCLUDE_FILE_IO_H_ +#include "../include/file_io.h" +#endif + +#ifndef INCLUDE_OUTPUTS_H_ +#include "../include/outputs.h" +#endif + +#ifndef INCLUDE_ITERATION_DATA_H_ +#include "../include/IterationData.h" +#endif + using namespace std; +/*! \brief Main calculation loop. + * + * \param jxi488: `int` Wavelength loop index. + * \param sconf: `ScattererConfiguration *` Pointer to a `ScattererConfiguration` object. + * \param gconf: `GeometryConfiguration *` Pointer to a `GeometryConfiguration` object. + * \param sa: `ScatteringAngles *` Pointer to a `ScatteringAngles` object. + * \param sid: `SphereIterationData *` Pointer to a `SphereIterationData` object. + * \param oi: `SphereOutputInfo *` Pointer to a `SphereOutputInfo` object. + * \param output_path: `const string &` Path to the output directory. + * \param vtppoanp: `VirtualBinaryFile *` Pointer to a `VirtualBinaryFile` object. + */ +int sphere_jxi488_cycle( + int jxi488, ScattererConfiguration *sconf, GeometryConfiguration *gconf, + ScatteringAngles *sa, SphereIterationData *sid, SphereOutputInfo *oi, + const string& output_path, VirtualBinaryFile *vtppoanp +); + /*! \brief C++ implementation of SPH * * \param config_file: `string` Name of the configuration file. * \param data_file: `string` Name of the input data file. * \param output_path: `string` Directory to write the output files in. + * \param mpidata: `const mixMPI *` Pointer to a mixMPI data structure. */ -void sphere(const string& config_file, const string& data_file, const string& output_path) { +void sphere(const string& config_file, const string& data_file, const string& output_path, const mixMPI *mpidata) { Logger *logger = new Logger(LOG_INFO); - dcomplex arg, s0, tfsas; - double th, ph; - logger->log("INFO: making legacy configuration...\n"); - ScattererConfiguration *sconf = NULL; - try { - sconf = ScattererConfiguration::from_dedfb(config_file); - } catch(const OpenConfigurationFileException &ex) { - logger->err("\nERROR: failed to open scatterer configuration file.\n"); - string message = ex.what(); - logger->err("FILE: " + message + "\n"); - delete logger; - exit(1); - } - sconf->write_formatted(output_path + "/c_OEDFB"); - sconf->write_binary(output_path + "/c_TEDF"); - sconf->write_binary(output_path + "/c_TEDF.hd5", "HDF5"); - GeometryConfiguration *gconf = NULL; - try { - gconf = GeometryConfiguration::from_legacy(data_file); - } catch(const OpenConfigurationFileException &ex) { - logger->err("\nERROR: failed to open geometry configuration file.\n"); - string message = ex.what(); - logger->err("FILE: " + message + "\n"); - if (sconf != NULL) delete sconf; - delete logger; - exit(1); - } - int s_nsph = sconf->number_of_spheres; - int nsph = gconf->number_of_spheres; - if (s_nsph == nsph) { - int isq, ibf; - double *argi, *args, *gaps; - double cost, sint, cosp, sinp; - double costs, sints, cosps, sinps; - double scan; - double *duk = new double[3]; - double *u = new double[3]; - double *us = new double[3]; - double *un = new double[3]; - double *uns = new double[3]; - double *up = new double[3]; - double *ups = new double[3]; - double *upmp = new double[3]; - double *upsmp = new double[3]; - double *unmp = new double[3]; - double *unsmp = new double[3]; - double **cmul = new double*[4]; - double **cmullr = new double*[4]; - for (int i = 0; i < 4; i++) { - cmul[i] = new double[4]; - cmullr[i] = new double[4]; - } - dcomplex **tqspe, **tqsps; - double **tqse, **tqss; - tqse = new double*[2]; - tqss = new double*[2]; - tqspe = new dcomplex*[2]; - tqsps = new dcomplex*[2]; - for (int ti = 0; ti < 2; ti++) { - tqse[ti] = new double[2](); - tqss[ti] = new double[2](); - tqspe[ti] = new dcomplex[2](); - tqsps[ti] = new dcomplex[2](); + int device_count = 0; + + //=========================== + // the following only happens on MPI process 0 + //=========================== + if (mpidata->rank == 0) { + logger->log("INFO: making legacy configuration..."); + ScattererConfiguration *sconf = NULL; + try { + sconf = ScattererConfiguration::from_dedfb(config_file); + } catch(const OpenConfigurationFileException &ex) { + logger->err("\nERROR: failed to open scatterer configuration file.\n"); + string message = ex.what(); + logger->err("FILE: " + message + "\n"); + delete logger; + return; } - double frx = 0.0, fry = 0.0, frz = 0.0; - double cfmp, cfsp, sfmp, sfsp; - int jw; - int l_max = gconf->l_max; - ParticleDescriptor *c1 = new ParticleDescriptorSphere(gconf, sconf); - int npnt = gconf->npnt; - int npntts = gconf->npntts; - int in_pol = gconf->in_pol; - int meridional_type = gconf->iavm; - int jwtm = gconf->jwtm; - double in_theta_start = gconf->in_theta_start; - double in_theta_step = gconf->in_theta_step; - double in_theta_end = gconf->in_theta_end; - double sc_theta_start = gconf->sc_theta_start; - double sc_theta_step = gconf->sc_theta_step; - double sc_theta_end = gconf->sc_theta_end; - double in_phi_start = gconf->in_phi_start; - double in_phi_step = gconf->in_phi_step; - double in_phi_end = gconf->in_phi_end; - double sc_phi_start = gconf->sc_phi_start; - double sc_phi_step = gconf->sc_phi_step; - double sc_phi_end = gconf->sc_phi_end; - argi = new double[1]; - args = new double[1]; - gaps = new double[2]; - FILE *output = fopen((output_path + "/c_OSPH").c_str(), "w"); - fprintf(output, " READ(IR,*)NSPH,LM,INPOL,NPNT,NPNTTS,ISAM\n"); - fprintf( - output, - " %5d%5d%5d%5d%5d%5d\n", - nsph, - l_max, - in_pol, - npnt, - npntts, - meridional_type - ); - fprintf(output, " READ(IR,*)TH,THSTP,THLST,THS,THSSTP,THSLST\n"); - fprintf( - output, - " %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE\n", - in_theta_start, - in_theta_step, - in_theta_end, - sc_theta_start, - sc_theta_step, - sc_theta_end - ); - fprintf(output, " READ(IR,*)PH,PHSTP,PHLST,PHS,PHSSTP,PHSLST\n"); - fprintf( - output, - " %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE\n", - in_phi_start, - in_phi_step, - in_phi_end, - sc_phi_start, - sc_phi_step, - sc_phi_end - ); - fprintf(output, " READ(IR,*)JWTM\n"); - fprintf(output, " %5d\n", jwtm); - fprintf(output, " READ(ITIN)NSPHT\n"); - fprintf(output, " READ(ITIN)(IOG(I),I=1,NSPH)\n"); - fprintf(output, " READ(ITIN)EXDC,WP,XIP,IDFC,NXI\n"); - fprintf(output, " READ(ITIN)(XIV(I),I=1,NXI)\n"); - fprintf(output, " READ(ITIN)NSHL(I),ROS(I)\n"); - fprintf(output, " READ(ITIN)(RCF(I,NS),NS=1,NSH)\n \n"); - double sml = 1.0e-3; - int nth = 0, nph = 0; - if (in_theta_step != 0.0) - nth = int((in_theta_end - in_theta_start) / in_theta_step + sml); - nth += 1; - if (in_phi_step != 0.0) - nph = int((in_phi_end - in_phi_start) / in_phi_step + sml); - nph += 1; - int nths = 0, nphs = 0; - double thsca; - if (meridional_type > 1) { // ISAM > 1, fixed scattering angle - nths = 1; - thsca = sc_theta_start - in_theta_start; - } else { //ISAM <= 1 - if (in_theta_step != 0.0) - nths = int((sc_theta_end - sc_theta_start) / sc_theta_step + sml); - nths += 1; - if (meridional_type == 1) { // ISAM = 1 - nphs = 1; - } else { // ISAM < 1 - if (sc_phi_step != 0.0) - nphs = int((sc_phi_end - sc_phi_start) / sc_phi_step + sml); - nphs += 1; - } + sconf->write_formatted(output_path + "/c_OEDFB"); + sconf->write_binary(output_path + "/c_TEDF"); + sconf->write_binary(output_path + "/c_TEDF.hd5", "HDF5"); + GeometryConfiguration *gconf = NULL; + try { + gconf = GeometryConfiguration::from_legacy(data_file); + } catch(const OpenConfigurationFileException &ex) { + logger->err("\nERROR: failed to open geometry configuration file.\n"); + string message = ex.what(); + logger->err("FILE: " + message + "\n"); + if (sconf != NULL) delete sconf; + delete logger; + return; } - int nk = nth * nph; - int nks = nths * nphs; - int nkks = nk * nks; - double th1 = in_theta_start; - double ph1 = in_phi_start; - double ths1 = sc_theta_start; - double phs1 = sc_phi_start; - const double half_pi = acos(0.0); - const double pi = 2.0 * half_pi; - double gcs = 0.0; - for (int i116 = 0; i116 < nsph; i116++) { - int i = i116 + 1; - int iogi = c1->iog[i116]; - if (iogi >= i) { - double gcss = pi * c1->ros[i116] * c1->ros[i116]; - c1->gcsv[i116] = gcss; - int nsh = c1->nshl[i116]; - for (int j115 = 0; j115 < nsh; j115++) { - c1->rc[i116][j115] = sconf->get_rcf(i116, j115) * c1->ros[i116]; + int s_nsph = sconf->number_of_spheres; + int nsph = gconf->number_of_spheres; + int configurations = sconf->configurations; + logger->log(" done.\n"); + // Sanity check on number of sphere consistency, should always be verified + if (s_nsph == nsph) { + ScatteringAngles *p_sa = new ScatteringAngles(gconf); + SphereIterationData *sid = new SphereIterationData(gconf, sconf, mpidata, 0); + SphereOutputInfo *p_output = new SphereOutputInfo(sconf, gconf, mpidata); + // FILE *output = fopen((output_path + "/c_OSPH").c_str(), "w"); + const double half_pi = acos(0.0); + const double pi = 2.0 * half_pi; + sid->c1->gcs = 0.0; + for (int i116 = 0; i116 < nsph; i116++) { + int i = i116 + 1; + int iogi = sid->c1->iog[i116]; + if (iogi >= i) { + double gcss = pi * sid->c1->ros[i116] * sid->c1->ros[i116]; + sid->c1->gcsv[i116] = gcss; + int nsh = sid->c1->nshl[i116]; + for (int j115 = 0; j115 < nsh; j115++) { + sid->c1->rc[i116][j115] = sconf->get_rcf(i116, j115) * sid->c1->ros[i116]; + } } + sid->c1->gcs += sid->c1->gcsv[iogi - 1]; } - gcs += c1->gcsv[iogi - 1]; - } - double ****zpv = new double***[l_max]; //[l_max][3][2][2]; // Matrix: dim[LM x 3 x 2 x 2] - for (int zi = 0; zi < l_max; zi++) { - zpv[zi] = new double**[3]; - for (int zj = 0; zj < 3; zj++) { - zpv[zi][zj] = new double*[2]; - for (int zk = 0; zk < 2; zk++) { - zpv[zi][zj][zk] = new double[2](); - } + thdps(gconf->l_max, sid->zpv); + double exdc = sconf->exdc; + double exri = sqrt(exdc); + + // Create empty virtual binary file + VirtualBinaryFile *vtppoanp = new VirtualBinaryFile(); + string tppoan_name = output_path + "/c_TPPOAN"; + int imode = 10, tmpvalue; + + //======================== + // write a block of info to virtual binary file + //======================== + vtppoanp->append_line(VirtualBinaryLine(imode)); + tmpvalue = gconf->isam; + vtppoanp->append_line(VirtualBinaryLine(tmpvalue)); + tmpvalue = gconf->in_pol; + vtppoanp->append_line(VirtualBinaryLine(tmpvalue)); + vtppoanp->append_line(VirtualBinaryLine(s_nsph)); + tmpvalue = p_sa->nth; + vtppoanp->append_line(VirtualBinaryLine(tmpvalue)); + tmpvalue = p_sa->nph; + vtppoanp->append_line(VirtualBinaryLine(tmpvalue)); + tmpvalue = p_sa->nths; + vtppoanp->append_line(VirtualBinaryLine(tmpvalue)); + tmpvalue = p_sa->nphs; + vtppoanp->append_line(VirtualBinaryLine(tmpvalue)); + vtppoanp->append_line(VirtualBinaryLine(nsph)); + for (int nsi = 0; nsi < nsph; nsi++) { + tmpvalue = sid->c1->iog[nsi]; + vtppoanp->append_line(VirtualBinaryLine(tmpvalue)); } - } - thdps(l_max, zpv); - double exdc = sconf->exdc; - double exri = sqrt(exdc); - fprintf(output, " REFR. INDEX OF EXTERNAL MEDIUM=%15.7lE\n", exri); - fstream tppoan; - string tppoan_name = output_path + "/c_TPPOAN"; - tppoan.open(tppoan_name.c_str(), ios::binary|ios::out); - if (tppoan.is_open()) { - int imode = 10; - tppoan.write(reinterpret_cast<char *>(&imode), sizeof(int)); - tppoan.write(reinterpret_cast<char *>(&(meridional_type)), sizeof(int)); - tppoan.write(reinterpret_cast<char *>(&(in_pol)), sizeof(int)); - tppoan.write(reinterpret_cast<char *>(&s_nsph), sizeof(int)); - tppoan.write(reinterpret_cast<char *>(&nth), sizeof(int)); - tppoan.write(reinterpret_cast<char *>(&nph), sizeof(int)); - tppoan.write(reinterpret_cast<char *>(&nths), sizeof(int)); - tppoan.write(reinterpret_cast<char *>(&nphs), sizeof(int)); - tppoan.write(reinterpret_cast<char *>(&nsph), sizeof(int)); - - for (int nsi = 0; nsi < nsph; nsi++) - tppoan.write(reinterpret_cast<char *>(&(c1->iog[nsi])), sizeof(int)); - if (in_pol == 0) fprintf(output, " LIN\n"); - else fprintf(output, " CIRC\n"); - fprintf(output, " \n"); - double wp = sconf->wp; - double xip = sconf->xip; - double wn = wp / 3.0e8; - double sqsfi = 1.0; - double vk, vkarg; - int idfc = sconf->idfc; - int nxi = sconf->number_of_scales; - if (idfc < 0) { - vk = xip * wn; - fprintf(output, " VK=%15.7lE, XI IS SCALE FACTOR FOR LENGTHS\n", vk); - fprintf(output, " \n"); + + if (sconf->idfc < 0) { + sid->vk = sid->xip * sid->wn; + p_output->vec_vk[0] = sid->vk; } - for (int jxi488 = 0; jxi488 < nxi; jxi488++) { - int jxi = jxi488 + 1; - logger->log("INFO: running scale iteration " + to_string(jxi) + " of " + to_string(nxi) + ".\n"); - fprintf(output, "========== JXI =%3d ====================\n", jxi); - double xi = sconf->get_scale(jxi488); - if (idfc >= 0) { - vk = xi * wn; - vkarg = vk; - fprintf(output, " VK=%15.7lE, XI=%15.7lE\n", xi, vk); - } else { // IDFC < 0 - vkarg = xi * vk; - sqsfi = 1.0 / (xi * xi); - fprintf(output, " XI=%15.7lE\n", xi); + + // Do the first wavelength iteration + int jxi488 = 1; + // Use pragmas to put OMP parallelism to second level. + int jer = 0; +#pragma omp parallel + { +#pragma omp single + { + jer = sphere_jxi488_cycle(jxi488 - 1, sconf, gconf, p_sa, sid, p_output, output_path, vtppoanp); + } // OMP single + } // OMP parallel + if (jer != 0) { // First iteration failed. Halt the calculation. + delete p_output; + delete p_sa; + delete sid; + delete logger; + delete sconf; + delete gconf; + return; + } + + //================================================== + // do the first outputs here, so that I open here the new files, afterwards I only append + //================================================== + vtppoanp->write_to_disk(output_path + "/c_TPPOAN"); + delete vtppoanp; + + // here go the calls that send data to be duplicated on other MPI processes from process 0 to others, using MPI broadcasts, but only if MPI is actually used +#ifdef MPI_VERSION + if (mpidata->mpirunning) { + gconf->mpibcast(mpidata); + sconf->mpibcast(mpidata); + sid->mpibcast(mpidata); + p_sa->mpibcast(mpidata); + } +#endif + // Create this variable and initialise it with a default here, so that it is defined anyway, with or without OpenMP support enabled + int ompnumthreads = 1; + // this is for MPI process 0 (or even if we are not using MPI at all) + int myjxi488startoffset = 0; + int myMPIstride = ompnumthreads; + int myMPIblock = ompnumthreads; + // Define here shared arrays of virtual ascii and binary files, so that thread 0 will be able to access them all later + SphereOutputInfo **p_outarray = NULL; + VirtualBinaryFile **vtppoanarray = NULL; + + //=========================================== + // open the OpenMP parallel context, so each thread can initialise its stuff + //=========================================== +#pragma omp parallel + { + // Create and initialise this variable here, so that if OpenMP is enabled it is local to the thread, and if OpenMP is not enabled it has a well-defiled value anyway + int myompthread = 0; + +#ifdef _OPENMP + // If OpenMP is enabled, give actual values to myompthread and ompnumthreads, and open thread-local output files + myompthread = omp_get_thread_num(); + if (myompthread == 0) ompnumthreads = omp_get_num_threads(); +#endif + + if (myompthread == 0) { + // Initialise some shared variables only on thread 0 + p_outarray = new SphereOutputInfo*[ompnumthreads]; + vtppoanarray = new VirtualBinaryFile*[ompnumthreads]; + myMPIblock = ompnumthreads; + myMPIstride = myMPIblock; + } + +#ifdef MPI_VERSION + if (myompthread == 0) { + if (mpidata->mpirunning) { + // only go through this if MPI has been actually used + for (int rr=1; rr<mpidata->nprocs; rr++) { + // individually send their respective starting points to other MPI processes: they start immediately after the frequencies computed by previous processes so far + int remotejxi488startoffset = myMPIstride; + MPI_Send(&remotejxi488startoffset, 1, MPI_INT, rr, 3, MPI_COMM_WORLD); + int remoteMPIblock; + MPI_Recv(&remoteMPIblock, 1, MPI_INT, rr, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + // update myMPIstride to include the ones due to MPI process rr + myMPIstride += remoteMPIblock; + } + // now I know the total myMPIstride, I can send it to all processes + MPI_Bcast(&myMPIstride, 1, MPI_INT, 0, MPI_COMM_WORLD); + } + } +#endif + // add an omp barrier to make sure that the global variables defined by thread 0 are known to all threads below this +#pragma omp barrier + + // To test parallelism, I will now start feeding this function with "clean" copies of the parameters, so that they will not be changed by previous iterations, and each one will behave as the first one. Define all (empty) variables here, so they have the correct scope, then they get different definitions depending on thread number + SphereIterationData *sid_2 = NULL; + SphereOutputInfo *p_output_2 = NULL; + VirtualBinaryFile *vtppoanp_2 = NULL; + // for threads other than the 0, create distinct copies of all relevant data, while for thread 0 just define new references / pointers to the original ones + if (myompthread == 0) { + sid_2 = sid; + // OMP thread 0 of MPI process 0 holds the pointer to the full output structure + p_output_2 = p_output; + p_outarray[0] = p_output_2; + } else { + // this is not thread 0, so do create fresh copies of all local variables + sid_2 = new SphereIterationData(*sid); + } + // make sure all threads align here: I don't want the following loop to accidentally start for thread 0, possibly modifying some variables before they are copied by all other threads + if (myompthread==0) { + logger->log("Syncing OpenMP threads and starting the loop on wavelengths\n"); + // Thread 0 of process 0 has already allocated all necessary output memory } - tppoan.write(reinterpret_cast<char *>(&vk), sizeof(double)); - for (int i132 = 0; i132 < nsph; i132++) { - int i = i132 + 1; - int iogi = c1->iog[i132]; - if (iogi != i) { - for (int l123 = 0; l123 < l_max; l123++) { - c1->rmi[l123][i132] = c1->rmi[l123][iogi - 1]; - c1->rei[l123][i132] = c1->rei[l123][iogi - 1]; +#pragma omp barrier + // ok, now I can actually start the parallel calculations + for (int ixi488=2; ixi488<=sid_2->number_of_scales; ixi488 +=myMPIstride) { + // the parallel loop over MPI processes covers a different set of indices for each thread +#pragma omp barrier + int myjxi488 = ixi488+myompthread; + // each thread opens new virtual files and stores their pointers in the shared array + vtppoanp_2 = new VirtualBinaryFile(); + // each thread puts a copy of the pointers to its virtual files in the shared arrays + vtppoanarray[myompthread] = vtppoanp_2; +#pragma omp barrier + + // each MPI process handles a number of contiguous scales corresponding to its number of OMP threads at this omp level of parallelism + if (myjxi488 <= sid_2->number_of_scales) { + if (myompthread > 0) { + // UPDATE: non-0 threads need to allocate memory for one scale at a time. + p_output_2 = new SphereOutputInfo(sconf, gconf, mpidata, myjxi488, 1); + p_outarray[myompthread] = p_output_2; + } + int jer = sphere_jxi488_cycle(myjxi488 - 1, sconf, gconf, p_sa, sid_2, p_output_2, output_path, vtppoanp_2); + } else { + if (myompthread > 0) { + // If there is no input for this thread, set output pointer to NULL. + p_outarray[myompthread] = NULL; } - continue; // i132 } - // label 125 - int nsh = c1->nshl[i132]; - int ici = (nsh + 1) / 2; - if (idfc == 0) { - for (int ic = 0; ic < ici; ic++) - c1->dc0[ic] = sconf->get_dielectric_constant(ic, i132, jxi488); // WARNING: IDFC=0 is not tested! - } else { // IDFC != 0 - if (jxi == 1) { - for (int ic = 0; ic < ici; ic++) { - c1->dc0[ic] = sconf->get_dielectric_constant(ic, i132, jxi488); +#pragma omp barrier + // threads different from 0 append their virtual files to the one of thread 0, and delete them + if (myompthread == 0) { + for (int ti=1; ti<ompnumthreads; ti++) { + if (p_outarray[ti] != NULL) { + p_outarray[0]->insert(*(p_outarray[ti])); + delete p_outarray[ti]; + p_outarray[ti] = NULL; } + vtppoanarray[0]->append(*(vtppoanarray[ti])); + delete vtppoanarray[ti]; } } - if (nsh % 2 == 0) c1->dc0[ici] = exdc; - int jer = 0; - int lcalc = 0; - dme(l_max, i, npnt, npntts, vkarg, exdc, exri, c1, jer, lcalc, arg); - if (jer != 0) { - fprintf(output, " STOP IN DME\n"); - fprintf(output, " AT %1d LCALC=%3d TOO SMALL WITH ARG=%15.7lE+i(%15.7lE)\n", jer, lcalc, real(arg), imag(arg)); - tppoan.close(); - fclose(output); - delete sconf; - delete gconf; - delete c1; - for (int zi = l_max - 1; zi > -1; zi--) { - for (int zj = 0; zj < 3; zj++) { - for (int zk = 0; zk < 2; zk++) { - delete[] zpv[zi][zj][zk]; - } - delete[] zpv[zi][zj]; +#pragma omp barrier + //============================================== + // Collect all virtual files on thread 0 of MPI process 0, and append them to disk + //============================================== + if (myompthread == 0) { + // thread 0 writes its virtual files, now including contributions from all threads, to disk, and deletes them + // p_outarray[0]->append_to_disk(output_path + "/c_OCLU"); + // delete p_outarray[0]; + vtppoanarray[0]->append_to_disk(output_path + "/c_TPPOAN"); + delete vtppoanarray[0]; + +#ifdef MPI_VERSION + if (mpidata->mpirunning) { + // only go through this if MPI has been actually used + for (int rr=1; rr<mpidata->nprocs; rr++) { + // get the data from process rr by receiving it in total memory structure + p_outarray[0]->mpireceive(mpidata, rr); + // get the data from process rr, creating a new virtual ascii file + // VirtualAsciiFile *p_output = new VirtualAsciiFile(mpidata, rr); + // append to disk and delete virtual ascii file + // p_output->append_to_disk(output_path + "/c_OCLU"); + // delete p_output; + + // get the data from process rr, creating a new virtual binary file + VirtualBinaryFile *vtppoanp = new VirtualBinaryFile(mpidata, rr); + // append to disk and delete virtual binary file + vtppoanp->append_to_disk(output_path + "/c_TPPOAN"); + delete vtppoanp; + int test = MPI_Barrier(MPI_COMM_WORLD); } - delete[] zpv[zi]; } - delete[] zpv; - delete[] duk; - delete[] u; - delete[] us; - delete[] un; - delete[] uns; - delete[] up; - delete[] ups; - delete[] upmp; - delete[] upsmp; - delete[] unmp; - delete[] unsmp; - delete[] argi; - delete[] args; - delete[] gaps; - for (int i = 3; i > -1; i--) { - delete[] cmul[i]; - delete[] cmullr[i]; +#endif + } + // end block writing to disk +#pragma omp barrier + + } // ixi488 strided MPI loop +#pragma omp barrier + if (myompthread == 0) { + delete[] p_outarray; + delete[] vtppoanarray; + } + { + string message = "INFO: Closing thread-local output files of thread " + to_string(myompthread) + " and syncing threads.\n"; + logger->log(message); + } + delete sid_2; + } // OMP parallel + delete p_sa; + p_output->write(output_path + "/c_OSPH.hd5", "HDF5"); + p_output->write(output_path + "/c_OSPH", "LEGACY"); + delete p_output; + logger->log("Finished. Output written to " + output_path + "/c_OSPH.\n"); + } else { // NSPH mismatch between geometry and scatterer configurations. + throw UnrecognizedConfigurationException( + "Inconsistent geometry and scatterer configurations." + ); + } + delete sconf; + delete gconf; + } // end of instruction block for MPI process 0 + + //=============================== + // instruction block for MPI processes different from 0 + //=============================== +#ifdef MPI_VERSION + else { // Instruction block for MPI processes other than 0. + // here go the code for MPI processes other than 0 + // copy gconf, sconf, cid and p_scattering_angles from MPI process 0 + GeometryConfiguration *gconf = new GeometryConfiguration(mpidata); + ScattererConfiguration *sconf = new ScattererConfiguration(mpidata); + SphereIterationData *sid = new SphereIterationData(mpidata, device_count); + ScatteringAngles *p_sa = new ScatteringAngles(mpidata); + + // Create this variable and initialise it with a default here, so that it is defined anyway, with or without OpenMP support enabled + int ompnumthreads = 1; + SphereOutputInfo **p_outarray = NULL; + VirtualBinaryFile **vtppoanarray = NULL; + int myjxi488startoffset; + int myMPIstride = ompnumthreads; + int myMPIblock = ompnumthreads; + +#pragma omp parallel + { + // Create and initialise this variable here, so that if OpenMP is enabled it is local to the thread, and if OpenMP is not enabled it has a well-defiled value anyway + int myompthread = 0; +#ifdef _OPENMP + // If OpenMP is enabled, give actual values to myompthread and ompnumthreads, and open thread-local output files + myompthread = omp_get_thread_num(); + if (myompthread == 0) ompnumthreads = omp_get_num_threads(); +#endif + if (myompthread == 0) { + // receive the start parameter from MPI process 0 + MPI_Recv(&myjxi488startoffset, 1, MPI_INT, 0, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + // send my number of omp threads to process 0 + MPI_Send(&ompnumthreads, 1, MPI_INT, 0, 3, MPI_COMM_WORLD); + // receive myMPIstride sent by MPI process 0 to all processes + MPI_Bcast(&myMPIstride, 1, MPI_INT, 0, MPI_COMM_WORLD); + // allocate virtual files for each thread + p_outarray = new SphereOutputInfo*[ompnumthreads]; + vtppoanarray = new VirtualBinaryFile*[ompnumthreads]; + } +#pragma omp barrier + // To test parallelism, I will now start feeding this function with "clean" copies of the parameters, so that they will not be changed by previous iterations, and each one will behave as the first one. Define all (empty) variables here, so they have the correct scope, then they get different definitions depending on thread number + SphereIterationData *sid_2 = NULL; + SphereOutputInfo *p_output_2 = NULL; + VirtualBinaryFile *vtppoanp_2 = NULL; + // PLACEHOLDER + // for threads other than the 0, create distinct copies of all relevant data, while for thread 0 just define new references / pointers to the original ones + if (myompthread == 0) { + sid_2 = sid; + } else { + // this is not thread 0, so do create fresh copies of all local variables + sid_2 = new SphereIterationData(*sid); + } + // make sure all threads align here: I don't want the following loop to accidentally start for thread 0, possibly modifying some variables before they are copied by all other threads +#pragma omp barrier + // ok, now I can actually start the parallel calculations + for (int ixi488=2; ixi488<=sid_2->number_of_scales; ixi488 +=myMPIstride) { + // the parallel loop over MPI processes covers a different set of indices for each thread +#pragma omp barrier + int myjxi488 = ixi488 + myjxi488startoffset + myompthread; + // each thread opens new virtual files and stores their pointers in the shared array + vtppoanp_2 = new VirtualBinaryFile(); + // each thread puts a copy of the pointers to its virtual files in the shared arrays + vtppoanarray[myompthread] = vtppoanp_2; +#pragma omp barrier + if (myompthread==0) logger->log("Syncing OpenMP threads and starting the loop on wavelengths\n"); + // ok, now I can actually start the parallel calculations + // each MPI process handles a number of contiguous scales corresponding to its number of OMP threads at this omp level of parallelism + if (myjxi488 <= sid_2->number_of_scales) { + if (myompthread > 0) { + // UPDATE: non-0 threads need to allocate memory for one scale at a time. + p_output_2 = new SphereOutputInfo(sconf, gconf, mpidata, myjxi488, 1); + p_outarray[myompthread] = p_output_2; + } else { + // Thread 0 of non-zero MPI processes needs to allocate memory for the + // output of all threads. + p_output_2 = new SphereOutputInfo(sconf, gconf, mpidata, myjxi488, ompnumthreads); + p_outarray[0] = p_output_2; + } + int jer = sphere_jxi488_cycle(myjxi488 - 1, sconf, gconf, p_sa, sid_2, p_output_2, output_path, vtppoanp_2); + } else { + if (myompthread > 0) { + // If there is no input for this thread, set the output pointer to NULL. + p_outarray[myompthread] = NULL; + } + } + +#pragma omp barrier + // threads different from 0 append their virtual files to the one of thread 0, and delete them + if (myompthread == 0) { + for (int ti=1; ti<ompnumthreads; ti++) { + if (p_outarray[ti] != NULL) { + p_outarray[0]->insert(*(p_outarray[ti])); + delete p_outarray[ti]; + p_outarray[ti] = NULL; } - delete[] cmul; - delete[] cmullr; - for (int ti = 1; ti > -1; ti--) { - delete[] tqse[ti]; - delete[] tqss[ti]; - delete[] tqspe[ti]; - delete[] tqsps[ti]; + vtppoanarray[0]->append(*(vtppoanarray[ti])); + delete vtppoanarray[ti]; + } + // thread 0 sends the collected virtualfiles to thread 0 of MPI process 0, then deletes them + for (int rr=1; rr<mpidata->nprocs; rr++) { + if (rr == mpidata->rank) { + p_outarray[0]->mpisend(mpidata); + delete p_outarray[0]; + vtppoanarray[0]->mpisend(mpidata); + delete vtppoanarray[0]; } - delete[] tqse; - delete[] tqss; - delete[] tqspe; - delete[] tqsps; - delete logger; - return; + int test = MPI_Barrier(MPI_COMM_WORLD); } - } // i132 - if (idfc >= 0 and nsph == 1 and jxi == jwtm) { - // This is the condition that writes the transition matrix to output. - string ttms_name = output_path + "/c_TTMS.hd5"; - TransitionMatrix::write_binary( - ttms_name, l_max, vk, exri, c1->rmi, c1->rei, - sconf->get_radius(0), "HDF5" - ); - ttms_name = output_path + "/c_TTMS"; - TransitionMatrix::write_binary( - ttms_name, l_max, vk, exri, c1->rmi, c1->rei, - sconf->get_radius(0) - ); } - double cs0 = 0.25 * vk * vk * vk / half_pi; - sscr0(tfsas, nsph, l_max, vk, exri, c1); - double sqk = vk * vk * exdc; - aps(zpv, l_max, nsph, c1, sqk, gaps); - rabas(in_pol, l_max, nsph, c1, tqse, tqspe, tqss, tqsps); - for (int i170 = 0; i170 < nsph; i170++) { - int i = i170 + 1; - if (c1->iog[i170] >= i) { - double albeds = c1->sscs[i170] / c1->sexs[i170]; - c1->sqscs[i170] *= sqsfi; - c1->sqabs[i170] *= sqsfi; - c1->sqexs[i170] *= sqsfi; - fprintf(output, " SPHERE %2d\n", i); - if (c1->nshl[i170] != 1) { - fprintf(output, " SIZE=%15.7lE\n", c1->vsz[i170]); - } else { - fprintf( - output, - " SIZE=%15.7lE, REFRACTIVE INDEX=%15.7lE%15.7lE\n", - c1->vsz[i170], - real(c1->vkt[i170]), - imag(c1->vkt[i170]) - ); - } - fprintf(output, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n"); - fprintf( - output, - " %14.7lE%15.7lE%15.7lE%15.7lE\n", - c1->sscs[i170], c1->sabs[i170], - c1->sexs[i170], albeds - ); - fprintf(output, " ---- SCS/GS -- ABS/GS -- EXS/GS ---\n"); - fprintf( - output, - " %14.7lE%15.7lE%15.7lE\n", - c1->sqscs[i170], c1->sqabs[i170], - c1->sqexs[i170] - ); - fprintf(output, " FSAS=%15.7lE%15.7lE\n", real(c1->fsas[i170]), imag(c1->fsas[i170])); - double csch = 2.0 * vk * sqsfi / c1->gcsv[i170]; - s0 = c1->fsas[i170] * exri; - double qschu = csch * imag(s0); - double pschu = csch * real(s0); - double s0mag = cs0 * cabs(s0); - fprintf( - output, - " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", - qschu, pschu, s0mag - ); - double rapr = c1->sexs[i170] - gaps[i170]; - double cosav = gaps[i170] / c1->sscs[i170]; - fprintf(output, " COSAV=%15.7lE, RAPRS=%15.7lE\n", cosav, rapr); - fprintf(output, " IPO=%2d, TQEk=%15.7lE, TQSk=%15.7lE\n", 1, tqse[0][i170], tqss[0][i170]); - fprintf(output, " IPO=%2d, TQEk=%15.7lE, TQSk=%15.7lE\n", 2, tqse[1][i170], tqss[1][i170]); - tppoan.write(reinterpret_cast<char *>(&(tqse[0][i170])), sizeof(double)); - tppoan.write(reinterpret_cast<char *>(&(tqss[0][i170])), sizeof(double)); - double val = real(tqspe[0][i170]); - tppoan.write(reinterpret_cast<char *>(&val), sizeof(double)); - val = imag(tqspe[0][i170]); - tppoan.write(reinterpret_cast<char *>(&val), sizeof(double)); - val = real(tqsps[0][i170]); - tppoan.write(reinterpret_cast<char *>(&val), sizeof(double)); - val = imag(tqsps[0][i170]); - tppoan.write(reinterpret_cast<char *>(&val), sizeof(double)); - tppoan.write(reinterpret_cast<char *>(&(tqse[1][i170])), sizeof(double)); - tppoan.write(reinterpret_cast<char *>(&(tqss[1][i170])), sizeof(double)); - val = real(tqspe[1][i170]); - tppoan.write(reinterpret_cast<char *>(&val), sizeof(double)); - val = imag(tqspe[1][i170]); - tppoan.write(reinterpret_cast<char *>(&val), sizeof(double)); - val = real(tqsps[1][i170]); - tppoan.write(reinterpret_cast<char *>(&val), sizeof(double)); - val = imag(tqsps[1][i170]); - tppoan.write(reinterpret_cast<char *>(&val), sizeof(double)); - } // End if iog[i170] >= i - } // i170 loop - if (nsph != 1) { - fprintf(output, " FSAT=(%15.7lE,%15.7lE)\n", real(tfsas), imag(tfsas)); - double csch = 2.0 * vk * sqsfi / gcs; - s0 = tfsas * exri; - double qschu = csch * imag(s0); - double pschu = csch * real(s0); - double s0mag = cs0 * cabs(s0); - fprintf( - output, - " QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", - qschu, pschu, s0mag - ); + } // ixi488: close strided loop running on MPI processes + // Clean memory +#pragma omp barrier + if (myompthread == 0) { + delete[] p_outarray; + delete[] vtppoanarray; + } + delete sid_2; + } // OMP parallel + delete p_sa; + delete sconf; + delete gconf; + } // End instructions block for MPI non-0 processes. +#endif // MPI_VERSION + delete logger; +} // sphere() + +int sphere_jxi488_cycle( + int jxi488, ScattererConfiguration *sconf, GeometryConfiguration *gconf, + ScatteringAngles *sa, SphereIterationData *sid, SphereOutputInfo *oi, + const string& output_path, VirtualBinaryFile *vtppoanp +) { + const dcomplex cc0 = 0.0 + I * 0.0; + const double half_pi = acos(0.0); + const double pi = 2.0 * half_pi; + int jer = 0; + Logger *logger = new Logger(LOG_INFO); + int oindex = 0; + int jxi = jxi488 + 1; + int nsph = gconf->number_of_spheres; + int l_max = gconf->l_max; + int in_pol = gconf->in_pol; + int npnt = gconf->npnt; + int npntts = gconf->npntts; + int jwtm = gconf->jwtm; + double wn = sconf->wp / 3.0e8; + double sqsfi = 1.0; + int idfc = sconf->idfc; + int nxi = sconf->number_of_scales; + int configurations = sconf->configurations; + int ndirs = sa->nkks; + int lcalc; + int jw, isq, ibf; + logger->log("INFO: running scale iteration " + to_string(jxi) + " of " + to_string(nxi) + ".\n"); + double vk, vkarg; + double xi = sconf->get_scale(jxi488); + double exdc = sconf->exdc; + double exri = sqrt(exdc); + if (idfc >= 0) { + vk = xi * wn; + vkarg = vk; + oi->vec_vk[jxi488] = vk; + oi->vec_xi[jxi488] = xi; + } else { // IDFC < 0 + vk = sconf->xip * wn; + vkarg = xi * vk; + sqsfi = 1.0 / (xi * xi); + oi->vec_vk[jxi488] = vk; + oi->vec_xi[jxi488] = xi; + } + vtppoanp->append_line(VirtualBinaryLine(vk)); + double thsca = (gconf->isam > 1) ? sa->ths - sa->th : 0.0; + for (int i132 = 0; i132 < nsph; i132++) { + int i = i132 + 1; + int iogi = sid->c1->iog[i132]; + if (iogi != i) { + for (int l123 = 0; l123 < l_max; l123++) { + sid->c1->rmi[l123][i132] = sid->c1->rmi[l123][iogi - 1]; + sid->c1->rei[l123][i132] = sid->c1->rei[l123][iogi - 1]; + } + continue; // i132 + } + // label 125 + int nsh = sid->c1->nshl[i132]; + int ici = (nsh + 1) / 2; + if (idfc == 0) { + for (int ic = 0; ic < ici; ic++) + sid->c1->dc0[ic] = sconf->get_dielectric_constant(ic, i132, jxi488); // WARNING: IDFC=0 is not tested! + } else { // IDFC != 0 + if (jxi == 1) { + for (int ic = 0; ic < ici; ic++) { + sid->c1->dc0[ic] = sconf->get_dielectric_constant(ic, i132, jxi488); + } + } + } + if (nsh % 2 == 0) sid->c1->dc0[ici] = exdc; + dme(l_max, i, npnt, npntts, vkarg, exdc, exri, sid->c1, jer, lcalc, sid->arg); + if (jer != 0) { + oi->vec_ier[jxi] = 1; + oi->lcalc = lcalc; + return jer; + } + } // i132 + if (idfc >= 0 and nsph == 1 and jxi == jwtm) { + // This is the condition that writes the transition matrix to output. + string ttms_name = output_path + "/c_TTMS.hd5"; + TransitionMatrix::write_binary( + ttms_name, l_max, vk, exri, sid->c1->rmi, sid->c1->rei, + sconf->get_radius(0), "HDF5" + ); + ttms_name = output_path + "/c_TTMS"; + TransitionMatrix::write_binary( + ttms_name, l_max, vk, exri, sid->c1->rmi, sid->c1->rei, + sconf->get_radius(0) + ); + } + double cs0 = 0.25 * vk * vk * vk / half_pi; + sscr0(sid->tfsas, nsph, l_max, vk, exri, sid->c1); + double sqk = vk * vk * exdc; + aps(sid->zpv, l_max, nsph, sid->c1, sqk, sid->gaps); + rabas(in_pol, l_max, nsph, sid->c1, sid->tqse, sid->tqspe, sid->tqss, sid->tqsps); + int last_configuration = 0; + for (int i170 = 0; i170 < nsph; i170++) { + int i = i170 + 1; + if (sid->c1->iog[i170] >= i) { + last_configuration++; + oindex = jxi488 * configurations + last_configuration - 1; + double albeds = sid->c1->sscs[i170] / sid->c1->sexs[i170]; + sid->c1->sqscs[i170] *= sqsfi; + sid->c1->sqabs[i170] *= sqsfi; + sid->c1->sqexs[i170] *= sqsfi; + if (sid->c1->nshl[i170] != 1) { + oi->vec_sphere_ref_indices[oindex] = cc0; + oi->vec_sphere_sizes[oindex] = sid->c1->vsz[i170]; + } else { + oi->vec_sphere_ref_indices[oindex] = sid->c1->vkt[i170]; + oi->vec_sphere_sizes[oindex] = sid->c1->vsz[i170]; + } + oi->vec_scs[oindex] = sid->c1->sscs[i170]; + oi->vec_abs[oindex] = sid->c1->sabs[i170]; + oi->vec_exs[oindex] = sid->c1->sexs[i170]; + oi->vec_albeds[oindex] = albeds; + oi->vec_scsrt[oindex] = sid->c1->sqscs[i170]; + oi->vec_absrt[oindex] = sid->c1->sqabs[i170]; + oi->vec_exsrt[oindex] = sid->c1->sqexs[i170]; + oi->vec_fsas[oindex] = sid->c1->fsas[i170]; + double csch = 2.0 * vk * sqsfi / sid->c1->gcsv[i170]; + dcomplex s0 = sid->c1->fsas[i170] * exri; + double qschu = csch * imag(s0); + double pschu = csch * real(s0); + double s0mag = cs0 * cabs(s0); + oi->vec_qschu[oindex] = qschu; + oi->vec_pschu[oindex] = pschu; + oi->vec_s0mag[oindex] = s0mag; + double rapr = sid->c1->sexs[i170] - sid->gaps[i170]; + double cosav = sid->gaps[i170] / sid->c1->sscs[i170]; + oi->vec_cosav[oindex] = cosav; + oi->vec_raprs[oindex] = rapr; + oi->vec_tqek1[oindex] = sid->tqse[0][i170]; + oi->vec_tqsk1[oindex] = sid->tqss[0][i170]; + oi->vec_tqek2[oindex] = sid->tqse[1][i170]; + oi->vec_tqsk2[oindex] = sid->tqss[1][i170]; + double value = sid->tqse[0][i170]; + vtppoanp->append_line(VirtualBinaryLine(value)); + value = sid->tqss[0][i170]; + vtppoanp->append_line(VirtualBinaryLine(value)); + value = real(sid->tqspe[0][i170]); + vtppoanp->append_line(VirtualBinaryLine(value)); + value = imag(sid->tqspe[0][i170]); + vtppoanp->append_line(VirtualBinaryLine(value)); + value = real(sid->tqsps[0][i170]); + vtppoanp->append_line(VirtualBinaryLine(value)); + value = imag(sid->tqsps[0][i170]); + vtppoanp->append_line(VirtualBinaryLine(value)); + value = sid->tqse[1][i170]; + vtppoanp->append_line(VirtualBinaryLine(value)); + value = sid->tqss[1][i170]; + vtppoanp->append_line(VirtualBinaryLine(value)); + value = real(sid->tqspe[1][i170]); + vtppoanp->append_line(VirtualBinaryLine(value)); + value = imag(sid->tqspe[1][i170]); + vtppoanp->append_line(VirtualBinaryLine(value)); + value = real(sid->tqsps[1][i170]); + vtppoanp->append_line(VirtualBinaryLine(value)); + value = imag(sid->tqsps[1][i170]); + vtppoanp->append_line(VirtualBinaryLine(value)); + } // End if iog[i170] >= i + } // i170 loop + if (nsph != 1) { + oi->vec_fsat[jxi488] = sid->tfsas; + double csch = 2.0 * vk * sqsfi / sid->c1->gcs; + dcomplex s0 = sid->tfsas * exri; + double qschu = csch * imag(s0); + double pschu = csch * real(s0); + double s0mag = cs0 * cabs(s0); + oi->vec_qschut[jxi488] = qschu; + oi->vec_pschut[jxi488] = pschu; + oi->vec_s0magt[jxi488] = s0mag; + } + double th = sa->th; + int done_dirs = 0; + int nks = sa->nths * sa->nphs; + int nkks = sa->nth * sa->nph * nks; + int nth = sa->nth; + int nph = sa->nph; + double frx, fry, frz; + for (int jth486 = 0; jth486 < sa->nth; jth486++) { // OpenMP parallelizable section + int jth = jth486 + 1; + double ph = sa->ph; + for (int jph484 = 0; jph484 < sa->nph; jph484++) { + int jph = jph484 + 1; + bool goto182 = (sa->nk == 1) && (jxi > 1); + double cost, sint, cosp, sinp; + if (!goto182) { + upvmp(th, ph, 0, cost, sint, cosp, sinp, sid->u, sid->upmp, sid->unmp); + } + if (gconf->isam >= 0) { + wmamp(0, cost, sint, cosp, sinp, in_pol, l_max, 0, nsph, sid->argi, sid->u, sid->upmp, sid->unmp, sid->c1); + for (int i183 = 0; i183 < nsph; i183++) { + double rapr = sid->c1->sexs[i183] - sid->gaps[i183]; + frx = rapr * sid->u[0]; + fry = rapr * sid->u[1]; + frz = rapr * sid->u[2]; + } + jw = 1; + } + double thsl = sa->ths; + double phsph = 0.0; + for (int jths482 = 0; jths482 < sa->nths; jths482++) { + int jths = jths482 + 1; + double ths = thsl; + int icspnv = 0; + if (gconf->isam > 1) ths = th + thsca; + if (gconf->isam >= 1) { + phsph = 0.0; + if ((ths < 0.0) || (ths > 180.0)) phsph = 180.0; + if (ths < 0.0) ths *= -1.0; + if (ths > 180.0) ths = 360.0 - ths; + if (phsph != 0.0) icspnv = 1; } - th = th1; - for (int jth486 = 0; jth486 < nth; jth486++) { // OpenMP parallelizable section - int jth = jth486 + 1; - ph = ph1; - for (int jph484 = 0; jph484 < nph; jph484++) { - int jph = jph484 + 1; - bool goto182 = (nk == 1) && (jxi > 1); - if (!goto182) { - upvmp(th, ph, 0, cost, sint, cosp, sinp, u, upmp, unmp); + double phs = sa->phs; + for (int jphs480 = 0; jphs480 < sa->nphs; jphs480++) { + int jphs = jphs480 + 1; + double costs, sints, cosps, sinps; + if (gconf->isam >= 1) { + phs = ph + phsph; + if (phs >= 360.0) phs -= 360.0; + } + bool goto190 = (nks == 1) && ((jxi > 1) || (jth > 1) || (jph > 1)); + if (!goto190) { + upvmp(ths, phs, icspnv, costs, sints, cosps, sinps, sid->us, sid->upsmp, sid->unsmp); + if (gconf->isam >= 0) { + wmamp(2, costs, sints, cosps, sinps, in_pol, l_max, 0, nsph, sid->args, sid->us, sid->upsmp, sid->unsmp, sid->c1); + } + } + if (nkks != 0 || jxi == 1) { + upvsp( + sid->u, sid->upmp, sid->unmp, sid->us, sid->upsmp, sid->unsmp, + sid->up, sid->un, sid->ups, sid->uns, sid->duk, isq, ibf, + sid->scan, sid->cfmp, sid->sfmp, sid->cfsp, sid->sfsp + ); + if (gconf->isam < 0) { + wmasp( + cost, sint, cosp, sinp, costs, sints, cosps, sinps, + sid->u, sid->up, sid->un, sid->us, sid->ups, sid->uns, + isq, ibf, in_pol, l_max, 0, nsph, sid->argi, sid->args, + sid->c1 + ); } - if (meridional_type >= 0) { - wmamp(0, cost, sint, cosp, sinp, in_pol, l_max, 0, nsph, argi, u, upmp, unmp, c1); - for (int i183 = 0; i183 < nsph; i183++) { - double rapr = c1->sexs[i183] - gaps[i183]; - frx = rapr * u[0]; - fry = rapr * u[1]; - frz = rapr * u[2]; + for (int i193 = 0; i193 < 3; i193++) { + sid->un[i193] = sid->unmp[i193]; + sid->uns[i193] = sid->unsmp[i193]; + } + } + if (gconf->isam < 0) jw = 1; + vtppoanp->append_line(VirtualBinaryLine(th)); + vtppoanp->append_line(VirtualBinaryLine(ph)); + vtppoanp->append_line(VirtualBinaryLine(ths)); + vtppoanp->append_line(VirtualBinaryLine(phs)); + double value = sid->scan; + vtppoanp->append_line(VirtualBinaryLine(value)); + if (jw != 0) { + jw = 0; + value = sid->u[0]; + vtppoanp->append_line(VirtualBinaryLine(value)); + value = sid->u[1]; + vtppoanp->append_line(VirtualBinaryLine(value)); + value = sid->u[2]; + vtppoanp->append_line(VirtualBinaryLine(value)); + } + oi->vec_dir_scand[done_dirs] = sid->scan; + oi->vec_dir_cfmp[done_dirs] = sid->cfmp; + oi->vec_dir_cfsp[done_dirs] = sid->cfsp; + oi->vec_dir_sfmp[done_dirs] = sid->sfmp; + oi->vec_dir_sfsp[done_dirs] = sid->sfsp; + if (gconf->isam >= 0) { + oi->vec_dir_un[3 * done_dirs] = sid->un[0]; + oi->vec_dir_un[3 * done_dirs + 1] = sid->un[1]; + oi->vec_dir_un[3 * done_dirs + 2] = sid->un[2]; + oi->vec_dir_uns[3 * done_dirs] = sid->uns[0]; + oi->vec_dir_uns[3 * done_dirs + 1] = sid->uns[1]; + oi->vec_dir_uns[3 * done_dirs + 2] = sid->uns[2]; + } else { + oi->vec_dir_un[3 * done_dirs] = sid->un[0]; + oi->vec_dir_un[3 * done_dirs + 1] = sid->un[1]; + oi->vec_dir_un[3 * done_dirs + 2] = sid->un[2]; + oi->vec_dir_uns[3 * done_dirs] = 0.0; + oi->vec_dir_uns[3 * done_dirs + 1] = 0.0; + oi->vec_dir_uns[3 * done_dirs + 2] = 0.0; + } + sscr2(nsph, l_max, vk, exri, sid->c1); + last_configuration = 0; + for (int ns226 = 0; ns226 < nsph; ns226++) { + int ns = ns226 + 1; + oindex = jxi488 * nsph * ndirs + nsph * done_dirs + ns226; + oi->vec_dir_sas11[oindex] = sid->c1->sas[ns226][0][0]; + oi->vec_dir_sas21[oindex] = sid->c1->sas[ns226][1][0]; + oi->vec_dir_sas12[oindex] = sid->c1->sas[ns226][0][1]; + oi->vec_dir_sas22[oindex] = sid->c1->sas[ns226][1][1]; + oi->vec_dir_fx[jxi488 * nsph * nth * nph + nsph * nph * (jth - 1) + nsph * (jph - 1) + ns226] = frx; + oi->vec_dir_fy[jxi488 * nsph * nth * nph + nsph * nph * (jth - 1) + nsph * (jph - 1) + ns226] = fry; + oi->vec_dir_fz[jxi488 * nsph * nth * nph + nsph * nph * (jth - 1) + nsph * (jph - 1) + ns226] = frz; + for (int i225 = 0; i225 < 16; i225++) sid->c1->vint[i225] = sid->c1->vints[ns226][i225]; + mmulc(sid->c1->vint, sid->cmullr, sid->cmul); + for (int imul = 0; imul < 4; imul++) { + int muls_index = 16 * jxi488 * nsph * ndirs + 16 * nsph * done_dirs + 4 * imul; + for (int jmul = 0; jmul < 4; jmul++) { + oi->vec_dir_muls[muls_index + jmul] = sid->cmul[imul][jmul]; } - jw = 1; } - double thsl = ths1; - double phsph = 0.0; - for (int jths482 = 0; jths482 < nths; jths482++) { - int jths = jths482 + 1; - double ths = thsl; - int icspnv = 0; - if (meridional_type > 1) ths = th + thsca; - if (meridional_type >= 1) { - phsph = 0.0; - if ((ths < 0.0) || (ths > 180.0)) phsph = 180.0; - if (ths < 0.0) ths *= -1.0; - if (ths > 180.0) ths = 360.0 - ths; - if (phsph != 0.0) icspnv = 1; + for (int imul = 0; imul < 4; imul++) { + int muls_index = 16 * jxi488 * nsph * ndirs + 16 * nsph * done_dirs + 4 * imul; + for (int jmul = 0; jmul < 4; jmul++) { + oi->vec_dir_mulslr[muls_index + jmul] = sid->cmullr[imul][jmul]; } - double phs = phs1; - for (int jphs480 = 0; jphs480 < nphs; jphs480++) { - int jphs = jphs480 + 1; - if (meridional_type >= 1) { - phs = ph + phsph; - if (phs >= 360.0) phs -= 360.0; - } - bool goto190 = (nks == 1) && ((jxi > 1) || (jth > 1) || (jph > 1)); - if (!goto190) { - upvmp(ths, phs, icspnv, costs, sints, cosps, sinps, us, upsmp, unsmp); - if (meridional_type >= 0) { - wmamp(2, costs, sints, cosps, sinps, in_pol, l_max, 0, nsph, args, us, upsmp, unsmp, c1); - } - } - if (nkks != 0 || jxi == 1) { - upvsp(u, upmp, unmp, us, upsmp, unsmp, up, un, ups, uns, duk, isq, ibf, scan, cfmp, sfmp, cfsp, sfsp); - if (meridional_type < 0) { - wmasp( - cost, sint, cosp, sinp, costs, sints, cosps, sinps, - u, up, un, us, ups, uns, isq, ibf, in_pol, - l_max, 0, nsph, argi, args, c1 - ); - } - for (int i193 = 0; i193 < 3; i193++) { - un[i193] = unmp[i193]; - uns[i193] = unsmp[i193]; - } - } - if (meridional_type < 0) jw = 1; - tppoan.write(reinterpret_cast<char *>(&th), sizeof(double)); - tppoan.write(reinterpret_cast<char *>(&ph), sizeof(double)); - tppoan.write(reinterpret_cast<char *>(&ths), sizeof(double)); - tppoan.write(reinterpret_cast<char *>(&phs), sizeof(double)); - tppoan.write(reinterpret_cast<char *>(&scan), sizeof(double)); - if (jw != 0) { - jw = 0; - tppoan.write(reinterpret_cast<char *>(&(u[0])), sizeof(double)); - tppoan.write(reinterpret_cast<char *>(&(u[1])), sizeof(double)); - tppoan.write(reinterpret_cast<char *>(&(u[2])), sizeof(double)); - } - fprintf( - output, - "********** JTH =%3d, JPH =%3d, JTHS =%3d, JPHS =%3d ********************\n", - jth, jph, jths, jphs - ); - fprintf( - output, - " TIDG=%10.3lE, PIDG=%10.3lE, TSDG=%10.3lE, PSDG=%10.3lE\n", - th, ph, ths, phs - ); - fprintf(output, " SCAND=%10.3lE\n", scan); - fprintf(output, " CFMP=%15.7lE, SFMP=%15.7lE\n", cfmp, sfmp); - fprintf(output, " CFSP=%15.7lE, SFSP=%15.7lE\n", cfsp, sfsp); - if (meridional_type >= 0) { - fprintf(output, " UNI=(%12.5lE,%12.5lE,%12.5lE)\n", un[0], un[1], un[2]); - fprintf(output, " UNS=(%12.5lE,%12.5lE,%12.5lE)\n", uns[0], uns[1], uns[2]); - } else { - fprintf(output, " UN=(%12.5lE,%12.5lE,%12.5lE)\n", un[0], un[1], un[2]); - } - sscr2(nsph, l_max, vk, exri, c1); - for (int ns226 = 0; ns226 < nsph; ns226++) { - int ns = ns226 + 1; - fprintf(output, " SPHERE %2d\n", ns); - fprintf( - output, " SAS(1,1)=%15.7lE%15.7lE, SAS(2,1)=%15.7lE%15.7lE\n", - real(c1->sas[ns226][0][0]), imag(c1->sas[ns226][0][0]), - real(c1->sas[ns226][1][0]), imag(c1->sas[ns226][1][0]) - ); - fprintf( - output, " SAS(1,2)=%15.7lE%15.7lE, SAS(2,2)=%15.7lE%15.7lE\n", - real(c1->sas[ns226][0][1]), imag(c1->sas[ns226][0][1]), - real(c1->sas[ns226][1][1]), imag(c1->sas[ns226][1][1]) - ); - if (jths == 1 && jphs == 1) - fprintf( - output, " Fx=%15.7lE, Fy=%15.7lE, Fz=%15.7lE\n", - frx, fry, frz - ); - for (int i225 = 0; i225 < 16; i225++) c1->vint[i225] = c1->vints[ns226][i225]; - mmulc(c1->vint, cmullr, cmul); - fprintf(output, " MULS\n "); - for (int imul = 0; imul < 4; imul++) { - for (int jmul = 0; jmul < 4; jmul++) { - fprintf(output, "%15.7lE", cmul[imul][jmul]); - } - if (imul < 3) fprintf(output, "\n "); - else fprintf(output, "\n"); - } - fprintf(output, " MULSLR\n "); - for (int imul = 0; imul < 4; imul++) { - for (int jmul = 0; jmul < 4; jmul++) { - fprintf(output, "%15.7lE", cmullr[imul][jmul]); - } - if (imul < 3) fprintf(output, "\n "); - else fprintf(output, "\n"); - } - for (int vi = 0; vi < 16; vi++) { - double value = real(c1->vint[vi]); - tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); - value = imag(c1->vint[vi]); - tppoan.write(reinterpret_cast<char *>(&value), sizeof(double)); - } - for (int imul = 0; imul < 4; imul++) { - for (int jmul = 0; jmul < 4; jmul++) { - tppoan.write(reinterpret_cast<char *>(&(cmul[imul][jmul])), sizeof(double)); - } - } - } // ns226 loop - if (meridional_type < 1) phs += sc_phi_step; - } // jphs480 loop - if (meridional_type <= 1) thsl += sc_theta_step; - } // jths482 loop - ph += in_phi_step; - } // jph484 loop on elevation - th += in_theta_step; - } // jth486 loop on azimuth - logger->log("INFO: finished scale iteration " + to_string(jxi) + " of " + to_string(nxi) + ".\n"); - } //jxi488 loop on scales - tppoan.close(); - } else { // In case TPPOAN could not be opened. Should never happen. - logger->err("ERROR: failed to open TPPOAN file.\n"); - } - fclose(output); - delete c1; - for (int zi = l_max - 1; zi > -1; zi--) { - for (int zj = 0; zj < 3; zj++) { - for (int zk = 0; zk < 2; zk++) { - delete[] zpv[zi][zj][zk]; - } - delete[] zpv[zi][zj]; - } - delete[] zpv[zi]; + } + for (int vi = 0; vi < 16; vi++) { + value = real(sid->c1->vint[vi]); + vtppoanp->append_line(VirtualBinaryLine(value)); + value = imag(sid->c1->vint[vi]); + vtppoanp->append_line(VirtualBinaryLine(value)); + } + for (int imul = 0; imul < 4; imul++) { + for (int jmul = 0; jmul < 4; jmul++) { + value = sid->cmul[imul][jmul]; + vtppoanp->append_line(VirtualBinaryLine(value)); + } + } + } // ns226 loop + if (gconf->isam < 1) phs += sa->phsstp; + done_dirs++; + } // jphs480 loop + if (gconf->isam <= 1) thsl += sa->thsstp; + } // jths482 loop + ph += sa->phstp; + } // jph484 loop on elevation + th += sa->thstp; + } // jth486 loop on azimuth + oi->vec_jxi[jxi488] = jxi; + logger->log("INFO: finished scale iteration " + to_string(jxi) + " of " + to_string(nxi) + ".\n"); + return jer; +} + +// >>> IMPLEMENTATION OF SphereIterationData CLASS <<< +SphereIterationData::SphereIterationData( + GeometryConfiguration *gconf, ScattererConfiguration *sconf, + const mixMPI *mpidata, const int device_count +) { + const dcomplex cc0 = 0.0 + I * 0.0; + _nsph = gconf->number_of_spheres; + _lm = gconf->l_max; + arg = cc0; + s0 = cc0; + tfsas = cc0; + c1 = new ParticleDescriptorSphere(gconf, sconf); + argi = new double[1](); + args = new double[1](); + scan = 0.0; + cfmp = 0.0; + cfsp = 0.0; + sfmp = 0.0; + sfsp = 0.0; + wn = sconf->wp / 3.0e8; + xip = sconf->xip; + vk = 0.0; + // Scale block initialization + number_of_scales = sconf->number_of_scales; + xiblock = (int) ceil(((double) (sconf->number_of_scales-1))/((double) mpidata->nprocs)); + lastxi = ((mpidata->rank+1) * xiblock)+1; + firstxi = lastxi-xiblock+1; + if (lastxi > sconf->number_of_scales) lastxi = sconf->number_of_scales; + // End of scale block initialization + gaps = new double[_nsph](); + duk = new double[3](); + u = new double[3](); + us = new double[3](); + un = new double[3](); + uns = new double[3](); + up = new double[3](); + ups = new double[3](); + upmp = new double[3](); + upsmp = new double[3](); + unmp = new double[3](); + unsmp = new double[3](); + vec_cmul = new double[16](); + vec_cmullr = new double[16](); + cmul = new double*[4]; + cmullr = new double*[4]; + for (int ci = 0; ci < 4; ci++) { + cmul[ci] = (vec_cmul + 4 * ci); + cmullr[ci] = (vec_cmullr + 4 * ci); + } + vec_tqspe = new dcomplex[2 * _nsph](); + vec_tqsps = new dcomplex[2 * _nsph](); + vec_tqse = new double[2 * _nsph](); + vec_tqss = new double[2 * _nsph](); + tqspe = new dcomplex*[2]; + tqsps = new dcomplex*[2]; + tqse = new double*[2]; + tqss = new double*[2]; + for (int ti = 0; ti < 2; ti++) { + tqspe[ti] = (vec_tqspe + _nsph * ti); + tqsps[ti] = (vec_tqsps + _nsph * ti); + tqse[ti] = (vec_tqse + _nsph * ti); + tqss[ti] = (vec_tqss + _nsph * ti); + } + vec_zpv = new double[_lm * 12](); + zpv = new double***[_lm]; + for (int zi = 0; zi < _lm; zi++) { + zpv[zi] = new double**[3]; + for (int zj = 0; zj < 3; zj++) { + int vec_index = 12 * zi + 4 * zj; + zpv[zi][zj] = new double*[2]; + zpv[zi][zj][0] = (vec_zpv + vec_index); + zpv[zi][zj][1] = (vec_zpv + vec_index + 2); } - delete[] zpv; - delete[] duk; - delete[] u; - delete[] us; - delete[] un; - delete[] uns; - delete[] up; - delete[] ups; - delete[] upmp; - delete[] upsmp; - delete[] unmp; - delete[] unsmp; - delete[] argi; - delete[] args; - delete[] gaps; - for (int i = 3; i > -1; i--) { - delete[] cmul[i]; - delete[] cmullr[i]; + } +} + +SphereIterationData::SphereIterationData(const SphereIterationData &rhs) { + _nsph = rhs._nsph; + _lm = rhs._lm; + arg = rhs.arg; + s0 = rhs.s0; + tfsas = rhs.tfsas; + c1 = new ParticleDescriptorSphere(reinterpret_cast<ParticleDescriptorSphere &>(*(rhs.c1))); + argi = new double[1]; + args = new double[1]; + argi[0] = rhs.argi[0]; + args[0] = rhs.args[0]; + scan = rhs.scan; + cfmp = rhs.cfmp; + cfsp = rhs.cfsp; + sfmp = rhs.sfmp; + sfsp = rhs.sfsp; + wn = rhs.wn; + xip = rhs.xip; + vk = rhs.vk; + // Scale block initialization + number_of_scales = rhs.number_of_scales; + xiblock = rhs.xiblock; + lastxi = rhs.lastxi; + firstxi = rhs.firstxi; + // End of scale block initialization + gaps = new double[_nsph]; + for (int si = 0; si < _nsph; si++) gaps[si] = rhs.gaps[si]; + duk = new double[3]; + u = new double[3]; + us = new double[3]; + un = new double[3]; + uns = new double[3]; + up = new double[3]; + ups = new double[3]; + upmp = new double[3]; + upsmp = new double[3]; + unmp = new double[3]; + unsmp = new double[3]; + for (int ui = 0; ui < 3; ui++) { + duk[ui] = rhs.duk[ui]; + u[ui] = rhs.u[ui]; + us[ui] = rhs.us[ui]; + un[ui] = rhs.un[ui]; + uns[ui] = rhs.us[ui]; + up[ui] = rhs.up[ui]; + ups[ui] = rhs.ups[ui]; + upmp[ui] = rhs.upmp[ui]; + upsmp[ui] = rhs.upsmp[ui]; + unmp[ui] = rhs.unmp[ui]; + unsmp[ui] = rhs.unsmp[ui]; + } + vec_cmul = new double[16]; + vec_cmullr = new double[16]; + for (int mi = 0; mi < 16; mi++) { + vec_cmul[mi] = rhs.vec_cmul[mi]; + vec_cmullr[mi] = rhs.vec_cmullr[mi]; + } + cmul = new double*[4]; + cmullr = new double*[4]; + for (int ci = 0; ci < 4; ci++) { + cmul[ci] = (vec_cmul + 4 * ci); + cmullr[ci] = (vec_cmullr + 4 * ci); + } + vec_tqspe = new dcomplex[2 * _nsph](); + vec_tqsps = new dcomplex[2 * _nsph](); + vec_tqse = new double[2 * _nsph](); + vec_tqss = new double[2 * _nsph](); + for (int ti = 0; ti < 2 * _nsph; ti++) { + vec_tqspe[ti] = rhs.vec_tqspe[ti]; + vec_tqsps[ti] = rhs.vec_tqsps[ti]; + vec_tqse[ti] = rhs.vec_tqse[ti]; + vec_tqss[ti] = rhs.vec_tqss[ti]; + } + tqspe = new dcomplex*[2]; + tqsps = new dcomplex*[2]; + tqse = new double*[2]; + tqss = new double*[2]; + for (int ti = 0; ti < 2; ti++) { + tqspe[ti] = (vec_tqspe + _nsph * ti); + tqsps[ti] = (vec_tqsps + _nsph * ti); + tqse[ti] = (vec_tqse + _nsph * ti); + tqss[ti] = (vec_tqss + _nsph * ti); + } + vec_zpv = new double[_lm * 12]; + for (int zi = 0; zi < _lm * 12; zi++) vec_zpv[zi] = rhs.vec_zpv[zi]; + zpv = new double***[_lm]; + for (int zi = 0; zi < _lm; zi++) { + zpv[zi] = new double**[3]; + for (int zj = 0; zj < 3; zj++) { + int vec_index = 12 * zi + 4 * zj; + zpv[zi][zj] = new double*[2]; + zpv[zi][zj][0] = (vec_zpv + vec_index); + zpv[zi][zj][1] = (vec_zpv + vec_index + 2); } - delete[] cmul; - delete[] cmullr; - for (int ti = 1; ti > -1; ti--) { - delete[] tqse[ti]; - delete[] tqss[ti]; - delete[] tqspe[ti]; - delete[] tqsps[ti]; + } +} + +SphereIterationData::~SphereIterationData() { + int lm = c1->li; + delete c1; + delete[] argi; + delete[] args; + delete[] gaps; + delete[] duk; + delete[] u; + delete[] us; + delete[] un; + delete[] uns; + delete[] up; + delete[] ups; + delete[] upmp; + delete[] upsmp; + delete[] unmp; + delete[] unsmp; + delete[] vec_cmul; + delete[] vec_cmullr; + delete[] cmul; + delete[] cmullr; + delete[] vec_tqspe; + delete[] vec_tqsps; + delete[] vec_tqse; + delete[] vec_tqss; + delete[] tqspe; + delete[] tqsps; + delete[] tqse; + delete[] tqss; + delete[] vec_zpv; + for (int zi = 0; zi < lm; zi++) { + for (int zj = 0; zj < 3; zj++) { + delete[] zpv[zi][zj]; } - delete[] tqse; - delete[] tqss; - delete[] tqspe; - delete[] tqsps; - logger->log("Finished: output written to " + output_path + "/c_OSPH.\n"); - } else { // NSPH mismatch between geometry and scatterer configurations. - throw UnrecognizedConfigurationException( - "Inconsistent geometry and scatterer configurations." - ); + delete[] zpv[zi]; } - delete sconf; - delete gconf; - delete logger; + delete[] zpv; +} + +#ifdef MPI_VERSION +SphereIterationData::SphereIterationData(const mixMPI *mpidata, const int device_count) { + // Buld child object + c1 = new ParticleDescriptorSphere(mpidata); + + // Collect the scalar values + MPI_Bcast(&_nsph, 1, MPI_INT32_T, 0, MPI_COMM_WORLD); + MPI_Bcast(&_lm, 1, MPI_INT32_T, 0, MPI_COMM_WORLD); + MPI_Bcast(&arg, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(&s0, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(&tfsas, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(&scan, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&wn, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xip, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&vk, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xiblock, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&number_of_scales, 1, MPI_INT, 0, MPI_COMM_WORLD); + lastxi = ((mpidata->rank+1) * xiblock)+1; + firstxi = lastxi-xiblock+1; + if (lastxi > number_of_scales) lastxi = number_of_scales; + + // Collect length-1 vectors + argi = new double[1]; + args = new double[1]; + MPI_Bcast(argi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(args, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + // Collect vectors whose size depend on NSPH + gaps = new double[_nsph]; + vec_tqspe = new dcomplex[2 * _nsph]; + vec_tqsps = new dcomplex[2 * _nsph]; + vec_tqse = new double[2 * _nsph]; + vec_tqss = new double[2 * _nsph]; + MPI_Bcast(gaps, _nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(vec_tqspe, 2 * _nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(vec_tqsps, 2 * _nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(vec_tqse, 2 * _nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(vec_tqss, 2 * _nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + // Collect length-3 vectors + duk = new double[3]; + u = new double[3]; + us = new double[3]; + un = new double[3]; + uns = new double[3]; + up = new double[3]; + ups = new double[3]; + upmp = new double[3]; + upsmp = new double[3]; + unmp = new double[3]; + unsmp = new double[3]; + MPI_Bcast(duk, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(u, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(us, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(un, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(uns, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(up, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(ups, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + // Collect length-16 vectors + vec_cmul = new double[16]; + vec_cmullr = new double[16]; + MPI_Bcast(vec_cmul, 16, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(vec_cmullr, 16, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + // Collect vectors whose size depend on LM + vec_zpv = new double[12 * _lm]; + MPI_Bcast(vec_zpv, 12 * _lm, MPI_DOUBLE, 0, MPI_COMM_WORLD); +} + +int SphereIterationData::mpibcast(const mixMPI *mpidata) { + int result = 0; + // Broadcast child object + c1->mpibcast(mpidata); + + // Broadcast scalar values + MPI_Bcast(&_nsph, 1, MPI_INT32_T, 0, MPI_COMM_WORLD); + MPI_Bcast(&_lm, 1, MPI_INT32_T, 0, MPI_COMM_WORLD); + MPI_Bcast(&arg, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(&s0, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(&tfsas, 1, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(&scan, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&cfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfmp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&sfsp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&wn, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xip, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&vk, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&xiblock, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&number_of_scales, 1, MPI_INT, 0, MPI_COMM_WORLD); + + // Broadcast length-1 vectors + MPI_Bcast(argi, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(args, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + // Broadcast vectors whose size depend on NSPH + MPI_Bcast(gaps, _nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(vec_tqspe, 2 * _nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(vec_tqsps, 2 * _nsph, MPI_C_DOUBLE_COMPLEX, 0, MPI_COMM_WORLD); + MPI_Bcast(vec_tqse, 2 * _nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(vec_tqss, 2 * _nsph, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + // Broadcast length-3 vectors + MPI_Bcast(duk, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(u, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(us, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(un, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(uns, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(up, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(ups, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(upsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(unsmp, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + // Broadcast length-16 vectors + MPI_Bcast(vec_cmul, 16, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(vec_cmullr, 16, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + // Broadcast vectors whose size depend on LM + MPI_Bcast(vec_zpv, 12 * _lm, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + return 0; } +#endif // MPI_VERSION +// >>> END OF SphereIterationData CLASS IMPLEMENTATION <<< diff --git a/src/testing/test_ParticleDescriptor.cpp b/src/testing/test_ParticleDescriptor.cpp index 9eb221887ba1df88d32297885a479ba3f48e89ac..1cf34ad91e0fb63d9c37ba870bf9bbf9b6bf5fa5 100644 --- a/src/testing/test_ParticleDescriptor.cpp +++ b/src/testing/test_ParticleDescriptor.cpp @@ -56,7 +56,7 @@ int test_cluster_devel() { const string scat_data_file = "../../test_data/cluster/DEDFB"; GeometryConfiguration *gconf = GeometryConfiguration::from_legacy(geom_data_file); ScattererConfiguration *sconf = ScattererConfiguration::from_dedfb(scat_data_file); - ParticleDescriptor *pd = new ParticleDescriptorCluster(gconf, sconf); + ParticleDescriptorCluster *pd = new ParticleDescriptorCluster(gconf, sconf); delete gconf; delete sconf; delete pd; @@ -73,7 +73,7 @@ int test_inclusion() { const string scat_data_file = "../../test_data/inclusion/DEDFB"; GeometryConfiguration *gconf = GeometryConfiguration::from_legacy(geom_data_file); ScattererConfiguration *sconf = ScattererConfiguration::from_dedfb(scat_data_file); - ParticleDescriptor *pd = new ParticleDescriptorInclusion(gconf, sconf); + ParticleDescriptorInclusion *pd = new ParticleDescriptorInclusion(gconf, sconf); delete gconf; delete sconf; delete pd; @@ -90,7 +90,7 @@ int test_sphere() { const string scat_data_file = "../../test_data/sphere/DEDFB"; GeometryConfiguration *gconf = GeometryConfiguration::from_legacy(geom_data_file); ScattererConfiguration *sconf = ScattererConfiguration::from_dedfb(scat_data_file); - ParticleDescriptor *pd = new ParticleDescriptorSphere(gconf, sconf); + ParticleDescriptorSphere *pd = new ParticleDescriptorSphere(gconf, sconf); delete gconf; delete sconf; delete pd; diff --git a/src/testing/test_TEDF.cpp b/src/testing/test_TEDF.cpp index 0c50ee74eff9468e0095a1d698d2fb0759df63b4..eeb975221b36c2c2eb03cfce301b324a3ae0c221 100644 --- a/src/testing/test_TEDF.cpp +++ b/src/testing/test_TEDF.cpp @@ -73,7 +73,7 @@ int main(int argc, char **argv) { legacy_file = string(argv[2]); hdf5_file = string(argv[3]); } - ScattererConfiguration *a, *b, *c; + ScattererConfiguration *a = NULL, *b = NULL, *c = NULL; try { a = ScattererConfiguration::from_dedfb(dedfb_file); } catch (...) { printf("Failed to open legacy configuration file.\n"); @@ -104,5 +104,8 @@ int main(int argc, char **argv) { printf("Configuration objects c and b are different.\n"); result += 100; } + if (a != NULL) delete a; + if (b != NULL) delete b; + if (c != NULL) delete c; return result; } diff --git a/src/testing/test_cluster_outputs.cpp b/src/testing/test_cluster_outputs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63f5a3ef24289ef037b1b424535e0437613bbe98 --- /dev/null +++ b/src/testing/test_cluster_outputs.cpp @@ -0,0 +1,67 @@ +#include <string> + +#ifndef INCLUDE_TYPES_H_ +#include "../include/types.h" +#endif + +#ifndef INCLUDE_ERRORS_H_ +#include "../include/errors.h" +#endif + +#ifndef INCLUDE_CONFIGURATION_H_ +#include "../include/Configuration.h" +#endif + +#ifndef INCLUDE_COMMONS_H_ +#include "../include/Commons.h" +#endif + +#ifndef INCLUDE_OUTPUTS_H_ +#include "../include/outputs.h" +#endif + +using namespace std; + +int test_cluster_hdf5_output(); +int test_cluster_case_3(); + +int main() { + int result = 0; + result += test_cluster_hdf5_output(); // 1 if failed + // result += test_cluster_devel(); // 10 if failed + result += test_cluster_case_3(); // 100 if failed + // result += test_inclusion(); // 1000 if failed + return result; +} + +int test_cluster_hdf5_output() { + int result = 0; + try { + const string hdf5_file = "../../test_data/cluster/c_OCLU_24.hd5"; + ClusterOutputInfo *oi = new ClusterOutputInfo(hdf5_file); + oi->write("c_OCLU_24", "LEGACY"); + delete oi; + } catch (const exception& ex) { + result = 1; + } + return result; +} + +int test_cluster_case_3() { + int result = 0; + try { + const string geom_data_file = "../../test_data/cluster/case_3/DCLU"; + const string scat_data_file = "../../test_data/cluster/case_3/DEDFB_33"; + mixMPI *mpidata = new mixMPI(); + GeometryConfiguration *gconf = GeometryConfiguration::from_legacy(geom_data_file); + ScattererConfiguration *sconf = ScattererConfiguration::from_dedfb(scat_data_file); + ClusterOutputInfo *oi = new ClusterOutputInfo(sconf, gconf, mpidata); + delete gconf; + delete sconf; + delete oi; + delete mpidata; + } catch (const exception& ex) { + result = 100; + } + return result; +} diff --git a/src/testing/test_inclusion_outputs.cpp b/src/testing/test_inclusion_outputs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ac93471acc09b4b03d09e294b08a69b6cab02884 --- /dev/null +++ b/src/testing/test_inclusion_outputs.cpp @@ -0,0 +1,65 @@ +#include <string> + +#ifndef INCLUDE_TYPES_H_ +#include "../include/types.h" +#endif + +#ifndef INCLUDE_ERRORS_H_ +#include "../include/errors.h" +#endif + +#ifndef INCLUDE_CONFIGURATION_H_ +#include "../include/Configuration.h" +#endif + +#ifndef INCLUDE_COMMONS_H_ +#include "../include/Commons.h" +#endif + +#ifndef INCLUDE_OUTPUTS_H_ +#include "../include/outputs.h" +#endif + +using namespace std; + +int test_inclusion_hdf5_output(); +int test_inclusion_devel(); + +int main() { + int result = 0; + result += test_inclusion_hdf5_output(); // 1 if failed + result += test_inclusion_devel(); // 10 if failed + return result; +} + +int test_inclusion_hdf5_output() { + int result = 0; + try { + const string hdf5_file = "../../test_data/inclusion/c_OINCLU.hd5"; + InclusionOutputInfo *oi = new InclusionOutputInfo(hdf5_file); + oi->write("c_OINCLU", "LEGACY"); + delete oi; + } catch (const exception& ex) { + result = 1; + } + return result; +} + +int test_inclusion_devel() { + int result = 0; + try { + const string geom_data_file = "../../test_data/inclusion/DINCLU"; + const string scat_data_file = "../../test_data/inclusion/DEDFB"; + mixMPI *mpidata = new mixMPI(); + GeometryConfiguration *gconf = GeometryConfiguration::from_legacy(geom_data_file); + ScattererConfiguration *sconf = ScattererConfiguration::from_dedfb(scat_data_file); + InclusionOutputInfo *oi = new InclusionOutputInfo(sconf, gconf, mpidata); + delete gconf; + delete sconf; + delete oi; + delete mpidata; + } catch (const exception& ex) { + result = 10; + } + return result; +} diff --git a/src/testing/test_sphere_outputs.cpp b/src/testing/test_sphere_outputs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5acb13c197768345dfcf846b0e538dcfe2fc7e53 --- /dev/null +++ b/src/testing/test_sphere_outputs.cpp @@ -0,0 +1,65 @@ +#include <string> + +#ifndef INCLUDE_TYPES_H_ +#include "../include/types.h" +#endif + +#ifndef INCLUDE_ERRORS_H_ +#include "../include/errors.h" +#endif + +#ifndef INCLUDE_CONFIGURATION_H_ +#include "../include/Configuration.h" +#endif + +#ifndef INCLUDE_COMMONS_H_ +#include "../include/Commons.h" +#endif + +#ifndef INCLUDE_OUTPUTS_H_ +#include "../include/outputs.h" +#endif + +using namespace std; + +int test_sphere_hdf5_output(); +int test_sphere_devel(); + +int main() { + int result = 0; + result += test_sphere_hdf5_output(); // 1 if failed + result += test_sphere_devel(); // 10 if failed + return result; +} + +int test_sphere_hdf5_output() { + int result = 0; + try { + const string hdf5_file = "../../test_data/sphere/c_OSPH.hd5"; + SphereOutputInfo *oi = new SphereOutputInfo(hdf5_file); + oi->write("c_OSPH", "LEGACY"); + delete oi; + } catch (const exception& ex) { + result = 1; + } + return result; +} + +int test_sphere_devel() { + int result = 0; + try { + const string geom_data_file = "../../test_data/sphere/DSPH"; + const string scat_data_file = "../../test_data/sphere/DEDFB"; + mixMPI *mpidata = new mixMPI(); + GeometryConfiguration *gconf = GeometryConfiguration::from_legacy(geom_data_file); + ScattererConfiguration *sconf = ScattererConfiguration::from_dedfb(scat_data_file); + SphereOutputInfo *oi = new SphereOutputInfo(sconf, gconf, mpidata); + delete gconf; + delete sconf; + delete oi; + delete mpidata; + } catch (const exception& ex) { + result = 10; + } + return result; +} diff --git a/test_data/cluster/c_OCLU_24.hd5 b/test_data/cluster/c_OCLU_24.hd5 new file mode 100644 index 0000000000000000000000000000000000000000..58d76ef853d3470653b7e7f40fc44555e8fa66b1 Binary files /dev/null and b/test_data/cluster/c_OCLU_24.hd5 differ diff --git a/test_data/cluster/case_24_short/.gitkeep b/test_data/cluster/case_24_short/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test_data/cluster/case_24_short/DCLU_24 b/test_data/cluster/case_24_short/DCLU_24 new file mode 100644 index 0000000000000000000000000000000000000000..7c402c44b054dfe8d7736fdefd1e24d2fd4b4dce --- /dev/null +++ b/test_data/cluster/case_24_short/DCLU_24 @@ -0,0 +1,29 @@ + 24 2 2 5760 1 149 300 0 0 + 0.0000000e+00 1.0000000e-08 0.0000000e+00 + 0.0000000e+00 -1.0000000e-08 0.0000000e+00 + 8.5355339e-09 5.0000000e-09 0.0000000e+00 + 8.5355339e-09 -5.0000000e-09 0.0000000e+00 + -8.5355339e-09 5.0000000e-09 0.0000000e+00 + -8.5355339e-09 -5.0000000e-09 0.0000000e+00 + 0.0000000e+00 1.0000000e-08 1.0000000e-08 + 0.0000000e+00 -1.0000000e-08 1.0000000e-08 + 8.5355339e-09 5.0000000e-09 1.0000000e-08 + 8.5355339e-09 -5.0000000e-09 1.0000000e-08 + -8.5355339e-09 5.0000000e-09 1.0000000e-08 + -8.5355339e-09 -5.0000000e-09 1.0000000e-08 + 0.0000000e+00 1.0000000e-08 2.0000000e-08 + 0.0000000e+00 -1.0000000e-08 2.0000000e-08 + 8.5355339e-09 5.0000000e-09 2.0000000e-08 + 8.5355339e-09 -5.0000000e-09 2.0000000e-08 + -8.5355339e-09 5.0000000e-09 2.0000000e-08 + -8.5355339e-09 -5.0000000e-09 2.0000000e-08 + 0.0000000e+00 1.0000000e-08 3.0000000e-08 + 0.0000000e+00 -1.0000000e-08 3.0000000e-08 + 8.5355339e-09 5.0000000e-09 3.0000000e-08 + 8.5355339e-09 -5.0000000e-09 3.0000000e-08 + -8.5355339e-09 5.0000000e-09 3.0000000e-08 + -8.5355339e-09 -5.0000000e-09 3.0000000e-08 + 0.00D01 0.00D00 0.00D01 180.00D00 0.00D01 0.00D01 + 0.00D01 0.00D00 0.00D01 0.00D00 0.00D01 0.00D01 + 1 +0 diff --git a/test_data/cluster/case_24_short/DEDFB_24 b/test_data/cluster/case_24_short/DEDFB_24 new file mode 100644 index 0000000000000000000000000000000000000000..a5afb5c746cb7661f54c2a47db363dde70ab745d --- /dev/null +++ b/test_data/cluster/case_24_short/DEDFB_24 @@ -0,0 +1,15 @@ + 24 0 + 1.000D00 3.0000000D08 1.000000D00 0 4 0 3 +4.2000000e-07 +4.2100000e-07 +4.2200000e-07 +4.2300000e-07 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 5.00d-9 + 1.000000D00 + ( 0.6965478043675424 , 0.012177869466280656 ) + ( 0.6910987175052832 , 0.012554064506388863 ) + ( 0.6855360485660978 , 0.012942754740189038 ) + ( 0.6798066752951744 , 0.013350374401007377 ) + 0 \ No newline at end of file diff --git a/test_data/cluster/case_24_short/OCLU_24 b/test_data/cluster/case_24_short/OCLU_24 new file mode 100644 index 0000000000000000000000000000000000000000..0415a767d1397e9bee28b1de49e1b3ea49ccde39 --- /dev/null +++ b/test_data/cluster/case_24_short/OCLU_24 @@ -0,0 +1,501 @@ + READ(IR,*)NSPH,LI,LE,MXNDM,INPOL,NPNT,NPNTTS,IAVM,ISAM + 24 2 2 5760 1 149 300 0 0 + READ(IR,*)RXX(I),RYY(I),RZZ(I) + 0.00000000D+00 1.00000000D-08 0.00000000D+00 + 0.00000000D+00 -1.00000000D-08 0.00000000D+00 + 8.53553390D-09 5.00000000D-09 0.00000000D+00 + 8.53553390D-09 -5.00000000D-09 0.00000000D+00 + -8.53553390D-09 5.00000000D-09 0.00000000D+00 + -8.53553390D-09 -5.00000000D-09 0.00000000D+00 + 0.00000000D+00 1.00000000D-08 1.00000000D-08 + 0.00000000D+00 -1.00000000D-08 1.00000000D-08 + 8.53553390D-09 5.00000000D-09 1.00000000D-08 + 8.53553390D-09 -5.00000000D-09 1.00000000D-08 + -8.53553390D-09 5.00000000D-09 1.00000000D-08 + -8.53553390D-09 -5.00000000D-09 1.00000000D-08 + 0.00000000D+00 1.00000000D-08 2.00000000D-08 + 0.00000000D+00 -1.00000000D-08 2.00000000D-08 + 8.53553390D-09 5.00000000D-09 2.00000000D-08 + 8.53553390D-09 -5.00000000D-09 2.00000000D-08 + -8.53553390D-09 5.00000000D-09 2.00000000D-08 + -8.53553390D-09 -5.00000000D-09 2.00000000D-08 + 0.00000000D+00 1.00000000D-08 3.00000000D-08 + 0.00000000D+00 -1.00000000D-08 3.00000000D-08 + 8.53553390D-09 5.00000000D-09 3.00000000D-08 + 8.53553390D-09 -5.00000000D-09 3.00000000D-08 + -8.53553390D-09 5.00000000D-09 3.00000000D-08 + -8.53553390D-09 -5.00000000D-09 3.00000000D-08 + READ(IR,*)TH,THSTP,THLST,THS,THSSTP,THSLST + 0.000D+00 0.000D+00 0.000D+00 1.800D+02 0.000D+00 0.000D+00 + READ(IR,*)PH,PHSTP,PHLST,PHS,PHSSTP,PHSLST + 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 0.000D+00 + READ(IR,*)JWTM + 1 + READ(ITIN)NSPHT + READ(ITIN)(IOG(I),I=1,NSPH) + READ(ITIN)EXDC,WP,XIP,IDFC,NXI + READ(ITIN)(XIV(I),I=1,NXI) + READ(ITIN)NSHL(I),ROS(I) + READ(ITIN)(RCF(I,NS),NS=1,NSH) + + REFR. INDEX OF EXTERNAL MEDIUM= 1.0000000D+00 +========== JXI = 1 ==================== + VK= 1.4959965D+07, XI= 1.4959965D+07 + CIRC + SPHERE 1 + SIZE= 7.4799825D-02, REFRACTIVE INDEX= 8.3462628D-01 7.2954026D-03 + ----- SCS ----- ABS ----- EXS ----- ALBEDS -- + 8.2890738D-23 1.1793572D-19 1.1801861D-19 7.0235312D-04 + ---- SCS/GS -- ABS/GS -- EXS/GS --- + 1.0553976D-06 1.5016042D-03 1.5026596D-03 + FSAS= -8.8317489D-26 3.9444814D-27 + QSCHU= 1.5026596D-03, PSCHU= -3.3644758D-02, S0MAG= 4.7107635D-05 + COSAV= 8.4691304D-04, RAPRS= 1.1801854D-19 + IPO= 1, TQEk= -2.6412630D-05, TQSk= -1.8550993D-08 + IPO= 2, TQEk= 2.6412630D-05, TQSk= 1.8550993D-08 + FSAT= -2.1196197D-24 9.4667554D-26 + QSCHU= 1.5026596D-03, PSCHU= -3.3644758D-02, S0MAG= 1.1305832D-03 + CLUSTER (ENSEMBLE AVERAGE, MODE 0) + CIRC -1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 4.6111264D-20 2.8291167D-18 2.8752279D-18 1.6037429D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.4462786D-05 1.5008930D-03 1.5253558D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3178738D+01 9.9952638D-01 1.0151040D+00 + FSAC(1,1)= -2.1169381D-24 9.6097415D-26 FSAC(2,1)= 0.0000000D+00 -0.0000000D+00 + RE(FSAC(1,1))/RE(TFSAS)= 9.9873484D-01, IM(FSAC(1,1))/IM(TFSAS)= 1.0151040D+00 + QSCHU= 1.5253558D-03, PSCHU= -3.3602192D-02, S0MAG= 1.1291900D-03 + COSAV= 1.3948860D-02, RAPRS= 2.8745847D-18 + Fk= 2.8745847D-18 + CIRC 1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 4.6111264D-20 2.8291167D-18 2.8752279D-18 1.6037429D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.4462786D-05 1.5008930D-03 1.5253558D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3178738D+01 9.9952638D-01 1.0151040D+00 + FSAC(2,2)= -2.1169381D-24 9.6097415D-26 FSAC(1,2)= 0.0000000D+00 -0.0000000D+00 + RE(FSAC(2,2))/RE(TFSAS)= 9.9873484D-01, IM(FSAC(2,2))/IM(TFSAS)= 1.0151040D+00 + QSCHU= 1.5253558D-03, PSCHU= -3.3602192D-02, S0MAG= 1.1291900D-03 + COSAV= 1.3948860D-02, RAPRS= 2.8745847D-18 + Fk= 2.8745847D-18 + (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))= -0.0000000D+00 + (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))= -2.3891251D-16 +********** JTH = 1, JPH = 1, JTHS = 1, JPHS = 1 ******************** + TIDG= 0.000D+00, PIDG= 0.000D+00, TSDG= 1.800D+02, PSDG= 0.000D+00 + SCAND= 1.800D+02 + CFMP= 1.0000000D+00, SFMP= 0.0000000D+00 + CFSP= -1.0000000D+00, SFSP= 0.0000000D+00 + UNI=(-0.00000D+00, 1.00000D+00, 0.00000D+00) + UNS=(-0.00000D+00, 1.00000D+00, 0.00000D+00) + CIRC + SPHERE 1 + SAS(1,1)= 0.0000000D+00 -0.0000000D+00, SAS(2,1)= 8.8127616D-26 -3.9363014D-27 + SAS(1,2)= 8.8127616D-26 -3.9363014D-27, SAS(2,2)= 0.0000000D+00 -0.0000000D+00 + MULS + 9.8730694D-24 0.0000000D+00 -0.0000000D+00 -0.0000000D+00 + 0.0000000D+00 -9.8730694D-24 0.0000000D+00 0.0000000D+00 + -0.0000000D+00 0.0000000D+00 9.8730694D-24 0.0000000D+00 + -0.0000000D+00 0.0000000D+00 0.0000000D+00 -9.8730694D-24 + MULSLR + 0.0000000D+00 9.8730694D-24 -0.0000000D+00 -0.0000000D+00 + 9.8730694D-24 0.0000000D+00 -0.0000000D+00 -0.0000000D+00 + -0.0000000D+00 -0.0000000D+00 9.8730694D-24 0.0000000D+00 + -0.0000000D+00 -0.0000000D+00 0.0000000D+00 -9.8730694D-24 + SAT(1,1)= 0.0000000D+00 0.0000000D+00, SAT(2,1)= 1.8393376D-24 7.8670066D-25 + SAT(1,2)= 1.8393376D-24 7.8670066D-25, SAT(2,2)= 0.0000000D+00 0.0000000D+00 + CLUSTER + CIRC -1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 4.7431539D-20 2.9429800D-18 2.9904116D-18 1.5861208D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.5163213D-05 1.5612994D-03 1.5864626D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3842400D+01 1.0397543D+00 1.0557698D+00 + FSAC(1,1)= -2.1777955D-24 9.9947145D-26 FSAC(2,1)= 1.6141565D-28 -1.6459244D-29 + SAC(1,1)= -1.2584222D-28 -6.4229521D-29 SAC(2,1)= 1.8944959D-24 8.1184535D-25 + RE(FSAC(1,1))/RE(TFSAS)= 1.0274463D+00, IM(FSAC(1,1))/IM(TFSAS)= 1.0557698D+00 + QSCHU= 1.5864626D-03, PSCHU= -3.4568182D-02, S0MAG= 1.1616782D-03 + COSAV= 2.2532617D-02, RAPRS= 2.9893428D-18 + Fl= 8.6669662D-38, Fr= 3.9988310D-38, Fk= 2.9893428D-18 + Fx= 8.6669662D-38, Fy= 3.9988310D-38, Fz= 2.9893428D-18 + TQEl= -2.9987027D-21, TQEr= 3.0179427D-20, TQEk= -6.6925577D-04 + TQSl= -5.0445282D-23, TQSr= -1.8756209D-23, TQSk= -1.0615204D-05 + TQEx= -2.9987027D-21, TQEy= 3.0179427D-20, TQEz= -6.6925577D-04 + TQSx= -5.0445282D-23, TQSy= -1.8756209D-23, TQSz= -1.0615204D-05 + CIRC 1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 4.7431539D-20 2.9429800D-18 2.9904116D-18 1.5861208D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.5163213D-05 1.5612994D-03 1.5864626D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3842400D+01 1.0397543D+00 1.0557698D+00 + FSAC(2,2)= -2.1777955D-24 9.9947145D-26 FSAC(1,2)= 1.6141565D-28 -1.6459244D-29 + SAC(2,2)= -1.2584222D-28 -6.4229521D-29 SAC(1,2)= 1.8944959D-24 8.1184535D-25 + RE(FSAC(2,2))/RE(TFSAS)= 1.0274463D+00, IM(FSAC(2,2))/IM(TFSAS)= 1.0557698D+00 + QSCHU= 1.5864626D-03, PSCHU= -3.4568182D-02, S0MAG= 1.1616782D-03 + COSAV= 2.2532617D-02, RAPRS= 2.9893428D-18 + Fl= -1.1220598D-37, Fr= 2.1873964D-37, Fk= 2.9893428D-18 + Fx= -1.1220598D-37, Fy= 2.1873964D-37, Fz= 2.9893428D-18 + TQEl= 1.0108289D-19, TQEr= 7.7575736D-20, TQEk= 6.6925577D-04 + TQSl= 3.9116466D-23, TQSr= 4.0820231D-23, TQSk= 1.0615204D-05 + TQEx= 1.0108289D-19, TQEy= 7.7575736D-20, TQEz= 6.6925577D-04 + TQSx= 3.9116466D-23, TQSy= 4.0820231D-23, TQSz= 1.0615204D-05 + (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))= -0.0000000D+00 + (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))= -1.8376812D-15 + MULC + 5.3897460D-21 7.5236394D-37 7.3725285D-25 -4.5883310D-38 + -7.5226883D-37 -5.3897460D-21 3.3841380D-38 4.9525738D-26 + 7.3725285D-25 3.3933216D-38 5.3897460D-21 -1.0405739D-36 + 4.5731207D-38 -4.9525738D-26 -1.0405674D-36 -5.3897460D-21 + MULCLR + 2.5325616D-29 5.3897460D-21 3.6862642D-25 2.4762869D-26 + 5.3897460D-21 2.5325616D-29 3.6862642D-25 -2.4762869D-26 + 7.3725285D-25 7.3725285D-25 5.3897460D-21 -1.0405739D-36 + -4.9525738D-26 4.9525738D-26 -1.0405674D-36 -5.3897460D-21 +========== JXI = 2 ==================== + VK= 1.4924431D+07, XI= 1.4924431D+07 + CIRC + SPHERE 1 + SIZE= 7.4622153D-02, REFRACTIVE INDEX= 8.3135776D-01 7.5503382D-03 + ----- SCS ----- ABS ----- EXS ----- ALBEDS -- + 8.5429103D-23 1.2177971D-19 1.2186514D-19 7.0101344D-04 + ---- SCS/GS -- ABS/GS -- EXS/GS --- + 1.0877171D-06 1.5505475D-03 1.5516352D-03 + FSAS= -9.0083833D-26 4.0827401D-27 + QSCHU= 1.5516352D-03, PSCHU= -3.4236136D-02, S0MAG= 4.7709611D-05 + COSAV= 8.4204349D-04, RAPRS= 1.2186507D-19 + IPO= 1, TQEk= -2.7144075D-05, TQSk= -1.9028361D-08 + IPO= 2, TQEk= 2.7144075D-05, TQSk= 1.9028361D-08 + FSAT= -2.1620120D-24 9.7985762D-26 + QSCHU= 1.5516352D-03, PSCHU= -3.4236136D-02, S0MAG= 1.1450307D-03 + CLUSTER (ENSEMBLE AVERAGE, MODE 0) + CIRC -1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 4.7534267D-20 2.9217221D-18 2.9692563D-18 1.6008812D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.5217712D-05 1.5500217D-03 1.5752394D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3184072D+01 9.9966091D-01 1.0152125D+00 + FSAC(1,1)= -2.1593385D-24 9.9476368D-26 FSAC(2,1)= 0.0000000D+00 -0.0000000D+00 + RE(FSAC(1,1))/RE(TFSAS)= 9.9876344D-01, IM(FSAC(1,1))/IM(TFSAS)= 1.0152125D+00 + QSCHU= 1.5752394D-03, PSCHU= -3.4193801D-02, S0MAG= 1.1436537D-03 + COSAV= 1.3877915D-02, RAPRS= 2.9685966D-18 + Fk= 2.9685966D-18 + CIRC 1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 4.7534267D-20 2.9217221D-18 2.9692563D-18 1.6008812D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.5217712D-05 1.5500217D-03 1.5752394D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3184072D+01 9.9966091D-01 1.0152125D+00 + FSAC(2,2)= -2.1593385D-24 9.9476368D-26 FSAC(1,2)= 0.0000000D+00 -0.0000000D+00 + RE(FSAC(2,2))/RE(TFSAS)= 9.9876344D-01, IM(FSAC(2,2))/IM(TFSAS)= 1.0152125D+00 + QSCHU= 1.5752394D-03, PSCHU= -3.4193801D-02, S0MAG= 1.1436537D-03 + COSAV= 1.3877915D-02, RAPRS= 2.9685966D-18 + Fk= 2.9685966D-18 + (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))= -0.0000000D+00 + (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))= 4.6159454D-16 +********** JTH = 1, JPH = 1, JTHS = 1, JPHS = 1 ******************** + TIDG= 0.000D+00, PIDG= 0.000D+00, TSDG= 1.800D+02, PSDG= 0.000D+00 + SCAND= 1.800D+02 + CFMP= 1.0000000D+00, SFMP= 0.0000000D+00 + CFSP= -1.0000000D+00, SFSP= 0.0000000D+00 + UNI=(-0.00000D+00, 1.00000D+00, 0.00000D+00) + UNS=(-0.00000D+00, 1.00000D+00, 0.00000D+00) + CIRC + SPHERE 1 + SAS(1,1)= 0.0000000D+00 -0.0000000D+00, SAS(2,1)= 8.9891213D-26 -4.0743237D-27 + SAS(1,2)= 8.9891213D-26 -4.0743237D-27, SAS(2,2)= 0.0000000D+00 -0.0000000D+00 + MULS + 1.0175532D-23 0.0000000D+00 -0.0000000D+00 -0.0000000D+00 + 0.0000000D+00 -1.0175532D-23 0.0000000D+00 0.0000000D+00 + -0.0000000D+00 0.0000000D+00 1.0175532D-23 0.0000000D+00 + -0.0000000D+00 0.0000000D+00 0.0000000D+00 -1.0175532D-23 + MULSLR + 0.0000000D+00 1.0175532D-23 -0.0000000D+00 -0.0000000D+00 + 1.0175532D-23 0.0000000D+00 -0.0000000D+00 -0.0000000D+00 + -0.0000000D+00 -0.0000000D+00 1.0175532D-23 0.0000000D+00 + -0.0000000D+00 -0.0000000D+00 0.0000000D+00 -1.0175532D-23 + SAT(1,1)= 0.0000000D+00 0.0000000D+00, SAT(2,1)= 1.8780938D-24 7.9945009D-25 + SAT(1,2)= 1.8780938D-24 7.9945009D-25, SAT(2,2)= 0.0000000D+00 0.0000000D+00 + CLUSTER + CIRC -1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 4.8916049D-20 3.0404472D-18 3.0893633D-18 1.5833699D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.5950770D-05 1.6130073D-03 1.6389581D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3858014D+01 1.0402825D+00 1.0562780D+00 + FSAC(1,1)= -2.2217335D-24 1.0350020D-25 FSAC(2,1)= 1.6888526D-28 -1.7434761D-29 + SAC(1,1)= -1.3232713D-28 -6.6479948D-29 SAC(2,1)= 1.9348034D-24 8.2506092D-25 + RE(FSAC(1,1))/RE(TFSAS)= 1.0276231D+00, IM(FSAC(1,1))/IM(TFSAS)= 1.0562780D+00 + QSCHU= 1.6389581D-03, PSCHU= -3.5181845D-02, S0MAG= 1.1767282D-03 + COSAV= 2.2415292D-02, RAPRS= 3.0882668D-18 + Fl= 8.2768602D-38, Fr= 2.1910286D-37, Fk= 3.0882668D-18 + Fx= 8.2768602D-38, Fy= 2.1910286D-37, Fz= 3.0882668D-18 + TQEl= 7.4428108D-20, TQEr= -5.3551524D-20, TQEk= -6.8812054D-04 + TQSl= 4.0169449D-23, TQSr= -3.7285964D-23, TQSk= -1.0895493D-05 + TQEx= 7.4428108D-20, TQEy= -5.3551524D-20, TQEz= -6.8812054D-04 + TQSx= 4.0169449D-23, TQSy= -3.7285964D-23, TQSz= -1.0895493D-05 + CIRC 1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 4.8916049D-20 3.0404472D-18 3.0893633D-18 1.5833699D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.5950770D-05 1.6130073D-03 1.6389581D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3858014D+01 1.0402825D+00 1.0562780D+00 + FSAC(2,2)= -2.2217335D-24 1.0350020D-25 FSAC(1,2)= 1.6888526D-28 -1.7434761D-29 + SAC(2,2)= -1.3232713D-28 -6.6479948D-29 SAC(1,2)= 1.9348034D-24 8.2506092D-25 + RE(FSAC(2,2))/RE(TFSAS)= 1.0276231D+00, IM(FSAC(2,2))/IM(TFSAS)= 1.0562780D+00 + QSCHU= 1.6389581D-03, PSCHU= -3.5181845D-02, S0MAG= 1.1767282D-03 + COSAV= 2.2415292D-02, RAPRS= 3.0882668D-18 + Fl= -2.1863145D-38, Fr= 2.0962273D-37, Fk= 3.0882668D-18 + Fx= -2.1863145D-38, Fy= 2.0962273D-37, Fz= 3.0882668D-18 + TQEl= 1.1769173D-19, TQEr= -7.0029171D-20, TQEk= 6.8812054D-04 + TQSl= -9.2827473D-23, TQSr= -6.4745061D-23, TQSk= 1.0895493D-05 + TQEx= 1.1769173D-19, TQEy= -7.0029171D-20, TQEz= 6.8812054D-04 + TQSx= -9.2827473D-23, TQSy= -6.4745061D-23, TQSz= 1.0895493D-05 + (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))= 1.6534025D-16 + (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))= -6.6547329D-16 + MULC + 5.5598758D-21 1.5045989D-36 7.8135774D-25 6.8589636D-40 + -1.5046667D-36 -5.5598758D-21 1.3958995D-38 4.8879786D-26 + 7.8135774D-25 1.4188584D-38 5.5598758D-21 -7.6166567D-37 + -8.0930031D-40 -4.8879786D-26 -7.6166565D-37 -5.5598758D-21 + MULCLR + 2.7559480D-29 5.5598758D-21 3.9067887D-25 2.4439893D-26 + 5.5598758D-21 2.7559480D-29 3.9067887D-25 -2.4439893D-26 + 7.8135774D-25 7.8135774D-25 5.5598758D-21 -7.6166567D-37 + -4.8879786D-26 4.8879786D-26 -7.6166565D-37 -5.5598758D-21 +========== JXI = 3 ==================== + VK= 1.4889065D+07, XI= 1.4889065D+07 + CIRC + SPHERE 1 + SIZE= 7.4445324D-02, REFRACTIVE INDEX= 8.2800793D-01 7.8155983D-03 + ----- SCS ----- ABS ----- EXS ----- ALBEDS -- + 8.8064221D-23 1.2576981D-19 1.2585788D-19 6.9971164D-04 + ---- SCS/GS -- ABS/GS -- EXS/GS --- + 1.1212685D-06 1.6013510D-03 1.6024723D-03 + FSAS= -9.1894300D-26 4.2265206D-27 + QSCHU= 1.6024723D-03, PSCHU= -3.4841441D-02, S0MAG= 4.8324773D-05 + COSAV= 8.3719371D-04, RAPRS= 1.2585780D-19 + IPO= 1, TQEk= -2.7900709D-05, TQSk= -1.9522451D-08 + IPO= 2, TQEk= 2.7900709D-05, TQSk= 1.9522451D-08 + FSAT= -2.2054632D-24 1.0143649D-25 + QSCHU= 1.6024723D-03, PSCHU= -3.4841441D-02, S0MAG= 1.1597946D-03 + CLUSTER (ENSEMBLE AVERAGE, MODE 0) + CIRC -1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 4.9011978D-20 3.0178832D-18 3.0668952D-18 1.5980976D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.6001662D-05 1.6010368D-03 1.6270384D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3189506D+01 9.9980379D-01 1.0153302D+00 + FSAC(1,1)= -2.2028042D-24 1.0299153D-25 FSAC(2,1)= 0.0000000D+00 -0.0000000D+00 + RE(FSAC(1,1))/RE(TFSAS)= 9.9879433D-01, IM(FSAC(1,1))/IM(TFSAS)= 1.0153302D+00 + QSCHU= 1.6270384D-03, PSCHU= -3.4799434D-02, S0MAG= 1.1584370D-03 + COSAV= 1.3807368D-02, RAPRS= 3.0662185D-18 + Fk= 3.0662185D-18 + CIRC 1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 4.9011978D-20 3.0178832D-18 3.0668952D-18 1.5980976D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.6001662D-05 1.6010368D-03 1.6270384D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3189506D+01 9.9980379D-01 1.0153302D+00 + FSAC(2,2)= -2.2028042D-24 1.0299153D-25 FSAC(1,2)= 0.0000000D+00 -0.0000000D+00 + RE(FSAC(2,2))/RE(TFSAS)= 9.9879433D-01, IM(FSAC(2,2))/IM(TFSAS)= 1.0153302D+00 + QSCHU= 1.6270384D-03, PSCHU= -3.4799434D-02, S0MAG= 1.1584370D-03 + COSAV= 1.3807368D-02, RAPRS= 3.0662185D-18 + Fk= 3.0662185D-18 + (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))= -0.0000000D+00 + (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))= 0.0000000D+00 +********** JTH = 1, JPH = 1, JTHS = 1, JPHS = 1 ******************** + TIDG= 0.000D+00, PIDG= 0.000D+00, TSDG= 1.800D+02, PSDG= 0.000D+00 + SCAND= 1.800D+02 + CFMP= 1.0000000D+00, SFMP= 0.0000000D+00 + CFSP= -1.0000000D+00, SFSP= 0.0000000D+00 + UNI=(-0.00000D+00, 1.00000D+00, 0.00000D+00) + UNS=(-0.00000D+00, 1.00000D+00, 0.00000D+00) + CIRC + SPHERE 1 + SAS(1,1)= 0.0000000D+00 -0.0000000D+00, SAS(2,1)= 9.1698877D-26 -4.2178599D-27 + SAS(1,2)= 9.1698877D-26 -4.2178599D-27, SAS(2,2)= 0.0000000D+00 -0.0000000D+00 + MULS + 1.0489525D-23 0.0000000D+00 -0.0000000D+00 -0.0000000D+00 + 0.0000000D+00 -1.0489525D-23 0.0000000D+00 0.0000000D+00 + -0.0000000D+00 0.0000000D+00 1.0489525D-23 0.0000000D+00 + -0.0000000D+00 0.0000000D+00 0.0000000D+00 -1.0489525D-23 + MULSLR + 0.0000000D+00 1.0489525D-23 -0.0000000D+00 -0.0000000D+00 + 1.0489525D-23 0.0000000D+00 -0.0000000D+00 -0.0000000D+00 + -0.0000000D+00 -0.0000000D+00 1.0489525D-23 0.0000000D+00 + -0.0000000D+00 -0.0000000D+00 0.0000000D+00 -1.0489525D-23 + SAT(1,1)= 0.0000000D+00 0.0000000D+00, SAT(2,1)= 1.9178477D-24 8.1245286D-25 + SAT(1,2)= 1.9178477D-24 8.1245286D-25, SAT(2,2)= 0.0000000D+00 0.0000000D+00 + CLUSTER + CIRC -1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 5.0458716D-20 3.1417270D-18 3.1921857D-18 1.5806949D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.6769180D-05 1.6667379D-03 1.6935071D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3874015D+01 1.0408324D+00 1.0568090D+00 + FSAC(1,1)= -2.2667945D-24 1.0719900D-25 FSAC(2,1)= 1.7671521D-28 -1.8473507D-29 + SAC(1,1)= -1.3914061D-28 -6.8814877D-29 SAC(2,1)= 1.9761740D-24 8.3854413D-25 + RE(FSAC(1,1))/RE(TFSAS)= 1.0278088D+00, IM(FSAC(1,1))/IM(TFSAS)= 1.0568090D+00 + QSCHU= 1.6935071D-03, PSCHU= -3.5810339D-02, S0MAG= 1.1921190D-03 + COSAV= 2.2298550D-02, RAPRS= 3.1910605D-18 + Fl= -2.9985071D-38, Fr= 5.1062724D-38, Fk= 3.1910605D-18 + Fx= -2.9985071D-38, Fy= 5.1062724D-38, Fz= 3.1910605D-18 + TQEl= 2.3576974D-20, TQEr= -1.6205080D-20, TQEk= -7.0765729D-04 + TQSl= 2.5121387D-24, TQSr= 3.8886833D-23, TQSk= -1.1185902D-05 + TQEx= 2.3576974D-20, TQEy= -1.6205080D-20, TQEz= -7.0765729D-04 + TQSx= 2.5121387D-24, TQSy= 3.8886833D-23, TQSz= -1.1185902D-05 + CIRC 1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 5.0458716D-20 3.1417270D-18 3.1921857D-18 1.5806949D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.6769180D-05 1.6667379D-03 1.6935071D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3874015D+01 1.0408324D+00 1.0568090D+00 + FSAC(2,2)= -2.2667945D-24 1.0719900D-25 FSAC(1,2)= 1.7671521D-28 -1.8473507D-29 + SAC(2,2)= -1.3914061D-28 -6.8814877D-29 SAC(1,2)= 1.9761740D-24 8.3854413D-25 + RE(FSAC(2,2))/RE(TFSAS)= 1.0278088D+00, IM(FSAC(2,2))/IM(TFSAS)= 1.0568090D+00 + QSCHU= 1.6935071D-03, PSCHU= -3.5810339D-02, S0MAG= 1.1921190D-03 + COSAV= 2.2298550D-02, RAPRS= 3.1910605D-18 + Fl= 1.0825039D-37, Fr= -3.5959270D-39, Fk= 3.1910605D-18 + Fx= 1.0825039D-37, Fy= -3.5959270D-39, Fz= 3.1910605D-18 + TQEl= 1.4147629D-20, TQEr= -4.1318702D-21, TQEk= 7.0765729D-04 + TQSl= 3.6331375D-23, TQSr= -6.7523457D-23, TQSk= 1.1185902D-05 + TQEx= 1.4147629D-20, TQEy= -4.1318702D-21, TQEz= 7.0765729D-04 + TQSx= 3.6331375D-23, TQSy= -6.7523457D-23, TQSz= 1.1185902D-05 + (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))= -0.0000000D+00 + (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))= 2.1417060D-16 + MULC + 5.7366981D-21 -1.7908594D-41 8.2823590D-25 3.9259675D-38 + -1.7908594D-41 -5.7366980D-21 6.4560354D-38 4.8086854D-26 + 8.2823590D-25 6.4560354D-38 5.7366981D-21 2.5630626D-42 + -3.9259675D-38 -4.8086854D-26 -2.5630626D-42 -5.7366980D-21 + MULCLR + 2.9994914D-29 5.7366981D-21 4.1411795D-25 2.4043427D-26 + 5.7366981D-21 2.9994914D-29 4.1411795D-25 -2.4043427D-26 + 8.2823590D-25 8.2823590D-25 5.7366981D-21 2.5630626D-42 + -4.8086854D-26 4.8086854D-26 -2.5630626D-42 -5.7366980D-21 +========== JXI = 4 ==================== + VK= 1.4853866D+07, XI= 1.4853866D+07 + CIRC + SPHERE 1 + SIZE= 7.4269330D-02, REFRACTIVE INDEX= 8.2454364D-01 8.0956142D-03 + ----- SCS ----- ABS ----- EXS ----- ALBEDS -- + 9.0832607D-23 1.2997569D-19 1.3006652D-19 6.9835500D-04 + ---- SCS/GS -- ABS/GS -- EXS/GS --- + 1.1565167D-06 1.6549019D-03 1.6560584D-03 + FSAS= -9.3766777D-26 4.3782044D-27 + QSCHU= 1.6560584D-03, PSCHU= -3.5467339D-02, S0MAG= 4.8962156D-05 + COSAV= 8.3235548D-04, RAPRS= 1.3006645D-19 + IPO= 1, TQEk= -2.8697531D-05, TQSk= -2.0041064D-08 + IPO= 2, TQEk= 2.8697531D-05, TQSk= 2.0041064D-08 + FSAT= -2.2504027D-24 1.0507691D-25 + QSCHU= 1.6560584D-03, PSCHU= -3.5467339D-02, S0MAG= 1.1750917D-03 + CLUSTER (ENSEMBLE AVERAGE, MODE 0) + CIRC -1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 5.0564822D-20 3.1192812D-18 3.1698461D-18 1.5951823D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.6825471D-05 1.6548301D-03 1.6816556D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3195058D+01 9.9995661D-01 1.0154567D+00 + FSAC(1,1)= -2.2477647D-24 1.0670105D-25 FSAC(2,1)= 0.0000000D+00 -0.0000000D+00 + RE(FSAC(1,1))/RE(TFSAS)= 9.9882781D-01, IM(FSAC(1,1))/IM(TFSAS)= 1.0154567D+00 + QSCHU= 1.6816556D-03, PSCHU= -3.5425764D-02, S0MAG= 1.1737572D-03 + COSAV= 1.3737170D-02, RAPRS= 3.1691514D-18 + Fk= 3.1691514D-18 + CIRC 1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 5.0564822D-20 3.1192812D-18 3.1698461D-18 1.5951823D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.6825471D-05 1.6548301D-03 1.6816556D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3195058D+01 9.9995661D-01 1.0154567D+00 + FSAC(2,2)= -2.2477647D-24 1.0670105D-25 FSAC(1,2)= 0.0000000D+00 -0.0000000D+00 + RE(FSAC(2,2))/RE(TFSAS)= 9.9882781D-01, IM(FSAC(2,2))/IM(TFSAS)= 1.0154567D+00 + QSCHU= 1.6816556D-03, PSCHU= -3.5425764D-02, S0MAG= 1.1737572D-03 + COSAV= 1.3737170D-02, RAPRS= 3.1691514D-18 + Fk= 3.1691514D-18 + (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))= -0.0000000D+00 + (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))= -8.6068038D-16 +********** JTH = 1, JPH = 1, JTHS = 1, JPHS = 1 ******************** + TIDG= 0.000D+00, PIDG= 0.000D+00, TSDG= 1.800D+02, PSDG= 0.000D+00 + SCAND= 1.800D+02 + CFMP= 1.0000000D+00, SFMP= 0.0000000D+00 + CFSP= -1.0000000D+00, SFSP= 0.0000000D+00 + UNI=(-0.00000D+00, 1.00000D+00, 0.00000D+00) + UNS=(-0.00000D+00, 1.00000D+00, 0.00000D+00) + CIRC + SPHERE 1 + SAS(1,1)= 0.0000000D+00 -0.0000000D+00, SAS(2,1)= 9.3568456D-26 -4.3692866D-27 + SAS(1,2)= 9.3568456D-26 -4.3692866D-27, SAS(2,2)= 0.0000000D+00 -0.0000000D+00 + MULS + 1.0819400D-23 0.0000000D+00 -0.0000000D+00 -0.0000000D+00 + 0.0000000D+00 -1.0819400D-23 0.0000000D+00 0.0000000D+00 + -0.0000000D+00 0.0000000D+00 1.0819400D-23 0.0000000D+00 + -0.0000000D+00 0.0000000D+00 0.0000000D+00 -1.0819400D-23 + MULSLR + 0.0000000D+00 1.0819400D-23 -0.0000000D+00 -0.0000000D+00 + 1.0819400D-23 0.0000000D+00 -0.0000000D+00 -0.0000000D+00 + -0.0000000D+00 -0.0000000D+00 1.0819400D-23 0.0000000D+00 + -0.0000000D+00 -0.0000000D+00 0.0000000D+00 -1.0819400D-23 + SAT(1,1)= 0.0000000D+00 0.0000000D+00, SAT(2,1)= 1.9589894D-24 8.2583248D-25 + SAT(1,2)= 1.9589894D-24 8.2583248D-25, SAT(2,2)= 0.0000000D+00 0.0000000D+00 + CLUSTER + CIRC -1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 5.2080948D-20 3.2485931D-18 3.3006740D-18 1.5778883D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.7629801D-05 1.7234322D-03 1.7510620D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3890534D+01 1.0414105D+00 1.0573673D+00 + FSAC(1,1)= -2.3134272D-24 1.1110488D-25 FSAC(2,1)= 1.8499733D-28 -1.9593532D-29 + SAC(1,1)= -1.4636374D-28 -7.1257955D-29 SAC(2,1)= 2.0190180D-24 8.5242396D-25 + RE(FSAC(1,1))/RE(TFSAS)= 1.0280059D+00, IM(FSAC(1,1))/IM(TFSAS)= 1.0573673D+00 + QSCHU= 1.7510620D-03, PSCHU= -3.6460633D-02, S0MAG= 1.2080773D-03 + COSAV= 2.2182275D-02, RAPRS= 3.2995188D-18 + Fl= -1.0543266D-38, Fr= -1.5319052D-37, Fk= 3.2995188D-18 + Fx= -1.0543266D-38, Fy= -1.5319052D-37, Fz= 3.2995188D-18 + TQEl= 1.6043526D-20, TQEr= -2.3754995D-20, TQEk= -7.2825192D-04 + TQSl= -2.8683649D-24, TQSr= 3.6411323D-23, TQSk= -1.1491001D-05 + TQEx= 1.6043526D-20, TQEy= -2.3754995D-20, TQEz= -7.2825192D-04 + TQSx= -2.8683649D-24, TQSy= 3.6411323D-23, TQSz= -1.1491001D-05 + CIRC 1 + ----- SCC ----- ABC ----- EXC ----- ALBEDC -- + 5.2080948D-20 3.2485931D-18 3.3006740D-18 1.5778883D-02 + --- SCC/TGS - ABC/TGS - EXC/TGS --- + 2.7629801D-05 1.7234322D-03 1.7510620D-03 + ---- SCCRT --- ABCRT --- EXCRT ---- + 2.3890534D+01 1.0414105D+00 1.0573673D+00 + FSAC(2,2)= -2.3134272D-24 1.1110488D-25 FSAC(1,2)= 1.8499733D-28 -1.9593532D-29 + SAC(2,2)= -1.4636374D-28 -7.1257955D-29 SAC(1,2)= 2.0190180D-24 8.5242396D-25 + RE(FSAC(2,2))/RE(TFSAS)= 1.0280059D+00, IM(FSAC(2,2))/IM(TFSAS)= 1.0573673D+00 + QSCHU= 1.7510620D-03, PSCHU= -3.6460633D-02, S0MAG= 1.2080773D-03 + COSAV= 2.2182275D-02, RAPRS= 3.2995188D-18 + Fl= 2.7263891D-38, Fr= -9.4005429D-38, Fk= 3.2995188D-18 + Fx= 2.7263891D-38, Fy= -9.4005429D-38, Fz= 3.2995188D-18 + TQEl= -5.1856063D-20, TQEr= -4.0973284D-20, TQEk= 7.2825192D-04 + TQSl= -1.5934558D-23, TQSr= 5.5088164D-23, TQSk= 1.1491001D-05 + TQEx= -5.1856063D-20, TQEy= -4.0973284D-20, TQEz= 7.2825192D-04 + TQSx= -1.5934558D-23, TQSy= 5.5088164D-23, TQSz= 1.1491001D-05 + (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))= -0.0000000D+00 + (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))= -2.2730560D-15 + MULC + 5.9226532D-21 7.5236242D-37 8.7859111D-25 -3.2162513D-38 + -7.5227035D-37 -5.9226531D-21 -3.4346476D-38 4.7122016D-26 + 8.7859111D-25 -3.4162805D-38 5.9226532D-21 1.3719613D-36 + 3.2360533D-38 -4.7122016D-26 1.3719658D-36 -5.9226531D-21 + MULCLR + 3.2677197D-29 5.9226532D-21 4.3929555D-25 2.3561008D-26 + 5.9226532D-21 3.2677197D-29 4.3929555D-25 -2.3561008D-26 + 8.7859111D-25 8.7859111D-25 5.9226532D-21 1.3719613D-36 + -4.7122016D-26 4.7122016D-26 1.3719658D-36 -5.9226531D-21 diff --git a/test_data/inclusion/c_OINCLU.hd5 b/test_data/inclusion/c_OINCLU.hd5 new file mode 100644 index 0000000000000000000000000000000000000000..7d7371ffd94387790e15c2cda446db9c7891f87a Binary files /dev/null and b/test_data/inclusion/c_OINCLU.hd5 differ diff --git a/test_data/sphere/c_OSPH.hd5 b/test_data/sphere/c_OSPH.hd5 new file mode 100644 index 0000000000000000000000000000000000000000..17c682f024d1896edd5db82abff4f10e79b2e75e Binary files /dev/null and b/test_data/sphere/c_OSPH.hd5 differ